13312 lines
1.1 MiB
13312 lines
1.1 MiB
require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
|
||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||
// Copyright (C) 2011 Recurity Labs GmbH
|
||
//
|
||
// This library is free software; you can redistribute it and/or
|
||
// modify it under the terms of the GNU Lesser General Public
|
||
// License as published by the Free Software Foundation; either
|
||
// version 2.1 of the License, or (at your option) any later version.
|
||
//
|
||
// This library is distributed in the hope that it will be useful,
|
||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
// Lesser General Public License for more details.
|
||
//
|
||
// You should have received a copy of the GNU Lesser General Public
|
||
// License along with this library; if not, write to the Free Software
|
||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||
|
||
var config = require('./config');
|
||
var packet = require('./packet');
|
||
var enums = require('./enums.js');
|
||
var armor = require('./encoding/armor.js');
|
||
|
||
/**
|
||
* @class
|
||
* @classdesc Class that represents an OpenPGP cleartext signed message.
|
||
* See http://tools.ietf.org/html/rfc4880#section-7
|
||
* @param {String} text The cleartext of the signed message
|
||
* @param {packetlist} packetlist The packetlist with signature packets or undefined
|
||
* if message not yet signed
|
||
*/
|
||
|
||
function CleartextMessage(text, packetlist) {
|
||
if (!(this instanceof CleartextMessage)) {
|
||
return new CleartextMessage(packetlist);
|
||
}
|
||
// normalize EOL to canonical form <CR><LF>
|
||
this.text = text.replace(/\r/g, '').replace(/[\t ]+\n/g, "\n").replace(/\n/g,"\r\n");
|
||
this.packets = packetlist || new packet.list();
|
||
}
|
||
|
||
/**
|
||
* Returns the key IDs of the keys that signed the cleartext message
|
||
* @return {[keyId]} array of keyid objects
|
||
*/
|
||
CleartextMessage.prototype.getSigningKeyIds = function() {
|
||
var keyIds = [];
|
||
var signatureList = this.packets.filterByTag(enums.packet.signature);
|
||
signatureList.forEach(function(packet) {
|
||
keyIds.push(packet.issuerKeyId);
|
||
});
|
||
return keyIds;
|
||
};
|
||
|
||
/**
|
||
* Sign the cleartext message
|
||
* @param {[key]} privateKeys private keys with decrypted secret key data for signing
|
||
*/
|
||
CleartextMessage.prototype.sign = function(privateKeys) {
|
||
var packetlist = new packet.list();
|
||
var literalDataPacket = new packet.literal();
|
||
literalDataPacket.setText(this.text);
|
||
for (var i = 0; i < privateKeys.length; i++) {
|
||
var signaturePacket = new packet.signature();
|
||
signaturePacket.signatureType = enums.signature.text;
|
||
signaturePacket.hashAlgorithm = config.prefer_hash_algorithm;
|
||
var signingKeyPacket = privateKeys[i].getSigningKeyPacket();
|
||
signaturePacket.publicKeyAlgorithm = signingKeyPacket.algorithm;
|
||
if (!signingKeyPacket.isDecrypted) throw new Error('Private key is not decrypted.');
|
||
signaturePacket.sign(signingKeyPacket, literalDataPacket);
|
||
packetlist.push(signaturePacket);
|
||
}
|
||
this.packets = packetlist;
|
||
};
|
||
|
||
/**
|
||
* Verify signatures of cleartext signed message
|
||
* @param {[key]} publicKeys public keys to verify signatures
|
||
* @return {[{'keyid': keyid, 'valid': Boolean}]} list of signer's keyid and validity of signature
|
||
*/
|
||
CleartextMessage.prototype.verify = function(publicKeys) {
|
||
var result = [];
|
||
var signatureList = this.packets.filterByTag(enums.packet.signature);
|
||
var literalDataPacket = new packet.literal();
|
||
// we assume that cleartext signature is generated based on UTF8 cleartext,
|
||
// fails for other encodings, see CP-1252 test case in test/signature.js
|
||
literalDataPacket.setText(this.text);
|
||
publicKeys.forEach(function(pubKey) {
|
||
for (var i = 0; i < signatureList.length; i++) {
|
||
var publicKeyPacket = pubKey.getPublicKeyPacket([signatureList[i].issuerKeyId]);
|
||
if (publicKeyPacket) {
|
||
var verifiedSig = {};
|
||
verifiedSig.keyid = signatureList[i].issuerKeyId;
|
||
verifiedSig.status = signatureList[i].verify(publicKeyPacket, literalDataPacket);
|
||
result.push(verifiedSig);
|
||
break;
|
||
}
|
||
}
|
||
});
|
||
return result;
|
||
};
|
||
|
||
/**
|
||
* Get cleartext
|
||
* @return {String} cleartext of message
|
||
*/
|
||
CleartextMessage.prototype.getText = function() {
|
||
// normalize end of line to \n
|
||
return this.text.replace(/\r\n/g,"\n");
|
||
};
|
||
|
||
/**
|
||
* Returns ASCII armored text of cleartext signed message
|
||
* @return {String} ASCII armor
|
||
*/
|
||
CleartextMessage.prototype.armor = function() {
|
||
var body = {
|
||
hash: enums.read(enums.hash, config.prefer_hash_algorithm).toUpperCase(),
|
||
text: this.text,
|
||
data: this.packets.write()
|
||
}
|
||
return armor.encode(enums.armor.signed, body);
|
||
};
|
||
|
||
|
||
/**
|
||
* reads an OpenPGP cleartext signed message and returns a CleartextMessage object
|
||
* @param {String} armoredText text to be parsed
|
||
* @return {CleartextMessage} new cleartext message object
|
||
*/
|
||
function readArmored(armoredText) {
|
||
var input = armor.decode(armoredText);
|
||
if (input.type !== enums.armor.signed) {
|
||
throw new Error('No cleartext signed message.');
|
||
}
|
||
var packetlist = new packet.list();
|
||
packetlist.read(input.data);
|
||
var newMessage = new CleartextMessage(input.text, packetlist);
|
||
return newMessage;
|
||
}
|
||
|
||
exports.CleartextMessage = CleartextMessage;
|
||
exports.readArmored = readArmored;
|
||
|
||
},{"./config":3,"./encoding/armor.js":25,"./enums.js":27,"./packet":35}],2:[function(require,module,exports){
|
||
JXG = {
|
||
exists: (function(undefined) {
|
||
return function(v) {
|
||
return !(v === undefined || v === null);
|
||
}
|
||
})()
|
||
};
|
||
JXG.decompress = function(str) {
|
||
return unescape((new JXG.Util.Unzip(JXG.Util.Base64.decodeAsArray(str))).unzip()[0][0]);
|
||
};
|
||
/*
|
||
Copyright 2008-2012
|
||
Matthias Ehmann,
|
||
Michael Gerhaeuser,
|
||
Carsten Miller,
|
||
Bianca Valentin,
|
||
Alfred Wassermann,
|
||
Peter Wilfahrt
|
||
|
||
This file is part of JSXGraph.
|
||
|
||
Dual licensed under the Apache License Version 2.0, or LGPL Version 3 licenses.
|
||
|
||
You should have received a copy of the GNU Lesser General Public License
|
||
along with JSXCompressor. If not, see <http://www.gnu.org/licenses/>.
|
||
|
||
You should have received a copy of the Apache License along with JSXCompressor.
|
||
If not, see <http://www.apache.org/licenses/>.
|
||
|
||
*/
|
||
|
||
/**
|
||
* @class Util class
|
||
* @classdesc Utilities for uncompressing and base64 decoding
|
||
* Class for gunzipping, unzipping and base64 decoding of files.
|
||
* It is used for reading GEONExT, Geogebra and Intergeo files.
|
||
*
|
||
* Only Huffman codes are decoded in gunzip.
|
||
* The code is based on the source code for gunzip.c by Pasi Ojala
|
||
* {@link http://www.cs.tut.fi/~albert/Dev/gunzip/gunzip.c}
|
||
* {@link http://www.cs.tut.fi/~albert}
|
||
*/
|
||
JXG.Util = {};
|
||
|
||
/**
|
||
* Unzip zip files
|
||
*/
|
||
JXG.Util.Unzip = function(barray) {
|
||
var outputArr = [],
|
||
output = "",
|
||
debug = false,
|
||
gpflags,
|
||
files = 0,
|
||
unzipped = [],
|
||
crc,
|
||
buf32k = new Array(32768),
|
||
bIdx = 0,
|
||
modeZIP = false,
|
||
|
||
CRC, SIZE,
|
||
|
||
bitReverse = [
|
||
0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
|
||
0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
|
||
0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
|
||
0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
|
||
0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
|
||
0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
|
||
0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
|
||
0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
|
||
0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
|
||
0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
|
||
0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
|
||
0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
|
||
0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
|
||
0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
|
||
0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
|
||
0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
|
||
0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
|
||
0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
|
||
0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
|
||
0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
|
||
0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
|
||
0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
|
||
0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
|
||
0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
|
||
0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
|
||
0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
|
||
0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
|
||
0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
|
||
0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
|
||
0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
|
||
0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
|
||
0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
|
||
],
|
||
|
||
cplens = [
|
||
3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
|
||
35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0
|
||
],
|
||
|
||
cplext = [
|
||
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
|
||
3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99
|
||
],
|
||
/* 99==invalid */
|
||
|
||
cpdist = [
|
||
0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0007, 0x0009, 0x000d,
|
||
0x0011, 0x0019, 0x0021, 0x0031, 0x0041, 0x0061, 0x0081, 0x00c1,
|
||
0x0101, 0x0181, 0x0201, 0x0301, 0x0401, 0x0601, 0x0801, 0x0c01,
|
||
0x1001, 0x1801, 0x2001, 0x3001, 0x4001, 0x6001
|
||
],
|
||
|
||
cpdext = [
|
||
0, 0, 0, 0, 1, 1, 2, 2,
|
||
3, 3, 4, 4, 5, 5, 6, 6,
|
||
7, 7, 8, 8, 9, 9, 10, 10,
|
||
11, 11, 12, 12, 13, 13
|
||
],
|
||
|
||
border = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15],
|
||
|
||
bA = barray,
|
||
|
||
bytepos = 0,
|
||
bitpos = 0,
|
||
bb = 1,
|
||
bits = 0,
|
||
|
||
NAMEMAX = 256,
|
||
|
||
nameBuf = [],
|
||
|
||
fileout;
|
||
|
||
function readByte() {
|
||
bits += 8;
|
||
if (bytepos < bA.length) {
|
||
//if (debug)
|
||
// document.write(bytepos+": "+bA[bytepos]+"<br>");
|
||
return bA[bytepos++];
|
||
} else
|
||
return -1;
|
||
};
|
||
|
||
function byteAlign() {
|
||
bb = 1;
|
||
};
|
||
|
||
function readBit() {
|
||
var carry;
|
||
bits++;
|
||
carry = (bb & 1);
|
||
bb >>= 1;
|
||
if (bb == 0) {
|
||
bb = readByte();
|
||
carry = (bb & 1);
|
||
bb = (bb >> 1) | 0x80;
|
||
}
|
||
return carry;
|
||
};
|
||
|
||
function readBits(a) {
|
||
var res = 0,
|
||
i = a;
|
||
|
||
while (i--) {
|
||
res = (res << 1) | readBit();
|
||
}
|
||
if (a) {
|
||
res = bitReverse[res] >> (8 - a);
|
||
}
|
||
return res;
|
||
};
|
||
|
||
function flushBuffer() {
|
||
//document.write('FLUSHBUFFER:'+buf32k);
|
||
bIdx = 0;
|
||
};
|
||
|
||
function addBuffer(a) {
|
||
SIZE++;
|
||
//CRC=updcrc(a,crc);
|
||
buf32k[bIdx++] = a;
|
||
outputArr.push(String.fromCharCode(a));
|
||
//output+=String.fromCharCode(a);
|
||
if (bIdx == 0x8000) {
|
||
//document.write('ADDBUFFER:'+buf32k);
|
||
bIdx = 0;
|
||
}
|
||
};
|
||
|
||
function HufNode() {
|
||
this.b0 = 0;
|
||
this.b1 = 0;
|
||
this.jump = null;
|
||
this.jumppos = -1;
|
||
};
|
||
|
||
var LITERALS = 288;
|
||
|
||
var literalTree = new Array(LITERALS);
|
||
var distanceTree = new Array(32);
|
||
var treepos = 0;
|
||
var Places = null;
|
||
var Places2 = null;
|
||
|
||
var impDistanceTree = new Array(64);
|
||
var impLengthTree = new Array(64);
|
||
|
||
var len = 0;
|
||
var fpos = new Array(17);
|
||
fpos[0] = 0;
|
||
var flens;
|
||
var fmax;
|
||
|
||
function IsPat() {
|
||
while (1) {
|
||
if (fpos[len] >= fmax)
|
||
return -1;
|
||
if (flens[fpos[len]] == len)
|
||
return fpos[len]++;
|
||
fpos[len]++;
|
||
}
|
||
};
|
||
|
||
function Rec() {
|
||
var curplace = Places[treepos];
|
||
var tmp;
|
||
if (debug)
|
||
document.write("<br>len:" + len + " treepos:" + treepos);
|
||
if (len == 17) { //war 17
|
||
return -1;
|
||
}
|
||
treepos++;
|
||
len++;
|
||
|
||
tmp = IsPat();
|
||
if (debug)
|
||
document.write("<br>IsPat " + tmp);
|
||
if (tmp >= 0) {
|
||
curplace.b0 = tmp; /* leaf cell for 0-bit */
|
||
if (debug)
|
||
document.write("<br>b0 " + curplace.b0);
|
||
} else {
|
||
/* Not a Leaf cell */
|
||
curplace.b0 = 0x8000;
|
||
if (debug)
|
||
document.write("<br>b0 " + curplace.b0);
|
||
if (Rec())
|
||
return -1;
|
||
}
|
||
tmp = IsPat();
|
||
if (tmp >= 0) {
|
||
curplace.b1 = tmp; /* leaf cell for 1-bit */
|
||
if (debug)
|
||
document.write("<br>b1 " + curplace.b1);
|
||
curplace.jump = null; /* Just for the display routine */
|
||
} else {
|
||
/* Not a Leaf cell */
|
||
curplace.b1 = 0x8000;
|
||
if (debug)
|
||
document.write("<br>b1 " + curplace.b1);
|
||
curplace.jump = Places[treepos];
|
||
curplace.jumppos = treepos;
|
||
if (Rec())
|
||
return -1;
|
||
}
|
||
len--;
|
||
return 0;
|
||
};
|
||
|
||
function CreateTree(currentTree, numval, lengths, show) {
|
||
var i;
|
||
/* Create the Huffman decode tree/table */
|
||
//document.write("<br>createtree<br>");
|
||
if (debug)
|
||
document.write("currentTree " + currentTree + " numval " + numval + " lengths " + lengths + " show " + show);
|
||
Places = currentTree;
|
||
treepos = 0;
|
||
flens = lengths;
|
||
fmax = numval;
|
||
for (i = 0; i < 17; i++)
|
||
fpos[i] = 0;
|
||
len = 0;
|
||
if (Rec()) {
|
||
//fprintf(stderr, "invalid huffman tree\n");
|
||
if (debug)
|
||
alert("invalid huffman tree\n");
|
||
return -1;
|
||
}
|
||
if (debug) {
|
||
document.write('<br>Tree: ' + Places.length);
|
||
for (var a = 0; a < 32; a++) {
|
||
document.write("Places[" + a + "].b0=" + Places[a].b0 + "<br>");
|
||
document.write("Places[" + a + "].b1=" + Places[a].b1 + "<br>");
|
||
}
|
||
}
|
||
|
||
/*if(show) {
|
||
var tmp;
|
||
for(tmp=currentTree;tmp<Places;tmp++) {
|
||
fprintf(stdout, "0x%03x 0x%03x (0x%04x)",tmp-currentTree, tmp->jump?tmp->jump-currentTree:0,(tmp->jump?tmp->jump-currentTree:0)*6+0xcf0);
|
||
if(!(tmp.b0 & 0x8000)) {
|
||
//fprintf(stdout, " 0x%03x (%c)", tmp->b0,(tmp->b0<256 && isprint(tmp->b0))?tmp->b0:'<27>');
|
||
}
|
||
if(!(tmp.b1 & 0x8000)) {
|
||
if((tmp.b0 & 0x8000))
|
||
fprintf(stdout, " ");
|
||
fprintf(stdout, " 0x%03x (%c)", tmp->b1,(tmp->b1<256 && isprint(tmp->b1))?tmp->b1:'<27>');
|
||
}
|
||
fprintf(stdout, "\n");
|
||
}
|
||
}*/
|
||
return 0;
|
||
};
|
||
|
||
function DecodeValue(currentTree) {
|
||
var len, i,
|
||
xtreepos = 0,
|
||
X = currentTree[xtreepos],
|
||
b;
|
||
|
||
/* decode one symbol of the data */
|
||
while (1) {
|
||
b = readBit();
|
||
if (debug)
|
||
document.write("b=" + b);
|
||
if (b) {
|
||
if (!(X.b1 & 0x8000)) {
|
||
if (debug)
|
||
document.write("ret1");
|
||
return X.b1; /* If leaf node, return data */
|
||
}
|
||
X = X.jump;
|
||
len = currentTree.length;
|
||
for (i = 0; i < len; i++) {
|
||
if (currentTree[i] === X) {
|
||
xtreepos = i;
|
||
break;
|
||
}
|
||
}
|
||
//xtreepos++;
|
||
} else {
|
||
if (!(X.b0 & 0x8000)) {
|
||
if (debug)
|
||
document.write("ret2");
|
||
return X.b0; /* If leaf node, return data */
|
||
}
|
||
//X++; //??????????????????
|
||
xtreepos++;
|
||
X = currentTree[xtreepos];
|
||
}
|
||
}
|
||
};
|
||
|
||
function DeflateLoop() {
|
||
var last, c, type, i, len;
|
||
|
||
do {
|
||
/*if((last = readBit())){
|
||
fprintf(errfp, "Last Block: ");
|
||
} else {
|
||
fprintf(errfp, "Not Last Block: ");
|
||
}*/
|
||
last = readBit();
|
||
type = readBits(2);
|
||
switch (type) {
|
||
case 0:
|
||
if (debug)
|
||
alert("Stored\n");
|
||
break;
|
||
case 1:
|
||
if (debug)
|
||
alert("Fixed Huffman codes\n");
|
||
break;
|
||
case 2:
|
||
if (debug)
|
||
alert("Dynamic Huffman codes\n");
|
||
break;
|
||
case 3:
|
||
if (debug)
|
||
alert("Reserved block type!!\n");
|
||
break;
|
||
default:
|
||
if (debug)
|
||
alert("Unexpected value %d!\n", type);
|
||
break;
|
||
}
|
||
|
||
if (type == 0) {
|
||
var blockLen, cSum;
|
||
|
||
// Stored
|
||
byteAlign();
|
||
blockLen = readByte();
|
||
blockLen |= (readByte() << 8);
|
||
|
||
cSum = readByte();
|
||
cSum |= (readByte() << 8);
|
||
|
||
if (((blockLen ^ ~cSum) & 0xffff)) {
|
||
document.write("BlockLen checksum mismatch\n");
|
||
}
|
||
while (blockLen--) {
|
||
c = readByte();
|
||
addBuffer(c);
|
||
}
|
||
} else if (type == 1) {
|
||
var j;
|
||
|
||
/* Fixed Huffman tables -- fixed decode routine */
|
||
while (1) {
|
||
/*
|
||
256 0000000 0
|
||
: : :
|
||
279 0010111 23
|
||
0 00110000 48
|
||
: : :
|
||
143 10111111 191
|
||
280 11000000 192
|
||
: : :
|
||
287 11000111 199
|
||
144 110010000 400
|
||
: : :
|
||
255 111111111 511
|
||
|
||
Note the bit order!
|
||
*/
|
||
|
||
j = (bitReverse[readBits(7)] >> 1);
|
||
if (j > 23) {
|
||
j = (j << 1) | readBit(); /* 48..255 */
|
||
|
||
if (j > 199) { /* 200..255 */
|
||
j -= 128; /* 72..127 */
|
||
j = (j << 1) | readBit(); /* 144..255 << */
|
||
} else { /* 48..199 */
|
||
j -= 48; /* 0..151 */
|
||
if (j > 143) {
|
||
j = j + 136; /* 280..287 << */
|
||
/* 0..143 << */
|
||
}
|
||
}
|
||
} else { /* 0..23 */
|
||
j += 256; /* 256..279 << */
|
||
}
|
||
if (j < 256) {
|
||
addBuffer(j);
|
||
//document.write("out:"+String.fromCharCode(j));
|
||
/*fprintf(errfp, "@%d %02x\n", SIZE, j);*/
|
||
} else if (j == 256) {
|
||
/* EOF */
|
||
break;
|
||
} else {
|
||
var len, dist;
|
||
|
||
j -= 256 + 1; /* bytes + EOF */
|
||
len = readBits(cplext[j]) + cplens[j];
|
||
|
||
j = bitReverse[readBits(5)] >> 3;
|
||
if (cpdext[j] > 8) {
|
||
dist = readBits(8);
|
||
dist |= (readBits(cpdext[j] - 8) << 8);
|
||
} else {
|
||
dist = readBits(cpdext[j]);
|
||
}
|
||
dist += cpdist[j];
|
||
|
||
/*fprintf(errfp, "@%d (l%02x,d%04x)\n", SIZE, len, dist);*/
|
||
for (j = 0; j < len; j++) {
|
||
var c = buf32k[(bIdx - dist) & 0x7fff];
|
||
addBuffer(c);
|
||
}
|
||
}
|
||
} // while
|
||
} else if (type == 2) {
|
||
var j, n, literalCodes, distCodes, lenCodes;
|
||
var ll = new Array(288 + 32); // "static" just to preserve stack
|
||
|
||
// Dynamic Huffman tables
|
||
|
||
literalCodes = 257 + readBits(5);
|
||
distCodes = 1 + readBits(5);
|
||
lenCodes = 4 + readBits(4);
|
||
//document.write("<br>param: "+literalCodes+" "+distCodes+" "+lenCodes+"<br>");
|
||
for (j = 0; j < 19; j++) {
|
||
ll[j] = 0;
|
||
}
|
||
|
||
// Get the decode tree code lengths
|
||
|
||
//document.write("<br>");
|
||
for (j = 0; j < lenCodes; j++) {
|
||
ll[border[j]] = readBits(3);
|
||
//document.write(ll[border[j]]+" ");
|
||
}
|
||
//fprintf(errfp, "\n");
|
||
//document.write('<br>ll:'+ll);
|
||
len = distanceTree.length;
|
||
for (i = 0; i < len; i++)
|
||
distanceTree[i] = new HufNode();
|
||
if (CreateTree(distanceTree, 19, ll, 0)) {
|
||
flushBuffer();
|
||
return 1;
|
||
}
|
||
if (debug) {
|
||
document.write("<br>distanceTree");
|
||
for (var a = 0; a < distanceTree.length; a++) {
|
||
document.write("<br>" + distanceTree[a].b0 + " " + distanceTree[a].b1 + " " + distanceTree[a].jump + " " +
|
||
distanceTree[a].jumppos);
|
||
/*if (distanceTree[a].jumppos!=-1)
|
||
document.write(" "+distanceTree[a].jump.b0+" "+distanceTree[a].jump.b1);
|
||
*/
|
||
}
|
||
}
|
||
//document.write('<BR>tree created');
|
||
|
||
//read in literal and distance code lengths
|
||
n = literalCodes + distCodes;
|
||
i = 0;
|
||
var z = -1;
|
||
if (debug)
|
||
document.write("<br>n=" + n + " bits: " + bits + "<br>");
|
||
while (i < n) {
|
||
z++;
|
||
j = DecodeValue(distanceTree);
|
||
if (debug)
|
||
document.write("<br>" + z + " i:" + i + " decode: " + j + " bits " + bits + "<br>");
|
||
if (j < 16) { // length of code in bits (0..15)
|
||
ll[i++] = j;
|
||
} else if (j == 16) { // repeat last length 3 to 6 times
|
||
var l;
|
||
j = 3 + readBits(2);
|
||
if (i + j > n) {
|
||
flushBuffer();
|
||
return 1;
|
||
}
|
||
l = i ? ll[i - 1] : 0;
|
||
while (j--) {
|
||
ll[i++] = l;
|
||
}
|
||
} else {
|
||
if (j == 17) { // 3 to 10 zero length codes
|
||
j = 3 + readBits(3);
|
||
} else { // j == 18: 11 to 138 zero length codes
|
||
j = 11 + readBits(7);
|
||
}
|
||
if (i + j > n) {
|
||
flushBuffer();
|
||
return 1;
|
||
}
|
||
while (j--) {
|
||
ll[i++] = 0;
|
||
}
|
||
}
|
||
}
|
||
/*for(j=0; j<literalCodes+distCodes; j++) {
|
||
//fprintf(errfp, "%d ", ll[j]);
|
||
if ((j&7)==7)
|
||
fprintf(errfp, "\n");
|
||
}
|
||
fprintf(errfp, "\n");*/
|
||
// Can overwrite tree decode tree as it is not used anymore
|
||
len = literalTree.length;
|
||
for (i = 0; i < len; i++)
|
||
literalTree[i] = new HufNode();
|
||
if (CreateTree(literalTree, literalCodes, ll, 0)) {
|
||
flushBuffer();
|
||
return 1;
|
||
}
|
||
len = literalTree.length;
|
||
for (i = 0; i < len; i++)
|
||
distanceTree[i] = new HufNode();
|
||
var ll2 = new Array();
|
||
for (i = literalCodes; i < ll.length; i++) {
|
||
ll2[i - literalCodes] = ll[i];
|
||
}
|
||
if (CreateTree(distanceTree, distCodes, ll2, 0)) {
|
||
flushBuffer();
|
||
return 1;
|
||
}
|
||
if (debug)
|
||
document.write("<br>literalTree");
|
||
outer: while (1) {
|
||
j = DecodeValue(literalTree);
|
||
if (j >= 256) { // In C64: if carry set
|
||
var len, dist;
|
||
j -= 256;
|
||
if (j == 0) {
|
||
// EOF
|
||
break;
|
||
}
|
||
j--;
|
||
len = readBits(cplext[j]) + cplens[j];
|
||
|
||
j = DecodeValue(distanceTree);
|
||
if (cpdext[j] > 8) {
|
||
dist = readBits(8);
|
||
dist |= (readBits(cpdext[j] - 8) << 8);
|
||
} else {
|
||
dist = readBits(cpdext[j]);
|
||
}
|
||
dist += cpdist[j];
|
||
while (len--) {
|
||
if (bIdx - dist < 0) {
|
||
break outer;
|
||
}
|
||
var c = buf32k[(bIdx - dist) & 0x7fff];
|
||
addBuffer(c);
|
||
}
|
||
} else {
|
||
addBuffer(j);
|
||
}
|
||
}
|
||
}
|
||
} while (!last);
|
||
flushBuffer();
|
||
|
||
byteAlign();
|
||
return 0;
|
||
};
|
||
|
||
JXG.Util.Unzip.prototype.unzipFile = function(name) {
|
||
var i;
|
||
this.unzip();
|
||
//alert(unzipped[0][1]);
|
||
for (i = 0; i < unzipped.length; i++) {
|
||
if (unzipped[i][1] == name) {
|
||
return unzipped[i][0];
|
||
}
|
||
}
|
||
|
||
};
|
||
|
||
JXG.Util.Unzip.prototype.deflate = function() {
|
||
outputArr = [];
|
||
var tmp = [];
|
||
modeZIP = false;
|
||
DeflateLoop();
|
||
if (debug)
|
||
alert(outputArr.join(''));
|
||
unzipped[files] = new Array(2);
|
||
unzipped[files][0] = outputArr.join('');
|
||
unzipped[files][1] = "DEFLATE";
|
||
files++;
|
||
return unzipped;
|
||
}
|
||
|
||
JXG.Util.Unzip.prototype.unzip = function() {
|
||
//convertToByteArray(input);
|
||
if (debug)
|
||
alert(bA);
|
||
/*for (i=0;i<bA.length*8;i++){
|
||
document.write(readBit());
|
||
if ((i+1)%8==0)
|
||
document.write(" ");
|
||
}*/
|
||
/*for (i=0;i<bA.length;i++){
|
||
document.write(readByte()+" ");
|
||
if ((i+1)%8==0)
|
||
document.write(" ");
|
||
}
|
||
for (i=0;i<bA.length;i++){
|
||
document.write(bA[i]+" ");
|
||
if ((i+1)%16==0)
|
||
document.write("<br>");
|
||
}
|
||
*/
|
||
//alert(bA);
|
||
nextFile();
|
||
return unzipped;
|
||
};
|
||
|
||
function nextFile() {
|
||
if (debug)
|
||
alert("NEXTFILE");
|
||
outputArr = [];
|
||
var tmp = [];
|
||
modeZIP = false;
|
||
tmp[0] = readByte();
|
||
tmp[1] = readByte();
|
||
if (debug)
|
||
alert("type: " + tmp[0] + " " + tmp[1]);
|
||
if (tmp[0] == parseInt("78", 16) && tmp[1] == parseInt("da", 16)) { //GZIP
|
||
if (debug)
|
||
alert("GEONExT-GZIP");
|
||
DeflateLoop();
|
||
if (debug)
|
||
alert(outputArr.join(''));
|
||
unzipped[files] = new Array(2);
|
||
unzipped[files][0] = outputArr.join('');
|
||
unzipped[files][1] = "geonext.gxt";
|
||
files++;
|
||
}
|
||
if (tmp[0] == parseInt("78", 16) && tmp[1] == parseInt("9c", 16)) { //ZLIB
|
||
if (debug)
|
||
alert("ZLIB");
|
||
DeflateLoop();
|
||
if (debug)
|
||
alert(outputArr.join(''));
|
||
unzipped[files] = new Array(2);
|
||
unzipped[files][0] = outputArr.join('');
|
||
unzipped[files][1] = "ZLIB";
|
||
files++;
|
||
}
|
||
if (tmp[0] == parseInt("1f", 16) && tmp[1] == parseInt("8b", 16)) { //GZIP
|
||
if (debug)
|
||
alert("GZIP");
|
||
//DeflateLoop();
|
||
skipdir();
|
||
if (debug)
|
||
alert(outputArr.join(''));
|
||
unzipped[files] = new Array(2);
|
||
unzipped[files][0] = outputArr.join('');
|
||
unzipped[files][1] = "file";
|
||
files++;
|
||
}
|
||
if (tmp[0] == parseInt("50", 16) && tmp[1] == parseInt("4b", 16)) { //ZIP
|
||
modeZIP = true;
|
||
tmp[2] = readByte();
|
||
tmp[3] = readByte();
|
||
if (tmp[2] == parseInt("3", 16) && tmp[3] == parseInt("4", 16)) {
|
||
//MODE_ZIP
|
||
tmp[0] = readByte();
|
||
tmp[1] = readByte();
|
||
if (debug)
|
||
alert("ZIP-Version: " + tmp[1] + " " + tmp[0] / 10 + "." + tmp[0] % 10);
|
||
|
||
gpflags = readByte();
|
||
gpflags |= (readByte() << 8);
|
||
if (debug)
|
||
alert("gpflags: " + gpflags);
|
||
|
||
var method = readByte();
|
||
method |= (readByte() << 8);
|
||
if (debug)
|
||
alert("method: " + method);
|
||
|
||
readByte();
|
||
readByte();
|
||
readByte();
|
||
readByte();
|
||
|
||
var crc = readByte();
|
||
crc |= (readByte() << 8);
|
||
crc |= (readByte() << 16);
|
||
crc |= (readByte() << 24);
|
||
|
||
var compSize = readByte();
|
||
compSize |= (readByte() << 8);
|
||
compSize |= (readByte() << 16);
|
||
compSize |= (readByte() << 24);
|
||
|
||
var size = readByte();
|
||
size |= (readByte() << 8);
|
||
size |= (readByte() << 16);
|
||
size |= (readByte() << 24);
|
||
|
||
if (debug)
|
||
alert("local CRC: " + crc + "\nlocal Size: " + size + "\nlocal CompSize: " + compSize);
|
||
|
||
var filelen = readByte();
|
||
filelen |= (readByte() << 8);
|
||
|
||
var extralen = readByte();
|
||
extralen |= (readByte() << 8);
|
||
|
||
if (debug)
|
||
alert("filelen " + filelen);
|
||
i = 0;
|
||
nameBuf = [];
|
||
while (filelen--) {
|
||
var c = readByte();
|
||
if (c == "/" | c == ":") {
|
||
i = 0;
|
||
} else if (i < NAMEMAX - 1)
|
||
nameBuf[i++] = String.fromCharCode(c);
|
||
}
|
||
if (debug)
|
||
alert("nameBuf: " + nameBuf);
|
||
|
||
//nameBuf[i] = "\0";
|
||
if (!fileout)
|
||
fileout = nameBuf;
|
||
|
||
var i = 0;
|
||
while (i < extralen) {
|
||
c = readByte();
|
||
i++;
|
||
}
|
||
|
||
CRC = 0xffffffff;
|
||
SIZE = 0;
|
||
|
||
if (size == 0 && fileOut.charAt(fileout.length - 1) == "/") {
|
||
//skipdir
|
||
if (debug)
|
||
alert("skipdir");
|
||
}
|
||
if (method == 8) {
|
||
DeflateLoop();
|
||
if (debug)
|
||
alert(outputArr.join(''));
|
||
unzipped[files] = new Array(2);
|
||
unzipped[files][0] = outputArr.join('');
|
||
unzipped[files][1] = nameBuf.join('');
|
||
files++;
|
||
//return outputArr.join('');
|
||
}
|
||
skipdir();
|
||
}
|
||
}
|
||
};
|
||
|
||
function skipdir() {
|
||
var crc,
|
||
tmp = [],
|
||
compSize, size, os, i, c;
|
||
|
||
if ((gpflags & 8)) {
|
||
tmp[0] = readByte();
|
||
tmp[1] = readByte();
|
||
tmp[2] = readByte();
|
||
tmp[3] = readByte();
|
||
|
||
if (tmp[0] == parseInt("50", 16) &&
|
||
tmp[1] == parseInt("4b", 16) &&
|
||
tmp[2] == parseInt("07", 16) &&
|
||
tmp[3] == parseInt("08", 16)) {
|
||
crc = readByte();
|
||
crc |= (readByte() << 8);
|
||
crc |= (readByte() << 16);
|
||
crc |= (readByte() << 24);
|
||
} else {
|
||
crc = tmp[0] | (tmp[1] << 8) | (tmp[2] << 16) | (tmp[3] << 24);
|
||
}
|
||
|
||
compSize = readByte();
|
||
compSize |= (readByte() << 8);
|
||
compSize |= (readByte() << 16);
|
||
compSize |= (readByte() << 24);
|
||
|
||
size = readByte();
|
||
size |= (readByte() << 8);
|
||
size |= (readByte() << 16);
|
||
size |= (readByte() << 24);
|
||
|
||
if (debug)
|
||
alert("CRC:");
|
||
}
|
||
|
||
if (modeZIP)
|
||
nextFile();
|
||
|
||
tmp[0] = readByte();
|
||
if (tmp[0] != 8) {
|
||
if (debug)
|
||
alert("Unknown compression method!");
|
||
return 0;
|
||
}
|
||
|
||
gpflags = readByte();
|
||
if (debug) {
|
||
if ((gpflags & ~(parseInt("1f", 16))))
|
||
alert("Unknown flags set!");
|
||
}
|
||
|
||
readByte();
|
||
readByte();
|
||
readByte();
|
||
readByte();
|
||
|
||
readByte();
|
||
os = readByte();
|
||
|
||
if ((gpflags & 4)) {
|
||
tmp[0] = readByte();
|
||
tmp[2] = readByte();
|
||
len = tmp[0] + 256 * tmp[1];
|
||
if (debug)
|
||
alert("Extra field size: " + len);
|
||
for (i = 0; i < len; i++)
|
||
readByte();
|
||
}
|
||
|
||
if ((gpflags & 8)) {
|
||
i = 0;
|
||
nameBuf = [];
|
||
while (c = readByte()) {
|
||
if (c == "7" || c == ":")
|
||
i = 0;
|
||
if (i < NAMEMAX - 1)
|
||
nameBuf[i++] = c;
|
||
}
|
||
//nameBuf[i] = "\0";
|
||
if (debug)
|
||
alert("original file name: " + nameBuf);
|
||
}
|
||
|
||
if ((gpflags & 16)) {
|
||
while (c = readByte()) {
|
||
//FILE COMMENT
|
||
}
|
||
}
|
||
|
||
if ((gpflags & 2)) {
|
||
readByte();
|
||
readByte();
|
||
}
|
||
|
||
DeflateLoop();
|
||
|
||
crc = readByte();
|
||
crc |= (readByte() << 8);
|
||
crc |= (readByte() << 16);
|
||
crc |= (readByte() << 24);
|
||
|
||
size = readByte();
|
||
size |= (readByte() << 8);
|
||
size |= (readByte() << 16);
|
||
size |= (readByte() << 24);
|
||
|
||
if (modeZIP)
|
||
nextFile();
|
||
|
||
};
|
||
|
||
};
|
||
|
||
/**
|
||
* Base64 encoding / decoding
|
||
* {@link http://www.webtoolkit.info/}
|
||
*/
|
||
JXG.Util.Base64 = {
|
||
|
||
// private property
|
||
_keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
|
||
|
||
// public method for encoding
|
||
encode: function(input) {
|
||
var output = [],
|
||
chr1, chr2, chr3, enc1, enc2, enc3, enc4,
|
||
i = 0;
|
||
|
||
input = JXG.Util.Base64._utf8_encode(input);
|
||
|
||
while (i < input.length) {
|
||
|
||
chr1 = input.charCodeAt(i++);
|
||
chr2 = input.charCodeAt(i++);
|
||
chr3 = input.charCodeAt(i++);
|
||
|
||
enc1 = chr1 >> 2;
|
||
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
|
||
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
|
||
enc4 = chr3 & 63;
|
||
|
||
if (isNaN(chr2)) {
|
||
enc3 = enc4 = 64;
|
||
} else if (isNaN(chr3)) {
|
||
enc4 = 64;
|
||
}
|
||
|
||
output.push([this._keyStr.charAt(enc1),
|
||
this._keyStr.charAt(enc2),
|
||
this._keyStr.charAt(enc3),
|
||
this._keyStr.charAt(enc4)
|
||
].join(''));
|
||
}
|
||
|
||
return output.join('');
|
||
},
|
||
|
||
// public method for decoding
|
||
decode: function(input, utf8) {
|
||
var output = [],
|
||
chr1, chr2, chr3,
|
||
enc1, enc2, enc3, enc4,
|
||
i = 0;
|
||
|
||
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
|
||
|
||
while (i < input.length) {
|
||
|
||
enc1 = this._keyStr.indexOf(input.charAt(i++));
|
||
enc2 = this._keyStr.indexOf(input.charAt(i++));
|
||
enc3 = this._keyStr.indexOf(input.charAt(i++));
|
||
enc4 = this._keyStr.indexOf(input.charAt(i++));
|
||
|
||
chr1 = (enc1 << 2) | (enc2 >> 4);
|
||
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
|
||
chr3 = ((enc3 & 3) << 6) | enc4;
|
||
|
||
output.push(String.fromCharCode(chr1));
|
||
|
||
if (enc3 != 64) {
|
||
output.push(String.fromCharCode(chr2));
|
||
}
|
||
if (enc4 != 64) {
|
||
output.push(String.fromCharCode(chr3));
|
||
}
|
||
}
|
||
|
||
output = output.join('');
|
||
|
||
if (utf8) {
|
||
output = JXG.Util.Base64._utf8_decode(output);
|
||
}
|
||
return output;
|
||
|
||
},
|
||
|
||
// private method for UTF-8 encoding
|
||
_utf8_encode: function(string) {
|
||
string = string.replace(/\r\n/g, "\n");
|
||
var utftext = "";
|
||
|
||
for (var n = 0; n < string.length; n++) {
|
||
|
||
var c = string.charCodeAt(n);
|
||
|
||
if (c < 128) {
|
||
utftext += String.fromCharCode(c);
|
||
} else if ((c > 127) && (c < 2048)) {
|
||
utftext += String.fromCharCode((c >> 6) | 192);
|
||
utftext += String.fromCharCode((c & 63) | 128);
|
||
} else {
|
||
utftext += String.fromCharCode((c >> 12) | 224);
|
||
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
|
||
utftext += String.fromCharCode((c & 63) | 128);
|
||
}
|
||
|
||
}
|
||
|
||
return utftext;
|
||
},
|
||
|
||
// private method for UTF-8 decoding
|
||
_utf8_decode: function(utftext) {
|
||
var string = [],
|
||
i = 0,
|
||
c = 0,
|
||
c2 = 0,
|
||
c3 = 0;
|
||
|
||
while (i < utftext.length) {
|
||
c = utftext.charCodeAt(i);
|
||
if (c < 128) {
|
||
string.push(String.fromCharCode(c));
|
||
i++;
|
||
} else if ((c > 191) && (c < 224)) {
|
||
c2 = utftext.charCodeAt(i + 1);
|
||
string.push(String.fromCharCode(((c & 31) << 6) | (c2 & 63)));
|
||
i += 2;
|
||
} else {
|
||
c2 = utftext.charCodeAt(i + 1);
|
||
c3 = utftext.charCodeAt(i + 2);
|
||
string.push(String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)));
|
||
i += 3;
|
||
}
|
||
}
|
||
return string.join('');
|
||
},
|
||
|
||
_destrip: function(stripped, wrap) {
|
||
var lines = [],
|
||
lineno, i,
|
||
destripped = [];
|
||
|
||
if (wrap == null)
|
||
wrap = 76;
|
||
|
||
stripped.replace(/ /g, "");
|
||
lineno = stripped.length / wrap;
|
||
for (i = 0; i < lineno; i++)
|
||
lines[i] = stripped.substr(i * wrap, wrap);
|
||
if (lineno != stripped.length / wrap)
|
||
lines[lines.length] = stripped.substr(lineno * wrap, stripped.length - (lineno * wrap));
|
||
|
||
for (i = 0; i < lines.length; i++)
|
||
destripped.push(lines[i]);
|
||
return destripped.join('\n');
|
||
},
|
||
|
||
decodeAsArray: function(input) {
|
||
var dec = this.decode(input),
|
||
ar = [],
|
||
i;
|
||
for (i = 0; i < dec.length; i++) {
|
||
ar[i] = dec.charCodeAt(i);
|
||
}
|
||
return ar;
|
||
},
|
||
|
||
decodeGEONExT: function(input) {
|
||
return decodeAsArray(destrip(input), false);
|
||
}
|
||
};
|
||
|
||
/**
|
||
* @private
|
||
*/
|
||
JXG.Util.asciiCharCodeAt = function(str, i) {
|
||
var c = str.charCodeAt(i);
|
||
if (c > 255) {
|
||
switch (c) {
|
||
case 8364:
|
||
c = 128;
|
||
break;
|
||
case 8218:
|
||
c = 130;
|
||
break;
|
||
case 402:
|
||
c = 131;
|
||
break;
|
||
case 8222:
|
||
c = 132;
|
||
break;
|
||
case 8230:
|
||
c = 133;
|
||
break;
|
||
case 8224:
|
||
c = 134;
|
||
break;
|
||
case 8225:
|
||
c = 135;
|
||
break;
|
||
case 710:
|
||
c = 136;
|
||
break;
|
||
case 8240:
|
||
c = 137;
|
||
break;
|
||
case 352:
|
||
c = 138;
|
||
break;
|
||
case 8249:
|
||
c = 139;
|
||
break;
|
||
case 338:
|
||
c = 140;
|
||
break;
|
||
case 381:
|
||
c = 142;
|
||
break;
|
||
case 8216:
|
||
c = 145;
|
||
break;
|
||
case 8217:
|
||
c = 146;
|
||
break;
|
||
case 8220:
|
||
c = 147;
|
||
break;
|
||
case 8221:
|
||
c = 148;
|
||
break;
|
||
case 8226:
|
||
c = 149;
|
||
break;
|
||
case 8211:
|
||
c = 150;
|
||
break;
|
||
case 8212:
|
||
c = 151;
|
||
break;
|
||
case 732:
|
||
c = 152;
|
||
break;
|
||
case 8482:
|
||
c = 153;
|
||
break;
|
||
case 353:
|
||
c = 154;
|
||
break;
|
||
case 8250:
|
||
c = 155;
|
||
break;
|
||
case 339:
|
||
c = 156;
|
||
break;
|
||
case 382:
|
||
c = 158;
|
||
break;
|
||
case 376:
|
||
c = 159;
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
return c;
|
||
};
|
||
|
||
/**
|
||
* Decoding string into utf-8
|
||
* @param {String} string to decode
|
||
* @return {String} utf8 decoded string
|
||
*/
|
||
JXG.Util.utf8Decode = function(utftext) {
|
||
var string = [];
|
||
var i = 0;
|
||
var c = 0,
|
||
c1 = 0,
|
||
c2 = 0,
|
||
c3;
|
||
if (!JXG.exists(utftext)) return '';
|
||
|
||
while (i < utftext.length) {
|
||
c = utftext.charCodeAt(i);
|
||
|
||
if (c < 128) {
|
||
string.push(String.fromCharCode(c));
|
||
i++;
|
||
} else if ((c > 191) && (c < 224)) {
|
||
c2 = utftext.charCodeAt(i + 1);
|
||
string.push(String.fromCharCode(((c & 31) << 6) | (c2 & 63)));
|
||
i += 2;
|
||
} else {
|
||
c2 = utftext.charCodeAt(i + 1);
|
||
c3 = utftext.charCodeAt(i + 2);
|
||
string.push(String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)));
|
||
i += 3;
|
||
}
|
||
};
|
||
return string.join('');
|
||
};
|
||
|
||
/**
|
||
* Generate a random uuid.
|
||
* http://www.broofa.com
|
||
* mailto:robert@broofa.com
|
||
*
|
||
* Copyright (c) 2010 Robert Kieffer
|
||
* Dual licensed under the MIT and GPL licenses.
|
||
*
|
||
* EXAMPLES:
|
||
* >>> Math.uuid()
|
||
* "92329D39-6F5C-4520-ABFC-AAB64544E172"
|
||
*/
|
||
JXG.Util.genUUID = function() {
|
||
// Private array of chars to use
|
||
var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split(''),
|
||
uuid = new Array(36),
|
||
rnd = 0,
|
||
r;
|
||
|
||
for (var i = 0; i < 36; i++) {
|
||
if (i == 8 || i == 13 || i == 18 || i == 23) {
|
||
uuid[i] = '-';
|
||
} else if (i == 14) {
|
||
uuid[i] = '4';
|
||
} else {
|
||
if (rnd <= 0x02) rnd = 0x2000000 + (Math.random() * 0x1000000) | 0;
|
||
r = rnd & 0xf;
|
||
rnd = rnd >> 4;
|
||
uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
|
||
}
|
||
}
|
||
|
||
return uuid.join('');
|
||
};
|
||
|
||
|
||
module.exports = JXG;
|
||
|
||
},{}],3:[function(require,module,exports){
|
||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||
// Copyright (C) 2011 Recurity Labs GmbH
|
||
//
|
||
// This library is free software; you can redistribute it and/or
|
||
// modify it under the terms of the GNU Lesser General Public
|
||
// License as published by the Free Software Foundation; either
|
||
// version 2.1 of the License, or (at your option) any later version.
|
||
//
|
||
// This library is distributed in the hope that it will be useful,
|
||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
// Lesser General Public License for more details.
|
||
//
|
||
// You should have received a copy of the GNU Lesser General Public
|
||
// License along with this library; if not, write to the Free Software
|
||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||
|
||
var enums = require('../enums.js');
|
||
|
||
/**
|
||
*
|
||
* This object contains configuration values and implements
|
||
* storing and retrieving configuration them from HTML5 local storage.
|
||
*
|
||
* This object can be accessed after calling openpgp.init()
|
||
* using openpgp.config
|
||
* Stored config parameters can be accessed using
|
||
* openpgp.config.config
|
||
* @class
|
||
* @classdesc Implementation of the GPG4Browsers config object
|
||
*/
|
||
var config = function() {
|
||
/**
|
||
* @property {Integer} prefer_hash_algorithm
|
||
* @property {Integer} encryption_cipher
|
||
* @property {Integer} compression
|
||
* @property {Boolean} show_version
|
||
* @property {Boolean} show_comment
|
||
* @property {Boolean} integrity_protect
|
||
* @property {String} keyserver
|
||
*/
|
||
this.prefer_hash_algorithm = enums.hash.sha256;
|
||
this.encryption_cipher = enums.symmetric.aes256;
|
||
this.compression = enums.compression.zip;
|
||
this.show_version = true;
|
||
this.show_comment = true;
|
||
this.integrity_protect = true;
|
||
this.keyserver = "keyserver.linux.it"; // "pgp.mit.edu:11371"
|
||
|
||
this.versionstring = "OpenPGP.js VERSION";
|
||
this.commentstring = "http://openpgpjs.org";
|
||
|
||
/**
|
||
* If enabled, debug messages will be printed
|
||
*/
|
||
this.debug = false;
|
||
|
||
};
|
||
|
||
module.exports = new config();
|
||
|
||
},{"../enums.js":27}],4:[function(require,module,exports){
|
||
// Modified by Recurity Labs GmbH
|
||
|
||
// modified version of http://www.hanewin.net/encrypt/PGdecode.js:
|
||
|
||
/* OpenPGP encryption using RSA/AES
|
||
* Copyright 2005-2006 Herbert Hanewinkel, www.haneWIN.de
|
||
* version 2.0, check www.haneWIN.de for the latest version
|
||
|
||
* This software is provided as-is, without express or implied warranty.
|
||
* Permission to use, copy, modify, distribute or sell this software, with or
|
||
* without fee, for any purpose and by any individual or organization, is hereby
|
||
* granted, provided that the above copyright notice and this paragraph appear
|
||
* in all copies. Distribution as a part of an application or binary must
|
||
* include the above copyright notice in the documentation and/or other
|
||
* materials provided with the application or distribution.
|
||
*/
|
||
|
||
var util = require('../util'),
|
||
cipher = require('./cipher');
|
||
|
||
module.exports = {
|
||
|
||
/**
|
||
* An array of bytes, that is integers with values from 0 to 255
|
||
* @typedef {(Array|Uint8Array)} openpgp_byte_array
|
||
*/
|
||
|
||
/**
|
||
* Block cipher function
|
||
* @callback openpgp_cipher_block_fn
|
||
* @param {openpgp_byte_array} block A block to perform operations on
|
||
* @param {openpgp_byte_array} key to use in encryption/decryption
|
||
* @return {openpgp_byte_array} Encrypted/decrypted block
|
||
*/
|
||
|
||
|
||
// --------------------------------------
|
||
/**
|
||
* This function encrypts a given with the specified prefixrandom
|
||
* using the specified blockcipher to encrypt a message
|
||
* @param {String} prefixrandom random bytes of block_size length provided
|
||
* as a string to be used in prefixing the data
|
||
* @param {openpgp_cipher_block_fn} blockcipherfn the algorithm encrypt function to encrypt
|
||
* data in one block_size encryption.
|
||
* @param {Integer} block_size the block size in bytes of the algorithm used
|
||
* @param {String} plaintext data to be encrypted provided as a string
|
||
* @param {openpgp_byte_array} key key to be used to encrypt the data. This will be passed to the
|
||
* blockcipherfn
|
||
* @param {Boolean} resync a boolean value specifying if a resync of the
|
||
* IV should be used or not. The encrypteddatapacket uses the
|
||
* "old" style with a resync. Encryption within an
|
||
* encryptedintegrityprotecteddata packet is not resyncing the IV.
|
||
* @return {String} a string with the encrypted data
|
||
*/
|
||
encrypt: function(prefixrandom, cipherfn, plaintext, key, resync) {
|
||
cipherfn = new cipher[cipherfn](key);
|
||
var block_size = cipherfn.blockSize;
|
||
|
||
var FR = new Array(block_size);
|
||
var FRE = new Array(block_size);
|
||
|
||
prefixrandom = prefixrandom + prefixrandom.charAt(block_size - 2) + prefixrandom.charAt(block_size - 1);
|
||
util.print_debug("prefixrandom:" + util.hexstrdump(prefixrandom));
|
||
var ciphertext = "";
|
||
// 1. The feedback register (FR) is set to the IV, which is all zeros.
|
||
for (var i = 0; i < block_size; i++) FR[i] = 0;
|
||
|
||
// 2. FR is encrypted to produce FRE (FR Encrypted). This is the
|
||
// encryption of an all-zero value.
|
||
FRE = cipherfn.encrypt(FR);
|
||
// 3. FRE is xored with the first BS octets of random data prefixed to
|
||
// the plaintext to produce C[1] through C[BS], the first BS octets
|
||
// of ciphertext.
|
||
for (var i = 0; i < block_size; i++) ciphertext += String.fromCharCode(FRE[i] ^ prefixrandom.charCodeAt(i));
|
||
|
||
// 4. FR is loaded with C[1] through C[BS].
|
||
for (var i = 0; i < block_size; i++) FR[i] = ciphertext.charCodeAt(i);
|
||
|
||
// 5. FR is encrypted to produce FRE, the encryption of the first BS
|
||
// octets of ciphertext.
|
||
FRE = cipherfn.encrypt(FR);
|
||
|
||
// 6. The left two octets of FRE get xored with the next two octets of
|
||
// data that were prefixed to the plaintext. This produces C[BS+1]
|
||
// and C[BS+2], the next two octets of ciphertext.
|
||
ciphertext += String.fromCharCode(FRE[0] ^ prefixrandom.charCodeAt(block_size));
|
||
ciphertext += String.fromCharCode(FRE[1] ^ prefixrandom.charCodeAt(block_size + 1));
|
||
|
||
if (resync) {
|
||
// 7. (The resync step) FR is loaded with C3-C10.
|
||
for (var i = 0; i < block_size; i++) FR[i] = ciphertext.charCodeAt(i + 2);
|
||
} else {
|
||
for (var i = 0; i < block_size; i++) FR[i] = ciphertext.charCodeAt(i);
|
||
}
|
||
// 8. FR is encrypted to produce FRE.
|
||
FRE = cipherfn.encrypt(FR, key);
|
||
|
||
if (resync) {
|
||
// 9. FRE is xored with the first 8 octets of the given plaintext, now
|
||
// that we have finished encrypting the 10 octets of prefixed data.
|
||
// This produces C11-C18, the next 8 octets of ciphertext.
|
||
for (var i = 0; i < block_size; i++)
|
||
ciphertext += String.fromCharCode(FRE[i] ^ plaintext.charCodeAt(i));
|
||
for (n = block_size + 2; n < plaintext.length; n += block_size) {
|
||
// 10. FR is loaded with C11-C18
|
||
for (var i = 0; i < block_size; i++) FR[i] = ciphertext.charCodeAt(n + i);
|
||
|
||
// 11. FR is encrypted to produce FRE.
|
||
FRE = cipherfn.encrypt(FR);
|
||
|
||
// 12. FRE is xored with the next 8 octets of plaintext, to produce the
|
||
// next 8 octets of ciphertext. These are loaded into FR and the
|
||
// process is repeated until the plaintext is used up.
|
||
for (var i = 0; i < block_size; i++) ciphertext += String.fromCharCode(FRE[i] ^ plaintext.charCodeAt((n - 2) +
|
||
i));
|
||
}
|
||
} else {
|
||
plaintext = " " + plaintext;
|
||
// 9. FRE is xored with the first 8 octets of the given plaintext, now
|
||
// that we have finished encrypting the 10 octets of prefixed data.
|
||
// This produces C11-C18, the next 8 octets of ciphertext.
|
||
for (var i = 2; i < block_size; i++) ciphertext += String.fromCharCode(FRE[i] ^ plaintext.charCodeAt(i));
|
||
var tempCiphertext = ciphertext.substring(0, 2 * block_size).split('');
|
||
var tempCiphertextString = ciphertext.substring(block_size);
|
||
for (n = block_size; n < plaintext.length; n += block_size) {
|
||
// 10. FR is loaded with C11-C18
|
||
for (var i = 0; i < block_size; i++) FR[i] = tempCiphertextString.charCodeAt(i);
|
||
tempCiphertextString = '';
|
||
|
||
// 11. FR is encrypted to produce FRE.
|
||
FRE = cipherfn.encrypt(FR);
|
||
|
||
// 12. FRE is xored with the next 8 octets of plaintext, to produce the
|
||
// next 8 octets of ciphertext. These are loaded into FR and the
|
||
// process is repeated until the plaintext is used up.
|
||
for (var i = 0; i < block_size; i++) {
|
||
tempCiphertext.push(String.fromCharCode(FRE[i] ^ plaintext.charCodeAt(n + i)));
|
||
tempCiphertextString += String.fromCharCode(FRE[i] ^ plaintext.charCodeAt(n + i));
|
||
}
|
||
}
|
||
ciphertext = tempCiphertext.join('');
|
||
|
||
}
|
||
|
||
ciphertext = ciphertext.substring(0, plaintext.length + 2 + block_size);
|
||
|
||
return ciphertext;
|
||
},
|
||
|
||
/**
|
||
* Decrypts the prefixed data for the Modification Detection Code (MDC) computation
|
||
* @param {openpgp_block_cipher_fn} cipherfn.encrypt Cipher function to use
|
||
* @param {Integer} block_size Blocksize of the algorithm
|
||
* @param {openpgp_byte_array} key The key for encryption
|
||
* @param {String} ciphertext The encrypted data
|
||
* @return {String} plaintext Data of D(ciphertext) with blocksize length +2
|
||
*/
|
||
mdc: function(cipherfn, key, ciphertext) {
|
||
cipherfn = new cipher[cipherfn](key);
|
||
var block_size = cipherfn.blockSize;
|
||
|
||
var iblock = new Array(block_size);
|
||
var ablock = new Array(block_size);
|
||
var i;
|
||
|
||
|
||
// initialisation vector
|
||
for (i = 0; i < block_size; i++) iblock[i] = 0;
|
||
|
||
iblock = cipherfn.encrypt(iblock);
|
||
for (i = 0; i < block_size; i++) {
|
||
ablock[i] = ciphertext.charCodeAt(i);
|
||
iblock[i] ^= ablock[i];
|
||
}
|
||
|
||
ablock = cipherfn.encrypt(ablock);
|
||
|
||
return util.bin2str(iblock) +
|
||
String.fromCharCode(ablock[0] ^ ciphertext.charCodeAt(block_size)) +
|
||
String.fromCharCode(ablock[1] ^ ciphertext.charCodeAt(block_size + 1));
|
||
},
|
||
/**
|
||
* This function decrypts a given plaintext using the specified
|
||
* blockcipher to decrypt a message
|
||
* @param {openpgp_cipher_block_fn} blockcipherfn The algorithm _encrypt_ function to encrypt
|
||
* data in one block_size encryption.
|
||
* @param {Integer} block_size the block size in bytes of the algorithm used
|
||
* @param {String} plaintext ciphertext to be decrypted provided as a string
|
||
* @param {openpgp_byte_array} key key to be used to decrypt the ciphertext. This will be passed to the
|
||
* blockcipherfn
|
||
* @param {Boolean} resync a boolean value specifying if a resync of the
|
||
* IV should be used or not. The encrypteddatapacket uses the
|
||
* "old" style with a resync. Decryption within an
|
||
* encryptedintegrityprotecteddata packet is not resyncing the IV.
|
||
* @return {String} a string with the plaintext data
|
||
*/
|
||
|
||
decrypt: function(cipherfn, key, ciphertext, resync) {
|
||
cipherfn = new cipher[cipherfn](key);
|
||
var block_size = cipherfn.blockSize;
|
||
|
||
var iblock = new Array(block_size);
|
||
var ablock = new Array(block_size);
|
||
var i, n = '';
|
||
var text = [];
|
||
|
||
// initialisation vector
|
||
for (i = 0; i < block_size; i++) iblock[i] = 0;
|
||
|
||
iblock = cipherfn.encrypt(iblock, key);
|
||
for (i = 0; i < block_size; i++) {
|
||
ablock[i] = ciphertext.charCodeAt(i);
|
||
iblock[i] ^= ablock[i];
|
||
}
|
||
|
||
ablock = cipherfn.encrypt(ablock, key);
|
||
|
||
// test check octets
|
||
if (iblock[block_size - 2] != (ablock[0] ^ ciphertext.charCodeAt(block_size)) || iblock[block_size - 1] != (ablock[
|
||
1] ^ ciphertext.charCodeAt(block_size + 1))) {
|
||
throw new Error('Invalid data.');
|
||
}
|
||
|
||
/* RFC4880: Tag 18 and Resync:
|
||
* [...] Unlike the Symmetrically Encrypted Data Packet, no
|
||
* special CFB resynchronization is done after encrypting this prefix
|
||
* data. See "OpenPGP CFB Mode" below for more details.
|
||
|
||
*/
|
||
|
||
if (resync) {
|
||
for (i = 0; i < block_size; i++) iblock[i] = ciphertext.charCodeAt(i + 2);
|
||
for (n = block_size + 2; n < ciphertext.length; n += block_size) {
|
||
ablock = cipherfn.encrypt(iblock);
|
||
|
||
for (i = 0; i < block_size && i + n < ciphertext.length; i++) {
|
||
iblock[i] = ciphertext.charCodeAt(n + i);
|
||
text.push(String.fromCharCode(ablock[i] ^ iblock[i]));
|
||
}
|
||
}
|
||
} else {
|
||
for (i = 0; i < block_size; i++) iblock[i] = ciphertext.charCodeAt(i);
|
||
for (n = block_size; n < ciphertext.length; n += block_size) {
|
||
ablock = cipherfn.encrypt(iblock);
|
||
for (i = 0; i < block_size && i + n < ciphertext.length; i++) {
|
||
iblock[i] = ciphertext.charCodeAt(n + i);
|
||
text.push(String.fromCharCode(ablock[i] ^ iblock[i]));
|
||
}
|
||
}
|
||
}
|
||
|
||
var n = resync ? 0 : 2;
|
||
|
||
text = text.join('');
|
||
|
||
text = text.substring(n, ciphertext.length - block_size - 2 + n);
|
||
|
||
|
||
return text;
|
||
},
|
||
|
||
|
||
normalEncrypt: function(cipherfn, key, plaintext, iv) {
|
||
cipherfn = new cipher[cipherfn](key);
|
||
var block_size = cipherfn.blockSize;
|
||
|
||
var blocki = "";
|
||
var blockc = "";
|
||
var pos = 0;
|
||
var cyphertext = [];
|
||
var tempBlock = [];
|
||
blockc = iv.substring(0, block_size);
|
||
while (plaintext.length > block_size * pos) {
|
||
var encblock = cipherfn.encrypt(util.str2bin(blockc));
|
||
blocki = plaintext.substring((pos * block_size), (pos * block_size) + block_size);
|
||
for (var i = 0; i < blocki.length; i++)
|
||
tempBlock.push(String.fromCharCode(blocki.charCodeAt(i) ^ encblock[i]));
|
||
blockc = tempBlock.join('');
|
||
tempBlock = [];
|
||
cyphertext.push(blockc);
|
||
pos++;
|
||
}
|
||
return cyphertext.join('');
|
||
},
|
||
|
||
normalDecrypt: function(cipherfn, key, ciphertext, iv) {
|
||
cipherfn = new cipher[cipherfn](key);
|
||
var block_size = cipherfn.blockSize;
|
||
|
||
var blockp = "";
|
||
var pos = 0;
|
||
var plaintext = [];
|
||
var offset = 0;
|
||
if (iv == null)
|
||
for (var i = 0; i < block_size; i++) blockp += String.fromCharCode(0);
|
||
else
|
||
blockp = iv.substring(0, block_size);
|
||
while (ciphertext.length > (block_size * pos)) {
|
||
var decblock = cipherfn.encrypt(util.str2bin(blockp));
|
||
blockp = ciphertext.substring((pos * (block_size)) + offset, (pos * (block_size)) + (block_size) + offset);
|
||
for (var i = 0; i < blockp.length; i++) {
|
||
plaintext.push(String.fromCharCode(blockp.charCodeAt(i) ^ decblock[i]));
|
||
}
|
||
pos++;
|
||
}
|
||
|
||
return plaintext.join('');
|
||
}
|
||
}
|
||
|
||
},{"../util":56,"./cipher":9}],5:[function(require,module,exports){
|
||
/* Rijndael (AES) Encryption
|
||
* Copyright 2005 Herbert Hanewinkel, www.haneWIN.de
|
||
* version 1.1, check www.haneWIN.de for the latest version
|
||
|
||
* This software is provided as-is, without express or implied warranty.
|
||
* Permission to use, copy, modify, distribute or sell this software, with or
|
||
* without fee, for any purpose and by any individual or organization, is hereby
|
||
* granted, provided that the above copyright notice and this paragraph appear
|
||
* in all copies. Distribution as a part of an application or binary must
|
||
* include the above copyright notice in the documentation and/or other
|
||
* materials provided with the application or distribution.
|
||
*/
|
||
|
||
var util = require('../../util');
|
||
|
||
// The round constants used in subkey expansion
|
||
var Rcon = [
|
||
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8,
|
||
0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4,
|
||
0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91
|
||
];
|
||
|
||
// Precomputed lookup table for the SBox
|
||
var S = [
|
||
99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171,
|
||
118, 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164,
|
||
114, 192, 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113,
|
||
216, 49, 21, 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226,
|
||
235, 39, 178, 117, 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214,
|
||
179, 41, 227, 47, 132, 83, 209, 0, 237, 32, 252, 177, 91, 106, 203,
|
||
190, 57, 74, 76, 88, 207, 208, 239, 170, 251, 67, 77, 51, 133, 69,
|
||
249, 2, 127, 80, 60, 159, 168, 81, 163, 64, 143, 146, 157, 56, 245,
|
||
188, 182, 218, 33, 16, 255, 243, 210, 205, 12, 19, 236, 95, 151, 68,
|
||
23, 196, 167, 126, 61, 100, 93, 25, 115, 96, 129, 79, 220, 34, 42,
|
||
144, 136, 70, 238, 184, 20, 222, 94, 11, 219, 224, 50, 58, 10, 73,
|
||
6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, 231, 200, 55, 109,
|
||
141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8, 186, 120, 37,
|
||
46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, 112, 62,
|
||
181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, 225,
|
||
248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223,
|
||
140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187,
|
||
22
|
||
];
|
||
|
||
var T1 = [
|
||
0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6,
|
||
0x0df2f2ff, 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591,
|
||
0x50303060, 0x03010102, 0xa96767ce, 0x7d2b2b56,
|
||
0x19fefee7, 0x62d7d7b5, 0xe6abab4d, 0x9a7676ec,
|
||
0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa,
|
||
0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb,
|
||
0xecadad41, 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45,
|
||
0xbf9c9c23, 0xf7a4a453, 0x967272e4, 0x5bc0c09b,
|
||
0xc2b7b775, 0x1cfdfde1, 0xae93933d, 0x6a26264c,
|
||
0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83,
|
||
0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9,
|
||
0x937171e2, 0x73d8d8ab, 0x53313162, 0x3f15152a,
|
||
0x0c040408, 0x52c7c795, 0x65232346, 0x5ec3c39d,
|
||
0x28181830, 0xa1969637, 0x0f05050a, 0xb59a9a2f,
|
||
0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df,
|
||
0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea,
|
||
0x1b090912, 0x9e83831d, 0x742c2c58, 0x2e1a1a34,
|
||
0x2d1b1b36, 0xb26e6edc, 0xee5a5ab4, 0xfba0a05b,
|
||
0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, 0xceb3b37d,
|
||
0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413,
|
||
0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1,
|
||
0x60202040, 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6,
|
||
0xbe6a6ad4, 0x46cbcb8d, 0xd9bebe67, 0x4b393972,
|
||
0xde4a4a94, 0xd44c4c98, 0xe85858b0, 0x4acfcf85,
|
||
0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed,
|
||
0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511,
|
||
0xcf45458a, 0x10f9f9e9, 0x06020204, 0x817f7ffe,
|
||
0xf05050a0, 0x443c3c78, 0xba9f9f25, 0xe3a8a84b,
|
||
0xf35151a2, 0xfea3a35d, 0xc0404080, 0x8a8f8f05,
|
||
0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1,
|
||
0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142,
|
||
0x30101020, 0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf,
|
||
0x4ccdcd81, 0x140c0c18, 0x35131326, 0x2fececc3,
|
||
0xe15f5fbe, 0xa2979735, 0xcc444488, 0x3917172e,
|
||
0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a,
|
||
0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6,
|
||
0xa06060c0, 0x98818119, 0xd14f4f9e, 0x7fdcdca3,
|
||
0x66222244, 0x7e2a2a54, 0xab90903b, 0x8388880b,
|
||
0xca46468c, 0x29eeeec7, 0xd3b8b86b, 0x3c141428,
|
||
0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad,
|
||
0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14,
|
||
0xdb494992, 0x0a06060c, 0x6c242448, 0xe45c5cb8,
|
||
0x5dc2c29f, 0x6ed3d3bd, 0xefacac43, 0xa66262c4,
|
||
0xa8919139, 0xa4959531, 0x37e4e4d3, 0x8b7979f2,
|
||
0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda,
|
||
0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949,
|
||
0xb46c6cd8, 0xfa5656ac, 0x07f4f4f3, 0x25eaeacf,
|
||
0xaf6565ca, 0x8e7a7af4, 0xe9aeae47, 0x18080810,
|
||
0xd5baba6f, 0x887878f0, 0x6f25254a, 0x722e2e5c,
|
||
0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697,
|
||
0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e,
|
||
0xdd4b4b96, 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f,
|
||
0x907070e0, 0x423e3e7c, 0xc4b5b571, 0xaa6666cc,
|
||
0xd8484890, 0x05030306, 0x01f6f6f7, 0x120e0e1c,
|
||
0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969,
|
||
0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27,
|
||
0x38e1e1d9, 0x13f8f8eb, 0xb398982b, 0x33111122,
|
||
0xbb6969d2, 0x70d9d9a9, 0x898e8e07, 0xa7949433,
|
||
0xb69b9b2d, 0x221e1e3c, 0x92878715, 0x20e9e9c9,
|
||
0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5,
|
||
0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a,
|
||
0xdabfbf65, 0x31e6e6d7, 0xc6424284, 0xb86868d0,
|
||
0xc3414182, 0xb0999929, 0x772d2d5a, 0x110f0f1e,
|
||
0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 0x3a16162c
|
||
];
|
||
|
||
var T2 = [
|
||
0x6363c6a5, 0x7c7cf884, 0x7777ee99, 0x7b7bf68d,
|
||
0xf2f2ff0d, 0x6b6bd6bd, 0x6f6fdeb1, 0xc5c59154,
|
||
0x30306050, 0x01010203, 0x6767cea9, 0x2b2b567d,
|
||
0xfefee719, 0xd7d7b562, 0xabab4de6, 0x7676ec9a,
|
||
0xcaca8f45, 0x82821f9d, 0xc9c98940, 0x7d7dfa87,
|
||
0xfafaef15, 0x5959b2eb, 0x47478ec9, 0xf0f0fb0b,
|
||
0xadad41ec, 0xd4d4b367, 0xa2a25ffd, 0xafaf45ea,
|
||
0x9c9c23bf, 0xa4a453f7, 0x7272e496, 0xc0c09b5b,
|
||
0xb7b775c2, 0xfdfde11c, 0x93933dae, 0x26264c6a,
|
||
0x36366c5a, 0x3f3f7e41, 0xf7f7f502, 0xcccc834f,
|
||
0x3434685c, 0xa5a551f4, 0xe5e5d134, 0xf1f1f908,
|
||
0x7171e293, 0xd8d8ab73, 0x31316253, 0x15152a3f,
|
||
0x0404080c, 0xc7c79552, 0x23234665, 0xc3c39d5e,
|
||
0x18183028, 0x969637a1, 0x05050a0f, 0x9a9a2fb5,
|
||
0x07070e09, 0x12122436, 0x80801b9b, 0xe2e2df3d,
|
||
0xebebcd26, 0x27274e69, 0xb2b27fcd, 0x7575ea9f,
|
||
0x0909121b, 0x83831d9e, 0x2c2c5874, 0x1a1a342e,
|
||
0x1b1b362d, 0x6e6edcb2, 0x5a5ab4ee, 0xa0a05bfb,
|
||
0x5252a4f6, 0x3b3b764d, 0xd6d6b761, 0xb3b37dce,
|
||
0x2929527b, 0xe3e3dd3e, 0x2f2f5e71, 0x84841397,
|
||
0x5353a6f5, 0xd1d1b968, 0x00000000, 0xededc12c,
|
||
0x20204060, 0xfcfce31f, 0xb1b179c8, 0x5b5bb6ed,
|
||
0x6a6ad4be, 0xcbcb8d46, 0xbebe67d9, 0x3939724b,
|
||
0x4a4a94de, 0x4c4c98d4, 0x5858b0e8, 0xcfcf854a,
|
||
0xd0d0bb6b, 0xefefc52a, 0xaaaa4fe5, 0xfbfbed16,
|
||
0x434386c5, 0x4d4d9ad7, 0x33336655, 0x85851194,
|
||
0x45458acf, 0xf9f9e910, 0x02020406, 0x7f7ffe81,
|
||
0x5050a0f0, 0x3c3c7844, 0x9f9f25ba, 0xa8a84be3,
|
||
0x5151a2f3, 0xa3a35dfe, 0x404080c0, 0x8f8f058a,
|
||
0x92923fad, 0x9d9d21bc, 0x38387048, 0xf5f5f104,
|
||
0xbcbc63df, 0xb6b677c1, 0xdadaaf75, 0x21214263,
|
||
0x10102030, 0xffffe51a, 0xf3f3fd0e, 0xd2d2bf6d,
|
||
0xcdcd814c, 0x0c0c1814, 0x13132635, 0xececc32f,
|
||
0x5f5fbee1, 0x979735a2, 0x444488cc, 0x17172e39,
|
||
0xc4c49357, 0xa7a755f2, 0x7e7efc82, 0x3d3d7a47,
|
||
0x6464c8ac, 0x5d5dbae7, 0x1919322b, 0x7373e695,
|
||
0x6060c0a0, 0x81811998, 0x4f4f9ed1, 0xdcdca37f,
|
||
0x22224466, 0x2a2a547e, 0x90903bab, 0x88880b83,
|
||
0x46468cca, 0xeeeec729, 0xb8b86bd3, 0x1414283c,
|
||
0xdedea779, 0x5e5ebce2, 0x0b0b161d, 0xdbdbad76,
|
||
0xe0e0db3b, 0x32326456, 0x3a3a744e, 0x0a0a141e,
|
||
0x494992db, 0x06060c0a, 0x2424486c, 0x5c5cb8e4,
|
||
0xc2c29f5d, 0xd3d3bd6e, 0xacac43ef, 0x6262c4a6,
|
||
0x919139a8, 0x959531a4, 0xe4e4d337, 0x7979f28b,
|
||
0xe7e7d532, 0xc8c88b43, 0x37376e59, 0x6d6ddab7,
|
||
0x8d8d018c, 0xd5d5b164, 0x4e4e9cd2, 0xa9a949e0,
|
||
0x6c6cd8b4, 0x5656acfa, 0xf4f4f307, 0xeaeacf25,
|
||
0x6565caaf, 0x7a7af48e, 0xaeae47e9, 0x08081018,
|
||
0xbaba6fd5, 0x7878f088, 0x25254a6f, 0x2e2e5c72,
|
||
0x1c1c3824, 0xa6a657f1, 0xb4b473c7, 0xc6c69751,
|
||
0xe8e8cb23, 0xdddda17c, 0x7474e89c, 0x1f1f3e21,
|
||
0x4b4b96dd, 0xbdbd61dc, 0x8b8b0d86, 0x8a8a0f85,
|
||
0x7070e090, 0x3e3e7c42, 0xb5b571c4, 0x6666ccaa,
|
||
0x484890d8, 0x03030605, 0xf6f6f701, 0x0e0e1c12,
|
||
0x6161c2a3, 0x35356a5f, 0x5757aef9, 0xb9b969d0,
|
||
0x86861791, 0xc1c19958, 0x1d1d3a27, 0x9e9e27b9,
|
||
0xe1e1d938, 0xf8f8eb13, 0x98982bb3, 0x11112233,
|
||
0x6969d2bb, 0xd9d9a970, 0x8e8e0789, 0x949433a7,
|
||
0x9b9b2db6, 0x1e1e3c22, 0x87871592, 0xe9e9c920,
|
||
0xcece8749, 0x5555aaff, 0x28285078, 0xdfdfa57a,
|
||
0x8c8c038f, 0xa1a159f8, 0x89890980, 0x0d0d1a17,
|
||
0xbfbf65da, 0xe6e6d731, 0x424284c6, 0x6868d0b8,
|
||
0x414182c3, 0x999929b0, 0x2d2d5a77, 0x0f0f1e11,
|
||
0xb0b07bcb, 0x5454a8fc, 0xbbbb6dd6, 0x16162c3a
|
||
];
|
||
|
||
var T3 = [
|
||
0x63c6a563, 0x7cf8847c, 0x77ee9977, 0x7bf68d7b,
|
||
0xf2ff0df2, 0x6bd6bd6b, 0x6fdeb16f, 0xc59154c5,
|
||
0x30605030, 0x01020301, 0x67cea967, 0x2b567d2b,
|
||
0xfee719fe, 0xd7b562d7, 0xab4de6ab, 0x76ec9a76,
|
||
0xca8f45ca, 0x821f9d82, 0xc98940c9, 0x7dfa877d,
|
||
0xfaef15fa, 0x59b2eb59, 0x478ec947, 0xf0fb0bf0,
|
||
0xad41ecad, 0xd4b367d4, 0xa25ffda2, 0xaf45eaaf,
|
||
0x9c23bf9c, 0xa453f7a4, 0x72e49672, 0xc09b5bc0,
|
||
0xb775c2b7, 0xfde11cfd, 0x933dae93, 0x264c6a26,
|
||
0x366c5a36, 0x3f7e413f, 0xf7f502f7, 0xcc834fcc,
|
||
0x34685c34, 0xa551f4a5, 0xe5d134e5, 0xf1f908f1,
|
||
0x71e29371, 0xd8ab73d8, 0x31625331, 0x152a3f15,
|
||
0x04080c04, 0xc79552c7, 0x23466523, 0xc39d5ec3,
|
||
0x18302818, 0x9637a196, 0x050a0f05, 0x9a2fb59a,
|
||
0x070e0907, 0x12243612, 0x801b9b80, 0xe2df3de2,
|
||
0xebcd26eb, 0x274e6927, 0xb27fcdb2, 0x75ea9f75,
|
||
0x09121b09, 0x831d9e83, 0x2c58742c, 0x1a342e1a,
|
||
0x1b362d1b, 0x6edcb26e, 0x5ab4ee5a, 0xa05bfba0,
|
||
0x52a4f652, 0x3b764d3b, 0xd6b761d6, 0xb37dceb3,
|
||
0x29527b29, 0xe3dd3ee3, 0x2f5e712f, 0x84139784,
|
||
0x53a6f553, 0xd1b968d1, 0x00000000, 0xedc12ced,
|
||
0x20406020, 0xfce31ffc, 0xb179c8b1, 0x5bb6ed5b,
|
||
0x6ad4be6a, 0xcb8d46cb, 0xbe67d9be, 0x39724b39,
|
||
0x4a94de4a, 0x4c98d44c, 0x58b0e858, 0xcf854acf,
|
||
0xd0bb6bd0, 0xefc52aef, 0xaa4fe5aa, 0xfbed16fb,
|
||
0x4386c543, 0x4d9ad74d, 0x33665533, 0x85119485,
|
||
0x458acf45, 0xf9e910f9, 0x02040602, 0x7ffe817f,
|
||
0x50a0f050, 0x3c78443c, 0x9f25ba9f, 0xa84be3a8,
|
||
0x51a2f351, 0xa35dfea3, 0x4080c040, 0x8f058a8f,
|
||
0x923fad92, 0x9d21bc9d, 0x38704838, 0xf5f104f5,
|
||
0xbc63dfbc, 0xb677c1b6, 0xdaaf75da, 0x21426321,
|
||
0x10203010, 0xffe51aff, 0xf3fd0ef3, 0xd2bf6dd2,
|
||
0xcd814ccd, 0x0c18140c, 0x13263513, 0xecc32fec,
|
||
0x5fbee15f, 0x9735a297, 0x4488cc44, 0x172e3917,
|
||
0xc49357c4, 0xa755f2a7, 0x7efc827e, 0x3d7a473d,
|
||
0x64c8ac64, 0x5dbae75d, 0x19322b19, 0x73e69573,
|
||
0x60c0a060, 0x81199881, 0x4f9ed14f, 0xdca37fdc,
|
||
0x22446622, 0x2a547e2a, 0x903bab90, 0x880b8388,
|
||
0x468cca46, 0xeec729ee, 0xb86bd3b8, 0x14283c14,
|
||
0xdea779de, 0x5ebce25e, 0x0b161d0b, 0xdbad76db,
|
||
0xe0db3be0, 0x32645632, 0x3a744e3a, 0x0a141e0a,
|
||
0x4992db49, 0x060c0a06, 0x24486c24, 0x5cb8e45c,
|
||
0xc29f5dc2, 0xd3bd6ed3, 0xac43efac, 0x62c4a662,
|
||
0x9139a891, 0x9531a495, 0xe4d337e4, 0x79f28b79,
|
||
0xe7d532e7, 0xc88b43c8, 0x376e5937, 0x6ddab76d,
|
||
0x8d018c8d, 0xd5b164d5, 0x4e9cd24e, 0xa949e0a9,
|
||
0x6cd8b46c, 0x56acfa56, 0xf4f307f4, 0xeacf25ea,
|
||
0x65caaf65, 0x7af48e7a, 0xae47e9ae, 0x08101808,
|
||
0xba6fd5ba, 0x78f08878, 0x254a6f25, 0x2e5c722e,
|
||
0x1c38241c, 0xa657f1a6, 0xb473c7b4, 0xc69751c6,
|
||
0xe8cb23e8, 0xdda17cdd, 0x74e89c74, 0x1f3e211f,
|
||
0x4b96dd4b, 0xbd61dcbd, 0x8b0d868b, 0x8a0f858a,
|
||
0x70e09070, 0x3e7c423e, 0xb571c4b5, 0x66ccaa66,
|
||
0x4890d848, 0x03060503, 0xf6f701f6, 0x0e1c120e,
|
||
0x61c2a361, 0x356a5f35, 0x57aef957, 0xb969d0b9,
|
||
0x86179186, 0xc19958c1, 0x1d3a271d, 0x9e27b99e,
|
||
0xe1d938e1, 0xf8eb13f8, 0x982bb398, 0x11223311,
|
||
0x69d2bb69, 0xd9a970d9, 0x8e07898e, 0x9433a794,
|
||
0x9b2db69b, 0x1e3c221e, 0x87159287, 0xe9c920e9,
|
||
0xce8749ce, 0x55aaff55, 0x28507828, 0xdfa57adf,
|
||
0x8c038f8c, 0xa159f8a1, 0x89098089, 0x0d1a170d,
|
||
0xbf65dabf, 0xe6d731e6, 0x4284c642, 0x68d0b868,
|
||
0x4182c341, 0x9929b099, 0x2d5a772d, 0x0f1e110f,
|
||
0xb07bcbb0, 0x54a8fc54, 0xbb6dd6bb, 0x162c3a16
|
||
];
|
||
|
||
var T4 = [
|
||
0xc6a56363, 0xf8847c7c, 0xee997777, 0xf68d7b7b,
|
||
0xff0df2f2, 0xd6bd6b6b, 0xdeb16f6f, 0x9154c5c5,
|
||
0x60503030, 0x02030101, 0xcea96767, 0x567d2b2b,
|
||
0xe719fefe, 0xb562d7d7, 0x4de6abab, 0xec9a7676,
|
||
0x8f45caca, 0x1f9d8282, 0x8940c9c9, 0xfa877d7d,
|
||
0xef15fafa, 0xb2eb5959, 0x8ec94747, 0xfb0bf0f0,
|
||
0x41ecadad, 0xb367d4d4, 0x5ffda2a2, 0x45eaafaf,
|
||
0x23bf9c9c, 0x53f7a4a4, 0xe4967272, 0x9b5bc0c0,
|
||
0x75c2b7b7, 0xe11cfdfd, 0x3dae9393, 0x4c6a2626,
|
||
0x6c5a3636, 0x7e413f3f, 0xf502f7f7, 0x834fcccc,
|
||
0x685c3434, 0x51f4a5a5, 0xd134e5e5, 0xf908f1f1,
|
||
0xe2937171, 0xab73d8d8, 0x62533131, 0x2a3f1515,
|
||
0x080c0404, 0x9552c7c7, 0x46652323, 0x9d5ec3c3,
|
||
0x30281818, 0x37a19696, 0x0a0f0505, 0x2fb59a9a,
|
||
0x0e090707, 0x24361212, 0x1b9b8080, 0xdf3de2e2,
|
||
0xcd26ebeb, 0x4e692727, 0x7fcdb2b2, 0xea9f7575,
|
||
0x121b0909, 0x1d9e8383, 0x58742c2c, 0x342e1a1a,
|
||
0x362d1b1b, 0xdcb26e6e, 0xb4ee5a5a, 0x5bfba0a0,
|
||
0xa4f65252, 0x764d3b3b, 0xb761d6d6, 0x7dceb3b3,
|
||
0x527b2929, 0xdd3ee3e3, 0x5e712f2f, 0x13978484,
|
||
0xa6f55353, 0xb968d1d1, 0x00000000, 0xc12ceded,
|
||
0x40602020, 0xe31ffcfc, 0x79c8b1b1, 0xb6ed5b5b,
|
||
0xd4be6a6a, 0x8d46cbcb, 0x67d9bebe, 0x724b3939,
|
||
0x94de4a4a, 0x98d44c4c, 0xb0e85858, 0x854acfcf,
|
||
0xbb6bd0d0, 0xc52aefef, 0x4fe5aaaa, 0xed16fbfb,
|
||
0x86c54343, 0x9ad74d4d, 0x66553333, 0x11948585,
|
||
0x8acf4545, 0xe910f9f9, 0x04060202, 0xfe817f7f,
|
||
0xa0f05050, 0x78443c3c, 0x25ba9f9f, 0x4be3a8a8,
|
||
0xa2f35151, 0x5dfea3a3, 0x80c04040, 0x058a8f8f,
|
||
0x3fad9292, 0x21bc9d9d, 0x70483838, 0xf104f5f5,
|
||
0x63dfbcbc, 0x77c1b6b6, 0xaf75dada, 0x42632121,
|
||
0x20301010, 0xe51affff, 0xfd0ef3f3, 0xbf6dd2d2,
|
||
0x814ccdcd, 0x18140c0c, 0x26351313, 0xc32fecec,
|
||
0xbee15f5f, 0x35a29797, 0x88cc4444, 0x2e391717,
|
||
0x9357c4c4, 0x55f2a7a7, 0xfc827e7e, 0x7a473d3d,
|
||
0xc8ac6464, 0xbae75d5d, 0x322b1919, 0xe6957373,
|
||
0xc0a06060, 0x19988181, 0x9ed14f4f, 0xa37fdcdc,
|
||
0x44662222, 0x547e2a2a, 0x3bab9090, 0x0b838888,
|
||
0x8cca4646, 0xc729eeee, 0x6bd3b8b8, 0x283c1414,
|
||
0xa779dede, 0xbce25e5e, 0x161d0b0b, 0xad76dbdb,
|
||
0xdb3be0e0, 0x64563232, 0x744e3a3a, 0x141e0a0a,
|
||
0x92db4949, 0x0c0a0606, 0x486c2424, 0xb8e45c5c,
|
||
0x9f5dc2c2, 0xbd6ed3d3, 0x43efacac, 0xc4a66262,
|
||
0x39a89191, 0x31a49595, 0xd337e4e4, 0xf28b7979,
|
||
0xd532e7e7, 0x8b43c8c8, 0x6e593737, 0xdab76d6d,
|
||
0x018c8d8d, 0xb164d5d5, 0x9cd24e4e, 0x49e0a9a9,
|
||
0xd8b46c6c, 0xacfa5656, 0xf307f4f4, 0xcf25eaea,
|
||
0xcaaf6565, 0xf48e7a7a, 0x47e9aeae, 0x10180808,
|
||
0x6fd5baba, 0xf0887878, 0x4a6f2525, 0x5c722e2e,
|
||
0x38241c1c, 0x57f1a6a6, 0x73c7b4b4, 0x9751c6c6,
|
||
0xcb23e8e8, 0xa17cdddd, 0xe89c7474, 0x3e211f1f,
|
||
0x96dd4b4b, 0x61dcbdbd, 0x0d868b8b, 0x0f858a8a,
|
||
0xe0907070, 0x7c423e3e, 0x71c4b5b5, 0xccaa6666,
|
||
0x90d84848, 0x06050303, 0xf701f6f6, 0x1c120e0e,
|
||
0xc2a36161, 0x6a5f3535, 0xaef95757, 0x69d0b9b9,
|
||
0x17918686, 0x9958c1c1, 0x3a271d1d, 0x27b99e9e,
|
||
0xd938e1e1, 0xeb13f8f8, 0x2bb39898, 0x22331111,
|
||
0xd2bb6969, 0xa970d9d9, 0x07898e8e, 0x33a79494,
|
||
0x2db69b9b, 0x3c221e1e, 0x15928787, 0xc920e9e9,
|
||
0x8749cece, 0xaaff5555, 0x50782828, 0xa57adfdf,
|
||
0x038f8c8c, 0x59f8a1a1, 0x09808989, 0x1a170d0d,
|
||
0x65dabfbf, 0xd731e6e6, 0x84c64242, 0xd0b86868,
|
||
0x82c34141, 0x29b09999, 0x5a772d2d, 0x1e110f0f,
|
||
0x7bcbb0b0, 0xa8fc5454, 0x6dd6bbbb, 0x2c3a1616
|
||
];
|
||
|
||
function B0(x) {
|
||
return (x & 255);
|
||
}
|
||
|
||
function B1(x) {
|
||
return ((x >> 8) & 255);
|
||
}
|
||
|
||
function B2(x) {
|
||
return ((x >> 16) & 255);
|
||
}
|
||
|
||
function B3(x) {
|
||
return ((x >> 24) & 255);
|
||
}
|
||
|
||
function F1(x0, x1, x2, x3) {
|
||
return B1(T1[x0 & 255]) | (B1(T1[(x1 >> 8) & 255]) << 8) | (B1(T1[(x2 >> 16) & 255]) << 16) | (B1(T1[x3 >>> 24]) <<
|
||
24);
|
||
}
|
||
|
||
function packBytes(octets) {
|
||
var i, j;
|
||
var len = octets.length;
|
||
var b = new Array(len / 4);
|
||
|
||
if (!octets || len % 4) return;
|
||
|
||
for (i = 0, j = 0; j < len; j += 4)
|
||
b[i++] = octets[j] | (octets[j + 1] << 8) | (octets[j + 2] << 16) | (octets[j + 3] << 24);
|
||
|
||
return b;
|
||
}
|
||
|
||
function unpackBytes(packed) {
|
||
var j;
|
||
var i = 0,
|
||
l = packed.length;
|
||
var r = new Array(l * 4);
|
||
|
||
for (j = 0; j < l; j++) {
|
||
r[i++] = B0(packed[j]);
|
||
r[i++] = B1(packed[j]);
|
||
r[i++] = B2(packed[j]);
|
||
r[i++] = B3(packed[j]);
|
||
}
|
||
return r;
|
||
}
|
||
|
||
// ------------------------------------------------
|
||
|
||
var maxkc = 8;
|
||
var maxrk = 14;
|
||
|
||
function keyExpansion(key) {
|
||
var kc, i, j, r, t;
|
||
var rounds;
|
||
var keySched = new Array(maxrk + 1);
|
||
var keylen = key.length;
|
||
var k = new Array(maxkc);
|
||
var tk = new Array(maxkc);
|
||
var rconpointer = 0;
|
||
|
||
if (keylen == 16) {
|
||
rounds = 10;
|
||
kc = 4;
|
||
} else if (keylen == 24) {
|
||
rounds = 12;
|
||
kc = 6;
|
||
} else if (keylen == 32) {
|
||
rounds = 14;
|
||
kc = 8;
|
||
} else {
|
||
util.print_error('aes.js: Invalid key-length for AES key:' + keylen);
|
||
return;
|
||
}
|
||
|
||
for (i = 0; i < maxrk + 1; i++) keySched[i] = new Array(4);
|
||
|
||
for (i = 0, j = 0; j < keylen; j++, i += 4)
|
||
k[j] = key.charCodeAt(i) | (key.charCodeAt(i + 1) << 8) | (key.charCodeAt(i + 2) << 16) | (key.charCodeAt(i + 3) <<
|
||
24);
|
||
|
||
for (j = kc - 1; j >= 0; j--) tk[j] = k[j];
|
||
|
||
r = 0;
|
||
t = 0;
|
||
for (j = 0;
|
||
(j < kc) && (r < rounds + 1);) {
|
||
for (;
|
||
(j < kc) && (t < 4); j++, t++) {
|
||
keySched[r][t] = tk[j];
|
||
}
|
||
if (t == 4) {
|
||
r++;
|
||
t = 0;
|
||
}
|
||
}
|
||
|
||
while (r < rounds + 1) {
|
||
var temp = tk[kc - 1];
|
||
|
||
tk[0] ^= S[B1(temp)] | (S[B2(temp)] << 8) | (S[B3(temp)] << 16) | (S[B0(temp)] << 24);
|
||
tk[0] ^= Rcon[rconpointer++];
|
||
|
||
if (kc != 8) {
|
||
for (j = 1; j < kc; j++) tk[j] ^= tk[j - 1];
|
||
} else {
|
||
for (j = 1; j < kc / 2; j++) tk[j] ^= tk[j - 1];
|
||
|
||
temp = tk[kc / 2 - 1];
|
||
tk[kc / 2] ^= S[B0(temp)] | (S[B1(temp)] << 8) | (S[B2(temp)] << 16) | (S[B3(temp)] << 24);
|
||
|
||
for (j = kc / 2 + 1; j < kc; j++) tk[j] ^= tk[j - 1];
|
||
}
|
||
|
||
for (j = 0;
|
||
(j < kc) && (r < rounds + 1);) {
|
||
for (;
|
||
(j < kc) && (t < 4); j++, t++) {
|
||
keySched[r][t] = tk[j];
|
||
}
|
||
if (t == 4) {
|
||
r++;
|
||
t = 0;
|
||
}
|
||
}
|
||
}
|
||
this.rounds = rounds;
|
||
this.rk = keySched;
|
||
return this;
|
||
}
|
||
|
||
function AESencrypt(block, ctx) {
|
||
var r;
|
||
var t0, t1, t2, t3;
|
||
|
||
var b = packBytes(block);
|
||
var rounds = ctx.rounds;
|
||
var b0 = b[0];
|
||
var b1 = b[1];
|
||
var b2 = b[2];
|
||
var b3 = b[3];
|
||
|
||
for (r = 0; r < rounds - 1; r++) {
|
||
t0 = b0 ^ ctx.rk[r][0];
|
||
t1 = b1 ^ ctx.rk[r][1];
|
||
t2 = b2 ^ ctx.rk[r][2];
|
||
t3 = b3 ^ ctx.rk[r][3];
|
||
|
||
b0 = T1[t0 & 255] ^ T2[(t1 >> 8) & 255] ^ T3[(t2 >> 16) & 255] ^ T4[t3 >>> 24];
|
||
b1 = T1[t1 & 255] ^ T2[(t2 >> 8) & 255] ^ T3[(t3 >> 16) & 255] ^ T4[t0 >>> 24];
|
||
b2 = T1[t2 & 255] ^ T2[(t3 >> 8) & 255] ^ T3[(t0 >> 16) & 255] ^ T4[t1 >>> 24];
|
||
b3 = T1[t3 & 255] ^ T2[(t0 >> 8) & 255] ^ T3[(t1 >> 16) & 255] ^ T4[t2 >>> 24];
|
||
}
|
||
|
||
// last round is special
|
||
r = rounds - 1;
|
||
|
||
t0 = b0 ^ ctx.rk[r][0];
|
||
t1 = b1 ^ ctx.rk[r][1];
|
||
t2 = b2 ^ ctx.rk[r][2];
|
||
t3 = b3 ^ ctx.rk[r][3];
|
||
|
||
b[0] = F1(t0, t1, t2, t3) ^ ctx.rk[rounds][0];
|
||
b[1] = F1(t1, t2, t3, t0) ^ ctx.rk[rounds][1];
|
||
b[2] = F1(t2, t3, t0, t1) ^ ctx.rk[rounds][2];
|
||
b[3] = F1(t3, t0, t1, t2) ^ ctx.rk[rounds][3];
|
||
|
||
return unpackBytes(b);
|
||
}
|
||
|
||
function makeClass(length) {
|
||
|
||
var c = function(key) {
|
||
this.key = keyExpansion(key);
|
||
|
||
this.encrypt = function(block) {
|
||
return AESencrypt(block, this.key);
|
||
}
|
||
}
|
||
|
||
c.blockSize = c.prototype.blockSize = 16;
|
||
c.keySize = c.prototype.keySize = length / 8;
|
||
|
||
return c;
|
||
}
|
||
|
||
module.exports = {}
|
||
|
||
var types = [128, 192, 256];
|
||
|
||
for (var i in types) {
|
||
module.exports[types[i]] = makeClass(types[i]);
|
||
}
|
||
|
||
},{"../../util":56}],6:[function(require,module,exports){
|
||
/* Modified by Recurity Labs GmbH
|
||
*
|
||
* Originally written by nklein software (nklein.com)
|
||
*/
|
||
|
||
/*
|
||
* Javascript implementation based on Bruce Schneier's reference implementation.
|
||
*
|
||
*
|
||
* The constructor doesn't do much of anything. It's just here
|
||
* so we can start defining properties and methods and such.
|
||
*/
|
||
function Blowfish() {};
|
||
|
||
/*
|
||
* Declare the block size so that protocols know what size
|
||
* Initialization Vector (IV) they will need.
|
||
*/
|
||
Blowfish.prototype.BLOCKSIZE = 8;
|
||
|
||
/*
|
||
* These are the default SBOXES.
|
||
*/
|
||
Blowfish.prototype.SBOXES = [
|
||
[
|
||
0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96,
|
||
0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
|
||
0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658,
|
||
0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
|
||
0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e,
|
||
0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
|
||
0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6,
|
||
0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
|
||
0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c,
|
||
0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
|
||
0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1,
|
||
0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
|
||
0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a,
|
||
0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
|
||
0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176,
|
||
0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
|
||
0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706,
|
||
0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
|
||
0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b,
|
||
0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
|
||
0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c,
|
||
0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
|
||
0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a,
|
||
0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
|
||
0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760,
|
||
0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
|
||
0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8,
|
||
0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
|
||
0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33,
|
||
0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
|
||
0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0,
|
||
0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
|
||
0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777,
|
||
0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
|
||
0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705,
|
||
0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
|
||
0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e,
|
||
0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
|
||
0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9,
|
||
0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
|
||
0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f,
|
||
0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
|
||
0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a
|
||
],
|
||
[
|
||
0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d,
|
||
0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
|
||
0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65,
|
||
0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
|
||
0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9,
|
||
0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
|
||
0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d,
|
||
0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
|
||
0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc,
|
||
0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
|
||
0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908,
|
||
0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
|
||
0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124,
|
||
0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
|
||
0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908,
|
||
0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
|
||
0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b,
|
||
0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
|
||
0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa,
|
||
0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
|
||
0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d,
|
||
0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
|
||
0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5,
|
||
0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
|
||
0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96,
|
||
0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
|
||
0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca,
|
||
0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
|
||
0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77,
|
||
0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
|
||
0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054,
|
||
0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
|
||
0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea,
|
||
0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
|
||
0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646,
|
||
0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
|
||
0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea,
|
||
0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
|
||
0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e,
|
||
0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
|
||
0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd,
|
||
0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
|
||
0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7
|
||
],
|
||
[
|
||
0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7,
|
||
0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
|
||
0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af,
|
||
0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
|
||
0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4,
|
||
0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
|
||
0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec,
|
||
0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
|
||
0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332,
|
||
0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
|
||
0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58,
|
||
0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
|
||
0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22,
|
||
0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
|
||
0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60,
|
||
0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
|
||
0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99,
|
||
0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
|
||
0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74,
|
||
0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
|
||
0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3,
|
||
0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
|
||
0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979,
|
||
0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
|
||
0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa,
|
||
0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
|
||
0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086,
|
||
0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
|
||
0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24,
|
||
0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
|
||
0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84,
|
||
0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
|
||
0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09,
|
||
0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
|
||
0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe,
|
||
0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
|
||
0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0,
|
||
0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
|
||
0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188,
|
||
0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
|
||
0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8,
|
||
0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
|
||
0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0
|
||
],
|
||
[
|
||
0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742,
|
||
0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
|
||
0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79,
|
||
0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
|
||
0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a,
|
||
0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
|
||
0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1,
|
||
0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
|
||
0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797,
|
||
0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
|
||
0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6,
|
||
0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
|
||
0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba,
|
||
0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
|
||
0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5,
|
||
0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
|
||
0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce,
|
||
0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
|
||
0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd,
|
||
0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
|
||
0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb,
|
||
0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
|
||
0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc,
|
||
0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
|
||
0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc,
|
||
0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
|
||
0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a,
|
||
0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
|
||
0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a,
|
||
0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
|
||
0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b,
|
||
0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
|
||
0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e,
|
||
0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
|
||
0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623,
|
||
0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
|
||
0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a,
|
||
0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
|
||
0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3,
|
||
0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
|
||
0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c,
|
||
0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
|
||
0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
|
||
]
|
||
];
|
||
|
||
//*
|
||
//* This is the default PARRAY
|
||
//*
|
||
Blowfish.prototype.PARRAY = [
|
||
0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0,
|
||
0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
|
||
0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b
|
||
];
|
||
|
||
//*
|
||
//* This is the number of rounds the cipher will go
|
||
//*
|
||
Blowfish.prototype.NN = 16;
|
||
|
||
//*
|
||
//* This function is needed to get rid of problems
|
||
//* with the high-bit getting set. If we don't do
|
||
//* this, then sometimes ( aa & 0x00FFFFFFFF ) is not
|
||
//* equal to ( bb & 0x00FFFFFFFF ) even when they
|
||
//* agree bit-for-bit for the first 32 bits.
|
||
//*
|
||
Blowfish.prototype._clean = function(xx) {
|
||
if (xx < 0) {
|
||
var yy = xx & 0x7FFFFFFF;
|
||
xx = yy + 0x80000000;
|
||
}
|
||
return xx;
|
||
};
|
||
|
||
//*
|
||
//* This is the mixing function that uses the sboxes
|
||
//*
|
||
Blowfish.prototype._F = function(xx) {
|
||
var aa;
|
||
var bb;
|
||
var cc;
|
||
var dd;
|
||
var yy;
|
||
|
||
dd = xx & 0x00FF;
|
||
xx >>>= 8;
|
||
cc = xx & 0x00FF;
|
||
xx >>>= 8;
|
||
bb = xx & 0x00FF;
|
||
xx >>>= 8;
|
||
aa = xx & 0x00FF;
|
||
|
||
yy = this.sboxes[0][aa] + this.sboxes[1][bb];
|
||
yy = yy ^ this.sboxes[2][cc];
|
||
yy = yy + this.sboxes[3][dd];
|
||
|
||
return yy;
|
||
};
|
||
|
||
//*
|
||
//* This method takes an array with two values, left and right
|
||
//* and does NN rounds of Blowfish on them.
|
||
//*
|
||
Blowfish.prototype._encrypt_block = function(vals) {
|
||
var dataL = vals[0];
|
||
var dataR = vals[1];
|
||
|
||
var ii;
|
||
|
||
for (ii = 0; ii < this.NN; ++ii) {
|
||
dataL = dataL ^ this.parray[ii];
|
||
dataR = this._F(dataL) ^ dataR;
|
||
|
||
var tmp = dataL;
|
||
dataL = dataR;
|
||
dataR = tmp;
|
||
}
|
||
|
||
dataL = dataL ^ this.parray[this.NN + 0];
|
||
dataR = dataR ^ this.parray[this.NN + 1];
|
||
|
||
vals[0] = this._clean(dataR);
|
||
vals[1] = this._clean(dataL);
|
||
};
|
||
|
||
//*
|
||
//* This method takes a vector of numbers and turns them
|
||
//* into long words so that they can be processed by the
|
||
//* real algorithm.
|
||
//*
|
||
//* Maybe I should make the real algorithm above take a vector
|
||
//* instead. That will involve more looping, but it won't require
|
||
//* the F() method to deconstruct the vector.
|
||
//*
|
||
Blowfish.prototype.encrypt_block = function(vector) {
|
||
var ii;
|
||
var vals = [0, 0];
|
||
var off = this.BLOCKSIZE / 2;
|
||
for (ii = 0; ii < this.BLOCKSIZE / 2; ++ii) {
|
||
vals[0] = (vals[0] << 8) | (vector[ii + 0] & 0x00FF);
|
||
vals[1] = (vals[1] << 8) | (vector[ii + off] & 0x00FF);
|
||
}
|
||
|
||
this._encrypt_block(vals);
|
||
|
||
var ret = [];
|
||
for (ii = 0; ii < this.BLOCKSIZE / 2; ++ii) {
|
||
ret[ii + 0] = (vals[0] >>> (24 - 8 * (ii)) & 0x00FF);
|
||
ret[ii + off] = (vals[1] >>> (24 - 8 * (ii)) & 0x00FF);
|
||
// vals[ 0 ] = ( vals[ 0 ] >>> 8 );
|
||
// vals[ 1 ] = ( vals[ 1 ] >>> 8 );
|
||
}
|
||
|
||
return ret;
|
||
};
|
||
|
||
//*
|
||
//* This method takes an array with two values, left and right
|
||
//* and undoes NN rounds of Blowfish on them.
|
||
//*
|
||
Blowfish.prototype._decrypt_block = function(vals) {
|
||
var dataL = vals[0];
|
||
var dataR = vals[1];
|
||
|
||
var ii;
|
||
|
||
for (ii = this.NN + 1; ii > 1; --ii) {
|
||
dataL = dataL ^ this.parray[ii];
|
||
dataR = this._F(dataL) ^ dataR;
|
||
|
||
var tmp = dataL;
|
||
dataL = dataR;
|
||
dataR = tmp;
|
||
}
|
||
|
||
dataL = dataL ^ this.parray[1];
|
||
dataR = dataR ^ this.parray[0];
|
||
|
||
vals[0] = this._clean(dataR);
|
||
vals[1] = this._clean(dataL);
|
||
};
|
||
|
||
//*
|
||
//* This method takes a key array and initializes the
|
||
//* sboxes and parray for this encryption.
|
||
//*
|
||
Blowfish.prototype.init = function(key) {
|
||
var ii;
|
||
var jj = 0;
|
||
|
||
this.parray = [];
|
||
for (ii = 0; ii < this.NN + 2; ++ii) {
|
||
var data = 0x00000000;
|
||
var kk;
|
||
for (kk = 0; kk < 4; ++kk) {
|
||
data = (data << 8) | (key[jj] & 0x00FF);
|
||
if (++jj >= key.length) {
|
||
jj = 0;
|
||
}
|
||
}
|
||
this.parray[ii] = this.PARRAY[ii] ^ data;
|
||
}
|
||
|
||
this.sboxes = [];
|
||
for (ii = 0; ii < 4; ++ii) {
|
||
this.sboxes[ii] = [];
|
||
for (jj = 0; jj < 256; ++jj) {
|
||
this.sboxes[ii][jj] = this.SBOXES[ii][jj];
|
||
}
|
||
}
|
||
|
||
var vals = [0x00000000, 0x00000000];
|
||
|
||
for (ii = 0; ii < this.NN + 2; ii += 2) {
|
||
this._encrypt_block(vals);
|
||
this.parray[ii + 0] = vals[0];
|
||
this.parray[ii + 1] = vals[1];
|
||
}
|
||
|
||
for (ii = 0; ii < 4; ++ii) {
|
||
for (jj = 0; jj < 256; jj += 2) {
|
||
this._encrypt_block(vals);
|
||
this.sboxes[ii][jj + 0] = vals[0];
|
||
this.sboxes[ii][jj + 1] = vals[1];
|
||
}
|
||
}
|
||
};
|
||
|
||
var util = require('../../util');
|
||
|
||
// added by Recurity Labs
|
||
|
||
function BFencrypt(block, key) {
|
||
var bf = new Blowfish();
|
||
bf.init(util.str2bin(key));
|
||
return bf.encrypt_block(block);
|
||
}
|
||
|
||
function BF(key) {
|
||
this.bf = new Blowfish();
|
||
this.bf.init(util.str2bin(key));
|
||
|
||
this.encrypt = function(block) {
|
||
return this.bf.encrypt_block(block);
|
||
}
|
||
}
|
||
|
||
|
||
module.exports = BF;
|
||
module.exports.keySize = BF.prototype.keySize = 16;
|
||
module.exports.blockSize = BF.prototype.blockSize = 16;
|
||
|
||
},{"../../util":56}],7:[function(require,module,exports){
|
||
// Use of this source code is governed by a BSD-style
|
||
// license that can be found in the LICENSE file.
|
||
|
||
// Copyright 2010 pjacobs@xeekr.com . All rights reserved.
|
||
|
||
// Modified by Recurity Labs GmbH
|
||
|
||
// fixed/modified by Herbert Hanewinkel, www.haneWIN.de
|
||
// check www.haneWIN.de for the latest version
|
||
|
||
// cast5.js is a Javascript implementation of CAST-128, as defined in RFC 2144.
|
||
// CAST-128 is a common OpenPGP cipher.
|
||
|
||
|
||
// CAST5 constructor
|
||
|
||
|
||
|
||
function openpgp_symenc_cast5() {
|
||
this.BlockSize = 8;
|
||
this.KeySize = 16;
|
||
|
||
this.setKey = function(key) {
|
||
this.masking = new Array(16);
|
||
this.rotate = new Array(16);
|
||
|
||
this.reset();
|
||
|
||
if (key.length == this.KeySize) {
|
||
this.keySchedule(key);
|
||
} else {
|
||
util.print_error('cast5.js: CAST-128: keys must be 16 bytes');
|
||
return false;
|
||
}
|
||
return true;
|
||
};
|
||
|
||
this.reset = function() {
|
||
for (var i = 0; i < 16; i++) {
|
||
this.masking[i] = 0;
|
||
this.rotate[i] = 0;
|
||
}
|
||
};
|
||
|
||
this.getBlockSize = function() {
|
||
return BlockSize;
|
||
};
|
||
|
||
this.encrypt = function(src) {
|
||
var dst = new Array(src.length);
|
||
|
||
for (var i = 0; i < src.length; i += 8) {
|
||
var l = src[i] << 24 | src[i + 1] << 16 | src[i + 2] << 8 | src[i + 3];
|
||
var r = src[i + 4] << 24 | src[i + 5] << 16 | src[i + 6] << 8 | src[i + 7];
|
||
var t;
|
||
|
||
t = r;
|
||
r = l ^ f1(r, this.masking[0], this.rotate[0]);
|
||
l = t;
|
||
t = r;
|
||
r = l ^ f2(r, this.masking[1], this.rotate[1]);
|
||
l = t;
|
||
t = r;
|
||
r = l ^ f3(r, this.masking[2], this.rotate[2]);
|
||
l = t;
|
||
t = r;
|
||
r = l ^ f1(r, this.masking[3], this.rotate[3]);
|
||
l = t;
|
||
|
||
t = r;
|
||
r = l ^ f2(r, this.masking[4], this.rotate[4]);
|
||
l = t;
|
||
t = r;
|
||
r = l ^ f3(r, this.masking[5], this.rotate[5]);
|
||
l = t;
|
||
t = r;
|
||
r = l ^ f1(r, this.masking[6], this.rotate[6]);
|
||
l = t;
|
||
t = r;
|
||
r = l ^ f2(r, this.masking[7], this.rotate[7]);
|
||
l = t;
|
||
|
||
t = r;
|
||
r = l ^ f3(r, this.masking[8], this.rotate[8]);
|
||
l = t;
|
||
t = r;
|
||
r = l ^ f1(r, this.masking[9], this.rotate[9]);
|
||
l = t;
|
||
t = r;
|
||
r = l ^ f2(r, this.masking[10], this.rotate[10]);
|
||
l = t;
|
||
t = r;
|
||
r = l ^ f3(r, this.masking[11], this.rotate[11]);
|
||
l = t;
|
||
|
||
t = r;
|
||
r = l ^ f1(r, this.masking[12], this.rotate[12]);
|
||
l = t;
|
||
t = r;
|
||
r = l ^ f2(r, this.masking[13], this.rotate[13]);
|
||
l = t;
|
||
t = r;
|
||
r = l ^ f3(r, this.masking[14], this.rotate[14]);
|
||
l = t;
|
||
t = r;
|
||
r = l ^ f1(r, this.masking[15], this.rotate[15]);
|
||
l = t;
|
||
|
||
dst[i] = (r >>> 24) & 255;
|
||
dst[i + 1] = (r >>> 16) & 255;
|
||
dst[i + 2] = (r >>> 8) & 255;
|
||
dst[i + 3] = r & 255;
|
||
dst[i + 4] = (l >>> 24) & 255;
|
||
dst[i + 5] = (l >>> 16) & 255;
|
||
dst[i + 6] = (l >>> 8) & 255;
|
||
dst[i + 7] = l & 255;
|
||
}
|
||
|
||
return dst;
|
||
};
|
||
|
||
this.decrypt = function(src) {
|
||
var dst = new Array(src.length);
|
||
|
||
for (var i = 0; i < src.length; i += 8) {
|
||
var l = src[i] << 24 | src[i + 1] << 16 | src[i + 2] << 8 | src[i + 3];
|
||
var r = src[i + 4] << 24 | src[i + 5] << 16 | src[i + 6] << 8 | src[i + 7];
|
||
var t;
|
||
|
||
t = r;
|
||
r = l ^ f1(r, this.masking[15], this.rotate[15]);
|
||
l = t;
|
||
t = r;
|
||
r = l ^ f3(r, this.masking[14], this.rotate[14]);
|
||
l = t;
|
||
t = r;
|
||
r = l ^ f2(r, this.masking[13], this.rotate[13]);
|
||
l = t;
|
||
t = r;
|
||
r = l ^ f1(r, this.masking[12], this.rotate[12]);
|
||
l = t;
|
||
|
||
t = r;
|
||
r = l ^ f3(r, this.masking[11], this.rotate[11]);
|
||
l = t;
|
||
t = r;
|
||
r = l ^ f2(r, this.masking[10], this.rotate[10]);
|
||
l = t;
|
||
t = r;
|
||
r = l ^ f1(r, this.masking[9], this.rotate[9]);
|
||
l = t;
|
||
t = r;
|
||
r = l ^ f3(r, this.masking[8], this.rotate[8]);
|
||
l = t;
|
||
|
||
t = r;
|
||
r = l ^ f2(r, this.masking[7], this.rotate[7]);
|
||
l = t;
|
||
t = r;
|
||
r = l ^ f1(r, this.masking[6], this.rotate[6]);
|
||
l = t;
|
||
t = r;
|
||
r = l ^ f3(r, this.masking[5], this.rotate[5]);
|
||
l = t;
|
||
t = r;
|
||
r = l ^ f2(r, this.masking[4], this.rotate[4]);
|
||
l = t;
|
||
|
||
t = r;
|
||
r = l ^ f1(r, this.masking[3], this.rotate[3]);
|
||
l = t;
|
||
t = r;
|
||
r = l ^ f3(r, this.masking[2], this.rotate[2]);
|
||
l = t;
|
||
t = r;
|
||
r = l ^ f2(r, this.masking[1], this.rotate[1]);
|
||
l = t;
|
||
t = r;
|
||
r = l ^ f1(r, this.masking[0], this.rotate[0]);
|
||
l = t;
|
||
|
||
dst[i] = (r >>> 24) & 255;
|
||
dst[i + 1] = (r >>> 16) & 255;
|
||
dst[i + 2] = (r >>> 8) & 255;
|
||
dst[i + 3] = r & 255;
|
||
dst[i + 4] = (l >>> 24) & 255;
|
||
dst[i + 5] = (l >> 16) & 255;
|
||
dst[i + 6] = (l >> 8) & 255;
|
||
dst[i + 7] = l & 255;
|
||
}
|
||
|
||
return dst;
|
||
};
|
||
var scheduleA = new Array(4);
|
||
|
||
scheduleA[0] = new Array(4);
|
||
scheduleA[0][0] = new Array(4, 0, 0xd, 0xf, 0xc, 0xe, 0x8);
|
||
scheduleA[0][1] = new Array(5, 2, 16 + 0, 16 + 2, 16 + 1, 16 + 3, 0xa);
|
||
scheduleA[0][2] = new Array(6, 3, 16 + 7, 16 + 6, 16 + 5, 16 + 4, 9);
|
||
scheduleA[0][3] = new Array(7, 1, 16 + 0xa, 16 + 9, 16 + 0xb, 16 + 8, 0xb);
|
||
|
||
scheduleA[1] = new Array(4);
|
||
scheduleA[1][0] = new Array(0, 6, 16 + 5, 16 + 7, 16 + 4, 16 + 6, 16 + 0);
|
||
scheduleA[1][1] = new Array(1, 4, 0, 2, 1, 3, 16 + 2);
|
||
scheduleA[1][2] = new Array(2, 5, 7, 6, 5, 4, 16 + 1);
|
||
scheduleA[1][3] = new Array(3, 7, 0xa, 9, 0xb, 8, 16 + 3);
|
||
|
||
scheduleA[2] = new Array(4);
|
||
scheduleA[2][0] = new Array(4, 0, 0xd, 0xf, 0xc, 0xe, 8);
|
||
scheduleA[2][1] = new Array(5, 2, 16 + 0, 16 + 2, 16 + 1, 16 + 3, 0xa);
|
||
scheduleA[2][2] = new Array(6, 3, 16 + 7, 16 + 6, 16 + 5, 16 + 4, 9);
|
||
scheduleA[2][3] = new Array(7, 1, 16 + 0xa, 16 + 9, 16 + 0xb, 16 + 8, 0xb);
|
||
|
||
|
||
scheduleA[3] = new Array(4);
|
||
scheduleA[3][0] = new Array(0, 6, 16 + 5, 16 + 7, 16 + 4, 16 + 6, 16 + 0);
|
||
scheduleA[3][1] = new Array(1, 4, 0, 2, 1, 3, 16 + 2);
|
||
scheduleA[3][2] = new Array(2, 5, 7, 6, 5, 4, 16 + 1);
|
||
scheduleA[3][3] = new Array(3, 7, 0xa, 9, 0xb, 8, 16 + 3);
|
||
|
||
var scheduleB = new Array(4);
|
||
|
||
scheduleB[0] = new Array(4);
|
||
scheduleB[0][0] = new Array(16 + 8, 16 + 9, 16 + 7, 16 + 6, 16 + 2);
|
||
scheduleB[0][1] = new Array(16 + 0xa, 16 + 0xb, 16 + 5, 16 + 4, 16 + 6);
|
||
scheduleB[0][2] = new Array(16 + 0xc, 16 + 0xd, 16 + 3, 16 + 2, 16 + 9);
|
||
scheduleB[0][3] = new Array(16 + 0xe, 16 + 0xf, 16 + 1, 16 + 0, 16 + 0xc);
|
||
|
||
scheduleB[1] = new Array(4);
|
||
scheduleB[1][0] = new Array(3, 2, 0xc, 0xd, 8);
|
||
scheduleB[1][1] = new Array(1, 0, 0xe, 0xf, 0xd);
|
||
scheduleB[1][2] = new Array(7, 6, 8, 9, 3);
|
||
scheduleB[1][3] = new Array(5, 4, 0xa, 0xb, 7);
|
||
|
||
|
||
scheduleB[2] = new Array(4);
|
||
scheduleB[2][0] = new Array(16 + 3, 16 + 2, 16 + 0xc, 16 + 0xd, 16 + 9);
|
||
scheduleB[2][1] = new Array(16 + 1, 16 + 0, 16 + 0xe, 16 + 0xf, 16 + 0xc);
|
||
scheduleB[2][2] = new Array(16 + 7, 16 + 6, 16 + 8, 16 + 9, 16 + 2);
|
||
scheduleB[2][3] = new Array(16 + 5, 16 + 4, 16 + 0xa, 16 + 0xb, 16 + 6);
|
||
|
||
|
||
scheduleB[3] = new Array(4);
|
||
scheduleB[3][0] = new Array(8, 9, 7, 6, 3);
|
||
scheduleB[3][1] = new Array(0xa, 0xb, 5, 4, 7);
|
||
scheduleB[3][2] = new Array(0xc, 0xd, 3, 2, 8);
|
||
scheduleB[3][3] = new Array(0xe, 0xf, 1, 0, 0xd);
|
||
|
||
// changed 'in' to 'inn' (in javascript 'in' is a reserved word)
|
||
this.keySchedule = function(inn) {
|
||
var t = new Array(8);
|
||
var k = new Array(32);
|
||
|
||
for (var i = 0; i < 4; i++) {
|
||
var j = i * 4;
|
||
t[i] = inn[j] << 24 | inn[j + 1] << 16 | inn[j + 2] << 8 | inn[j + 3];
|
||
}
|
||
|
||
var x = [6, 7, 4, 5];
|
||
var ki = 0;
|
||
|
||
for (var half = 0; half < 2; half++) {
|
||
for (var round = 0; round < 4; round++) {
|
||
for (var j = 0; j < 4; j++) {
|
||
var a = scheduleA[round][j];
|
||
var w = t[a[1]];
|
||
|
||
w ^= sBox[4][(t[a[2] >>> 2] >>> (24 - 8 * (a[2] & 3))) & 0xff];
|
||
w ^= sBox[5][(t[a[3] >>> 2] >>> (24 - 8 * (a[3] & 3))) & 0xff];
|
||
w ^= sBox[6][(t[a[4] >>> 2] >>> (24 - 8 * (a[4] & 3))) & 0xff];
|
||
w ^= sBox[7][(t[a[5] >>> 2] >>> (24 - 8 * (a[5] & 3))) & 0xff];
|
||
w ^= sBox[x[j]][(t[a[6] >>> 2] >>> (24 - 8 * (a[6] & 3))) & 0xff];
|
||
t[a[0]] = w;
|
||
}
|
||
|
||
for (var j = 0; j < 4; j++) {
|
||
var b = scheduleB[round][j];
|
||
var w = sBox[4][(t[b[0] >>> 2] >>> (24 - 8 * (b[0] & 3))) & 0xff];
|
||
|
||
w ^= sBox[5][(t[b[1] >>> 2] >>> (24 - 8 * (b[1] & 3))) & 0xff];
|
||
w ^= sBox[6][(t[b[2] >>> 2] >>> (24 - 8 * (b[2] & 3))) & 0xff];
|
||
w ^= sBox[7][(t[b[3] >>> 2] >>> (24 - 8 * (b[3] & 3))) & 0xff];
|
||
w ^= sBox[4 + j][(t[b[4] >>> 2] >>> (24 - 8 * (b[4] & 3))) & 0xff];
|
||
k[ki] = w;
|
||
ki++;
|
||
}
|
||
}
|
||
}
|
||
|
||
for (var i = 0; i < 16; i++) {
|
||
this.masking[i] = k[i];
|
||
this.rotate[i] = k[16 + i] & 0x1f;
|
||
}
|
||
};
|
||
|
||
// These are the three 'f' functions. See RFC 2144, section 2.2.
|
||
|
||
function f1(d, m, r) {
|
||
var t = m + d;
|
||
var I = (t << r) | (t >>> (32 - r));
|
||
return ((sBox[0][I >>> 24] ^ sBox[1][(I >>> 16) & 255]) - sBox[2][(I >>> 8) & 255]) + sBox[3][I & 255];
|
||
}
|
||
|
||
function f2(d, m, r) {
|
||
var t = m ^ d;
|
||
var I = (t << r) | (t >>> (32 - r));
|
||
return ((sBox[0][I >>> 24] - sBox[1][(I >>> 16) & 255]) + sBox[2][(I >>> 8) & 255]) ^ sBox[3][I & 255];
|
||
}
|
||
|
||
function f3(d, m, r) {
|
||
var t = m - d;
|
||
var I = (t << r) | (t >>> (32 - r));
|
||
return ((sBox[0][I >>> 24] + sBox[1][(I >>> 16) & 255]) ^ sBox[2][(I >>> 8) & 255]) - sBox[3][I & 255];
|
||
}
|
||
|
||
var sBox = new Array(8);
|
||
sBox[0] = new Array(
|
||
0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9c004dd3, 0x6003e540, 0xcf9fc949,
|
||
0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0, 0x15c361d2, 0xc2e7661d, 0x22d4ff8e,
|
||
0x28683b6f, 0xc07fd059, 0xff2379c8, 0x775f50e2, 0x43c340d3, 0xdf2f8656, 0x887ca41a, 0xa2d2bd2d,
|
||
0xa1c9e0d6, 0x346c4819, 0x61b76d87, 0x22540f2f, 0x2abe32e1, 0xaa54166b, 0x22568e3a, 0xa2d341d0,
|
||
0x66db40c8, 0xa784392f, 0x004dff2f, 0x2db9d2de, 0x97943fac, 0x4a97c1d8, 0x527644b7, 0xb5f437a7,
|
||
0xb82cbaef, 0xd751d159, 0x6ff7f0ed, 0x5a097a1f, 0x827b68d0, 0x90ecf52e, 0x22b0c054, 0xbc8e5935,
|
||
0x4b6d2f7f, 0x50bb64a2, 0xd2664910, 0xbee5812d, 0xb7332290, 0xe93b159f, 0xb48ee411, 0x4bff345d,
|
||
0xfd45c240, 0xad31973f, 0xc4f6d02e, 0x55fc8165, 0xd5b1caad, 0xa1ac2dae, 0xa2d4b76d, 0xc19b0c50,
|
||
0x882240f2, 0x0c6e4f38, 0xa4e4bfd7, 0x4f5ba272, 0x564c1d2f, 0xc59c5319, 0xb949e354, 0xb04669fe,
|
||
0xb1b6ab8a, 0xc71358dd, 0x6385c545, 0x110f935d, 0x57538ad5, 0x6a390493, 0xe63d37e0, 0x2a54f6b3,
|
||
0x3a787d5f, 0x6276a0b5, 0x19a6fcdf, 0x7a42206a, 0x29f9d4d5, 0xf61b1891, 0xbb72275e, 0xaa508167,
|
||
0x38901091, 0xc6b505eb, 0x84c7cb8c, 0x2ad75a0f, 0x874a1427, 0xa2d1936b, 0x2ad286af, 0xaa56d291,
|
||
0xd7894360, 0x425c750d, 0x93b39e26, 0x187184c9, 0x6c00b32d, 0x73e2bb14, 0xa0bebc3c, 0x54623779,
|
||
0x64459eab, 0x3f328b82, 0x7718cf82, 0x59a2cea6, 0x04ee002e, 0x89fe78e6, 0x3fab0950, 0x325ff6c2,
|
||
0x81383f05, 0x6963c5c8, 0x76cb5ad6, 0xd49974c9, 0xca180dcf, 0x380782d5, 0xc7fa5cf6, 0x8ac31511,
|
||
0x35e79e13, 0x47da91d0, 0xf40f9086, 0xa7e2419e, 0x31366241, 0x051ef495, 0xaa573b04, 0x4a805d8d,
|
||
0x548300d0, 0x00322a3c, 0xbf64cddf, 0xba57a68e, 0x75c6372b, 0x50afd341, 0xa7c13275, 0x915a0bf5,
|
||
0x6b54bfab, 0x2b0b1426, 0xab4cc9d7, 0x449ccd82, 0xf7fbf265, 0xab85c5f3, 0x1b55db94, 0xaad4e324,
|
||
0xcfa4bd3f, 0x2deaa3e2, 0x9e204d02, 0xc8bd25ac, 0xeadf55b3, 0xd5bd9e98, 0xe31231b2, 0x2ad5ad6c,
|
||
0x954329de, 0xadbe4528, 0xd8710f69, 0xaa51c90f, 0xaa786bf6, 0x22513f1e, 0xaa51a79b, 0x2ad344cc,
|
||
0x7b5a41f0, 0xd37cfbad, 0x1b069505, 0x41ece491, 0xb4c332e6, 0x032268d4, 0xc9600acc, 0xce387e6d,
|
||
0xbf6bb16c, 0x6a70fb78, 0x0d03d9c9, 0xd4df39de, 0xe01063da, 0x4736f464, 0x5ad328d8, 0xb347cc96,
|
||
0x75bb0fc3, 0x98511bfb, 0x4ffbcc35, 0xb58bcf6a, 0xe11f0abc, 0xbfc5fe4a, 0xa70aec10, 0xac39570a,
|
||
0x3f04442f, 0x6188b153, 0xe0397a2e, 0x5727cb79, 0x9ceb418f, 0x1cacd68d, 0x2ad37c96, 0x0175cb9d,
|
||
0xc69dff09, 0xc75b65f0, 0xd9db40d8, 0xec0e7779, 0x4744ead4, 0xb11c3274, 0xdd24cb9e, 0x7e1c54bd,
|
||
0xf01144f9, 0xd2240eb1, 0x9675b3fd, 0xa3ac3755, 0xd47c27af, 0x51c85f4d, 0x56907596, 0xa5bb15e6,
|
||
0x580304f0, 0xca042cf1, 0x011a37ea, 0x8dbfaadb, 0x35ba3e4a, 0x3526ffa0, 0xc37b4d09, 0xbc306ed9,
|
||
0x98a52666, 0x5648f725, 0xff5e569d, 0x0ced63d0, 0x7c63b2cf, 0x700b45e1, 0xd5ea50f1, 0x85a92872,
|
||
0xaf1fbda7, 0xd4234870, 0xa7870bf3, 0x2d3b4d79, 0x42e04198, 0x0cd0ede7, 0x26470db8, 0xf881814c,
|
||
0x474d6ad7, 0x7c0c5e5c, 0xd1231959, 0x381b7298, 0xf5d2f4db, 0xab838653, 0x6e2f1e23, 0x83719c9e,
|
||
0xbd91e046, 0x9a56456e, 0xdc39200c, 0x20c8c571, 0x962bda1c, 0xe1e696ff, 0xb141ab08, 0x7cca89b9,
|
||
0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 0x427b169c, 0x5ac9f049, 0xdd8f0f00, 0x5c8165bf);
|
||
|
||
sBox[1] = new Array(
|
||
0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a, 0xeec5207a, 0x55889c94, 0x72fc0651,
|
||
0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef, 0x5f0c0794, 0x18dcdb7d, 0xa1d6eff3,
|
||
0xa0b52f7b, 0x59e83605, 0xee15b094, 0xe9ffd909, 0xdc440086, 0xef944459, 0xba83ccb3, 0xe0c3cdfb,
|
||
0xd1da4181, 0x3b092ab1, 0xf997f1c1, 0xa5e6cf7b, 0x01420ddb, 0xe4e7ef5b, 0x25a1ff41, 0xe180f806,
|
||
0x1fc41080, 0x179bee7a, 0xd37ac6a9, 0xfe5830a4, 0x98de8b7f, 0x77e83f4e, 0x79929269, 0x24fa9f7b,
|
||
0xe113c85b, 0xacc40083, 0xd7503525, 0xf7ea615f, 0x62143154, 0x0d554b63, 0x5d681121, 0xc866c359,
|
||
0x3d63cf73, 0xcee234c0, 0xd4d87e87, 0x5c672b21, 0x071f6181, 0x39f7627f, 0x361e3084, 0xe4eb573b,
|
||
0x602f64a4, 0xd63acd9c, 0x1bbc4635, 0x9e81032d, 0x2701f50c, 0x99847ab4, 0xa0e3df79, 0xba6cf38c,
|
||
0x10843094, 0x2537a95e, 0xf46f6ffe, 0xa1ff3b1f, 0x208cfb6a, 0x8f458c74, 0xd9e0a227, 0x4ec73a34,
|
||
0xfc884f69, 0x3e4de8df, 0xef0e0088, 0x3559648d, 0x8a45388c, 0x1d804366, 0x721d9bfd, 0xa58684bb,
|
||
0xe8256333, 0x844e8212, 0x128d8098, 0xfed33fb4, 0xce280ae1, 0x27e19ba5, 0xd5a6c252, 0xe49754bd,
|
||
0xc5d655dd, 0xeb667064, 0x77840b4d, 0xa1b6a801, 0x84db26a9, 0xe0b56714, 0x21f043b7, 0xe5d05860,
|
||
0x54f03084, 0x066ff472, 0xa31aa153, 0xdadc4755, 0xb5625dbf, 0x68561be6, 0x83ca6b94, 0x2d6ed23b,
|
||
0xeccf01db, 0xa6d3d0ba, 0xb6803d5c, 0xaf77a709, 0x33b4a34c, 0x397bc8d6, 0x5ee22b95, 0x5f0e5304,
|
||
0x81ed6f61, 0x20e74364, 0xb45e1378, 0xde18639b, 0x881ca122, 0xb96726d1, 0x8049a7e8, 0x22b7da7b,
|
||
0x5e552d25, 0x5272d237, 0x79d2951c, 0xc60d894c, 0x488cb402, 0x1ba4fe5b, 0xa4b09f6b, 0x1ca815cf,
|
||
0xa20c3005, 0x8871df63, 0xb9de2fcb, 0x0cc6c9e9, 0x0beeff53, 0xe3214517, 0xb4542835, 0x9f63293c,
|
||
0xee41e729, 0x6e1d2d7c, 0x50045286, 0x1e6685f3, 0xf33401c6, 0x30a22c95, 0x31a70850, 0x60930f13,
|
||
0x73f98417, 0xa1269859, 0xec645c44, 0x52c877a9, 0xcdff33a6, 0xa02b1741, 0x7cbad9a2, 0x2180036f,
|
||
0x50d99c08, 0xcb3f4861, 0xc26bd765, 0x64a3f6ab, 0x80342676, 0x25a75e7b, 0xe4e6d1fc, 0x20c710e6,
|
||
0xcdf0b680, 0x17844d3b, 0x31eef84d, 0x7e0824e4, 0x2ccb49eb, 0x846a3bae, 0x8ff77888, 0xee5d60f6,
|
||
0x7af75673, 0x2fdd5cdb, 0xa11631c1, 0x30f66f43, 0xb3faec54, 0x157fd7fa, 0xef8579cc, 0xd152de58,
|
||
0xdb2ffd5e, 0x8f32ce19, 0x306af97a, 0x02f03ef8, 0x99319ad5, 0xc242fa0f, 0xa7e3ebb0, 0xc68e4906,
|
||
0xb8da230c, 0x80823028, 0xdcdef3c8, 0xd35fb171, 0x088a1bc8, 0xbec0c560, 0x61a3c9e8, 0xbca8f54d,
|
||
0xc72feffa, 0x22822e99, 0x82c570b4, 0xd8d94e89, 0x8b1c34bc, 0x301e16e6, 0x273be979, 0xb0ffeaa6,
|
||
0x61d9b8c6, 0x00b24869, 0xb7ffce3f, 0x08dc283b, 0x43daf65a, 0xf7e19798, 0x7619b72f, 0x8f1c9ba4,
|
||
0xdc8637a0, 0x16a7d3b1, 0x9fc393b7, 0xa7136eeb, 0xc6bcc63e, 0x1a513742, 0xef6828bc, 0x520365d6,
|
||
0x2d6a77ab, 0x3527ed4b, 0x821fd216, 0x095c6e2e, 0xdb92f2fb, 0x5eea29cb, 0x145892f5, 0x91584f7f,
|
||
0x5483697b, 0x2667a8cc, 0x85196048, 0x8c4bacea, 0x833860d4, 0x0d23e0f9, 0x6c387e8a, 0x0ae6d249,
|
||
0xb284600c, 0xd835731d, 0xdcb1c647, 0xac4c56ea, 0x3ebd81b3, 0x230eabb0, 0x6438bc87, 0xf0b5b1fa,
|
||
0x8f5ea2b3, 0xfc184642, 0x0a036b7a, 0x4fb089bd, 0x649da589, 0xa345415e, 0x5c038323, 0x3e5d3bb9,
|
||
0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 0x7160a539, 0x73bfbe70, 0x83877605, 0x4523ecf1);
|
||
|
||
sBox[2] = new Array(
|
||
0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff, 0x369fe44b, 0x8c1fc644, 0xaececa90,
|
||
0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806, 0xf0ad0548, 0xe13c8d83, 0x927010d5,
|
||
0x11107d9f, 0x07647db9, 0xb2e3e4d4, 0x3d4f285e, 0xb9afa820, 0xfade82e0, 0xa067268b, 0x8272792e,
|
||
0x553fb2c0, 0x489ae22b, 0xd4ef9794, 0x125e3fbc, 0x21fffcee, 0x825b1bfd, 0x9255c5ed, 0x1257a240,
|
||
0x4e1a8302, 0xbae07fff, 0x528246e7, 0x8e57140e, 0x3373f7bf, 0x8c9f8188, 0xa6fc4ee8, 0xc982b5a5,
|
||
0xa8c01db7, 0x579fc264, 0x67094f31, 0xf2bd3f5f, 0x40fff7c1, 0x1fb78dfc, 0x8e6bd2c1, 0x437be59b,
|
||
0x99b03dbf, 0xb5dbc64b, 0x638dc0e6, 0x55819d99, 0xa197c81c, 0x4a012d6e, 0xc5884a28, 0xccc36f71,
|
||
0xb843c213, 0x6c0743f1, 0x8309893c, 0x0feddd5f, 0x2f7fe850, 0xd7c07f7e, 0x02507fbf, 0x5afb9a04,
|
||
0xa747d2d0, 0x1651192e, 0xaf70bf3e, 0x58c31380, 0x5f98302e, 0x727cc3c4, 0x0a0fb402, 0x0f7fef82,
|
||
0x8c96fdad, 0x5d2c2aae, 0x8ee99a49, 0x50da88b8, 0x8427f4a0, 0x1eac5790, 0x796fb449, 0x8252dc15,
|
||
0xefbd7d9b, 0xa672597d, 0xada840d8, 0x45f54504, 0xfa5d7403, 0xe83ec305, 0x4f91751a, 0x925669c2,
|
||
0x23efe941, 0xa903f12e, 0x60270df2, 0x0276e4b6, 0x94fd6574, 0x927985b2, 0x8276dbcb, 0x02778176,
|
||
0xf8af918d, 0x4e48f79e, 0x8f616ddf, 0xe29d840e, 0x842f7d83, 0x340ce5c8, 0x96bbb682, 0x93b4b148,
|
||
0xef303cab, 0x984faf28, 0x779faf9b, 0x92dc560d, 0x224d1e20, 0x8437aa88, 0x7d29dc96, 0x2756d3dc,
|
||
0x8b907cee, 0xb51fd240, 0xe7c07ce3, 0xe566b4a1, 0xc3e9615e, 0x3cf8209d, 0x6094d1e3, 0xcd9ca341,
|
||
0x5c76460e, 0x00ea983b, 0xd4d67881, 0xfd47572c, 0xf76cedd9, 0xbda8229c, 0x127dadaa, 0x438a074e,
|
||
0x1f97c090, 0x081bdb8a, 0x93a07ebe, 0xb938ca15, 0x97b03cff, 0x3dc2c0f8, 0x8d1ab2ec, 0x64380e51,
|
||
0x68cc7bfb, 0xd90f2788, 0x12490181, 0x5de5ffd4, 0xdd7ef86a, 0x76a2e214, 0xb9a40368, 0x925d958f,
|
||
0x4b39fffa, 0xba39aee9, 0xa4ffd30b, 0xfaf7933b, 0x6d498623, 0x193cbcfa, 0x27627545, 0x825cf47a,
|
||
0x61bd8ba0, 0xd11e42d1, 0xcead04f4, 0x127ea392, 0x10428db7, 0x8272a972, 0x9270c4a8, 0x127de50b,
|
||
0x285ba1c8, 0x3c62f44f, 0x35c0eaa5, 0xe805d231, 0x428929fb, 0xb4fcdf82, 0x4fb66a53, 0x0e7dc15b,
|
||
0x1f081fab, 0x108618ae, 0xfcfd086d, 0xf9ff2889, 0x694bcc11, 0x236a5cae, 0x12deca4d, 0x2c3f8cc5,
|
||
0xd2d02dfe, 0xf8ef5896, 0xe4cf52da, 0x95155b67, 0x494a488c, 0xb9b6a80c, 0x5c8f82bc, 0x89d36b45,
|
||
0x3a609437, 0xec00c9a9, 0x44715253, 0x0a874b49, 0xd773bc40, 0x7c34671c, 0x02717ef6, 0x4feb5536,
|
||
0xa2d02fff, 0xd2bf60c4, 0xd43f03c0, 0x50b4ef6d, 0x07478cd1, 0x006e1888, 0xa2e53f55, 0xb9e6d4bc,
|
||
0xa2048016, 0x97573833, 0xd7207d67, 0xde0f8f3d, 0x72f87b33, 0xabcc4f33, 0x7688c55d, 0x7b00a6b0,
|
||
0x947b0001, 0x570075d2, 0xf9bb88f8, 0x8942019e, 0x4264a5ff, 0x856302e0, 0x72dbd92b, 0xee971b69,
|
||
0x6ea22fde, 0x5f08ae2b, 0xaf7a616d, 0xe5c98767, 0xcf1febd2, 0x61efc8c2, 0xf1ac2571, 0xcc8239c2,
|
||
0x67214cb8, 0xb1e583d1, 0xb7dc3e62, 0x7f10bdce, 0xf90a5c38, 0x0ff0443d, 0x606e6dc6, 0x60543a49,
|
||
0x5727c148, 0x2be98a1d, 0x8ab41738, 0x20e1be24, 0xaf96da0f, 0x68458425, 0x99833be5, 0x600d457d,
|
||
0x282f9350, 0x8334b362, 0xd91d1120, 0x2b6d8da0, 0x642b1e31, 0x9c305a00, 0x52bce688, 0x1b03588a,
|
||
0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 0xdfef4636, 0xa133c501, 0xe9d3531c, 0xee353783);
|
||
|
||
sBox[3] = new Array(
|
||
0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb, 0x64ad8c57, 0x85510443, 0xfa020ed1,
|
||
0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43, 0x6497b7b1, 0xf3641f63, 0x241e4adf,
|
||
0x28147f5f, 0x4fa2b8cd, 0xc9430040, 0x0cc32220, 0xfdd30b30, 0xc0a5374f, 0x1d2d00d9, 0x24147b15,
|
||
0xee4d111a, 0x0fca5167, 0x71ff904c, 0x2d195ffe, 0x1a05645f, 0x0c13fefe, 0x081b08ca, 0x05170121,
|
||
0x80530100, 0xe83e5efe, 0xac9af4f8, 0x7fe72701, 0xd2b8ee5f, 0x06df4261, 0xbb9e9b8a, 0x7293ea25,
|
||
0xce84ffdf, 0xf5718801, 0x3dd64b04, 0xa26f263b, 0x7ed48400, 0x547eebe6, 0x446d4ca0, 0x6cf3d6f5,
|
||
0x2649abdf, 0xaea0c7f5, 0x36338cc1, 0x503f7e93, 0xd3772061, 0x11b638e1, 0x72500e03, 0xf80eb2bb,
|
||
0xabe0502e, 0xec8d77de, 0x57971e81, 0xe14f6746, 0xc9335400, 0x6920318f, 0x081dbb99, 0xffc304a5,
|
||
0x4d351805, 0x7f3d5ce3, 0xa6c866c6, 0x5d5bcca9, 0xdaec6fea, 0x9f926f91, 0x9f46222f, 0x3991467d,
|
||
0xa5bf6d8e, 0x1143c44f, 0x43958302, 0xd0214eeb, 0x022083b8, 0x3fb6180c, 0x18f8931e, 0x281658e6,
|
||
0x26486e3e, 0x8bd78a70, 0x7477e4c1, 0xb506e07c, 0xf32d0a25, 0x79098b02, 0xe4eabb81, 0x28123b23,
|
||
0x69dead38, 0x1574ca16, 0xdf871b62, 0x211c40b7, 0xa51a9ef9, 0x0014377b, 0x041e8ac8, 0x09114003,
|
||
0xbd59e4d2, 0xe3d156d5, 0x4fe876d5, 0x2f91a340, 0x557be8de, 0x00eae4a7, 0x0ce5c2ec, 0x4db4bba6,
|
||
0xe756bdff, 0xdd3369ac, 0xec17b035, 0x06572327, 0x99afc8b0, 0x56c8c391, 0x6b65811c, 0x5e146119,
|
||
0x6e85cb75, 0xbe07c002, 0xc2325577, 0x893ff4ec, 0x5bbfc92d, 0xd0ec3b25, 0xb7801ab7, 0x8d6d3b24,
|
||
0x20c763ef, 0xc366a5fc, 0x9c382880, 0x0ace3205, 0xaac9548a, 0xeca1d7c7, 0x041afa32, 0x1d16625a,
|
||
0x6701902c, 0x9b757a54, 0x31d477f7, 0x9126b031, 0x36cc6fdb, 0xc70b8b46, 0xd9e66a48, 0x56e55a79,
|
||
0x026a4ceb, 0x52437eff, 0x2f8f76b4, 0x0df980a5, 0x8674cde3, 0xedda04eb, 0x17a9be04, 0x2c18f4df,
|
||
0xb7747f9d, 0xab2af7b4, 0xefc34d20, 0x2e096b7c, 0x1741a254, 0xe5b6a035, 0x213d42f6, 0x2c1c7c26,
|
||
0x61c2f50f, 0x6552daf9, 0xd2c231f8, 0x25130f69, 0xd8167fa2, 0x0418f2c8, 0x001a96a6, 0x0d1526ab,
|
||
0x63315c21, 0x5e0a72ec, 0x49bafefd, 0x187908d9, 0x8d0dbd86, 0x311170a7, 0x3e9b640c, 0xcc3e10d7,
|
||
0xd5cad3b6, 0x0caec388, 0xf73001e1, 0x6c728aff, 0x71eae2a1, 0x1f9af36e, 0xcfcbd12f, 0xc1de8417,
|
||
0xac07be6b, 0xcb44a1d8, 0x8b9b0f56, 0x013988c3, 0xb1c52fca, 0xb4be31cd, 0xd8782806, 0x12a3a4e2,
|
||
0x6f7de532, 0x58fd7eb6, 0xd01ee900, 0x24adffc2, 0xf4990fc5, 0x9711aac5, 0x001d7b95, 0x82e5e7d2,
|
||
0x109873f6, 0x00613096, 0xc32d9521, 0xada121ff, 0x29908415, 0x7fbb977f, 0xaf9eb3db, 0x29c9ed2a,
|
||
0x5ce2a465, 0xa730f32c, 0xd0aa3fe8, 0x8a5cc091, 0xd49e2ce7, 0x0ce454a9, 0xd60acd86, 0x015f1919,
|
||
0x77079103, 0xdea03af6, 0x78a8565e, 0xdee356df, 0x21f05cbe, 0x8b75e387, 0xb3c50651, 0xb8a5c3ef,
|
||
0xd8eeb6d2, 0xe523be77, 0xc2154529, 0x2f69efdf, 0xafe67afb, 0xf470c4b2, 0xf3e0eb5b, 0xd6cc9876,
|
||
0x39e4460c, 0x1fda8538, 0x1987832f, 0xca007367, 0xa99144f8, 0x296b299e, 0x492fc295, 0x9266beab,
|
||
0xb5676e69, 0x9bd3ddda, 0xdf7e052f, 0xdb25701c, 0x1b5e51ee, 0xf65324e6, 0x6afce36c, 0x0316cc04,
|
||
0x8644213e, 0xb7dc59d0, 0x7965291f, 0xccd6fd43, 0x41823979, 0x932bcdf6, 0xb657c34d, 0x4edfd282,
|
||
0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 0x13ecf0b0, 0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2);
|
||
|
||
sBox[4] = new Array(
|
||
0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, 0xb86a7fff, 0x1dd358f5, 0x44dd9d44, 0x1731167f,
|
||
0x08fbf1fa, 0xe7f511cc, 0xd2051b00, 0x735aba00, 0x2ab722d8, 0x386381cb, 0xacf6243a, 0x69befd7a,
|
||
0xe6a2e77f, 0xf0c720cd, 0xc4494816, 0xccf5c180, 0x38851640, 0x15b0a848, 0xe68b18cb, 0x4caadeff,
|
||
0x5f480a01, 0x0412b2aa, 0x259814fc, 0x41d0efe2, 0x4e40b48d, 0x248eb6fb, 0x8dba1cfe, 0x41a99b02,
|
||
0x1a550a04, 0xba8f65cb, 0x7251f4e7, 0x95a51725, 0xc106ecd7, 0x97a5980a, 0xc539b9aa, 0x4d79fe6a,
|
||
0xf2f3f763, 0x68af8040, 0xed0c9e56, 0x11b4958b, 0xe1eb5a88, 0x8709e6b0, 0xd7e07156, 0x4e29fea7,
|
||
0x6366e52d, 0x02d1c000, 0xc4ac8e05, 0x9377f571, 0x0c05372a, 0x578535f2, 0x2261be02, 0xd642a0c9,
|
||
0xdf13a280, 0x74b55bd2, 0x682199c0, 0xd421e5ec, 0x53fb3ce8, 0xc8adedb3, 0x28a87fc9, 0x3d959981,
|
||
0x5c1ff900, 0xfe38d399, 0x0c4eff0b, 0x062407ea, 0xaa2f4fb1, 0x4fb96976, 0x90c79505, 0xb0a8a774,
|
||
0xef55a1ff, 0xe59ca2c2, 0xa6b62d27, 0xe66a4263, 0xdf65001f, 0x0ec50966, 0xdfdd55bc, 0x29de0655,
|
||
0x911e739a, 0x17af8975, 0x32c7911c, 0x89f89468, 0x0d01e980, 0x524755f4, 0x03b63cc9, 0x0cc844b2,
|
||
0xbcf3f0aa, 0x87ac36e9, 0xe53a7426, 0x01b3d82b, 0x1a9e7449, 0x64ee2d7e, 0xcddbb1da, 0x01c94910,
|
||
0xb868bf80, 0x0d26f3fd, 0x9342ede7, 0x04a5c284, 0x636737b6, 0x50f5b616, 0xf24766e3, 0x8eca36c1,
|
||
0x136e05db, 0xfef18391, 0xfb887a37, 0xd6e7f7d4, 0xc7fb7dc9, 0x3063fcdf, 0xb6f589de, 0xec2941da,
|
||
0x26e46695, 0xb7566419, 0xf654efc5, 0xd08d58b7, 0x48925401, 0xc1bacb7f, 0xe5ff550f, 0xb6083049,
|
||
0x5bb5d0e8, 0x87d72e5a, 0xab6a6ee1, 0x223a66ce, 0xc62bf3cd, 0x9e0885f9, 0x68cb3e47, 0x086c010f,
|
||
0xa21de820, 0xd18b69de, 0xf3f65777, 0xfa02c3f6, 0x407edac3, 0xcbb3d550, 0x1793084d, 0xb0d70eba,
|
||
0x0ab378d5, 0xd951fb0c, 0xded7da56, 0x4124bbe4, 0x94ca0b56, 0x0f5755d1, 0xe0e1e56e, 0x6184b5be,
|
||
0x580a249f, 0x94f74bc0, 0xe327888e, 0x9f7b5561, 0xc3dc0280, 0x05687715, 0x646c6bd7, 0x44904db3,
|
||
0x66b4f0a3, 0xc0f1648a, 0x697ed5af, 0x49e92ff6, 0x309e374f, 0x2cb6356a, 0x85808573, 0x4991f840,
|
||
0x76f0ae02, 0x083be84d, 0x28421c9a, 0x44489406, 0x736e4cb8, 0xc1092910, 0x8bc95fc6, 0x7d869cf4,
|
||
0x134f616f, 0x2e77118d, 0xb31b2be1, 0xaa90b472, 0x3ca5d717, 0x7d161bba, 0x9cad9010, 0xaf462ba2,
|
||
0x9fe459d2, 0x45d34559, 0xd9f2da13, 0xdbc65487, 0xf3e4f94e, 0x176d486f, 0x097c13ea, 0x631da5c7,
|
||
0x445f7382, 0x175683f4, 0xcdc66a97, 0x70be0288, 0xb3cdcf72, 0x6e5dd2f3, 0x20936079, 0x459b80a5,
|
||
0xbe60e2db, 0xa9c23101, 0xeba5315c, 0x224e42f2, 0x1c5c1572, 0xf6721b2c, 0x1ad2fff3, 0x8c25404e,
|
||
0x324ed72f, 0x4067b7fd, 0x0523138e, 0x5ca3bc78, 0xdc0fd66e, 0x75922283, 0x784d6b17, 0x58ebb16e,
|
||
0x44094f85, 0x3f481d87, 0xfcfeae7b, 0x77b5ff76, 0x8c2302bf, 0xaaf47556, 0x5f46b02a, 0x2b092801,
|
||
0x3d38f5f7, 0x0ca81f36, 0x52af4a8a, 0x66d5e7c0, 0xdf3b0874, 0x95055110, 0x1b5ad7a8, 0xf61ed5ad,
|
||
0x6cf6e479, 0x20758184, 0xd0cefa65, 0x88f7be58, 0x4a046826, 0x0ff6f8f3, 0xa09c7f70, 0x5346aba0,
|
||
0x5ce96c28, 0xe176eda3, 0x6bac307f, 0x376829d2, 0x85360fa9, 0x17e3fe2a, 0x24b79767, 0xf5a96b20,
|
||
0xd6cd2595, 0x68ff1ebf, 0x7555442c, 0xf19f06be, 0xf9e0659a, 0xeeb9491d, 0x34010718, 0xbb30cab8,
|
||
0xe822fe15, 0x88570983, 0x750e6249, 0xda627e55, 0x5e76ffa8, 0xb1534546, 0x6d47de08, 0xefe9e7d4);
|
||
|
||
sBox[5] = new Array(
|
||
0xf6fa8f9d, 0x2cac6ce1, 0x4ca34867, 0xe2337f7c, 0x95db08e7, 0x016843b4, 0xeced5cbc, 0x325553ac,
|
||
0xbf9f0960, 0xdfa1e2ed, 0x83f0579d, 0x63ed86b9, 0x1ab6a6b8, 0xde5ebe39, 0xf38ff732, 0x8989b138,
|
||
0x33f14961, 0xc01937bd, 0xf506c6da, 0xe4625e7e, 0xa308ea99, 0x4e23e33c, 0x79cbd7cc, 0x48a14367,
|
||
0xa3149619, 0xfec94bd5, 0xa114174a, 0xeaa01866, 0xa084db2d, 0x09a8486f, 0xa888614a, 0x2900af98,
|
||
0x01665991, 0xe1992863, 0xc8f30c60, 0x2e78ef3c, 0xd0d51932, 0xcf0fec14, 0xf7ca07d2, 0xd0a82072,
|
||
0xfd41197e, 0x9305a6b0, 0xe86be3da, 0x74bed3cd, 0x372da53c, 0x4c7f4448, 0xdab5d440, 0x6dba0ec3,
|
||
0x083919a7, 0x9fbaeed9, 0x49dbcfb0, 0x4e670c53, 0x5c3d9c01, 0x64bdb941, 0x2c0e636a, 0xba7dd9cd,
|
||
0xea6f7388, 0xe70bc762, 0x35f29adb, 0x5c4cdd8d, 0xf0d48d8c, 0xb88153e2, 0x08a19866, 0x1ae2eac8,
|
||
0x284caf89, 0xaa928223, 0x9334be53, 0x3b3a21bf, 0x16434be3, 0x9aea3906, 0xefe8c36e, 0xf890cdd9,
|
||
0x80226dae, 0xc340a4a3, 0xdf7e9c09, 0xa694a807, 0x5b7c5ecc, 0x221db3a6, 0x9a69a02f, 0x68818a54,
|
||
0xceb2296f, 0x53c0843a, 0xfe893655, 0x25bfe68a, 0xb4628abc, 0xcf222ebf, 0x25ac6f48, 0xa9a99387,
|
||
0x53bddb65, 0xe76ffbe7, 0xe967fd78, 0x0ba93563, 0x8e342bc1, 0xe8a11be9, 0x4980740d, 0xc8087dfc,
|
||
0x8de4bf99, 0xa11101a0, 0x7fd37975, 0xda5a26c0, 0xe81f994f, 0x9528cd89, 0xfd339fed, 0xb87834bf,
|
||
0x5f04456d, 0x22258698, 0xc9c4c83b, 0x2dc156be, 0x4f628daa, 0x57f55ec5, 0xe2220abe, 0xd2916ebf,
|
||
0x4ec75b95, 0x24f2c3c0, 0x42d15d99, 0xcd0d7fa0, 0x7b6e27ff, 0xa8dc8af0, 0x7345c106, 0xf41e232f,
|
||
0x35162386, 0xe6ea8926, 0x3333b094, 0x157ec6f2, 0x372b74af, 0x692573e4, 0xe9a9d848, 0xf3160289,
|
||
0x3a62ef1d, 0xa787e238, 0xf3a5f676, 0x74364853, 0x20951063, 0x4576698d, 0xb6fad407, 0x592af950,
|
||
0x36f73523, 0x4cfb6e87, 0x7da4cec0, 0x6c152daa, 0xcb0396a8, 0xc50dfe5d, 0xfcd707ab, 0x0921c42f,
|
||
0x89dff0bb, 0x5fe2be78, 0x448f4f33, 0x754613c9, 0x2b05d08d, 0x48b9d585, 0xdc049441, 0xc8098f9b,
|
||
0x7dede786, 0xc39a3373, 0x42410005, 0x6a091751, 0x0ef3c8a6, 0x890072d6, 0x28207682, 0xa9a9f7be,
|
||
0xbf32679d, 0xd45b5b75, 0xb353fd00, 0xcbb0e358, 0x830f220a, 0x1f8fb214, 0xd372cf08, 0xcc3c4a13,
|
||
0x8cf63166, 0x061c87be, 0x88c98f88, 0x6062e397, 0x47cf8e7a, 0xb6c85283, 0x3cc2acfb, 0x3fc06976,
|
||
0x4e8f0252, 0x64d8314d, 0xda3870e3, 0x1e665459, 0xc10908f0, 0x513021a5, 0x6c5b68b7, 0x822f8aa0,
|
||
0x3007cd3e, 0x74719eef, 0xdc872681, 0x073340d4, 0x7e432fd9, 0x0c5ec241, 0x8809286c, 0xf592d891,
|
||
0x08a930f6, 0x957ef305, 0xb7fbffbd, 0xc266e96f, 0x6fe4ac98, 0xb173ecc0, 0xbc60b42a, 0x953498da,
|
||
0xfba1ae12, 0x2d4bd736, 0x0f25faab, 0xa4f3fceb, 0xe2969123, 0x257f0c3d, 0x9348af49, 0x361400bc,
|
||
0xe8816f4a, 0x3814f200, 0xa3f94043, 0x9c7a54c2, 0xbc704f57, 0xda41e7f9, 0xc25ad33a, 0x54f4a084,
|
||
0xb17f5505, 0x59357cbe, 0xedbd15c8, 0x7f97c5ab, 0xba5ac7b5, 0xb6f6deaf, 0x3a479c3a, 0x5302da25,
|
||
0x653d7e6a, 0x54268d49, 0x51a477ea, 0x5017d55b, 0xd7d25d88, 0x44136c76, 0x0404a8c8, 0xb8e5a121,
|
||
0xb81a928a, 0x60ed5869, 0x97c55b96, 0xeaec991b, 0x29935913, 0x01fdb7f1, 0x088e8dfa, 0x9ab6f6f5,
|
||
0x3b4cbf9f, 0x4a5de3ab, 0xe6051d35, 0xa0e1d855, 0xd36b4cf1, 0xf544edeb, 0xb0e93524, 0xbebb8fbd,
|
||
0xa2d762cf, 0x49c92f54, 0x38b5f331, 0x7128a454, 0x48392905, 0xa65b1db8, 0x851c97bd, 0xd675cf2f);
|
||
|
||
sBox[6] = new Array(
|
||
0x85e04019, 0x332bf567, 0x662dbfff, 0xcfc65693, 0x2a8d7f6f, 0xab9bc912, 0xde6008a1, 0x2028da1f,
|
||
0x0227bce7, 0x4d642916, 0x18fac300, 0x50f18b82, 0x2cb2cb11, 0xb232e75c, 0x4b3695f2, 0xb28707de,
|
||
0xa05fbcf6, 0xcd4181e9, 0xe150210c, 0xe24ef1bd, 0xb168c381, 0xfde4e789, 0x5c79b0d8, 0x1e8bfd43,
|
||
0x4d495001, 0x38be4341, 0x913cee1d, 0x92a79c3f, 0x089766be, 0xbaeeadf4, 0x1286becf, 0xb6eacb19,
|
||
0x2660c200, 0x7565bde4, 0x64241f7a, 0x8248dca9, 0xc3b3ad66, 0x28136086, 0x0bd8dfa8, 0x356d1cf2,
|
||
0x107789be, 0xb3b2e9ce, 0x0502aa8f, 0x0bc0351e, 0x166bf52a, 0xeb12ff82, 0xe3486911, 0xd34d7516,
|
||
0x4e7b3aff, 0x5f43671b, 0x9cf6e037, 0x4981ac83, 0x334266ce, 0x8c9341b7, 0xd0d854c0, 0xcb3a6c88,
|
||
0x47bc2829, 0x4725ba37, 0xa66ad22b, 0x7ad61f1e, 0x0c5cbafa, 0x4437f107, 0xb6e79962, 0x42d2d816,
|
||
0x0a961288, 0xe1a5c06e, 0x13749e67, 0x72fc081a, 0xb1d139f7, 0xf9583745, 0xcf19df58, 0xbec3f756,
|
||
0xc06eba30, 0x07211b24, 0x45c28829, 0xc95e317f, 0xbc8ec511, 0x38bc46e9, 0xc6e6fa14, 0xbae8584a,
|
||
0xad4ebc46, 0x468f508b, 0x7829435f, 0xf124183b, 0x821dba9f, 0xaff60ff4, 0xea2c4e6d, 0x16e39264,
|
||
0x92544a8b, 0x009b4fc3, 0xaba68ced, 0x9ac96f78, 0x06a5b79a, 0xb2856e6e, 0x1aec3ca9, 0xbe838688,
|
||
0x0e0804e9, 0x55f1be56, 0xe7e5363b, 0xb3a1f25d, 0xf7debb85, 0x61fe033c, 0x16746233, 0x3c034c28,
|
||
0xda6d0c74, 0x79aac56c, 0x3ce4e1ad, 0x51f0c802, 0x98f8f35a, 0x1626a49f, 0xeed82b29, 0x1d382fe3,
|
||
0x0c4fb99a, 0xbb325778, 0x3ec6d97b, 0x6e77a6a9, 0xcb658b5c, 0xd45230c7, 0x2bd1408b, 0x60c03eb7,
|
||
0xb9068d78, 0xa33754f4, 0xf430c87d, 0xc8a71302, 0xb96d8c32, 0xebd4e7be, 0xbe8b9d2d, 0x7979fb06,
|
||
0xe7225308, 0x8b75cf77, 0x11ef8da4, 0xe083c858, 0x8d6b786f, 0x5a6317a6, 0xfa5cf7a0, 0x5dda0033,
|
||
0xf28ebfb0, 0xf5b9c310, 0xa0eac280, 0x08b9767a, 0xa3d9d2b0, 0x79d34217, 0x021a718d, 0x9ac6336a,
|
||
0x2711fd60, 0x438050e3, 0x069908a8, 0x3d7fedc4, 0x826d2bef, 0x4eeb8476, 0x488dcf25, 0x36c9d566,
|
||
0x28e74e41, 0xc2610aca, 0x3d49a9cf, 0xbae3b9df, 0xb65f8de6, 0x92aeaf64, 0x3ac7d5e6, 0x9ea80509,
|
||
0xf22b017d, 0xa4173f70, 0xdd1e16c3, 0x15e0d7f9, 0x50b1b887, 0x2b9f4fd5, 0x625aba82, 0x6a017962,
|
||
0x2ec01b9c, 0x15488aa9, 0xd716e740, 0x40055a2c, 0x93d29a22, 0xe32dbf9a, 0x058745b9, 0x3453dc1e,
|
||
0xd699296e, 0x496cff6f, 0x1c9f4986, 0xdfe2ed07, 0xb87242d1, 0x19de7eae, 0x053e561a, 0x15ad6f8c,
|
||
0x66626c1c, 0x7154c24c, 0xea082b2a, 0x93eb2939, 0x17dcb0f0, 0x58d4f2ae, 0x9ea294fb, 0x52cf564c,
|
||
0x9883fe66, 0x2ec40581, 0x763953c3, 0x01d6692e, 0xd3a0c108, 0xa1e7160e, 0xe4f2dfa6, 0x693ed285,
|
||
0x74904698, 0x4c2b0edd, 0x4f757656, 0x5d393378, 0xa132234f, 0x3d321c5d, 0xc3f5e194, 0x4b269301,
|
||
0xc79f022f, 0x3c997e7e, 0x5e4f9504, 0x3ffafbbd, 0x76f7ad0e, 0x296693f4, 0x3d1fce6f, 0xc61e45be,
|
||
0xd3b5ab34, 0xf72bf9b7, 0x1b0434c0, 0x4e72b567, 0x5592a33d, 0xb5229301, 0xcfd2a87f, 0x60aeb767,
|
||
0x1814386b, 0x30bcc33d, 0x38a0c07d, 0xfd1606f2, 0xc363519b, 0x589dd390, 0x5479f8e6, 0x1cb8d647,
|
||
0x97fd61a9, 0xea7759f4, 0x2d57539d, 0x569a58cf, 0xe84e63ad, 0x462e1b78, 0x6580f87e, 0xf3817914,
|
||
0x91da55f4, 0x40a230f3, 0xd1988f35, 0xb6e318d2, 0x3ffa50bc, 0x3d40f021, 0xc3c0bdae, 0x4958c24c,
|
||
0x518f36b2, 0x84b1d370, 0x0fedce83, 0x878ddada, 0xf2a279c7, 0x94e01be8, 0x90716f4b, 0x954b8aa3);
|
||
|
||
sBox[7] = new Array(
|
||
0xe216300d, 0xbbddfffc, 0xa7ebdabd, 0x35648095, 0x7789f8b7, 0xe6c1121b, 0x0e241600, 0x052ce8b5,
|
||
0x11a9cfb0, 0xe5952f11, 0xece7990a, 0x9386d174, 0x2a42931c, 0x76e38111, 0xb12def3a, 0x37ddddfc,
|
||
0xde9adeb1, 0x0a0cc32c, 0xbe197029, 0x84a00940, 0xbb243a0f, 0xb4d137cf, 0xb44e79f0, 0x049eedfd,
|
||
0x0b15a15d, 0x480d3168, 0x8bbbde5a, 0x669ded42, 0xc7ece831, 0x3f8f95e7, 0x72df191b, 0x7580330d,
|
||
0x94074251, 0x5c7dcdfa, 0xabbe6d63, 0xaa402164, 0xb301d40a, 0x02e7d1ca, 0x53571dae, 0x7a3182a2,
|
||
0x12a8ddec, 0xfdaa335d, 0x176f43e8, 0x71fb46d4, 0x38129022, 0xce949ad4, 0xb84769ad, 0x965bd862,
|
||
0x82f3d055, 0x66fb9767, 0x15b80b4e, 0x1d5b47a0, 0x4cfde06f, 0xc28ec4b8, 0x57e8726e, 0x647a78fc,
|
||
0x99865d44, 0x608bd593, 0x6c200e03, 0x39dc5ff6, 0x5d0b00a3, 0xae63aff2, 0x7e8bd632, 0x70108c0c,
|
||
0xbbd35049, 0x2998df04, 0x980cf42a, 0x9b6df491, 0x9e7edd53, 0x06918548, 0x58cb7e07, 0x3b74ef2e,
|
||
0x522fffb1, 0xd24708cc, 0x1c7e27cd, 0xa4eb215b, 0x3cf1d2e2, 0x19b47a38, 0x424f7618, 0x35856039,
|
||
0x9d17dee7, 0x27eb35e6, 0xc9aff67b, 0x36baf5b8, 0x09c467cd, 0xc18910b1, 0xe11dbf7b, 0x06cd1af8,
|
||
0x7170c608, 0x2d5e3354, 0xd4de495a, 0x64c6d006, 0xbcc0c62c, 0x3dd00db3, 0x708f8f34, 0x77d51b42,
|
||
0x264f620f, 0x24b8d2bf, 0x15c1b79e, 0x46a52564, 0xf8d7e54e, 0x3e378160, 0x7895cda5, 0x859c15a5,
|
||
0xe6459788, 0xc37bc75f, 0xdb07ba0c, 0x0676a3ab, 0x7f229b1e, 0x31842e7b, 0x24259fd7, 0xf8bef472,
|
||
0x835ffcb8, 0x6df4c1f2, 0x96f5b195, 0xfd0af0fc, 0xb0fe134c, 0xe2506d3d, 0x4f9b12ea, 0xf215f225,
|
||
0xa223736f, 0x9fb4c428, 0x25d04979, 0x34c713f8, 0xc4618187, 0xea7a6e98, 0x7cd16efc, 0x1436876c,
|
||
0xf1544107, 0xbedeee14, 0x56e9af27, 0xa04aa441, 0x3cf7c899, 0x92ecbae6, 0xdd67016d, 0x151682eb,
|
||
0xa842eedf, 0xfdba60b4, 0xf1907b75, 0x20e3030f, 0x24d8c29e, 0xe139673b, 0xefa63fb8, 0x71873054,
|
||
0xb6f2cf3b, 0x9f326442, 0xcb15a4cc, 0xb01a4504, 0xf1e47d8d, 0x844a1be5, 0xbae7dfdc, 0x42cbda70,
|
||
0xcd7dae0a, 0x57e85b7a, 0xd53f5af6, 0x20cf4d8c, 0xcea4d428, 0x79d130a4, 0x3486ebfb, 0x33d3cddc,
|
||
0x77853b53, 0x37effcb5, 0xc5068778, 0xe580b3e6, 0x4e68b8f4, 0xc5c8b37e, 0x0d809ea2, 0x398feb7c,
|
||
0x132a4f94, 0x43b7950e, 0x2fee7d1c, 0x223613bd, 0xdd06caa2, 0x37df932b, 0xc4248289, 0xacf3ebc3,
|
||
0x5715f6b7, 0xef3478dd, 0xf267616f, 0xc148cbe4, 0x9052815e, 0x5e410fab, 0xb48a2465, 0x2eda7fa4,
|
||
0xe87b40e4, 0xe98ea084, 0x5889e9e1, 0xefd390fc, 0xdd07d35b, 0xdb485694, 0x38d7e5b2, 0x57720101,
|
||
0x730edebc, 0x5b643113, 0x94917e4f, 0x503c2fba, 0x646f1282, 0x7523d24a, 0xe0779695, 0xf9c17a8f,
|
||
0x7a5b2121, 0xd187b896, 0x29263a4d, 0xba510cdf, 0x81f47c9f, 0xad1163ed, 0xea7b5965, 0x1a00726e,
|
||
0x11403092, 0x00da6d77, 0x4a0cdd61, 0xad1f4603, 0x605bdfb0, 0x9eedc364, 0x22ebe6a8, 0xcee7d28a,
|
||
0xa0e736a0, 0x5564a6b9, 0x10853209, 0xc7eb8f37, 0x2de705ca, 0x8951570f, 0xdf09822b, 0xbd691a6c,
|
||
0xaa12e4f2, 0x87451c0f, 0xe0f6a27a, 0x3ada4819, 0x4cf1764f, 0x0d771c2b, 0x67cdb156, 0x350d8384,
|
||
0x5938fa0f, 0x42399ef3, 0x36997b07, 0x0e84093d, 0x4aa93e61, 0x8360d87b, 0x1fa98b0c, 0x1149382c,
|
||
0xe97625a5, 0x0614d1b7, 0x0e25244b, 0x0c768347, 0x589e8d82, 0x0d2059d1, 0xa466bb1e, 0xf8da0a82,
|
||
0x04f19130, 0xba6e4ec0, 0x99265164, 0x1ee7230d, 0x50b2ad80, 0xeaee6801, 0x8db2a283, 0xea8bf59e);
|
||
|
||
};
|
||
|
||
var util = require('../../util');
|
||
|
||
function cast5(key) {
|
||
this.cast5 = new openpgp_symenc_cast5();
|
||
this.cast5.setKey(util.str2bin(key));
|
||
|
||
this.encrypt = function(block) {
|
||
return this.cast5.encrypt(block);
|
||
}
|
||
}
|
||
|
||
module.exports = cast5;
|
||
module.exports.blockSize = cast5.prototype.blockSize = 8;
|
||
module.exports.keySize = cast5.prototype.keySize = 16;
|
||
|
||
},{"../../util":56}],8:[function(require,module,exports){
|
||
//Paul Tero, July 2001
|
||
//http://www.tero.co.uk/des/
|
||
//
|
||
//Optimised for performance with large blocks by Michael Hayworth, November 2001
|
||
//http://www.netdealing.com
|
||
//
|
||
// Modified by Recurity Labs GmbH
|
||
|
||
//THIS SOFTWARE IS PROVIDED "AS IS" AND
|
||
//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||
//IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||
//ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||
//FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||
//DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||
//OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||
//HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||
//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||
//OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||
//SUCH DAMAGE.
|
||
|
||
//des
|
||
//this takes the key, the message, and whether to encrypt or decrypt
|
||
|
||
|
||
|
||
|
||
function des(keys, message, encrypt, mode, iv, padding) {
|
||
//declaring this locally speeds things up a bit
|
||
var spfunction1 = new Array(0x1010400, 0, 0x10000, 0x1010404, 0x1010004, 0x10404, 0x4, 0x10000, 0x400, 0x1010400,
|
||
0x1010404, 0x400, 0x1000404, 0x1010004, 0x1000000, 0x4, 0x404, 0x1000400, 0x1000400, 0x10400, 0x10400, 0x1010000,
|
||
0x1010000, 0x1000404, 0x10004, 0x1000004, 0x1000004, 0x10004, 0, 0x404, 0x10404, 0x1000000, 0x10000, 0x1010404, 0x4,
|
||
0x1010000, 0x1010400, 0x1000000, 0x1000000, 0x400, 0x1010004, 0x10000, 0x10400, 0x1000004, 0x400, 0x4, 0x1000404,
|
||
0x10404, 0x1010404, 0x10004, 0x1010000, 0x1000404, 0x1000004, 0x404, 0x10404, 0x1010400, 0x404, 0x1000400,
|
||
0x1000400, 0, 0x10004, 0x10400, 0, 0x1010004);
|
||
var spfunction2 = new Array(-0x7fef7fe0, -0x7fff8000, 0x8000, 0x108020, 0x100000, 0x20, -0x7fefffe0, -0x7fff7fe0, -
|
||
0x7fffffe0, -0x7fef7fe0, -0x7fef8000, -0x80000000, -0x7fff8000, 0x100000, 0x20, -0x7fefffe0, 0x108000, 0x100020, -
|
||
0x7fff7fe0, 0, -0x80000000, 0x8000, 0x108020, -0x7ff00000, 0x100020, -0x7fffffe0, 0, 0x108000, 0x8020, -0x7fef8000, -
|
||
0x7ff00000, 0x8020, 0, 0x108020, -0x7fefffe0, 0x100000, -0x7fff7fe0, -0x7ff00000, -0x7fef8000, 0x8000, -0x7ff00000, -
|
||
0x7fff8000, 0x20, -0x7fef7fe0, 0x108020, 0x20, 0x8000, -0x80000000, 0x8020, -0x7fef8000, 0x100000, -0x7fffffe0,
|
||
0x100020, -0x7fff7fe0, -0x7fffffe0, 0x100020, 0x108000, 0, -0x7fff8000, 0x8020, -0x80000000, -0x7fefffe0, -
|
||
0x7fef7fe0, 0x108000);
|
||
var spfunction3 = new Array(0x208, 0x8020200, 0, 0x8020008, 0x8000200, 0, 0x20208, 0x8000200, 0x20008, 0x8000008,
|
||
0x8000008, 0x20000, 0x8020208, 0x20008, 0x8020000, 0x208, 0x8000000, 0x8, 0x8020200, 0x200, 0x20200, 0x8020000,
|
||
0x8020008, 0x20208, 0x8000208, 0x20200, 0x20000, 0x8000208, 0x8, 0x8020208, 0x200, 0x8000000, 0x8020200, 0x8000000,
|
||
0x20008, 0x208, 0x20000, 0x8020200, 0x8000200, 0, 0x200, 0x20008, 0x8020208, 0x8000200, 0x8000008, 0x200, 0,
|
||
0x8020008, 0x8000208, 0x20000, 0x8000000, 0x8020208, 0x8, 0x20208, 0x20200, 0x8000008, 0x8020000, 0x8000208, 0x208,
|
||
0x8020000, 0x20208, 0x8, 0x8020008, 0x20200);
|
||
var spfunction4 = new Array(0x802001, 0x2081, 0x2081, 0x80, 0x802080, 0x800081, 0x800001, 0x2001, 0, 0x802000,
|
||
0x802000, 0x802081, 0x81, 0, 0x800080, 0x800001, 0x1, 0x2000, 0x800000, 0x802001, 0x80, 0x800000, 0x2001, 0x2080,
|
||
0x800081, 0x1, 0x2080, 0x800080, 0x2000, 0x802080, 0x802081, 0x81, 0x800080, 0x800001, 0x802000, 0x802081, 0x81, 0,
|
||
0, 0x802000, 0x2080, 0x800080, 0x800081, 0x1, 0x802001, 0x2081, 0x2081, 0x80, 0x802081, 0x81, 0x1, 0x2000, 0x800001,
|
||
0x2001, 0x802080, 0x800081, 0x2001, 0x2080, 0x800000, 0x802001, 0x80, 0x800000, 0x2000, 0x802080);
|
||
var spfunction5 = new Array(0x100, 0x2080100, 0x2080000, 0x42000100, 0x80000, 0x100, 0x40000000, 0x2080000,
|
||
0x40080100, 0x80000, 0x2000100, 0x40080100, 0x42000100, 0x42080000, 0x80100, 0x40000000, 0x2000000, 0x40080000,
|
||
0x40080000, 0, 0x40000100, 0x42080100, 0x42080100, 0x2000100, 0x42080000, 0x40000100, 0, 0x42000000, 0x2080100,
|
||
0x2000000, 0x42000000, 0x80100, 0x80000, 0x42000100, 0x100, 0x2000000, 0x40000000, 0x2080000, 0x42000100,
|
||
0x40080100, 0x2000100, 0x40000000, 0x42080000, 0x2080100, 0x40080100, 0x100, 0x2000000, 0x42080000, 0x42080100,
|
||
0x80100, 0x42000000, 0x42080100, 0x2080000, 0, 0x40080000, 0x42000000, 0x80100, 0x2000100, 0x40000100, 0x80000, 0,
|
||
0x40080000, 0x2080100, 0x40000100);
|
||
var spfunction6 = new Array(0x20000010, 0x20400000, 0x4000, 0x20404010, 0x20400000, 0x10, 0x20404010, 0x400000,
|
||
0x20004000, 0x404010, 0x400000, 0x20000010, 0x400010, 0x20004000, 0x20000000, 0x4010, 0, 0x400010, 0x20004010,
|
||
0x4000, 0x404000, 0x20004010, 0x10, 0x20400010, 0x20400010, 0, 0x404010, 0x20404000, 0x4010, 0x404000, 0x20404000,
|
||
0x20000000, 0x20004000, 0x10, 0x20400010, 0x404000, 0x20404010, 0x400000, 0x4010, 0x20000010, 0x400000, 0x20004000,
|
||
0x20000000, 0x4010, 0x20000010, 0x20404010, 0x404000, 0x20400000, 0x404010, 0x20404000, 0, 0x20400010, 0x10, 0x4000,
|
||
0x20400000, 0x404010, 0x4000, 0x400010, 0x20004010, 0, 0x20404000, 0x20000000, 0x400010, 0x20004010);
|
||
var spfunction7 = new Array(0x200000, 0x4200002, 0x4000802, 0, 0x800, 0x4000802, 0x200802, 0x4200800, 0x4200802,
|
||
0x200000, 0, 0x4000002, 0x2, 0x4000000, 0x4200002, 0x802, 0x4000800, 0x200802, 0x200002, 0x4000800, 0x4000002,
|
||
0x4200000, 0x4200800, 0x200002, 0x4200000, 0x800, 0x802, 0x4200802, 0x200800, 0x2, 0x4000000, 0x200800, 0x4000000,
|
||
0x200800, 0x200000, 0x4000802, 0x4000802, 0x4200002, 0x4200002, 0x2, 0x200002, 0x4000000, 0x4000800, 0x200000,
|
||
0x4200800, 0x802, 0x200802, 0x4200800, 0x802, 0x4000002, 0x4200802, 0x4200000, 0x200800, 0, 0x2, 0x4200802, 0,
|
||
0x200802, 0x4200000, 0x800, 0x4000002, 0x4000800, 0x800, 0x200002);
|
||
var spfunction8 = new Array(0x10001040, 0x1000, 0x40000, 0x10041040, 0x10000000, 0x10001040, 0x40, 0x10000000,
|
||
0x40040, 0x10040000, 0x10041040, 0x41000, 0x10041000, 0x41040, 0x1000, 0x40, 0x10040000, 0x10000040, 0x10001000,
|
||
0x1040, 0x41000, 0x40040, 0x10040040, 0x10041000, 0x1040, 0, 0, 0x10040040, 0x10000040, 0x10001000, 0x41040,
|
||
0x40000, 0x41040, 0x40000, 0x10041000, 0x1000, 0x40, 0x10040040, 0x1000, 0x41040, 0x10001000, 0x40, 0x10000040,
|
||
0x10040000, 0x10040040, 0x10000000, 0x40000, 0x10001040, 0, 0x10041040, 0x40040, 0x10000040, 0x10040000, 0x10001000,
|
||
0x10001040, 0, 0x10041040, 0x41000, 0x41000, 0x1040, 0x1040, 0x40040, 0x10000000, 0x10041000);
|
||
|
||
//create the 16 or 48 subkeys we will need
|
||
var m = 0,
|
||
i, j, temp, temp2, right1, right2, left, right, looping;
|
||
var cbcleft, cbcleft2, cbcright, cbcright2
|
||
var endloop, loopinc;
|
||
var len = message.length;
|
||
var chunk = 0;
|
||
//set up the loops for single and triple des
|
||
var iterations = keys.length == 32 ? 3 : 9; //single or triple des
|
||
if (iterations == 3) {
|
||
looping = encrypt ? new Array(0, 32, 2) : new Array(30, -2, -2);
|
||
} else {
|
||
looping = encrypt ? new Array(0, 32, 2, 62, 30, -2, 64, 96, 2) : new Array(94, 62, -2, 32, 64, 2, 30, -2, -2);
|
||
}
|
||
|
||
//pad the message depending on the padding parameter
|
||
//only add padding if encrypting - note that you need to use the same padding option for both encrypt and decrypt
|
||
if (encrypt) {
|
||
message = des_addPadding(message, padding);
|
||
len = message.length;
|
||
}
|
||
|
||
//store the result here
|
||
result = "";
|
||
tempresult = "";
|
||
|
||
if (mode == 1) { //CBC mode
|
||
cbcleft = (iv.charCodeAt(m++) << 24) | (iv.charCodeAt(m++) << 16) | (iv.charCodeAt(m++) << 8) | iv.charCodeAt(m++);
|
||
cbcright = (iv.charCodeAt(m++) << 24) | (iv.charCodeAt(m++) << 16) | (iv.charCodeAt(m++) << 8) | iv.charCodeAt(m++);
|
||
m = 0;
|
||
}
|
||
|
||
//loop through each 64 bit chunk of the message
|
||
while (m < len) {
|
||
left = (message.charCodeAt(m++) << 24) | (message.charCodeAt(m++) << 16) | (message.charCodeAt(m++) << 8) | message
|
||
.charCodeAt(m++);
|
||
right = (message.charCodeAt(m++) << 24) | (message.charCodeAt(m++) << 16) | (message.charCodeAt(m++) << 8) |
|
||
message.charCodeAt(m++);
|
||
|
||
//for Cipher Block Chaining mode, xor the message with the previous result
|
||
if (mode == 1) {
|
||
if (encrypt) {
|
||
left ^= cbcleft;
|
||
right ^= cbcright;
|
||
} else {
|
||
cbcleft2 = cbcleft;
|
||
cbcright2 = cbcright;
|
||
cbcleft = left;
|
||
cbcright = right;
|
||
}
|
||
}
|
||
|
||
//first each 64 but chunk of the message must be permuted according to IP
|
||
temp = ((left >>> 4) ^ right) & 0x0f0f0f0f;
|
||
right ^= temp;
|
||
left ^= (temp << 4);
|
||
temp = ((left >>> 16) ^ right) & 0x0000ffff;
|
||
right ^= temp;
|
||
left ^= (temp << 16);
|
||
temp = ((right >>> 2) ^ left) & 0x33333333;
|
||
left ^= temp;
|
||
right ^= (temp << 2);
|
||
temp = ((right >>> 8) ^ left) & 0x00ff00ff;
|
||
left ^= temp;
|
||
right ^= (temp << 8);
|
||
temp = ((left >>> 1) ^ right) & 0x55555555;
|
||
right ^= temp;
|
||
left ^= (temp << 1);
|
||
|
||
left = ((left << 1) | (left >>> 31));
|
||
right = ((right << 1) | (right >>> 31));
|
||
|
||
//do this either 1 or 3 times for each chunk of the message
|
||
for (j = 0; j < iterations; j += 3) {
|
||
endloop = looping[j + 1];
|
||
loopinc = looping[j + 2];
|
||
//now go through and perform the encryption or decryption
|
||
for (i = looping[j]; i != endloop; i += loopinc) { //for efficiency
|
||
right1 = right ^ keys[i];
|
||
right2 = ((right >>> 4) | (right << 28)) ^ keys[i + 1];
|
||
//the result is attained by passing these bytes through the S selection functions
|
||
temp = left;
|
||
left = right;
|
||
right = temp ^ (spfunction2[(right1 >>> 24) & 0x3f] | spfunction4[(right1 >>> 16) & 0x3f] | spfunction6[(right1 >>>
|
||
8) & 0x3f] | spfunction8[right1 & 0x3f] | spfunction1[(right2 >>> 24) & 0x3f] | spfunction3[(right2 >>> 16) &
|
||
0x3f] | spfunction5[(right2 >>> 8) & 0x3f] | spfunction7[right2 & 0x3f]);
|
||
}
|
||
temp = left;
|
||
left = right;
|
||
right = temp; //unreverse left and right
|
||
} //for either 1 or 3 iterations
|
||
|
||
//move then each one bit to the right
|
||
left = ((left >>> 1) | (left << 31));
|
||
right = ((right >>> 1) | (right << 31));
|
||
|
||
//now perform IP-1, which is IP in the opposite direction
|
||
temp = ((left >>> 1) ^ right) & 0x55555555;
|
||
right ^= temp;
|
||
left ^= (temp << 1);
|
||
temp = ((right >>> 8) ^ left) & 0x00ff00ff;
|
||
left ^= temp;
|
||
right ^= (temp << 8);
|
||
temp = ((right >>> 2) ^ left) & 0x33333333;
|
||
left ^= temp;
|
||
right ^= (temp << 2);
|
||
temp = ((left >>> 16) ^ right) & 0x0000ffff;
|
||
right ^= temp;
|
||
left ^= (temp << 16);
|
||
temp = ((left >>> 4) ^ right) & 0x0f0f0f0f;
|
||
right ^= temp;
|
||
left ^= (temp << 4);
|
||
|
||
//for Cipher Block Chaining mode, xor the message with the previous result
|
||
if (mode == 1) {
|
||
if (encrypt) {
|
||
cbcleft = left;
|
||
cbcright = right;
|
||
} else {
|
||
left ^= cbcleft2;
|
||
right ^= cbcright2;
|
||
}
|
||
}
|
||
tempresult += String.fromCharCode((left >>> 24), ((left >>> 16) & 0xff), ((left >>> 8) & 0xff), (left & 0xff), (
|
||
right >>> 24), ((right >>> 16) & 0xff), ((right >>> 8) & 0xff), (right & 0xff));
|
||
|
||
chunk += 8;
|
||
if (chunk == 512) {
|
||
result += tempresult;
|
||
tempresult = "";
|
||
chunk = 0;
|
||
}
|
||
} //for every 8 characters, or 64 bits in the message
|
||
|
||
//return the result as an array
|
||
result += tempresult;
|
||
|
||
//only remove padding if decrypting - note that you need to use the same padding option for both encrypt and decrypt
|
||
if (!encrypt) {
|
||
result = des_removePadding(result, padding);
|
||
}
|
||
|
||
return result;
|
||
} //end of des
|
||
|
||
|
||
|
||
//des_createKeys
|
||
//this takes as input a 64 bit key (even though only 56 bits are used)
|
||
//as an array of 2 integers, and returns 16 48 bit keys
|
||
|
||
function des_createKeys(key) {
|
||
//declaring this locally speeds things up a bit
|
||
pc2bytes0 = new Array(0, 0x4, 0x20000000, 0x20000004, 0x10000, 0x10004, 0x20010000, 0x20010004, 0x200, 0x204,
|
||
0x20000200, 0x20000204, 0x10200, 0x10204, 0x20010200, 0x20010204);
|
||
pc2bytes1 = new Array(0, 0x1, 0x100000, 0x100001, 0x4000000, 0x4000001, 0x4100000, 0x4100001, 0x100, 0x101, 0x100100,
|
||
0x100101, 0x4000100, 0x4000101, 0x4100100, 0x4100101);
|
||
pc2bytes2 = new Array(0, 0x8, 0x800, 0x808, 0x1000000, 0x1000008, 0x1000800, 0x1000808, 0, 0x8, 0x800, 0x808,
|
||
0x1000000, 0x1000008, 0x1000800, 0x1000808);
|
||
pc2bytes3 = new Array(0, 0x200000, 0x8000000, 0x8200000, 0x2000, 0x202000, 0x8002000, 0x8202000, 0x20000, 0x220000,
|
||
0x8020000, 0x8220000, 0x22000, 0x222000, 0x8022000, 0x8222000);
|
||
pc2bytes4 = new Array(0, 0x40000, 0x10, 0x40010, 0, 0x40000, 0x10, 0x40010, 0x1000, 0x41000, 0x1010, 0x41010, 0x1000,
|
||
0x41000, 0x1010, 0x41010);
|
||
pc2bytes5 = new Array(0, 0x400, 0x20, 0x420, 0, 0x400, 0x20, 0x420, 0x2000000, 0x2000400, 0x2000020, 0x2000420,
|
||
0x2000000, 0x2000400, 0x2000020, 0x2000420);
|
||
pc2bytes6 = new Array(0, 0x10000000, 0x80000, 0x10080000, 0x2, 0x10000002, 0x80002, 0x10080002, 0, 0x10000000,
|
||
0x80000, 0x10080000, 0x2, 0x10000002, 0x80002, 0x10080002);
|
||
pc2bytes7 = new Array(0, 0x10000, 0x800, 0x10800, 0x20000000, 0x20010000, 0x20000800, 0x20010800, 0x20000, 0x30000,
|
||
0x20800, 0x30800, 0x20020000, 0x20030000, 0x20020800, 0x20030800);
|
||
pc2bytes8 = new Array(0, 0x40000, 0, 0x40000, 0x2, 0x40002, 0x2, 0x40002, 0x2000000, 0x2040000, 0x2000000, 0x2040000,
|
||
0x2000002, 0x2040002, 0x2000002, 0x2040002);
|
||
pc2bytes9 = new Array(0, 0x10000000, 0x8, 0x10000008, 0, 0x10000000, 0x8, 0x10000008, 0x400, 0x10000400, 0x408,
|
||
0x10000408, 0x400, 0x10000400, 0x408, 0x10000408);
|
||
pc2bytes10 = new Array(0, 0x20, 0, 0x20, 0x100000, 0x100020, 0x100000, 0x100020, 0x2000, 0x2020, 0x2000, 0x2020,
|
||
0x102000, 0x102020, 0x102000, 0x102020);
|
||
pc2bytes11 = new Array(0, 0x1000000, 0x200, 0x1000200, 0x200000, 0x1200000, 0x200200, 0x1200200, 0x4000000, 0x5000000,
|
||
0x4000200, 0x5000200, 0x4200000, 0x5200000, 0x4200200, 0x5200200);
|
||
pc2bytes12 = new Array(0, 0x1000, 0x8000000, 0x8001000, 0x80000, 0x81000, 0x8080000, 0x8081000, 0x10, 0x1010,
|
||
0x8000010, 0x8001010, 0x80010, 0x81010, 0x8080010, 0x8081010);
|
||
pc2bytes13 = new Array(0, 0x4, 0x100, 0x104, 0, 0x4, 0x100, 0x104, 0x1, 0x5, 0x101, 0x105, 0x1, 0x5, 0x101, 0x105);
|
||
|
||
//how many iterations (1 for des, 3 for triple des)
|
||
var iterations = key.length > 8 ? 3 : 1; //changed by Paul 16/6/2007 to use Triple DES for 9+ byte keys
|
||
//stores the return keys
|
||
var keys = new Array(32 * iterations);
|
||
//now define the left shifts which need to be done
|
||
var shifts = new Array(0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0);
|
||
//other variables
|
||
var lefttemp, righttemp, m = 0,
|
||
n = 0,
|
||
temp;
|
||
|
||
for (var j = 0; j < iterations; j++) { //either 1 or 3 iterations
|
||
left = (key.charCodeAt(m++) << 24) | (key.charCodeAt(m++) << 16) | (key.charCodeAt(m++) << 8) | key.charCodeAt(m++);
|
||
right = (key.charCodeAt(m++) << 24) | (key.charCodeAt(m++) << 16) | (key.charCodeAt(m++) << 8) | key.charCodeAt(m++);
|
||
|
||
temp = ((left >>> 4) ^ right) & 0x0f0f0f0f;
|
||
right ^= temp;
|
||
left ^= (temp << 4);
|
||
temp = ((right >>> -16) ^ left) & 0x0000ffff;
|
||
left ^= temp;
|
||
right ^= (temp << -16);
|
||
temp = ((left >>> 2) ^ right) & 0x33333333;
|
||
right ^= temp;
|
||
left ^= (temp << 2);
|
||
temp = ((right >>> -16) ^ left) & 0x0000ffff;
|
||
left ^= temp;
|
||
right ^= (temp << -16);
|
||
temp = ((left >>> 1) ^ right) & 0x55555555;
|
||
right ^= temp;
|
||
left ^= (temp << 1);
|
||
temp = ((right >>> 8) ^ left) & 0x00ff00ff;
|
||
left ^= temp;
|
||
right ^= (temp << 8);
|
||
temp = ((left >>> 1) ^ right) & 0x55555555;
|
||
right ^= temp;
|
||
left ^= (temp << 1);
|
||
|
||
//the right side needs to be shifted and to get the last four bits of the left side
|
||
temp = (left << 8) | ((right >>> 20) & 0x000000f0);
|
||
//left needs to be put upside down
|
||
left = (right << 24) | ((right << 8) & 0xff0000) | ((right >>> 8) & 0xff00) | ((right >>> 24) & 0xf0);
|
||
right = temp;
|
||
|
||
//now go through and perform these shifts on the left and right keys
|
||
for (i = 0; i < shifts.length; i++) {
|
||
//shift the keys either one or two bits to the left
|
||
if (shifts[i]) {
|
||
left = (left << 2) | (left >>> 26);
|
||
right = (right << 2) | (right >>> 26);
|
||
} else {
|
||
left = (left << 1) | (left >>> 27);
|
||
right = (right << 1) | (right >>> 27);
|
||
}
|
||
left &= -0xf;
|
||
right &= -0xf;
|
||
|
||
//now apply PC-2, in such a way that E is easier when encrypting or decrypting
|
||
//this conversion will look like PC-2 except only the last 6 bits of each byte are used
|
||
//rather than 48 consecutive bits and the order of lines will be according to
|
||
//how the S selection functions will be applied: S2, S4, S6, S8, S1, S3, S5, S7
|
||
lefttemp = pc2bytes0[left >>> 28] | pc2bytes1[(left >>> 24) & 0xf] | pc2bytes2[(left >>> 20) & 0xf] | pc2bytes3[(
|
||
left >>> 16) & 0xf] | pc2bytes4[(left >>> 12) & 0xf] | pc2bytes5[(left >>> 8) & 0xf] | pc2bytes6[(left >>> 4) &
|
||
0xf];
|
||
righttemp = pc2bytes7[right >>> 28] | pc2bytes8[(right >>> 24) & 0xf] | pc2bytes9[(right >>> 20) & 0xf] |
|
||
pc2bytes10[(right >>> 16) & 0xf] | pc2bytes11[(right >>> 12) & 0xf] | pc2bytes12[(right >>> 8) & 0xf] |
|
||
pc2bytes13[(right >>> 4) & 0xf];
|
||
temp = ((righttemp >>> 16) ^ lefttemp) & 0x0000ffff;
|
||
keys[n++] = lefttemp ^ temp;
|
||
keys[n++] = righttemp ^ (temp << 16);
|
||
}
|
||
} //for each iterations
|
||
//return the keys we've created
|
||
return keys;
|
||
} //end of des_createKeys
|
||
|
||
|
||
function des_addPadding(message, padding) {
|
||
var padLength = 8 - (message.length % 8);
|
||
if ((padding == 2) && (padLength < 8)) { //pad the message with spaces
|
||
message += " ".substr(0, padLength);
|
||
} else if (padding == 1) { //PKCS7 padding
|
||
message += String.fromCharCode(padLength, padLength, padLength, padLength, padLength, padLength, padLength,
|
||
padLength).substr(0, padLength);
|
||
} else if (!padding && (padLength < 8)) { //pad the message out with null bytes
|
||
message += "\0\0\0\0\0\0\0\0".substr(0, padLength);
|
||
}
|
||
return message;
|
||
}
|
||
|
||
function des_removePadding(message, padding) {
|
||
if (padding == 2) { // space padded
|
||
message = message.replace(/ *$/g, "");
|
||
} else if (padding == 1) { // PKCS7
|
||
var padCount = message.charCodeAt(message.length - 1);
|
||
message = message.substr(0, message.length - padCount);
|
||
} else if (!padding) { // null padding
|
||
message = message.replace(/\0*$/g, "");
|
||
}
|
||
return message;
|
||
}
|
||
|
||
|
||
var util = require('../../util');
|
||
|
||
// added by Recurity Labs
|
||
|
||
function Des(key) {
|
||
this.key = [];
|
||
|
||
for (var i = 0; i < 3; i++) {
|
||
this.key.push(key.substr(i * 8, 8));
|
||
}
|
||
|
||
this.encrypt = function(block) {
|
||
return util.str2bin(des(des_createKeys(this.key[2]),
|
||
des(des_createKeys(this.key[1]),
|
||
des(des_createKeys(this.key[0]),
|
||
util.bin2str(block), true, 0, null, null),
|
||
false, 0, null, null), true, 0, null, null));
|
||
}
|
||
}
|
||
|
||
Des.keySize = Des.prototype.keySize = 24;
|
||
Des.blockSize = Des.prototype.blockSize = 8;
|
||
|
||
// This is "original" DES - Des is actually Triple DES.
|
||
// This is only exported so we can unit test.
|
||
|
||
function OriginalDes(key) {
|
||
this.key = key;
|
||
|
||
this.encrypt = function(block, padding) {
|
||
var keys = des_createKeys(this.key);
|
||
return util.str2bin(des(keys, util.bin2str(block), true, 0, null, padding));
|
||
}
|
||
|
||
this.decrypt = function(block, padding) {
|
||
var keys = des_createKeys(this.key);
|
||
return util.str2bin(des(keys, util.bin2str(block), false, 0, null, padding));
|
||
}
|
||
}
|
||
|
||
module.exports = {
|
||
des: Des,
|
||
originalDes: OriginalDes
|
||
}
|
||
|
||
},{"../../util":56}],9:[function(require,module,exports){
|
||
var desModule = require('./des.js');
|
||
|
||
module.exports = {
|
||
des: desModule['des'],
|
||
originalDes: desModule['originalDes'],
|
||
cast5: require('./cast5.js'),
|
||
twofish: require('./twofish.js'),
|
||
blowfish: require('./blowfish.js')
|
||
}
|
||
|
||
var aes = require('./aes.js');
|
||
|
||
for (var i in aes) {
|
||
module.exports['aes' + i] = aes[i];
|
||
}
|
||
|
||
},{"./aes.js":5,"./blowfish.js":6,"./cast5.js":7,"./des.js":8,"./twofish.js":10}],10:[function(require,module,exports){
|
||
/* Modified by Recurity Labs GmbH
|
||
*
|
||
* Cipher.js
|
||
* A block-cipher algorithm implementation on JavaScript
|
||
* See Cipher.readme.txt for further information.
|
||
*
|
||
* Copyright(c) 2009 Atsushi Oka [ http://oka.nu/ ]
|
||
* This script file is distributed under the LGPL
|
||
*
|
||
* ACKNOWLEDGMENT
|
||
*
|
||
* The main subroutines are written by Michiel van Everdingen.
|
||
*
|
||
* Michiel van Everdingen
|
||
* http://home.versatel.nl/MAvanEverdingen/index.html
|
||
*
|
||
* All rights for these routines are reserved to Michiel van Everdingen.
|
||
*
|
||
*/
|
||
|
||
|
||
|
||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
//Math
|
||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
var MAXINT = 0xFFFFFFFF;
|
||
|
||
function rotb(b, n) {
|
||
return (b << n | b >>> (8 - n)) & 0xFF;
|
||
}
|
||
|
||
function rotw(w, n) {
|
||
return (w << n | w >>> (32 - n)) & MAXINT;
|
||
}
|
||
|
||
function getW(a, i) {
|
||
return a[i] | a[i + 1] << 8 | a[i + 2] << 16 | a[i + 3] << 24;
|
||
}
|
||
|
||
function setW(a, i, w) {
|
||
a.splice(i, 4, w & 0xFF, (w >>> 8) & 0xFF, (w >>> 16) & 0xFF, (w >>> 24) & 0xFF);
|
||
}
|
||
|
||
function setWInv(a, i, w) {
|
||
a.splice(i, 4, (w >>> 24) & 0xFF, (w >>> 16) & 0xFF, (w >>> 8) & 0xFF, w & 0xFF);
|
||
}
|
||
|
||
function getB(x, n) {
|
||
return (x >>> (n * 8)) & 0xFF;
|
||
}
|
||
|
||
function getNrBits(i) {
|
||
var n = 0;
|
||
while (i > 0) {
|
||
n++;
|
||
i >>>= 1;
|
||
}
|
||
return n;
|
||
}
|
||
|
||
function getMask(n) {
|
||
return (1 << n) - 1;
|
||
}
|
||
|
||
//added 2008/11/13 XXX MUST USE ONE-WAY HASH FUNCTION FOR SECURITY REASON
|
||
|
||
function randByte() {
|
||
return Math.floor(Math.random() * 256);
|
||
}
|
||
// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
// Twofish
|
||
// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
function createTwofish() {
|
||
//
|
||
var keyBytes = null;
|
||
var dataBytes = null;
|
||
var dataOffset = -1;
|
||
// var dataLength = -1;
|
||
var algorithmName = null;
|
||
// var idx2 = -1;
|
||
//
|
||
|
||
algorithmName = "twofish";
|
||
|
||
var tfsKey = [];
|
||
var tfsM = [
|
||
[],
|
||
[],
|
||
[],
|
||
[]
|
||
];
|
||
|
||
function tfsInit(key) {
|
||
keyBytes = key;
|
||
var i, a, b, c, d, meKey = [],
|
||
moKey = [],
|
||
inKey = [];
|
||
var kLen;
|
||
var sKey = [];
|
||
var f01, f5b, fef;
|
||
|
||
var q0 = [
|
||
[8, 1, 7, 13, 6, 15, 3, 2, 0, 11, 5, 9, 14, 12, 10, 4],
|
||
[2, 8, 11, 13, 15, 7, 6, 14, 3, 1, 9, 4, 0, 10, 12, 5]
|
||
];
|
||
var q1 = [
|
||
[14, 12, 11, 8, 1, 2, 3, 5, 15, 4, 10, 6, 7, 0, 9, 13],
|
||
[1, 14, 2, 11, 4, 12, 3, 7, 6, 13, 10, 5, 15, 9, 0, 8]
|
||
];
|
||
var q2 = [
|
||
[11, 10, 5, 14, 6, 13, 9, 0, 12, 8, 15, 3, 2, 4, 7, 1],
|
||
[4, 12, 7, 5, 1, 6, 9, 10, 0, 14, 13, 8, 2, 11, 3, 15]
|
||
];
|
||
var q3 = [
|
||
[13, 7, 15, 4, 1, 2, 6, 14, 9, 11, 3, 0, 8, 5, 12, 10],
|
||
[11, 9, 5, 1, 12, 3, 13, 14, 6, 4, 7, 15, 2, 0, 8, 10]
|
||
];
|
||
var ror4 = [0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15];
|
||
var ashx = [0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, 5, 14, 7];
|
||
var q = [
|
||
[],
|
||
[]
|
||
];
|
||
var m = [
|
||
[],
|
||
[],
|
||
[],
|
||
[]
|
||
];
|
||
|
||
function ffm5b(x) {
|
||
return x ^ (x >> 2) ^ [0, 90, 180, 238][x & 3];
|
||
}
|
||
|
||
function ffmEf(x) {
|
||
return x ^ (x >> 1) ^ (x >> 2) ^ [0, 238, 180, 90][x & 3];
|
||
}
|
||
|
||
function mdsRem(p, q) {
|
||
var i, t, u;
|
||
for (i = 0; i < 8; i++) {
|
||
t = q >>> 24;
|
||
q = ((q << 8) & MAXINT) | p >>> 24;
|
||
p = (p << 8) & MAXINT;
|
||
u = t << 1;
|
||
if (t & 128) {
|
||
u ^= 333;
|
||
}
|
||
q ^= t ^ (u << 16);
|
||
u ^= t >>> 1;
|
||
if (t & 1) {
|
||
u ^= 166;
|
||
}
|
||
q ^= u << 24 | u << 8;
|
||
}
|
||
return q;
|
||
}
|
||
|
||
function qp(n, x) {
|
||
var a, b, c, d;
|
||
a = x >> 4;
|
||
b = x & 15;
|
||
c = q0[n][a ^ b];
|
||
d = q1[n][ror4[b] ^ ashx[a]];
|
||
return q3[n][ror4[d] ^ ashx[c]] << 4 | q2[n][c ^ d];
|
||
}
|
||
|
||
function hFun(x, key) {
|
||
var a = getB(x, 0),
|
||
b = getB(x, 1),
|
||
c = getB(x, 2),
|
||
d = getB(x, 3);
|
||
switch (kLen) {
|
||
case 4:
|
||
a = q[1][a] ^ getB(key[3], 0);
|
||
b = q[0][b] ^ getB(key[3], 1);
|
||
c = q[0][c] ^ getB(key[3], 2);
|
||
d = q[1][d] ^ getB(key[3], 3);
|
||
case 3:
|
||
a = q[1][a] ^ getB(key[2], 0);
|
||
b = q[1][b] ^ getB(key[2], 1);
|
||
c = q[0][c] ^ getB(key[2], 2);
|
||
d = q[0][d] ^ getB(key[2], 3);
|
||
case 2:
|
||
a = q[0][q[0][a] ^ getB(key[1], 0)] ^ getB(key[0], 0);
|
||
b = q[0][q[1][b] ^ getB(key[1], 1)] ^ getB(key[0], 1);
|
||
c = q[1][q[0][c] ^ getB(key[1], 2)] ^ getB(key[0], 2);
|
||
d = q[1][q[1][d] ^ getB(key[1], 3)] ^ getB(key[0], 3);
|
||
}
|
||
return m[0][a] ^ m[1][b] ^ m[2][c] ^ m[3][d];
|
||
}
|
||
|
||
keyBytes = keyBytes.slice(0, 32);
|
||
i = keyBytes.length;
|
||
while (i != 16 && i != 24 && i != 32)
|
||
keyBytes[i++] = 0;
|
||
|
||
for (i = 0; i < keyBytes.length; i += 4) {
|
||
inKey[i >> 2] = getW(keyBytes, i);
|
||
}
|
||
for (i = 0; i < 256; i++) {
|
||
q[0][i] = qp(0, i);
|
||
q[1][i] = qp(1, i);
|
||
}
|
||
for (i = 0; i < 256; i++) {
|
||
f01 = q[1][i];
|
||
f5b = ffm5b(f01);
|
||
fef = ffmEf(f01);
|
||
m[0][i] = f01 + (f5b << 8) + (fef << 16) + (fef << 24);
|
||
m[2][i] = f5b + (fef << 8) + (f01 << 16) + (fef << 24);
|
||
f01 = q[0][i];
|
||
f5b = ffm5b(f01);
|
||
fef = ffmEf(f01);
|
||
m[1][i] = fef + (fef << 8) + (f5b << 16) + (f01 << 24);
|
||
m[3][i] = f5b + (f01 << 8) + (fef << 16) + (f5b << 24);
|
||
}
|
||
|
||
kLen = inKey.length / 2;
|
||
for (i = 0; i < kLen; i++) {
|
||
a = inKey[i + i];
|
||
meKey[i] = a;
|
||
b = inKey[i + i + 1];
|
||
moKey[i] = b;
|
||
sKey[kLen - i - 1] = mdsRem(a, b);
|
||
}
|
||
for (i = 0; i < 40; i += 2) {
|
||
a = 0x1010101 * i;
|
||
b = a + 0x1010101;
|
||
a = hFun(a, meKey);
|
||
b = rotw(hFun(b, moKey), 8);
|
||
tfsKey[i] = (a + b) & MAXINT;
|
||
tfsKey[i + 1] = rotw(a + 2 * b, 9);
|
||
}
|
||
for (i = 0; i < 256; i++) {
|
||
a = b = c = d = i;
|
||
switch (kLen) {
|
||
case 4:
|
||
a = q[1][a] ^ getB(sKey[3], 0);
|
||
b = q[0][b] ^ getB(sKey[3], 1);
|
||
c = q[0][c] ^ getB(sKey[3], 2);
|
||
d = q[1][d] ^ getB(sKey[3], 3);
|
||
case 3:
|
||
a = q[1][a] ^ getB(sKey[2], 0);
|
||
b = q[1][b] ^ getB(sKey[2], 1);
|
||
c = q[0][c] ^ getB(sKey[2], 2);
|
||
d = q[0][d] ^ getB(sKey[2], 3);
|
||
case 2:
|
||
tfsM[0][i] = m[0][q[0][q[0][a] ^ getB(sKey[1], 0)] ^ getB(sKey[0], 0)];
|
||
tfsM[1][i] = m[1][q[0][q[1][b] ^ getB(sKey[1], 1)] ^ getB(sKey[0], 1)];
|
||
tfsM[2][i] = m[2][q[1][q[0][c] ^ getB(sKey[1], 2)] ^ getB(sKey[0], 2)];
|
||
tfsM[3][i] = m[3][q[1][q[1][d] ^ getB(sKey[1], 3)] ^ getB(sKey[0], 3)];
|
||
}
|
||
}
|
||
}
|
||
|
||
function tfsG0(x) {
|
||
return tfsM[0][getB(x, 0)] ^ tfsM[1][getB(x, 1)] ^ tfsM[2][getB(x, 2)] ^ tfsM[3][getB(x, 3)];
|
||
}
|
||
|
||
function tfsG1(x) {
|
||
return tfsM[0][getB(x, 3)] ^ tfsM[1][getB(x, 0)] ^ tfsM[2][getB(x, 1)] ^ tfsM[3][getB(x, 2)];
|
||
}
|
||
|
||
function tfsFrnd(r, blk) {
|
||
var a = tfsG0(blk[0]);
|
||
var b = tfsG1(blk[1]);
|
||
blk[2] = rotw(blk[2] ^ (a + b + tfsKey[4 * r + 8]) & MAXINT, 31);
|
||
blk[3] = rotw(blk[3], 1) ^ (a + 2 * b + tfsKey[4 * r + 9]) & MAXINT;
|
||
a = tfsG0(blk[2]);
|
||
b = tfsG1(blk[3]);
|
||
blk[0] = rotw(blk[0] ^ (a + b + tfsKey[4 * r + 10]) & MAXINT, 31);
|
||
blk[1] = rotw(blk[1], 1) ^ (a + 2 * b + tfsKey[4 * r + 11]) & MAXINT;
|
||
}
|
||
|
||
function tfsIrnd(i, blk) {
|
||
var a = tfsG0(blk[0]);
|
||
var b = tfsG1(blk[1]);
|
||
blk[2] = rotw(blk[2], 1) ^ (a + b + tfsKey[4 * i + 10]) & MAXINT;
|
||
blk[3] = rotw(blk[3] ^ (a + 2 * b + tfsKey[4 * i + 11]) & MAXINT, 31);
|
||
a = tfsG0(blk[2]);
|
||
b = tfsG1(blk[3]);
|
||
blk[0] = rotw(blk[0], 1) ^ (a + b + tfsKey[4 * i + 8]) & MAXINT;
|
||
blk[1] = rotw(blk[1] ^ (a + 2 * b + tfsKey[4 * i + 9]) & MAXINT, 31);
|
||
}
|
||
|
||
function tfsClose() {
|
||
tfsKey = [];
|
||
tfsM = [
|
||
[],
|
||
[],
|
||
[],
|
||
[]
|
||
];
|
||
}
|
||
|
||
function tfsEncrypt(data, offset) {
|
||
dataBytes = data;
|
||
dataOffset = offset;
|
||
var blk = [getW(dataBytes, dataOffset) ^ tfsKey[0],
|
||
getW(dataBytes, dataOffset + 4) ^ tfsKey[1],
|
||
getW(dataBytes, dataOffset + 8) ^ tfsKey[2],
|
||
getW(dataBytes, dataOffset + 12) ^ tfsKey[3]
|
||
];
|
||
for (var j = 0; j < 8; j++) {
|
||
tfsFrnd(j, blk);
|
||
}
|
||
setW(dataBytes, dataOffset, blk[2] ^ tfsKey[4]);
|
||
setW(dataBytes, dataOffset + 4, blk[3] ^ tfsKey[5]);
|
||
setW(dataBytes, dataOffset + 8, blk[0] ^ tfsKey[6]);
|
||
setW(dataBytes, dataOffset + 12, blk[1] ^ tfsKey[7]);
|
||
dataOffset += 16;
|
||
return dataBytes;
|
||
}
|
||
|
||
function tfsDecrypt(data, offset) {
|
||
dataBytes = data;
|
||
dataOffset = offset;
|
||
var blk = [getW(dataBytes, dataOffset) ^ tfsKey[4],
|
||
getW(dataBytes, dataOffset + 4) ^ tfsKey[5],
|
||
getW(dataBytes, dataOffset + 8) ^ tfsKey[6],
|
||
getW(dataBytes, dataOffset + 12) ^ tfsKey[7]
|
||
];
|
||
for (var j = 7; j >= 0; j--) {
|
||
tfsIrnd(j, blk);
|
||
}
|
||
setW(dataBytes, dataOffset, blk[2] ^ tfsKey[0]);
|
||
setW(dataBytes, dataOffset + 4, blk[3] ^ tfsKey[1]);
|
||
setW(dataBytes, dataOffset + 8, blk[0] ^ tfsKey[2]);
|
||
setW(dataBytes, dataOffset + 12, blk[1] ^ tfsKey[3]);
|
||
dataOffset += 16;
|
||
}
|
||
|
||
// added by Recurity Labs
|
||
|
||
function tfsFinal() {
|
||
return dataBytes;
|
||
}
|
||
|
||
return {
|
||
name: "twofish",
|
||
blocksize: 128 / 8,
|
||
open: tfsInit,
|
||
close: tfsClose,
|
||
encrypt: tfsEncrypt,
|
||
decrypt: tfsDecrypt,
|
||
// added by Recurity Labs
|
||
finalize: tfsFinal
|
||
};
|
||
}
|
||
|
||
var util = require('../../util');
|
||
|
||
// added by Recurity Labs
|
||
|
||
function TFencrypt(block, key) {
|
||
var block_copy = [].concat(block);
|
||
var tf = createTwofish();
|
||
tf.open(util.str2bin(key), 0);
|
||
var result = tf.encrypt(block_copy, 0);
|
||
tf.close();
|
||
return result;
|
||
}
|
||
|
||
function TF(key) {
|
||
this.tf = createTwofish();
|
||
this.tf.open(util.str2bin(key), 0);
|
||
|
||
this.encrypt = function(block) {
|
||
return this.tf.encrypt([].concat(block), 0);
|
||
}
|
||
}
|
||
|
||
|
||
module.exports = TF;
|
||
module.exports.keySize = TF.prototype.keySize = 32;
|
||
module.exports.blockSize = TF.prototype.blockSize = 16;
|
||
|
||
},{"../../util":56}],11:[function(require,module,exports){
|
||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||
// Copyright (C) 2011 Recurity Labs GmbH
|
||
//
|
||
// This library is free software; you can redistribute it and/or
|
||
// modify it under the terms of the GNU Lesser General Public
|
||
// License as published by the Free Software Foundation; either
|
||
// version 2.1 of the License, or (at your option) any later version.
|
||
//
|
||
// This library is distributed in the hope that it will be useful,
|
||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
// Lesser General Public License for more details.
|
||
//
|
||
// You should have received a copy of the GNU Lesser General Public
|
||
// License along with this library; if not, write to the Free Software
|
||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||
|
||
// The GPG4Browsers crypto interface
|
||
|
||
var random = require('./random.js'),
|
||
cipher = require('./cipher'),
|
||
publicKey = require('./public_key'),
|
||
type_mpi = require('../type/mpi.js');
|
||
|
||
module.exports = {
|
||
/**
|
||
* Encrypts data using the specified public key multiprecision integers
|
||
* and the specified algorithm.
|
||
* @param {Integer} algo Algorithm to be used (See RFC4880 9.1)
|
||
* @param {openpgp_type_mpi[]} publicMPIs Algorithm dependent multiprecision integers
|
||
* @param {openpgp_type_mpi} data Data to be encrypted as MPI
|
||
* @return {openpgp_type_mpi[]} if RSA an openpgp_type_mpi;
|
||
* if elgamal encryption an array of two openpgp_type_mpi is returned; otherwise null
|
||
*/
|
||
publicKeyEncrypt: function(algo, publicMPIs, data) {
|
||
var result = (function() {
|
||
switch (algo) {
|
||
case 'rsa_encrypt':
|
||
case 'rsa_encrypt_sign':
|
||
var rsa = new publicKey.rsa();
|
||
var n = publicMPIs[0].toBigInteger();
|
||
var e = publicMPIs[1].toBigInteger();
|
||
var m = data.toBigInteger();
|
||
return [rsa.encrypt(m, e, n)];
|
||
|
||
case 'elgamal':
|
||
var elgamal = new publicKey.elgamal();
|
||
var p = publicMPIs[0].toBigInteger();
|
||
var g = publicMPIs[1].toBigInteger();
|
||
var y = publicMPIs[2].toBigInteger();
|
||
var m = data.toBigInteger();
|
||
return elgamal.encrypt(m, g, p, y);
|
||
|
||
default:
|
||
return [];
|
||
}
|
||
})();
|
||
|
||
return result.map(function(bn) {
|
||
var mpi = new type_mpi();
|
||
mpi.fromBigInteger(bn);
|
||
return mpi;
|
||
});
|
||
},
|
||
|
||
/**
|
||
* Decrypts data using the specified public key multiprecision integers of the private key,
|
||
* the specified secretMPIs of the private key and the specified algorithm.
|
||
* @param {Integer} algo Algorithm to be used (See RFC4880 9.1)
|
||
* @param {openpgp_type_mpi[]} publicMPIs Algorithm dependent multiprecision integers
|
||
* of the public key part of the private key
|
||
* @param {openpgp_type_mpi[]} secretMPIs Algorithm dependent multiprecision integers
|
||
* of the private key used
|
||
* @param {openpgp_type_mpi} data Data to be encrypted as MPI
|
||
* @return {openpgp_type_mpi} returns a big integer containing the decrypted data; otherwise null
|
||
*/
|
||
|
||
publicKeyDecrypt: function(algo, keyIntegers, dataIntegers) {
|
||
var bn = (function() {
|
||
switch (algo) {
|
||
case 'rsa_encrypt_sign':
|
||
case 'rsa_encrypt':
|
||
var rsa = new publicKey.rsa();
|
||
// 0 and 1 are the public key.
|
||
var d = keyIntegers[2].toBigInteger();
|
||
var p = keyIntegers[3].toBigInteger();
|
||
var q = keyIntegers[4].toBigInteger();
|
||
var u = keyIntegers[5].toBigInteger();
|
||
var m = dataIntegers[0].toBigInteger();
|
||
return rsa.decrypt(m, d, p, q, u);
|
||
case 'elgamal':
|
||
var elgamal = new publicKey.elgamal();
|
||
var x = keyIntegers[3].toBigInteger();
|
||
var c1 = dataIntegers[0].toBigInteger();
|
||
var c2 = dataIntegers[1].toBigInteger();
|
||
var p = keyIntegers[0].toBigInteger();
|
||
return elgamal.decrypt(c1, c2, p, x);
|
||
default:
|
||
return null;
|
||
}
|
||
})();
|
||
|
||
var result = new type_mpi();
|
||
result.fromBigInteger(bn);
|
||
return result;
|
||
},
|
||
|
||
/** Returns the number of integers comprising the private key of an algorithm
|
||
* @param {openpgp.publickey} algo The public key algorithm
|
||
* @return {Integer} The number of integers.
|
||
*/
|
||
getPrivateMpiCount: function(algo) {
|
||
switch (algo) {
|
||
case 'rsa_encrypt':
|
||
case 'rsa_encrypt_sign':
|
||
case 'rsa_sign':
|
||
// Algorithm-Specific Fields for RSA secret keys:
|
||
// - multiprecision integer (MPI) of RSA secret exponent d.
|
||
// - MPI of RSA secret prime value p.
|
||
// - MPI of RSA secret prime value q (p < q).
|
||
// - MPI of u, the multiplicative inverse of p, mod q.
|
||
return 4;
|
||
case 'elgamal':
|
||
// Algorithm-Specific Fields for Elgamal secret keys:
|
||
// - MPI of Elgamal secret exponent x.
|
||
return 1;
|
||
case 'dsa':
|
||
// Algorithm-Specific Fields for DSA secret keys:
|
||
// - MPI of DSA secret exponent x.
|
||
return 1;
|
||
default:
|
||
throw new Error('Unknown algorithm');
|
||
}
|
||
},
|
||
|
||
getPublicMpiCount: function(algo) {
|
||
// - A series of multiprecision integers comprising the key material:
|
||
// Algorithm-Specific Fields for RSA public keys:
|
||
// - a multiprecision integer (MPI) of RSA public modulus n;
|
||
// - an MPI of RSA public encryption exponent e.
|
||
switch (algo) {
|
||
case 'rsa_encrypt':
|
||
case 'rsa_encrypt_sign':
|
||
case 'rsa_sign':
|
||
return 2;
|
||
|
||
// Algorithm-Specific Fields for Elgamal public keys:
|
||
// - MPI of Elgamal prime p;
|
||
// - MPI of Elgamal group generator g;
|
||
// - MPI of Elgamal public key value y (= g**x mod p where x is secret).
|
||
case 'elgamal':
|
||
return 3;
|
||
|
||
// Algorithm-Specific Fields for DSA public keys:
|
||
// - MPI of DSA prime p;
|
||
// - MPI of DSA group order q (q is a prime divisor of p-1);
|
||
// - MPI of DSA group generator g;
|
||
// - MPI of DSA public-key value y (= g**x mod p where x is secret).
|
||
case 'dsa':
|
||
return 4;
|
||
|
||
default:
|
||
throw new Error('Unknown algorithm.');
|
||
}
|
||
},
|
||
|
||
generateMpi: function(algo, bits) {
|
||
var result = (function() {
|
||
switch (algo) {
|
||
case 'rsa_encrypt':
|
||
case 'rsa_encrypt_sign':
|
||
case 'rsa_sign':
|
||
//remember "publicKey" refers to the crypto/public_key dir
|
||
var rsa = new publicKey.rsa();
|
||
var keyObject = rsa.generate(bits, "10001");
|
||
var output = [];
|
||
output.push(keyObject.n);
|
||
output.push(keyObject.ee);
|
||
output.push(keyObject.d);
|
||
output.push(keyObject.p);
|
||
output.push(keyObject.q);
|
||
output.push(keyObject.u);
|
||
return output;
|
||
default:
|
||
throw new Error('Unsupported algorithm for key generation.');
|
||
}
|
||
})();
|
||
|
||
return result.map(function(bn) {
|
||
var mpi = new type_mpi();
|
||
mpi.fromBigInteger(bn);
|
||
return mpi;
|
||
});
|
||
},
|
||
|
||
|
||
/**
|
||
* generate random byte prefix as string for the specified algorithm
|
||
* @param {Integer} algo Algorithm to use (see RFC4880 9.2)
|
||
* @return {String} Random bytes with length equal to the block
|
||
* size of the cipher
|
||
*/
|
||
getPrefixRandom: function(algo) {
|
||
return random.getRandomBytes(cipher[algo].blockSize);
|
||
},
|
||
|
||
/**
|
||
* Generating a session key for the specified symmetric algorithm
|
||
* @param {Integer} algo Algorithm to use (see RFC4880 9.2)
|
||
* @return {String} Random bytes as a string to be used as a key
|
||
*/
|
||
generateSessionKey: function(algo) {
|
||
return random.getRandomBytes(cipher[algo].keySize);
|
||
},
|
||
|
||
};
|
||
|
||
},{"../type/mpi.js":54,"./cipher":9,"./public_key":20,"./random.js":23}],12:[function(require,module,exports){
|
||
var sha = require('./sha.js');
|
||
|
||
module.exports = {
|
||
md5: require('./md5.js'),
|
||
sha1: sha.sha1,
|
||
sha256: sha.sha256,
|
||
sha224: sha.sha224,
|
||
sha384: sha.sha384,
|
||
sha512: sha.sha512,
|
||
ripemd: require('./ripe-md.js'),
|
||
|
||
/**
|
||
* Create a hash on the specified data using the specified algorithm
|
||
* @param {Integer} algo Hash algorithm type (see RFC4880 9.4)
|
||
* @param {String} data Data to be hashed
|
||
* @return {String} hash value
|
||
*/
|
||
digest: function(algo, data) {
|
||
switch (algo) {
|
||
case 1:
|
||
// - MD5 [HAC]
|
||
return this.md5(data);
|
||
case 2:
|
||
// - SHA-1 [FIPS180]
|
||
return this.sha1(data);
|
||
case 3:
|
||
// - RIPE-MD/160 [HAC]
|
||
return this.ripemd(data);
|
||
case 8:
|
||
// - SHA256 [FIPS180]
|
||
return this.sha256(data);
|
||
case 9:
|
||
// - SHA384 [FIPS180]
|
||
return this.sha384(data);
|
||
case 10:
|
||
// - SHA512 [FIPS180]
|
||
return this.sha512(data);
|
||
case 11:
|
||
// - SHA224 [FIPS180]
|
||
return this.sha224(data);
|
||
default:
|
||
throw new Error('Invalid hash function.');
|
||
}
|
||
},
|
||
|
||
/**
|
||
* Returns the hash size in bytes of the specified hash algorithm type
|
||
* @param {Integer} algo Hash algorithm type (See RFC4880 9.4)
|
||
* @return {Integer} Size in bytes of the resulting hash
|
||
*/
|
||
getHashByteLength: function(algo) {
|
||
switch (algo) {
|
||
case 1:
|
||
// - MD5 [HAC]
|
||
return 16;
|
||
case 2:
|
||
// - SHA-1 [FIPS180]
|
||
case 3:
|
||
// - RIPE-MD/160 [HAC]
|
||
return 20;
|
||
case 8:
|
||
// - SHA256 [FIPS180]
|
||
return 32;
|
||
case 9:
|
||
// - SHA384 [FIPS180]
|
||
return 48
|
||
case 10:
|
||
// - SHA512 [FIPS180]
|
||
return 64;
|
||
case 11:
|
||
// - SHA224 [FIPS180]
|
||
return 28;
|
||
default:
|
||
throw new Error('Invalid hash algorithm.');
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
},{"./md5.js":13,"./ripe-md.js":14,"./sha.js":15}],13:[function(require,module,exports){
|
||
/**
|
||
* A fast MD5 JavaScript implementation
|
||
* Copyright (c) 2012 Joseph Myers
|
||
* http://www.myersdaily.org/joseph/javascript/md5-text.html
|
||
*
|
||
* Permission to use, copy, modify, and distribute this software
|
||
* and its documentation for any purposes and without
|
||
* fee is hereby granted provided that this copyright notice
|
||
* appears in all copies.
|
||
*
|
||
* Of course, this soft is provided "as is" without express or implied
|
||
* warranty of any kind.
|
||
*/
|
||
|
||
var util = require('../../util/util.js');
|
||
|
||
function MD5(entree) {
|
||
var hex = md5(entree);
|
||
var bin = util.hex2bin(hex);
|
||
return bin;
|
||
}
|
||
|
||
function md5cycle(x, k) {
|
||
var a = x[0],
|
||
b = x[1],
|
||
c = x[2],
|
||
d = x[3];
|
||
|
||
a = ff(a, b, c, d, k[0], 7, -680876936);
|
||
d = ff(d, a, b, c, k[1], 12, -389564586);
|
||
c = ff(c, d, a, b, k[2], 17, 606105819);
|
||
b = ff(b, c, d, a, k[3], 22, -1044525330);
|
||
a = ff(a, b, c, d, k[4], 7, -176418897);
|
||
d = ff(d, a, b, c, k[5], 12, 1200080426);
|
||
c = ff(c, d, a, b, k[6], 17, -1473231341);
|
||
b = ff(b, c, d, a, k[7], 22, -45705983);
|
||
a = ff(a, b, c, d, k[8], 7, 1770035416);
|
||
d = ff(d, a, b, c, k[9], 12, -1958414417);
|
||
c = ff(c, d, a, b, k[10], 17, -42063);
|
||
b = ff(b, c, d, a, k[11], 22, -1990404162);
|
||
a = ff(a, b, c, d, k[12], 7, 1804603682);
|
||
d = ff(d, a, b, c, k[13], 12, -40341101);
|
||
c = ff(c, d, a, b, k[14], 17, -1502002290);
|
||
b = ff(b, c, d, a, k[15], 22, 1236535329);
|
||
|
||
a = gg(a, b, c, d, k[1], 5, -165796510);
|
||
d = gg(d, a, b, c, k[6], 9, -1069501632);
|
||
c = gg(c, d, a, b, k[11], 14, 643717713);
|
||
b = gg(b, c, d, a, k[0], 20, -373897302);
|
||
a = gg(a, b, c, d, k[5], 5, -701558691);
|
||
d = gg(d, a, b, c, k[10], 9, 38016083);
|
||
c = gg(c, d, a, b, k[15], 14, -660478335);
|
||
b = gg(b, c, d, a, k[4], 20, -405537848);
|
||
a = gg(a, b, c, d, k[9], 5, 568446438);
|
||
d = gg(d, a, b, c, k[14], 9, -1019803690);
|
||
c = gg(c, d, a, b, k[3], 14, -187363961);
|
||
b = gg(b, c, d, a, k[8], 20, 1163531501);
|
||
a = gg(a, b, c, d, k[13], 5, -1444681467);
|
||
d = gg(d, a, b, c, k[2], 9, -51403784);
|
||
c = gg(c, d, a, b, k[7], 14, 1735328473);
|
||
b = gg(b, c, d, a, k[12], 20, -1926607734);
|
||
|
||
a = hh(a, b, c, d, k[5], 4, -378558);
|
||
d = hh(d, a, b, c, k[8], 11, -2022574463);
|
||
c = hh(c, d, a, b, k[11], 16, 1839030562);
|
||
b = hh(b, c, d, a, k[14], 23, -35309556);
|
||
a = hh(a, b, c, d, k[1], 4, -1530992060);
|
||
d = hh(d, a, b, c, k[4], 11, 1272893353);
|
||
c = hh(c, d, a, b, k[7], 16, -155497632);
|
||
b = hh(b, c, d, a, k[10], 23, -1094730640);
|
||
a = hh(a, b, c, d, k[13], 4, 681279174);
|
||
d = hh(d, a, b, c, k[0], 11, -358537222);
|
||
c = hh(c, d, a, b, k[3], 16, -722521979);
|
||
b = hh(b, c, d, a, k[6], 23, 76029189);
|
||
a = hh(a, b, c, d, k[9], 4, -640364487);
|
||
d = hh(d, a, b, c, k[12], 11, -421815835);
|
||
c = hh(c, d, a, b, k[15], 16, 530742520);
|
||
b = hh(b, c, d, a, k[2], 23, -995338651);
|
||
|
||
a = ii(a, b, c, d, k[0], 6, -198630844);
|
||
d = ii(d, a, b, c, k[7], 10, 1126891415);
|
||
c = ii(c, d, a, b, k[14], 15, -1416354905);
|
||
b = ii(b, c, d, a, k[5], 21, -57434055);
|
||
a = ii(a, b, c, d, k[12], 6, 1700485571);
|
||
d = ii(d, a, b, c, k[3], 10, -1894986606);
|
||
c = ii(c, d, a, b, k[10], 15, -1051523);
|
||
b = ii(b, c, d, a, k[1], 21, -2054922799);
|
||
a = ii(a, b, c, d, k[8], 6, 1873313359);
|
||
d = ii(d, a, b, c, k[15], 10, -30611744);
|
||
c = ii(c, d, a, b, k[6], 15, -1560198380);
|
||
b = ii(b, c, d, a, k[13], 21, 1309151649);
|
||
a = ii(a, b, c, d, k[4], 6, -145523070);
|
||
d = ii(d, a, b, c, k[11], 10, -1120210379);
|
||
c = ii(c, d, a, b, k[2], 15, 718787259);
|
||
b = ii(b, c, d, a, k[9], 21, -343485551);
|
||
|
||
x[0] = add32(a, x[0]);
|
||
x[1] = add32(b, x[1]);
|
||
x[2] = add32(c, x[2]);
|
||
x[3] = add32(d, x[3]);
|
||
|
||
}
|
||
|
||
function cmn(q, a, b, x, s, t) {
|
||
a = add32(add32(a, q), add32(x, t));
|
||
return add32((a << s) | (a >>> (32 - s)), b);
|
||
}
|
||
|
||
function ff(a, b, c, d, x, s, t) {
|
||
return cmn((b & c) | ((~b) & d), a, b, x, s, t);
|
||
}
|
||
|
||
function gg(a, b, c, d, x, s, t) {
|
||
return cmn((b & d) | (c & (~d)), a, b, x, s, t);
|
||
}
|
||
|
||
function hh(a, b, c, d, x, s, t) {
|
||
return cmn(b ^ c ^ d, a, b, x, s, t);
|
||
}
|
||
|
||
function ii(a, b, c, d, x, s, t) {
|
||
return cmn(c ^ (b | (~d)), a, b, x, s, t);
|
||
}
|
||
|
||
function md51(s) {
|
||
txt = '';
|
||
var n = s.length,
|
||
state = [1732584193, -271733879, -1732584194, 271733878],
|
||
i;
|
||
for (i = 64; i <= s.length; i += 64) {
|
||
md5cycle(state, md5blk(s.substring(i - 64, i)));
|
||
}
|
||
s = s.substring(i - 64);
|
||
var tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
||
for (i = 0; i < s.length; i++)
|
||
tail[i >> 2] |= s.charCodeAt(i) << ((i % 4) << 3);
|
||
tail[i >> 2] |= 0x80 << ((i % 4) << 3);
|
||
if (i > 55) {
|
||
md5cycle(state, tail);
|
||
for (i = 0; i < 16; i++) tail[i] = 0;
|
||
}
|
||
tail[14] = n * 8;
|
||
md5cycle(state, tail);
|
||
return state;
|
||
}
|
||
|
||
/* there needs to be support for Unicode here,
|
||
* unless we pretend that we can redefine the MD-5
|
||
* algorithm for multi-byte characters (perhaps
|
||
* by adding every four 16-bit characters and
|
||
* shortening the sum to 32 bits). Otherwise
|
||
* I suggest performing MD-5 as if every character
|
||
* was two bytes--e.g., 0040 0025 = @%--but then
|
||
* how will an ordinary MD-5 sum be matched?
|
||
* There is no way to standardize text to something
|
||
* like UTF-8 before transformation; speed cost is
|
||
* utterly prohibitive. The JavaScript standard
|
||
* itself needs to look at this: it should start
|
||
* providing access to strings as preformed UTF-8
|
||
* 8-bit unsigned value arrays.
|
||
*/
|
||
function md5blk(s) { /* I figured global was faster. */
|
||
var md5blks = [],
|
||
i; /* Andy King said do it this way. */
|
||
for (i = 0; i < 64; i += 4) {
|
||
md5blks[i >> 2] = s.charCodeAt(i) + (s.charCodeAt(i + 1) << 8) + (s.charCodeAt(i + 2) << 16) + (s.charCodeAt(i + 3) <<
|
||
24);
|
||
}
|
||
return md5blks;
|
||
}
|
||
|
||
var hex_chr = '0123456789abcdef'.split('');
|
||
|
||
function rhex(n) {
|
||
var s = '',
|
||
j = 0;
|
||
for (; j < 4; j++)
|
||
s += hex_chr[(n >> (j * 8 + 4)) & 0x0F] + hex_chr[(n >> (j * 8)) & 0x0F];
|
||
return s;
|
||
}
|
||
|
||
function hex(x) {
|
||
for (var i = 0; i < x.length; i++)
|
||
x[i] = rhex(x[i]);
|
||
return x.join('');
|
||
}
|
||
|
||
function md5(s) {
|
||
return hex(md51(s));
|
||
}
|
||
|
||
/* this function is much faster,
|
||
so if possible we use it. Some IEs
|
||
are the only ones I know of that
|
||
need the idiotic second function,
|
||
generated by an if clause. */
|
||
|
||
function add32(a, b) {
|
||
return (a + b) & 0xFFFFFFFF;
|
||
}
|
||
|
||
if (md5('hello') != '5d41402abc4b2a76b9719d911017c592') {
|
||
function add32(x, y) {
|
||
var lsw = (x & 0xFFFF) + (y & 0xFFFF),
|
||
msw = (x >> 16) + (y >> 16) + (lsw >> 16);
|
||
return (msw << 16) | (lsw & 0xFFFF);
|
||
}
|
||
}
|
||
|
||
module.exports = MD5
|
||
|
||
},{"../../util/util.js":56}],14:[function(require,module,exports){
|
||
/*
|
||
* CryptoMX Tools
|
||
* Copyright (C) 2004 - 2006 Derek Buitenhuis
|
||
*
|
||
* This program is free software; you can redistribute it and/or
|
||
* modify it under the terms of the GNU General Public License
|
||
* as published by the Free Software Foundation; either version 2
|
||
* of the License, or (at your option) any later version.
|
||
*
|
||
* This program is distributed in the hope that it will be useful,
|
||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
* GNU General Public License for more details.
|
||
*
|
||
* You should have received a copy of the GNU General Public License
|
||
* along with this program; if not, write to the Free Software
|
||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||
*/
|
||
|
||
/* Modified by Recurity Labs GmbH
|
||
*/
|
||
|
||
var RMDsize = 160;
|
||
var X = new Array();
|
||
|
||
function ROL(x, n) {
|
||
return new Number((x << n) | (x >>> (32 - n)));
|
||
}
|
||
|
||
function F(x, y, z) {
|
||
return new Number(x ^ y ^ z);
|
||
}
|
||
|
||
function G(x, y, z) {
|
||
return new Number((x & y) | (~x & z));
|
||
}
|
||
|
||
function H(x, y, z) {
|
||
return new Number((x | ~y) ^ z);
|
||
}
|
||
|
||
function I(x, y, z) {
|
||
return new Number((x & z) | (y & ~z));
|
||
}
|
||
|
||
function J(x, y, z) {
|
||
return new Number(x ^ (y | ~z));
|
||
}
|
||
|
||
function mixOneRound(a, b, c, d, e, x, s, roundNumber) {
|
||
switch (roundNumber) {
|
||
case 0:
|
||
a += F(b, c, d) + x + 0x00000000;
|
||
break;
|
||
case 1:
|
||
a += G(b, c, d) + x + 0x5a827999;
|
||
break;
|
||
case 2:
|
||
a += H(b, c, d) + x + 0x6ed9eba1;
|
||
break;
|
||
case 3:
|
||
a += I(b, c, d) + x + 0x8f1bbcdc;
|
||
break;
|
||
case 4:
|
||
a += J(b, c, d) + x + 0xa953fd4e;
|
||
break;
|
||
case 5:
|
||
a += J(b, c, d) + x + 0x50a28be6;
|
||
break;
|
||
case 6:
|
||
a += I(b, c, d) + x + 0x5c4dd124;
|
||
break;
|
||
case 7:
|
||
a += H(b, c, d) + x + 0x6d703ef3;
|
||
break;
|
||
case 8:
|
||
a += G(b, c, d) + x + 0x7a6d76e9;
|
||
break;
|
||
case 9:
|
||
a += F(b, c, d) + x + 0x00000000;
|
||
break;
|
||
|
||
default:
|
||
document.write("Bogus round number");
|
||
break;
|
||
}
|
||
|
||
a = ROL(a, s) + e;
|
||
c = ROL(c, 10);
|
||
|
||
a &= 0xffffffff;
|
||
b &= 0xffffffff;
|
||
c &= 0xffffffff;
|
||
d &= 0xffffffff;
|
||
e &= 0xffffffff;
|
||
|
||
var retBlock = new Array();
|
||
retBlock[0] = a;
|
||
retBlock[1] = b;
|
||
retBlock[2] = c;
|
||
retBlock[3] = d;
|
||
retBlock[4] = e;
|
||
retBlock[5] = x;
|
||
retBlock[6] = s;
|
||
|
||
return retBlock;
|
||
}
|
||
|
||
function MDinit(MDbuf) {
|
||
MDbuf[0] = 0x67452301;
|
||
MDbuf[1] = 0xefcdab89;
|
||
MDbuf[2] = 0x98badcfe;
|
||
MDbuf[3] = 0x10325476;
|
||
MDbuf[4] = 0xc3d2e1f0;
|
||
}
|
||
|
||
var ROLs = [
|
||
[11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8],
|
||
[7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12],
|
||
[11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5],
|
||
[11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12],
|
||
[9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6],
|
||
[8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6],
|
||
[9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11],
|
||
[9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5],
|
||
[15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8],
|
||
[8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11]
|
||
];
|
||
|
||
var indexes = [
|
||
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
|
||
[7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8],
|
||
[3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12],
|
||
[1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2],
|
||
[4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13],
|
||
[5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12],
|
||
[6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2],
|
||
[15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13],
|
||
[8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14],
|
||
[12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11]
|
||
];
|
||
|
||
function compress(MDbuf, X) {
|
||
blockA = new Array();
|
||
blockB = new Array();
|
||
|
||
var retBlock;
|
||
|
||
for (var i = 0; i < 5; i++) {
|
||
blockA[i] = new Number(MDbuf[i]);
|
||
blockB[i] = new Number(MDbuf[i]);
|
||
}
|
||
|
||
var step = 0;
|
||
for (var j = 0; j < 5; j++) {
|
||
for (var i = 0; i < 16; i++) {
|
||
retBlock = mixOneRound(
|
||
blockA[(step + 0) % 5],
|
||
blockA[(step + 1) % 5],
|
||
blockA[(step + 2) % 5],
|
||
blockA[(step + 3) % 5],
|
||
blockA[(step + 4) % 5],
|
||
X[indexes[j][i]],
|
||
ROLs[j][i],
|
||
j);
|
||
|
||
blockA[(step + 0) % 5] = retBlock[0];
|
||
blockA[(step + 1) % 5] = retBlock[1];
|
||
blockA[(step + 2) % 5] = retBlock[2];
|
||
blockA[(step + 3) % 5] = retBlock[3];
|
||
blockA[(step + 4) % 5] = retBlock[4];
|
||
|
||
step += 4;
|
||
}
|
||
}
|
||
|
||
step = 0;
|
||
for (var j = 5; j < 10; j++) {
|
||
for (var i = 0; i < 16; i++) {
|
||
retBlock = mixOneRound(
|
||
blockB[(step + 0) % 5],
|
||
blockB[(step + 1) % 5],
|
||
blockB[(step + 2) % 5],
|
||
blockB[(step + 3) % 5],
|
||
blockB[(step + 4) % 5],
|
||
X[indexes[j][i]],
|
||
ROLs[j][i],
|
||
j);
|
||
|
||
blockB[(step + 0) % 5] = retBlock[0];
|
||
blockB[(step + 1) % 5] = retBlock[1];
|
||
blockB[(step + 2) % 5] = retBlock[2];
|
||
blockB[(step + 3) % 5] = retBlock[3];
|
||
blockB[(step + 4) % 5] = retBlock[4];
|
||
|
||
step += 4;
|
||
}
|
||
}
|
||
|
||
blockB[3] += blockA[2] + MDbuf[1];
|
||
MDbuf[1] = MDbuf[2] + blockA[3] + blockB[4];
|
||
MDbuf[2] = MDbuf[3] + blockA[4] + blockB[0];
|
||
MDbuf[3] = MDbuf[4] + blockA[0] + blockB[1];
|
||
MDbuf[4] = MDbuf[0] + blockA[1] + blockB[2];
|
||
MDbuf[0] = blockB[3];
|
||
}
|
||
|
||
function zeroX(X) {
|
||
for (var i = 0; i < 16; i++) {
|
||
X[i] = 0;
|
||
}
|
||
}
|
||
|
||
function MDfinish(MDbuf, strptr, lswlen, mswlen) {
|
||
var X = new Array(16);
|
||
zeroX(X);
|
||
|
||
var j = 0;
|
||
for (var i = 0; i < (lswlen & 63); i++) {
|
||
X[i >>> 2] ^= (strptr.charCodeAt(j++) & 255) << (8 * (i & 3));
|
||
}
|
||
|
||
X[(lswlen >>> 2) & 15] ^= 1 << (8 * (lswlen & 3) + 7);
|
||
|
||
if ((lswlen & 63) > 55) {
|
||
compress(MDbuf, X);
|
||
var X = new Array(16);
|
||
zeroX(X);
|
||
}
|
||
|
||
X[14] = lswlen << 3;
|
||
X[15] = (lswlen >>> 29) | (mswlen << 3);
|
||
|
||
compress(MDbuf, X);
|
||
}
|
||
|
||
function BYTES_TO_DWORD(fourChars) {
|
||
var tmp = (fourChars.charCodeAt(3) & 255) << 24;
|
||
tmp |= (fourChars.charCodeAt(2) & 255) << 16;
|
||
tmp |= (fourChars.charCodeAt(1) & 255) << 8;
|
||
tmp |= (fourChars.charCodeAt(0) & 255);
|
||
|
||
return tmp;
|
||
}
|
||
|
||
function RMD(message) {
|
||
var MDbuf = new Array(RMDsize / 32);
|
||
var hashcode = new Array(RMDsize / 8);
|
||
var length;
|
||
var nbytes;
|
||
|
||
MDinit(MDbuf);
|
||
length = message.length;
|
||
|
||
var X = new Array(16);
|
||
zeroX(X);
|
||
|
||
var j = 0;
|
||
for (var nbytes = length; nbytes > 63; nbytes -= 64) {
|
||
for (var i = 0; i < 16; i++) {
|
||
X[i] = BYTES_TO_DWORD(message.substr(j, 4));
|
||
j += 4;
|
||
}
|
||
compress(MDbuf, X);
|
||
}
|
||
|
||
MDfinish(MDbuf, message.substr(j), length, 0);
|
||
|
||
for (var i = 0; i < RMDsize / 8; i += 4) {
|
||
hashcode[i] = MDbuf[i >>> 2] & 255;
|
||
hashcode[i + 1] = (MDbuf[i >>> 2] >>> 8) & 255;
|
||
hashcode[i + 2] = (MDbuf[i >>> 2] >>> 16) & 255;
|
||
hashcode[i + 3] = (MDbuf[i >>> 2] >>> 24) & 255;
|
||
}
|
||
|
||
return hashcode;
|
||
}
|
||
|
||
|
||
function RMDstring(message) {
|
||
var hashcode = RMD(message);
|
||
var retString = "";
|
||
|
||
for (var i = 0; i < RMDsize / 8; i++) {
|
||
retString += String.fromCharCode(hashcode[i]);
|
||
}
|
||
|
||
return retString;
|
||
}
|
||
|
||
module.exports = RMDstring;
|
||
|
||
},{}],15:[function(require,module,exports){
|
||
/* A JavaScript implementation of the SHA family of hashes, as defined in FIPS
|
||
* PUB 180-2 as well as the corresponding HMAC implementation as defined in
|
||
* FIPS PUB 198a
|
||
*
|
||
* Version 1.3 Copyright Brian Turek 2008-2010
|
||
* Distributed under the BSD License
|
||
* See http://jssha.sourceforge.net/ for more information
|
||
*
|
||
* Several functions taken from Paul Johnson
|
||
*/
|
||
|
||
/* Modified by Recurity Labs GmbH
|
||
*
|
||
* This code has been slightly modified direct string output:
|
||
* - bin2bstr has been added
|
||
* - following wrappers of this library have been added:
|
||
* - str_sha1
|
||
* - str_sha256
|
||
* - str_sha224
|
||
* - str_sha384
|
||
* - str_sha512
|
||
*/
|
||
|
||
var jsSHA = (function() {
|
||
|
||
/*
|
||
* Configurable variables. Defaults typically work
|
||
*/
|
||
/* Number of Bits Per character (8 for ASCII, 16 for Unicode) */
|
||
var charSize = 8,
|
||
/* base-64 pad character. "=" for strict RFC compliance */
|
||
b64pad = "",
|
||
/* hex output format. 0 - lowercase; 1 - uppercase */
|
||
hexCase = 0,
|
||
|
||
/*
|
||
* Int_64 is a object for 2 32-bit numbers emulating a 64-bit number
|
||
*
|
||
* @constructor
|
||
* @param {Number} msint_32 The most significant 32-bits of a 64-bit number
|
||
* @param {Number} lsint_32 The least significant 32-bits of a 64-bit number
|
||
*/
|
||
Int_64 = function(msint_32, lsint_32) {
|
||
this.highOrder = msint_32;
|
||
this.lowOrder = lsint_32;
|
||
},
|
||
|
||
/*
|
||
* Convert a string to an array of big-endian words
|
||
* If charSize is ASCII, characters >255 have their hi-byte silently
|
||
* ignored.
|
||
*
|
||
* @param {String} str String to be converted to binary representation
|
||
* @return Integer array representation of the parameter
|
||
*/
|
||
str2binb = function(str) {
|
||
var bin = [],
|
||
mask = (1 << charSize) - 1,
|
||
length = str.length * charSize,
|
||
i;
|
||
|
||
for (i = 0; i < length; i += charSize) {
|
||
bin[i >> 5] |= (str.charCodeAt(i / charSize) & mask) <<
|
||
(32 - charSize - (i % 32));
|
||
}
|
||
|
||
return bin;
|
||
},
|
||
|
||
/*
|
||
* Convert a hex string to an array of big-endian words
|
||
*
|
||
* @param {String} str String to be converted to binary representation
|
||
* @return Integer array representation of the parameter
|
||
*/
|
||
hex2binb = function(str) {
|
||
var bin = [],
|
||
length = str.length,
|
||
i, num;
|
||
|
||
for (i = 0; i < length; i += 2) {
|
||
num = parseInt(str.substr(i, 2), 16);
|
||
if (!isNaN(num)) {
|
||
bin[i >> 3] |= num << (24 - (4 * (i % 8)));
|
||
} else {
|
||
return "INVALID HEX STRING";
|
||
}
|
||
}
|
||
|
||
return bin;
|
||
},
|
||
|
||
/*
|
||
* Convert an array of big-endian words to a hex string.
|
||
*
|
||
* @private
|
||
* @param {Array} binarray Array of integers to be converted to hexidecimal
|
||
* representation
|
||
* @return Hexidecimal representation of the parameter in String form
|
||
*/
|
||
binb2hex = function(binarray) {
|
||
var hex_tab = (hexCase) ? "0123456789ABCDEF" : "0123456789abcdef",
|
||
str = "",
|
||
length = binarray.length * 4,
|
||
i, srcByte;
|
||
|
||
for (i = 0; i < length; i += 1) {
|
||
srcByte = binarray[i >> 2] >> ((3 - (i % 4)) * 8);
|
||
str += hex_tab.charAt((srcByte >> 4) & 0xF) +
|
||
hex_tab.charAt(srcByte & 0xF);
|
||
}
|
||
|
||
return str;
|
||
},
|
||
|
||
/*
|
||
* Convert an array of big-endian words to a base-64 string
|
||
*
|
||
* @private
|
||
* @param {Array} binarray Array of integers to be converted to base-64
|
||
* representation
|
||
* @return Base-64 encoded representation of the parameter in String form
|
||
*/
|
||
binb2b64 = function(binarray) {
|
||
var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" +
|
||
"0123456789+/",
|
||
str = "",
|
||
length = binarray.length * 4,
|
||
i, j,
|
||
triplet;
|
||
|
||
for (i = 0; i < length; i += 3) {
|
||
triplet = (((binarray[i >> 2] >> 8 * (3 - i % 4)) & 0xFF) << 16) |
|
||
(((binarray[i + 1 >> 2] >> 8 * (3 - (i + 1) % 4)) & 0xFF) << 8) |
|
||
((binarray[i + 2 >> 2] >> 8 * (3 - (i + 2) % 4)) & 0xFF);
|
||
for (j = 0; j < 4; j += 1) {
|
||
if (i * 8 + j * 6 <= binarray.length * 32) {
|
||
str += tab.charAt((triplet >> 6 * (3 - j)) & 0x3F);
|
||
} else {
|
||
str += b64pad;
|
||
}
|
||
}
|
||
}
|
||
return str;
|
||
},
|
||
|
||
/*
|
||
* Convert an array of big-endian words to a string
|
||
*/
|
||
binb2str = function(bin) {
|
||
var str = "";
|
||
var mask = (1 << 8) - 1;
|
||
for (var i = 0; i < bin.length * 32; i += 8)
|
||
str += String.fromCharCode((bin[i >> 5] >>> (24 - i % 32)) & mask);
|
||
return str;
|
||
},
|
||
/*
|
||
* The 32-bit implementation of circular rotate left
|
||
*
|
||
* @private
|
||
* @param {Number} x The 32-bit integer argument
|
||
* @param {Number} n The number of bits to shift
|
||
* @return The x shifted circularly by n bits
|
||
*/
|
||
rotl_32 = function(x, n) {
|
||
return (x << n) | (x >>> (32 - n));
|
||
},
|
||
|
||
/*
|
||
* The 32-bit implementation of circular rotate right
|
||
*
|
||
* @private
|
||
* @param {Number} x The 32-bit integer argument
|
||
* @param {Number} n The number of bits to shift
|
||
* @return The x shifted circularly by n bits
|
||
*/
|
||
rotr_32 = function(x, n) {
|
||
return (x >>> n) | (x << (32 - n));
|
||
},
|
||
|
||
/*
|
||
* The 64-bit implementation of circular rotate right
|
||
*
|
||
* @private
|
||
* @param {Int_64} x The 64-bit integer argument
|
||
* @param {Number} n The number of bits to shift
|
||
* @return The x shifted circularly by n bits
|
||
*/
|
||
rotr_64 = function(x, n) {
|
||
if (n <= 32) {
|
||
return new Int_64(
|
||
(x.highOrder >>> n) | (x.lowOrder << (32 - n)), (x.lowOrder >>> n) | (x.highOrder << (32 - n)));
|
||
} else {
|
||
return new Int_64(
|
||
(x.lowOrder >>> n) | (x.highOrder << (32 - n)), (x.highOrder >>> n) | (x.lowOrder << (32 - n)));
|
||
}
|
||
},
|
||
|
||
/*
|
||
* The 32-bit implementation of shift right
|
||
*
|
||
* @private
|
||
* @param {Number} x The 32-bit integer argument
|
||
* @param {Number} n The number of bits to shift
|
||
* @return The x shifted by n bits
|
||
*/
|
||
shr_32 = function(x, n) {
|
||
return x >>> n;
|
||
},
|
||
|
||
/*
|
||
* The 64-bit implementation of shift right
|
||
*
|
||
* @private
|
||
* @param {Int_64} x The 64-bit integer argument
|
||
* @param {Number} n The number of bits to shift
|
||
* @return The x shifted by n bits
|
||
*/
|
||
shr_64 = function(x, n) {
|
||
if (n <= 32) {
|
||
return new Int_64(
|
||
x.highOrder >>> n,
|
||
x.lowOrder >>> n | (x.highOrder << (32 - n)));
|
||
} else {
|
||
return new Int_64(
|
||
0,
|
||
x.highOrder << (32 - n));
|
||
}
|
||
},
|
||
|
||
/*
|
||
* The 32-bit implementation of the NIST specified Parity function
|
||
*
|
||
* @private
|
||
* @param {Number} x The first 32-bit integer argument
|
||
* @param {Number} y The second 32-bit integer argument
|
||
* @param {Number} z The third 32-bit integer argument
|
||
* @return The NIST specified output of the function
|
||
*/
|
||
parity_32 = function(x, y, z) {
|
||
return x ^ y ^ z;
|
||
},
|
||
|
||
/*
|
||
* The 32-bit implementation of the NIST specified Ch function
|
||
*
|
||
* @private
|
||
* @param {Number} x The first 32-bit integer argument
|
||
* @param {Number} y The second 32-bit integer argument
|
||
* @param {Number} z The third 32-bit integer argument
|
||
* @return The NIST specified output of the function
|
||
*/
|
||
ch_32 = function(x, y, z) {
|
||
return (x & y) ^ (~x & z);
|
||
},
|
||
|
||
/*
|
||
* The 64-bit implementation of the NIST specified Ch function
|
||
*
|
||
* @private
|
||
* @param {Int_64} x The first 64-bit integer argument
|
||
* @param {Int_64} y The second 64-bit integer argument
|
||
* @param {Int_64} z The third 64-bit integer argument
|
||
* @return The NIST specified output of the function
|
||
*/
|
||
ch_64 = function(x, y, z) {
|
||
return new Int_64(
|
||
(x.highOrder & y.highOrder) ^ (~x.highOrder & z.highOrder), (x.lowOrder & y.lowOrder) ^ (~x.lowOrder & z.lowOrder));
|
||
},
|
||
|
||
/*
|
||
* The 32-bit implementation of the NIST specified Maj function
|
||
*
|
||
* @private
|
||
* @param {Number} x The first 32-bit integer argument
|
||
* @param {Number} y The second 32-bit integer argument
|
||
* @param {Number} z The third 32-bit integer argument
|
||
* @return The NIST specified output of the function
|
||
*/
|
||
maj_32 = function(x, y, z) {
|
||
return (x & y) ^ (x & z) ^ (y & z);
|
||
},
|
||
|
||
/*
|
||
* The 64-bit implementation of the NIST specified Maj function
|
||
*
|
||
* @private
|
||
* @param {Int_64} x The first 64-bit integer argument
|
||
* @param {Int_64} y The second 64-bit integer argument
|
||
* @param {Int_64} z The third 64-bit integer argument
|
||
* @return The NIST specified output of the function
|
||
*/
|
||
maj_64 = function(x, y, z) {
|
||
return new Int_64(
|
||
(x.highOrder & y.highOrder) ^
|
||
(x.highOrder & z.highOrder) ^
|
||
(y.highOrder & z.highOrder), (x.lowOrder & y.lowOrder) ^
|
||
(x.lowOrder & z.lowOrder) ^
|
||
(y.lowOrder & z.lowOrder));
|
||
},
|
||
|
||
/*
|
||
* The 32-bit implementation of the NIST specified Sigma0 function
|
||
*
|
||
* @private
|
||
* @param {Number} x The 32-bit integer argument
|
||
* @return The NIST specified output of the function
|
||
*/
|
||
sigma0_32 = function(x) {
|
||
return rotr_32(x, 2) ^ rotr_32(x, 13) ^ rotr_32(x, 22);
|
||
},
|
||
|
||
/*
|
||
* The 64-bit implementation of the NIST specified Sigma0 function
|
||
*
|
||
* @private
|
||
* @param {Int_64} x The 64-bit integer argument
|
||
* @return The NIST specified output of the function
|
||
*/
|
||
sigma0_64 = function(x) {
|
||
var rotr28 = rotr_64(x, 28),
|
||
rotr34 = rotr_64(x, 34),
|
||
rotr39 = rotr_64(x, 39);
|
||
|
||
return new Int_64(
|
||
rotr28.highOrder ^ rotr34.highOrder ^ rotr39.highOrder,
|
||
rotr28.lowOrder ^ rotr34.lowOrder ^ rotr39.lowOrder);
|
||
},
|
||
|
||
/*
|
||
* The 32-bit implementation of the NIST specified Sigma1 function
|
||
*
|
||
* @private
|
||
* @param {Number} x The 32-bit integer argument
|
||
* @return The NIST specified output of the function
|
||
*/
|
||
sigma1_32 = function(x) {
|
||
return rotr_32(x, 6) ^ rotr_32(x, 11) ^ rotr_32(x, 25);
|
||
},
|
||
|
||
/*
|
||
* The 64-bit implementation of the NIST specified Sigma1 function
|
||
*
|
||
* @private
|
||
* @param {Int_64} x The 64-bit integer argument
|
||
* @return The NIST specified output of the function
|
||
*/
|
||
sigma1_64 = function(x) {
|
||
var rotr14 = rotr_64(x, 14),
|
||
rotr18 = rotr_64(x, 18),
|
||
rotr41 = rotr_64(x, 41);
|
||
|
||
return new Int_64(
|
||
rotr14.highOrder ^ rotr18.highOrder ^ rotr41.highOrder,
|
||
rotr14.lowOrder ^ rotr18.lowOrder ^ rotr41.lowOrder);
|
||
},
|
||
|
||
/*
|
||
* The 32-bit implementation of the NIST specified Gamma0 function
|
||
*
|
||
* @private
|
||
* @param {Number} x The 32-bit integer argument
|
||
* @return The NIST specified output of the function
|
||
*/
|
||
gamma0_32 = function(x) {
|
||
return rotr_32(x, 7) ^ rotr_32(x, 18) ^ shr_32(x, 3);
|
||
},
|
||
|
||
/*
|
||
* The 64-bit implementation of the NIST specified Gamma0 function
|
||
*
|
||
* @private
|
||
* @param {Int_64} x The 64-bit integer argument
|
||
* @return The NIST specified output of the function
|
||
*/
|
||
gamma0_64 = function(x) {
|
||
var rotr1 = rotr_64(x, 1),
|
||
rotr8 = rotr_64(x, 8),
|
||
shr7 = shr_64(x, 7);
|
||
|
||
return new Int_64(
|
||
rotr1.highOrder ^ rotr8.highOrder ^ shr7.highOrder,
|
||
rotr1.lowOrder ^ rotr8.lowOrder ^ shr7.lowOrder);
|
||
},
|
||
|
||
/*
|
||
* The 32-bit implementation of the NIST specified Gamma1 function
|
||
*
|
||
* @private
|
||
* @param {Number} x The 32-bit integer argument
|
||
* @return The NIST specified output of the function
|
||
*/
|
||
gamma1_32 = function(x) {
|
||
return rotr_32(x, 17) ^ rotr_32(x, 19) ^ shr_32(x, 10);
|
||
},
|
||
|
||
/*
|
||
* The 64-bit implementation of the NIST specified Gamma1 function
|
||
*
|
||
* @private
|
||
* @param {Int_64} x The 64-bit integer argument
|
||
* @return The NIST specified output of the function
|
||
*/
|
||
gamma1_64 = function(x) {
|
||
var rotr19 = rotr_64(x, 19),
|
||
rotr61 = rotr_64(x, 61),
|
||
shr6 = shr_64(x, 6);
|
||
|
||
return new Int_64(
|
||
rotr19.highOrder ^ rotr61.highOrder ^ shr6.highOrder,
|
||
rotr19.lowOrder ^ rotr61.lowOrder ^ shr6.lowOrder);
|
||
},
|
||
|
||
/*
|
||
* Add two 32-bit integers, wrapping at 2^32. This uses 16-bit operations
|
||
* internally to work around bugs in some JS interpreters.
|
||
*
|
||
* @private
|
||
* @param {Number} x The first 32-bit integer argument to be added
|
||
* @param {Number} y The second 32-bit integer argument to be added
|
||
* @return The sum of x + y
|
||
*/
|
||
safeAdd_32_2 = function(x, y) {
|
||
var lsw = (x & 0xFFFF) + (y & 0xFFFF),
|
||
msw = (x >>> 16) + (y >>> 16) + (lsw >>> 16);
|
||
|
||
return ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF);
|
||
},
|
||
|
||
/*
|
||
* Add four 32-bit integers, wrapping at 2^32. This uses 16-bit operations
|
||
* internally to work around bugs in some JS interpreters.
|
||
*
|
||
* @private
|
||
* @param {Number} a The first 32-bit integer argument to be added
|
||
* @param {Number} b The second 32-bit integer argument to be added
|
||
* @param {Number} c The third 32-bit integer argument to be added
|
||
* @param {Number} d The fourth 32-bit integer argument to be added
|
||
* @return The sum of a + b + c + d
|
||
*/
|
||
safeAdd_32_4 = function(a, b, c, d) {
|
||
var lsw = (a & 0xFFFF) + (b & 0xFFFF) + (c & 0xFFFF) + (d & 0xFFFF),
|
||
msw = (a >>> 16) + (b >>> 16) + (c >>> 16) + (d >>> 16) +
|
||
(lsw >>> 16);
|
||
|
||
return ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF);
|
||
},
|
||
|
||
/*
|
||
* Add five 32-bit integers, wrapping at 2^32. This uses 16-bit operations
|
||
* internally to work around bugs in some JS interpreters.
|
||
*
|
||
* @private
|
||
* @param {Number} a The first 32-bit integer argument to be added
|
||
* @param {Number} b The second 32-bit integer argument to be added
|
||
* @param {Number} c The third 32-bit integer argument to be added
|
||
* @param {Number} d The fourth 32-bit integer argument to be added
|
||
* @param {Number} e The fifth 32-bit integer argument to be added
|
||
* @return The sum of a + b + c + d + e
|
||
*/
|
||
safeAdd_32_5 = function(a, b, c, d, e) {
|
||
var lsw = (a & 0xFFFF) + (b & 0xFFFF) + (c & 0xFFFF) + (d & 0xFFFF) +
|
||
(e & 0xFFFF),
|
||
msw = (a >>> 16) + (b >>> 16) + (c >>> 16) + (d >>> 16) +
|
||
(e >>> 16) + (lsw >>> 16);
|
||
|
||
return ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF);
|
||
},
|
||
|
||
/*
|
||
* Add two 64-bit integers, wrapping at 2^64. This uses 16-bit operations
|
||
* internally to work around bugs in some JS interpreters.
|
||
*
|
||
* @private
|
||
* @param {Int_64} x The first 64-bit integer argument to be added
|
||
* @param {Int_64} y The second 64-bit integer argument to be added
|
||
* @return The sum of x + y
|
||
*/
|
||
safeAdd_64_2 = function(x, y) {
|
||
var lsw, msw, lowOrder, highOrder;
|
||
|
||
lsw = (x.lowOrder & 0xFFFF) + (y.lowOrder & 0xFFFF);
|
||
msw = (x.lowOrder >>> 16) + (y.lowOrder >>> 16) + (lsw >>> 16);
|
||
lowOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF);
|
||
|
||
lsw = (x.highOrder & 0xFFFF) + (y.highOrder & 0xFFFF) + (msw >>> 16);
|
||
msw = (x.highOrder >>> 16) + (y.highOrder >>> 16) + (lsw >>> 16);
|
||
highOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF);
|
||
|
||
return new Int_64(highOrder, lowOrder);
|
||
},
|
||
|
||
/*
|
||
* Add four 64-bit integers, wrapping at 2^64. This uses 16-bit operations
|
||
* internally to work around bugs in some JS interpreters.
|
||
*
|
||
* @private
|
||
* @param {Int_64} a The first 64-bit integer argument to be added
|
||
* @param {Int_64} b The second 64-bit integer argument to be added
|
||
* @param {Int_64} c The third 64-bit integer argument to be added
|
||
* @param {Int_64} d The fouth 64-bit integer argument to be added
|
||
* @return The sum of a + b + c + d
|
||
*/
|
||
safeAdd_64_4 = function(a, b, c, d) {
|
||
var lsw, msw, lowOrder, highOrder;
|
||
|
||
lsw = (a.lowOrder & 0xFFFF) + (b.lowOrder & 0xFFFF) +
|
||
(c.lowOrder & 0xFFFF) + (d.lowOrder & 0xFFFF);
|
||
msw = (a.lowOrder >>> 16) + (b.lowOrder >>> 16) +
|
||
(c.lowOrder >>> 16) + (d.lowOrder >>> 16) + (lsw >>> 16);
|
||
lowOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF);
|
||
|
||
lsw = (a.highOrder & 0xFFFF) + (b.highOrder & 0xFFFF) +
|
||
(c.highOrder & 0xFFFF) + (d.highOrder & 0xFFFF) + (msw >>> 16);
|
||
msw = (a.highOrder >>> 16) + (b.highOrder >>> 16) +
|
||
(c.highOrder >>> 16) + (d.highOrder >>> 16) + (lsw >>> 16);
|
||
highOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF);
|
||
|
||
return new Int_64(highOrder, lowOrder);
|
||
},
|
||
|
||
/*
|
||
* Add five 64-bit integers, wrapping at 2^64. This uses 16-bit operations
|
||
* internally to work around bugs in some JS interpreters.
|
||
*
|
||
* @private
|
||
* @param {Int_64} a The first 64-bit integer argument to be added
|
||
* @param {Int_64} b The second 64-bit integer argument to be added
|
||
* @param {Int_64} c The third 64-bit integer argument to be added
|
||
* @param {Int_64} d The fouth 64-bit integer argument to be added
|
||
* @param {Int_64} e The fouth 64-bit integer argument to be added
|
||
* @return The sum of a + b + c + d + e
|
||
*/
|
||
safeAdd_64_5 = function(a, b, c, d, e) {
|
||
var lsw, msw, lowOrder, highOrder;
|
||
|
||
lsw = (a.lowOrder & 0xFFFF) + (b.lowOrder & 0xFFFF) +
|
||
(c.lowOrder & 0xFFFF) + (d.lowOrder & 0xFFFF) +
|
||
(e.lowOrder & 0xFFFF);
|
||
msw = (a.lowOrder >>> 16) + (b.lowOrder >>> 16) +
|
||
(c.lowOrder >>> 16) + (d.lowOrder >>> 16) + (e.lowOrder >>> 16) +
|
||
(lsw >>> 16);
|
||
lowOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF);
|
||
|
||
lsw = (a.highOrder & 0xFFFF) + (b.highOrder & 0xFFFF) +
|
||
(c.highOrder & 0xFFFF) + (d.highOrder & 0xFFFF) +
|
||
(e.highOrder & 0xFFFF) + (msw >>> 16);
|
||
msw = (a.highOrder >>> 16) + (b.highOrder >>> 16) +
|
||
(c.highOrder >>> 16) + (d.highOrder >>> 16) +
|
||
(e.highOrder >>> 16) + (lsw >>> 16);
|
||
highOrder = ((msw & 0xFFFF) << 16) | (lsw & 0xFFFF);
|
||
|
||
return new Int_64(highOrder, lowOrder);
|
||
},
|
||
|
||
/*
|
||
* Calculates the SHA-1 hash of the string set at instantiation
|
||
*
|
||
* @private
|
||
* @param {Array} message The binary array representation of the string to
|
||
* hash
|
||
* @param {Number} messageLen The number of bits in the message
|
||
* @return The array of integers representing the SHA-1 hash of message
|
||
*/
|
||
coreSHA1 = function(message, messageLen) {
|
||
var W = [],
|
||
a, b, c, d, e, T, ch = ch_32,
|
||
parity = parity_32,
|
||
maj = maj_32,
|
||
rotl = rotl_32,
|
||
safeAdd_2 = safeAdd_32_2,
|
||
i, t,
|
||
safeAdd_5 = safeAdd_32_5,
|
||
appendedMessageLength,
|
||
H = [
|
||
0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0
|
||
],
|
||
K = [
|
||
0x5a827999, 0x5a827999, 0x5a827999, 0x5a827999,
|
||
0x5a827999, 0x5a827999, 0x5a827999, 0x5a827999,
|
||
0x5a827999, 0x5a827999, 0x5a827999, 0x5a827999,
|
||
0x5a827999, 0x5a827999, 0x5a827999, 0x5a827999,
|
||
0x5a827999, 0x5a827999, 0x5a827999, 0x5a827999,
|
||
0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1,
|
||
0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1,
|
||
0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1,
|
||
0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1,
|
||
0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1,
|
||
0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc,
|
||
0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc,
|
||
0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc,
|
||
0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc,
|
||
0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc,
|
||
0xca62c1d6, 0xca62c1d6, 0xca62c1d6, 0xca62c1d6,
|
||
0xca62c1d6, 0xca62c1d6, 0xca62c1d6, 0xca62c1d6,
|
||
0xca62c1d6, 0xca62c1d6, 0xca62c1d6, 0xca62c1d6,
|
||
0xca62c1d6, 0xca62c1d6, 0xca62c1d6, 0xca62c1d6,
|
||
0xca62c1d6, 0xca62c1d6, 0xca62c1d6, 0xca62c1d6
|
||
];
|
||
|
||
/* Append '1' at the end of the binary string */
|
||
message[messageLen >> 5] |= 0x80 << (24 - (messageLen % 32));
|
||
/* Append length of binary string in the position such that the new
|
||
length is a multiple of 512. Logic does not work for even multiples
|
||
of 512 but there can never be even multiples of 512 */
|
||
message[(((messageLen + 65) >> 9) << 4) + 15] = messageLen;
|
||
|
||
appendedMessageLength = message.length;
|
||
|
||
for (i = 0; i < appendedMessageLength; i += 16) {
|
||
a = H[0];
|
||
b = H[1];
|
||
c = H[2];
|
||
d = H[3];
|
||
e = H[4];
|
||
|
||
for (t = 0; t < 80; t += 1) {
|
||
if (t < 16) {
|
||
W[t] = message[t + i];
|
||
} else {
|
||
W[t] = rotl(W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16], 1);
|
||
}
|
||
|
||
if (t < 20) {
|
||
T = safeAdd_5(rotl(a, 5), ch(b, c, d), e, K[t], W[t]);
|
||
} else if (t < 40) {
|
||
T = safeAdd_5(rotl(a, 5), parity(b, c, d), e, K[t], W[t]);
|
||
} else if (t < 60) {
|
||
T = safeAdd_5(rotl(a, 5), maj(b, c, d), e, K[t], W[t]);
|
||
} else {
|
||
T = safeAdd_5(rotl(a, 5), parity(b, c, d), e, K[t], W[t]);
|
||
}
|
||
|
||
e = d;
|
||
d = c;
|
||
c = rotl(b, 30);
|
||
b = a;
|
||
a = T;
|
||
}
|
||
|
||
H[0] = safeAdd_2(a, H[0]);
|
||
H[1] = safeAdd_2(b, H[1]);
|
||
H[2] = safeAdd_2(c, H[2]);
|
||
H[3] = safeAdd_2(d, H[3]);
|
||
H[4] = safeAdd_2(e, H[4]);
|
||
}
|
||
|
||
return H;
|
||
},
|
||
|
||
/*
|
||
* Calculates the desired SHA-2 hash of the string set at instantiation
|
||
*
|
||
* @private
|
||
* @param {Array} The binary array representation of the string to hash
|
||
* @param {Number} The number of bits in message
|
||
* @param {String} variant The desired SHA-2 variant
|
||
* @return The array of integers representing the SHA-2 hash of message
|
||
*/
|
||
coreSHA2 = function(message, messageLen, variant) {
|
||
var a, b, c, d, e, f, g, h, T1, T2, H, numRounds, lengthPosition, i, t,
|
||
binaryStringInc, binaryStringMult, safeAdd_2, safeAdd_4, safeAdd_5,
|
||
gamma0, gamma1, sigma0, sigma1, ch, maj, Int, K, W = [],
|
||
appendedMessageLength;
|
||
|
||
/* Set up the various function handles and variable for the specific
|
||
* variant */
|
||
if (variant === "SHA-224" || variant === "SHA-256") {
|
||
/* 32-bit variant */
|
||
numRounds = 64;
|
||
lengthPosition = (((messageLen + 65) >> 9) << 4) + 15;
|
||
binaryStringInc = 16;
|
||
binaryStringMult = 1;
|
||
Int = Number;
|
||
safeAdd_2 = safeAdd_32_2;
|
||
safeAdd_4 = safeAdd_32_4;
|
||
safeAdd_5 = safeAdd_32_5;
|
||
gamma0 = gamma0_32;
|
||
gamma1 = gamma1_32;
|
||
sigma0 = sigma0_32;
|
||
sigma1 = sigma1_32;
|
||
maj = maj_32;
|
||
ch = ch_32;
|
||
K = [
|
||
0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5,
|
||
0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5,
|
||
0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3,
|
||
0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174,
|
||
0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC,
|
||
0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA,
|
||
0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7,
|
||
0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967,
|
||
0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13,
|
||
0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85,
|
||
0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3,
|
||
0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070,
|
||
0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5,
|
||
0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3,
|
||
0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208,
|
||
0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2
|
||
];
|
||
|
||
if (variant === "SHA-224") {
|
||
H = [
|
||
0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939,
|
||
0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4
|
||
];
|
||
} else {
|
||
H = [
|
||
0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
|
||
0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19
|
||
];
|
||
}
|
||
} else if (variant === "SHA-384" || variant === "SHA-512") {
|
||
/* 64-bit variant */
|
||
numRounds = 80;
|
||
lengthPosition = (((messageLen + 128) >> 10) << 5) + 31;
|
||
binaryStringInc = 32;
|
||
binaryStringMult = 2;
|
||
Int = Int_64;
|
||
safeAdd_2 = safeAdd_64_2;
|
||
safeAdd_4 = safeAdd_64_4;
|
||
safeAdd_5 = safeAdd_64_5;
|
||
gamma0 = gamma0_64;
|
||
gamma1 = gamma1_64;
|
||
sigma0 = sigma0_64;
|
||
sigma1 = sigma1_64;
|
||
maj = maj_64;
|
||
ch = ch_64;
|
||
|
||
K = [
|
||
new Int(0x428a2f98, 0xd728ae22), new Int(0x71374491, 0x23ef65cd),
|
||
new Int(0xb5c0fbcf, 0xec4d3b2f), new Int(0xe9b5dba5, 0x8189dbbc),
|
||
new Int(0x3956c25b, 0xf348b538), new Int(0x59f111f1, 0xb605d019),
|
||
new Int(0x923f82a4, 0xaf194f9b), new Int(0xab1c5ed5, 0xda6d8118),
|
||
new Int(0xd807aa98, 0xa3030242), new Int(0x12835b01, 0x45706fbe),
|
||
new Int(0x243185be, 0x4ee4b28c), new Int(0x550c7dc3, 0xd5ffb4e2),
|
||
new Int(0x72be5d74, 0xf27b896f), new Int(0x80deb1fe, 0x3b1696b1),
|
||
new Int(0x9bdc06a7, 0x25c71235), new Int(0xc19bf174, 0xcf692694),
|
||
new Int(0xe49b69c1, 0x9ef14ad2), new Int(0xefbe4786, 0x384f25e3),
|
||
new Int(0x0fc19dc6, 0x8b8cd5b5), new Int(0x240ca1cc, 0x77ac9c65),
|
||
new Int(0x2de92c6f, 0x592b0275), new Int(0x4a7484aa, 0x6ea6e483),
|
||
new Int(0x5cb0a9dc, 0xbd41fbd4), new Int(0x76f988da, 0x831153b5),
|
||
new Int(0x983e5152, 0xee66dfab), new Int(0xa831c66d, 0x2db43210),
|
||
new Int(0xb00327c8, 0x98fb213f), new Int(0xbf597fc7, 0xbeef0ee4),
|
||
new Int(0xc6e00bf3, 0x3da88fc2), new Int(0xd5a79147, 0x930aa725),
|
||
new Int(0x06ca6351, 0xe003826f), new Int(0x14292967, 0x0a0e6e70),
|
||
new Int(0x27b70a85, 0x46d22ffc), new Int(0x2e1b2138, 0x5c26c926),
|
||
new Int(0x4d2c6dfc, 0x5ac42aed), new Int(0x53380d13, 0x9d95b3df),
|
||
new Int(0x650a7354, 0x8baf63de), new Int(0x766a0abb, 0x3c77b2a8),
|
||
new Int(0x81c2c92e, 0x47edaee6), new Int(0x92722c85, 0x1482353b),
|
||
new Int(0xa2bfe8a1, 0x4cf10364), new Int(0xa81a664b, 0xbc423001),
|
||
new Int(0xc24b8b70, 0xd0f89791), new Int(0xc76c51a3, 0x0654be30),
|
||
new Int(0xd192e819, 0xd6ef5218), new Int(0xd6990624, 0x5565a910),
|
||
new Int(0xf40e3585, 0x5771202a), new Int(0x106aa070, 0x32bbd1b8),
|
||
new Int(0x19a4c116, 0xb8d2d0c8), new Int(0x1e376c08, 0x5141ab53),
|
||
new Int(0x2748774c, 0xdf8eeb99), new Int(0x34b0bcb5, 0xe19b48a8),
|
||
new Int(0x391c0cb3, 0xc5c95a63), new Int(0x4ed8aa4a, 0xe3418acb),
|
||
new Int(0x5b9cca4f, 0x7763e373), new Int(0x682e6ff3, 0xd6b2b8a3),
|
||
new Int(0x748f82ee, 0x5defb2fc), new Int(0x78a5636f, 0x43172f60),
|
||
new Int(0x84c87814, 0xa1f0ab72), new Int(0x8cc70208, 0x1a6439ec),
|
||
new Int(0x90befffa, 0x23631e28), new Int(0xa4506ceb, 0xde82bde9),
|
||
new Int(0xbef9a3f7, 0xb2c67915), new Int(0xc67178f2, 0xe372532b),
|
||
new Int(0xca273ece, 0xea26619c), new Int(0xd186b8c7, 0x21c0c207),
|
||
new Int(0xeada7dd6, 0xcde0eb1e), new Int(0xf57d4f7f, 0xee6ed178),
|
||
new Int(0x06f067aa, 0x72176fba), new Int(0x0a637dc5, 0xa2c898a6),
|
||
new Int(0x113f9804, 0xbef90dae), new Int(0x1b710b35, 0x131c471b),
|
||
new Int(0x28db77f5, 0x23047d84), new Int(0x32caab7b, 0x40c72493),
|
||
new Int(0x3c9ebe0a, 0x15c9bebc), new Int(0x431d67c4, 0x9c100d4c),
|
||
new Int(0x4cc5d4be, 0xcb3e42b6), new Int(0x597f299c, 0xfc657e2a),
|
||
new Int(0x5fcb6fab, 0x3ad6faec), new Int(0x6c44198c, 0x4a475817)
|
||
];
|
||
|
||
if (variant === "SHA-384") {
|
||
H = [
|
||
new Int(0xcbbb9d5d, 0xc1059ed8), new Int(0x0629a292a, 0x367cd507),
|
||
new Int(0x9159015a, 0x3070dd17), new Int(0x0152fecd8, 0xf70e5939),
|
||
new Int(0x67332667, 0xffc00b31), new Int(0x98eb44a87, 0x68581511),
|
||
new Int(0xdb0c2e0d, 0x64f98fa7), new Int(0x047b5481d, 0xbefa4fa4)
|
||
];
|
||
} else {
|
||
H = [
|
||
new Int(0x6a09e667, 0xf3bcc908), new Int(0xbb67ae85, 0x84caa73b),
|
||
new Int(0x3c6ef372, 0xfe94f82b), new Int(0xa54ff53a, 0x5f1d36f1),
|
||
new Int(0x510e527f, 0xade682d1), new Int(0x9b05688c, 0x2b3e6c1f),
|
||
new Int(0x1f83d9ab, 0xfb41bd6b), new Int(0x5be0cd19, 0x137e2179)
|
||
];
|
||
}
|
||
}
|
||
|
||
/* Append '1' at the end of the binary string */
|
||
message[messageLen >> 5] |= 0x80 << (24 - messageLen % 32);
|
||
/* Append length of binary string in the position such that the new
|
||
* length is correct */
|
||
message[lengthPosition] = messageLen;
|
||
|
||
appendedMessageLength = message.length;
|
||
|
||
for (i = 0; i < appendedMessageLength; i += binaryStringInc) {
|
||
a = H[0];
|
||
b = H[1];
|
||
c = H[2];
|
||
d = H[3];
|
||
e = H[4];
|
||
f = H[5];
|
||
g = H[6];
|
||
h = H[7];
|
||
|
||
for (t = 0; t < numRounds; t += 1) {
|
||
if (t < 16) {
|
||
/* Bit of a hack - for 32-bit, the second term is ignored */
|
||
W[t] = new Int(message[t * binaryStringMult + i],
|
||
message[t * binaryStringMult + i + 1]);
|
||
} else {
|
||
W[t] = safeAdd_4(
|
||
gamma1(W[t - 2]), W[t - 7],
|
||
gamma0(W[t - 15]), W[t - 16]);
|
||
}
|
||
|
||
T1 = safeAdd_5(h, sigma1(e), ch(e, f, g), K[t], W[t]);
|
||
T2 = safeAdd_2(sigma0(a), maj(a, b, c));
|
||
h = g;
|
||
g = f;
|
||
f = e;
|
||
e = safeAdd_2(d, T1);
|
||
d = c;
|
||
c = b;
|
||
b = a;
|
||
a = safeAdd_2(T1, T2);
|
||
}
|
||
|
||
H[0] = safeAdd_2(a, H[0]);
|
||
H[1] = safeAdd_2(b, H[1]);
|
||
H[2] = safeAdd_2(c, H[2]);
|
||
H[3] = safeAdd_2(d, H[3]);
|
||
H[4] = safeAdd_2(e, H[4]);
|
||
H[5] = safeAdd_2(f, H[5]);
|
||
H[6] = safeAdd_2(g, H[6]);
|
||
H[7] = safeAdd_2(h, H[7]);
|
||
}
|
||
|
||
switch (variant) {
|
||
case "SHA-224":
|
||
return [
|
||
H[0], H[1], H[2], H[3],
|
||
H[4], H[5], H[6]];
|
||
case "SHA-256":
|
||
return H;
|
||
case "SHA-384":
|
||
return [
|
||
H[0].highOrder, H[0].lowOrder,
|
||
H[1].highOrder, H[1].lowOrder,
|
||
H[2].highOrder, H[2].lowOrder,
|
||
H[3].highOrder, H[3].lowOrder,
|
||
H[4].highOrder, H[4].lowOrder,
|
||
H[5].highOrder, H[5].lowOrder];
|
||
case "SHA-512":
|
||
return [
|
||
H[0].highOrder, H[0].lowOrder,
|
||
H[1].highOrder, H[1].lowOrder,
|
||
H[2].highOrder, H[2].lowOrder,
|
||
H[3].highOrder, H[3].lowOrder,
|
||
H[4].highOrder, H[4].lowOrder,
|
||
H[5].highOrder, H[5].lowOrder,
|
||
H[6].highOrder, H[6].lowOrder,
|
||
H[7].highOrder, H[7].lowOrder];
|
||
default:
|
||
/* This should never be reached */
|
||
return [];
|
||
}
|
||
},
|
||
|
||
/*
|
||
* jsSHA is the workhorse of the library. Instantiate it with the string to
|
||
* be hashed as the parameter
|
||
*
|
||
* @constructor
|
||
* @param {String} srcString The string to be hashed
|
||
* @param {String} inputFormat The format of srcString, ASCII or HEX
|
||
*/
|
||
jsSHA = function(srcString, inputFormat) {
|
||
|
||
this.sha1 = null;
|
||
this.sha224 = null;
|
||
this.sha256 = null;
|
||
this.sha384 = null;
|
||
this.sha512 = null;
|
||
|
||
this.strBinLen = null;
|
||
this.strToHash = null;
|
||
|
||
/* Convert the input string into the correct type */
|
||
if ("HEX" === inputFormat) {
|
||
if (0 !== (srcString.length % 2)) {
|
||
return "TEXT MUST BE IN BYTE INCREMENTS";
|
||
}
|
||
this.strBinLen = srcString.length * 4;
|
||
this.strToHash = hex2binb(srcString);
|
||
} else if (("ASCII" === inputFormat) ||
|
||
('undefined' === typeof(inputFormat))) {
|
||
this.strBinLen = srcString.length * charSize;
|
||
this.strToHash = str2binb(srcString);
|
||
} else {
|
||
return "UNKNOWN TEXT INPUT TYPE";
|
||
}
|
||
};
|
||
|
||
jsSHA.prototype = {
|
||
/*
|
||
* Returns the desired SHA hash of the string specified at instantiation
|
||
* using the specified parameters
|
||
*
|
||
* @param {String} variant The desired SHA variant (SHA-1, SHA-224,
|
||
* SHA-256, SHA-384, or SHA-512)
|
||
* @param {String} format The desired output formatting (B64 or HEX)
|
||
* @return The string representation of the hash in the format specified
|
||
*/
|
||
getHash: function(variant, format) {
|
||
var formatFunc = null,
|
||
message = this.strToHash.slice();
|
||
|
||
switch (format) {
|
||
case "HEX":
|
||
formatFunc = binb2hex;
|
||
break;
|
||
case "B64":
|
||
formatFunc = binb2b64;
|
||
break;
|
||
case "ASCII":
|
||
formatFunc = binb2str;
|
||
break;
|
||
default:
|
||
return "FORMAT NOT RECOGNIZED";
|
||
}
|
||
|
||
switch (variant) {
|
||
case "SHA-1":
|
||
if (null === this.sha1) {
|
||
this.sha1 = coreSHA1(message, this.strBinLen);
|
||
}
|
||
return formatFunc(this.sha1);
|
||
case "SHA-224":
|
||
if (null === this.sha224) {
|
||
this.sha224 = coreSHA2(message, this.strBinLen, variant);
|
||
}
|
||
return formatFunc(this.sha224);
|
||
case "SHA-256":
|
||
if (null === this.sha256) {
|
||
this.sha256 = coreSHA2(message, this.strBinLen, variant);
|
||
}
|
||
return formatFunc(this.sha256);
|
||
case "SHA-384":
|
||
if (null === this.sha384) {
|
||
this.sha384 = coreSHA2(message, this.strBinLen, variant);
|
||
}
|
||
return formatFunc(this.sha384);
|
||
case "SHA-512":
|
||
if (null === this.sha512) {
|
||
this.sha512 = coreSHA2(message, this.strBinLen, variant);
|
||
}
|
||
return formatFunc(this.sha512);
|
||
default:
|
||
return "HASH NOT RECOGNIZED";
|
||
}
|
||
},
|
||
|
||
/*
|
||
* Returns the desired HMAC of the string specified at instantiation
|
||
* using the key and variant param.
|
||
*
|
||
* @param {String} key The key used to calculate the HMAC
|
||
* @param {String} inputFormat The format of key, ASCII or HEX
|
||
* @param {String} variant The desired SHA variant (SHA-1, SHA-224,
|
||
* SHA-256, SHA-384, or SHA-512)
|
||
* @param {String} outputFormat The desired output formatting
|
||
* (B64 or HEX)
|
||
* @return The string representation of the hash in the format specified
|
||
*/
|
||
getHMAC: function(key, inputFormat, variant, outputFormat) {
|
||
var formatFunc, keyToUse, blockByteSize, blockBitSize, i,
|
||
retVal, lastArrayIndex, keyBinLen, hashBitSize,
|
||
keyWithIPad = [],
|
||
keyWithOPad = [];
|
||
|
||
/* Validate the output format selection */
|
||
switch (outputFormat) {
|
||
case "HEX":
|
||
formatFunc = binb2hex;
|
||
break;
|
||
case "B64":
|
||
formatFunc = binb2b64;
|
||
break;
|
||
case "ASCII":
|
||
formatFunc = binb2str;
|
||
break;
|
||
default:
|
||
return "FORMAT NOT RECOGNIZED";
|
||
}
|
||
|
||
/* Validate the hash variant selection and set needed variables */
|
||
switch (variant) {
|
||
case "SHA-1":
|
||
blockByteSize = 64;
|
||
hashBitSize = 160;
|
||
break;
|
||
case "SHA-224":
|
||
blockByteSize = 64;
|
||
hashBitSize = 224;
|
||
break;
|
||
case "SHA-256":
|
||
blockByteSize = 64;
|
||
hashBitSize = 256;
|
||
break;
|
||
case "SHA-384":
|
||
blockByteSize = 128;
|
||
hashBitSize = 384;
|
||
break;
|
||
case "SHA-512":
|
||
blockByteSize = 128;
|
||
hashBitSize = 512;
|
||
break;
|
||
default:
|
||
return "HASH NOT RECOGNIZED";
|
||
}
|
||
|
||
/* Validate input format selection */
|
||
if ("HEX" === inputFormat) {
|
||
/* Nibbles must come in pairs */
|
||
if (0 !== (key.length % 2)) {
|
||
return "KEY MUST BE IN BYTE INCREMENTS";
|
||
}
|
||
keyToUse = hex2binb(key);
|
||
keyBinLen = key.length * 4;
|
||
} else if ("ASCII" === inputFormat) {
|
||
keyToUse = str2binb(key);
|
||
keyBinLen = key.length * charSize;
|
||
} else {
|
||
return "UNKNOWN KEY INPUT TYPE";
|
||
}
|
||
|
||
/* These are used multiple times, calculate and store them */
|
||
blockBitSize = blockByteSize * 8;
|
||
lastArrayIndex = (blockByteSize / 4) - 1;
|
||
|
||
/* Figure out what to do with the key based on its size relative to
|
||
* the hash's block size */
|
||
if (blockByteSize < (keyBinLen / 8)) {
|
||
if ("SHA-1" === variant) {
|
||
keyToUse = coreSHA1(keyToUse, keyBinLen);
|
||
} else {
|
||
keyToUse = coreSHA2(keyToUse, keyBinLen, variant);
|
||
}
|
||
/* For all variants, the block size is bigger than the output
|
||
* size so there will never be a useful byte at the end of the
|
||
* string */
|
||
keyToUse[lastArrayIndex] &= 0xFFFFFF00;
|
||
} else if (blockByteSize > (keyBinLen / 8)) {
|
||
/* If the blockByteSize is greater than the key length, there
|
||
* will always be at LEAST one "useless" byte at the end of the
|
||
* string */
|
||
keyToUse[lastArrayIndex] &= 0xFFFFFF00;
|
||
}
|
||
|
||
/* Create ipad and opad */
|
||
for (i = 0; i <= lastArrayIndex; i += 1) {
|
||
keyWithIPad[i] = keyToUse[i] ^ 0x36363636;
|
||
keyWithOPad[i] = keyToUse[i] ^ 0x5C5C5C5C;
|
||
}
|
||
|
||
/* Calculate the HMAC */
|
||
if ("SHA-1" === variant) {
|
||
retVal = coreSHA1(
|
||
keyWithIPad.concat(this.strToHash),
|
||
blockBitSize + this.strBinLen);
|
||
retVal = coreSHA1(
|
||
keyWithOPad.concat(retVal),
|
||
blockBitSize + hashBitSize);
|
||
} else {
|
||
retVal = coreSHA2(
|
||
keyWithIPad.concat(this.strToHash),
|
||
blockBitSize + this.strBinLen, variant);
|
||
retVal = coreSHA2(
|
||
keyWithOPad.concat(retVal),
|
||
blockBitSize + hashBitSize, variant);
|
||
}
|
||
|
||
return (formatFunc(retVal));
|
||
}
|
||
};
|
||
|
||
return jsSHA;
|
||
}());
|
||
|
||
module.exports = {
|
||
sha1: function(str) {
|
||
var shaObj = new jsSHA(str, "ASCII");
|
||
return shaObj.getHash("SHA-1", "ASCII");
|
||
},
|
||
sha224: function(str) {
|
||
var shaObj = new jsSHA(str, "ASCII");
|
||
return shaObj.getHash("SHA-224", "ASCII");
|
||
},
|
||
sha256: function(str) {
|
||
var shaObj = new jsSHA(str, "ASCII");
|
||
return shaObj.getHash("SHA-256", "ASCII");
|
||
},
|
||
sha384: function(str) {
|
||
var shaObj = new jsSHA(str, "ASCII");
|
||
return shaObj.getHash("SHA-384", "ASCII");
|
||
|
||
},
|
||
sha512: function(str) {
|
||
var shaObj = new jsSHA(str, "ASCII");
|
||
return shaObj.getHash("SHA-512", "ASCII");
|
||
}
|
||
}
|
||
|
||
},{}],16:[function(require,module,exports){
|
||
module.exports = {
|
||
cipher: require('./cipher'),
|
||
hash: require('./hash'),
|
||
cfb: require('./cfb.js'),
|
||
publicKey: require('./public_key'),
|
||
signature: require('./signature.js'),
|
||
random: require('./random.js'),
|
||
pkcs1: require('./pkcs1.js')
|
||
|
||
}
|
||
|
||
var crypto = require('./crypto.js');
|
||
|
||
for (var i in crypto)
|
||
module.exports[i] = crypto[i];
|
||
|
||
},{"./cfb.js":4,"./cipher":9,"./crypto.js":11,"./hash":12,"./pkcs1.js":17,"./public_key":20,"./random.js":23,"./signature.js":24}],17:[function(require,module,exports){
|
||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||
// Copyright (C) 2011 Recurity Labs GmbH
|
||
//
|
||
// This library is free software; you can redistribute it and/or
|
||
// modify it under the terms of the GNU Lesser General Public
|
||
// License as published by the Free Software Foundation; either
|
||
// version 2.1 of the License, or (at your option) any later version.
|
||
//
|
||
// This library is distributed in the hope that it will be useful,
|
||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
// Lesser General Public License for more details.
|
||
//
|
||
// You should have received a copy of the GNU Lesser General Public
|
||
// License along with this library; if not, write to the Free Software
|
||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||
|
||
/**
|
||
* ASN1 object identifiers for hashes (See RFC4880 5.2.2)
|
||
*/
|
||
hash_headers = new Array();
|
||
hash_headers[1] = [0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04,
|
||
0x10
|
||
];
|
||
hash_headers[3] = [0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x24, 0x03, 0x02, 0x01, 0x05, 0x00, 0x04, 0x14];
|
||
hash_headers[2] = [0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14];
|
||
hash_headers[8] = [0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00,
|
||
0x04, 0x20
|
||
];
|
||
hash_headers[9] = [0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00,
|
||
0x04, 0x30
|
||
];
|
||
hash_headers[10] = [0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
|
||
0x00, 0x04, 0x40
|
||
];
|
||
hash_headers[11] = [0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05,
|
||
0x00, 0x04, 0x1C
|
||
];
|
||
|
||
|
||
var crypto = require('./crypto.js'),
|
||
random = require('./random.js'),
|
||
util = require('../util'),
|
||
BigInteger = require('./public_key/jsbn.js'),
|
||
hash = require('./hash');
|
||
|
||
module.exports = {
|
||
eme: {
|
||
/**
|
||
* create a EME-PKCS1-v1_5 padding (See RFC4880 13.1.1)
|
||
* @param {String} message message to be padded
|
||
* @param {Integer} length Length to the resulting message
|
||
* @return {String} EME-PKCS1 padded message
|
||
*/
|
||
encode: function(message, length) {
|
||
if (message.length > length - 11)
|
||
return -1;
|
||
var result = "";
|
||
result += String.fromCharCode(0);
|
||
result += String.fromCharCode(2);
|
||
for (var i = 0; i < length - message.length - 3; i++) {
|
||
result += String.fromCharCode(random.getPseudoRandom(1, 255));
|
||
}
|
||
result += String.fromCharCode(0);
|
||
result += message;
|
||
return result;
|
||
},
|
||
|
||
/**
|
||
* decodes a EME-PKCS1-v1_5 padding (See RFC4880 13.1.2)
|
||
* @param {String} message EME-PKCS1 padded message
|
||
* @return {String} decoded message
|
||
*/
|
||
decode: function(message, len) {
|
||
if (message.length < len)
|
||
message = String.fromCharCode(0) + message;
|
||
if (message.length < 12 || message.charCodeAt(0) != 0 || message.charCodeAt(1) != 2)
|
||
return -1;
|
||
var i = 2;
|
||
while (message.charCodeAt(i) != 0 && message.length > i)
|
||
i++;
|
||
return message.substring(i + 1, message.length);
|
||
},
|
||
},
|
||
|
||
emsa: {
|
||
|
||
/**
|
||
* create a EMSA-PKCS1-v1_5 padding (See RFC4880 13.1.3)
|
||
* @param {Integer} algo Hash algorithm type used
|
||
* @param {String} data Data to be hashed
|
||
* @param {Integer} keylength Key size of the public mpi in bytes
|
||
* @returns {String} Hashcode with pkcs1padding as string
|
||
*/
|
||
encode: function(algo, data, keylength) {
|
||
var data2 = "";
|
||
data2 += String.fromCharCode(0x00);
|
||
data2 += String.fromCharCode(0x01);
|
||
for (var i = 0; i < (keylength - hash_headers[algo].length - 3 -
|
||
hash.getHashByteLength(algo)); i++)
|
||
|
||
data2 += String.fromCharCode(0xff);
|
||
|
||
data2 += String.fromCharCode(0x00);
|
||
|
||
for (var i = 0; i < hash_headers[algo].length; i++)
|
||
data2 += String.fromCharCode(hash_headers[algo][i]);
|
||
|
||
data2 += hash.digest(algo, data);
|
||
return new BigInteger(util.hexstrdump(data2), 16);
|
||
},
|
||
|
||
/**
|
||
* extract the hash out of an EMSA-PKCS1-v1.5 padding (See RFC4880 13.1.3)
|
||
* @param {String} data Hash in pkcs1 encoding
|
||
* @returns {String} The hash as string
|
||
*/
|
||
decode: function(algo, data) {
|
||
var i = 0;
|
||
if (data.charCodeAt(0) == 0) i++;
|
||
else if (data.charCodeAt(0) != 1) return -1;
|
||
else i++;
|
||
|
||
while (data.charCodeAt(i) == 0xFF) i++;
|
||
if (data.charCodeAt(i++) != 0) return -1;
|
||
var j = 0;
|
||
for (j = 0; j < hash_headers[algo].length && j + i < data.length; j++) {
|
||
if (data.charCodeAt(j + i) != hash_headers[algo][j]) return -1;
|
||
}
|
||
i += j;
|
||
if (data.substring(i).length < hash.getHashByteLength(algo)) return -1;
|
||
return data.substring(i);
|
||
}
|
||
}
|
||
}
|
||
|
||
},{"../util":56,"./crypto.js":11,"./hash":12,"./public_key/jsbn.js":21,"./random.js":23}],18:[function(require,module,exports){
|
||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||
// Copyright (C) 2011 Recurity Labs GmbH
|
||
//
|
||
// This library is free software; you can redistribute it and/or
|
||
// modify it under the terms of the GNU Lesser General Public
|
||
// License as published by the Free Software Foundation; either
|
||
// version 2.1 of the License, or (at your option) any later version.
|
||
//
|
||
// This library is distributed in the hope that it will be useful,
|
||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
// Lesser General Public License for more details.
|
||
//
|
||
// You should have received a copy of the GNU Lesser General Public
|
||
// License along with this library; if not, write to the Free Software
|
||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||
//
|
||
// A Digital signature algorithm implementation
|
||
|
||
var BigInteger = require('./jsbn.js'),
|
||
random = require('../random.js'),
|
||
hashModule = require('../hash'),
|
||
util = require('../../util');
|
||
|
||
function DSA() {
|
||
// s1 = ((g**s) mod p) mod q
|
||
// s1 = ((s**-1)*(sha-1(m)+(s1*x) mod q)
|
||
function sign(hashalgo, m, g, p, q, x) {
|
||
// If the output size of the chosen hash is larger than the number of
|
||
// bits of q, the hash result is truncated to fit by taking the number
|
||
// of leftmost bits equal to the number of bits of q. This (possibly
|
||
// truncated) hash function result is treated as a number and used
|
||
// directly in the DSA signature algorithm.
|
||
var hashed_data = util.getLeftNBits(hashModule.digest(hashalgo, m), q.bitLength());
|
||
var hash = new BigInteger(util.hexstrdump(hashed_data), 16);
|
||
var k = random.getRandomBigIntegerInRange(BigInteger.ONE.add(BigInteger.ONE), q.subtract(BigInteger.ONE));
|
||
var s1 = (g.modPow(k, p)).mod(q);
|
||
var s2 = (k.modInverse(q).multiply(hash.add(x.multiply(s1)))).mod(q);
|
||
var result = new Array();
|
||
result[0] = s1.toMPI();
|
||
result[1] = s2.toMPI();
|
||
return result;
|
||
}
|
||
|
||
function select_hash_algorithm(q) {
|
||
var usersetting = openpgp.config.config.prefer_hash_algorithm;
|
||
/*
|
||
* 1024-bit key, 160-bit q, SHA-1, SHA-224, SHA-256, SHA-384, or SHA-512 hash
|
||
* 2048-bit key, 224-bit q, SHA-224, SHA-256, SHA-384, or SHA-512 hash
|
||
* 2048-bit key, 256-bit q, SHA-256, SHA-384, or SHA-512 hash
|
||
* 3072-bit key, 256-bit q, SHA-256, SHA-384, or SHA-512 hash
|
||
*/
|
||
switch (Math.round(q.bitLength() / 8)) {
|
||
case 20:
|
||
// 1024 bit
|
||
if (usersetting != 2 &&
|
||
usersetting > 11 &&
|
||
usersetting != 10 &&
|
||
usersetting < 8)
|
||
return 2; // prefer sha1
|
||
return usersetting;
|
||
case 28:
|
||
// 2048 bit
|
||
if (usersetting > 11 &&
|
||
usersetting < 8)
|
||
return 11;
|
||
return usersetting;
|
||
case 32:
|
||
// 4096 bit // prefer sha224
|
||
if (usersetting > 10 &&
|
||
usersetting < 8)
|
||
return 8; // prefer sha256
|
||
return usersetting;
|
||
default:
|
||
util.print_debug("DSA select hash algorithm: returning null for an unknown length of q");
|
||
return null;
|
||
|
||
}
|
||
}
|
||
this.select_hash_algorithm = select_hash_algorithm;
|
||
|
||
function verify(hashalgo, s1, s2, m, p, q, g, y) {
|
||
var hashed_data = util.getLeftNBits(hashModule.digest(hashalgo, m), q.bitLength());
|
||
var hash = new BigInteger(util.hexstrdump(hashed_data), 16);
|
||
if (BigInteger.ZERO.compareTo(s1) > 0 ||
|
||
s1.compareTo(q) > 0 ||
|
||
BigInteger.ZERO.compareTo(s2) > 0 ||
|
||
s2.compareTo(q) > 0) {
|
||
util.print_error("invalid DSA Signature");
|
||
return null;
|
||
}
|
||
var w = s2.modInverse(q);
|
||
var u1 = hash.multiply(w).mod(q);
|
||
var u2 = s1.multiply(w).mod(q);
|
||
return g.modPow(u1, p).multiply(y.modPow(u2, p)).mod(p).mod(q);
|
||
}
|
||
|
||
/*
|
||
* unused code. This can be used as a start to write a key generator
|
||
* function.
|
||
|
||
function generateKey(bitcount) {
|
||
var qi = new BigInteger(bitcount, primeCenterie);
|
||
var pi = generateP(q, 512);
|
||
var gi = generateG(p, q, bitcount);
|
||
var xi;
|
||
do {
|
||
xi = new BigInteger(q.bitCount(), rand);
|
||
} while (x.compareTo(BigInteger.ZERO) != 1 && x.compareTo(q) != -1);
|
||
var yi = g.modPow(x, p);
|
||
return {x: xi, q: qi, p: pi, g: gi, y: yi};
|
||
}
|
||
|
||
function generateP(q, bitlength, randomfn) {
|
||
if (bitlength % 64 != 0) {
|
||
return false;
|
||
}
|
||
var pTemp;
|
||
var pTemp2;
|
||
do {
|
||
pTemp = randomfn(bitcount, true);
|
||
pTemp2 = pTemp.subtract(BigInteger.ONE);
|
||
pTemp = pTemp.subtract(pTemp2.remainder(q));
|
||
} while (!pTemp.isProbablePrime(primeCenterie) || pTemp.bitLength() != l);
|
||
return pTemp;
|
||
}
|
||
|
||
function generateG(p, q, bitlength, randomfn) {
|
||
var aux = p.subtract(BigInteger.ONE);
|
||
var pow = aux.divide(q);
|
||
var gTemp;
|
||
do {
|
||
gTemp = randomfn(bitlength);
|
||
} while (gTemp.compareTo(aux) != -1 && gTemp.compareTo(BigInteger.ONE) != 1);
|
||
return gTemp.modPow(pow, p);
|
||
}
|
||
|
||
function generateK(q, bitlength, randomfn) {
|
||
var tempK;
|
||
do {
|
||
tempK = randomfn(bitlength, false);
|
||
} while (tempK.compareTo(q) != -1 && tempK.compareTo(BigInteger.ZERO) != 1);
|
||
return tempK;
|
||
}
|
||
|
||
function generateR(q,p) {
|
||
k = generateK(q);
|
||
var r = g.modPow(k, p).mod(q);
|
||
return r;
|
||
}
|
||
|
||
function generateS(hashfn,k,r,m,q,x) {
|
||
var hash = hashfn(m);
|
||
s = (k.modInverse(q).multiply(hash.add(x.multiply(r)))).mod(q);
|
||
return s;
|
||
} */
|
||
this.sign = sign;
|
||
this.verify = verify;
|
||
// this.generate = generateKey;
|
||
}
|
||
|
||
module.exports = DSA;
|
||
|
||
},{"../../util":56,"../hash":12,"../random.js":23,"./jsbn.js":21}],19:[function(require,module,exports){
|
||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||
// Copyright (C) 2011 Recurity Labs GmbH
|
||
//
|
||
// This library is free software; you can redistribute it and/or
|
||
// modify it under the terms of the GNU Lesser General Public
|
||
// License as published by the Free Software Foundation; either
|
||
// version 2.1 of the License, or (at your option) any later version.
|
||
//
|
||
// This library is distributed in the hope that it will be useful,
|
||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
// Lesser General Public License for more details.
|
||
//
|
||
// You should have received a copy of the GNU Lesser General Public
|
||
// License along with this library; if not, write to the Free Software
|
||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||
//
|
||
// ElGamal implementation
|
||
|
||
var BigInteger = require('./jsbn.js'),
|
||
random = require('../random.js'),
|
||
util = require('../../util');
|
||
|
||
function Elgamal() {
|
||
|
||
function encrypt(m, g, p, y) {
|
||
// choose k in {2,...,p-2}
|
||
var two = BigInteger.ONE.add(BigInteger.ONE);
|
||
var pMinus2 = p.subtract(two);
|
||
var k = random.getRandomBigIntegerInRange(two, pMinus2);
|
||
k = k.mod(pMinus2).add(BigInteger.ONE);
|
||
var c = [];
|
||
c[0] = g.modPow(k, p);
|
||
c[1] = y.modPow(k, p).multiply(m).mod(p);
|
||
return c;
|
||
}
|
||
|
||
function decrypt(c1, c2, p, x) {
|
||
util.print_debug("Elgamal Decrypt:\nc1:" + util.hexstrdump(c1.toMPI()) + "\n" +
|
||
"c2:" + util.hexstrdump(c2.toMPI()) + "\n" +
|
||
"p:" + util.hexstrdump(p.toMPI()) + "\n" +
|
||
"x:" + util.hexstrdump(x.toMPI()));
|
||
return (c1.modPow(x, p).modInverse(p)).multiply(c2).mod(p);
|
||
//var c = c1.pow(x).modInverse(p); // c0^-a mod p
|
||
//return c.multiply(c2).mod(p);
|
||
}
|
||
|
||
// signing and signature verification using Elgamal is not required by OpenPGP.
|
||
this.encrypt = encrypt;
|
||
this.decrypt = decrypt;
|
||
}
|
||
|
||
module.exports = Elgamal;
|
||
|
||
},{"../../util":56,"../random.js":23,"./jsbn.js":21}],20:[function(require,module,exports){
|
||
module.exports = {
|
||
rsa: require('./rsa.js'),
|
||
elgamal: require('./elgamal.js'),
|
||
dsa: require('./dsa.js')
|
||
}
|
||
|
||
},{"./dsa.js":18,"./elgamal.js":19,"./rsa.js":22}],21:[function(require,module,exports){
|
||
/*
|
||
* Copyright (c) 2003-2005 Tom Wu (tjw@cs.Stanford.EDU)
|
||
* All Rights Reserved.
|
||
*
|
||
* Modified by Recurity Labs GmbH
|
||
*
|
||
* Permission is hereby granted, free of charge, to any person obtaining
|
||
* a copy of this software and associated documentation files (the
|
||
* "Software"), to deal in the Software without restriction, including
|
||
* without limitation the rights to use, copy, modify, merge, publish,
|
||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||
* permit persons to whom the Software is furnished to do so, subject to
|
||
* the following conditions:
|
||
*
|
||
* The above copyright notice and this permission notice shall be
|
||
* included in all copies or substantial portions of the Software.
|
||
*
|
||
* THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
|
||
* EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
|
||
* WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
||
*
|
||
* IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
|
||
* INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
|
||
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
|
||
* THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
|
||
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||
*
|
||
* In addition, the following condition applies:
|
||
*
|
||
* All redistributions must retain an intact copy of this copyright notice
|
||
* and disclaimer.
|
||
*/
|
||
|
||
|
||
var util = require('../../util');
|
||
|
||
// Basic JavaScript BN library - subset useful for RSA encryption.
|
||
|
||
// Bits per digit
|
||
var dbits;
|
||
|
||
// JavaScript engine analysis
|
||
var canary = 0xdeadbeefcafe;
|
||
var j_lm = ((canary & 0xffffff) == 0xefcafe);
|
||
|
||
// (public) Constructor
|
||
|
||
function BigInteger(a, b, c) {
|
||
if (a != null)
|
||
if ("number" == typeof a) this.fromNumber(a, b, c);
|
||
else if (b == null && "string" != typeof a) this.fromString(a, 256);
|
||
else this.fromString(a, b);
|
||
}
|
||
|
||
// return new, unset BigInteger
|
||
|
||
function nbi() {
|
||
return new BigInteger(null);
|
||
}
|
||
|
||
// am: Compute w_j += (x*this_i), propagate carries,
|
||
// c is initial carry, returns final carry.
|
||
// c < 3*dvalue, x < 2*dvalue, this_i < dvalue
|
||
// We need to select the fastest one that works in this environment.
|
||
|
||
// am1: use a single mult and divide to get the high bits,
|
||
// max digit bits should be 26 because
|
||
// max internal value = 2*dvalue^2-2*dvalue (< 2^53)
|
||
|
||
function am1(i, x, w, j, c, n) {
|
||
while (--n >= 0) {
|
||
var v = x * this[i++] + w[j] + c;
|
||
c = Math.floor(v / 0x4000000);
|
||
w[j++] = v & 0x3ffffff;
|
||
}
|
||
return c;
|
||
}
|
||
// am2 avoids a big mult-and-extract completely.
|
||
// Max digit bits should be <= 30 because we do bitwise ops
|
||
// on values up to 2*hdvalue^2-hdvalue-1 (< 2^31)
|
||
|
||
function am2(i, x, w, j, c, n) {
|
||
var xl = x & 0x7fff,
|
||
xh = x >> 15;
|
||
while (--n >= 0) {
|
||
var l = this[i] & 0x7fff;
|
||
var h = this[i++] >> 15;
|
||
var m = xh * l + h * xl;
|
||
l = xl * l + ((m & 0x7fff) << 15) + w[j] + (c & 0x3fffffff);
|
||
c = (l >>> 30) + (m >>> 15) + xh * h + (c >>> 30);
|
||
w[j++] = l & 0x3fffffff;
|
||
}
|
||
return c;
|
||
}
|
||
// Alternately, set max digit bits to 28 since some
|
||
// browsers slow down when dealing with 32-bit numbers.
|
||
|
||
function am3(i, x, w, j, c, n) {
|
||
var xl = x & 0x3fff,
|
||
xh = x >> 14;
|
||
while (--n >= 0) {
|
||
var l = this[i] & 0x3fff;
|
||
var h = this[i++] >> 14;
|
||
var m = xh * l + h * xl;
|
||
l = xl * l + ((m & 0x3fff) << 14) + w[j] + c;
|
||
c = (l >> 28) + (m >> 14) + xh * h;
|
||
w[j++] = l & 0xfffffff;
|
||
}
|
||
return c;
|
||
}
|
||
/*if(j_lm && (navigator != undefined &&
|
||
navigator.appName == "Microsoft Internet Explorer")) {
|
||
BigInteger.prototype.am = am2;
|
||
dbits = 30;
|
||
}
|
||
else if(j_lm && (navigator != undefined && navigator.appName != "Netscape")) {*/
|
||
BigInteger.prototype.am = am1;
|
||
dbits = 26;
|
||
/*}
|
||
else { // Mozilla/Netscape seems to prefer am3
|
||
BigInteger.prototype.am = am3;
|
||
dbits = 28;
|
||
}*/
|
||
|
||
BigInteger.prototype.DB = dbits;
|
||
BigInteger.prototype.DM = ((1 << dbits) - 1);
|
||
BigInteger.prototype.DV = (1 << dbits);
|
||
|
||
var BI_FP = 52;
|
||
BigInteger.prototype.FV = Math.pow(2, BI_FP);
|
||
BigInteger.prototype.F1 = BI_FP - dbits;
|
||
BigInteger.prototype.F2 = 2 * dbits - BI_FP;
|
||
|
||
// Digit conversions
|
||
var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz";
|
||
var BI_RC = new Array();
|
||
var rr, vv;
|
||
rr = "0".charCodeAt(0);
|
||
for (vv = 0; vv <= 9; ++vv) BI_RC[rr++] = vv;
|
||
rr = "a".charCodeAt(0);
|
||
for (vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
|
||
rr = "A".charCodeAt(0);
|
||
for (vv = 10; vv < 36; ++vv) BI_RC[rr++] = vv;
|
||
|
||
function int2char(n) {
|
||
return BI_RM.charAt(n);
|
||
}
|
||
|
||
function intAt(s, i) {
|
||
var c = BI_RC[s.charCodeAt(i)];
|
||
return (c == null) ? -1 : c;
|
||
}
|
||
|
||
// (protected) copy this to r
|
||
|
||
function bnpCopyTo(r) {
|
||
for (var i = this.t - 1; i >= 0; --i) r[i] = this[i];
|
||
r.t = this.t;
|
||
r.s = this.s;
|
||
}
|
||
|
||
// (protected) set from integer value x, -DV <= x < DV
|
||
|
||
function bnpFromInt(x) {
|
||
this.t = 1;
|
||
this.s = (x < 0) ? -1 : 0;
|
||
if (x > 0) this[0] = x;
|
||
else if (x < -1) this[0] = x + DV;
|
||
else this.t = 0;
|
||
}
|
||
|
||
// return bigint initialized to value
|
||
|
||
function nbv(i) {
|
||
var r = nbi();
|
||
r.fromInt(i);
|
||
return r;
|
||
}
|
||
|
||
// (protected) set from string and radix
|
||
|
||
function bnpFromString(s, b) {
|
||
var k;
|
||
if (b == 16) k = 4;
|
||
else if (b == 8) k = 3;
|
||
else if (b == 256) k = 8; // byte array
|
||
else if (b == 2) k = 1;
|
||
else if (b == 32) k = 5;
|
||
else if (b == 4) k = 2;
|
||
else {
|
||
this.fromRadix(s, b);
|
||
return;
|
||
}
|
||
this.t = 0;
|
||
this.s = 0;
|
||
var i = s.length,
|
||
mi = false,
|
||
sh = 0;
|
||
while (--i >= 0) {
|
||
var x = (k == 8) ? s[i] & 0xff : intAt(s, i);
|
||
if (x < 0) {
|
||
if (s.charAt(i) == "-") mi = true;
|
||
continue;
|
||
}
|
||
mi = false;
|
||
if (sh == 0)
|
||
this[this.t++] = x;
|
||
else if (sh + k > this.DB) {
|
||
this[this.t - 1] |= (x & ((1 << (this.DB - sh)) - 1)) << sh;
|
||
this[this.t++] = (x >> (this.DB - sh));
|
||
} else
|
||
this[this.t - 1] |= x << sh;
|
||
sh += k;
|
||
if (sh >= this.DB) sh -= this.DB;
|
||
}
|
||
if (k == 8 && (s[0] & 0x80) != 0) {
|
||
this.s = -1;
|
||
if (sh > 0) this[this.t - 1] |= ((1 << (this.DB - sh)) - 1) << sh;
|
||
}
|
||
this.clamp();
|
||
if (mi) BigInteger.ZERO.subTo(this, this);
|
||
}
|
||
|
||
// (protected) clamp off excess high words
|
||
|
||
function bnpClamp() {
|
||
var c = this.s & this.DM;
|
||
while (this.t > 0 && this[this.t - 1] == c)--this.t;
|
||
}
|
||
|
||
// (public) return string representation in given radix
|
||
|
||
function bnToString(b) {
|
||
if (this.s < 0) return "-" + this.negate().toString(b);
|
||
var k;
|
||
if (b == 16) k = 4;
|
||
else if (b == 8) k = 3;
|
||
else if (b == 2) k = 1;
|
||
else if (b == 32) k = 5;
|
||
else if (b == 4) k = 2;
|
||
else return this.toRadix(b);
|
||
var km = (1 << k) - 1,
|
||
d, m = false,
|
||
r = "",
|
||
i = this.t;
|
||
var p = this.DB - (i * this.DB) % k;
|
||
if (i-- > 0) {
|
||
if (p < this.DB && (d = this[i] >> p) > 0) {
|
||
m = true;
|
||
r = int2char(d);
|
||
}
|
||
while (i >= 0) {
|
||
if (p < k) {
|
||
d = (this[i] & ((1 << p) - 1)) << (k - p);
|
||
d |= this[--i] >> (p += this.DB - k);
|
||
} else {
|
||
d = (this[i] >> (p -= k)) & km;
|
||
if (p <= 0) {
|
||
p += this.DB;
|
||
--i;
|
||
}
|
||
}
|
||
if (d > 0) m = true;
|
||
if (m) r += int2char(d);
|
||
}
|
||
}
|
||
return m ? r : "0";
|
||
}
|
||
|
||
// (public) -this
|
||
|
||
function bnNegate() {
|
||
var r = nbi();
|
||
BigInteger.ZERO.subTo(this, r);
|
||
return r;
|
||
}
|
||
|
||
// (public) |this|
|
||
|
||
function bnAbs() {
|
||
return (this.s < 0) ? this.negate() : this;
|
||
}
|
||
|
||
// (public) return + if this > a, - if this < a, 0 if equal
|
||
|
||
function bnCompareTo(a) {
|
||
var r = this.s - a.s;
|
||
if (r != 0) return r;
|
||
var i = this.t;
|
||
r = i - a.t;
|
||
if (r != 0) return r;
|
||
while (--i >= 0) if ((r = this[i] - a[i]) != 0) return r;
|
||
return 0;
|
||
}
|
||
|
||
// returns bit length of the integer x
|
||
|
||
function nbits(x) {
|
||
var r = 1,
|
||
t;
|
||
if ((t = x >>> 16) != 0) {
|
||
x = t;
|
||
r += 16;
|
||
}
|
||
if ((t = x >> 8) != 0) {
|
||
x = t;
|
||
r += 8;
|
||
}
|
||
if ((t = x >> 4) != 0) {
|
||
x = t;
|
||
r += 4;
|
||
}
|
||
if ((t = x >> 2) != 0) {
|
||
x = t;
|
||
r += 2;
|
||
}
|
||
if ((t = x >> 1) != 0) {
|
||
x = t;
|
||
r += 1;
|
||
}
|
||
return r;
|
||
}
|
||
|
||
// (public) return the number of bits in "this"
|
||
|
||
function bnBitLength() {
|
||
if (this.t <= 0) return 0;
|
||
return this.DB * (this.t - 1) + nbits(this[this.t - 1] ^ (this.s & this.DM));
|
||
}
|
||
|
||
// (protected) r = this << n*DB
|
||
|
||
function bnpDLShiftTo(n, r) {
|
||
var i;
|
||
for (i = this.t - 1; i >= 0; --i) r[i + n] = this[i];
|
||
for (i = n - 1; i >= 0; --i) r[i] = 0;
|
||
r.t = this.t + n;
|
||
r.s = this.s;
|
||
}
|
||
|
||
// (protected) r = this >> n*DB
|
||
|
||
function bnpDRShiftTo(n, r) {
|
||
for (var i = n; i < this.t; ++i) r[i - n] = this[i];
|
||
r.t = Math.max(this.t - n, 0);
|
||
r.s = this.s;
|
||
}
|
||
|
||
// (protected) r = this << n
|
||
|
||
function bnpLShiftTo(n, r) {
|
||
var bs = n % this.DB;
|
||
var cbs = this.DB - bs;
|
||
var bm = (1 << cbs) - 1;
|
||
var ds = Math.floor(n / this.DB),
|
||
c = (this.s << bs) & this.DM,
|
||
i;
|
||
for (i = this.t - 1; i >= 0; --i) {
|
||
r[i + ds + 1] = (this[i] >> cbs) | c;
|
||
c = (this[i] & bm) << bs;
|
||
}
|
||
for (i = ds - 1; i >= 0; --i) r[i] = 0;
|
||
r[ds] = c;
|
||
r.t = this.t + ds + 1;
|
||
r.s = this.s;
|
||
r.clamp();
|
||
}
|
||
|
||
// (protected) r = this >> n
|
||
|
||
function bnpRShiftTo(n, r) {
|
||
r.s = this.s;
|
||
var ds = Math.floor(n / this.DB);
|
||
if (ds >= this.t) {
|
||
r.t = 0;
|
||
return;
|
||
}
|
||
var bs = n % this.DB;
|
||
var cbs = this.DB - bs;
|
||
var bm = (1 << bs) - 1;
|
||
r[0] = this[ds] >> bs;
|
||
for (var i = ds + 1; i < this.t; ++i) {
|
||
r[i - ds - 1] |= (this[i] & bm) << cbs;
|
||
r[i - ds] = this[i] >> bs;
|
||
}
|
||
if (bs > 0) r[this.t - ds - 1] |= (this.s & bm) << cbs;
|
||
r.t = this.t - ds;
|
||
r.clamp();
|
||
}
|
||
|
||
// (protected) r = this - a
|
||
|
||
function bnpSubTo(a, r) {
|
||
var i = 0,
|
||
c = 0,
|
||
m = Math.min(a.t, this.t);
|
||
while (i < m) {
|
||
c += this[i] - a[i];
|
||
r[i++] = c & this.DM;
|
||
c >>= this.DB;
|
||
}
|
||
if (a.t < this.t) {
|
||
c -= a.s;
|
||
while (i < this.t) {
|
||
c += this[i];
|
||
r[i++] = c & this.DM;
|
||
c >>= this.DB;
|
||
}
|
||
c += this.s;
|
||
} else {
|
||
c += this.s;
|
||
while (i < a.t) {
|
||
c -= a[i];
|
||
r[i++] = c & this.DM;
|
||
c >>= this.DB;
|
||
}
|
||
c -= a.s;
|
||
}
|
||
r.s = (c < 0) ? -1 : 0;
|
||
if (c < -1) r[i++] = this.DV + c;
|
||
else if (c > 0) r[i++] = c;
|
||
r.t = i;
|
||
r.clamp();
|
||
}
|
||
|
||
// (protected) r = this * a, r != this,a (HAC 14.12)
|
||
// "this" should be the larger one if appropriate.
|
||
|
||
function bnpMultiplyTo(a, r) {
|
||
var x = this.abs(),
|
||
y = a.abs();
|
||
var i = x.t;
|
||
r.t = i + y.t;
|
||
while (--i >= 0) r[i] = 0;
|
||
for (i = 0; i < y.t; ++i) r[i + x.t] = x.am(0, y[i], r, i, 0, x.t);
|
||
r.s = 0;
|
||
r.clamp();
|
||
if (this.s != a.s) BigInteger.ZERO.subTo(r, r);
|
||
}
|
||
|
||
// (protected) r = this^2, r != this (HAC 14.16)
|
||
|
||
function bnpSquareTo(r) {
|
||
var x = this.abs();
|
||
var i = r.t = 2 * x.t;
|
||
while (--i >= 0) r[i] = 0;
|
||
for (i = 0; i < x.t - 1; ++i) {
|
||
var c = x.am(i, x[i], r, 2 * i, 0, 1);
|
||
if ((r[i + x.t] += x.am(i + 1, 2 * x[i], r, 2 * i + 1, c, x.t - i - 1)) >= x.DV) {
|
||
r[i + x.t] -= x.DV;
|
||
r[i + x.t + 1] = 1;
|
||
}
|
||
}
|
||
if (r.t > 0) r[r.t - 1] += x.am(i, x[i], r, 2 * i, 0, 1);
|
||
r.s = 0;
|
||
r.clamp();
|
||
}
|
||
|
||
// (protected) divide this by m, quotient and remainder to q, r (HAC 14.20)
|
||
// r != q, this != m. q or r may be null.
|
||
|
||
function bnpDivRemTo(m, q, r) {
|
||
var pm = m.abs();
|
||
if (pm.t <= 0) return;
|
||
var pt = this.abs();
|
||
if (pt.t < pm.t) {
|
||
if (q != null) q.fromInt(0);
|
||
if (r != null) this.copyTo(r);
|
||
return;
|
||
}
|
||
if (r == null) r = nbi();
|
||
var y = nbi(),
|
||
ts = this.s,
|
||
ms = m.s;
|
||
var nsh = this.DB - nbits(pm[pm.t - 1]); // normalize modulus
|
||
if (nsh > 0) {
|
||
pm.lShiftTo(nsh, y);
|
||
pt.lShiftTo(nsh, r);
|
||
} else {
|
||
pm.copyTo(y);
|
||
pt.copyTo(r);
|
||
}
|
||
var ys = y.t;
|
||
var y0 = y[ys - 1];
|
||
if (y0 == 0) return;
|
||
var yt = y0 * (1 << this.F1) + ((ys > 1) ? y[ys - 2] >> this.F2 : 0);
|
||
var d1 = this.FV / yt,
|
||
d2 = (1 << this.F1) / yt,
|
||
e = 1 << this.F2;
|
||
var i = r.t,
|
||
j = i - ys,
|
||
t = (q == null) ? nbi() : q;
|
||
y.dlShiftTo(j, t);
|
||
if (r.compareTo(t) >= 0) {
|
||
r[r.t++] = 1;
|
||
r.subTo(t, r);
|
||
}
|
||
BigInteger.ONE.dlShiftTo(ys, t);
|
||
t.subTo(y, y); // "negative" y so we can replace sub with am later
|
||
while (y.t < ys) y[y.t++] = 0;
|
||
while (--j >= 0) {
|
||
// Estimate quotient digit
|
||
var qd = (r[--i] == y0) ? this.DM : Math.floor(r[i] * d1 + (r[i - 1] + e) * d2);
|
||
if ((r[i] += y.am(0, qd, r, j, 0, ys)) < qd) { // Try it out
|
||
y.dlShiftTo(j, t);
|
||
r.subTo(t, r);
|
||
while (r[i] < --qd) r.subTo(t, r);
|
||
}
|
||
}
|
||
if (q != null) {
|
||
r.drShiftTo(ys, q);
|
||
if (ts != ms) BigInteger.ZERO.subTo(q, q);
|
||
}
|
||
r.t = ys;
|
||
r.clamp();
|
||
if (nsh > 0) r.rShiftTo(nsh, r); // Denormalize remainder
|
||
if (ts < 0) BigInteger.ZERO.subTo(r, r);
|
||
}
|
||
|
||
// (public) this mod a
|
||
|
||
function bnMod(a) {
|
||
var r = nbi();
|
||
this.abs().divRemTo(a, null, r);
|
||
if (this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) a.subTo(r, r);
|
||
return r;
|
||
}
|
||
|
||
// Modular reduction using "classic" algorithm
|
||
|
||
function Classic(m) {
|
||
this.m = m;
|
||
}
|
||
|
||
function cConvert(x) {
|
||
if (x.s < 0 || x.compareTo(this.m) >= 0) return x.mod(this.m);
|
||
else return x;
|
||
}
|
||
|
||
function cRevert(x) {
|
||
return x;
|
||
}
|
||
|
||
function cReduce(x) {
|
||
x.divRemTo(this.m, null, x);
|
||
}
|
||
|
||
function cMulTo(x, y, r) {
|
||
x.multiplyTo(y, r);
|
||
this.reduce(r);
|
||
}
|
||
|
||
function cSqrTo(x, r) {
|
||
x.squareTo(r);
|
||
this.reduce(r);
|
||
}
|
||
|
||
Classic.prototype.convert = cConvert;
|
||
Classic.prototype.revert = cRevert;
|
||
Classic.prototype.reduce = cReduce;
|
||
Classic.prototype.mulTo = cMulTo;
|
||
Classic.prototype.sqrTo = cSqrTo;
|
||
|
||
// (protected) return "-1/this % 2^DB"; useful for Mont. reduction
|
||
// justification:
|
||
// xy == 1 (mod m)
|
||
// xy = 1+km
|
||
// xy(2-xy) = (1+km)(1-km)
|
||
// x[y(2-xy)] = 1-k^2m^2
|
||
// x[y(2-xy)] == 1 (mod m^2)
|
||
// if y is 1/x mod m, then y(2-xy) is 1/x mod m^2
|
||
// should reduce x and y(2-xy) by m^2 at each step to keep size bounded.
|
||
// JS multiply "overflows" differently from C/C++, so care is needed here.
|
||
|
||
function bnpInvDigit() {
|
||
if (this.t < 1) return 0;
|
||
var x = this[0];
|
||
if ((x & 1) == 0) return 0;
|
||
var y = x & 3; // y == 1/x mod 2^2
|
||
y = (y * (2 - (x & 0xf) * y)) & 0xf; // y == 1/x mod 2^4
|
||
y = (y * (2 - (x & 0xff) * y)) & 0xff; // y == 1/x mod 2^8
|
||
y = (y * (2 - (((x & 0xffff) * y) & 0xffff))) & 0xffff; // y == 1/x mod 2^16
|
||
// last step - calculate inverse mod DV directly;
|
||
// assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints
|
||
y = (y * (2 - x * y % this.DV)) % this.DV; // y == 1/x mod 2^dbits
|
||
// we really want the negative inverse, and -DV < y < DV
|
||
return (y > 0) ? this.DV - y : -y;
|
||
}
|
||
|
||
// Montgomery reduction
|
||
|
||
function Montgomery(m) {
|
||
this.m = m;
|
||
this.mp = m.invDigit();
|
||
this.mpl = this.mp & 0x7fff;
|
||
this.mph = this.mp >> 15;
|
||
this.um = (1 << (m.DB - 15)) - 1;
|
||
this.mt2 = 2 * m.t;
|
||
}
|
||
|
||
// xR mod m
|
||
|
||
function montConvert(x) {
|
||
var r = nbi();
|
||
x.abs().dlShiftTo(this.m.t, r);
|
||
r.divRemTo(this.m, null, r);
|
||
if (x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) this.m.subTo(r, r);
|
||
return r;
|
||
}
|
||
|
||
// x/R mod m
|
||
|
||
function montRevert(x) {
|
||
var r = nbi();
|
||
x.copyTo(r);
|
||
this.reduce(r);
|
||
return r;
|
||
}
|
||
|
||
// x = x/R mod m (HAC 14.32)
|
||
|
||
function montReduce(x) {
|
||
while (x.t <= this.mt2) // pad x so am has enough room later
|
||
x[x.t++] = 0;
|
||
for (var i = 0; i < this.m.t; ++i) {
|
||
// faster way of calculating u0 = x[i]*mp mod DV
|
||
var j = x[i] & 0x7fff;
|
||
var u0 = (j * this.mpl + (((j * this.mph + (x[i] >> 15) * this.mpl) & this.um) << 15)) & x.DM;
|
||
// use am to combine the multiply-shift-add into one call
|
||
j = i + this.m.t;
|
||
x[j] += this.m.am(0, u0, x, i, 0, this.m.t);
|
||
// propagate carry
|
||
while (x[j] >= x.DV) {
|
||
x[j] -= x.DV;
|
||
x[++j]++;
|
||
}
|
||
}
|
||
x.clamp();
|
||
x.drShiftTo(this.m.t, x);
|
||
if (x.compareTo(this.m) >= 0) x.subTo(this.m, x);
|
||
}
|
||
|
||
// r = "x^2/R mod m"; x != r
|
||
|
||
function montSqrTo(x, r) {
|
||
x.squareTo(r);
|
||
this.reduce(r);
|
||
}
|
||
|
||
// r = "xy/R mod m"; x,y != r
|
||
|
||
function montMulTo(x, y, r) {
|
||
x.multiplyTo(y, r);
|
||
this.reduce(r);
|
||
}
|
||
|
||
Montgomery.prototype.convert = montConvert;
|
||
Montgomery.prototype.revert = montRevert;
|
||
Montgomery.prototype.reduce = montReduce;
|
||
Montgomery.prototype.mulTo = montMulTo;
|
||
Montgomery.prototype.sqrTo = montSqrTo;
|
||
|
||
// (protected) true iff this is even
|
||
|
||
function bnpIsEven() {
|
||
return ((this.t > 0) ? (this[0] & 1) : this.s) == 0;
|
||
}
|
||
|
||
// (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79)
|
||
|
||
function bnpExp(e, z) {
|
||
if (e > 0xffffffff || e < 1) return BigInteger.ONE;
|
||
var r = nbi(),
|
||
r2 = nbi(),
|
||
g = z.convert(this),
|
||
i = nbits(e) - 1;
|
||
g.copyTo(r);
|
||
while (--i >= 0) {
|
||
z.sqrTo(r, r2);
|
||
if ((e & (1 << i)) > 0) z.mulTo(r2, g, r);
|
||
else {
|
||
var t = r;
|
||
r = r2;
|
||
r2 = t;
|
||
}
|
||
}
|
||
return z.revert(r);
|
||
}
|
||
|
||
// (public) this^e % m, 0 <= e < 2^32
|
||
|
||
function bnModPowInt(e, m) {
|
||
var z;
|
||
if (e < 256 || m.isEven()) z = new Classic(m);
|
||
else z = new Montgomery(m);
|
||
return this.exp(e, z);
|
||
}
|
||
|
||
// protected
|
||
BigInteger.prototype.copyTo = bnpCopyTo;
|
||
BigInteger.prototype.fromInt = bnpFromInt;
|
||
BigInteger.prototype.fromString = bnpFromString;
|
||
BigInteger.prototype.clamp = bnpClamp;
|
||
BigInteger.prototype.dlShiftTo = bnpDLShiftTo;
|
||
BigInteger.prototype.drShiftTo = bnpDRShiftTo;
|
||
BigInteger.prototype.lShiftTo = bnpLShiftTo;
|
||
BigInteger.prototype.rShiftTo = bnpRShiftTo;
|
||
BigInteger.prototype.subTo = bnpSubTo;
|
||
BigInteger.prototype.multiplyTo = bnpMultiplyTo;
|
||
BigInteger.prototype.squareTo = bnpSquareTo;
|
||
BigInteger.prototype.divRemTo = bnpDivRemTo;
|
||
BigInteger.prototype.invDigit = bnpInvDigit;
|
||
BigInteger.prototype.isEven = bnpIsEven;
|
||
BigInteger.prototype.exp = bnpExp;
|
||
|
||
// public
|
||
BigInteger.prototype.toString = bnToString;
|
||
BigInteger.prototype.negate = bnNegate;
|
||
BigInteger.prototype.abs = bnAbs;
|
||
BigInteger.prototype.compareTo = bnCompareTo;
|
||
BigInteger.prototype.bitLength = bnBitLength;
|
||
BigInteger.prototype.mod = bnMod;
|
||
BigInteger.prototype.modPowInt = bnModPowInt;
|
||
|
||
// "constants"
|
||
BigInteger.ZERO = nbv(0);
|
||
BigInteger.ONE = nbv(1);
|
||
|
||
module.exports = BigInteger;
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
/*
|
||
* Copyright (c) 2003-2005 Tom Wu (tjw@cs.Stanford.EDU)
|
||
* All Rights Reserved.
|
||
*
|
||
* Modified by Recurity Labs GmbH
|
||
*
|
||
* Permission is hereby granted, free of charge, to any person obtaining
|
||
* a copy of this software and associated documentation files (the
|
||
* "Software"), to deal in the Software without restriction, including
|
||
* without limitation the rights to use, copy, modify, merge, publish,
|
||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||
* permit persons to whom the Software is furnished to do so, subject to
|
||
* the following conditions:
|
||
*
|
||
* The above copyright notice and this permission notice shall be
|
||
* included in all copies or substantial portions of the Software.
|
||
*
|
||
* THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
|
||
* EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
|
||
* WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
||
*
|
||
* IN NO EVENT SHALL TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
|
||
* INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
|
||
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
|
||
* THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
|
||
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||
*
|
||
* In addition, the following condition applies:
|
||
*
|
||
* All redistributions must retain an intact copy of this copyright notice
|
||
* and disclaimer.
|
||
*/
|
||
|
||
|
||
// Extended JavaScript BN functions, required for RSA private ops.
|
||
|
||
// Version 1.1: new BigInteger("0", 10) returns "proper" zero
|
||
// Version 1.2: square() API, isProbablePrime fix
|
||
|
||
// (public)
|
||
function bnClone() {
|
||
var r = nbi();
|
||
this.copyTo(r);
|
||
return r;
|
||
}
|
||
|
||
// (public) return value as integer
|
||
|
||
function bnIntValue() {
|
||
if (this.s < 0) {
|
||
if (this.t == 1) return this[0] - this.DV;
|
||
else if (this.t == 0) return -1;
|
||
} else if (this.t == 1) return this[0];
|
||
else if (this.t == 0) return 0;
|
||
// assumes 16 < DB < 32
|
||
return ((this[1] & ((1 << (32 - this.DB)) - 1)) << this.DB) | this[0];
|
||
}
|
||
|
||
// (public) return value as byte
|
||
|
||
function bnByteValue() {
|
||
return (this.t == 0) ? this.s : (this[0] << 24) >> 24;
|
||
}
|
||
|
||
// (public) return value as short (assumes DB>=16)
|
||
|
||
function bnShortValue() {
|
||
return (this.t == 0) ? this.s : (this[0] << 16) >> 16;
|
||
}
|
||
|
||
// (protected) return x s.t. r^x < DV
|
||
|
||
function bnpChunkSize(r) {
|
||
return Math.floor(Math.LN2 * this.DB / Math.log(r));
|
||
}
|
||
|
||
// (public) 0 if this == 0, 1 if this > 0
|
||
|
||
function bnSigNum() {
|
||
if (this.s < 0) return -1;
|
||
else if (this.t <= 0 || (this.t == 1 && this[0] <= 0)) return 0;
|
||
else return 1;
|
||
}
|
||
|
||
// (protected) convert to radix string
|
||
|
||
function bnpToRadix(b) {
|
||
if (b == null) b = 10;
|
||
if (this.signum() == 0 || b < 2 || b > 36) return "0";
|
||
var cs = this.chunkSize(b);
|
||
var a = Math.pow(b, cs);
|
||
var d = nbv(a),
|
||
y = nbi(),
|
||
z = nbi(),
|
||
r = "";
|
||
this.divRemTo(d, y, z);
|
||
while (y.signum() > 0) {
|
||
r = (a + z.intValue()).toString(b).substr(1) + r;
|
||
y.divRemTo(d, y, z);
|
||
}
|
||
return z.intValue().toString(b) + r;
|
||
}
|
||
|
||
// (protected) convert from radix string
|
||
|
||
function bnpFromRadix(s, b) {
|
||
this.fromInt(0);
|
||
if (b == null) b = 10;
|
||
var cs = this.chunkSize(b);
|
||
var d = Math.pow(b, cs),
|
||
mi = false,
|
||
j = 0,
|
||
w = 0;
|
||
for (var i = 0; i < s.length; ++i) {
|
||
var x = intAt(s, i);
|
||
if (x < 0) {
|
||
if (s.charAt(i) == "-" && this.signum() == 0) mi = true;
|
||
continue;
|
||
}
|
||
w = b * w + x;
|
||
if (++j >= cs) {
|
||
this.dMultiply(d);
|
||
this.dAddOffset(w, 0);
|
||
j = 0;
|
||
w = 0;
|
||
}
|
||
}
|
||
if (j > 0) {
|
||
this.dMultiply(Math.pow(b, j));
|
||
this.dAddOffset(w, 0);
|
||
}
|
||
if (mi) BigInteger.ZERO.subTo(this, this);
|
||
}
|
||
|
||
// (protected) alternate constructor
|
||
|
||
function bnpFromNumber(a, b, c) {
|
||
if ("number" == typeof b) {
|
||
// new BigInteger(int,int,RNG)
|
||
if (a < 2) this.fromInt(1);
|
||
else {
|
||
this.fromNumber(a, c);
|
||
if (!this.testBit(a - 1)) // force MSB set
|
||
this.bitwiseTo(BigInteger.ONE.shiftLeft(a - 1), op_or, this);
|
||
if (this.isEven()) this.dAddOffset(1, 0); // force odd
|
||
while (!this.isProbablePrime(b)) {
|
||
this.dAddOffset(2, 0);
|
||
if (this.bitLength() > a) this.subTo(BigInteger.ONE.shiftLeft(a - 1), this);
|
||
}
|
||
}
|
||
} else {
|
||
// new BigInteger(int,RNG)
|
||
var x = new Array(),
|
||
t = a & 7;
|
||
x.length = (a >> 3) + 1;
|
||
b.nextBytes(x);
|
||
if (t > 0) x[0] &= ((1 << t) - 1);
|
||
else x[0] = 0;
|
||
this.fromString(x, 256);
|
||
}
|
||
}
|
||
|
||
// (public) convert to bigendian byte array
|
||
|
||
function bnToByteArray() {
|
||
var i = this.t,
|
||
r = new Array();
|
||
r[0] = this.s;
|
||
var p = this.DB - (i * this.DB) % 8,
|
||
d, k = 0;
|
||
if (i-- > 0) {
|
||
if (p < this.DB && (d = this[i] >> p) != (this.s & this.DM) >> p)
|
||
r[k++] = d | (this.s << (this.DB - p));
|
||
while (i >= 0) {
|
||
if (p < 8) {
|
||
d = (this[i] & ((1 << p) - 1)) << (8 - p);
|
||
d |= this[--i] >> (p += this.DB - 8);
|
||
} else {
|
||
d = (this[i] >> (p -= 8)) & 0xff;
|
||
if (p <= 0) {
|
||
p += this.DB;
|
||
--i;
|
||
}
|
||
}
|
||
//if((d&0x80) != 0) d |= -256;
|
||
//if(k == 0 && (this.s&0x80) != (d&0x80)) ++k;
|
||
if (k > 0 || d != this.s) r[k++] = d;
|
||
}
|
||
}
|
||
return r;
|
||
}
|
||
|
||
function bnEquals(a) {
|
||
return (this.compareTo(a) == 0);
|
||
}
|
||
|
||
function bnMin(a) {
|
||
return (this.compareTo(a) < 0) ? this : a;
|
||
}
|
||
|
||
function bnMax(a) {
|
||
return (this.compareTo(a) > 0) ? this : a;
|
||
}
|
||
|
||
// (protected) r = this op a (bitwise)
|
||
|
||
function bnpBitwiseTo(a, op, r) {
|
||
var i, f, m = Math.min(a.t, this.t);
|
||
for (i = 0; i < m; ++i) r[i] = op(this[i], a[i]);
|
||
if (a.t < this.t) {
|
||
f = a.s & this.DM;
|
||
for (i = m; i < this.t; ++i) r[i] = op(this[i], f);
|
||
r.t = this.t;
|
||
} else {
|
||
f = this.s & this.DM;
|
||
for (i = m; i < a.t; ++i) r[i] = op(f, a[i]);
|
||
r.t = a.t;
|
||
}
|
||
r.s = op(this.s, a.s);
|
||
r.clamp();
|
||
}
|
||
|
||
// (public) this & a
|
||
|
||
function op_and(x, y) {
|
||
return x & y;
|
||
}
|
||
|
||
function bnAnd(a) {
|
||
var r = nbi();
|
||
this.bitwiseTo(a, op_and, r);
|
||
return r;
|
||
}
|
||
|
||
// (public) this | a
|
||
|
||
function op_or(x, y) {
|
||
return x | y;
|
||
}
|
||
|
||
function bnOr(a) {
|
||
var r = nbi();
|
||
this.bitwiseTo(a, op_or, r);
|
||
return r;
|
||
}
|
||
|
||
// (public) this ^ a
|
||
|
||
function op_xor(x, y) {
|
||
return x ^ y;
|
||
}
|
||
|
||
function bnXor(a) {
|
||
var r = nbi();
|
||
this.bitwiseTo(a, op_xor, r);
|
||
return r;
|
||
}
|
||
|
||
// (public) this & ~a
|
||
|
||
function op_andnot(x, y) {
|
||
return x & ~y;
|
||
}
|
||
|
||
function bnAndNot(a) {
|
||
var r = nbi();
|
||
this.bitwiseTo(a, op_andnot, r);
|
||
return r;
|
||
}
|
||
|
||
// (public) ~this
|
||
|
||
function bnNot() {
|
||
var r = nbi();
|
||
for (var i = 0; i < this.t; ++i) r[i] = this.DM & ~this[i];
|
||
r.t = this.t;
|
||
r.s = ~this.s;
|
||
return r;
|
||
}
|
||
|
||
// (public) this << n
|
||
|
||
function bnShiftLeft(n) {
|
||
var r = nbi();
|
||
if (n < 0) this.rShiftTo(-n, r);
|
||
else this.lShiftTo(n, r);
|
||
return r;
|
||
}
|
||
|
||
// (public) this >> n
|
||
|
||
function bnShiftRight(n) {
|
||
var r = nbi();
|
||
if (n < 0) this.lShiftTo(-n, r);
|
||
else this.rShiftTo(n, r);
|
||
return r;
|
||
}
|
||
|
||
// return index of lowest 1-bit in x, x < 2^31
|
||
|
||
function lbit(x) {
|
||
if (x == 0) return -1;
|
||
var r = 0;
|
||
if ((x & 0xffff) == 0) {
|
||
x >>= 16;
|
||
r += 16;
|
||
}
|
||
if ((x & 0xff) == 0) {
|
||
x >>= 8;
|
||
r += 8;
|
||
}
|
||
if ((x & 0xf) == 0) {
|
||
x >>= 4;
|
||
r += 4;
|
||
}
|
||
if ((x & 3) == 0) {
|
||
x >>= 2;
|
||
r += 2;
|
||
}
|
||
if ((x & 1) == 0)++r;
|
||
return r;
|
||
}
|
||
|
||
// (public) returns index of lowest 1-bit (or -1 if none)
|
||
|
||
function bnGetLowestSetBit() {
|
||
for (var i = 0; i < this.t; ++i)
|
||
if (this[i] != 0) return i * this.DB + lbit(this[i]);
|
||
if (this.s < 0) return this.t * this.DB;
|
||
return -1;
|
||
}
|
||
|
||
// return number of 1 bits in x
|
||
|
||
function cbit(x) {
|
||
var r = 0;
|
||
while (x != 0) {
|
||
x &= x - 1;
|
||
++r;
|
||
}
|
||
return r;
|
||
}
|
||
|
||
// (public) return number of set bits
|
||
|
||
function bnBitCount() {
|
||
var r = 0,
|
||
x = this.s & this.DM;
|
||
for (var i = 0; i < this.t; ++i) r += cbit(this[i] ^ x);
|
||
return r;
|
||
}
|
||
|
||
// (public) true iff nth bit is set
|
||
|
||
function bnTestBit(n) {
|
||
var j = Math.floor(n / this.DB);
|
||
if (j >= this.t) return (this.s != 0);
|
||
return ((this[j] & (1 << (n % this.DB))) != 0);
|
||
}
|
||
|
||
// (protected) this op (1<<n)
|
||
|
||
function bnpChangeBit(n, op) {
|
||
var r = BigInteger.ONE.shiftLeft(n);
|
||
this.bitwiseTo(r, op, r);
|
||
return r;
|
||
}
|
||
|
||
// (public) this | (1<<n)
|
||
|
||
function bnSetBit(n) {
|
||
return this.changeBit(n, op_or);
|
||
}
|
||
|
||
// (public) this & ~(1<<n)
|
||
|
||
function bnClearBit(n) {
|
||
return this.changeBit(n, op_andnot);
|
||
}
|
||
|
||
// (public) this ^ (1<<n)
|
||
|
||
function bnFlipBit(n) {
|
||
return this.changeBit(n, op_xor);
|
||
}
|
||
|
||
// (protected) r = this + a
|
||
|
||
function bnpAddTo(a, r) {
|
||
var i = 0,
|
||
c = 0,
|
||
m = Math.min(a.t, this.t);
|
||
while (i < m) {
|
||
c += this[i] + a[i];
|
||
r[i++] = c & this.DM;
|
||
c >>= this.DB;
|
||
}
|
||
if (a.t < this.t) {
|
||
c += a.s;
|
||
while (i < this.t) {
|
||
c += this[i];
|
||
r[i++] = c & this.DM;
|
||
c >>= this.DB;
|
||
}
|
||
c += this.s;
|
||
} else {
|
||
c += this.s;
|
||
while (i < a.t) {
|
||
c += a[i];
|
||
r[i++] = c & this.DM;
|
||
c >>= this.DB;
|
||
}
|
||
c += a.s;
|
||
}
|
||
r.s = (c < 0) ? -1 : 0;
|
||
if (c > 0) r[i++] = c;
|
||
else if (c < -1) r[i++] = this.DV + c;
|
||
r.t = i;
|
||
r.clamp();
|
||
}
|
||
|
||
// (public) this + a
|
||
|
||
function bnAdd(a) {
|
||
var r = nbi();
|
||
this.addTo(a, r);
|
||
return r;
|
||
}
|
||
|
||
// (public) this - a
|
||
|
||
function bnSubtract(a) {
|
||
var r = nbi();
|
||
this.subTo(a, r);
|
||
return r;
|
||
}
|
||
|
||
// (public) this * a
|
||
|
||
function bnMultiply(a) {
|
||
var r = nbi();
|
||
this.multiplyTo(a, r);
|
||
return r;
|
||
}
|
||
|
||
// (public) this^2
|
||
|
||
function bnSquare() {
|
||
var r = nbi();
|
||
this.squareTo(r);
|
||
return r;
|
||
}
|
||
|
||
// (public) this / a
|
||
|
||
function bnDivide(a) {
|
||
var r = nbi();
|
||
this.divRemTo(a, r, null);
|
||
return r;
|
||
}
|
||
|
||
// (public) this % a
|
||
|
||
function bnRemainder(a) {
|
||
var r = nbi();
|
||
this.divRemTo(a, null, r);
|
||
return r;
|
||
}
|
||
|
||
// (public) [this/a,this%a]
|
||
|
||
function bnDivideAndRemainder(a) {
|
||
var q = nbi(),
|
||
r = nbi();
|
||
this.divRemTo(a, q, r);
|
||
return new Array(q, r);
|
||
}
|
||
|
||
// (protected) this *= n, this >= 0, 1 < n < DV
|
||
|
||
function bnpDMultiply(n) {
|
||
this[this.t] = this.am(0, n - 1, this, 0, 0, this.t);
|
||
++this.t;
|
||
this.clamp();
|
||
}
|
||
|
||
// (protected) this += n << w words, this >= 0
|
||
|
||
function bnpDAddOffset(n, w) {
|
||
if (n == 0) return;
|
||
while (this.t <= w) this[this.t++] = 0;
|
||
this[w] += n;
|
||
while (this[w] >= this.DV) {
|
||
this[w] -= this.DV;
|
||
if (++w >= this.t) this[this.t++] = 0;
|
||
++this[w];
|
||
}
|
||
}
|
||
|
||
// A "null" reducer
|
||
|
||
function NullExp() {}
|
||
|
||
function nNop(x) {
|
||
return x;
|
||
}
|
||
|
||
function nMulTo(x, y, r) {
|
||
x.multiplyTo(y, r);
|
||
}
|
||
|
||
function nSqrTo(x, r) {
|
||
x.squareTo(r);
|
||
}
|
||
|
||
NullExp.prototype.convert = nNop;
|
||
NullExp.prototype.revert = nNop;
|
||
NullExp.prototype.mulTo = nMulTo;
|
||
NullExp.prototype.sqrTo = nSqrTo;
|
||
|
||
// (public) this^e
|
||
|
||
function bnPow(e) {
|
||
return this.exp(e, new NullExp());
|
||
}
|
||
|
||
// (protected) r = lower n words of "this * a", a.t <= n
|
||
// "this" should be the larger one if appropriate.
|
||
|
||
function bnpMultiplyLowerTo(a, n, r) {
|
||
var i = Math.min(this.t + a.t, n);
|
||
r.s = 0; // assumes a,this >= 0
|
||
r.t = i;
|
||
while (i > 0) r[--i] = 0;
|
||
var j;
|
||
for (j = r.t - this.t; i < j; ++i) r[i + this.t] = this.am(0, a[i], r, i, 0, this.t);
|
||
for (j = Math.min(a.t, n); i < j; ++i) this.am(0, a[i], r, i, 0, n - i);
|
||
r.clamp();
|
||
}
|
||
|
||
// (protected) r = "this * a" without lower n words, n > 0
|
||
// "this" should be the larger one if appropriate.
|
||
|
||
function bnpMultiplyUpperTo(a, n, r) {
|
||
--n;
|
||
var i = r.t = this.t + a.t - n;
|
||
r.s = 0; // assumes a,this >= 0
|
||
while (--i >= 0) r[i] = 0;
|
||
for (i = Math.max(n - this.t, 0); i < a.t; ++i)
|
||
r[this.t + i - n] = this.am(n - i, a[i], r, 0, 0, this.t + i - n);
|
||
r.clamp();
|
||
r.drShiftTo(1, r);
|
||
}
|
||
|
||
// Barrett modular reduction
|
||
|
||
function Barrett(m) {
|
||
// setup Barrett
|
||
this.r2 = nbi();
|
||
this.q3 = nbi();
|
||
BigInteger.ONE.dlShiftTo(2 * m.t, this.r2);
|
||
this.mu = this.r2.divide(m);
|
||
this.m = m;
|
||
}
|
||
|
||
function barrettConvert(x) {
|
||
if (x.s < 0 || x.t > 2 * this.m.t) return x.mod(this.m);
|
||
else if (x.compareTo(this.m) < 0) return x;
|
||
else {
|
||
var r = nbi();
|
||
x.copyTo(r);
|
||
this.reduce(r);
|
||
return r;
|
||
}
|
||
}
|
||
|
||
function barrettRevert(x) {
|
||
return x;
|
||
}
|
||
|
||
// x = x mod m (HAC 14.42)
|
||
|
||
function barrettReduce(x) {
|
||
x.drShiftTo(this.m.t - 1, this.r2);
|
||
if (x.t > this.m.t + 1) {
|
||
x.t = this.m.t + 1;
|
||
x.clamp();
|
||
}
|
||
this.mu.multiplyUpperTo(this.r2, this.m.t + 1, this.q3);
|
||
this.m.multiplyLowerTo(this.q3, this.m.t + 1, this.r2);
|
||
while (x.compareTo(this.r2) < 0) x.dAddOffset(1, this.m.t + 1);
|
||
x.subTo(this.r2, x);
|
||
while (x.compareTo(this.m) >= 0) x.subTo(this.m, x);
|
||
}
|
||
|
||
// r = x^2 mod m; x != r
|
||
|
||
function barrettSqrTo(x, r) {
|
||
x.squareTo(r);
|
||
this.reduce(r);
|
||
}
|
||
|
||
// r = x*y mod m; x,y != r
|
||
|
||
function barrettMulTo(x, y, r) {
|
||
x.multiplyTo(y, r);
|
||
this.reduce(r);
|
||
}
|
||
|
||
Barrett.prototype.convert = barrettConvert;
|
||
Barrett.prototype.revert = barrettRevert;
|
||
Barrett.prototype.reduce = barrettReduce;
|
||
Barrett.prototype.mulTo = barrettMulTo;
|
||
Barrett.prototype.sqrTo = barrettSqrTo;
|
||
|
||
// (public) this^e % m (HAC 14.85)
|
||
|
||
function bnModPow(e, m) {
|
||
var i = e.bitLength(),
|
||
k, r = nbv(1),
|
||
z;
|
||
if (i <= 0) return r;
|
||
else if (i < 18) k = 1;
|
||
else if (i < 48) k = 3;
|
||
else if (i < 144) k = 4;
|
||
else if (i < 768) k = 5;
|
||
else k = 6;
|
||
if (i < 8)
|
||
z = new Classic(m);
|
||
else if (m.isEven())
|
||
z = new Barrett(m);
|
||
else
|
||
z = new Montgomery(m);
|
||
|
||
// precomputation
|
||
var g = new Array(),
|
||
n = 3,
|
||
k1 = k - 1,
|
||
km = (1 << k) - 1;
|
||
g[1] = z.convert(this);
|
||
if (k > 1) {
|
||
var g2 = nbi();
|
||
z.sqrTo(g[1], g2);
|
||
while (n <= km) {
|
||
g[n] = nbi();
|
||
z.mulTo(g2, g[n - 2], g[n]);
|
||
n += 2;
|
||
}
|
||
}
|
||
|
||
var j = e.t - 1,
|
||
w, is1 = true,
|
||
r2 = nbi(),
|
||
t;
|
||
i = nbits(e[j]) - 1;
|
||
while (j >= 0) {
|
||
if (i >= k1) w = (e[j] >> (i - k1)) & km;
|
||
else {
|
||
w = (e[j] & ((1 << (i + 1)) - 1)) << (k1 - i);
|
||
if (j > 0) w |= e[j - 1] >> (this.DB + i - k1);
|
||
}
|
||
|
||
n = k;
|
||
while ((w & 1) == 0) {
|
||
w >>= 1;
|
||
--n;
|
||
}
|
||
if ((i -= n) < 0) {
|
||
i += this.DB;
|
||
--j;
|
||
}
|
||
if (is1) { // ret == 1, don't bother squaring or multiplying it
|
||
g[w].copyTo(r);
|
||
is1 = false;
|
||
} else {
|
||
while (n > 1) {
|
||
z.sqrTo(r, r2);
|
||
z.sqrTo(r2, r);
|
||
n -= 2;
|
||
}
|
||
if (n > 0) z.sqrTo(r, r2);
|
||
else {
|
||
t = r;
|
||
r = r2;
|
||
r2 = t;
|
||
}
|
||
z.mulTo(r2, g[w], r);
|
||
}
|
||
|
||
while (j >= 0 && (e[j] & (1 << i)) == 0) {
|
||
z.sqrTo(r, r2);
|
||
t = r;
|
||
r = r2;
|
||
r2 = t;
|
||
if (--i < 0) {
|
||
i = this.DB - 1;
|
||
--j;
|
||
}
|
||
}
|
||
}
|
||
return z.revert(r);
|
||
}
|
||
|
||
// (public) gcd(this,a) (HAC 14.54)
|
||
|
||
function bnGCD(a) {
|
||
var x = (this.s < 0) ? this.negate() : this.clone();
|
||
var y = (a.s < 0) ? a.negate() : a.clone();
|
||
if (x.compareTo(y) < 0) {
|
||
var t = x;
|
||
x = y;
|
||
y = t;
|
||
}
|
||
var i = x.getLowestSetBit(),
|
||
g = y.getLowestSetBit();
|
||
if (g < 0) return x;
|
||
if (i < g) g = i;
|
||
if (g > 0) {
|
||
x.rShiftTo(g, x);
|
||
y.rShiftTo(g, y);
|
||
}
|
||
while (x.signum() > 0) {
|
||
if ((i = x.getLowestSetBit()) > 0) x.rShiftTo(i, x);
|
||
if ((i = y.getLowestSetBit()) > 0) y.rShiftTo(i, y);
|
||
if (x.compareTo(y) >= 0) {
|
||
x.subTo(y, x);
|
||
x.rShiftTo(1, x);
|
||
} else {
|
||
y.subTo(x, y);
|
||
y.rShiftTo(1, y);
|
||
}
|
||
}
|
||
if (g > 0) y.lShiftTo(g, y);
|
||
return y;
|
||
}
|
||
|
||
// (protected) this % n, n < 2^26
|
||
|
||
function bnpModInt(n) {
|
||
if (n <= 0) return 0;
|
||
var d = this.DV % n,
|
||
r = (this.s < 0) ? n - 1 : 0;
|
||
if (this.t > 0)
|
||
if (d == 0) r = this[0] % n;
|
||
else for (var i = this.t - 1; i >= 0; --i) r = (d * r + this[i]) % n;
|
||
return r;
|
||
}
|
||
|
||
// (public) 1/this % m (HAC 14.61)
|
||
|
||
function bnModInverse(m) {
|
||
var ac = m.isEven();
|
||
if ((this.isEven() && ac) || m.signum() == 0) return BigInteger.ZERO;
|
||
var u = m.clone(),
|
||
v = this.clone();
|
||
var a = nbv(1),
|
||
b = nbv(0),
|
||
c = nbv(0),
|
||
d = nbv(1);
|
||
while (u.signum() != 0) {
|
||
while (u.isEven()) {
|
||
u.rShiftTo(1, u);
|
||
if (ac) {
|
||
if (!a.isEven() || !b.isEven()) {
|
||
a.addTo(this, a);
|
||
b.subTo(m, b);
|
||
}
|
||
a.rShiftTo(1, a);
|
||
} else if (!b.isEven()) b.subTo(m, b);
|
||
b.rShiftTo(1, b);
|
||
}
|
||
while (v.isEven()) {
|
||
v.rShiftTo(1, v);
|
||
if (ac) {
|
||
if (!c.isEven() || !d.isEven()) {
|
||
c.addTo(this, c);
|
||
d.subTo(m, d);
|
||
}
|
||
c.rShiftTo(1, c);
|
||
} else if (!d.isEven()) d.subTo(m, d);
|
||
d.rShiftTo(1, d);
|
||
}
|
||
if (u.compareTo(v) >= 0) {
|
||
u.subTo(v, u);
|
||
if (ac) a.subTo(c, a);
|
||
b.subTo(d, b);
|
||
} else {
|
||
v.subTo(u, v);
|
||
if (ac) c.subTo(a, c);
|
||
d.subTo(b, d);
|
||
}
|
||
}
|
||
if (v.compareTo(BigInteger.ONE) != 0) return BigInteger.ZERO;
|
||
if (d.compareTo(m) >= 0) return d.subtract(m);
|
||
if (d.signum() < 0) d.addTo(m, d);
|
||
else return d;
|
||
if (d.signum() < 0) return d.add(m);
|
||
else return d;
|
||
}
|
||
|
||
var lowprimes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101,
|
||
103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227,
|
||
229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359,
|
||
367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499,
|
||
503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647,
|
||
653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811,
|
||
821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971,
|
||
977, 983, 991, 997
|
||
];
|
||
var lplim = (1 << 26) / lowprimes[lowprimes.length - 1];
|
||
|
||
// (public) test primality with certainty >= 1-.5^t
|
||
|
||
function bnIsProbablePrime(t) {
|
||
var i, x = this.abs();
|
||
if (x.t == 1 && x[0] <= lowprimes[lowprimes.length - 1]) {
|
||
for (i = 0; i < lowprimes.length; ++i)
|
||
if (x[0] == lowprimes[i]) return true;
|
||
return false;
|
||
}
|
||
if (x.isEven()) return false;
|
||
i = 1;
|
||
while (i < lowprimes.length) {
|
||
var m = lowprimes[i],
|
||
j = i + 1;
|
||
while (j < lowprimes.length && m < lplim) m *= lowprimes[j++];
|
||
m = x.modInt(m);
|
||
while (i < j) if (m % lowprimes[i++] == 0) return false;
|
||
}
|
||
return x.millerRabin(t);
|
||
}
|
||
|
||
/* added by Recurity Labs */
|
||
|
||
function nbits(x) {
|
||
var n = 1,
|
||
t;
|
||
if ((t = x >>> 16) != 0) {
|
||
x = t;
|
||
n += 16;
|
||
}
|
||
if ((t = x >> 8) != 0) {
|
||
x = t;
|
||
n += 8;
|
||
}
|
||
if ((t = x >> 4) != 0) {
|
||
x = t;
|
||
n += 4;
|
||
}
|
||
if ((t = x >> 2) != 0) {
|
||
x = t;
|
||
n += 2;
|
||
}
|
||
if ((t = x >> 1) != 0) {
|
||
x = t;
|
||
n += 1;
|
||
}
|
||
return n;
|
||
}
|
||
|
||
function bnToMPI() {
|
||
var ba = this.toByteArray();
|
||
var size = (ba.length - 1) * 8 + nbits(ba[0]);
|
||
var result = "";
|
||
result += String.fromCharCode((size & 0xFF00) >> 8);
|
||
result += String.fromCharCode(size & 0xFF);
|
||
result += util.bin2str(ba);
|
||
return result;
|
||
}
|
||
/* END of addition */
|
||
|
||
// (protected) true if probably prime (HAC 4.24, Miller-Rabin)
|
||
function bnpMillerRabin(t) {
|
||
var n1 = this.subtract(BigInteger.ONE);
|
||
var k = n1.getLowestSetBit();
|
||
if (k <= 0) return false;
|
||
var r = n1.shiftRight(k);
|
||
t = (t + 1) >> 1;
|
||
if (t > lowprimes.length) t = lowprimes.length;
|
||
var a = nbi();
|
||
var j, bases = [];
|
||
for (var i = 0; i < t; ++i) {
|
||
//Pick bases at random, instead of starting at 2
|
||
for (;;) {
|
||
j = lowprimes[Math.floor(Math.random() * lowprimes.length)];
|
||
if (bases.indexOf(j) == -1) break;
|
||
}
|
||
bases.push(j);
|
||
a.fromInt(j);
|
||
var y = a.modPow(r, this);
|
||
if (y.compareTo(BigInteger.ONE) != 0 && y.compareTo(n1) != 0) {
|
||
var j = 1;
|
||
while (j++ < k && y.compareTo(n1) != 0) {
|
||
y = y.modPowInt(2, this);
|
||
if (y.compareTo(BigInteger.ONE) == 0) return false;
|
||
}
|
||
if (y.compareTo(n1) != 0) return false;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
var BigInteger = require('./jsbn.js');
|
||
|
||
// protected
|
||
BigInteger.prototype.chunkSize = bnpChunkSize;
|
||
BigInteger.prototype.toRadix = bnpToRadix;
|
||
BigInteger.prototype.fromRadix = bnpFromRadix;
|
||
BigInteger.prototype.fromNumber = bnpFromNumber;
|
||
BigInteger.prototype.bitwiseTo = bnpBitwiseTo;
|
||
BigInteger.prototype.changeBit = bnpChangeBit;
|
||
BigInteger.prototype.addTo = bnpAddTo;
|
||
BigInteger.prototype.dMultiply = bnpDMultiply;
|
||
BigInteger.prototype.dAddOffset = bnpDAddOffset;
|
||
BigInteger.prototype.multiplyLowerTo = bnpMultiplyLowerTo;
|
||
BigInteger.prototype.multiplyUpperTo = bnpMultiplyUpperTo;
|
||
BigInteger.prototype.modInt = bnpModInt;
|
||
BigInteger.prototype.millerRabin = bnpMillerRabin;
|
||
|
||
// public
|
||
BigInteger.prototype.clone = bnClone;
|
||
BigInteger.prototype.intValue = bnIntValue;
|
||
BigInteger.prototype.byteValue = bnByteValue;
|
||
BigInteger.prototype.shortValue = bnShortValue;
|
||
BigInteger.prototype.signum = bnSigNum;
|
||
BigInteger.prototype.toByteArray = bnToByteArray;
|
||
BigInteger.prototype.equals = bnEquals;
|
||
BigInteger.prototype.min = bnMin;
|
||
BigInteger.prototype.max = bnMax;
|
||
BigInteger.prototype.and = bnAnd;
|
||
BigInteger.prototype.or = bnOr;
|
||
BigInteger.prototype.xor = bnXor;
|
||
BigInteger.prototype.andNot = bnAndNot;
|
||
BigInteger.prototype.not = bnNot;
|
||
BigInteger.prototype.shiftLeft = bnShiftLeft;
|
||
BigInteger.prototype.shiftRight = bnShiftRight;
|
||
BigInteger.prototype.getLowestSetBit = bnGetLowestSetBit;
|
||
BigInteger.prototype.bitCount = bnBitCount;
|
||
BigInteger.prototype.testBit = bnTestBit;
|
||
BigInteger.prototype.setBit = bnSetBit;
|
||
BigInteger.prototype.clearBit = bnClearBit;
|
||
BigInteger.prototype.flipBit = bnFlipBit;
|
||
BigInteger.prototype.add = bnAdd;
|
||
BigInteger.prototype.subtract = bnSubtract;
|
||
BigInteger.prototype.multiply = bnMultiply;
|
||
BigInteger.prototype.divide = bnDivide;
|
||
BigInteger.prototype.remainder = bnRemainder;
|
||
BigInteger.prototype.divideAndRemainder = bnDivideAndRemainder;
|
||
BigInteger.prototype.modPow = bnModPow;
|
||
BigInteger.prototype.modInverse = bnModInverse;
|
||
BigInteger.prototype.pow = bnPow;
|
||
BigInteger.prototype.gcd = bnGCD;
|
||
BigInteger.prototype.isProbablePrime = bnIsProbablePrime;
|
||
BigInteger.prototype.toMPI = bnToMPI;
|
||
|
||
// JSBN-specific extension
|
||
BigInteger.prototype.square = bnSquare;
|
||
|
||
},{"../../util":56,"./jsbn.js":21}],22:[function(require,module,exports){
|
||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||
// Copyright (C) 2011 Recurity Labs GmbH
|
||
//
|
||
// This library is free software; you can redistribute it and/or
|
||
// modify it under the terms of the GNU Lesser General Public
|
||
// License as published by the Free Software Foundation; either
|
||
// version 2.1 of the License, or (at your option) any later version.
|
||
//
|
||
// This library is distributed in the hope that it will be useful,
|
||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
// Lesser General Public License for more details.
|
||
//
|
||
// You should have received a copy of the GNU Lesser General Public
|
||
// License along with this library; if not, write to the Free Software
|
||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||
//
|
||
// RSA implementation
|
||
|
||
var BigInteger = require('./jsbn.js'),
|
||
util = require('../../util'),
|
||
random = require('../random.js');
|
||
|
||
function SecureRandom() {
|
||
function nextBytes(byteArray) {
|
||
for (var n = 0; n < byteArray.length; n++) {
|
||
byteArray[n] = random.getSecureRandomOctet();
|
||
}
|
||
}
|
||
this.nextBytes = nextBytes;
|
||
}
|
||
|
||
function RSA() {
|
||
/**
|
||
* This function uses jsbn Big Num library to decrypt RSA
|
||
* @param m
|
||
* message
|
||
* @param d
|
||
* RSA d as BigInteger
|
||
* @param p
|
||
* RSA p as BigInteger
|
||
* @param q
|
||
* RSA q as BigInteger
|
||
* @param u
|
||
* RSA u as BigInteger
|
||
* @return {BigInteger} The decrypted value of the message
|
||
*/
|
||
function decrypt(m, d, p, q, u) {
|
||
var xp = m.mod(p).modPow(d.mod(p.subtract(BigInteger.ONE)), p);
|
||
var xq = m.mod(q).modPow(d.mod(q.subtract(BigInteger.ONE)), q);
|
||
util.print_debug("rsa.js decrypt\nxpn:" + util.hexstrdump(xp.toMPI()) + "\nxqn:" + util.hexstrdump(xq.toMPI()));
|
||
|
||
var t = xq.subtract(xp);
|
||
if (t[0] == 0) {
|
||
t = xp.subtract(xq);
|
||
t = t.multiply(u).mod(q);
|
||
t = q.subtract(t);
|
||
} else {
|
||
t = t.multiply(u).mod(q);
|
||
}
|
||
return t.multiply(p).add(xp);
|
||
}
|
||
|
||
/**
|
||
* encrypt message
|
||
* @param m message as BigInteger
|
||
* @param e public MPI part as BigInteger
|
||
* @param n public MPI part as BigInteger
|
||
* @return BigInteger
|
||
*/
|
||
function encrypt(m, e, n) {
|
||
return m.modPowInt(e, n);
|
||
}
|
||
|
||
/* Sign and Verify */
|
||
function sign(m, d, n) {
|
||
return m.modPow(d, n);
|
||
}
|
||
|
||
function verify(x, e, n) {
|
||
return x.modPowInt(e, n);
|
||
}
|
||
|
||
// "empty" RSA key constructor
|
||
|
||
function keyObject() {
|
||
this.n = null;
|
||
this.e = 0;
|
||
this.ee = null;
|
||
this.d = null;
|
||
this.p = null;
|
||
this.q = null;
|
||
this.dmp1 = null;
|
||
this.dmq1 = null;
|
||
this.u = null;
|
||
}
|
||
|
||
// Generate a new random private key B bits long, using public expt E
|
||
|
||
function generate(B, E) {
|
||
var key = new keyObject();
|
||
var rng = new SecureRandom();
|
||
var qs = B >> 1;
|
||
key.e = parseInt(E, 16);
|
||
key.ee = new BigInteger(E, 16);
|
||
for (;;) {
|
||
for (;;) {
|
||
key.p = new BigInteger(B - qs, 1, rng);
|
||
if (key.p.subtract(BigInteger.ONE).gcd(key.ee).compareTo(BigInteger.ONE) == 0 && key.p.isProbablePrime(10))
|
||
break;
|
||
}
|
||
for (;;) {
|
||
key.q = new BigInteger(qs, 1, rng);
|
||
if (key.q.subtract(BigInteger.ONE).gcd(key.ee).compareTo(BigInteger.ONE) == 0 && key.q.isProbablePrime(10))
|
||
break;
|
||
}
|
||
if (key.p.compareTo(key.q) <= 0) {
|
||
var t = key.p;
|
||
key.p = key.q;
|
||
key.q = t;
|
||
}
|
||
var p1 = key.p.subtract(BigInteger.ONE);
|
||
var q1 = key.q.subtract(BigInteger.ONE);
|
||
var phi = p1.multiply(q1);
|
||
if (phi.gcd(key.ee).compareTo(BigInteger.ONE) == 0) {
|
||
key.n = key.p.multiply(key.q);
|
||
key.d = key.ee.modInverse(phi);
|
||
key.dmp1 = key.d.mod(p1);
|
||
key.dmq1 = key.d.mod(q1);
|
||
key.u = key.p.modInverse(key.q);
|
||
break;
|
||
}
|
||
}
|
||
return key;
|
||
}
|
||
|
||
this.encrypt = encrypt;
|
||
this.decrypt = decrypt;
|
||
this.verify = verify;
|
||
this.sign = sign;
|
||
this.generate = generate;
|
||
this.keyObject = keyObject;
|
||
}
|
||
|
||
module.exports = RSA;
|
||
|
||
},{"../../util":56,"../random.js":23,"./jsbn.js":21}],23:[function(require,module,exports){
|
||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||
// Copyright (C) 2011 Recurity Labs GmbH
|
||
//
|
||
// This library is free software; you can redistribute it and/or
|
||
// modify it under the terms of the GNU Lesser General Public
|
||
// License as published by the Free Software Foundation; either
|
||
// version 2.1 of the License, or (at your option) any later version.
|
||
//
|
||
// This library is distributed in the hope that it will be useful,
|
||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
// Lesser General Public License for more details.
|
||
//
|
||
// You should have received a copy of the GNU Lesser General Public
|
||
// License along with this library; if not, write to the Free Software
|
||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||
|
||
// The GPG4Browsers crypto interface
|
||
|
||
var type_mpi = require('../type/mpi.js');
|
||
|
||
module.exports = {
|
||
/**
|
||
* Retrieve secure random byte string of the specified length
|
||
* @param {Integer} length Length in bytes to generate
|
||
* @return {String} Random byte string
|
||
*/
|
||
getRandomBytes: function(length) {
|
||
var result = '';
|
||
for (var i = 0; i < length; i++) {
|
||
result += String.fromCharCode(this.getSecureRandomOctet());
|
||
}
|
||
return result;
|
||
},
|
||
|
||
/**
|
||
* Return a pseudo-random number in the specified range
|
||
* @param {Integer} from Min of the random number
|
||
* @param {Integer} to Max of the random number (max 32bit)
|
||
* @return {Integer} A pseudo random number
|
||
*/
|
||
getPseudoRandom: function(from, to) {
|
||
return Math.round(Math.random() * (to - from)) + from;
|
||
},
|
||
|
||
/**
|
||
* Return a secure random number in the specified range
|
||
* @param {Integer} from Min of the random number
|
||
* @param {Integer} to Max of the random number (max 32bit)
|
||
* @return {Integer} A secure random number
|
||
*/
|
||
getSecureRandom: function(from, to) {
|
||
var buf = new Uint32Array(1);
|
||
window.crypto.getRandomValues(buf);
|
||
var bits = ((to - from)).toString(2).length;
|
||
while ((buf[0] & (Math.pow(2, bits) - 1)) > (to - from))
|
||
window.crypto.getRandomValues(buf);
|
||
return from + (Math.abs(buf[0] & (Math.pow(2, bits) - 1)));
|
||
},
|
||
|
||
getSecureRandomOctet: function() {
|
||
var buf = new Uint32Array(1);
|
||
window.crypto.getRandomValues(buf);
|
||
return buf[0] & 0xFF;
|
||
},
|
||
|
||
/**
|
||
* Create a secure random big integer of bits length
|
||
* @param {Integer} bits Bit length of the MPI to create
|
||
* @return {BigInteger} Resulting big integer
|
||
*/
|
||
getRandomBigInteger: function(bits) {
|
||
if (bits < 0) {
|
||
return null;
|
||
}
|
||
var numBytes = Math.floor((bits + 7) / 8);
|
||
|
||
var randomBits = this.getRandomBytes(numBytes);
|
||
if (bits % 8 > 0) {
|
||
|
||
randomBits = String.fromCharCode(
|
||
(Math.pow(2, bits % 8) - 1) &
|
||
randomBits.charCodeAt(0)) +
|
||
randomBits.substring(1);
|
||
}
|
||
var mpi = new type_mpi();
|
||
mpi.fromBytes(randomBits);
|
||
return mpi.toBigInteger();
|
||
},
|
||
|
||
getRandomBigIntegerInRange: function(min, max) {
|
||
if (max.compareTo(min) <= 0) {
|
||
return;
|
||
}
|
||
|
||
var range = max.subtract(min);
|
||
var r = this.getRandomBigInteger(range.bitLength());
|
||
while (r > range) {
|
||
r = this.getRandomBigInteger(range.bitLength());
|
||
}
|
||
return min.add(r);
|
||
}
|
||
|
||
};
|
||
|
||
},{"../type/mpi.js":54}],24:[function(require,module,exports){
|
||
var publicKey = require('./public_key'),
|
||
pkcs1 = require('./pkcs1.js'),
|
||
hashModule = require('./hash');
|
||
|
||
module.exports = {
|
||
/**
|
||
*
|
||
* @param {Integer} algo public Key algorithm
|
||
* @param {Integer} hash_algo Hash algorithm
|
||
* @param {openpgp_type_mpi[]} msg_MPIs Signature multiprecision integers
|
||
* @param {openpgp_type_mpi[]} publickey_MPIs Public key multiprecision integers
|
||
* @param {String} data Data on where the signature was computed on.
|
||
* @return {Boolean} true if signature (sig_data was equal to data over hash)
|
||
*/
|
||
verify: function(algo, hash_algo, msg_MPIs, publickey_MPIs, data) {
|
||
var calc_hash = hashModule.digest(hash_algo, data);
|
||
|
||
switch (algo) {
|
||
case 1:
|
||
// RSA (Encrypt or Sign) [HAC]
|
||
case 2:
|
||
// RSA Encrypt-Only [HAC]
|
||
case 3:
|
||
// RSA Sign-Only [HAC]
|
||
var rsa = new publicKey.rsa();
|
||
var n = publickey_MPIs[0].toBigInteger();
|
||
var e = publickey_MPIs[1].toBigInteger();
|
||
var x = msg_MPIs[0].toBigInteger();
|
||
var dopublic = rsa.verify(x, e, n);
|
||
var hash = pkcs1.emsa.decode(hash_algo, dopublic.toMPI().substring(2));
|
||
if (hash == -1) {
|
||
throw new Error('PKCS1 padding in message or key incorrect. Aborting...');
|
||
}
|
||
return hash == calc_hash;
|
||
|
||
case 16:
|
||
// Elgamal (Encrypt-Only) [ELGAMAL] [HAC]
|
||
throw new Error("signing with Elgamal is not defined in the OpenPGP standard.");
|
||
case 17:
|
||
// DSA (Digital Signature Algorithm) [FIPS186] [HAC]
|
||
var dsa = new publicKey.dsa();
|
||
var s1 = msg_MPIs[0].toBigInteger();
|
||
var s2 = msg_MPIs[1].toBigInteger();
|
||
var p = publickey_MPIs[0].toBigInteger();
|
||
var q = publickey_MPIs[1].toBigInteger();
|
||
var g = publickey_MPIs[2].toBigInteger();
|
||
var y = publickey_MPIs[3].toBigInteger();
|
||
var m = data;
|
||
var dopublic = dsa.verify(hash_algo, s1, s2, m, p, q, g, y);
|
||
return dopublic.compareTo(s1) == 0;
|
||
default:
|
||
throw new Error('Invalid signature algorithm.');
|
||
}
|
||
|
||
},
|
||
|
||
/**
|
||
* Create a signature on data using the specified algorithm
|
||
* @param {Integer} hash_algo hash Algorithm to use (See RFC4880 9.4)
|
||
* @param {Integer} algo Asymmetric cipher algorithm to use (See RFC4880 9.1)
|
||
* @param {openpgp_type_mpi[]} publicMPIs Public key multiprecision integers
|
||
* of the private key
|
||
* @param {openpgp_type_mpi[]} secretMPIs Private key multiprecision
|
||
* integers which is used to sign the data
|
||
* @param {String} data Data to be signed
|
||
* @return {openpgp_type_mpi[]}
|
||
*/
|
||
sign: function(hash_algo, algo, keyIntegers, data) {
|
||
|
||
switch (algo) {
|
||
case 1:
|
||
// RSA (Encrypt or Sign) [HAC]
|
||
case 2:
|
||
// RSA Encrypt-Only [HAC]
|
||
case 3:
|
||
// RSA Sign-Only [HAC]
|
||
var rsa = new publicKey.rsa();
|
||
var d = keyIntegers[2].toBigInteger();
|
||
var n = keyIntegers[0].toBigInteger();
|
||
var m = pkcs1.emsa.encode(hash_algo,
|
||
data, keyIntegers[0].byteLength());
|
||
|
||
return rsa.sign(m, d, n).toMPI();
|
||
|
||
case 17:
|
||
// DSA (Digital Signature Algorithm) [FIPS186] [HAC]
|
||
var dsa = new publicKey.dsa();
|
||
|
||
var p = keyIntegers[0].toBigInteger();
|
||
var q = keyIntegers[1].toBigInteger();
|
||
var g = keyIntegers[2].toBigInteger();
|
||
var y = keyIntegers[3].toBigInteger();
|
||
var x = keyIntegers[4].toBigInteger();
|
||
var m = data;
|
||
var result = dsa.sign(hash_algo, m, g, p, q, x);
|
||
|
||
return result[0].toString() + result[1].toString();
|
||
case 16:
|
||
// Elgamal (Encrypt-Only) [ELGAMAL] [HAC]
|
||
throw new Error('Signing with Elgamal is not defined in the OpenPGP standard.');
|
||
default:
|
||
throw new Error('Invalid signature algorithm.');
|
||
}
|
||
}
|
||
}
|
||
|
||
},{"./hash":12,"./pkcs1.js":17,"./public_key":20}],25:[function(require,module,exports){
|
||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||
// Copyright (C) 2011 Recurity Labs GmbH
|
||
//
|
||
// This library is free software; you can redistribute it and/or
|
||
// modify it under the terms of the GNU Lesser General Public
|
||
// License as published by the Free Software Foundation; either
|
||
// version 2.1 of the License, or (at your option) any later version.
|
||
//
|
||
// This library is distributed in the hope that it will be useful,
|
||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
// Lesser General Public License for more details.
|
||
//
|
||
// You should have received a copy of the GNU Lesser General Public
|
||
// License along with this library; if not, write to the Free Software
|
||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||
|
||
var base64 = require('./base64.js');
|
||
var enums = require('../enums.js');
|
||
var config = require('../config');
|
||
|
||
/**
|
||
* Finds out which Ascii Armoring type is used. This is an internal function
|
||
* @param {String} text [String] ascii armored text
|
||
* @returns {Integer} 0 = MESSAGE PART n of m
|
||
* 1 = MESSAGE PART n
|
||
* 2 = SIGNED MESSAGE
|
||
* 3 = PGP MESSAGE
|
||
* 4 = PUBLIC KEY BLOCK
|
||
* 5 = PRIVATE KEY BLOCK
|
||
* null = unknown
|
||
*/
|
||
function get_type(text) {
|
||
var reHeader = /^-----([^-]+)-----$\n/m;
|
||
|
||
var header = text.match(reHeader);
|
||
|
||
// BEGIN PGP MESSAGE, PART X/Y
|
||
// Used for multi-part messages, where the armor is split amongst Y
|
||
// parts, and this is the Xth part out of Y.
|
||
if (header[1].match(/BEGIN PGP MESSAGE, PART \d+\/\d+/)) {
|
||
return enums.armor.multipart_section;
|
||
} else
|
||
// BEGIN PGP MESSAGE, PART X
|
||
// Used for multi-part messages, where this is the Xth part of an
|
||
// unspecified number of parts. Requires the MESSAGE-ID Armor
|
||
// Header to be used.
|
||
if (header[1].match(/BEGIN PGP MESSAGE, PART \d+/)) {
|
||
return enums.armor.multipart_last;
|
||
|
||
} else
|
||
// BEGIN PGP SIGNATURE
|
||
// Used for detached signatures, OpenPGP/MIME signatures, and
|
||
// cleartext signatures. Note that PGP 2.x uses BEGIN PGP MESSAGE
|
||
// for detached signatures.
|
||
if (header[1].match(/BEGIN PGP SIGNED MESSAGE/)) {
|
||
return enums.armor.signed;
|
||
|
||
} else
|
||
// BEGIN PGP MESSAGE
|
||
// Used for signed, encrypted, or compressed files.
|
||
if (header[1].match(/BEGIN PGP MESSAGE/)) {
|
||
return enums.armor.message;
|
||
|
||
} else
|
||
// BEGIN PGP PUBLIC KEY BLOCK
|
||
// Used for armoring public keys.
|
||
if (header[1].match(/BEGIN PGP PUBLIC KEY BLOCK/)) {
|
||
return enums.armor.public_key;
|
||
|
||
} else
|
||
// BEGIN PGP PRIVATE KEY BLOCK
|
||
// Used for armoring private keys.
|
||
if (header[1].match(/BEGIN PGP PRIVATE KEY BLOCK/)) {
|
||
return enums.armor.private_key;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Add additional information to the armor version of an OpenPGP binary
|
||
* packet block.
|
||
* @author Alex
|
||
* @version 2011-12-16
|
||
* @returns {String} The header information
|
||
*/
|
||
function armor_addheader() {
|
||
var result = "";
|
||
if (config.show_version) {
|
||
result += "Version: " + config.versionstring + '\r\n';
|
||
}
|
||
if (config.show_comment) {
|
||
result += "Comment: " + config.commentstring + '\r\n';
|
||
}
|
||
result += '\r\n';
|
||
return result;
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
* Calculates a checksum over the given data and returns it base64 encoded
|
||
* @param {String} data Data to create a CRC-24 checksum for
|
||
* @return {String} Base64 encoded checksum
|
||
*/
|
||
function getCheckSum(data) {
|
||
var c = createcrc24(data);
|
||
var str = "" + String.fromCharCode(c >> 16) +
|
||
String.fromCharCode((c >> 8) & 0xFF) +
|
||
String.fromCharCode(c & 0xFF);
|
||
return base64.encode(str);
|
||
}
|
||
|
||
/**
|
||
* Calculates the checksum over the given data and compares it with the
|
||
* given base64 encoded checksum
|
||
* @param {String} data Data to create a CRC-24 checksum for
|
||
* @param {String} checksum Base64 encoded checksum
|
||
* @return {Boolean} True if the given checksum is correct; otherwise false
|
||
*/
|
||
function verifyCheckSum(data, checksum) {
|
||
var c = getCheckSum(data);
|
||
var d = checksum;
|
||
return c[0] == d[0] && c[1] == d[1] && c[2] == d[2];
|
||
}
|
||
/**
|
||
* Internal function to calculate a CRC-24 checksum over a given string (data)
|
||
* @param {String} data Data to create a CRC-24 checksum for
|
||
* @return {Integer} The CRC-24 checksum as number
|
||
*/
|
||
var crc_table = [
|
||
0x00000000, 0x00864cfb, 0x018ad50d, 0x010c99f6, 0x0393e6e1, 0x0315aa1a, 0x021933ec, 0x029f7f17, 0x07a18139,
|
||
0x0727cdc2, 0x062b5434, 0x06ad18cf, 0x043267d8, 0x04b42b23, 0x05b8b2d5, 0x053efe2e, 0x0fc54e89, 0x0f430272,
|
||
0x0e4f9b84, 0x0ec9d77f, 0x0c56a868, 0x0cd0e493, 0x0ddc7d65, 0x0d5a319e, 0x0864cfb0, 0x08e2834b, 0x09ee1abd,
|
||
0x09685646, 0x0bf72951, 0x0b7165aa, 0x0a7dfc5c, 0x0afbb0a7, 0x1f0cd1e9, 0x1f8a9d12, 0x1e8604e4, 0x1e00481f,
|
||
0x1c9f3708, 0x1c197bf3, 0x1d15e205, 0x1d93aefe, 0x18ad50d0, 0x182b1c2b, 0x192785dd, 0x19a1c926, 0x1b3eb631,
|
||
0x1bb8faca, 0x1ab4633c, 0x1a322fc7, 0x10c99f60, 0x104fd39b, 0x11434a6d, 0x11c50696, 0x135a7981, 0x13dc357a,
|
||
0x12d0ac8c, 0x1256e077, 0x17681e59, 0x17ee52a2, 0x16e2cb54, 0x166487af, 0x14fbf8b8, 0x147db443, 0x15712db5,
|
||
0x15f7614e, 0x3e19a3d2, 0x3e9fef29, 0x3f9376df, 0x3f153a24, 0x3d8a4533, 0x3d0c09c8, 0x3c00903e, 0x3c86dcc5,
|
||
0x39b822eb, 0x393e6e10, 0x3832f7e6, 0x38b4bb1d, 0x3a2bc40a, 0x3aad88f1, 0x3ba11107, 0x3b275dfc, 0x31dced5b,
|
||
0x315aa1a0,
|
||
0x30563856, 0x30d074ad, 0x324f0bba, 0x32c94741, 0x33c5deb7, 0x3343924c, 0x367d6c62, 0x36fb2099, 0x37f7b96f,
|
||
0x3771f594, 0x35ee8a83, 0x3568c678, 0x34645f8e, 0x34e21375, 0x2115723b, 0x21933ec0, 0x209fa736, 0x2019ebcd,
|
||
0x228694da, 0x2200d821, 0x230c41d7, 0x238a0d2c, 0x26b4f302, 0x2632bff9, 0x273e260f, 0x27b86af4, 0x252715e3,
|
||
0x25a15918, 0x24adc0ee, 0x242b8c15, 0x2ed03cb2, 0x2e567049, 0x2f5ae9bf, 0x2fdca544, 0x2d43da53, 0x2dc596a8,
|
||
0x2cc90f5e, 0x2c4f43a5, 0x2971bd8b, 0x29f7f170, 0x28fb6886, 0x287d247d, 0x2ae25b6a, 0x2a641791, 0x2b688e67,
|
||
0x2beec29c, 0x7c3347a4, 0x7cb50b5f, 0x7db992a9, 0x7d3fde52, 0x7fa0a145, 0x7f26edbe, 0x7e2a7448, 0x7eac38b3,
|
||
0x7b92c69d, 0x7b148a66, 0x7a181390, 0x7a9e5f6b, 0x7801207c, 0x78876c87, 0x798bf571, 0x790db98a, 0x73f6092d,
|
||
0x737045d6, 0x727cdc20, 0x72fa90db, 0x7065efcc, 0x70e3a337, 0x71ef3ac1, 0x7169763a, 0x74578814, 0x74d1c4ef,
|
||
0x75dd5d19, 0x755b11e2, 0x77c46ef5, 0x7742220e, 0x764ebbf8, 0x76c8f703, 0x633f964d, 0x63b9dab6, 0x62b54340,
|
||
0x62330fbb,
|
||
0x60ac70ac, 0x602a3c57, 0x6126a5a1, 0x61a0e95a, 0x649e1774, 0x64185b8f, 0x6514c279, 0x65928e82, 0x670df195,
|
||
0x678bbd6e, 0x66872498, 0x66016863, 0x6cfad8c4, 0x6c7c943f, 0x6d700dc9, 0x6df64132, 0x6f693e25, 0x6fef72de,
|
||
0x6ee3eb28, 0x6e65a7d3, 0x6b5b59fd, 0x6bdd1506, 0x6ad18cf0, 0x6a57c00b, 0x68c8bf1c, 0x684ef3e7, 0x69426a11,
|
||
0x69c426ea, 0x422ae476, 0x42aca88d, 0x43a0317b, 0x43267d80, 0x41b90297, 0x413f4e6c, 0x4033d79a, 0x40b59b61,
|
||
0x458b654f, 0x450d29b4, 0x4401b042, 0x4487fcb9, 0x461883ae, 0x469ecf55, 0x479256a3, 0x47141a58, 0x4defaaff,
|
||
0x4d69e604, 0x4c657ff2, 0x4ce33309, 0x4e7c4c1e, 0x4efa00e5, 0x4ff69913, 0x4f70d5e8, 0x4a4e2bc6, 0x4ac8673d,
|
||
0x4bc4fecb, 0x4b42b230, 0x49ddcd27, 0x495b81dc, 0x4857182a, 0x48d154d1, 0x5d26359f, 0x5da07964, 0x5cace092,
|
||
0x5c2aac69, 0x5eb5d37e, 0x5e339f85, 0x5f3f0673, 0x5fb94a88, 0x5a87b4a6, 0x5a01f85d, 0x5b0d61ab, 0x5b8b2d50,
|
||
0x59145247, 0x59921ebc, 0x589e874a, 0x5818cbb1, 0x52e37b16, 0x526537ed, 0x5369ae1b, 0x53efe2e0, 0x51709df7,
|
||
0x51f6d10c,
|
||
0x50fa48fa, 0x507c0401, 0x5542fa2f, 0x55c4b6d4, 0x54c82f22, 0x544e63d9, 0x56d11cce, 0x56575035, 0x575bc9c3,
|
||
0x57dd8538
|
||
];
|
||
|
||
function createcrc24(input) {
|
||
var crc = 0xB704CE;
|
||
var index = 0;
|
||
|
||
while ((input.length - index) > 16) {
|
||
crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index)) & 0xff];
|
||
crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 1)) & 0xff];
|
||
crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 2)) & 0xff];
|
||
crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 3)) & 0xff];
|
||
crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 4)) & 0xff];
|
||
crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 5)) & 0xff];
|
||
crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 6)) & 0xff];
|
||
crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 7)) & 0xff];
|
||
crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 8)) & 0xff];
|
||
crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 9)) & 0xff];
|
||
crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 10)) & 0xff];
|
||
crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 11)) & 0xff];
|
||
crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 12)) & 0xff];
|
||
crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 13)) & 0xff];
|
||
crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 14)) & 0xff];
|
||
crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index + 15)) & 0xff];
|
||
index += 16;
|
||
}
|
||
|
||
for (var j = index; j < input.length; j++) {
|
||
crc = (crc << 8) ^ crc_table[((crc >> 16) ^ input.charCodeAt(index++)) & 0xff];
|
||
}
|
||
return crc & 0xffffff;
|
||
}
|
||
|
||
/**
|
||
* Splits a message into two parts, the headers and the body. This is an internal function
|
||
* @param {String} text OpenPGP armored message part
|
||
* @returns {(Boolean|Object)} Either false in case of an error
|
||
* or an object with attribute "headers" containing the headers and
|
||
* and an attribute "body" containing the body.
|
||
*/
|
||
function split_headers(text) {
|
||
var reEmptyLine = /^[\t ]*\n/m;
|
||
var headers = "";
|
||
var body = text;
|
||
|
||
var matchResult = reEmptyLine.exec(text);
|
||
|
||
if (matchResult != null) {
|
||
headers = text.slice(0, matchResult.index);
|
||
body = text.slice(matchResult.index + matchResult[0].length);
|
||
}
|
||
|
||
return { headers: headers, body: body };
|
||
}
|
||
|
||
/**
|
||
* Splits a message into two parts, the body and the checksum. This is an internal function
|
||
* @param {String} text OpenPGP armored message part
|
||
* @returns {(Boolean|Object)} Either false in case of an error
|
||
* or an object with attribute "body" containing the body
|
||
* and an attribute "checksum" containing the checksum.
|
||
*/
|
||
function split_checksum(text) {
|
||
var reChecksumStart = /^=/m;
|
||
var body = text;
|
||
var checksum = "";
|
||
|
||
var matchResult = reChecksumStart.exec(text);
|
||
|
||
if (matchResult != null) {
|
||
body = text.slice(0, matchResult.index);
|
||
checksum = text.slice(matchResult.index + 1);
|
||
}
|
||
|
||
return { body: body, checksum: checksum };
|
||
}
|
||
|
||
/**
|
||
* DeArmor an OpenPGP armored message; verify the checksum and return
|
||
* the encoded bytes
|
||
* @param {String} text OpenPGP armored message
|
||
* @returns {(Boolean|Object)} Either false in case of an error
|
||
* or an object with attribute "text" containing the message text
|
||
* and an attribute "data" containing the bytes.
|
||
*/
|
||
function dearmor(text) {
|
||
var reSplit = /^-----[^-]+-----$\n/m;
|
||
|
||
text = text.replace(/\r/g, '');
|
||
|
||
var type = get_type(text);
|
||
|
||
var splittext = text.split(reSplit);
|
||
|
||
// IE has a bug in split with a re. If the pattern matches the beginning of the
|
||
// string it doesn't create an empty array element 0. So we need to detect this
|
||
// so we know the index of the data we are interested in.
|
||
var indexBase = 1;
|
||
|
||
var result, checksum;
|
||
|
||
if (text.search(reSplit) != splittext[0].length) {
|
||
indexBase = 0;
|
||
}
|
||
|
||
if (type != 2) {
|
||
var msg = split_headers(splittext[indexBase]);
|
||
var msg_sum = split_checksum(msg.body);
|
||
|
||
result = {
|
||
data: base64.decode(msg_sum.body),
|
||
type: type
|
||
};
|
||
|
||
checksum = msg_sum.checksum;
|
||
} else {
|
||
// Reverse dash-escaping for msg and remove trailing whitespace at end of line
|
||
var msg = split_headers(splittext[indexBase].replace(/^- /mg, '').replace(/[\t ]+\n/g, "\n"));
|
||
var sig = split_headers(splittext[indexBase + 1].replace(/^- /mg, ''));
|
||
var sig_sum = split_checksum(sig.body);
|
||
|
||
result = {
|
||
text: msg.body.replace(/\n$/, '').replace(/\n/g, "\r\n"),
|
||
data: base64.decode(sig_sum.body),
|
||
type: type
|
||
};
|
||
|
||
checksum = sig_sum.checksum;
|
||
}
|
||
|
||
if (!verifyCheckSum(result.data, checksum)) {
|
||
util.print_error("Ascii armor integrity check on message failed: '"
|
||
+ checksum
|
||
+ "' should be '"
|
||
+ getCheckSum(result) + "'");
|
||
return false;
|
||
} else {
|
||
return result;
|
||
}
|
||
}
|
||
|
||
|
||
/**
|
||
* Armor an OpenPGP binary packet block
|
||
* @param {Integer} messagetype type of the message
|
||
* @param body
|
||
* @param {Integer} partindex
|
||
* @param {Integer} parttotal
|
||
* @returns {String} Armored text
|
||
*/
|
||
function armor(messagetype, body, partindex, parttotal) {
|
||
var result = "";
|
||
switch (messagetype) {
|
||
case enums.armor.multipart_section:
|
||
result += "-----BEGIN PGP MESSAGE, PART " + partindex + "/" + parttotal + "-----\r\n";
|
||
result += armor_addheader();
|
||
result += base64.encode(body);
|
||
result += "\r\n=" + getCheckSum(body) + "\r\n";
|
||
result += "-----END PGP MESSAGE, PART " + partindex + "/" + parttotal + "-----\r\n";
|
||
break;
|
||
case enums.armor.mutlipart_last:
|
||
result += "-----BEGIN PGP MESSAGE, PART " + partindex + "-----\r\n";
|
||
result += armor_addheader();
|
||
result += base64.encode(body);
|
||
result += "\r\n=" + getCheckSum(body) + "\r\n";
|
||
result += "-----END PGP MESSAGE, PART " + partindex + "-----\r\n";
|
||
break;
|
||
case enums.armor.signed:
|
||
result += "\r\n-----BEGIN PGP SIGNED MESSAGE-----\r\n";
|
||
result += "Hash: " + body.hash + "\r\n\r\n";
|
||
result += body.text.replace(/\n-/g, "\n- -");
|
||
result += "\r\n-----BEGIN PGP SIGNATURE-----\r\n";
|
||
result += armor_addheader();
|
||
result += base64.encode(body.data);
|
||
result += "\r\n=" + getCheckSum(body.data) + "\r\n";
|
||
result += "-----END PGP SIGNATURE-----\r\n";
|
||
break;
|
||
case enums.armor.message:
|
||
result += "-----BEGIN PGP MESSAGE-----\r\n";
|
||
result += armor_addheader();
|
||
result += base64.encode(body);
|
||
result += "\r\n=" + getCheckSum(body) + "\r\n";
|
||
result += "-----END PGP MESSAGE-----\r\n";
|
||
break;
|
||
case enums.armor.public_key:
|
||
result += "-----BEGIN PGP PUBLIC KEY BLOCK-----\r\n";
|
||
result += armor_addheader();
|
||
result += base64.encode(body);
|
||
result += "\r\n=" + getCheckSum(body) + "\r\n";
|
||
result += "-----END PGP PUBLIC KEY BLOCK-----\r\n\r\n";
|
||
break;
|
||
case enums.armor.private_key:
|
||
result += "-----BEGIN PGP PRIVATE KEY BLOCK-----\r\n";
|
||
result += armor_addheader();
|
||
result += base64.encode(body);
|
||
result += "\r\n=" + getCheckSum(body) + "\r\n";
|
||
result += "-----END PGP PRIVATE KEY BLOCK-----\r\n";
|
||
break;
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
module.exports = {
|
||
encode: armor,
|
||
decode: dearmor
|
||
};
|
||
|
||
},{"../config":3,"../enums.js":27,"./base64.js":26}],26:[function(require,module,exports){
|
||
/* OpenPGP radix-64/base64 string encoding/decoding
|
||
* Copyright 2005 Herbert Hanewinkel, www.haneWIN.de
|
||
* version 1.0, check www.haneWIN.de for the latest version
|
||
*
|
||
* This software is provided as-is, without express or implied warranty.
|
||
* Permission to use, copy, modify, distribute or sell this software, with or
|
||
* without fee, for any purpose and by any individual or organization, is hereby
|
||
* granted, provided that the above copyright notice and this paragraph appear
|
||
* in all copies. Distribution as a part of an application or binary must
|
||
* include the above copyright notice in the documentation and/or other materials
|
||
* provided with the application or distribution.
|
||
*/
|
||
|
||
var b64s = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
||
|
||
function s2r(t) {
|
||
var a, c, n;
|
||
var r = '',
|
||
l = 0,
|
||
s = 0;
|
||
var tl = t.length;
|
||
|
||
for (n = 0; n < tl; n++) {
|
||
c = t.charCodeAt(n);
|
||
if (s == 0) {
|
||
r += b64s.charAt((c >> 2) & 63);
|
||
a = (c & 3) << 4;
|
||
} else if (s == 1) {
|
||
r += b64s.charAt((a | (c >> 4) & 15));
|
||
a = (c & 15) << 2;
|
||
} else if (s == 2) {
|
||
r += b64s.charAt(a | ((c >> 6) & 3));
|
||
l += 1;
|
||
if ((l % 60) == 0)
|
||
r += "\n";
|
||
r += b64s.charAt(c & 63);
|
||
}
|
||
l += 1;
|
||
if ((l % 60) == 0)
|
||
r += "\n";
|
||
|
||
s += 1;
|
||
if (s == 3)
|
||
s = 0;
|
||
}
|
||
if (s > 0) {
|
||
r += b64s.charAt(a);
|
||
l += 1;
|
||
if ((l % 60) == 0)
|
||
r += "\n";
|
||
r += '=';
|
||
l += 1;
|
||
}
|
||
if (s == 1) {
|
||
if ((l % 60) == 0)
|
||
r += "\n";
|
||
r += '=';
|
||
}
|
||
|
||
return r;
|
||
}
|
||
|
||
function r2s(t) {
|
||
var c, n;
|
||
var r = '',
|
||
s = 0,
|
||
a = 0;
|
||
var tl = t.length;
|
||
|
||
for (n = 0; n < tl; n++) {
|
||
c = b64s.indexOf(t.charAt(n));
|
||
if (c >= 0) {
|
||
if (s)
|
||
r += String.fromCharCode(a | (c >> (6 - s)) & 255);
|
||
s = (s + 2) & 7;
|
||
a = (c << s) & 255;
|
||
}
|
||
}
|
||
return r;
|
||
}
|
||
|
||
module.exports = {
|
||
encode: s2r,
|
||
decode: r2s
|
||
}
|
||
|
||
},{}],27:[function(require,module,exports){
|
||
var enums = {
|
||
|
||
/** A string to key specifier type
|
||
* @enum {Integer}
|
||
*/
|
||
s2k: {
|
||
simple: 0,
|
||
salted: 1,
|
||
iterated: 3,
|
||
gnu: 101
|
||
},
|
||
|
||
/** RFC4880, section 9.1
|
||
* @enum {String}
|
||
*/
|
||
publicKey: {
|
||
rsa_encrypt_sign: 1,
|
||
rsa_encrypt: 2,
|
||
rsa_sign: 3,
|
||
elgamal: 16,
|
||
dsa: 17
|
||
},
|
||
|
||
/** RFC4880, section 9.2
|
||
* @enum {String}
|
||
*/
|
||
symmetric: {
|
||
plaintext: 0,
|
||
/** Not implemented! */
|
||
idea: 1,
|
||
tripledes: 2,
|
||
cast5: 3,
|
||
blowfish: 4,
|
||
aes128: 7,
|
||
aes192: 8,
|
||
aes256: 9,
|
||
twofish: 10
|
||
},
|
||
|
||
/** RFC4880, section 9.3
|
||
* @enum {String}
|
||
*/
|
||
compression: {
|
||
uncompressed: 0,
|
||
/** RFC1951 */
|
||
zip: 1,
|
||
/** RFC1950 */
|
||
zlib: 2,
|
||
bzip2: 3
|
||
},
|
||
|
||
/** RFC4880, section 9.4
|
||
* @enum {String}
|
||
*/
|
||
hash: {
|
||
md5: 1,
|
||
sha1: 2,
|
||
ripemd: 3,
|
||
sha256: 8,
|
||
sha384: 9,
|
||
sha512: 10,
|
||
sha224: 11
|
||
},
|
||
|
||
|
||
/**
|
||
* @enum {String}
|
||
* A list of packet types and numeric tags associated with them.
|
||
*/
|
||
packet: {
|
||
public_key_encrypted_session_key: 1,
|
||
signature: 2,
|
||
sym_encrypted_session_key: 3,
|
||
one_pass_signature: 4,
|
||
secret_key: 5,
|
||
public_key: 6,
|
||
secret_subkey: 7,
|
||
compressed: 8,
|
||
symmetrically_encrypted: 9,
|
||
marker: 10,
|
||
literal: 11,
|
||
trust: 12,
|
||
userid: 13,
|
||
public_subkey: 14,
|
||
user_attribute: 17,
|
||
sym_encrypted_integrity_protected: 18,
|
||
modification_detection_code: 19
|
||
},
|
||
|
||
|
||
/**
|
||
* Data types in the literal packet
|
||
* @readonly
|
||
* @enum {String}
|
||
*/
|
||
literal: {
|
||
/** Binary data */
|
||
binary: 'b'.charCodeAt(),
|
||
/** Text data */
|
||
text: 't'.charCodeAt(),
|
||
/** Utf8 data */
|
||
utf8: 'u'.charCodeAt()
|
||
},
|
||
|
||
|
||
/** One pass signature packet type
|
||
* @enum {String} */
|
||
signature: {
|
||
/** 0x00: Signature of a binary document. */
|
||
binary: 0,
|
||
/** 0x01: Signature of a canonical text document.
|
||
* Canonicalyzing the document by converting line endings. */
|
||
text: 1,
|
||
/** 0x02: Standalone signature.
|
||
* This signature is a signature of only its own subpacket contents.
|
||
* It is calculated identically to a signature over a zero-lengh
|
||
* binary document. Note that it doesn't make sense to have a V3
|
||
* standalone signature. */
|
||
standalone: 2,
|
||
/** 0x10: Generic certification of a User ID and Public-Key packet.
|
||
* The issuer of this certification does not make any particular
|
||
* assertion as to how well the certifier has checked that the owner
|
||
* of the key is in fact the person described by the User ID. */
|
||
cert_generic: 16,
|
||
/** 0x11: Persona certification of a User ID and Public-Key packet.
|
||
* The issuer of this certification has not done any verification of
|
||
* the claim that the owner of this key is the User ID specified. */
|
||
cert_persona: 17,
|
||
/** 0x12: Casual certification of a User ID and Public-Key packet.
|
||
* The issuer of this certification has done some casual
|
||
* verification of the claim of identity. */
|
||
cert_casual: 18,
|
||
/** 0x13: Positive certification of a User ID and Public-Key packet.
|
||
* The issuer of this certification has done substantial
|
||
* verification of the claim of identity.
|
||
*
|
||
* Most OpenPGP implementations make their "key signatures" as 0x10
|
||
* certifications. Some implementations can issue 0x11-0x13
|
||
* certifications, but few differentiate between the types. */
|
||
cert_positive: 19,
|
||
/** 0x30: Certification revocation signature
|
||
* This signature revokes an earlier User ID certification signature
|
||
* (signature class 0x10 through 0x13) or direct-key signature
|
||
* (0x1F). It should be issued by the same key that issued the
|
||
* revoked signature or an authorized revocation key. The signature
|
||
* is computed over the same data as the certificate that it
|
||
* revokes, and should have a later creation date than that
|
||
* certificate. */
|
||
cert_revocation: 48,
|
||
/** 0x18: Subkey Binding Signature
|
||
* This signature is a statement by the top-level signing key that
|
||
* indicates that it owns the subkey. This signature is calculated
|
||
* directly on the primary key and subkey, and not on any User ID or
|
||
* other packets. A signature that binds a signing subkey MUST have
|
||
* an Embedded Signature subpacket in this binding signature that
|
||
* contains a 0x19 signature made by the signing subkey on the
|
||
* primary key and subkey. */
|
||
subkey_binding: 24,
|
||
/** 0x19: Primary Key Binding Signature
|
||
* This signature is a statement by a signing subkey, indicating
|
||
* that it is owned by the primary key and subkey. This signature
|
||
* is calculated the same way as a 0x18 signature: directly on the
|
||
* primary key and subkey, and not on any User ID or other packets.
|
||
|
||
* When a signature is made over a key, the hash data starts with the
|
||
* octet 0x99, followed by a two-octet length of the key, and then body
|
||
* of the key packet. (Note that this is an old-style packet header for
|
||
* a key packet with two-octet length.) A subkey binding signature
|
||
* (type 0x18) or primary key binding signature (type 0x19) then hashes
|
||
* the subkey using the same format as the main key (also using 0x99 as
|
||
* the first octet). */
|
||
key_binding: 25,
|
||
/** 0x1F: Signature directly on a key
|
||
* This signature is calculated directly on a key. It binds the
|
||
* information in the Signature subpackets to the key, and is
|
||
* appropriate to be used for subpackets that provide information
|
||
* about the key, such as the Revocation Key subpacket. It is also
|
||
* appropriate for statements that non-self certifiers want to make
|
||
* about the key itself, rather than the binding between a key and a
|
||
* name. */
|
||
key: 31,
|
||
/** 0x20: Key revocation signature
|
||
* The signature is calculated directly on the key being revoked. A
|
||
* revoked key is not to be used. Only revocation signatures by the
|
||
* key being revoked, or by an authorized revocation key, should be
|
||
* considered valid revocation signatures.a */
|
||
key_revocation: 32,
|
||
/** 0x28: Subkey revocation signature
|
||
* The signature is calculated directly on the subkey being revoked.
|
||
* A revoked subkey is not to be used. Only revocation signatures
|
||
* by the top-level signature key that is bound to this subkey, or
|
||
* by an authorized revocation key, should be considered valid
|
||
* revocation signatures.
|
||
* Key revocation signatures (types 0x20 and 0x28)
|
||
* hash only the key being revoked. */
|
||
subkey_revocation: 40,
|
||
/** 0x40: Timestamp signature.
|
||
* This signature is only meaningful for the timestamp contained in
|
||
* it. */
|
||
timestamp: 64,
|
||
/** 0x50: Third-Party Confirmation signature.
|
||
* This signature is a signature over some other OpenPGP Signature
|
||
* packet(s). It is analogous to a notary seal on the signed data.
|
||
* A third-party signature SHOULD include Signature Target
|
||
* subpacket(s) to give easy identification. Note that we really do
|
||
* mean SHOULD. There are plausible uses for this (such as a blind
|
||
* party that only sees the signature, not the key or source
|
||
* document) that cannot include a target subpacket. */
|
||
third_party: 80
|
||
},
|
||
|
||
signatureSubpacket: {
|
||
signature_creation_time: 2,
|
||
signature_expiration_time: 3,
|
||
exportable_certification: 4,
|
||
trust_signature: 5,
|
||
regular_expression: 6,
|
||
revocable: 7,
|
||
key_expiration_time: 9,
|
||
placeholder_backwards_compatibility: 10,
|
||
preferred_symmetric_algorithms: 11,
|
||
revocation_key: 12,
|
||
issuer: 16,
|
||
notation_data: 20,
|
||
preferred_hash_algorithms: 21,
|
||
preferred_compression_algorithms: 22,
|
||
key_server_preferences: 23,
|
||
preferred_key_server: 24,
|
||
primary_user_id: 25,
|
||
policy_uri: 26,
|
||
key_flags: 27,
|
||
signers_user_id: 28,
|
||
reason_for_revocation: 29,
|
||
features: 30,
|
||
signature_target: 31,
|
||
embedded_signature: 32
|
||
},
|
||
|
||
keyFlags: {
|
||
// 0x01 - This key may be used to certify other keys.
|
||
certify_keys: 1,
|
||
// 0x02 - This key may be used to sign data.
|
||
sign_data: 2,
|
||
// 0x04 - This key may be used to encrypt communications.
|
||
encrypt_communication: 4,
|
||
// 0x08 - This key may be used to encrypt storage.
|
||
encrypt_storage: 8,
|
||
// 0x10 - The private component of this key may have been split
|
||
// by a secret-sharing mechanism.
|
||
split_private_key: 16,
|
||
// 0x20 - This key may be used for authentication.
|
||
authentication: 32,
|
||
// 0x80 - The private component of this key may be in the
|
||
// possession of more than one person.
|
||
shared_private_key: 128
|
||
},
|
||
|
||
armor: {
|
||
multipart_section: 0,
|
||
multipart_last: 1,
|
||
signed: 2,
|
||
message: 3,
|
||
public_key: 4,
|
||
private_key: 5
|
||
},
|
||
|
||
// Asserts validity and converts from string/integer to integer.
|
||
write: function(type, e) {
|
||
if (typeof e == 'number') {
|
||
e = this.read(type, e);
|
||
}
|
||
|
||
if (type[e] !== undefined) {
|
||
return type[e];
|
||
} else throw new Error('Invalid enum value.');
|
||
},
|
||
// Converts from an integer to string.
|
||
read: function(type, e) {
|
||
for (var i in type)
|
||
if (type[i] == e) return i;
|
||
|
||
throw new Error('Invalid enum value.');
|
||
}
|
||
}
|
||
|
||
module.exports = enums;
|
||
|
||
},{}],"h6CH+m":[function(require,module,exports){
|
||
|
||
module.exports = require('./openpgp.js');
|
||
module.exports.key = require('./key.js');
|
||
module.exports.message = require('./message.js');
|
||
module.exports.cleartext = require('./cleartext.js');
|
||
module.exports.util = require('./util');
|
||
module.exports.packet = require('./packet');
|
||
module.exports.mpi = require('./type/mpi.js');
|
||
module.exports.s2k = require('./type/s2k.js');
|
||
module.exports.keyid = require('./type/keyid.js');
|
||
module.exports.armor = require('./encoding/armor.js');
|
||
module.exports.enums = require('./enums.js');
|
||
module.exports.config = require('./config');
|
||
module.exports.crypto = require('./crypto');
|
||
|
||
},{"./cleartext.js":1,"./config":3,"./crypto":16,"./encoding/armor.js":25,"./enums.js":27,"./key.js":30,"./message.js":31,"./openpgp.js":32,"./packet":35,"./type/keyid.js":53,"./type/mpi.js":54,"./type/s2k.js":55,"./util":56}],"openpgp":[function(require,module,exports){
|
||
module.exports=require('h6CH+m');
|
||
},{}],30:[function(require,module,exports){
|
||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||
// Copyright (C) 2011 Recurity Labs GmbH
|
||
//
|
||
// This library is free software; you can redistribute it and/or
|
||
// modify it under the terms of the GNU Lesser General Public
|
||
// License as published by the Free Software Foundation; either
|
||
// version 2.1 of the License, or (at your option) any later version.
|
||
//
|
||
// This library is distributed in the hope that it will be useful,
|
||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
// Lesser General Public License for more details.
|
||
//
|
||
// You should have received a copy of the GNU Lesser General Public
|
||
// License along with this library; if not, write to the Free Software
|
||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||
|
||
var packet = require('./packet');
|
||
var enums = require('./enums.js');
|
||
var armor = require('./encoding/armor.js');
|
||
var config = require('./config');
|
||
|
||
/**
|
||
* @class
|
||
* @classdesc Class that represents an OpenPGP key. Must contain a primary key.
|
||
* Can contain additional subkeys, signatures, user ids, user attributes.
|
||
* @param {packetlist} packetlist The packets that form this key
|
||
*/
|
||
|
||
function Key(packetlist) {
|
||
if (!(this instanceof Key)) {
|
||
return new Key(packetlist);
|
||
}
|
||
this.packets = packetlist || new packet.list();
|
||
}
|
||
|
||
/**
|
||
* Returns the primary key packet (secret or public)
|
||
* @returns {packet_secret_key|packet_public_key|null}
|
||
*/
|
||
Key.prototype.getKeyPacket = function() {
|
||
for (var i = 0; i < this.packets.length; i++) {
|
||
if (this.packets[i].tag == enums.packet.public_key ||
|
||
this.packets[i].tag == enums.packet.secret_key) {
|
||
return this.packets[i];
|
||
}
|
||
}
|
||
return null;
|
||
};
|
||
|
||
/**
|
||
* Returns all the private and public subkey packets
|
||
* @returns {[public_subkey|secret_subkey]}
|
||
*/
|
||
Key.prototype.getSubkeyPackets = function() {
|
||
|
||
var subkeys = [];
|
||
|
||
for (var i = 0; i < this.packets.length; i++) {
|
||
if (this.packets[i].tag == enums.packet.public_subkey ||
|
||
this.packets[i].tag == enums.packet.secret_subkey) {
|
||
subkeys.push(this.packets[i]);
|
||
}
|
||
}
|
||
|
||
return subkeys;
|
||
};
|
||
|
||
/**
|
||
* Returns all the private and public key and subkey packets
|
||
* @returns {[public_subkey|secret_subkey|packet_secret_key|packet_public_key]}
|
||
*/
|
||
Key.prototype.getAllKeyPackets = function() {
|
||
return [this.getKeyPacket()].concat(this.getSubkeyPackets());
|
||
};
|
||
|
||
/**
|
||
* Returns key IDs of all key packets
|
||
* @returns {[keyid]}
|
||
*/
|
||
Key.prototype.getKeyIds = function() {
|
||
var keyIds = [];
|
||
var keys = this.getAllKeyPackets();
|
||
for (var i = 0; i < keys.length; i++) {
|
||
keyIds.push(keys[i].getKeyId());
|
||
}
|
||
return keyIds;
|
||
};
|
||
|
||
function findKey(keys, keyIds) {
|
||
for (var i = 0; i < keys.length; i++) {
|
||
var keyId = keys[i].getKeyId();
|
||
for (var j = 0; j < keyIds.length; j++) {
|
||
if (keyId.equals(keyIds[j])) {
|
||
return keys[i];
|
||
}
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
|
||
/**
|
||
* Returns first public key packet for given array of key IDs
|
||
* @param {[keyid]} keyIds
|
||
* @return {public_subkey|packet_public_key|null}
|
||
*/
|
||
Key.prototype.getPublicKeyPacket = function(keyIds) {
|
||
var keys = this.packets.filterByTag(enums.packet.public_key, enums.packet.public_subkey);
|
||
return findKey(keys, keyIds);
|
||
};
|
||
|
||
/**
|
||
* Returns first private key packet for given array of key IDs
|
||
* @param {[keyid]} keyIds
|
||
* @return {secret_subkey|packet_secret_key|null}
|
||
*/
|
||
Key.prototype.getPrivateKeyPacket = function(keyIds) {
|
||
var keys = this.packets.filterByTag(enums.packet.secret_key, enums.packet.secret_subkey);
|
||
return findKey(keys, keyIds);
|
||
};
|
||
|
||
/**
|
||
* Returns userids
|
||
* @return {string} userid[]
|
||
*/
|
||
Key.prototype.getUserIds = function() {
|
||
var userids = [];
|
||
var useridPackets = this.packets.filterByTag(enums.packet.userid);
|
||
for (var i = 0; i < useridPackets.length; i++) {
|
||
userids.push(useridPackets[i].write());
|
||
}
|
||
return userids;
|
||
};
|
||
|
||
/**
|
||
* Returns true if this is a public key
|
||
* @return {Boolean}
|
||
*/
|
||
Key.prototype.isPublic = function() {
|
||
var publicKeyPackets = this.packets.filterByTag(enums.packet.public_key);
|
||
return publicKeyPackets.length ? true : false;
|
||
};
|
||
|
||
/**
|
||
* Returns true if this is a private key
|
||
* @return {Boolean}
|
||
*/
|
||
Key.prototype.isPrivate = function() {
|
||
var privateKeyPackets = this.packets.filterByTag(enums.packet.private_key);
|
||
return privateKeyPackets.length ? true : false;
|
||
};
|
||
|
||
/**
|
||
* Returns key as public key
|
||
* @return {key} public key
|
||
*/
|
||
Key.prototype.toPublic = function() {
|
||
var packetlist = new packet.list();
|
||
for (var i = 0; i < this.packets.length; i++) {
|
||
switch (this.packets[i].tag) {
|
||
case enums.packet.secret_key:
|
||
var bytes = this.packets[i].writePublicKey();
|
||
var pubKeyPacket = new packet.public_key();
|
||
pubKeyPacket.read(bytes);
|
||
packetlist.push(pubKeyPacket);
|
||
break;
|
||
case enums.packet.secret_subkey:
|
||
var bytes = this.packets[i].writePublicKey();
|
||
var pubSubkeyPacket = new packet.public_subkey();
|
||
pubSubkeyPacket.read(bytes);
|
||
packetlist.push(pubSubkeyPacket);
|
||
break;
|
||
default:
|
||
packetlist.push(this.packets[i]);
|
||
}
|
||
}
|
||
return new Key(packetlist);
|
||
};
|
||
|
||
/**
|
||
* Returns ASCII armored text of key
|
||
* @return {String} ASCII armor
|
||
*/
|
||
Key.prototype.armor = function() {
|
||
var type = this.isPublic() ? enums.armor.public_key : enums.armor.private_key;
|
||
return armor.encode(type, this.packets.write());
|
||
};
|
||
|
||
/**
|
||
* Returns first key packet that is available for signing
|
||
* @return {public_subkey|secret_subkey|packet_secret_key|packet_public_key|null}
|
||
*/
|
||
Key.prototype.getSigningKeyPacket = function() {
|
||
|
||
var signing = [ enums.publicKey.rsa_encrypt_sign, enums.publicKey.rsa_sign, enums.publicKey.dsa];
|
||
|
||
signing = signing.map(function(s) {
|
||
return enums.read(enums.publicKey, s);
|
||
});
|
||
|
||
var keys = this.getAllKeyPackets();
|
||
|
||
for (var i = 0; i < keys.length; i++) {
|
||
if (signing.indexOf(keys[i].algorithm) !== -1) {
|
||
return keys[i];
|
||
}
|
||
}
|
||
|
||
return null;
|
||
};
|
||
|
||
/**
|
||
* Returns preferred signature hash algorithm of this key
|
||
* @return {String}
|
||
*/
|
||
Key.prototype.getPreferredSignatureHashAlgorithm = function() {
|
||
//TODO implement: https://tools.ietf.org/html/rfc4880#section-5.2.3.8
|
||
//separate private key preference from digest preferences
|
||
return config.prefer_hash_algorithm;
|
||
};
|
||
|
||
/**
|
||
* Returns the first valid encryption key packet for this key
|
||
* @returns {public_subkey|secret_subkey|packet_secret_key|packet_public_key|null} key packet or null if no encryption key has been found
|
||
*/
|
||
Key.prototype.getEncryptionKeyPacket = function() {
|
||
// V4: by convention subkeys are prefered for encryption service
|
||
// V3: keys MUST NOT have subkeys
|
||
var isValidEncryptionKey = function(key) {
|
||
//TODO evaluate key flags: http://tools.ietf.org/html/rfc4880#section-5.2.3.21
|
||
return key.algorithm != enums.read(enums.publicKey, enums.publicKey.dsa) && key.algorithm != enums.read(enums.publicKey,
|
||
enums.publicKey.rsa_sign);
|
||
//TODO verify key
|
||
//&& keys.verifyKey()
|
||
};
|
||
|
||
var subkeys = this.getSubkeyPackets();
|
||
|
||
for (var j = 0; j < subkeys.length; j++) {
|
||
if (isValidEncryptionKey(subkeys[j])) {
|
||
return subkeys[j];
|
||
}
|
||
}
|
||
// if no valid subkey for encryption, use primary key
|
||
var primaryKey = this.getKeyPacket();
|
||
if (isValidEncryptionKey(primaryKey)) {
|
||
return primaryKey;
|
||
}
|
||
return null;
|
||
};
|
||
|
||
/**
|
||
* Decrypts all secret key and subkey packets
|
||
* @param {String} passphrase
|
||
* @return {Boolean} true if all key and subkey packets decrypted successfully
|
||
*/
|
||
Key.prototype.decrypt = function(passphrase) {
|
||
var keys = this.packets.filterByTag(enums.packet.secret_key, enums.packet.secret_subkey);
|
||
for (var i = 0; i < keys.length; i++) {
|
||
var success = keys[i].decrypt(passphrase);
|
||
if (!success) return false;
|
||
}
|
||
return true;
|
||
};
|
||
|
||
/**
|
||
* Decrypts specific key packets by key ID
|
||
* @param {[keyid]} keyIds
|
||
* @param {String} passphrase
|
||
* @return {Boolean} true if all key packets decrypted successfully
|
||
*/
|
||
Key.prototype.decryptKeyPacket = function(keyIds, passphrase) {
|
||
//TODO return value
|
||
var keys = this.packets.filterByTag(enums.packet.secret_key, enums.packet.secret_subkey);
|
||
for (var i = 0; i < keys.length; i++) {
|
||
var keyId = keys[i].getKeyId();
|
||
for (var j = 0; j < keyIds.length; j++) {
|
||
if (keyId.equals(keyIds[j])) {
|
||
var success = keys[i].decrypt(passphrase);
|
||
if (!success) return false;
|
||
}
|
||
}
|
||
}
|
||
return true;
|
||
};
|
||
|
||
// TODO
|
||
Key.prototype.verify = function() {
|
||
|
||
};
|
||
// TODO
|
||
Key.prototype.revoke = function() {
|
||
|
||
};
|
||
|
||
/**
|
||
* Reads an OpenPGP armored text and returns a key object
|
||
* @param {String} armoredText text to be parsed
|
||
* @return {key} new key object
|
||
*/
|
||
function readArmored(armoredText) {
|
||
var input = armor.decode(armoredText);
|
||
if (!(input.type == enums.armor.public_key || input.type == enums.armor.private_key)) {
|
||
throw new Error('Armored text not of type key');
|
||
}
|
||
var packetlist = new packet.list();
|
||
packetlist.read(input.data);
|
||
var newKey = new Key(packetlist);
|
||
return newKey;
|
||
}
|
||
|
||
/**
|
||
* Generates a new OpenPGP key. Currently only supports RSA keys.
|
||
* Primary and subkey will be of same type.
|
||
* @param {Integer} keyType to indicate what type of key to make.
|
||
* RSA is 1. See http://tools.ietf.org/html/rfc4880#section-9.1
|
||
* @param {Integer} numBits number of bits for the key creation.
|
||
* @param {String} userId assumes already in form of "User Name <username@email.com>"
|
||
* @param {String} passphrase The passphrase used to encrypt the resulting private key
|
||
* @return {Key}
|
||
*/
|
||
function generate(keyType, numBits, userId, passphrase) {
|
||
var packetlist = new packet.list();
|
||
|
||
var secretKeyPacket = new packet.secret_key();
|
||
secretKeyPacket.algorithm = enums.read(enums.publicKey, keyType);
|
||
secretKeyPacket.generate(numBits);
|
||
secretKeyPacket.encrypt(passphrase);
|
||
|
||
var userIdPacket = new packet.userid();
|
||
userIdPacket.read(userId);
|
||
|
||
var dataToSign = {};
|
||
dataToSign.userid = userIdPacket;
|
||
dataToSign.key = secretKeyPacket;
|
||
var signaturePacket = new packet.signature();
|
||
signaturePacket.signatureType = enums.signature.cert_generic;
|
||
signaturePacket.publicKeyAlgorithm = keyType;
|
||
//TODO we should load preferred hash from config, or as input to this function
|
||
signaturePacket.hashAlgorithm = enums.hash.sha256;
|
||
signaturePacket.keyFlags = [enums.keyFlags.certify_keys | enums.keyFlags.sign_data];
|
||
signaturePacket.sign(secretKeyPacket, dataToSign);
|
||
|
||
var secretSubkeyPacket = new packet.secret_subkey();
|
||
secretSubkeyPacket.algorithm = enums.read(enums.publicKey, keyType);
|
||
secretSubkeyPacket.generate(numBits);
|
||
secretSubkeyPacket.encrypt(passphrase);
|
||
|
||
dataToSign = {};
|
||
dataToSign.key = secretKeyPacket;
|
||
dataToSign.bind = secretSubkeyPacket;
|
||
var subkeySignaturePacket = new packet.signature();
|
||
subkeySignaturePacket.signatureType = enums.signature.subkey_binding;
|
||
subkeySignaturePacket.publicKeyAlgorithm = keyType;
|
||
//TODO we should load preferred hash from config, or as input to this function
|
||
subkeySignaturePacket.hashAlgorithm = enums.hash.sha256;
|
||
subkeySignaturePacket.keyFlags = [enums.keyFlags.encrypt_communication | enums.keyFlags.encrypt_storage];
|
||
subkeySignaturePacket.sign(secretKeyPacket, dataToSign);
|
||
|
||
packetlist.push(secretKeyPacket);
|
||
packetlist.push(userIdPacket);
|
||
packetlist.push(signaturePacket);
|
||
packetlist.push(secretSubkeyPacket);
|
||
packetlist.push(subkeySignaturePacket);
|
||
|
||
return new Key(packetlist);
|
||
}
|
||
|
||
exports.Key = Key;
|
||
exports.readArmored = readArmored;
|
||
exports.generate = generate;
|
||
|
||
},{"./config":3,"./encoding/armor.js":25,"./enums.js":27,"./packet":35}],31:[function(require,module,exports){
|
||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||
// Copyright (C) 2011 Recurity Labs GmbH
|
||
//
|
||
// This library is free software; you can redistribute it and/or
|
||
// modify it under the terms of the GNU Lesser General Public
|
||
// License as published by the Free Software Foundation; either
|
||
// version 2.1 of the License, or (at your option) any later version.
|
||
//
|
||
// This library is distributed in the hope that it will be useful,
|
||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
// Lesser General Public License for more details.
|
||
//
|
||
// You should have received a copy of the GNU Lesser General Public
|
||
// License along with this library; if not, write to the Free Software
|
||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||
|
||
var packet = require('./packet');
|
||
var enums = require('./enums.js');
|
||
var armor = require('./encoding/armor.js');
|
||
var config = require('./config');
|
||
var crypto = require('./crypto');
|
||
var util = require('./util');
|
||
|
||
/**
|
||
* @class
|
||
* @classdesc Class that represents an OpenPGP message.
|
||
* Can be an encrypted message, signed message, compressed message or literal message
|
||
* @param {packetlist} packetlist The packets that form this message
|
||
* See http://tools.ietf.org/html/rfc4880#section-11.3
|
||
*/
|
||
|
||
function Message(packetlist) {
|
||
if (!(this instanceof Message)) {
|
||
return new Message(packetlist);
|
||
}
|
||
this.packets = packetlist || new packet.list();
|
||
}
|
||
|
||
/**
|
||
* Returns the key IDs of the keys to which the session key is encrypted
|
||
* @return {[keyId]} array of keyid objects
|
||
*/
|
||
Message.prototype.getEncryptionKeyIds = function() {
|
||
var keyIds = [];
|
||
var pkESKeyPacketlist = this.packets.filterByTag(enums.packet.public_key_encrypted_session_key);
|
||
pkESKeyPacketlist.forEach(function(packet) {
|
||
keyIds.push(packet.publicKeyId);
|
||
});
|
||
return keyIds;
|
||
};
|
||
|
||
/**
|
||
* Returns the key IDs of the keys that signed the message
|
||
* @return {[keyId]} array of keyid objects
|
||
*/
|
||
Message.prototype.getSigningKeyIds = function() {
|
||
var keyIds = [];
|
||
var msg = this.unwrapCompressed();
|
||
// search for one pass signatures
|
||
var onePassSigList = msg.packets.filterByTag(enums.packet.one_pass_signature);
|
||
onePassSigList.forEach(function(packet) {
|
||
keyIds.push(packet.signingKeyId);
|
||
});
|
||
// if nothing found look for signature packets
|
||
if (!keyIds.length) {
|
||
var signatureList = msg.packets.filterByTag(enums.packet.signature);
|
||
signatureList.forEach(function(packet) {
|
||
keyIds.push(packet.issuerKeyId);
|
||
});
|
||
}
|
||
return keyIds;
|
||
};
|
||
|
||
/**
|
||
* Decrypt the message
|
||
* @param {key} privateKey private key with decrypted secret data
|
||
* @return {[message]} new message with decrypted content
|
||
*/
|
||
Message.prototype.decrypt = function(privateKey) {
|
||
var encryptionKeyIds = this.getEncryptionKeyIds();
|
||
if (!encryptionKeyIds.length) {
|
||
// nothing to decrypt return unmodified message
|
||
return this;
|
||
}
|
||
var privateKeyPacket = privateKey.getPrivateKeyPacket(encryptionKeyIds);
|
||
if (!privateKeyPacket.isDecrypted) throw new Error('Private key is not decrypted.');
|
||
var pkESKeyPacketlist = this.packets.filterByTag(enums.packet.public_key_encrypted_session_key);
|
||
var pkESKeyPacket;
|
||
for (var i = 0; i < pkESKeyPacketlist.length; i++) {
|
||
if (pkESKeyPacketlist[i].publicKeyId.equals(privateKeyPacket.getKeyId())) {
|
||
pkESKeyPacket = pkESKeyPacketlist[i];
|
||
pkESKeyPacket.decrypt(privateKeyPacket);
|
||
break;
|
||
}
|
||
}
|
||
if (pkESKeyPacket) {
|
||
var symEncryptedPacketlist = this.packets.filterByTag(enums.packet.symmetrically_encrypted, enums.packet.sym_encrypted_integrity_protected);
|
||
if (symEncryptedPacketlist.length !== 0) {
|
||
var symEncryptedPacket = symEncryptedPacketlist[0];
|
||
symEncryptedPacket.decrypt(pkESKeyPacket.sessionKeyAlgorithm, pkESKeyPacket.sessionKey);
|
||
return new Message(symEncryptedPacket.packets);
|
||
}
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Get literal data that is the body of the message
|
||
* @return {String|null} literal body of the message as string
|
||
*/
|
||
Message.prototype.getLiteralData = function() {
|
||
var literal = this.packets.findPacket(enums.packet.literal);
|
||
return literal && literal.data || null;
|
||
};
|
||
|
||
/**
|
||
* Get literal data as text
|
||
* @return {String|null} literal body of the message interpreted as text
|
||
*/
|
||
Message.prototype.getText = function() {
|
||
var literal = this.packets.findPacket(enums.packet.literal);
|
||
if (literal) {
|
||
return literal.getText();
|
||
} else {
|
||
return null;
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Encrypt the message
|
||
* @param {[key]} keys array of keys, used to encrypt the message
|
||
* @return {[message]} new message with encrypted content
|
||
*/
|
||
Message.prototype.encrypt = function(keys) {
|
||
var packetlist = new packet.list();
|
||
//TODO get preferred algo from signature
|
||
var sessionKey = crypto.generateSessionKey(enums.read(enums.symmetric, config.encryption_cipher));
|
||
keys.forEach(function(key) {
|
||
var encryptionKeyPacket = key.getEncryptionKeyPacket();
|
||
if (encryptionKeyPacket) {
|
||
var pkESKeyPacket = new packet.public_key_encrypted_session_key();
|
||
pkESKeyPacket.publicKeyId = encryptionKeyPacket.getKeyId();
|
||
pkESKeyPacket.publicKeyAlgorithm = encryptionKeyPacket.algorithm;
|
||
pkESKeyPacket.sessionKey = sessionKey;
|
||
//TODO get preferred algo from signature
|
||
pkESKeyPacket.sessionKeyAlgorithm = enums.read(enums.symmetric, config.encryption_cipher);
|
||
pkESKeyPacket.encrypt(encryptionKeyPacket);
|
||
packetlist.push(pkESKeyPacket);
|
||
}
|
||
});
|
||
var symEncryptedPacket;
|
||
if (config.integrity_protect) {
|
||
symEncryptedPacket = new packet.sym_encrypted_integrity_protected();
|
||
} else {
|
||
symEncryptedPacket = new packet.symmetrically_encrypted();
|
||
}
|
||
symEncryptedPacket.packets = this.packets;
|
||
//TODO get preferred algo from signature
|
||
symEncryptedPacket.encrypt(enums.read(enums.symmetric, config.encryption_cipher), sessionKey);
|
||
packetlist.push(symEncryptedPacket);
|
||
return new Message(packetlist);
|
||
};
|
||
|
||
/**
|
||
* Sign the message (the literal data packet of the message)
|
||
* @param {[key]} privateKey private keys with decrypted secret key data for signing
|
||
* @return {message} new message with signed content
|
||
*/
|
||
Message.prototype.sign = function(privateKeys) {
|
||
|
||
var packetlist = new packet.list();
|
||
|
||
var literalDataPacket = this.packets.findPacket(enums.packet.literal);
|
||
if (!literalDataPacket) throw new Error('No literal data packet to sign.');
|
||
|
||
var literalFormat = enums.write(enums.literal, literalDataPacket.format);
|
||
var signatureType = literalFormat == enums.literal.binary
|
||
? enums.signature.binary : enums.signature.text;
|
||
|
||
for (var i = 0; i < privateKeys.length; i++) {
|
||
var onePassSig = new packet.one_pass_signature();
|
||
onePassSig.type = signatureType;
|
||
//TODO get preferred hashg algo from key signature
|
||
onePassSig.hashAlgorithm = config.prefer_hash_algorithm;
|
||
var signingKeyPacket = privateKeys[i].getSigningKeyPacket();
|
||
onePassSig.publicKeyAlgorithm = signingKeyPacket.algorithm;
|
||
onePassSig.signingKeyId = signingKeyPacket.getKeyId();
|
||
packetlist.push(onePassSig);
|
||
}
|
||
|
||
packetlist.push(literalDataPacket);
|
||
|
||
for (var i = privateKeys.length - 1; i >= 0; i--) {
|
||
var signaturePacket = new packet.signature();
|
||
signaturePacket.signatureType = signatureType;
|
||
signaturePacket.hashAlgorithm = config.prefer_hash_algorithm;
|
||
signaturePacket.publicKeyAlgorithm = signingKeyPacket.algorithm;
|
||
if (!signingKeyPacket.isDecrypted) throw new Error('Private key is not decrypted.');
|
||
signaturePacket.sign(signingKeyPacket, literalDataPacket);
|
||
packetlist.push(signaturePacket);
|
||
}
|
||
|
||
return new Message(packetlist);
|
||
};
|
||
|
||
/**
|
||
* Verify message signatures
|
||
* @param {[key]} publicKeys public keys to verify signatures
|
||
* @return {[{'keyid': keyid, 'valid': Boolean}]} list of signer's keyid and validity of signature
|
||
*/
|
||
Message.prototype.verify = function(publicKeys) {
|
||
var result = [];
|
||
var msg = this.unwrapCompressed();
|
||
var literalDataList = msg.packets.filterByTag(enums.packet.literal);
|
||
if (literalDataList.length !== 1) throw new Error('Can only verify message with one literal data packet.');
|
||
var signatureList = msg.packets.filterByTag(enums.packet.signature);
|
||
publicKeys.forEach(function(pubKey) {
|
||
for (var i = 0; i < signatureList.length; i++) {
|
||
var publicKeyPacket = pubKey.getPublicKeyPacket([signatureList[i].issuerKeyId]);
|
||
if (publicKeyPacket) {
|
||
var verifiedSig = {};
|
||
verifiedSig.keyid = signatureList[i].issuerKeyId;
|
||
verifiedSig.status = signatureList[i].verify(publicKeyPacket, literalDataList[0]);
|
||
result.push(verifiedSig);
|
||
break;
|
||
}
|
||
}
|
||
});
|
||
return result;
|
||
};
|
||
|
||
/**
|
||
* Unwrap compressed message
|
||
* @return {message} message Content of compressed message
|
||
*/
|
||
Message.prototype.unwrapCompressed = function() {
|
||
var compressed = this.packets.filterByTag(enums.packet.compressed);
|
||
if (compressed.length) {
|
||
return new Message(compressed[0].packets);
|
||
} else {
|
||
return this;
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Returns ASCII armored text of message
|
||
* @return {String} ASCII armor
|
||
*/
|
||
Message.prototype.armor = function() {
|
||
return armor.encode(enums.armor.message, this.packets.write());
|
||
};
|
||
|
||
/**
|
||
* reads an OpenPGP armored message and returns a message object
|
||
* @param {String} armoredText text to be parsed
|
||
* @return {message} new message object
|
||
*/
|
||
function readArmored(armoredText) {
|
||
//TODO how do we want to handle bad text? Exception throwing
|
||
//TODO don't accept non-message armored texts
|
||
var input = armor.decode(armoredText).data;
|
||
var packetlist = new packet.list();
|
||
packetlist.read(input);
|
||
var newMessage = new Message(packetlist);
|
||
return newMessage;
|
||
}
|
||
|
||
/**
|
||
* creates new message object from text
|
||
* @param {String} text
|
||
* @return {message} new message object
|
||
*/
|
||
function fromText(text) {
|
||
var literalDataPacket = new packet.literal();
|
||
// text will be converted to UTF8
|
||
literalDataPacket.setText(text);
|
||
var literalDataPacketlist = new packet.list();
|
||
literalDataPacketlist.push(literalDataPacket);
|
||
var newMessage = new Message(literalDataPacketlist);
|
||
return newMessage;
|
||
}
|
||
|
||
/**
|
||
* creates new message object from binary data
|
||
* @param {String} bytes
|
||
* @return {message} new message object
|
||
*/
|
||
function fromBinary(bytes) {
|
||
var literalDataPacket = new packet.literal();
|
||
literalDataPacket.setBytes(bytes, enums.read(enums.literal, enums.literal.binary));
|
||
var literalDataPacketlist = new packet.list();
|
||
literalDataPacketlist.push(literalDataPacket);
|
||
var newMessage = new Message(literalDataPacketlist);
|
||
return newMessage;
|
||
}
|
||
|
||
exports.Message = Message;
|
||
exports.readArmored = readArmored;
|
||
exports.fromText = fromText;
|
||
|
||
},{"./config":3,"./crypto":16,"./encoding/armor.js":25,"./enums.js":27,"./packet":35,"./util":56}],32:[function(require,module,exports){
|
||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||
// Copyright (C) 2011 Recurity Labs GmbH
|
||
//
|
||
// This library is free software; you can redistribute it and/or
|
||
// modify it under the terms of the GNU Lesser General Public
|
||
// License as published by the Free Software Foundation; either
|
||
// version 2.1 of the License, or (at your option) any later version.
|
||
//
|
||
// This library is distributed in the hope that it will be useful,
|
||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
// Lesser General Public License for more details.
|
||
//
|
||
// You should have received a copy of the GNU Lesser General Public
|
||
// License along with this library; if not, write to the Free Software
|
||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||
|
||
/**
|
||
* @fileoverview The openpgp base module should provide all of the functionality
|
||
* to consume the openpgp.js library. All additional classes are documented
|
||
* for extending and developing on top of the base library.
|
||
*/
|
||
|
||
var armor = require('./encoding/armor.js');
|
||
var packet = require('./packet');
|
||
var enums = require('./enums.js');
|
||
var config = require('./config');
|
||
var message = require('./message.js');
|
||
var cleartext = require('./cleartext.js');
|
||
var key = require('./key.js');
|
||
|
||
|
||
/**
|
||
* Encrypts message text with keys
|
||
* @param {[key]} keys array of keys, used to encrypt the message
|
||
* @param {String} text message as native JavaScript string
|
||
* @return {String} encrypted ASCII armored message
|
||
*/
|
||
function encryptMessage(keys, text) {
|
||
var msg = message.fromText(text);
|
||
msg = msg.encrypt(keys);
|
||
var armored = armor.encode(enums.armor.message, msg.packets.write());
|
||
return armored;
|
||
}
|
||
|
||
/**
|
||
* Signs message text and encrypts it
|
||
* @param {[key]} publicKeys array of keys, used to encrypt the message
|
||
* @param {key} privateKey private key with decrypted secret key data for signing
|
||
* @param {String} text message as native JavaScript string
|
||
* @return {String} encrypted ASCII armored message
|
||
*/
|
||
function signAndEncryptMessage(publicKeys, privateKey, text) {
|
||
var msg = message.fromText(text);
|
||
msg = msg.sign([privateKey]);
|
||
msg = msg.encrypt(publicKeys);
|
||
var armored = armor.encode(enums.armor.message, msg.packets.write());
|
||
return armored;
|
||
}
|
||
|
||
/**
|
||
* Decrypts message
|
||
* @param {key} privateKey private key with decrypted secret key data
|
||
* @param {message} message the message object with the encrypted data
|
||
* @return {String|null} decrypted message as as native JavaScript string
|
||
* or null if no literal data found
|
||
*/
|
||
function decryptMessage(privateKey, message) {
|
||
message = message.decrypt(privateKey);
|
||
return message.getText();
|
||
}
|
||
|
||
/**
|
||
* Decrypts message and verifies signatures
|
||
* @param {key} privateKey private key with decrypted secret key data
|
||
* @param {[key]} publicKeys public keys to verify signatures
|
||
* @param {message} message the message object with signed and encrypted data
|
||
* @return {{'text': String, signatures: [{'keyid': keyid, 'status': Boolean}]}}
|
||
* decrypted message as as native JavaScript string
|
||
* with verified signatures or null if no literal data found
|
||
*/
|
||
function decryptAndVerifyMessage(privateKey, publicKeys, message) {
|
||
var result = {};
|
||
message = message.decrypt(privateKey);
|
||
result.text = message.getText();
|
||
if (result.text) {
|
||
result.signatures = message.verify(publicKeys);
|
||
return result;
|
||
}
|
||
return null;
|
||
}
|
||
|
||
/**
|
||
* Signs a cleartext message
|
||
* @param {[Key]} privateKeys private key with decrypted secret key data to sign cleartext
|
||
* @param {String} text cleartext
|
||
* @return {String} ASCII armored message
|
||
*/
|
||
function signClearMessage(privateKeys, text) {
|
||
var cleartextMessage = new cleartext.CleartextMessage(text);
|
||
cleartextMessage.sign(privateKeys);
|
||
return cleartextMessage.armor();
|
||
}
|
||
|
||
/**
|
||
* Verifies signatures of cleartext signed message
|
||
* @param {[Key]} publicKeys public keys to verify signatures
|
||
* @param {CleartextMessage} message cleartext message object with signatures
|
||
* @return {{'text': String, signatures: [{'keyid': keyid, 'status': Boolean}]}}
|
||
* cleartext with status of verified signatures
|
||
*/
|
||
function verifyClearSignedMessage(publicKeys, message) {
|
||
var result = {};
|
||
if (!(message instanceof cleartext.CleartextMessage)) {
|
||
throw new Error('Parameter [message] needs to be of type CleartextMessage.');
|
||
}
|
||
result.text = message.getText();
|
||
result.signatures = message.verify(publicKeys);
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Generates a new OpenPGP key pair. Currently only supports RSA keys.
|
||
* Primary and subkey will be of same type.
|
||
* @param {Integer} keyType to indicate what type of key to make.
|
||
* RSA is 1. See http://tools.ietf.org/html/rfc4880#section-9.1
|
||
* @param {Integer} numBits number of bits for the key creation. (should be 1024+, generally)
|
||
* @param {String} userId assumes already in form of "User Name <username@email.com>"
|
||
* @param {String} passphrase The passphrase used to encrypt the resulting private key
|
||
* @return {Object} {key: [Key], privateKeyArmored: [String], publicKeyArmored: [String]}
|
||
*/
|
||
function generateKeyPair(keyType, numBits, userId, passphrase) {
|
||
var result = {};
|
||
var newKey = key.generate(keyType, numBits, userId, passphrase);
|
||
result.key = newKey;
|
||
result.privateKeyArmored = newKey.armor();
|
||
result.publicKeyArmored = newKey.toPublic().armor();
|
||
return result;
|
||
}
|
||
|
||
exports.encryptMessage = encryptMessage;
|
||
exports.signAndEncryptMessage = signAndEncryptMessage;
|
||
exports.decryptMessage = decryptMessage;
|
||
exports.decryptAndVerifyMessage = decryptAndVerifyMessage
|
||
exports.signClearMessage = signClearMessage;
|
||
exports.verifyClearSignedMessage = verifyClearSignedMessage;
|
||
exports.generateKeyPair = generateKeyPair;
|
||
|
||
},{"./cleartext.js":1,"./config":3,"./encoding/armor.js":25,"./enums.js":27,"./key.js":30,"./message.js":31,"./packet":35}],33:[function(require,module,exports){
|
||
var enums = require('../enums.js');
|
||
|
||
// This is pretty ugly, but browserify needs to have the requires explicitly written.
|
||
module.exports = {
|
||
compressed: require('./compressed.js'),
|
||
sym_encrypted_integrity_protected: require('./sym_encrypted_integrity_protected.js'),
|
||
public_key_encrypted_session_key: require('./public_key_encrypted_session_key.js'),
|
||
sym_encrypted_session_key: require('./sym_encrypted_session_key.js'),
|
||
literal: require('./literal.js'),
|
||
public_key: require('./public_key.js'),
|
||
symmetrically_encrypted: require('./symmetrically_encrypted.js'),
|
||
marker: require('./marker.js'),
|
||
public_subkey: require('./public_subkey.js'),
|
||
user_attribute: require('./user_attribute.js'),
|
||
one_pass_signature: require('./one_pass_signature.js'),
|
||
secret_key: require('./secret_key.js'),
|
||
userid: require('./userid.js'),
|
||
secret_subkey: require('./secret_subkey.js'),
|
||
signature: require('./signature.js'),
|
||
trust: require('./trust.js')
|
||
}
|
||
|
||
for (var i in enums.packet) {
|
||
var packetClass = module.exports[i];
|
||
|
||
if (packetClass != undefined)
|
||
packetClass.prototype.tag = enums.packet[i];
|
||
}
|
||
|
||
},{"../enums.js":27,"./compressed.js":34,"./literal.js":36,"./marker.js":37,"./one_pass_signature.js":38,"./public_key.js":41,"./public_key_encrypted_session_key.js":42,"./public_subkey.js":43,"./secret_key.js":44,"./secret_subkey.js":45,"./signature.js":46,"./sym_encrypted_integrity_protected.js":47,"./sym_encrypted_session_key.js":48,"./symmetrically_encrypted.js":49,"./trust.js":50,"./user_attribute.js":51,"./userid.js":52}],34:[function(require,module,exports){
|
||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||
// Copyright (C) 2011 Recurity Labs GmbH
|
||
//
|
||
// This library is free software; you can redistribute it and/or
|
||
// modify it under the terms of the GNU Lesser General Public
|
||
// License as published by the Free Software Foundation; either
|
||
// version 2.1 of the License, or (at your option) any later version.
|
||
//
|
||
// This library is distributed in the hope that it will be useful,
|
||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
// Lesser General Public License for more details.
|
||
//
|
||
// You should have received a copy of the GNU Lesser General Public
|
||
// License along with this library; if not, write to the Free Software
|
||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||
|
||
var enums = require('../enums.js'),
|
||
JXG = require('../compression/jxg.js'),
|
||
base64 = require('../encoding/base64.js');
|
||
|
||
/**
|
||
* @class
|
||
* @classdesc Implementation of the Compressed Data Packet (Tag 8)
|
||
*
|
||
* RFC4880 5.6:
|
||
* The Compressed Data packet contains compressed data. Typically, this
|
||
* packet is found as the contents of an encrypted packet, or following
|
||
* a Signature or One-Pass Signature packet, and contains a literal data
|
||
* packet.
|
||
*/
|
||
module.exports = function packet_compressed() {
|
||
/** @type {packetlist} */
|
||
this.packets;
|
||
/** @type {compression} */
|
||
this.algorithm = 'uncompressed';
|
||
|
||
this.compressed = null;
|
||
|
||
|
||
/**
|
||
* Parsing function for the packet.
|
||
* @param {String} input Payload of a tag 8 packet
|
||
* @param {Integer} position Position to start reading from the input string
|
||
* @parAM {iNTEGER} LEN lENGTH OF the packet or the remaining length of
|
||
* input at position
|
||
* @return {openpgp_packet_compressed} Object representation
|
||
*/
|
||
this.read = function(bytes) {
|
||
// One octet that gives the algorithm used to compress the packet.
|
||
this.algorithm = enums.read(enums.compression, bytes.charCodeAt(0));
|
||
|
||
// Compressed data, which makes up the remainder of the packet.
|
||
this.compressed = bytes.substr(1);
|
||
|
||
this.decompress();
|
||
}
|
||
|
||
|
||
|
||
this.write = function() {
|
||
if (this.compressed == null)
|
||
this.compress();
|
||
|
||
return String.fromCharCode(enums.write(enums.compression, this.algorithm)) + this.compressed;
|
||
}
|
||
|
||
|
||
/**
|
||
* Decompression method for decompressing the compressed data
|
||
* read by read_packet
|
||
* @return {String} The decompressed data
|
||
*/
|
||
this.decompress = function() {
|
||
var decompressed;
|
||
|
||
switch (this.algorithm) {
|
||
case 'uncompressed':
|
||
decompressed = this.compressed;
|
||
break;
|
||
|
||
case 'zip':
|
||
var compData = this.compressed;
|
||
|
||
var radix = base64.encode(compData).replace(/\n/g, "");
|
||
// no header in this case, directly call deflate
|
||
var jxg_obj = new JXG.Util.Unzip(JXG.Util.Base64.decodeAsArray(radix));
|
||
|
||
decompressed = unescape(jxg_obj.deflate()[0][0]);
|
||
break;
|
||
|
||
case 'zlib':
|
||
//RFC 1950. Bits 0-3 Compression Method
|
||
var compressionMethod = this.compressed.charCodeAt(0) % 0x10;
|
||
|
||
//Bits 4-7 RFC 1950 are LZ77 Window. Generally this value is 7 == 32k window size.
|
||
// 2nd Byte in RFC 1950 is for "FLAGs" Allows for a Dictionary
|
||
// (how is this defined). Basic checksum, and compression level.
|
||
|
||
if (compressionMethod == 8) { //CM 8 is for DEFLATE, RFC 1951
|
||
// remove 4 bytes ADLER32 checksum from the end
|
||
var compData = this.compressed.substring(0, this.compressed.length - 4);
|
||
var radix = base64.encode(compData).replace(/\n/g, "");
|
||
//TODO check ADLER32 checksum
|
||
decompressed = JXG.decompress(radix);
|
||
break;
|
||
|
||
} else {
|
||
util.print_error("Compression algorithm ZLIB only supports " +
|
||
"DEFLATE compression method.");
|
||
}
|
||
break;
|
||
|
||
case 'bzip2':
|
||
// TODO: need to implement this
|
||
throw new Error('Compression algorithm BZip2 [BZ2] is not implemented.');
|
||
break;
|
||
|
||
default:
|
||
throw new Error("Compression algorithm unknown :" + this.alogrithm);
|
||
break;
|
||
}
|
||
|
||
this.packets.read(decompressed);
|
||
}
|
||
|
||
/**
|
||
* Compress the packet data (member decompressedData)
|
||
* @param {Integer} type Algorithm to be used // See RFC 4880 9.3
|
||
* @param {String} data Data to be compressed
|
||
* @return {String} The compressed data stored in attribute compressedData
|
||
*/
|
||
this.compress = function() {
|
||
switch (this.algorithm) {
|
||
|
||
case 'uncompressed':
|
||
// - Uncompressed
|
||
this.compressed = this.packets.write();
|
||
break;
|
||
|
||
case 'zip':
|
||
// - ZIP [RFC1951]
|
||
util.print_error("Compression algorithm ZIP [RFC1951] is not implemented.");
|
||
break;
|
||
|
||
case 'zlib':
|
||
// - ZLIB [RFC1950]
|
||
// TODO: need to implement this
|
||
util.print_error("Compression algorithm ZLIB [RFC1950] is not implemented.");
|
||
break;
|
||
|
||
case 'bzip2':
|
||
// - BZip2 [BZ2]
|
||
// TODO: need to implement this
|
||
util.print_error("Compression algorithm BZip2 [BZ2] is not implemented.");
|
||
break;
|
||
|
||
default:
|
||
util.print_error("Compression algorithm unknown :" + this.type);
|
||
break;
|
||
}
|
||
}
|
||
};
|
||
|
||
},{"../compression/jxg.js":2,"../encoding/base64.js":26,"../enums.js":27}],35:[function(require,module,exports){
|
||
var enums = require('../enums.js');
|
||
|
||
module.exports = {
|
||
list: require('./packetlist.js'),
|
||
};
|
||
|
||
var packets = require('./all_packets.js');
|
||
|
||
for (var i in packets)
|
||
module.exports[i] = packets[i];
|
||
|
||
},{"../enums.js":27,"./all_packets.js":33,"./packetlist.js":40}],36:[function(require,module,exports){
|
||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||
// Copyright (C) 2011 Recurity Labs GmbH
|
||
//
|
||
// This library is free software; you can redistribute it and/or
|
||
// modify it under the terms of the GNU Lesser General Public
|
||
// License as published by the Free Software Foundation; either
|
||
// version 2.1 of the License, or (at your option) any later version.
|
||
//
|
||
// This library is distributed in the hope that it will be useful,
|
||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
// Lesser General Public License for more details.
|
||
//
|
||
// You should have received a copy of the GNU Lesser General Public
|
||
// License along with this library; if not, write to the Free Software
|
||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||
|
||
var util = require('../util'),
|
||
enums = require('../enums.js');
|
||
|
||
/**
|
||
* @class
|
||
* @classdesc Implementation of the Literal Data Packet (Tag 11)
|
||
*
|
||
* RFC4880 5.9: A Literal Data packet contains the body of a message; data that
|
||
* is not to be further interpreted.
|
||
*/
|
||
module.exports = function packet_literal() {
|
||
this.format = 'utf8'; // default format for literal data packets
|
||
this.data = ''; // literal data representation as native JavaScript string or bytes
|
||
this.date = new Date();
|
||
|
||
|
||
/**
|
||
* Set the packet data to a javascript native string, end of line
|
||
* will be normalized to \r\n and by default text is converted to UTF8
|
||
* @param {String} text Any native javascript string
|
||
*/
|
||
this.setText = function(text) {
|
||
// normalize EOL to \r\n
|
||
text = text.replace(/\r/g, '').replace(/\n/g, '\r\n');
|
||
// encode UTF8
|
||
this.data = this.format == 'utf8' ? util.encode_utf8(text) : text;
|
||
}
|
||
|
||
/**
|
||
* Returns literal data packets as native JavaScript string
|
||
* with normalized end of line to \n
|
||
* @return {String} literal data as text
|
||
*/
|
||
this.getText = function() {
|
||
// decode UTF8
|
||
var text = util.decode_utf8(this.data);
|
||
// normalize EOL to \n
|
||
return text.replace(/\r\n/g, '\n');
|
||
}
|
||
|
||
/**
|
||
* Set the packet data to value represented by the provided string of bytes.
|
||
* @param {String} bytes The string of bytes
|
||
* @param {'utf8|'binary'|'text'} format The format of the string of bytes
|
||
*/
|
||
this.setBytes = function(bytes, format) {
|
||
this.format = format;
|
||
this.data = bytes;
|
||
}
|
||
|
||
|
||
/**
|
||
* Get the byte sequence representing the literal packet data
|
||
* @returns {String} A sequence of bytes
|
||
*/
|
||
this.getBytes = function() {
|
||
return this.data;
|
||
}
|
||
|
||
|
||
/**
|
||
* Parsing function for a literal data packet (tag 11).
|
||
*
|
||
* @param {String} input Payload of a tag 11 packet
|
||
* @param {Integer} position
|
||
* Position to start reading from the input string
|
||
* @param {Integer} len
|
||
* Length of the packet or the remaining length of
|
||
* input at position
|
||
* @return {openpgp_packet_encrypteddata} object representation
|
||
*/
|
||
this.read = function(bytes) {
|
||
// - A one-octet field that describes how the data is formatted.
|
||
|
||
var format = enums.read(enums.literal, bytes.charCodeAt(0));
|
||
|
||
var filename_len = bytes.charCodeAt(1);
|
||
this.filename = util.decode_utf8(bytes.substr(2, filename_len));
|
||
|
||
this.date = util.readDate(bytes.substr(2 + filename_len, 4));
|
||
|
||
var data = bytes.substring(6 + filename_len);
|
||
|
||
this.setBytes(data, format);
|
||
}
|
||
|
||
/**
|
||
* Creates a string representation of the packet
|
||
*
|
||
* @param {String} data The data to be inserted as body
|
||
* @return {String} string-representation of the packet
|
||
*/
|
||
this.write = function() {
|
||
var filename = util.encode_utf8("msg.txt");
|
||
|
||
var data = this.getBytes();
|
||
|
||
var result = '';
|
||
result += String.fromCharCode(enums.write(enums.literal, this.format));
|
||
result += String.fromCharCode(filename.length);
|
||
result += filename;
|
||
result += util.writeDate(this.date);
|
||
result += data;
|
||
return result;
|
||
}
|
||
}
|
||
|
||
},{"../enums.js":27,"../util":56}],37:[function(require,module,exports){
|
||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||
// Copyright (C) 2011 Recurity Labs GmbH
|
||
//
|
||
// This library is free software; you can redistribute it and/or
|
||
// modify it under the terms of the GNU Lesser General Public
|
||
// License as published by the Free Software Foundation; either
|
||
// version 2.1 of the License, or (at your option) any later version.
|
||
//
|
||
// This library is distributed in the hope that it will be useful,
|
||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
// Lesser General Public License for more details.
|
||
//
|
||
// You should have received a copy of the GNU Lesser General Public
|
||
// License along with this library; if not, write to the Free Software
|
||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||
|
||
/**
|
||
* @class
|
||
* @classdesc Implementation of the strange "Marker packet" (Tag 10)
|
||
*
|
||
* RFC4880 5.8: An experimental version of PGP used this packet as the Literal
|
||
* packet, but no released version of PGP generated Literal packets with this
|
||
* tag. With PGP 5.x, this packet has been reassigned and is reserved for use as
|
||
* the Marker packet.
|
||
*
|
||
* Such a packet MUST be ignored when received.
|
||
*/
|
||
function packet_marker() {
|
||
/**
|
||
* Parsing function for a literal data packet (tag 10).
|
||
*
|
||
* @param {String} input Payload of a tag 10 packet
|
||
* @param {Integer} position
|
||
* Position to start reading from the input string
|
||
* @param {Integer} len
|
||
* Length of the packet or the remaining length of
|
||
* input at position
|
||
* @return {openpgp_packet_encrypteddata} Object representation
|
||
*/
|
||
this.read = function(bytes) {
|
||
if (bytes.charCodeAt(0) == 0x50 && // P
|
||
bytes.charCodeAt(1) == 0x47 && // G
|
||
bytes.charCodeAt(2) == 0x50) // P
|
||
return true;
|
||
// marker packet does not contain "PGP"
|
||
return false;
|
||
}
|
||
}
|
||
|
||
module.exports = packet_marker;
|
||
|
||
},{}],38:[function(require,module,exports){
|
||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||
// Copyright (C) 2011 Recurity Labs GmbH
|
||
//
|
||
// This library is free software; you can redistribute it and/or
|
||
// modify it under the terms of the GNU Lesser General Public
|
||
// License as published by the Free Software Foundation; either
|
||
// version 2.1 of the License, or (at your option) any later version.
|
||
//
|
||
// This library is distributed in the hope that it will be useful,
|
||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
// Lesser General Public License for more details.
|
||
//
|
||
// You should have received a copy of the GNU Lesser General Public
|
||
// License along with this library; if not, write to the Free Software
|
||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||
|
||
/**
|
||
* @class
|
||
* @classdesc Implementation of the One-Pass Signature Packets (Tag 4)
|
||
*
|
||
* RFC4880 5.4:
|
||
* The One-Pass Signature packet precedes the signed data and contains
|
||
* enough information to allow the receiver to begin calculating any
|
||
* hashes needed to verify the signature. It allows the Signature
|
||
* packet to be placed at the end of the message, so that the signer
|
||
* can compute the entire signed message in one pass.
|
||
*/
|
||
|
||
var enums = require('../enums.js'),
|
||
type_keyid = require('../type/keyid.js');
|
||
|
||
module.exports = function packet_one_pass_signature() {
|
||
this.version = null; // A one-octet version number. The current version is 3.
|
||
this.type = null; // A one-octet signature type. Signature types are described in RFC4880 Section 5.2.1.
|
||
this.hashAlgorithm = null; // A one-octet number describing the hash algorithm used. (See RFC4880 9.4)
|
||
this.publicKeyAlgorithm = null; // A one-octet number describing the public-key algorithm used. (See RFC4880 9.1)
|
||
this.signingKeyId = null; // An eight-octet number holding the Key ID of the signing key.
|
||
this.flags = null; // A one-octet number holding a flag showing whether the signature is nested. A zero value indicates that the next packet is another One-Pass Signature packet that describes another signature to be applied to the same message data.
|
||
|
||
/**
|
||
* parsing function for a one-pass signature packet (tag 4).
|
||
* @param {String} bytes payload of a tag 4 packet
|
||
* @return {packet_one_pass_signature} object representation
|
||
*/
|
||
this.read = function(bytes) {
|
||
var mypos = 0;
|
||
// A one-octet version number. The current version is 3.
|
||
this.version = bytes.charCodeAt(mypos++);
|
||
|
||
// A one-octet signature type. Signature types are described in
|
||
// Section 5.2.1.
|
||
this.type = enums.read(enums.signature, bytes.charCodeAt(mypos++));
|
||
|
||
// A one-octet number describing the hash algorithm used.
|
||
this.hashAlgorithm = enums.read(enums.hash, bytes.charCodeAt(mypos++));
|
||
|
||
// A one-octet number describing the public-key algorithm used.
|
||
this.publicKeyAlgorithm = enums.read(enums.publicKey, bytes.charCodeAt(mypos++));
|
||
|
||
// An eight-octet number holding the Key ID of the signing key.
|
||
this.signingKeyId = new type_keyid();
|
||
this.signingKeyId.read(bytes.substr(mypos));
|
||
mypos += 8;
|
||
|
||
// A one-octet number holding a flag showing whether the signature
|
||
// is nested. A zero value indicates that the next packet is
|
||
// another One-Pass Signature packet that describes another
|
||
// signature to be applied to the same message data.
|
||
this.flags = bytes.charCodeAt(mypos++);
|
||
return this;
|
||
}
|
||
|
||
/**
|
||
* creates a string representation of a one-pass signature packet
|
||
* @return {String} a string representation of a one-pass signature packet
|
||
*/
|
||
this.write = function() {
|
||
var result = "";
|
||
|
||
result += String.fromCharCode(3);
|
||
result += String.fromCharCode(enums.write(enums.signature, this.type));
|
||
result += String.fromCharCode(enums.write(enums.hash, this.hashAlgorithm));
|
||
result += String.fromCharCode(enums.write(enums.publicKey, this.publicKeyAlgorithm));
|
||
result += this.signingKeyId.write();
|
||
result += String.fromCharCode(this.flags);
|
||
|
||
return result;
|
||
}
|
||
};
|
||
|
||
},{"../enums.js":27,"../type/keyid.js":53}],39:[function(require,module,exports){
|
||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||
// Copyright (C) 2011 Recurity Labs GmbH
|
||
//
|
||
// This library is free software; you can redistribute it and/or
|
||
// modify it under the terms of the GNU Lesser General Public
|
||
// License as published by the Free Software Foundation; either
|
||
// version 2.1 of the License, or (at your option) any later version.
|
||
//
|
||
// This library is distributed in the hope that it will be useful,
|
||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
// Lesser General Public License for more details.
|
||
//
|
||
// You should have received a copy of the GNU Lesser General Public
|
||
// License along with this library; if not, write to the Free Software
|
||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||
|
||
var enums = require('../enums.js'),
|
||
util = require('../util');
|
||
|
||
|
||
module.exports = {
|
||
readSimpleLength: function(bytes) {
|
||
var len = 0,
|
||
offset,
|
||
type = bytes.charCodeAt(0);
|
||
|
||
|
||
if (type < 192) {
|
||
len = bytes.charCodeAt(0);
|
||
offset = 1;
|
||
} else if (type < 255) {
|
||
len = ((bytes.charCodeAt(0) - 192) << 8) + (bytes.charCodeAt(1)) + 192;
|
||
offset = 2;
|
||
} else if (type == 255) {
|
||
len = util.readNumber(bytes.substr(1, 4));
|
||
offset = 5;
|
||
}
|
||
|
||
return {
|
||
len: len,
|
||
offset: offset
|
||
};
|
||
},
|
||
|
||
/**
|
||
* Encodes a given integer of length to the openpgp length specifier to a
|
||
* string
|
||
*
|
||
* @param {Integer} length The length to encode
|
||
* @return {String} String with openpgp length representation
|
||
*/
|
||
writeSimpleLength: function(length) {
|
||
var result = "";
|
||
if (length < 192) {
|
||
result += String.fromCharCode(length);
|
||
} else if (length > 191 && length < 8384) {
|
||
/*
|
||
* let a = (total data packet length) - 192 let bc = two octet
|
||
* representation of a let d = b + 192
|
||
*/
|
||
result += String.fromCharCode(((length - 192) >> 8) + 192);
|
||
result += String.fromCharCode((length - 192) & 0xFF);
|
||
} else {
|
||
result += String.fromCharCode(255);
|
||
result += util.writeNumber(length, 4);
|
||
}
|
||
return result;
|
||
},
|
||
|
||
/**
|
||
* Writes a packet header version 4 with the given tag_type and length to a
|
||
* string
|
||
*
|
||
* @param {Integer} tag_type Tag type
|
||
* @param {Integer} length Length of the payload
|
||
* @return {String} String of the header
|
||
*/
|
||
writeHeader: function(tag_type, length) {
|
||
/* we're only generating v4 packet headers here */
|
||
var result = "";
|
||
result += String.fromCharCode(0xC0 | tag_type);
|
||
result += this.writeSimpleLength(length);
|
||
return result;
|
||
},
|
||
|
||
/**
|
||
* Writes a packet header Version 3 with the given tag_type and length to a
|
||
* string
|
||
*
|
||
* @param {Integer} tag_type Tag type
|
||
* @param {Integer} length Length of the payload
|
||
* @return {String} String of the header
|
||
*/
|
||
writeOldHeader: function(tag_type, length) {
|
||
var result = "";
|
||
if (length < 256) {
|
||
result += String.fromCharCode(0x80 | (tag_type << 2));
|
||
result += String.fromCharCode(length);
|
||
} else if (length < 65536) {
|
||
result += String.fromCharCode(0x80 | (tag_type << 2) | 1);
|
||
result += util.writeNumber(length, 2);
|
||
} else {
|
||
result += String.fromCharCode(0x80 | (tag_type << 2) | 2);
|
||
result += util.writeNumber(length, 4);
|
||
}
|
||
return result;
|
||
},
|
||
|
||
/**
|
||
* Generic static Packet Parser function
|
||
*
|
||
* @param {String} input Input stream as string
|
||
* @param {integer} position Position to start parsing
|
||
* @param {integer} len Length of the input from position on
|
||
* @return {Object} Returns a parsed openpgp_packet
|
||
*/
|
||
read: function(input, position, len) {
|
||
// some sanity checks
|
||
if (input == null || input.length <= position || input.substring(position).length < 2 || (input.charCodeAt(position) &
|
||
0x80) == 0) {
|
||
util
|
||
.print_error("Error during parsing. This message / key is probably not containing a valid OpenPGP format.");
|
||
return null;
|
||
}
|
||
var mypos = position;
|
||
var tag = -1;
|
||
var format = -1;
|
||
var packet_length;
|
||
|
||
format = 0; // 0 = old format; 1 = new format
|
||
if ((input.charCodeAt(mypos) & 0x40) != 0) {
|
||
format = 1;
|
||
}
|
||
|
||
var packet_length_type;
|
||
if (format) {
|
||
// new format header
|
||
tag = input.charCodeAt(mypos) & 0x3F; // bit 5-0
|
||
} else {
|
||
// old format header
|
||
tag = (input.charCodeAt(mypos) & 0x3F) >> 2; // bit 5-2
|
||
packet_length_type = input.charCodeAt(mypos) & 0x03; // bit 1-0
|
||
}
|
||
|
||
// header octet parsing done
|
||
mypos++;
|
||
|
||
// parsed length from length field
|
||
var bodydata = null;
|
||
|
||
// used for partial body lengths
|
||
var real_packet_length = -1;
|
||
if (!format) {
|
||
// 4.2.1. Old Format Packet Lengths
|
||
switch (packet_length_type) {
|
||
case 0:
|
||
// The packet has a one-octet length. The header is 2 octets
|
||
// long.
|
||
packet_length = input.charCodeAt(mypos++);
|
||
break;
|
||
case 1:
|
||
// The packet has a two-octet length. The header is 3 octets
|
||
// long.
|
||
packet_length = (input.charCodeAt(mypos++) << 8) | input.charCodeAt(mypos++);
|
||
break;
|
||
case 2:
|
||
// The packet has a four-octet length. The header is 5
|
||
// octets long.
|
||
packet_length = (input.charCodeAt(mypos++) << 24) | (input.charCodeAt(mypos++) << 16) | (input.charCodeAt(mypos++) <<
|
||
8) | input.charCodeAt(mypos++);
|
||
break;
|
||
default:
|
||
// 3 - The packet is of indeterminate length. The header is 1
|
||
// octet long, and the implementation must determine how long
|
||
// the packet is. If the packet is in a file, this means that
|
||
// the packet extends until the end of the file. In general,
|
||
// an implementation SHOULD NOT use indeterminate-length
|
||
// packets except where the end of the data will be clear
|
||
// from the context, and even then it is better to use a
|
||
// definite length, or a new format header. The new format
|
||
// headers described below have a mechanism for precisely
|
||
// encoding data of indeterminate length.
|
||
packet_length = len;
|
||
break;
|
||
}
|
||
|
||
} else // 4.2.2. New Format Packet Lengths
|
||
{
|
||
|
||
// 4.2.2.1. One-Octet Lengths
|
||
if (input.charCodeAt(mypos) < 192) {
|
||
packet_length = input.charCodeAt(mypos++);
|
||
util.print_debug("1 byte length:" + packet_length);
|
||
// 4.2.2.2. Two-Octet Lengths
|
||
} else if (input.charCodeAt(mypos) >= 192 && input.charCodeAt(mypos) < 224) {
|
||
packet_length = ((input.charCodeAt(mypos++) - 192) << 8) + (input.charCodeAt(mypos++)) + 192;
|
||
util.print_debug("2 byte length:" + packet_length);
|
||
// 4.2.2.4. Partial Body Lengths
|
||
} else if (input.charCodeAt(mypos) > 223 && input.charCodeAt(mypos) < 255) {
|
||
packet_length = 1 << (input.charCodeAt(mypos++) & 0x1F);
|
||
util.print_debug("4 byte length:" + packet_length);
|
||
// EEEK, we're reading the full data here...
|
||
var mypos2 = mypos + packet_length;
|
||
bodydata = input.substring(mypos, mypos + packet_length);
|
||
while (true) {
|
||
if (input.charCodeAt(mypos2) < 192) {
|
||
var tmplen = input.charCodeAt(mypos2++);
|
||
packet_length += tmplen;
|
||
bodydata += input.substring(mypos2, mypos2 + tmplen);
|
||
mypos2 += tmplen;
|
||
break;
|
||
} else if (input.charCodeAt(mypos2) >= 192 && input.charCodeAt(mypos2) < 224) {
|
||
var tmplen = ((input.charCodeAt(mypos2++) - 192) << 8) + (input.charCodeAt(mypos2++)) + 192;
|
||
packet_length += tmplen;
|
||
bodydata += input.substring(mypos2, mypos2 + tmplen);
|
||
mypos2 += tmplen;
|
||
break;
|
||
} else if (input.charCodeAt(mypos2) > 223 && input.charCodeAt(mypos2) < 255) {
|
||
var tmplen = 1 << (input.charCodeAt(mypos2++) & 0x1F);
|
||
packet_length += tmplen;
|
||
bodydata += input.substring(mypos2, mypos2 + tmplen);
|
||
mypos2 += tmplen;
|
||
} else {
|
||
mypos2++;
|
||
var tmplen = (input.charCodeAt(mypos2++) << 24) | (input.charCodeAt(mypos2++) << 16) | (input[mypos2++]
|
||
.charCodeAt() << 8) | input.charCodeAt(mypos2++);
|
||
bodydata += input.substring(mypos2, mypos2 + tmplen);
|
||
packet_length += tmplen;
|
||
mypos2 += tmplen;
|
||
break;
|
||
}
|
||
}
|
||
real_packet_length = mypos2;
|
||
// 4.2.2.3. Five-Octet Lengths
|
||
} else {
|
||
mypos++;
|
||
packet_length = (input.charCodeAt(mypos++) << 24) | (input.charCodeAt(mypos++) << 16) | (input.charCodeAt(mypos++) <<
|
||
8) | input.charCodeAt(mypos++);
|
||
}
|
||
}
|
||
|
||
// if there was'nt a partial body length: use the specified
|
||
// packet_length
|
||
if (real_packet_length == -1) {
|
||
real_packet_length = packet_length;
|
||
}
|
||
|
||
if (bodydata == null) {
|
||
bodydata = input.substring(mypos, mypos + real_packet_length);
|
||
}
|
||
|
||
return {
|
||
tag: tag,
|
||
packet: bodydata,
|
||
offset: mypos + real_packet_length
|
||
};
|
||
}
|
||
}
|
||
|
||
},{"../enums.js":27,"../util":56}],40:[function(require,module,exports){
|
||
var packetParser = require('./packet.js'),
|
||
packets = require('./all_packets.js'),
|
||
enums = require('../enums.js');
|
||
|
||
/**
|
||
* @class
|
||
* @classdesc This class represents a list of openpgp packets.
|
||
* Take care when iterating over it - the packets themselves
|
||
* are stored as numerical indices.
|
||
*/
|
||
module.exports = function packetlist() {
|
||
/** The number of packets contained within the list.
|
||
* @readonly
|
||
* @type {Integer} */
|
||
this.length = 0;
|
||
|
||
/**
|
||
* Reads a stream of binary data and interprents it as a list of packets.
|
||
* @param {openpgp_bytearray} An array of bytes.
|
||
*/
|
||
this.read = function(bytes) {
|
||
var i = 0;
|
||
|
||
while (i < bytes.length) {
|
||
var parsed = packetParser.read(bytes, i, bytes.length - i);
|
||
i = parsed.offset;
|
||
|
||
var tag = enums.read(enums.packet, parsed.tag);
|
||
var packet = new packets[tag]();
|
||
|
||
this.push(packet);
|
||
|
||
packet.read(parsed.packet);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Creates a binary representation of openpgp objects contained within the
|
||
* class instance.
|
||
* @returns {openpgp_bytearray} An array of bytes containing valid openpgp packets.
|
||
*/
|
||
this.write = function() {
|
||
var bytes = '';
|
||
|
||
for (var i = 0; i < this.length; i++) {
|
||
var packetbytes = this[i].write();
|
||
bytes += packetParser.writeHeader(this[i].tag, packetbytes.length);
|
||
bytes += packetbytes;
|
||
}
|
||
|
||
return bytes;
|
||
}
|
||
|
||
/**
|
||
* Adds a packet to the list. This is the only supported method of doing so;
|
||
* writing to packetlist[i] directly will result in an error.
|
||
*/
|
||
this.push = function(packet) {
|
||
packet.packets = packet.packets || new packetlist();
|
||
|
||
this[this.length] = packet;
|
||
this.length++;
|
||
}
|
||
|
||
/**
|
||
* Creates a new packetList with all packets that pass the test implemented by the provided function.
|
||
*/
|
||
this.filter = function(callback) {
|
||
|
||
var filtered = new packetlist();
|
||
|
||
for (var i = 0; i < this.length; i++) {
|
||
if (callback(this[i], i, this)) {
|
||
filtered.push(this[i]);
|
||
}
|
||
}
|
||
|
||
return filtered;
|
||
}
|
||
|
||
/**
|
||
* Creates a new packetList with all packets from the given types
|
||
*/
|
||
this.filterByTag = function() {
|
||
var args = Array.prototype.slice.call(arguments);
|
||
var filtered = new packetlist();
|
||
var that = this;
|
||
|
||
for (var i = 0; i < this.length; i++) {
|
||
if (args.some(function(packetType) {return that[i].tag == packetType})) {
|
||
filtered.push(this[i]);
|
||
}
|
||
}
|
||
|
||
return filtered;
|
||
}
|
||
|
||
/**
|
||
* Executes the provided callback once for each element
|
||
*/
|
||
this.forEach = function(callback) {
|
||
for (var i = 0; i < this.length; i++) {
|
||
callback(this[i]);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Traverses packet tree and returns first matching packet
|
||
* @param {enums.packet} type The packet type
|
||
* @return {packet|null}
|
||
*/
|
||
this.findPacket = function(type) {
|
||
var packetlist = this.filterByTag(type);
|
||
if (packetlist.length) {
|
||
return packetlist[0];
|
||
} else {
|
||
var found = null;
|
||
for (var i = 0; i < this.length; i++) {
|
||
if (this[i].packets.length) {
|
||
found = this[i].packets.findPacket(type);
|
||
if (found) return found;
|
||
}
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
|
||
}
|
||
|
||
},{"../enums.js":27,"./all_packets.js":33,"./packet.js":39}],41:[function(require,module,exports){
|
||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||
// Copyright (C) 2011 Recurity Labs GmbH
|
||
//
|
||
// This library is free software; you can redistribute it and/or
|
||
// modify it under the terms of the GNU Lesser General Public
|
||
// License as published by the Free Software Foundation; either
|
||
// version 2.1 of the License, or (at your option) any later version.
|
||
//
|
||
// This library is distributed in the hope that it will be useful,
|
||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
// Lesser General Public License for more details.
|
||
//
|
||
// You should have received a copy of the GNU Lesser General Public
|
||
// License along with this library; if not, write to the Free Software
|
||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||
|
||
var util = require('../util'),
|
||
type_mpi = require('../type/mpi.js'),
|
||
type_keyid = require('../type/keyid.js'),
|
||
enums = require('../enums.js'),
|
||
crypto = require('../crypto');
|
||
|
||
/**
|
||
* @class
|
||
* @classdesc Implementation of the Key Material Packet (Tag 5,6,7,14)
|
||
*
|
||
* RFC4480 5.5:
|
||
* A key material packet contains all the information about a public or
|
||
* private key. There are four variants of this packet type, and two
|
||
* major versions. Consequently, this section is complex.
|
||
*/
|
||
module.exports = function packet_public_key() {
|
||
/** Key creation date.
|
||
* @type {Date} */
|
||
this.created = new Date();
|
||
/** A list of multiprecision integers
|
||
* @type {openpgp_type_mpi} */
|
||
this.mpi = [];
|
||
/** Public key algorithm
|
||
* @type {openpgp.publickey} */
|
||
this.algorithm = 'rsa_sign';
|
||
|
||
|
||
/**
|
||
* Internal Parser for public keys as specified in RFC 4880 section
|
||
* 5.5.2 Public-Key Packet Formats
|
||
* called by read_tag<num>
|
||
* @param {String} input Input string to read the packet from
|
||
* @param {Integer} position Start position for the parser
|
||
* @param {Integer} len Length of the packet or remaining length of input
|
||
* @return {Object} This object with attributes set by the parser
|
||
*/
|
||
this.readPublicKey = this.read = function(bytes) {
|
||
// A one-octet version number (3 or 4).
|
||
var version = bytes.charCodeAt(0);
|
||
|
||
if (version == 4) {
|
||
// - A four-octet number denoting the time that the key was created.
|
||
this.created = util.readDate(bytes.substr(1, 4));
|
||
|
||
// - A one-octet number denoting the public-key algorithm of this key.
|
||
this.algorithm = enums.read(enums.publicKey, bytes.charCodeAt(5));
|
||
|
||
var mpicount = crypto.getPublicMpiCount(this.algorithm);
|
||
this.mpi = [];
|
||
|
||
var bmpi = bytes.substr(6);
|
||
var p = 0;
|
||
|
||
for (var i = 0; i < mpicount && p < bmpi.length; i++) {
|
||
|
||
this.mpi[i] = new type_mpi();
|
||
|
||
p += this.mpi[i].read(bmpi.substr(p))
|
||
|
||
if (p > bmpi.length)
|
||
util.print_error("openpgp.packet.keymaterial.js\n" + 'error reading MPI @:' + p);
|
||
}
|
||
|
||
return p + 6;
|
||
} else {
|
||
throw new Error('Version ' + version + ' of the key packet is unsupported.');
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Same as write_private_key, but has less information because of
|
||
* public key.
|
||
* @param {Integer} keyType Follows the OpenPGP algorithm standard,
|
||
* IE 1 corresponds to RSA.
|
||
* @param {RSA.keyObject} key
|
||
* @param timePacket
|
||
* @return {Object} {body: [string]OpenPGP packet body contents,
|
||
* header: [string] OpenPGP packet header, string: [string] header+body}
|
||
*/
|
||
this.writePublicKey = this.write = function() {
|
||
// Version
|
||
var result = String.fromCharCode(4);
|
||
result += util.writeDate(this.created);
|
||
result += String.fromCharCode(enums.write(enums.publicKey, this.algorithm));
|
||
|
||
var mpicount = crypto.getPublicMpiCount(this.algorithm);
|
||
|
||
for (var i = 0; i < mpicount; i++) {
|
||
result += this.mpi[i].write();
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
// Write an old version packet - it's used by some of the internal routines.
|
||
this.writeOld = function() {
|
||
var bytes = this.writePublicKey();
|
||
|
||
return String.fromCharCode(0x99) +
|
||
util.writeNumber(bytes.length, 2) +
|
||
bytes;
|
||
}
|
||
|
||
/**
|
||
* Calculates the key id of the key
|
||
* @return {String} A 8 byte key id
|
||
*/
|
||
this.getKeyId = function() {
|
||
var keyid = new type_keyid();
|
||
keyid.read(this.getFingerprint().substr(12, 8));
|
||
return keyid;
|
||
}
|
||
|
||
/**
|
||
* Calculates the fingerprint of the key
|
||
* @return {String} A string containing the fingerprint
|
||
*/
|
||
this.getFingerprint = function() {
|
||
var toHash = this.writeOld();
|
||
return crypto.hash.sha1(toHash, toHash.length);
|
||
}
|
||
|
||
}
|
||
|
||
},{"../crypto":16,"../enums.js":27,"../type/keyid.js":53,"../type/mpi.js":54,"../util":56}],42:[function(require,module,exports){
|
||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||
// Copyright (C) 2011 Recurity Labs GmbH
|
||
//
|
||
// This library is free software; you can redistribute it and/or
|
||
// modify it under the terms of the GNU Lesser General Public
|
||
// License as published by the Free Software Foundation; either
|
||
// version 2.1 of the License, or (at your option) any later version.
|
||
//
|
||
// This library is distributed in the hope that it will be useful,
|
||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
// Lesser General Public License for more details.
|
||
//
|
||
// You should have received a copy of the GNU Lesser General Public
|
||
// License along with this library; if not, write to the Free Software
|
||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||
|
||
var type_keyid = require('../type/keyid.js'),
|
||
util = require('../util'),
|
||
type_mpi = require('../type/mpi.js'),
|
||
enums = require('../enums.js'),
|
||
crypto = require('../crypto');
|
||
|
||
|
||
/**
|
||
* @class
|
||
* @classdesc Public-Key Encrypted Session Key Packets (Tag 1)
|
||
*
|
||
* RFC4880 5.1: A Public-Key Encrypted Session Key packet holds the session key
|
||
* used to encrypt a message. Zero or more Public-Key Encrypted Session Key
|
||
* packets and/or Symmetric-Key Encrypted Session Key packets may precede a
|
||
* Symmetrically Encrypted Data Packet, which holds an encrypted message. The
|
||
* message is encrypted with the session key, and the session key is itself
|
||
* encrypted and stored in the Encrypted Session Key packet(s). The
|
||
* Symmetrically Encrypted Data Packet is preceded by one Public-Key Encrypted
|
||
* Session Key packet for each OpenPGP key to which the message is encrypted.
|
||
* The recipient of the message finds a session key that is encrypted to their
|
||
* public key, decrypts the session key, and then uses the session key to
|
||
* decrypt the message.
|
||
*/
|
||
module.exports = function packet_public_key_encrypted_session_key() {
|
||
this.version = 3;
|
||
|
||
this.publicKeyId = new type_keyid();
|
||
this.publicKeyAlgorithm = 'rsa_encrypt';
|
||
|
||
this.sessionKey = null;
|
||
this.sessionKeyAlgorithm = 'aes256';
|
||
|
||
/** @type {openpgp_type_mpi[]} */
|
||
this.encrypted = [];
|
||
|
||
/**
|
||
* Parsing function for a publickey encrypted session key packet (tag 1).
|
||
*
|
||
* @param {String} input Payload of a tag 1 packet
|
||
* @param {Integer} position Position to start reading from the input string
|
||
* @param {Integer} len Length of the packet or the remaining length of
|
||
* input at position
|
||
* @return {openpgp_packet_encrypteddata} Object representation
|
||
*/
|
||
this.read = function(bytes) {
|
||
|
||
this.version = bytes.charCodeAt(0);
|
||
this.publicKeyId.read(bytes.substr(1));
|
||
this.publicKeyAlgorithm = enums.read(enums.publicKey, bytes.charCodeAt(9));
|
||
|
||
var i = 10;
|
||
|
||
var integerCount = (function(algo) {
|
||
switch (algo) {
|
||
case 'rsa_encrypt':
|
||
case 'rsa_encrypt_sign':
|
||
return 1;
|
||
|
||
case 'elgamal':
|
||
return 2;
|
||
|
||
default:
|
||
throw new Error("Invalid algorithm.");
|
||
}
|
||
})(this.publicKeyAlgorithm);
|
||
|
||
this.encrypted = [];
|
||
|
||
for (var j = 0; j < integerCount; j++) {
|
||
var mpi = new type_mpi();
|
||
i += mpi.read(bytes.substr(i));
|
||
this.encrypted.push(mpi);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Create a string representation of a tag 1 packet
|
||
*
|
||
* @param {String} publicKeyId
|
||
* The public key id corresponding to publicMPIs key as string
|
||
* @param {openpgp_type_mpi[]} publicMPIs
|
||
* Multiprecision integer objects describing the public key
|
||
* @param {Integer} pubalgo
|
||
* The corresponding public key algorithm // See RFC4880 9.1
|
||
* @param {Integer} symmalgo
|
||
* The symmetric cipher algorithm used to encrypt the data
|
||
* within an encrypteddatapacket or encryptedintegrity-
|
||
* protecteddatapacket
|
||
* following this packet //See RFC4880 9.2
|
||
* @param {String} sessionkey
|
||
* A string of randombytes representing the session key
|
||
* @return {String} The string representation
|
||
*/
|
||
this.write = function() {
|
||
|
||
var result = String.fromCharCode(this.version);
|
||
result += this.publicKeyId.write();
|
||
result += String.fromCharCode(
|
||
enums.write(enums.publicKey, this.publicKeyAlgorithm));
|
||
|
||
for (var i = 0; i < this.encrypted.length; i++) {
|
||
result += this.encrypted[i].write()
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
this.encrypt = function(key) {
|
||
var data = String.fromCharCode(
|
||
enums.write(enums.symmetric, this.sessionKeyAlgorithm));
|
||
|
||
data += this.sessionKey;
|
||
var checksum = util.calc_checksum(this.sessionKey);
|
||
data += util.writeNumber(checksum, 2);
|
||
|
||
var mpi = new type_mpi();
|
||
mpi.fromBytes(crypto.pkcs1.eme.encode(
|
||
data,
|
||
key.mpi[0].byteLength()));
|
||
|
||
this.encrypted = crypto.publicKeyEncrypt(
|
||
this.publicKeyAlgorithm,
|
||
key.mpi,
|
||
mpi);
|
||
}
|
||
|
||
/**
|
||
* Decrypts the session key (only for public key encrypted session key
|
||
* packets (tag 1)
|
||
*
|
||
* @param {openpgp_msg_message} msg
|
||
* The message object (with member encryptedData
|
||
* @param {openpgp_msg_privatekey} key
|
||
* Private key with secMPIs unlocked
|
||
* @return {String} The unencrypted session key
|
||
*/
|
||
this.decrypt = function(key) {
|
||
var result = crypto.publicKeyDecrypt(
|
||
this.publicKeyAlgorithm,
|
||
key.mpi,
|
||
this.encrypted).toBytes();
|
||
|
||
var checksum = util.readNumber(result.substr(result.length - 2));
|
||
|
||
var decoded = crypto.pkcs1.eme.decode(
|
||
result,
|
||
key.mpi[0].byteLength());
|
||
|
||
var key = decoded.substring(1, decoded.length - 2);
|
||
|
||
if (checksum != util.calc_checksum(key)) {
|
||
throw new Error('Checksum mismatch');
|
||
} else {
|
||
this.sessionKey = key;
|
||
this.sessionKeyAlgorithm =
|
||
enums.read(enums.symmetric, decoded.charCodeAt(0));
|
||
}
|
||
}
|
||
};
|
||
|
||
},{"../crypto":16,"../enums.js":27,"../type/keyid.js":53,"../type/mpi.js":54,"../util":56}],43:[function(require,module,exports){
|
||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||
// Copyright (C) 2011 Recurity Labs GmbH
|
||
//
|
||
// This library is free software; you can redistribute it and/or
|
||
// modify it under the terms of the GNU Lesser General Public
|
||
// License as published by the Free Software Foundation; either
|
||
// version 2.1 of the License, or (at your option) any later version.
|
||
//
|
||
// This library is distributed in the hope that it will be useful,
|
||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
// Lesser General Public License for more details.
|
||
//
|
||
// You should have received a copy of the GNU Lesser General Public
|
||
// License along with this library; if not, write to the Free Software
|
||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||
|
||
var public_key = require('./public_key.js');
|
||
|
||
module.exports = function public_subkey() {
|
||
public_key.call(this);
|
||
}
|
||
|
||
},{"./public_key.js":41}],44:[function(require,module,exports){
|
||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||
// Copyright (C) 2011 Recurity Labs GmbH
|
||
//
|
||
// This library is free software; you can redistribute it and/or
|
||
// modify it under the terms of the GNU Lesser General Public
|
||
// License as published by the Free Software Foundation; either
|
||
// version 2.1 of the License, or (at your option) any later version.
|
||
//
|
||
// This library is distributed in the hope that it will be useful,
|
||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
// Lesser General Public License for more details.
|
||
//
|
||
// You should have received a copy of the GNU Lesser General Public
|
||
// License along with this library; if not, write to the Free Software
|
||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||
|
||
var publicKey = require('./public_key.js'),
|
||
enums = require('../enums.js'),
|
||
util = require('../util'),
|
||
crypto = require('../crypto'),
|
||
type_mpi = require('../type/mpi.js'),
|
||
type_s2k = require('../type/s2k.js');
|
||
|
||
/**
|
||
* @class
|
||
* @classdesc Implementation of the Key Material Packet (Tag 5,6,7,14)
|
||
*
|
||
* RFC4480 5.5:
|
||
* A key material packet contains all the information about a public or
|
||
* private key. There are four variants of this packet type, and two
|
||
* major versions. Consequently, this section is complex.
|
||
*/
|
||
function packet_secret_key() {
|
||
publicKey.call(this);
|
||
// encrypted secret-key data
|
||
this.encrypted = null;
|
||
// indicator if secret-key data is available in decrypted form
|
||
this.isDecrypted = false;
|
||
|
||
|
||
function get_hash_len(hash) {
|
||
if (hash == 'sha1')
|
||
return 20;
|
||
else
|
||
return 2;
|
||
}
|
||
|
||
function get_hash_fn(hash) {
|
||
if (hash == 'sha1')
|
||
return crypto.hash.sha1;
|
||
else
|
||
return function(c) {
|
||
return util.writeNumber(util.calc_checksum(c), 2);
|
||
};
|
||
}
|
||
|
||
// Helper function
|
||
|
||
function parse_cleartext_mpi(hash_algorithm, cleartext, algorithm) {
|
||
var hashlen = get_hash_len(hash_algorithm),
|
||
hashfn = get_hash_fn(hash_algorithm);
|
||
|
||
var hashtext = cleartext.substr(cleartext.length - hashlen);
|
||
cleartext = cleartext.substr(0, cleartext.length - hashlen);
|
||
|
||
var hash = hashfn(cleartext);
|
||
|
||
if (hash != hashtext)
|
||
return new Error("Hash mismatch.");
|
||
|
||
var mpis = crypto.getPrivateMpiCount(algorithm);
|
||
|
||
var j = 0;
|
||
var mpi = [];
|
||
|
||
for (var i = 0; i < mpis && j < cleartext.length; i++) {
|
||
mpi[i] = new type_mpi();
|
||
j += mpi[i].read(cleartext.substr(j));
|
||
}
|
||
|
||
return mpi;
|
||
}
|
||
|
||
function write_cleartext_mpi(hash_algorithm, algorithm, mpi) {
|
||
var bytes = '';
|
||
var discard = crypto.getPublicMpiCount(algorithm);
|
||
|
||
for (var i = discard; i < mpi.length; i++) {
|
||
bytes += mpi[i].write();
|
||
}
|
||
|
||
|
||
bytes += get_hash_fn(hash_algorithm)(bytes);
|
||
|
||
return bytes;
|
||
}
|
||
|
||
|
||
// 5.5.3. Secret-Key Packet Formats
|
||
|
||
/**
|
||
* Internal parser for private keys as specified in RFC 4880 section 5.5.3
|
||
* @param {String} bytes Input string to read the packet from
|
||
*/
|
||
this.read = function(bytes) {
|
||
// - A Public-Key or Public-Subkey packet, as described above.
|
||
var len = this.readPublicKey(bytes);
|
||
|
||
bytes = bytes.substr(len);
|
||
|
||
|
||
// - One octet indicating string-to-key usage conventions. Zero
|
||
// indicates that the secret-key data is not encrypted. 255 or 254
|
||
// indicates that a string-to-key specifier is being given. Any
|
||
// other value is a symmetric-key encryption algorithm identifier.
|
||
var isEncrypted = bytes.charCodeAt(0);
|
||
|
||
if (isEncrypted) {
|
||
this.encrypted = bytes;
|
||
} else {
|
||
|
||
// - Plain or encrypted multiprecision integers comprising the secret
|
||
// key data. These algorithm-specific fields are as described
|
||
// below.
|
||
var parsedMPI = parse_cleartext_mpi('mod', bytes.substr(1), this.algorithm);
|
||
if (parsedMPI instanceof Error)
|
||
throw parsedMPI;
|
||
this.mpi = this.mpi.concat(parsedMPI);
|
||
this.isDecrypted = true;
|
||
}
|
||
|
||
};
|
||
|
||
/** Creates an OpenPGP key packet for the given key.
|
||
* @return {String} A string of bytes containing the secret key OpenPGP packet
|
||
*/
|
||
this.write = function() {
|
||
var bytes = this.writePublicKey();
|
||
|
||
if (!this.encrypted) {
|
||
bytes += String.fromCharCode(0);
|
||
|
||
bytes += write_cleartext_mpi('mod', this.algorithm, this.mpi);
|
||
} else {
|
||
bytes += this.encrypted;
|
||
}
|
||
|
||
return bytes;
|
||
};
|
||
|
||
|
||
|
||
|
||
/** Encrypt the payload. By default, we use aes256 and iterated, salted string
|
||
* to key specifier
|
||
* @param {String} passphrase
|
||
*/
|
||
this.encrypt = function(passphrase) {
|
||
|
||
var s2k = new type_s2k(),
|
||
symmetric = 'aes256',
|
||
cleartext = write_cleartext_mpi('sha1', this.algorithm, this.mpi),
|
||
key = produceEncryptionKey(s2k, passphrase, symmetric),
|
||
blockLen = crypto.cipher[symmetric].blockSize,
|
||
iv = crypto.random.getRandomBytes(blockLen);
|
||
|
||
|
||
this.encrypted = '';
|
||
this.encrypted += String.fromCharCode(254);
|
||
this.encrypted += String.fromCharCode(enums.write(enums.symmetric, symmetric));
|
||
this.encrypted += s2k.write();
|
||
this.encrypted += iv;
|
||
|
||
this.encrypted += crypto.cfb.normalEncrypt(symmetric, key, cleartext, iv);
|
||
};
|
||
|
||
function produceEncryptionKey(s2k, passphrase, algorithm) {
|
||
return s2k.produce_key(passphrase,
|
||
crypto.cipher[algorithm].keySize);
|
||
}
|
||
|
||
/**
|
||
* Decrypts the private key MPIs which are needed to use the key.
|
||
* openpgp_packet_keymaterial.hasUnencryptedSecretKeyData should be
|
||
* false otherwise
|
||
* a call to this function is not needed
|
||
*
|
||
* @param {String} str_passphrase The passphrase for this private key
|
||
* as string
|
||
* @return {Boolean} True if the passphrase was correct or MPI already
|
||
* decrypted; false if not
|
||
*/
|
||
this.decrypt = function(passphrase) {
|
||
if (this.isDecrypted)
|
||
return true;
|
||
|
||
var i = 0,
|
||
symmetric,
|
||
key;
|
||
|
||
var s2k_usage = this.encrypted.charCodeAt(i++);
|
||
|
||
// - [Optional] If string-to-key usage octet was 255 or 254, a one-
|
||
// octet symmetric encryption algorithm.
|
||
if (s2k_usage == 255 || s2k_usage == 254) {
|
||
symmetric = this.encrypted.charCodeAt(i++);
|
||
symmetric = enums.read(enums.symmetric, symmetric);
|
||
|
||
// - [Optional] If string-to-key usage octet was 255 or 254, a
|
||
// string-to-key specifier. The length of the string-to-key
|
||
// specifier is implied by its type, as described above.
|
||
var s2k = new type_s2k();
|
||
i += s2k.read(this.encrypted.substr(i));
|
||
|
||
key = produceEncryptionKey(s2k, passphrase, symmetric);
|
||
} else {
|
||
symmetric = s2k_usage;
|
||
symmetric = enums.read(enums.symmetric, symmetric);
|
||
key = crypto.hash.md5(passphrase);
|
||
}
|
||
|
||
|
||
// - [Optional] If secret data is encrypted (string-to-key usage octet
|
||
// not zero), an Initial Vector (IV) of the same length as the
|
||
// cipher's block size.
|
||
var iv = this.encrypted.substr(i,
|
||
crypto.cipher[symmetric].blockSize);
|
||
|
||
i += iv.length;
|
||
|
||
var cleartext,
|
||
ciphertext = this.encrypted.substr(i);
|
||
|
||
cleartext = crypto.cfb.normalDecrypt(symmetric, key, ciphertext, iv);
|
||
|
||
var hash = s2k_usage == 254 ?
|
||
'sha1' :
|
||
'mod';
|
||
|
||
var parsedMPI = parse_cleartext_mpi(hash, cleartext, this.algorithm);
|
||
if (parsedMPI instanceof Error)
|
||
return false;
|
||
this.mpi = this.mpi.concat(parsedMPI);
|
||
this.isDecrypted = true;
|
||
return true;
|
||
};
|
||
|
||
this.generate = function(bits) {
|
||
this.mpi = crypto.generateMpi(this.algorithm, bits);
|
||
this.isDecrypted = true;
|
||
};
|
||
|
||
}
|
||
|
||
packet_secret_key.prototype = new publicKey;
|
||
|
||
module.exports = packet_secret_key;
|
||
|
||
},{"../crypto":16,"../enums.js":27,"../type/mpi.js":54,"../type/s2k.js":55,"../util":56,"./public_key.js":41}],45:[function(require,module,exports){
|
||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||
// Copyright (C) 2011 Recurity Labs GmbH
|
||
//
|
||
// This library is free software; you can redistribute it and/or
|
||
// modify it under the terms of the GNU Lesser General Public
|
||
// License as published by the Free Software Foundation; either
|
||
// version 2.1 of the License, or (at your option) any later version.
|
||
//
|
||
// This library is distributed in the hope that it will be useful,
|
||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
// Lesser General Public License for more details.
|
||
//
|
||
// You should have received a copy of the GNU Lesser General Public
|
||
// License along with this library; if not, write to the Free Software
|
||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||
|
||
var secret_key = require('./secret_key.js');
|
||
|
||
module.exports = function secret_subkey() {
|
||
secret_key.call(this);
|
||
}
|
||
|
||
},{"./secret_key.js":44}],46:[function(require,module,exports){
|
||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||
// Copyright (C) 2011 Recurity Labs GmbH
|
||
//
|
||
// This library is free software; you can redistribute it and/or
|
||
// modify it under the terms of the GNU Lesser General Public
|
||
// License as published by the Free Software Foundation; either
|
||
// version 2.1 of the License, or (at your option) any later version.
|
||
//
|
||
// This library is distributed in the hope that it will be useful,
|
||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
// Lesser General Public License for more details.
|
||
//
|
||
// You should have received a copy of the GNU Lesser General Public
|
||
// License along with this library; if not, write to the Free Software
|
||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||
|
||
var util = require('../util'),
|
||
packet = require('./packet.js'),
|
||
enums = require('../enums.js'),
|
||
crypto = require('../crypto'),
|
||
type_mpi = require('../type/mpi.js'),
|
||
type_keyid = require('../type/keyid.js');
|
||
|
||
/**
|
||
* @class
|
||
* @classdesc Implementation of the Signature Packet (Tag 2)
|
||
*
|
||
* RFC4480 5.2:
|
||
* A Signature packet describes a binding between some public key and
|
||
* some data. The most common signatures are a signature of a file or a
|
||
* block of text, and a signature that is a certification of a User ID.
|
||
*/
|
||
module.exports = function packet_signature() {
|
||
|
||
this.version = null;
|
||
this.signatureType = null;
|
||
this.hashAlgorithm = null;
|
||
this.publicKeyAlgorithm = null;
|
||
|
||
this.signatureData = null;
|
||
this.signedHashValue = null;
|
||
this.mpi = null;
|
||
|
||
this.created = new Date();
|
||
this.signatureExpirationTime = null;
|
||
this.signatureNeverExpires = null;
|
||
this.exportable = null;
|
||
this.trustLevel = null;
|
||
this.trustAmount = null;
|
||
this.regularExpression = null;
|
||
this.revocable = null;
|
||
this.keyExpirationTime = null;
|
||
this.keyNeverExpires = null;
|
||
this.preferredSymmetricAlgorithms = null;
|
||
this.revocationKeyClass = null;
|
||
this.revocationKeyAlgorithm = null;
|
||
this.revocationKeyFingerprint = null;
|
||
this.issuerKeyId = new type_keyid();
|
||
this.notation = null;
|
||
this.preferredHashAlgorithms = null;
|
||
this.preferredCompressionAlgorithms = null;
|
||
this.keyServerPreferences = null;
|
||
this.preferredKeyServer = null;
|
||
this.isPrimaryUserID = null;
|
||
this.policyURI = null;
|
||
this.keyFlags = null;
|
||
this.signersUserId = null;
|
||
this.reasonForRevocationFlag = null;
|
||
this.reasonForRevocationString = null;
|
||
this.features = null;
|
||
this.signatureTargetPublicKeyAlgorithm = null;
|
||
this.signatureTargetHashAlgorithm = null;
|
||
this.signatureTargetHash = null;
|
||
this.embeddedSignature = null;
|
||
|
||
this.verified = false;
|
||
|
||
/**
|
||
* parsing function for a signature packet (tag 2).
|
||
* @param {String} bytes payload of a tag 2 packet
|
||
* @param {Integer} position position to start reading from the bytes string
|
||
* @param {Integer} len length of the packet or the remaining length of bytes at position
|
||
* @return {openpgp_packet_encrypteddata} object representation
|
||
*/
|
||
this.read = function(bytes) {
|
||
var i = 0;
|
||
|
||
this.version = bytes.charCodeAt(i++);
|
||
// switch on version (3 and 4)
|
||
switch (this.version) {
|
||
case 3:
|
||
// One-octet length of following hashed material. MUST be 5.
|
||
if (bytes.charCodeAt(i++) != 5)
|
||
util.print_debug("openpgp.packet.signature.js\n" +
|
||
'invalid One-octet length of following hashed material.' +
|
||
'MUST be 5. @:' + (i - 1));
|
||
|
||
var sigpos = i;
|
||
// One-octet signature type.
|
||
this.signatureType = bytes.charCodeAt(i++);
|
||
|
||
// Four-octet creation time.
|
||
this.created = util.readDate(bytes.substr(i, 4));
|
||
i += 4;
|
||
|
||
// storing data appended to data which gets verified
|
||
this.signatureData = bytes.substring(sigpos, i);
|
||
|
||
// Eight-octet Key ID of signer.
|
||
this.issuerKeyId.read(bytes.substring(i, i + 8));
|
||
i += 8;
|
||
|
||
// One-octet public-key algorithm.
|
||
this.publicKeyAlgorithm = bytes.charCodeAt(i++);
|
||
|
||
// One-octet hash algorithm.
|
||
this.hashAlgorithm = bytes.charCodeAt(i++);
|
||
break;
|
||
case 4:
|
||
this.signatureType = bytes.charCodeAt(i++);
|
||
this.publicKeyAlgorithm = bytes.charCodeAt(i++);
|
||
this.hashAlgorithm = bytes.charCodeAt(i++);
|
||
|
||
function subpackets(bytes) {
|
||
// Two-octet scalar octet count for following subpacket data.
|
||
var subpacket_length = util.readNumber(
|
||
bytes.substr(0, 2));
|
||
|
||
var i = 2;
|
||
|
||
// subpacket data set (zero or more subpackets)
|
||
var subpacked_read = 0;
|
||
while (i < 2 + subpacket_length) {
|
||
|
||
var len = packet.readSimpleLength(bytes.substr(i));
|
||
i += len.offset;
|
||
|
||
this.read_sub_packet(bytes.substr(i, len.len));
|
||
|
||
i += len.len;
|
||
}
|
||
|
||
return i;
|
||
}
|
||
|
||
// hashed subpackets
|
||
i += subpackets.call(this, bytes.substr(i), true);
|
||
|
||
// A V4 signature hashes the packet body
|
||
// starting from its first field, the version number, through the end
|
||
// of the hashed subpacket data. Thus, the fields hashed are the
|
||
// signature version, the signature type, the public-key algorithm, the
|
||
// hash algorithm, the hashed subpacket length, and the hashed
|
||
// subpacket body.
|
||
this.signatureData = bytes.substr(0, i);
|
||
|
||
// unhashed subpackets
|
||
i += subpackets.call(this, bytes.substr(i), false);
|
||
|
||
break;
|
||
default:
|
||
throw new Error('Version ' + version + ' of the signature is unsupported.');
|
||
break;
|
||
}
|
||
|
||
// Two-octet field holding left 16 bits of signed hash value.
|
||
this.signedHashValue = bytes.substr(i, 2);
|
||
i += 2;
|
||
|
||
this.signature = bytes.substr(i);
|
||
};
|
||
|
||
this.write = function() {
|
||
return this.signatureData +
|
||
util.writeNumber(0, 2) + // Number of unsigned subpackets.
|
||
this.signedHashValue +
|
||
this.signature;
|
||
};
|
||
|
||
/**
|
||
* Signs provided data. This needs to be done prior to serialization.
|
||
* @param {Object} data Contains packets to be signed.
|
||
* @param {openpgp_msg_privatekey} privatekey private key used to sign the message.
|
||
*/
|
||
this.sign = function(key, data) {
|
||
var signatureType = enums.write(enums.signature, this.signatureType),
|
||
publicKeyAlgorithm = enums.write(enums.publicKey, this.publicKeyAlgorithm),
|
||
hashAlgorithm = enums.write(enums.hash, this.hashAlgorithm);
|
||
|
||
var result = String.fromCharCode(4);
|
||
result += String.fromCharCode(signatureType);
|
||
result += String.fromCharCode(publicKeyAlgorithm);
|
||
result += String.fromCharCode(hashAlgorithm);
|
||
|
||
this.issuerKeyId = key.getKeyId();
|
||
|
||
// Add hashed subpackets
|
||
result += this.write_all_sub_packets();
|
||
|
||
this.signatureData = result;
|
||
|
||
var trailer = this.calculateTrailer();
|
||
|
||
var toHash = this.toSign(signatureType, data) +
|
||
this.signatureData + trailer;
|
||
|
||
var hash = crypto.hash.digest(hashAlgorithm, toHash);
|
||
|
||
this.signedHashValue = hash.substr(0, 2);
|
||
|
||
this.signature = crypto.signature.sign(hashAlgorithm,
|
||
publicKeyAlgorithm, key.mpi, toHash);
|
||
};
|
||
|
||
/**
|
||
* Creates string of bytes with all subpacket data
|
||
* @return {String} a string-representation of a all subpacket data
|
||
*/
|
||
this.write_all_sub_packets = function() {
|
||
var sub = enums.signatureSubpacket;
|
||
var result = '';
|
||
var bytes = '';
|
||
if (this.created !== null) {
|
||
result += write_sub_packet(sub.signature_creation_time, util.writeDate(this.created));
|
||
}
|
||
if (this.signatureExpirationTime !== null) {
|
||
result += write_sub_packet(sub.signature_expiration_time, util.writeDate(this.signatureExpirationTime));
|
||
}
|
||
if (this.exportable !== null) {
|
||
result += write_sub_packet(sub.exportable_certification, String.fromCharCode(this.exportable ? 1 : 0));
|
||
}
|
||
if (this.trustLevel !== null) {
|
||
bytes = String.fromCharCode(this.trustLevel) + String.fromCharCode(this.trustAmount);
|
||
result += write_sub_packet(sub.trust_signature, bytes);
|
||
}
|
||
if (this.regularExpression !== null) {
|
||
result += write_sub_packet(sub.regular_expression, this.regularExpression);
|
||
}
|
||
if (this.revocable !== null) {
|
||
result += write_sub_packet(sub.revocable, String.fromCharCode(this.revocable ? 1 : 0));
|
||
}
|
||
if (this.keyExpirationTime !== null) {
|
||
result += write_sub_packet(sub.key_expiration_time, util.writeDate(this.keyExpirationTime));
|
||
}
|
||
if (this.preferredSymmetricAlgorithms !== null) {
|
||
bytes = util.bin2str(this.preferredSymmetricAlgorithms);
|
||
result += write_sub_packet(sub.preferred_symmetric_algorithms, bytes);
|
||
}
|
||
if (this.revocationKeyClass !== null) {
|
||
bytes = String.fromCharCode(this.revocationKeyClass);
|
||
bytes += String.fromCharCode(this.revocationKeyAlgorithm);
|
||
bytes += this.revocationKeyFingerprint;
|
||
result += write_sub_packet(sub.revocation_key, bytes);
|
||
}
|
||
if (!this.issuerKeyId.isNull()) {
|
||
result += write_sub_packet(sub.issuer, this.issuerKeyId.write());
|
||
}
|
||
if (this.notation !== null) {
|
||
for (var name in this.notation) {
|
||
if (this.notation.hasOwnProperty(name)) {
|
||
var value = this.notation[name];
|
||
bytes = String.fromCharCode(0x80);
|
||
bytes += String.fromCharCode(0);
|
||
bytes += String.fromCharCode(0);
|
||
bytes += String.fromCharCode(0);
|
||
// 2 octets of name length
|
||
bytes += util.writeNumber(name.length, 2);
|
||
// 2 octets of value length
|
||
bytes += util.writeNumber(value.length, 2);
|
||
bytes += name + value;
|
||
result += write_sub_packet(sub.notation_data, bytes);
|
||
}
|
||
}
|
||
}
|
||
if (this.preferredHashAlgorithms !== null) {
|
||
bytes = util.bin2str(this.preferredHashAlgorithms);
|
||
result += write_sub_packet(sub.preferred_hash_algorithms, bytes);
|
||
}
|
||
if (this.preferredCompressionAlgorithms !== null) {
|
||
bytes = util.bin2str(this.preferredCompressionAlgorithms);
|
||
result += write_sub_packet(sub.preferred_hash_algorithms, bytes);
|
||
}
|
||
if (this.keyServerPreferences !== null) {
|
||
bytes = util.bin2str(this.keyServerPreferences);
|
||
result += write_sub_packet(sub.key_server_preferences, bytes);
|
||
}
|
||
if (this.preferredKeyServer !== null) {
|
||
result += write_sub_packet(sub.preferred_key_server, this.preferredKeyServer);
|
||
}
|
||
if (this.isPrimaryUserID !== null) {
|
||
result += write_sub_packet(sub.primary_user_id, String.fromCharCode(this.isPrimaryUserID ? 1 : 0));
|
||
}
|
||
if (this.policyURI !== null) {
|
||
result += write_sub_packet(sub.policy_uri, this.policyURI);
|
||
}
|
||
if (this.keyFlags !== null) {
|
||
bytes = util.bin2str(this.keyFlags);
|
||
result += write_sub_packet(sub.key_flags, bytes);
|
||
}
|
||
if (this.signersUserId !== null) {
|
||
result += write_sub_packet(sub.signers_user_id, this.signersUserId);
|
||
}
|
||
if (this.reasonForRevocationFlag !== null) {
|
||
bytes = String.fromCharCode(this.reasonForRevocationFlag);
|
||
bytes += this.reasonForRevocationString;
|
||
result += write_sub_packet(sub.reason_for_revocation, bytes);
|
||
}
|
||
if (this.features !== null) {
|
||
bytes = util.bin2str(this.features);
|
||
result += write_sub_packet(sub.features, bytes);
|
||
}
|
||
if (this.signatureTargetPublicKeyAlgorithm !== null) {
|
||
bytes = String.fromCharCode(this.signatureTargetPublicKeyAlgorithm);
|
||
bytes += String.fromCharCode(this.signatureTargetHashAlgorithm);
|
||
bytes += this.signatureTargetHash;
|
||
result += write_sub_packet(sub.signature_target, bytes);
|
||
}
|
||
if (this.embeddedSignature !== null) {
|
||
result += write_sub_packet(sub.embedded_signature, this.embeddedSignature.write());
|
||
}
|
||
result = util.writeNumber(result.length, 2) + result;
|
||
return result;
|
||
};
|
||
|
||
/**
|
||
* creates a string representation of a sub signature packet (See RFC 4880 5.2.3.1)
|
||
* @param {Integer} type subpacket signature type. Signature types as described
|
||
* in RFC4880 Section 5.2.3.2
|
||
* @param {String} data data to be included
|
||
* @return {String} a string-representation of a sub signature packet (See RFC 4880 5.2.3.1)
|
||
*/
|
||
function write_sub_packet(type, data) {
|
||
var result = "";
|
||
result += packet.writeSimpleLength(data.length + 1);
|
||
result += String.fromCharCode(type);
|
||
result += data;
|
||
return result;
|
||
}
|
||
|
||
// V4 signature sub packets
|
||
|
||
this.read_sub_packet = function(bytes) {
|
||
var mypos = 0;
|
||
|
||
function read_array(prop, bytes) {
|
||
this[prop] = [];
|
||
|
||
for (var i = 0; i < bytes.length; i++) {
|
||
this[prop].push(bytes.charCodeAt(i));
|
||
}
|
||
}
|
||
|
||
// The leftwost bit denotes a "critical" packet, but we ignore it.
|
||
var type = bytes.charCodeAt(mypos++) & 0x7F;
|
||
|
||
// subpacket type
|
||
switch (type) {
|
||
case 2:
|
||
// Signature Creation Time
|
||
this.created = util.readDate(bytes.substr(mypos));
|
||
break;
|
||
case 3:
|
||
// Signature Expiration Time
|
||
var time = util.readDate(bytes.substr(mypos));
|
||
|
||
this.signatureNeverExpires = time.getTime() == 0;
|
||
this.signatureExpirationTime = time;
|
||
|
||
break;
|
||
case 4:
|
||
// Exportable Certification
|
||
this.exportable = bytes.charCodeAt(mypos++) == 1;
|
||
break;
|
||
case 5:
|
||
// Trust Signature
|
||
this.trustLevel = bytes.charCodeAt(mypos++);
|
||
this.trustAmount = bytes.charCodeAt(mypos++);
|
||
break;
|
||
case 6:
|
||
// Regular Expression
|
||
this.regularExpression = bytes.substr(mypos);
|
||
break;
|
||
case 7:
|
||
// Revocable
|
||
this.revocable = bytes.charCodeAt(mypos++) == 1;
|
||
break;
|
||
case 9:
|
||
// Key Expiration Time
|
||
var time = util.readDate(bytes.substr(mypos));
|
||
|
||
this.keyExpirationTime = time;
|
||
this.keyNeverExpires = time.getTime() == 0;
|
||
|
||
break;
|
||
case 11:
|
||
// Preferred Symmetric Algorithms
|
||
this.preferredSymmetricAlgorithms = [];
|
||
|
||
while (mypos != bytes.length) {
|
||
this.preferredSymmetricAlgorithms.push(bytes.charCodeAt(mypos++));
|
||
}
|
||
|
||
break;
|
||
case 12:
|
||
// Revocation Key
|
||
// (1 octet of class, 1 octet of public-key algorithm ID, 20
|
||
// octets of
|
||
// fingerprint)
|
||
this.revocationKeyClass = bytes.charCodeAt(mypos++);
|
||
this.revocationKeyAlgorithm = bytes.charCodeAt(mypos++);
|
||
this.revocationKeyFingerprint = bytes.substr(mypos, 20);
|
||
break;
|
||
|
||
case 16:
|
||
// Issuer
|
||
this.issuerKeyId.read(bytes.substr(mypos));
|
||
break;
|
||
|
||
case 20:
|
||
// Notation Data
|
||
// We don't know how to handle anything but a text flagged data.
|
||
if (bytes.charCodeAt(mypos) == 0x80) {
|
||
|
||
// We extract key/value tuple from the byte stream.
|
||
mypos += 4;
|
||
var m = util.readNumber(bytes.substr(mypos, 2));
|
||
mypos += 2
|
||
var n = util.readNumber(bytes.substr(mypos, 2));
|
||
mypos += 2
|
||
|
||
var name = bytes.substr(mypos, m),
|
||
value = bytes.substr(mypos + m, n);
|
||
|
||
this.notation = this.notation || {};
|
||
this.notation[name] = value;
|
||
} else throw new Error("Unsupported notation flag.");
|
||
break;
|
||
case 21:
|
||
// Preferred Hash Algorithms
|
||
read_array.call(this, 'preferredHashAlgorithms', bytes.substr(mypos));
|
||
break;
|
||
case 22:
|
||
// Preferred Compression Algorithms
|
||
read_array.call(this, 'preferredCompressionAlgorithms ', bytes.substr(mypos));
|
||
break;
|
||
case 23:
|
||
// Key Server Preferences
|
||
read_array.call(this, 'keyServerPreferencess', bytes.substr(mypos));
|
||
break;
|
||
case 24:
|
||
// Preferred Key Server
|
||
this.preferredKeyServer = bytes.substr(mypos);
|
||
break;
|
||
case 25:
|
||
// Primary User ID
|
||
this.isPrimaryUserID = bytes[mypos++] != 0;
|
||
break;
|
||
case 26:
|
||
// Policy URI
|
||
this.policyURI = bytes.substr(mypos);
|
||
break;
|
||
case 27:
|
||
// Key Flags
|
||
read_array.call(this, 'keyFlags', bytes.substr(mypos));
|
||
break;
|
||
case 28:
|
||
// Signer's User ID
|
||
this.signersUserId += bytes.substr(mypos);
|
||
break;
|
||
case 29:
|
||
// Reason for Revocation
|
||
this.reasonForRevocationFlag = bytes.charCodeAt(mypos++);
|
||
this.reasonForRevocationString = bytes.substr(mypos);
|
||
break;
|
||
case 30:
|
||
// Features
|
||
read_array.call(this, 'features', bytes.substr(mypos));
|
||
break;
|
||
case 31:
|
||
// Signature Target
|
||
// (1 octet public-key algorithm, 1 octet hash algorithm, N octets hash)
|
||
this.signatureTargetPublicKeyAlgorithm = bytes.charCodeAt(mypos++);
|
||
this.signatureTargetHashAlgorithm = bytes.charCodeAt(mypos++);
|
||
|
||
var len = crypto.getHashByteLength(this.signatureTargetHashAlgorithm);
|
||
|
||
this.signatureTargetHash = bytes.substr(mypos, len);
|
||
break;
|
||
case 32:
|
||
// Embedded Signature
|
||
this.embeddedSignature = new packet_signature();
|
||
this.embeddedSignature.read(bytes.substr(mypos));
|
||
break;
|
||
default:
|
||
util.print_error("openpgp.packet.signature.js\n" +
|
||
'unknown signature subpacket type ' + type + " @:" + mypos +
|
||
" subplen:" + subplen + " len:" + len);
|
||
break;
|
||
}
|
||
};
|
||
|
||
// Produces data to produce signature on
|
||
this.toSign = function(type, data) {
|
||
var t = enums.signature;
|
||
|
||
switch (type) {
|
||
case t.binary:
|
||
case t.text:
|
||
return data.getBytes();
|
||
|
||
case t.standalone:
|
||
return '';
|
||
|
||
case t.cert_generic:
|
||
case t.cert_persona:
|
||
case t.cert_casual:
|
||
case t.cert_positive:
|
||
case t.cert_revocation:
|
||
{
|
||
var packet, tag;
|
||
|
||
if (data.userid !== undefined) {
|
||
tag = 0xB4;
|
||
packet = data.userid;
|
||
} else if (data.userattribute !== undefined) {
|
||
tag = 0xD1;
|
||
packet = data.userattribute;
|
||
} else throw new Error('Either a userid or userattribute packet needs to be ' +
|
||
'supplied for certification.');
|
||
|
||
var bytes = packet.write();
|
||
|
||
return this.toSign(t.key, data) +
|
||
String.fromCharCode(tag) +
|
||
util.writeNumber(bytes.length, 4) +
|
||
bytes;
|
||
}
|
||
case t.subkey_binding:
|
||
case t.key_binding:
|
||
{
|
||
return this.toSign(t.key, data) + this.toSign(t.key, {
|
||
key: data.bind
|
||
});
|
||
}
|
||
case t.key:
|
||
{
|
||
if (data.key == undefined)
|
||
throw new Error('Key packet is required for this sigtature.');
|
||
|
||
return data.key.writeOld();
|
||
}
|
||
case t.key_revocation:
|
||
case t.subkey_revocation:
|
||
return this.toSign(t.key, data);
|
||
case t.timestamp:
|
||
return '';
|
||
case t.third_party:
|
||
throw new Error('Not implemented');
|
||
break;
|
||
default:
|
||
throw new Error('Unknown signature type.')
|
||
}
|
||
}
|
||
|
||
|
||
this.calculateTrailer = function() {
|
||
// calculating the trailer
|
||
var trailer = '';
|
||
// V3 signatures don't have a trailer
|
||
if (this.version == 3) return trailer;
|
||
trailer += String.fromCharCode(4); // Version
|
||
trailer += String.fromCharCode(0xFF);
|
||
trailer += util.writeNumber(this.signatureData.length, 4);
|
||
return trailer
|
||
}
|
||
|
||
|
||
/**
|
||
* verifys the signature packet. Note: not signature types are implemented
|
||
* @param {String|Object} data data which on the signature applies
|
||
* @param {public_subkey|packet_public_key} key the public key to verify the signature
|
||
* @return {boolean} True if message is verified, else false.
|
||
*/
|
||
this.verify = function(key, data) {
|
||
var signatureType = enums.write(enums.signature, this.signatureType),
|
||
publicKeyAlgorithm = enums.write(enums.publicKey, this.publicKeyAlgorithm),
|
||
hashAlgorithm = enums.write(enums.hash, this.hashAlgorithm);
|
||
|
||
var bytes = this.toSign(signatureType, data),
|
||
trailer = this.calculateTrailer();
|
||
|
||
|
||
var mpicount = 0;
|
||
// Algorithm-Specific Fields for RSA signatures:
|
||
// - multiprecision number (MPI) of RSA signature value m**d mod n.
|
||
if (publicKeyAlgorithm > 0 && publicKeyAlgorithm < 4)
|
||
mpicount = 1;
|
||
// Algorithm-Specific Fields for DSA signatures:
|
||
// - MPI of DSA value r.
|
||
// - MPI of DSA value s.
|
||
else if (publicKeyAlgorithm == 17)
|
||
mpicount = 2;
|
||
|
||
var mpi = [],
|
||
i = 0;
|
||
for (var j = 0; j < mpicount; j++) {
|
||
mpi[j] = new type_mpi();
|
||
i += mpi[j].read(this.signature.substr(i));
|
||
}
|
||
|
||
this.verified = crypto.signature.verify(publicKeyAlgorithm,
|
||
hashAlgorithm, mpi, key.mpi,
|
||
bytes + this.signatureData + trailer);
|
||
|
||
return this.verified;
|
||
}
|
||
}
|
||
|
||
},{"../crypto":16,"../enums.js":27,"../type/keyid.js":53,"../type/mpi.js":54,"../util":56,"./packet.js":39}],47:[function(require,module,exports){
|
||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||
// Copyright (C) 2011 Recurity Labs GmbH
|
||
//
|
||
// This library is free software; you can redistribute it and/or
|
||
// modify it under the terms of the GNU Lesser General Public
|
||
// License as published by the Free Software Foundation; either
|
||
// version 2.1 of the License, or (at your option) any later version.
|
||
//
|
||
// This library is distributed in the hope that it will be useful,
|
||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
// Lesser General Public License for more details.
|
||
//
|
||
// You should have received a copy of the GNU Lesser General Public
|
||
// License along with this library; if not, write to the Free Software
|
||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||
|
||
var util = require('../util'),
|
||
crypto = require('../crypto');
|
||
|
||
/**
|
||
* @class
|
||
* @classdesc Implementation of the Sym. Encrypted Integrity Protected Data
|
||
* Packet (Tag 18)
|
||
*
|
||
* RFC4880 5.13: The Symmetrically Encrypted Integrity Protected Data packet is
|
||
* a variant of the Symmetrically Encrypted Data packet. It is a new feature
|
||
* created for OpenPGP that addresses the problem of detecting a modification to
|
||
* encrypted data. It is used in combination with a Modification Detection Code
|
||
* packet.
|
||
*/
|
||
|
||
module.exports = function packet_sym_encrypted_integrity_protected() {
|
||
/** The encrypted payload. */
|
||
this.encrypted = null; // string
|
||
/** @type {Boolean}
|
||
* If after decrypting the packet this is set to true,
|
||
* a modification has been detected and thus the contents
|
||
* should be discarded.
|
||
*/
|
||
this.modification = false;
|
||
this.packets;
|
||
|
||
|
||
this.read = function(bytes) {
|
||
// - A one-octet version number. The only currently defined value is
|
||
// 1.
|
||
var version = bytes.charCodeAt(0);
|
||
|
||
if (version != 1) {
|
||
throw new Error('Invalid packet version.');
|
||
}
|
||
|
||
// - Encrypted data, the output of the selected symmetric-key cipher
|
||
// operating in Cipher Feedback mode with shift amount equal to the
|
||
// block size of the cipher (CFB-n where n is the block size).
|
||
this.encrypted = bytes.substr(1);
|
||
}
|
||
|
||
this.write = function() {
|
||
|
||
return String.fromCharCode(1) // Version
|
||
+ this.encrypted;
|
||
}
|
||
|
||
this.encrypt = function(sessionKeyAlgorithm, key) {
|
||
var bytes = this.packets.write()
|
||
|
||
var prefixrandom = crypto.getPrefixRandom(sessionKeyAlgorithm);
|
||
var prefix = prefixrandom + prefixrandom.charAt(prefixrandom.length - 2) + prefixrandom.charAt(prefixrandom.length -
|
||
1)
|
||
|
||
var tohash = bytes;
|
||
|
||
|
||
// Modification detection code packet.
|
||
tohash += String.fromCharCode(0xD3);
|
||
tohash += String.fromCharCode(0x14);
|
||
|
||
|
||
tohash += crypto.hash.sha1(prefix + tohash);
|
||
|
||
|
||
this.encrypted = crypto.cfb.encrypt(prefixrandom,
|
||
sessionKeyAlgorithm, tohash, key, false).substring(0,
|
||
prefix.length + tohash.length);
|
||
}
|
||
|
||
/**
|
||
* Decrypts the encrypted data contained in this object read_packet must
|
||
* have been called before
|
||
*
|
||
* @param {Integer} sessionKeyAlgorithm
|
||
* The selected symmetric encryption algorithm to be used
|
||
* @param {String} key The key of cipher blocksize length to be used
|
||
* @return {String} The decrypted data of this packet
|
||
*/
|
||
this.decrypt = function(sessionKeyAlgorithm, key) {
|
||
var decrypted = crypto.cfb.decrypt(
|
||
sessionKeyAlgorithm, key, this.encrypted, false);
|
||
|
||
|
||
// there must be a modification detection code packet as the
|
||
// last packet and everything gets hashed except the hash itself
|
||
this.hash = crypto.hash.sha1(
|
||
crypto.cfb.mdc(sessionKeyAlgorithm, key, this.encrypted) + decrypted.substring(0, decrypted.length - 20));
|
||
|
||
|
||
var mdc = decrypted.substr(decrypted.length - 20, 20);
|
||
|
||
if (this.hash != mdc) {
|
||
throw new Error('Modification detected.');
|
||
} else
|
||
this.packets.read(decrypted.substr(0, decrypted.length - 22));
|
||
}
|
||
};
|
||
|
||
},{"../crypto":16,"../util":56}],48:[function(require,module,exports){
|
||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||
// Copyright (C) 2011 Recurity Labs GmbH
|
||
//
|
||
// This library is free software; you can redistribute it and/or
|
||
// modify it under the terms of the GNU Lesser General Public
|
||
// License as published by the Free Software Foundation; either
|
||
// version 2.1 of the License, or (at your option) any later version.
|
||
//
|
||
// This library is distributed in the hope that it will be useful,
|
||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
// Lesser General Public License for more details.
|
||
//
|
||
// You should have received a copy of the GNU Lesser General Public
|
||
// License along with this library; if not, write to the Free Software
|
||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||
|
||
var type_s2k = require('../type/s2k.js'),
|
||
enums = require('../enums.js'),
|
||
crypto = require('../crypto');
|
||
|
||
/**
|
||
* @class
|
||
* @classdesc Public-Key Encrypted Session Key Packets (Tag 1)
|
||
*
|
||
* RFC4880 5.1: A Public-Key Encrypted Session Key packet holds the session key
|
||
* used to encrypt a message. Zero or more Public-Key Encrypted Session Key
|
||
* packets and/or Symmetric-Key Encrypted Session Key packets may precede a
|
||
* Symmetrically Encrypted Data Packet, which holds an encrypted message. The
|
||
* message is encrypted with the session key, and the session key is itself
|
||
* encrypted and stored in the Encrypted Session Key packet(s). The
|
||
* Symmetrically Encrypted Data Packet is preceded by one Public-Key Encrypted
|
||
* Session Key packet for each OpenPGP key to which the message is encrypted.
|
||
* The recipient of the message finds a session key that is encrypted to their
|
||
* public key, decrypts the session key, and then uses the session key to
|
||
* decrypt the message.
|
||
*/
|
||
module.exports = function packet_sym_encrypted_session_key() {
|
||
this.tag = 3;
|
||
this.sessionKeyEncryptionAlgorithm = null;
|
||
this.sessionKeyAlgorithm = 'aes256';
|
||
this.encrypted = null;
|
||
this.s2k = new type_s2k();
|
||
|
||
/**
|
||
* Parsing function for a symmetric encrypted session key packet (tag 3).
|
||
*
|
||
* @param {String} input Payload of a tag 1 packet
|
||
* @param {Integer} position Position to start reading from the input string
|
||
* @param {Integer} len
|
||
* Length of the packet or the remaining length of
|
||
* input at position
|
||
* @return {openpgp_packet_encrypteddata} Object representation
|
||
*/
|
||
this.read = function(bytes) {
|
||
// A one-octet version number. The only currently defined version is 4.
|
||
this.version = bytes.charCodeAt(0);
|
||
|
||
// A one-octet number describing the symmetric algorithm used.
|
||
var algo = enums.read(enums.symmetric, bytes.charCodeAt(1));
|
||
|
||
// A string-to-key (S2K) specifier, length as defined above.
|
||
var s2klength = this.s2k.read(bytes.substr(2));
|
||
|
||
// Optionally, the encrypted session key itself, which is decrypted
|
||
// with the string-to-key object.
|
||
var done = s2klength + 2;
|
||
|
||
if (done < bytes.length) {
|
||
this.encrypted = bytes.substr(done);
|
||
this.sessionKeyEncryptionAlgorithm = algo
|
||
} else
|
||
this.sessionKeyAlgorithm = algo;
|
||
}
|
||
|
||
this.write = function() {
|
||
var algo = this.encrypted == null ?
|
||
this.sessionKeyAlgorithm :
|
||
this.sessionKeyEncryptionAlgorithm;
|
||
|
||
var bytes = String.fromCharCode(this.version) +
|
||
String.fromCharCode(enums.write(enums.symmetric, algo)) +
|
||
this.s2k.write();
|
||
|
||
if (this.encrypted != null)
|
||
bytes += this.encrypted;
|
||
return bytes;
|
||
}
|
||
|
||
/**
|
||
* Decrypts the session key (only for public key encrypted session key
|
||
* packets (tag 1)
|
||
*
|
||
* @param {openpgp_msg_message} msg
|
||
* The message object (with member encryptedData
|
||
* @param {openpgp_msg_privatekey} key
|
||
* Private key with secMPIs unlocked
|
||
* @return {String} The unencrypted session key
|
||
*/
|
||
this.decrypt = function(passphrase) {
|
||
var algo = this.sessionKeyEncryptionAlgorithm != null ?
|
||
this.sessionKeyEncryptionAlgorithm :
|
||
this.sessionKeyAlgorithm;
|
||
|
||
|
||
var length = crypto.cipher[algo].keySize;
|
||
var key = this.s2k.produce_key(passphrase, length);
|
||
|
||
if (this.encrypted == null) {
|
||
this.sessionKey = key;
|
||
|
||
} else {
|
||
var decrypted = crypto.cfb.decrypt(
|
||
this.sessionKeyEncryptionAlgorithm, key, this.encrypted, true);
|
||
|
||
this.sessionKeyAlgorithm = enums.read(enums.symmetric,
|
||
decrypted[0].keyCodeAt());
|
||
|
||
this.sessionKey = decrypted.substr(1);
|
||
}
|
||
}
|
||
|
||
this.encrypt = function(passphrase) {
|
||
var length = crypto.getKeyLength(this.sessionKeyEncryptionAlgorithm);
|
||
var key = this.s2k.produce_key(passphrase, length);
|
||
|
||
var private_key = String.fromCharCode(
|
||
enums.write(enums.symmetric, this.sessionKeyAlgorithm)) +
|
||
|
||
crypto.getRandomBytes(
|
||
crypto.getKeyLength(this.sessionKeyAlgorithm));
|
||
|
||
this.encrypted = crypto.cfb.encrypt(
|
||
crypto.getPrefixRandom(this.sessionKeyEncryptionAlgorithm),
|
||
this.sessionKeyEncryptionAlgorithm, key, private_key, true);
|
||
}
|
||
};
|
||
|
||
},{"../crypto":16,"../enums.js":27,"../type/s2k.js":55}],49:[function(require,module,exports){
|
||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||
// Copyright (C) 2011 Recurity Labs GmbH
|
||
//
|
||
// This library is free software; you can redistribute it and/or
|
||
// modify it under the terms of the GNU Lesser General Public
|
||
// License as published by the Free Software Foundation; either
|
||
// version 2.1 of the License, or (at your option) any later version.
|
||
//
|
||
// This library is distributed in the hope that it will be useful,
|
||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
// Lesser General Public License for more details.
|
||
//
|
||
// You should have received a copy of the GNU Lesser General Public
|
||
// License along with this library; if not, write to the Free Software
|
||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||
|
||
var crypto = require('../crypto');
|
||
|
||
/**
|
||
* @class
|
||
* @classdesc Implementation of the Symmetrically Encrypted Data Packet (Tag 9)
|
||
*
|
||
* RFC4880 5.7: The Symmetrically Encrypted Data packet contains data encrypted
|
||
* with a symmetric-key algorithm. When it has been decrypted, it contains other
|
||
* packets (usually a literal data packet or compressed data packet, but in
|
||
* theory other Symmetrically Encrypted Data packets or sequences of packets
|
||
* that form whole OpenPGP messages).
|
||
*/
|
||
|
||
module.exports = function packet_symmetrically_encrypted() {
|
||
this.encrypted = null;
|
||
/** Decrypted packets contained within.
|
||
* @type {openpgp_packetlist} */
|
||
this.packets;
|
||
|
||
this.read = function(bytes) {
|
||
this.encrypted = bytes;
|
||
}
|
||
|
||
this.write = function() {
|
||
return this.encrypted;
|
||
}
|
||
|
||
/**
|
||
* Symmetrically decrypt the packet data
|
||
*
|
||
* @param {Integer} sessionKeyAlgorithm
|
||
* Symmetric key algorithm to use // See RFC4880 9.2
|
||
* @param {String} key
|
||
* Key as string with the corresponding length to the
|
||
* algorithm
|
||
* @return The decrypted data;
|
||
*/
|
||
this.decrypt = function(sessionKeyAlgorithm, key) {
|
||
var decrypted = crypto.cfb.decrypt(
|
||
sessionKeyAlgorithm, key, this.encrypted, true);
|
||
|
||
this.packets.read(decrypted);
|
||
}
|
||
|
||
this.encrypt = function(algo, key) {
|
||
var data = this.packets.write();
|
||
|
||
this.encrypted = crypto.cfb.encrypt(
|
||
crypto.getPrefixRandom(algo), algo, data, key, true);
|
||
}
|
||
};
|
||
|
||
},{"../crypto":16}],50:[function(require,module,exports){
|
||
module.exports = function packet_trust() {
|
||
|
||
};
|
||
|
||
},{}],51:[function(require,module,exports){
|
||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||
// Copyright (C) 2011 Recurity Labs GmbH
|
||
//
|
||
// This library is free software; you can redistribute it and/or
|
||
// modify it under the terms of the GNU Lesser General Public
|
||
// License as published by the Free Software Foundation; either
|
||
// version 2.1 of the License, or (at your option) any later version.
|
||
//
|
||
// This library is distributed in the hope that it will be useful,
|
||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
// Lesser General Public License for more details.
|
||
//
|
||
// You should have received a copy of the GNU Lesser General Public
|
||
// License along with this library; if not, write to the Free Software
|
||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||
|
||
/**
|
||
* @class
|
||
* @classdesc Implementation of the User Attribute Packet (Tag 17)
|
||
* The User Attribute packet is a variation of the User ID packet. It
|
||
* is capable of storing more types of data than the User ID packet,
|
||
* which is limited to text. Like the User ID packet, a User Attribute
|
||
* packet may be certified by the key owner ("self-signed") or any other
|
||
* key owner who cares to certify it. Except as noted, a User Attribute
|
||
* packet may be used anywhere that a User ID packet may be used.
|
||
*
|
||
* While User Attribute packets are not a required part of the OpenPGP
|
||
* standard, implementations SHOULD provide at least enough
|
||
* compatibility to properly handle a certification signature on the
|
||
* User Attribute packet. A simple way to do this is by treating the
|
||
* User Attribute packet as a User ID packet with opaque contents, but
|
||
* an implementation may use any method desired.
|
||
*/
|
||
module.exports = function packet_user_attribute() {
|
||
this.tag = 17;
|
||
this.attributes = [];
|
||
|
||
/**
|
||
* parsing function for a user attribute packet (tag 17).
|
||
* @param {String} input payload of a tag 17 packet
|
||
* @param {Integer} position position to start reading from the input string
|
||
* @param {Integer} len length of the packet or the remaining length of input at position
|
||
* @return {openpgp_packet_encrypteddata} object representation
|
||
*/
|
||
this.read = function(bytes) {
|
||
var i = 0;
|
||
while (i < bytes.length) {
|
||
var len = openpgp_packet.read_simple_length(bytes);
|
||
|
||
i += len.offset;
|
||
this.attributes.push(bytes.substr(i, len.len));
|
||
i += len.len;
|
||
}
|
||
}
|
||
};
|
||
|
||
},{}],52:[function(require,module,exports){
|
||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||
// Copyright (C) 2011 Recurity Labs GmbH
|
||
//
|
||
// This library is free software; you can redistribute it and/or
|
||
// modify it under the terms of the GNU Lesser General Public
|
||
// License as published by the Free Software Foundation; either
|
||
// version 2.1 of the License, or (at your option) any later version.
|
||
//
|
||
// This library is distributed in the hope that it will be useful,
|
||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
// Lesser General Public License for more details.
|
||
//
|
||
// You should have received a copy of the GNU Lesser General Public
|
||
// License along with this library; if not, write to the Free Software
|
||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||
|
||
var util = require('../util');
|
||
|
||
/**
|
||
* @class
|
||
* @classdesc Implementation of the User ID Packet (Tag 13)
|
||
* A User ID packet consists of UTF-8 text that is intended to represent
|
||
* the name and email address of the key holder. By convention, it
|
||
* includes an RFC 2822 [RFC2822] mail name-addr, but there are no
|
||
* restrictions on its content. The packet length in the header
|
||
* specifies the length of the User ID.
|
||
*/
|
||
module.exports = function packet_userid() {
|
||
/** @type {String} A string containing the user id. Usually in the form
|
||
* John Doe <john@example.com>
|
||
*/
|
||
this.userid = '';
|
||
|
||
|
||
/**
|
||
* Parsing function for a user id packet (tag 13).
|
||
* @param {String} input payload of a tag 13 packet
|
||
* @param {Integer} position position to start reading from the input string
|
||
* @param {Integer} len length of the packet or the remaining length of input
|
||
* at position
|
||
* @return {openpgp_packet_encrypteddata} object representation
|
||
*/
|
||
this.read = function(bytes) {
|
||
this.userid = util.decode_utf8(bytes);
|
||
}
|
||
|
||
/**
|
||
* Creates a string representation of the user id packet
|
||
* @param {String} user_id the user id as string ("John Doe <john.doe@mail.us")
|
||
* @return {String} string representation
|
||
*/
|
||
this.write = function() {
|
||
return util.encode_utf8(this.userid);
|
||
}
|
||
}
|
||
|
||
},{"../util":56}],53:[function(require,module,exports){
|
||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||
// Copyright (C) 2011 Recurity Labs GmbH
|
||
//
|
||
// This library is free software; you can redistribute it and/or
|
||
// modify it under the terms of the GNU Lesser General Public
|
||
// License as published by the Free Software Foundation; either
|
||
// version 2.1 of the License, or (at your option) any later version.
|
||
//
|
||
// This library is distributed in the hope that it will be useful,
|
||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
// Lesser General Public License for more details.
|
||
//
|
||
// You should have received a copy of the GNU Lesser General Public
|
||
// License along with this library; if not, write to the Free Software
|
||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||
|
||
var util = require('../util');
|
||
|
||
/**
|
||
* @class
|
||
* @classdesc Implementation of type key id (RFC4880 3.3)
|
||
* A Key ID is an eight-octet scalar that identifies a key.
|
||
Implementations SHOULD NOT assume that Key IDs are unique. The
|
||
section "Enhanced Key Formats" below describes how Key IDs are
|
||
formed.
|
||
*/
|
||
function keyid() {
|
||
|
||
this.bytes = '';
|
||
|
||
|
||
/**
|
||
* Parsing method for a key id
|
||
* @param {String} input Input to read the key id from
|
||
* @param {integer} position Position where to start reading the key
|
||
* id from input
|
||
* @return {openpgp_type_keyid} This object
|
||
*/
|
||
this.read = function(bytes) {
|
||
this.bytes = bytes.substr(0, 8);
|
||
}
|
||
|
||
this.write = function() {
|
||
return this.bytes;
|
||
}
|
||
|
||
this.toHex = function() {
|
||
return util.hexstrdump(this.bytes);
|
||
}
|
||
|
||
this.equals = function(keyid) {
|
||
return this.bytes == keyid.bytes;
|
||
}
|
||
|
||
this.isNull = function() {
|
||
return this.bytes === '';
|
||
}
|
||
}
|
||
|
||
keyid.mapToHex = function(keyid) {
|
||
return keyid.toHex();
|
||
}
|
||
|
||
module.exports = keyid;
|
||
|
||
},{"../util":56}],54:[function(require,module,exports){
|
||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||
// Copyright (C) 2011 Recurity Labs GmbH
|
||
//
|
||
// This library is free software; you can redistribute it and/or
|
||
// modify it under the terms of the GNU Lesser General Public
|
||
// License as published by the Free Software Foundation; either
|
||
// version 2.1 of the License, or (at your option) any later version.
|
||
//
|
||
// This library is distributed in the hope that it will be useful,
|
||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
// Lesser General Public License for more details.
|
||
//
|
||
// You should have received a copy of the GNU Lesser General Public
|
||
// License along with this library; if not, write to the Free Software
|
||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||
|
||
// Hint: We hold our MPIs as an array of octets in big endian format preceeding a two
|
||
// octet scalar: MPI: [a,b,c,d,e,f]
|
||
// - MPI size: (a << 8) | b
|
||
// - MPI = c | d << 8 | e << ((MPI.length -2)*8) | f ((MPI.length -2)*8)
|
||
|
||
var BigInteger = require('../crypto/public_key/jsbn.js'),
|
||
util = require('../util');
|
||
|
||
/**
|
||
* @class
|
||
* @classdescImplementation of type MPI (RFC4880 3.2)
|
||
* Multiprecision integers (also called MPIs) are unsigned integers used
|
||
* to hold large integers such as the ones used in cryptographic
|
||
* calculations.
|
||
* An MPI consists of two pieces: a two-octet scalar that is the length
|
||
* of the MPI in bits followed by a string of octets that contain the
|
||
* actual integer.
|
||
*/
|
||
module.exports = function mpi() {
|
||
/** An implementation dependent integer */
|
||
this.data = null;
|
||
|
||
/**
|
||
* Parsing function for a mpi (RFC 4880 3.2).
|
||
* @param {String} input Payload of mpi data
|
||
* @param {Integer} position Position to start reading from the input
|
||
* string
|
||
* @param {Integer} len Length of the packet or the remaining length of
|
||
* input at position
|
||
* @return {openpgp_type_mpi} Object representation
|
||
*/
|
||
this.read = function(bytes) {
|
||
var bits = (bytes.charCodeAt(0) << 8) | bytes.charCodeAt(1);
|
||
|
||
// Additional rules:
|
||
//
|
||
// The size of an MPI is ((MPI.length + 7) / 8) + 2 octets.
|
||
//
|
||
// The length field of an MPI describes the length starting from its
|
||
// most significant non-zero bit. Thus, the MPI [00 02 01] is not
|
||
// formed correctly. It should be [00 01 01].
|
||
|
||
// TODO: Verification of this size method! This size calculation as
|
||
// specified above is not applicable in JavaScript
|
||
var bytelen = Math.ceil(bits / 8);
|
||
|
||
var raw = bytes.substr(2, bytelen);
|
||
this.fromBytes(raw);
|
||
|
||
return 2 + bytelen;
|
||
}
|
||
|
||
this.fromBytes = function(bytes) {
|
||
this.data = new BigInteger(util.hexstrdump(bytes), 16);
|
||
}
|
||
|
||
this.toBytes = function() {
|
||
return this.write().substr(2);
|
||
}
|
||
|
||
this.byteLength = function() {
|
||
return this.toBytes().length;
|
||
}
|
||
|
||
/**
|
||
* Converts the mpi object to a string as specified in RFC4880 3.2
|
||
* @return {String} mpi Byte representation
|
||
*/
|
||
this.write = function() {
|
||
return this.data.toMPI();
|
||
}
|
||
|
||
this.toBigInteger = function() {
|
||
return this.data.clone();
|
||
}
|
||
|
||
this.fromBigInteger = function(bn) {
|
||
this.data = bn.clone();
|
||
}
|
||
}
|
||
|
||
},{"../crypto/public_key/jsbn.js":21,"../util":56}],55:[function(require,module,exports){
|
||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||
// Copyright (C) 2011 Recurity Labs GmbH
|
||
//
|
||
// This library is free software; you can redistribute it and/or
|
||
// modify it under the terms of the GNU Lesser General Public
|
||
// License as published by the Free Software Foundation; either
|
||
// version 2.1 of the License, or (at your option) any later version.
|
||
//
|
||
// This library is distributed in the hope that it will be useful,
|
||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
// Lesser General Public License for more details.
|
||
//
|
||
// You should have received a copy of the GNU Lesser General Public
|
||
// License along with this library; if not, write to the Free Software
|
||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||
|
||
var enums = require('../enums.js'),
|
||
util = require('../util'),
|
||
crypto = require('../crypto');
|
||
|
||
/**
|
||
* @class
|
||
* @classdesc Implementation of the String-to-key specifier (RFC4880 3.7)
|
||
* String-to-key (S2K) specifiers are used to convert passphrase strings
|
||
into symmetric-key encryption/decryption keys. They are used in two
|
||
places, currently: to encrypt the secret part of private keys in the
|
||
private keyring, and to convert passphrases to encryption keys for
|
||
symmetrically encrypted messages.
|
||
*/
|
||
module.exports = function s2k() {
|
||
/** @type {openpgp.hash} */
|
||
this.algorithm = 'sha256';
|
||
/** @type {openpgp_type_s2k.type} */
|
||
this.type = 'iterated';
|
||
this.c = 96;
|
||
/** @type {openpgp_bytearray}
|
||
* Eight bytes of salt. */
|
||
this.salt = crypto.random.getRandomBytes(8);
|
||
|
||
|
||
// Exponen bias, defined in RFC4880
|
||
var expbias = 6;
|
||
|
||
this.get_count = function() {
|
||
return (16 + (this.c & 15)) << ((this.c >> 4) + expbias);
|
||
}
|
||
|
||
/**
|
||
* Parsing function for a string-to-key specifier (RFC 4880 3.7).
|
||
* @param {String} input Payload of string-to-key specifier
|
||
* @return {Integer} Actual length of the object
|
||
*/
|
||
this.read = function(bytes) {
|
||
var i = 0;
|
||
this.type = enums.read(enums.s2k, bytes.charCodeAt(i++));
|
||
this.algorithm = enums.read(enums.hash, bytes.charCodeAt(i++));
|
||
|
||
switch (this.type) {
|
||
case 'simple':
|
||
break;
|
||
|
||
case 'salted':
|
||
this.salt = bytes.substr(i, 8);
|
||
i += 8;
|
||
break;
|
||
|
||
case 'iterated':
|
||
this.salt = bytes.substr(i, 8);
|
||
i += 8;
|
||
|
||
// Octet 10: count, a one-octet, coded value
|
||
this.c = bytes.charCodeAt(i++);
|
||
break;
|
||
|
||
case 'gnu':
|
||
if (bytes.substr(i, 3) == "GNU") {
|
||
i += 3; // GNU
|
||
var gnuExtType = 1000 + bytes.charCodeAt(i++);
|
||
if (gnuExtType == 1001) {
|
||
this.type = gnuExtType;
|
||
// GnuPG extension mode 1001 -- don't write secret key at all
|
||
} else {
|
||
throw new Error("Unknown s2k gnu protection mode.");
|
||
}
|
||
} else {
|
||
throw new Error("Unknown s2k type.");
|
||
}
|
||
break;
|
||
|
||
default:
|
||
throw new Error("Unknown s2k type.");
|
||
break;
|
||
}
|
||
|
||
return i;
|
||
}
|
||
|
||
|
||
/**
|
||
* writes an s2k hash based on the inputs.
|
||
* @return {String} Produced key of hashAlgorithm hash length
|
||
*/
|
||
this.write = function() {
|
||
var bytes = String.fromCharCode(enums.write(enums.s2k, this.type));
|
||
bytes += String.fromCharCode(enums.write(enums.hash, this.algorithm));
|
||
|
||
switch (this.type) {
|
||
case 'simple':
|
||
break;
|
||
case 'salted':
|
||
bytes += this.salt;
|
||
break;
|
||
case 'iterated':
|
||
bytes += this.salt;
|
||
bytes += String.fromCharCode(this.c);
|
||
break;
|
||
};
|
||
|
||
return bytes;
|
||
}
|
||
|
||
/**
|
||
* Produces a key using the specified passphrase and the defined
|
||
* hashAlgorithm
|
||
* @param {String} passphrase Passphrase containing user input
|
||
* @return {String} Produced key with a length corresponding to
|
||
* hashAlgorithm hash length
|
||
*/
|
||
this.produce_key = function(passphrase, numBytes) {
|
||
passphrase = util.encode_utf8(passphrase);
|
||
|
||
function round(prefix, s2k) {
|
||
var algorithm = enums.write(enums.hash, s2k.algorithm);
|
||
|
||
switch (s2k.type) {
|
||
case 'simple':
|
||
return crypto.hash.digest(algorithm, prefix + passphrase);
|
||
|
||
case 'salted':
|
||
return crypto.hash.digest(algorithm,
|
||
prefix + s2k.salt + passphrase);
|
||
|
||
case 'iterated':
|
||
var isp = [],
|
||
count = s2k.get_count();
|
||
data = s2k.salt + passphrase;
|
||
|
||
while (isp.length * data.length < count)
|
||
isp.push(data);
|
||
|
||
isp = isp.join('');
|
||
|
||
if (isp.length > count)
|
||
isp = isp.substr(0, count);
|
||
|
||
return crypto.hash.digest(algorithm, prefix + isp);
|
||
};
|
||
}
|
||
|
||
var result = '',
|
||
prefix = '';
|
||
|
||
while (result.length <= numBytes) {
|
||
result += round(prefix, this);
|
||
prefix += String.fromCharCode(0);
|
||
}
|
||
|
||
return result.substr(0, numBytes);
|
||
}
|
||
}
|
||
|
||
},{"../crypto":16,"../enums.js":27,"../util":56}],56:[function(require,module,exports){
|
||
// GPG4Browsers - An OpenPGP implementation in javascript
|
||
// Copyright (C) 2011 Recurity Labs GmbH
|
||
//
|
||
// This library is free software; you can redistribute it and/or
|
||
// modify it under the terms of the GNU Lesser General Public
|
||
// License as published by the Free Software Foundation; either
|
||
// version 2.1 of the License, or (at your option) any later version.
|
||
//
|
||
// This library is distributed in the hope that it will be useful,
|
||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
// Lesser General Public License for more details.
|
||
//
|
||
// You should have received a copy of the GNU Lesser General Public
|
||
// License along with this library; if not, write to the Free Software
|
||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||
|
||
var config = require('../config');
|
||
|
||
var Util = function() {
|
||
|
||
this.readNumber = function(bytes) {
|
||
var n = 0;
|
||
|
||
for (var i = 0; i < bytes.length; i++) {
|
||
n <<= 8;
|
||
n += bytes.charCodeAt(i);
|
||
}
|
||
|
||
return n;
|
||
};
|
||
|
||
this.writeNumber = function(n, bytes) {
|
||
var b = '';
|
||
for (var i = 0; i < bytes; i++) {
|
||
b += String.fromCharCode((n >> (8 * (bytes - i - 1))) & 0xFF);
|
||
}
|
||
|
||
return b;
|
||
};
|
||
|
||
|
||
|
||
this.readDate = function(bytes) {
|
||
var n = this.readNumber(bytes);
|
||
var d = new Date();
|
||
d.setTime(n * 1000);
|
||
return d;
|
||
};
|
||
|
||
this.writeDate = function(time) {
|
||
var numeric = Math.round(time.getTime() / 1000);
|
||
|
||
return this.writeNumber(numeric, 4);
|
||
};
|
||
|
||
this.emailRegEx = /^[+a-zA-Z0-9_.-]+@([a-zA-Z0-9-]+\.)+[a-zA-Z0-9]{2,6}$/;
|
||
|
||
this.debug = false;
|
||
|
||
this.hexdump = function(str) {
|
||
var r = [];
|
||
var e = str.length;
|
||
var c = 0;
|
||
var h;
|
||
var i = 0;
|
||
while (c < e) {
|
||
h = str.charCodeAt(c++).toString(16);
|
||
while (h.length < 2) h = "0" + h;
|
||
r.push(" " + h);
|
||
i++;
|
||
if (i % 32 == 0)
|
||
r.push("\n ");
|
||
}
|
||
return r.join('');
|
||
};
|
||
|
||
/**
|
||
* Create hexstring from a binary
|
||
* @param {String} str String to convert
|
||
* @return {String} String containing the hexadecimal values
|
||
*/
|
||
this.hexstrdump = function(str) {
|
||
if (str == null)
|
||
return "";
|
||
var r = [];
|
||
var e = str.length;
|
||
var c = 0;
|
||
var h;
|
||
while (c < e) {
|
||
h = str.charCodeAt(c++).toString(16);
|
||
while (h.length < 2) h = "0" + h;
|
||
r.push("" + h);
|
||
}
|
||
return r.join('');
|
||
};
|
||
|
||
/**
|
||
* Create binary string from a hex encoded string
|
||
* @param {String} str Hex string to convert
|
||
* @return {String} String containing the binary values
|
||
*/
|
||
this.hex2bin = function(hex) {
|
||
var str = '';
|
||
for (var i = 0; i < hex.length; i += 2)
|
||
str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
|
||
return str;
|
||
};
|
||
|
||
/**
|
||
* Creating a hex string from an binary array of integers (0..255)
|
||
* @param {String} str Array of bytes to convert
|
||
* @return {String} Hexadecimal representation of the array
|
||
*/
|
||
this.hexidump = function(str) {
|
||
var r = [];
|
||
var e = str.length;
|
||
var c = 0;
|
||
var h;
|
||
while (c < e) {
|
||
h = str[c++].toString(16);
|
||
while (h.length < 2) h = "0" + h;
|
||
r.push("" + h);
|
||
}
|
||
return r.join('');
|
||
};
|
||
|
||
|
||
/**
|
||
* Convert a native javascript string to a string of utf8 bytes
|
||
* @param {String} str The string to convert
|
||
* @return {String} A valid squence of utf8 bytes
|
||
*/
|
||
this.encode_utf8 = function(str) {
|
||
return unescape(encodeURIComponent(str));
|
||
};
|
||
|
||
/**
|
||
* Convert a string of utf8 bytes to a native javascript string
|
||
* @param {String} utf8 A valid squence of utf8 bytes
|
||
* @return {String} A native javascript string
|
||
*/
|
||
this.decode_utf8 = function(utf8) {
|
||
try {
|
||
return decodeURIComponent(escape(utf8));
|
||
} catch (e) {
|
||
return utf8;
|
||
}
|
||
};
|
||
|
||
var str2bin = function(str, result) {
|
||
for (var i = 0; i < str.length; i++) {
|
||
result[i] = str.charCodeAt(i);
|
||
}
|
||
|
||
return result;
|
||
};
|
||
|
||
var bin2str = function(bin) {
|
||
var result = [];
|
||
|
||
for (var i = 0; i < bin.length; i++) {
|
||
result.push(String.fromCharCode(bin[i]));
|
||
}
|
||
|
||
return result.join('');
|
||
};
|
||
|
||
/**
|
||
* Convert a string to an array of integers(0.255)
|
||
* @param {String} str String to convert
|
||
* @return {Integer[]} An array of (binary) integers
|
||
*/
|
||
this.str2bin = function(str) {
|
||
return str2bin(str, new Array(str.length));
|
||
};
|
||
|
||
|
||
/**
|
||
* Convert an array of integers(0.255) to a string
|
||
* @param {Integer[]} bin An array of (binary) integers to convert
|
||
* @return {String} The string representation of the array
|
||
*/
|
||
this.bin2str = bin2str;
|
||
|
||
/**
|
||
* Convert a string to a Uint8Array
|
||
* @param {String} str String to convert
|
||
* @return {Uint8Array} The array of (binary) integers
|
||
*/
|
||
this.str2Uint8Array = function(str) {
|
||
return str2bin(str, new Uint8Array(new ArrayBuffer(str.length)));
|
||
};
|
||
|
||
/**
|
||
* Convert a Uint8Array to a string. This currently functions
|
||
* the same as bin2str.
|
||
* @param {Uint8Array} bin An array of (binary) integers to convert
|
||
* @return {String} String representation of the array
|
||
*/
|
||
this.Uint8Array2str = bin2str;
|
||
|
||
/**
|
||
* Calculates a 16bit sum of a string by adding each character
|
||
* codes modulus 65535
|
||
* @param {String} text String to create a sum of
|
||
* @return {Integer} An integer containing the sum of all character
|
||
* codes % 65535
|
||
*/
|
||
this.calc_checksum = function(text) {
|
||
var checksum = {
|
||
s: 0,
|
||
add: function(sadd) {
|
||
this.s = (this.s + sadd) % 65536;
|
||
}
|
||
};
|
||
for (var i = 0; i < text.length; i++) {
|
||
checksum.add(text.charCodeAt(i));
|
||
}
|
||
return checksum.s;
|
||
};
|
||
|
||
/**
|
||
* Helper function to print a debug message. Debug
|
||
* messages are only printed if
|
||
* openpgp.config.debug is set to true.
|
||
* @param {String} str String of the debug message
|
||
*/
|
||
this.print_debug = function(str) {
|
||
if (config.debug) {
|
||
console.log(str);
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Helper function to print a debug message. Debug
|
||
* messages are only printed if
|
||
* openpgp.config.debug is set to true.
|
||
* Different than print_debug because will call hexstrdump iff necessary.
|
||
* @param {String} str String of the debug message
|
||
*/
|
||
this.print_debug_hexstr_dump = function(str, strToHex) {
|
||
if (config.debug) {
|
||
str = str + this.hexstrdump(strToHex);
|
||
console.log(str);
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Helper function to print an error message.
|
||
* @param {String} str String of the error message
|
||
*/
|
||
this.print_error = function(str) {
|
||
if (config.debug)
|
||
throw str;
|
||
console.log(str);
|
||
};
|
||
|
||
/**
|
||
* Helper function to print an info message.
|
||
* @param {String} str String of the info message
|
||
*/
|
||
this.print_info = function(str) {
|
||
if (config.debug)
|
||
console.log(str);
|
||
};
|
||
|
||
this.print_warning = function(str) {
|
||
console.log(str);
|
||
};
|
||
|
||
this.getLeftNBits = function(string, bitcount) {
|
||
var rest = bitcount % 8;
|
||
if (rest == 0)
|
||
return string.substring(0, bitcount / 8);
|
||
var bytes = (bitcount - rest) / 8 + 1;
|
||
var result = string.substring(0, bytes);
|
||
return this.shiftRight(result, 8 - rest); // +String.fromCharCode(string.charCodeAt(bytes -1) << (8-rest) & 0xFF);
|
||
};
|
||
|
||
/**
|
||
* Shifting a string to n bits right
|
||
* @param {String} value The string to shift
|
||
* @param {Integer} bitcount Amount of bits to shift (MUST be smaller
|
||
* than 9)
|
||
* @return {String} Resulting string.
|
||
*/
|
||
this.shiftRight = function(value, bitcount) {
|
||
var temp = util.str2bin(value);
|
||
if (bitcount % 8 != 0) {
|
||
for (var i = temp.length - 1; i >= 0; i--) {
|
||
temp[i] >>= bitcount % 8;
|
||
if (i > 0)
|
||
temp[i] |= (temp[i - 1] << (8 - (bitcount % 8))) & 0xFF;
|
||
}
|
||
} else {
|
||
return value;
|
||
}
|
||
return util.bin2str(temp);
|
||
};
|
||
|
||
/**
|
||
* Return the algorithm type as string
|
||
* @return {String} String representing the message type
|
||
*/
|
||
this.get_hashAlgorithmString = function(algo) {
|
||
switch (algo) {
|
||
case 1:
|
||
return "MD5";
|
||
case 2:
|
||
return "SHA1";
|
||
case 3:
|
||
return "RIPEMD160";
|
||
case 8:
|
||
return "SHA256";
|
||
case 9:
|
||
return "SHA384";
|
||
case 10:
|
||
return "SHA512";
|
||
case 11:
|
||
return "SHA224";
|
||
}
|
||
return "unknown";
|
||
};
|
||
|
||
};
|
||
|
||
/**
|
||
* an instance that should be used.
|
||
*/
|
||
module.exports = new Util();
|
||
|
||
},{"../config":3}]},{},[])
|
||
//@ sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlcyI6WyIvaG9tZS9yb2JlcnQvemltYnJhLXBncC9vcGVucGdwanMta2V5cmluZy9zcmMvY2xlYXJ0ZXh0LmpzIiwiL2hvbWUvcm9iZXJ0L3ppbWJyYS1wZ3Avb3BlbnBncGpzLWtleXJpbmcvc3JjL2NvbXByZXNzaW9uL2p4Zy5qcyIsIi9ob21lL3JvYmVydC96aW1icmEtcGdwL29wZW5wZ3Bqcy1rZXlyaW5nL3NyYy9jb25maWcvY29uZmlnLmpzIiwiL2hvbWUvcm9iZXJ0L3ppbWJyYS1wZ3Avb3BlbnBncGpzLWtleXJpbmcvc3JjL2NyeXB0by9jZmIuanMiLCIvaG9tZS9yb2JlcnQvemltYnJhLXBncC9vcGVucGdwanMta2V5cmluZy9zcmMvY3J5cHRvL2NpcGhlci9hZXMuanMiLCIvaG9tZS9yb2JlcnQvemltYnJhLXBncC9vcGVucGdwanMta2V5cmluZy9zcmMvY3J5cHRvL2NpcGhlci9ibG93ZmlzaC5qcyIsIi9ob21lL3JvYmVydC96aW1icmEtcGdwL29wZW5wZ3Bqcy1rZXlyaW5nL3NyYy9jcnlwdG8vY2lwaGVyL2Nhc3Q1LmpzIiwiL2hvbWUvcm9iZXJ0L3ppbWJyYS1wZ3Avb3BlbnBncGpzLWtleXJpbmcvc3JjL2NyeXB0by9jaXBoZXIvZGVzLmpzIiwiL2hvbWUvcm9iZXJ0L3ppbWJyYS1wZ3Avb3BlbnBncGpzLWtleXJpbmcvc3JjL2NyeXB0by9jaXBoZXIvaW5kZXguanMiLCIvaG9tZS9yb2JlcnQvemltYnJhLXBncC9vcGVucGdwanMta2V5cmluZy9zcmMvY3J5cHRvL2NpcGhlci90d29maXNoLmpzIiwiL2hvbWUvcm9iZXJ0L3ppbWJyYS1wZ3Avb3BlbnBncGpzLWtleXJpbmcvc3JjL2NyeXB0by9jcnlwdG8uanMiLCIvaG9tZS9yb2JlcnQvemltYnJhLXBncC9vcGVucGdwanMta2V5cmluZy9zcmMvY3J5cHRvL2hhc2gvaW5kZXguanMiLCIvaG9tZS9yb2JlcnQvemltYnJhLXBncC9vcGVucGdwanMta2V5cmluZy9zcmMvY3J5cHRvL2hhc2gvbWQ1LmpzIiwiL2hvbWUvcm9iZXJ0L3ppbWJyYS1wZ3Avb3BlbnBncGpzLWtleXJpbmcvc3JjL2NyeXB0by9oYXNoL3JpcGUtbWQuanMiLCIvaG9tZS9yb2JlcnQvemltYnJhLXBncC9vcGVucGdwanMta2V5cmluZy9zcmMvY3J5cHRvL2hhc2gvc2hhLmpzIiwiL2hvbWUvcm9iZXJ0L3ppbWJyYS1wZ3Avb3BlbnBncGpzLWtleXJpbmcvc3JjL2NyeXB0by9pbmRleC5qcyIsIi9ob21lL3JvYmVydC96aW1icmEtcGdwL29wZW5wZ3Bqcy1rZXlyaW5nL3NyYy9jcnlwdG8vcGtjczEuanMiLCIvaG9tZS9yb2JlcnQvemltYnJhLXBncC9vcGVucGdwanMta2V5cmluZy9zcmMvY3J5cHRvL3B1YmxpY19rZXkvZHNhLmpzIiwiL2hvbWUvcm9iZXJ0L3ppbWJyYS1wZ3Avb3BlbnBncGpzLWtleXJpbmcvc3JjL2NyeXB0by9wdWJsaWNfa2V5L2VsZ2FtYWwuanMiLCIvaG9tZS9yb2JlcnQvemltYnJhLXBncC9vcGVucGdwanMta2V5cmluZy9zcmMvY3J5cHRvL3B1YmxpY19rZXkvaW5kZXguanMiLCIvaG9tZS9yb2JlcnQvemltYnJhLXBncC9vcGVucGdwanMta2V5cmluZy9zcmMvY3J5cHRvL3B1YmxpY19rZXkvanNibi5qcyIsIi9ob21lL3JvYmVydC96aW1icmEtcGdwL29wZW5wZ3Bqcy1rZXlyaW5nL3NyYy9jcnlwdG8vcHVibGljX2tleS9yc2EuanMiLCIvaG9tZS9yb2JlcnQvemltYnJhLXBncC9vcGVucGdwanMta2V5cmluZy9zcmMvY3J5cHRvL3JhbmRvbS5qcyIsIi9ob21lL3JvYmVydC96aW1icmEtcGdwL29wZW5wZ3Bqcy1rZXlyaW5nL3NyYy9jcnlwdG8vc2lnbmF0dXJlLmpzIiwiL2hvbWUvcm9iZXJ0L3ppbWJyYS1wZ3Avb3BlbnBncGpzLWtleXJpbmcvc3JjL2VuY29kaW5nL2FybW9yLmpzIiwiL2hvbWUvcm9iZXJ0L3ppbWJyYS1wZ3Avb3BlbnBncGpzLWtleXJpbmcvc3JjL2VuY29kaW5nL2Jhc2U2NC5qcyIsIi9ob21lL3JvYmVydC96aW1icmEtcGdwL29wZW5wZ3Bqcy1rZXlyaW5nL3NyYy9lbnVtcy5qcyIsIi9ob21lL3JvYmVydC96aW1icmEtcGdwL29wZW5wZ3Bqcy1rZXlyaW5nL3NyYy9pbmRleC5qcyIsIi9ob21lL3JvYmVydC96aW1icmEtcGdwL29wZW5wZ3Bqcy1rZXlyaW5nL3NyYy9rZXkuanMiLCIvaG9tZS9yb2JlcnQvemltYnJhLXBncC9vcGVucGdwanMta2V5cmluZy9zcmMvbWVzc2FnZS5qcyIsIi9ob21lL3JvYmVydC96aW1icmEtcGdwL29wZW5wZ3Bqcy1rZXlyaW5nL3NyYy9vcGVucGdwLmpzIiwiL2hvbWUvcm9iZXJ0L3ppbWJyYS1wZ3Avb3BlbnBncGpzLWtleXJpbmcvc3JjL3BhY2tldC9hbGxfcGFja2V0cy5qcyIsIi9ob21lL3JvYmVydC96aW1icmEtcGdwL29wZW5wZ3Bqcy1rZXlyaW5nL3NyYy9wYWNrZXQvY29tcHJlc3NlZC5qcyIsIi9ob21lL3JvYmVydC96aW1icmEtcGdwL29wZW5wZ3Bqcy1rZXlyaW5nL3NyYy9wYWNrZXQvaW5kZXguanMiLCIvaG9tZS9yb2JlcnQvemltYnJhLXBncC9vcGVucGdwanMta2V5cmluZy9zcmMvcGFja2V0L2xpdGVyYWwuanMiLCIvaG9tZS9yb2JlcnQvemltYnJhLXBncC9vcGVucGdwanMta2V5cmluZy9zcmMvcGFja2V0L21hcmtlci5qcyIsIi9ob21lL3JvYmVydC96aW1icmEtcGdwL29wZW5wZ3Bqcy1rZXlyaW5nL3NyYy9wYWNrZXQvb25lX3Bhc3Nfc2lnbmF0dXJlLmpzIiwiL2hvbWUvcm9iZXJ0L3ppbWJyYS1wZ3Avb3BlbnBncGpzLWtleXJpbmcvc3JjL3BhY2tldC9wYWNrZXQuanMiLCIvaG9tZS9yb2JlcnQvemltYnJhLXBncC9vcGVucGdwanMta2V5cmluZy9zcmMvcGFja2V0L3BhY2tldGxpc3QuanMiLCIvaG9tZS9yb2JlcnQvemltYnJhLXBncC9vcGVucGdwanMta2V5cmluZy9zcmMvcGFja2V0L3B1YmxpY19rZXkuanMiLCIvaG9tZS9yb2JlcnQvemltYnJhLXBncC9vcGVucGdwanMta2V5cmluZy9zcmMvcGFja2V0L3B1YmxpY19rZXlfZW5jcnlwdGVkX3Nlc3Npb25fa2V5LmpzIiwiL2hvbWUvcm9iZXJ0L3ppbWJyYS1wZ3Avb3BlbnBncGpzLWtleXJpbmcvc3JjL3BhY2tldC9wdWJsaWNfc3Via2V5LmpzIiwiL2hvbWUvcm9iZXJ0L3ppbWJyYS1wZ3Avb3BlbnBncGpzLWtleXJpbmcvc3JjL3BhY2tldC9zZWNyZXRfa2V5LmpzIiwiL2hvbWUvcm9iZXJ0L3ppbWJyYS1wZ3Avb3BlbnBncGpzLWtleXJpbmcvc3JjL3BhY2tldC9zZWNyZXRfc3Via2V5LmpzIiwiL2hvbWUvcm9iZXJ0L3ppbWJyYS1wZ3Avb3BlbnBncGpzLWtleXJpbmcvc3JjL3BhY2tldC9zaWduYXR1cmUuanMiLCIvaG9tZS9yb2JlcnQvemltYnJhLXBncC9vcGVucGdwanMta2V5cmluZy9zcmMvcGFja2V0L3N5bV9lbmNyeXB0ZWRfaW50ZWdyaXR5X3Byb3RlY3RlZC5qcyIsIi9ob21lL3JvYmVydC96aW1icmEtcGdwL29wZW5wZ3Bqcy1rZXlyaW5nL3NyYy9wYWNrZXQvc3ltX2VuY3J5cHRlZF9zZXNzaW9uX2tleS5qcyIsIi9ob21lL3JvYmVydC96aW1icmEtcGdwL29wZW5wZ3Bqcy1rZXlyaW5nL3NyYy9wYWNrZXQvc3ltbWV0cmljYWxseV9lbmNyeXB0ZWQuanMiLCIvaG9tZS9yb2JlcnQvemltYnJhLXBncC9vcGVucGdwanMta2V5cmluZy9zcmMvcGFja2V0L3RydXN0LmpzIiwiL2hvbWUvcm9iZXJ0L3ppbWJyYS1wZ3Avb3BlbnBncGpzLWtleXJpbmcvc3JjL3BhY2tldC91c2VyX2F0dHJpYnV0ZS5qcyIsIi9ob21lL3JvYmVydC96aW1icmEtcGdwL29wZW5wZ3Bqcy1rZXlyaW5nL3NyYy9wYWNrZXQvdXNlcmlkLmpzIiwiL2hvbWUvcm9iZXJ0L3ppbWJyYS1wZ3Avb3BlbnBncGpzLWtleXJpbmcvc3JjL3R5cGUva2V5aWQuanMiLCIvaG9tZS9yb2JlcnQvemltYnJhLXBncC9vcGVucGdwanMta2V5cmluZy9zcmMvdHlwZS9tcGkuanMiLCIvaG9tZS9yb2JlcnQvemltYnJhLXBncC9vcGVucGdwanMta2V5cmluZy9zcmMvdHlwZS9zMmsuanMiLCIvaG9tZS9yb2JlcnQvemltYnJhLXBncC9vcGVucGdwanMta2V5cmluZy9zcmMvdXRpbC91dGlsLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlJQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ252Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNURBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JUQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzZkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1WkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1bEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JaQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNmQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxWEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeE5BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsTkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDblNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVsQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDZkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdklBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xLQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDckRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pxREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqSkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6R0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hYQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlSQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7QUNkQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDblhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzU0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbkpBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbktBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDVkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0hBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25EQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuUUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hJQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUlBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoTEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN0QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbFFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFtQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeklBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwRUE7QUFDQTtBQUNBO0FBQ0E7O0FDSEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeERBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0tBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBHUEc0QnJvd3NlcnMgLSBBbiBPcGVuUEdQIGltcGxlbWVudGF0aW9uIGluIGphdmFzY3JpcHRcbi8vIENvcHlyaWdodCAoQykgMjAxMSBSZWN1cml0eSBMYWJzIEdtYkhcbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vclxuLy8gbW9kaWZ5IGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyXG4vLyB2ZXJzaW9uIDIuMSBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4vLyBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuLy8gTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZSBHTlVcbi8vIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG4vLyBcbi8vIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYWxvbmcgd2l0aCB0aGlzIGxpYnJhcnk7IGlmIG5vdCwgd3JpdGUgdG8gdGhlIEZyZWUgU29mdHdhcmVcbi8vIEZvdW5kYXRpb24sIEluYy4sIDUxIEZyYW5rbGluIFN0cmVldCwgRmlmdGggRmxvb3IsIEJvc3RvbiwgTUEgIDAyMTEwLTEzMDEgIFVTQVxuXG52YXIgY29uZmlnID0gcmVxdWlyZSgnLi9jb25maWcnKTtcbnZhciBwYWNrZXQgPSByZXF1aXJlKCcuL3BhY2tldCcpO1xudmFyIGVudW1zID0gcmVxdWlyZSgnLi9lbnVtcy5qcycpO1xudmFyIGFybW9yID0gcmVxdWlyZSgnLi9lbmNvZGluZy9hcm1vci5qcycpO1xuXG4vKipcbiAqIEBjbGFzc1xuICogQGNsYXNzZGVzYyBDbGFzcyB0aGF0IHJlcHJlc2VudHMgYW4gT3BlblBHUCBjbGVhcnRleHQgc2lnbmVkIG1lc3NhZ2UuXG4gKiBTZWUgaHR0cDovL3Rvb2xzLmlldGYub3JnL2h0bWwvcmZjNDg4MCNzZWN0aW9uLTdcbiAqIEBwYXJhbSAge1N0cmluZ30gICAgIHRleHQgICAgICAgVGhlIGNsZWFydGV4dCBvZiB0aGUgc2lnbmVkIG1lc3NhZ2VcbiAqIEBwYXJhbSAge3BhY2tldGxpc3R9IHBhY2tldGxpc3QgVGhlIHBhY2tldGxpc3Qgd2l0aCBzaWduYXR1cmUgcGFja2V0cyBvciB1bmRlZmluZWRcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgbWVzc2FnZSBub3QgeWV0IHNpZ25lZFxuICovXG5cbmZ1bmN0aW9uIENsZWFydGV4dE1lc3NhZ2UodGV4dCwgcGFja2V0bGlzdCkge1xuICBpZiAoISh0aGlzIGluc3RhbmNlb2YgQ2xlYXJ0ZXh0TWVzc2FnZSkpIHtcbiAgICByZXR1cm4gbmV3IENsZWFydGV4dE1lc3NhZ2UocGFja2V0bGlzdCk7XG4gIH1cbiAgLy8gbm9ybWFsaXplIEVPTCB0byBjYW5vbmljYWwgZm9ybSA8Q1I+PExGPlxuICB0aGlzLnRleHQgPSB0ZXh0LnJlcGxhY2UoL1xcci9nLCAnJykucmVwbGFjZSgvW1xcdCBdK1xcbi9nLCBcIlxcblwiKS5yZXBsYWNlKC9cXG4vZyxcIlxcclxcblwiKTtcbiAgdGhpcy5wYWNrZXRzID0gcGFja2V0bGlzdCB8fCBuZXcgcGFja2V0Lmxpc3QoKTtcbn1cblxuLyoqXG4gKiBSZXR1cm5zIHRoZSBrZXkgSURzIG9mIHRoZSBrZXlzIHRoYXQgc2lnbmVkIHRoZSBjbGVhcnRleHQgbWVzc2FnZVxuICogQHJldHVybiB7W2tleUlkXX0gYXJyYXkgb2Yga2V5aWQgb2JqZWN0c1xuICovXG5DbGVhcnRleHRNZXNzYWdlLnByb3RvdHlwZS5nZXRTaWduaW5nS2V5SWRzID0gZnVuY3Rpb24oKSB7XG4gIHZhciBrZXlJZHMgPSBbXTtcbiAgdmFyIHNpZ25hdHVyZUxpc3QgPSB0aGlzLnBhY2tldHMuZmlsdGVyQnlUYWcoZW51bXMucGFja2V0LnNpZ25hdHVyZSk7XG4gIHNpZ25hdHVyZUxpc3QuZm9yRWFjaChmdW5jdGlvbihwYWNrZXQpIHtcbiAgICBrZXlJZHMucHVzaChwYWNrZXQuaXNzdWVyS2V5SWQpO1xuICB9KTtcbiAgcmV0dXJuIGtleUlkcztcbn07XG5cbi8qKlxuICogU2lnbiB0aGUgY2xlYXJ0ZXh0IG1lc3NhZ2VcbiAqIEBwYXJhbSAge1trZXldfSBwcml2YXRlS2V5cyBwcml2YXRlIGtleXMgd2l0aCBkZWNyeXB0ZWQgc2VjcmV0IGtleSBkYXRhIGZvciBzaWduaW5nXG4gKi9cbkNsZWFydGV4dE1lc3NhZ2UucHJvdG90eXBlLnNpZ24gPSBmdW5jdGlvbihwcml2YXRlS2V5cykge1xuICB2YXIgcGFja2V0bGlzdCA9IG5ldyBwYWNrZXQubGlzdCgpOyAgXG4gIHZhciBsaXRlcmFsRGF0YVBhY2tldCA9IG5ldyBwYWNrZXQubGl0ZXJhbCgpO1xuICBsaXRlcmFsRGF0YVBhY2tldC5zZXRUZXh0KHRoaXMudGV4dCk7XG4gIGZvciAodmFyIGkgPSAwOyBpIDwgcHJpdmF0ZUtleXMubGVuZ3RoOyBpKyspIHtcbiAgICB2YXIgc2lnbmF0dXJlUGFja2V0ID0gbmV3IHBhY2tldC5zaWduYXR1cmUoKTtcbiAgICBzaWduYXR1cmVQYWNrZXQuc2lnbmF0dXJlVHlwZSA9IGVudW1zLnNpZ25hdHVyZS50ZXh0O1xuICAgIHNpZ25hdHVyZVBhY2tldC5oYXNoQWxnb3JpdGhtID0gY29uZmlnLnByZWZlcl9oYXNoX2FsZ29yaXRobTtcbiAgICB2YXIgc2lnbmluZ0tleVBhY2tldCA9IHByaXZhdGVLZXlzW2ldLmdldFNpZ25pbmdLZXlQYWNrZXQoKTtcbiAgICBzaWduYXR1cmVQYWNrZXQucHVibGljS2V5QWxnb3JpdGhtID0gc2lnbmluZ0tleVBhY2tldC5hbGdvcml0aG07XG4gICAgaWYgKCFzaWduaW5nS2V5UGFja2V0LmlzRGVjcnlwdGVkKSB0aHJvdyBuZXcgRXJyb3IoJ1ByaXZhdGUga2V5IGlzIG5vdCBkZWNyeXB0ZWQuJyk7XG4gICAgc2lnbmF0dXJlUGFja2V0LnNpZ24oc2lnbmluZ0tleVBhY2tldCwgbGl0ZXJhbERhdGFQYWNrZXQpO1xuICAgIHBhY2tldGxpc3QucHVzaChzaWduYXR1cmVQYWNrZXQpO1xuICB9XG4gIHRoaXMucGFja2V0cyA9IHBhY2tldGxpc3Q7XG59O1xuXG4vKipcbiAqIFZlcmlmeSBzaWduYXR1cmVzIG9mIGNsZWFydGV4dCBzaWduZWQgbWVzc2FnZVxuICogQHBhcmFtIHtba2V5XX0gcHVibGljS2V5cyBwdWJsaWMga2V5cyB0byB2ZXJpZnkgc2lnbmF0dXJlc1xuICogQHJldHVybiB7W3sna2V5aWQnOiBrZXlpZCwgJ3ZhbGlkJzogQm9vbGVhbn1dfSBsaXN0IG9mIHNpZ25lcidzIGtleWlkIGFuZCB2YWxpZGl0eSBvZiBzaWduYXR1cmVcbiAqL1xuQ2xlYXJ0ZXh0TWVzc2FnZS5wcm90b3R5cGUudmVyaWZ5ID0gZnVuY3Rpb24ocHVibGljS2V5cykge1xuICB2YXIgcmVzdWx0ID0gW107XG4gIHZhciBzaWduYXR1cmVMaXN0ID0gdGhpcy5wYWNrZXRzLmZpbHRlckJ5VGFnKGVudW1zLnBhY2tldC5zaWduYXR1cmUpO1xuICB2YXIgbGl0ZXJhbERhdGFQYWNrZXQgPSBuZXcgcGFja2V0LmxpdGVyYWwoKTtcbiAgLy8gd2UgYXNzdW1lIHRoYXQgY2xlYXJ0ZXh0IHNpZ25hdHVyZSBpcyBnZW5lcmF0ZWQgYmFzZWQgb24gVVRGOCBjbGVhcnRleHQsXG4gIC8vIGZhaWxzIGZvciBvdGhlciBlbmNvZGluZ3MsIHNlZSBDUC0xMjUyIHRlc3QgY2FzZSBpbiB0ZXN0L3NpZ25hdHVyZS5qc1xuICBsaXRlcmFsRGF0YVBhY2tldC5zZXRUZXh0KHRoaXMudGV4dCk7XG4gIHB1YmxpY0tleXMuZm9yRWFjaChmdW5jdGlvbihwdWJLZXkpIHtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHNpZ25hdHVyZUxpc3QubGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciBwdWJsaWNLZXlQYWNrZXQgPSBwdWJLZXkuZ2V0UHVibGljS2V5UGFja2V0KFtzaWduYXR1cmVMaXN0W2ldLmlzc3VlcktleUlkXSk7XG4gICAgICBpZiAocHVibGljS2V5UGFja2V0KSB7XG4gICAgICAgIHZhciB2ZXJpZmllZFNpZyA9IHt9O1xuICAgICAgICB2ZXJpZmllZFNpZy5rZXlpZCA9IHNpZ25hdHVyZUxpc3RbaV0uaXNzdWVyS2V5SWQ7XG4gICAgICAgIHZlcmlmaWVkU2lnLnN0YXR1cyA9IHNpZ25hdHVyZUxpc3RbaV0udmVyaWZ5KHB1YmxpY0tleVBhY2tldCwgbGl0ZXJhbERhdGFQYWNrZXQpO1xuICAgICAgICByZXN1bHQucHVzaCh2ZXJpZmllZFNpZyk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cbiAgfSk7XG4gIHJldHVybiByZXN1bHQ7XG59O1xuXG4vKipcbiAqIEdldCBjbGVhcnRleHRcbiAqIEByZXR1cm4ge1N0cmluZ30gY2xlYXJ0ZXh0IG9mIG1lc3NhZ2VcbiAqL1xuQ2xlYXJ0ZXh0TWVzc2FnZS5wcm90b3R5cGUuZ2V0VGV4dCA9IGZ1bmN0aW9uKCkge1xuICAvLyBub3JtYWxpemUgZW5kIG9mIGxpbmUgdG8gXFxuXG4gIHJldHVybiB0aGlzLnRleHQucmVwbGFjZSgvXFxyXFxuL2csXCJcXG5cIik7XG59O1xuXG4vKipcbiAqIFJldHVybnMgQVNDSUkgYXJtb3JlZCB0ZXh0IG9mIGNsZWFydGV4dCBzaWduZWQgbWVzc2FnZVxuICogQHJldHVybiB7U3RyaW5nfSBBU0NJSSBhcm1vclxuICovXG5DbGVhcnRleHRNZXNzYWdlLnByb3RvdHlwZS5hcm1vciA9IGZ1bmN0aW9uKCkge1xuICB2YXIgYm9keSA9IHtcbiAgICBoYXNoOiBlbnVtcy5yZWFkKGVudW1zLmhhc2gsIGNvbmZpZy5wcmVmZXJfaGFzaF9hbGdvcml0aG0pLnRvVXBwZXJDYXNlKCksXG4gICAgdGV4dDogdGhpcy50ZXh0LFxuICAgIGRhdGE6IHRoaXMucGFja2V0cy53cml0ZSgpXG4gIH1cbiAgcmV0dXJuIGFybW9yLmVuY29kZShlbnVtcy5hcm1vci5zaWduZWQsIGJvZHkpO1xufTtcblxuXG4vKipcbiAqIHJlYWRzIGFuIE9wZW5QR1AgY2xlYXJ0ZXh0IHNpZ25lZCBtZXNzYWdlIGFuZCByZXR1cm5zIGEgQ2xlYXJ0ZXh0TWVzc2FnZSBvYmplY3RcbiAqIEBwYXJhbSB7U3RyaW5nfSBhcm1vcmVkVGV4dCB0ZXh0IHRvIGJlIHBhcnNlZFxuICogQHJldHVybiB7Q2xlYXJ0ZXh0TWVzc2FnZX0gbmV3IGNsZWFydGV4dCBtZXNzYWdlIG9iamVjdFxuICovXG5mdW5jdGlvbiByZWFkQXJtb3JlZChhcm1vcmVkVGV4dCkge1xuICB2YXIgaW5wdXQgPSBhcm1vci5kZWNvZGUoYXJtb3JlZFRleHQpO1xuICBpZiAoaW5wdXQudHlwZSAhPT0gZW51bXMuYXJtb3Iuc2lnbmVkKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdObyBjbGVhcnRleHQgc2lnbmVkIG1lc3NhZ2UuJyk7XG4gIH1cbiAgdmFyIHBhY2tldGxpc3QgPSBuZXcgcGFja2V0Lmxpc3QoKTtcbiAgcGFja2V0bGlzdC5yZWFkKGlucHV0LmRhdGEpO1xuICB2YXIgbmV3TWVzc2FnZSA9IG5ldyBDbGVhcnRleHRNZXNzYWdlKGlucHV0LnRleHQsIHBhY2tldGxpc3QpO1xuICByZXR1cm4gbmV3TWVzc2FnZTtcbn1cblxuZXhwb3J0cy5DbGVhcnRleHRNZXNzYWdlID0gQ2xlYXJ0ZXh0TWVzc2FnZTtcbmV4cG9ydHMucmVhZEFybW9yZWQgPSByZWFkQXJtb3JlZDtcbiIsIkpYRyA9IHtcbiAgZXhpc3RzOiAoZnVuY3Rpb24odW5kZWZpbmVkKSB7XG4gICAgcmV0dXJuIGZ1bmN0aW9uKHYpIHtcbiAgICAgIHJldHVybiAhKHYgPT09IHVuZGVmaW5lZCB8fCB2ID09PSBudWxsKTtcbiAgICB9XG4gIH0pKClcbn07XG5KWEcuZGVjb21wcmVzcyA9IGZ1bmN0aW9uKHN0cikge1xuICByZXR1cm4gdW5lc2NhcGUoKG5ldyBKWEcuVXRpbC5VbnppcChKWEcuVXRpbC5CYXNlNjQuZGVjb2RlQXNBcnJheShzdHIpKSkudW56aXAoKVswXVswXSk7XG59O1xuLypcbiAgICBDb3B5cmlnaHQgMjAwOC0yMDEyXG4gICAgICAgIE1hdHRoaWFzIEVobWFubixcbiAgICAgICAgTWljaGFlbCBHZXJoYWV1c2VyLFxuICAgICAgICBDYXJzdGVuIE1pbGxlcixcbiAgICAgICAgQmlhbmNhIFZhbGVudGluLFxuICAgICAgICBBbGZyZWQgV2Fzc2VybWFubixcbiAgICAgICAgUGV0ZXIgV2lsZmFocnRcblxuICAgIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIEpTWEdyYXBoLlxuICAgIFxuICAgIER1YWwgbGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlIFZlcnNpb24gMi4wLCBvciBMR1BMIFZlcnNpb24gMyBsaWNlbnNlcy5cblxuICAgIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuICAgIGFsb25nIHdpdGggSlNYQ29tcHJlc3Nvci4gIElmIG5vdCwgc2VlIDxodHRwOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvPi5cbiAgICBcbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBBcGFjaGUgTGljZW5zZSBhbG9uZyB3aXRoIEpTWENvbXByZXNzb3IuICBcbiAgICBJZiBub3QsIHNlZSA8aHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzLz4uXG5cbiovXG5cbi8qKlxuICogQGNsYXNzIFV0aWwgY2xhc3NcbiAqIEBjbGFzc2Rlc2MgVXRpbGl0aWVzIGZvciB1bmNvbXByZXNzaW5nIGFuZCBiYXNlNjQgZGVjb2RpbmdcbiAqIENsYXNzIGZvciBndW56aXBwaW5nLCB1bnppcHBpbmcgYW5kIGJhc2U2NCBkZWNvZGluZyBvZiBmaWxlcy5cbiAqIEl0IGlzIHVzZWQgZm9yIHJlYWRpbmcgR0VPTkV4VCwgR2VvZ2VicmEgYW5kIEludGVyZ2VvIGZpbGVzLlxuICpcbiAqIE9ubHkgSHVmZm1hbiBjb2RlcyBhcmUgZGVjb2RlZCBpbiBndW56aXAuXG4gKiBUaGUgY29kZSBpcyBiYXNlZCBvbiB0aGUgc291cmNlIGNvZGUgZm9yIGd1bnppcC5jIGJ5IFBhc2kgT2phbGEgXG4gKiB7QGxpbmsgaHR0cDovL3d3dy5jcy50dXQuZmkvfmFsYmVydC9EZXYvZ3VuemlwL2d1bnppcC5jfVxuICoge0BsaW5rIGh0dHA6Ly93d3cuY3MudHV0LmZpL35hbGJlcnR9XG4gKi9cbkpYRy5VdGlsID0ge307XG5cbi8qKlxuICogVW56aXAgemlwIGZpbGVzXG4gKi9cbkpYRy5VdGlsLlVuemlwID0gZnVuY3Rpb24oYmFycmF5KSB7XG4gIHZhciBvdXRwdXRBcnIgPSBbXSxcbiAgICBvdXRwdXQgPSBcIlwiLFxuICAgIGRlYnVnID0gZmFsc2UsXG4gICAgZ3BmbGFncyxcbiAgICBmaWxlcyA9IDAsXG4gICAgdW56aXBwZWQgPSBbXSxcbiAgICBjcmMsXG4gICAgYnVmMzJrID0gbmV3IEFycmF5KDMyNzY4KSxcbiAgICBiSWR4ID0gMCxcbiAgICBtb2RlWklQID0gZmFsc2UsXG5cbiAgICBDUkMsIFNJWkUsXG5cbiAgICBiaXRSZXZlcnNlID0gW1xuICAgICAgICAweDAwLCAweDgwLCAweDQwLCAweGMwLCAweDIwLCAweGEwLCAweDYwLCAweGUwLFxuICAgICAgICAweDEwLCAweDkwLCAweDUwLCAweGQwLCAweDMwLCAweGIwLCAweDcwLCAweGYwLFxuICAgICAgICAweDA4LCAweDg4LCAweDQ4LCAweGM4LCAweDI4LCAweGE4LCAweDY4LCAweGU4LFxuICAgICAgICAweDE4LCAweDk4LCAweDU4LCAweGQ4LCAweDM4LCAweGI4LCAweDc4LCAweGY4LFxuICAgICAgICAweDA0LCAweDg0LCAweDQ0LCAweGM0LCAweDI0LCAweGE0LCAweDY0LCAweGU0LFxuICAgICAgICAweDE0LCAweDk0LCAweDU0LCAweGQ0LCAweDM0LCAweGI0LCAweDc0LCAweGY0LFxuICAgICAgICAweDBjLCAweDhjLCAweDRjLCAweGNjLCAweDJjLCAweGFjLCAweDZjLCAweGVjLFxuICAgICAgICAweDFjLCAweDljLCAweDVjLCAweGRjLCAweDNjLCAweGJjLCAweDdjLCAweGZjLFxuICAgICAgICAweDAyLCAweDgyLCAweDQyLCAweGMyLCAweDIyLCAweGEyLCAweDYyLCAweGUyLFxuICAgICAgICAweDEyLCAweDkyLCAweDUyLCAweGQyLCAweDMyLCAweGIyLCAweDcyLCAweGYyLFxuICAgICAgICAweDBhLCAweDhhLCAweDRhLCAweGNhLCAweDJhLCAweGFhLCAweDZhLCAweGVhLFxuICAgICAgICAweDFhLCAweDlhLCAweDVhLCAweGRhLCAweDNhLCAweGJhLCAweDdhLCAweGZhLFxuICAgICAgICAweDA2LCAweDg2LCAweDQ2LCAweGM2LCAweDI2LCAweGE2LCAweDY2LCAweGU2LFxuICAgICAgICAweDE2LCAweDk2LCAweDU2LCAweGQ2LCAweDM2LCAweGI2LCAweDc2LCAweGY2LFxuICAgICAgICAweDBlLCAweDhlLCAweDRlLCAweGNlLCAweDJlLCAweGFlLCAweDZlLCAweGVlLFxuICAgICAgICAweDFlLCAweDllLCAweDVlLCAweGRlLCAweDNlLCAweGJlLCAweDdlLCAweGZlLFxuICAgICAgICAweDAxLCAweDgxLCAweDQxLCAweGMxLCAweDIxLCAweGExLCAweDYxLCAweGUxLFxuICAgICAgICAweDExLCAweDkxLCAweDUxLCAweGQxLCAweDMxLCAweGIxLCAweDcxLCAweGYxLFxuICAgICAgICAweDA5LCAweDg5LCAweDQ5LCAweGM5LCAweDI5LCAweGE5LCAweDY5LCAweGU5LFxuICAgICAgICAweDE5LCAweDk5LCAweDU5LCAweGQ5LCAweDM5LCAweGI5LCAweDc5LCAweGY5LFxuICAgICAgICAweDA1LCAweDg1LCAweDQ1LCAweGM1LCAweDI1LCAweGE1LCAweDY1LCAweGU1LFxuICAgICAgICAweDE1LCAweDk1LCAweDU1LCAweGQ1LCAweDM1LCAweGI1LCAweDc1LCAweGY1LFxuICAgICAgICAweDBkLCAweDhkLCAweDRkLCAweGNkLCAweDJkLCAweGFkLCAweDZkLCAweGVkLFxuICAgICAgICAweDFkLCAweDlkLCAweDVkLCAweGRkLCAweDNkLCAweGJkLCAweDdkLCAweGZkLFxuICAgICAgICAweDAzLCAweDgzLCAweDQzLCAweGMzLCAweDIzLCAweGEzLCAweDYzLCAweGUzLFxuICAgICAgICAweDEzLCAweDkzLCAweDUzLCAweGQzLCAweDMzLCAweGIzLCAweDczLCAweGYzLFxuICAgICAgICAweDBiLCAweDhiLCAweDRiLCAweGNiLCAweDJiLCAweGFiLCAweDZiLCAweGViLFxuICAgICAgICAweDFiLCAweDliLCAweDViLCAweGRiLCAweDNiLCAweGJiLCAweDdiLCAweGZiLFxuICAgICAgICAweDA3LCAweDg3LCAweDQ3LCAweGM3LCAweDI3LCAweGE3LCAweDY3LCAweGU3LFxuICAgICAgICAweDE3LCAweDk3LCAweDU3LCAweGQ3LCAweDM3LCAweGI3LCAweDc3LCAweGY3LFxuICAgICAgICAweDBmLCAweDhmLCAweDRmLCAweGNmLCAweDJmLCAweGFmLCAweDZmLCAweGVmLFxuICAgICAgICAweDFmLCAweDlmLCAweDVmLCAweGRmLCAweDNmLCAweGJmLCAweDdmLCAweGZmXG4gICAgXSxcblxuICAgIGNwbGVucyA9IFtcbiAgICAgICAgMywgNCwgNSwgNiwgNywgOCwgOSwgMTAsIDExLCAxMywgMTUsIDE3LCAxOSwgMjMsIDI3LCAzMSxcbiAgICAgICAgMzUsIDQzLCA1MSwgNTksIDY3LCA4MywgOTksIDExNSwgMTMxLCAxNjMsIDE5NSwgMjI3LCAyNTgsIDAsIDBcbiAgICBdLFxuXG4gICAgY3BsZXh0ID0gW1xuICAgICAgICAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAxLCAxLCAxLCAxLCAyLCAyLCAyLCAyLFxuICAgICAgICAzLCAzLCAzLCAzLCA0LCA0LCA0LCA0LCA1LCA1LCA1LCA1LCAwLCA5OSwgOTlcbiAgICBdLFxuICAgIC8qIDk5PT1pbnZhbGlkICovXG5cbiAgICBjcGRpc3QgPSBbXG4gICAgICAgIDB4MDAwMSwgMHgwMDAyLCAweDAwMDMsIDB4MDAwNCwgMHgwMDA1LCAweDAwMDcsIDB4MDAwOSwgMHgwMDBkLFxuICAgICAgICAweDAwMTEsIDB4MDAxOSwgMHgwMDIxLCAweDAwMzEsIDB4MDA0MSwgMHgwMDYxLCAweDAwODEsIDB4MDBjMSxcbiAgICAgICAgMHgwMTAxLCAweDAxODEsIDB4MDIwMSwgMHgwMzAxLCAweDA0MDEsIDB4MDYwMSwgMHgwODAxLCAweDBjMDEsXG4gICAgICAgIDB4MTAwMSwgMHgxODAxLCAweDIwMDEsIDB4MzAwMSwgMHg0MDAxLCAweDYwMDFcbiAgICBdLFxuXG4gICAgY3BkZXh0ID0gW1xuICAgICAgICAwLCAwLCAwLCAwLCAxLCAxLCAyLCAyLFxuICAgICAgICAzLCAzLCA0LCA0LCA1LCA1LCA2LCA2LFxuICAgICAgICA3LCA3LCA4LCA4LCA5LCA5LCAxMCwgMTAsXG4gICAgICAgIDExLCAxMSwgMTIsIDEyLCAxMywgMTNcbiAgICBdLFxuXG4gICAgYm9yZGVyID0gWzE2LCAxNywgMTgsIDAsIDgsIDcsIDksIDYsIDEwLCA1LCAxMSwgNCwgMTIsIDMsIDEzLCAyLCAxNCwgMSwgMTVdLFxuXG4gICAgYkEgPSBiYXJyYXksXG5cbiAgICBieXRlcG9zID0gMCxcbiAgICBiaXRwb3MgPSAwLFxuICAgIGJiID0gMSxcbiAgICBiaXRzID0gMCxcblxuICAgIE5BTUVNQVggPSAyNTYsXG5cbiAgICBuYW1lQnVmID0gW10sXG5cbiAgICBmaWxlb3V0O1xuXG4gIGZ1bmN0aW9uIHJlYWRCeXRlKCkge1xuICAgIGJpdHMgKz0gODtcbiAgICBpZiAoYnl0ZXBvcyA8IGJBLmxlbmd0aCkge1xuICAgICAgLy9pZiAoZGVidWcpXG4gICAgICAvLyAgICBkb2N1bWVudC53cml0ZShieXRlcG9zK1wiOiBcIitiQVtieXRlcG9zXStcIjxicj5cIik7XG4gICAgICByZXR1cm4gYkFbYnl0ZXBvcysrXTtcbiAgICB9IGVsc2VcbiAgICAgIHJldHVybiAtMTtcbiAgfTtcblxuICBmdW5jdGlvbiBieXRlQWxpZ24oKSB7XG4gICAgYmIgPSAxO1xuICB9O1xuXG4gIGZ1bmN0aW9uIHJlYWRCaXQoKSB7XG4gICAgdmFyIGNhcnJ5O1xuICAgIGJpdHMrKztcbiAgICBjYXJyeSA9IChiYiAmIDEpO1xuICAgIGJiID4+PSAxO1xuICAgIGlmIChiYiA9PSAwKSB7XG4gICAgICBiYiA9IHJlYWRCeXRlKCk7XG4gICAgICBjYXJyeSA9IChiYiAmIDEpO1xuICAgICAgYmIgPSAoYmIgPj4gMSkgfCAweDgwO1xuICAgIH1cbiAgICByZXR1cm4gY2Fycnk7XG4gIH07XG5cbiAgZnVuY3Rpb24gcmVhZEJpdHMoYSkge1xuICAgIHZhciByZXMgPSAwLFxuICAgICAgaSA9IGE7XG5cbiAgICB3aGlsZSAoaS0tKSB7XG4gICAgICByZXMgPSAocmVzIDw8IDEpIHwgcmVhZEJpdCgpO1xuICAgIH1cbiAgICBpZiAoYSkge1xuICAgICAgcmVzID0gYml0UmV2ZXJzZVtyZXNdID4+ICg4IC0gYSk7XG4gICAgfVxuICAgIHJldHVybiByZXM7XG4gIH07XG5cbiAgZnVuY3Rpb24gZmx1c2hCdWZmZXIoKSB7XG4gICAgLy9kb2N1bWVudC53cml0ZSgnRkxVU0hCVUZGRVI6JytidWYzMmspO1xuICAgIGJJZHggPSAwO1xuICB9O1xuXG4gIGZ1bmN0aW9uIGFkZEJ1ZmZlcihhKSB7XG4gICAgU0laRSsrO1xuICAgIC8vQ1JDPXVwZGNyYyhhLGNyYyk7XG4gICAgYnVmMzJrW2JJZHgrK10gPSBhO1xuICAgIG91dHB1dEFyci5wdXNoKFN0cmluZy5mcm9tQ2hhckNvZGUoYSkpO1xuICAgIC8vb3V0cHV0Kz1TdHJpbmcuZnJvbUNoYXJDb2RlKGEpO1xuICAgIGlmIChiSWR4ID09IDB4ODAwMCkge1xuICAgICAgLy9kb2N1bWVudC53cml0ZSgnQUREQlVGRkVSOicrYnVmMzJrKTtcbiAgICAgIGJJZHggPSAwO1xuICAgIH1cbiAgfTtcblxuICBmdW5jdGlvbiBIdWZOb2RlKCkge1xuICAgIHRoaXMuYjAgPSAwO1xuICAgIHRoaXMuYjEgPSAwO1xuICAgIHRoaXMuanVtcCA9IG51bGw7XG4gICAgdGhpcy5qdW1wcG9zID0gLTE7XG4gIH07XG5cbiAgdmFyIExJVEVSQUxTID0gMjg4O1xuXG4gIHZhciBsaXRlcmFsVHJlZSA9IG5ldyBBcnJheShMSVRFUkFMUyk7XG4gIHZhciBkaXN0YW5jZVRyZWUgPSBuZXcgQXJyYXkoMzIpO1xuICB2YXIgdHJlZXBvcyA9IDA7XG4gIHZhciBQbGFjZXMgPSBudWxsO1xuICB2YXIgUGxhY2VzMiA9IG51bGw7XG5cbiAgdmFyIGltcERpc3RhbmNlVHJlZSA9IG5ldyBBcnJheSg2NCk7XG4gIHZhciBpbXBMZW5ndGhUcmVlID0gbmV3IEFycmF5KDY0KTtcblxuICB2YXIgbGVuID0gMDtcbiAgdmFyIGZwb3MgPSBuZXcgQXJyYXkoMTcpO1xuICBmcG9zWzBdID0gMDtcbiAgdmFyIGZsZW5zO1xuICB2YXIgZm1heDtcblxuICBmdW5jdGlvbiBJc1BhdCgpIHtcbiAgICB3aGlsZSAoMSkge1xuICAgICAgaWYgKGZwb3NbbGVuXSA+PSBmbWF4KVxuICAgICAgICByZXR1cm4gLTE7XG4gICAgICBpZiAoZmxlbnNbZnBvc1tsZW5dXSA9PSBsZW4pXG4gICAgICAgIHJldHVybiBmcG9zW2xlbl0rKztcbiAgICAgIGZwb3NbbGVuXSsrO1xuICAgIH1cbiAgfTtcblxuICBmdW5jdGlvbiBSZWMoKSB7XG4gICAgdmFyIGN1cnBsYWNlID0gUGxhY2VzW3RyZWVwb3NdO1xuICAgIHZhciB0bXA7XG4gICAgaWYgKGRlYnVnKVxuICAgICAgZG9jdW1lbnQud3JpdGUoXCI8YnI+bGVuOlwiICsgbGVuICsgXCIgdHJlZXBvczpcIiArIHRyZWVwb3MpO1xuICAgIGlmIChsZW4gPT0gMTcpIHsgLy93YXIgMTdcbiAgICAgIHJldHVybiAtMTtcbiAgICB9XG4gICAgdHJlZXBvcysrO1xuICAgIGxlbisrO1xuXG4gICAgdG1wID0gSXNQYXQoKTtcbiAgICBpZiAoZGVidWcpXG4gICAgICBkb2N1bWVudC53cml0ZShcIjxicj5Jc1BhdCBcIiArIHRtcCk7XG4gICAgaWYgKHRtcCA+PSAwKSB7XG4gICAgICBjdXJwbGFjZS5iMCA9IHRtcDsgLyogbGVhZiBjZWxsIGZvciAwLWJpdCAqL1xuICAgICAgaWYgKGRlYnVnKVxuICAgICAgICBkb2N1bWVudC53cml0ZShcIjxicj5iMCBcIiArIGN1cnBsYWNlLmIwKTtcbiAgICB9IGVsc2Uge1xuICAgICAgLyogTm90IGEgTGVhZiBjZWxsICovXG4gICAgICBjdXJwbGFjZS5iMCA9IDB4ODAwMDtcbiAgICAgIGlmIChkZWJ1ZylcbiAgICAgICAgZG9jdW1lbnQud3JpdGUoXCI8YnI+YjAgXCIgKyBjdXJwbGFjZS5iMCk7XG4gICAgICBpZiAoUmVjKCkpXG4gICAgICAgIHJldHVybiAtMTtcbiAgICB9XG4gICAgdG1wID0gSXNQYXQoKTtcbiAgICBpZiAodG1wID49IDApIHtcbiAgICAgIGN1cnBsYWNlLmIxID0gdG1wOyAvKiBsZWFmIGNlbGwgZm9yIDEtYml0ICovXG4gICAgICBpZiAoZGVidWcpXG4gICAgICAgIGRvY3VtZW50LndyaXRlKFwiPGJyPmIxIFwiICsgY3VycGxhY2UuYjEpO1xuICAgICAgY3VycGxhY2UuanVtcCA9IG51bGw7IC8qIEp1c3QgZm9yIHRoZSBkaXNwbGF5IHJvdXRpbmUgKi9cbiAgICB9IGVsc2Uge1xuICAgICAgLyogTm90IGEgTGVhZiBjZWxsICovXG4gICAgICBjdXJwbGFjZS5iMSA9IDB4ODAwMDtcbiAgICAgIGlmIChkZWJ1ZylcbiAgICAgICAgZG9jdW1lbnQud3JpdGUoXCI8YnI+YjEgXCIgKyBjdXJwbGFjZS5iMSk7XG4gICAgICBjdXJwbGFjZS5qdW1wID0gUGxhY2VzW3RyZWVwb3NdO1xuICAgICAgY3VycGxhY2UuanVtcHBvcyA9IHRyZWVwb3M7XG4gICAgICBpZiAoUmVjKCkpXG4gICAgICAgIHJldHVybiAtMTtcbiAgICB9XG4gICAgbGVuLS07XG4gICAgcmV0dXJuIDA7XG4gIH07XG5cbiAgZnVuY3Rpb24gQ3JlYXRlVHJlZShjdXJyZW50VHJlZSwgbnVtdmFsLCBsZW5ndGhzLCBzaG93KSB7XG4gICAgdmFyIGk7XG4gICAgLyogQ3JlYXRlIHRoZSBIdWZmbWFuIGRlY29kZSB0cmVlL3RhYmxlICovXG4gICAgLy9kb2N1bWVudC53cml0ZShcIjxicj5jcmVhdGV0cmVlPGJyPlwiKTtcbiAgICBpZiAoZGVidWcpXG4gICAgICBkb2N1bWVudC53cml0ZShcImN1cnJlbnRUcmVlIFwiICsgY3VycmVudFRyZWUgKyBcIiBudW12YWwgXCIgKyBudW12YWwgKyBcIiBsZW5ndGhzIFwiICsgbGVuZ3RocyArIFwiIHNob3cgXCIgKyBzaG93KTtcbiAgICBQbGFjZXMgPSBjdXJyZW50VHJlZTtcbiAgICB0cmVlcG9zID0gMDtcbiAgICBmbGVucyA9IGxlbmd0aHM7XG4gICAgZm1heCA9IG51bXZhbDtcbiAgICBmb3IgKGkgPSAwOyBpIDwgMTc7IGkrKylcbiAgICAgIGZwb3NbaV0gPSAwO1xuICAgIGxlbiA9IDA7XG4gICAgaWYgKFJlYygpKSB7XG4gICAgICAvL2ZwcmludGYoc3RkZXJyLCBcImludmFsaWQgaHVmZm1hbiB0cmVlXFxuXCIpO1xuICAgICAgaWYgKGRlYnVnKVxuICAgICAgICBhbGVydChcImludmFsaWQgaHVmZm1hbiB0cmVlXFxuXCIpO1xuICAgICAgcmV0dXJuIC0xO1xuICAgIH1cbiAgICBpZiAoZGVidWcpIHtcbiAgICAgIGRvY3VtZW50LndyaXRlKCc8YnI+VHJlZTogJyArIFBsYWNlcy5sZW5ndGgpO1xuICAgICAgZm9yICh2YXIgYSA9IDA7IGEgPCAzMjsgYSsrKSB7XG4gICAgICAgIGRvY3VtZW50LndyaXRlKFwiUGxhY2VzW1wiICsgYSArIFwiXS5iMD1cIiArIFBsYWNlc1thXS5iMCArIFwiPGJyPlwiKTtcbiAgICAgICAgZG9jdW1lbnQud3JpdGUoXCJQbGFjZXNbXCIgKyBhICsgXCJdLmIxPVwiICsgUGxhY2VzW2FdLmIxICsgXCI8YnI+XCIpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8qaWYoc2hvdykge1xuICAgICAgICAgICAgdmFyIHRtcDtcbiAgICAgICAgICAgIGZvcih0bXA9Y3VycmVudFRyZWU7dG1wPFBsYWNlczt0bXArKykge1xuICAgICAgICAgICAgICAgIGZwcmludGYoc3Rkb3V0LCBcIjB4JTAzeCAgMHglMDN4ICgweCUwNHgpXCIsdG1wLWN1cnJlbnRUcmVlLCB0bXAtPmp1bXA/dG1wLT5qdW1wLWN1cnJlbnRUcmVlOjAsKHRtcC0+anVtcD90bXAtPmp1bXAtY3VycmVudFRyZWU6MCkqNisweGNmMCk7XG4gICAgICAgICAgICAgICAgaWYoISh0bXAuYjAgJiAweDgwMDApKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vZnByaW50ZihzdGRvdXQsIFwiICAweCUwM3ggKCVjKVwiLCB0bXAtPmIwLCh0bXAtPmIwPDI1NiAmJiBpc3ByaW50KHRtcC0+YjApKT90bXAtPmIwOifvv70nKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYoISh0bXAuYjEgJiAweDgwMDApKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmKCh0bXAuYjAgJiAweDgwMDApKVxuICAgICAgICAgICAgICAgICAgICAgICAgZnByaW50ZihzdGRvdXQsIFwiICAgICAgICAgICBcIik7XG4gICAgICAgICAgICAgICAgICAgIGZwcmludGYoc3Rkb3V0LCBcIiAgMHglMDN4ICglYylcIiwgdG1wLT5iMSwodG1wLT5iMTwyNTYgJiYgaXNwcmludCh0bXAtPmIxKSk/dG1wLT5iMTon77+9Jyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGZwcmludGYoc3Rkb3V0LCBcIlxcblwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSovXG4gICAgcmV0dXJuIDA7XG4gIH07XG5cbiAgZnVuY3Rpb24gRGVjb2RlVmFsdWUoY3VycmVudFRyZWUpIHtcbiAgICB2YXIgbGVuLCBpLFxuICAgICAgeHRyZWVwb3MgPSAwLFxuICAgICAgWCA9IGN1cnJlbnRUcmVlW3h0cmVlcG9zXSxcbiAgICAgIGI7XG5cbiAgICAvKiBkZWNvZGUgb25lIHN5bWJvbCBvZiB0aGUgZGF0YSAqL1xuICAgIHdoaWxlICgxKSB7XG4gICAgICBiID0gcmVhZEJpdCgpO1xuICAgICAgaWYgKGRlYnVnKVxuICAgICAgICBkb2N1bWVudC53cml0ZShcImI9XCIgKyBiKTtcbiAgICAgIGlmIChiKSB7XG4gICAgICAgIGlmICghKFguYjEgJiAweDgwMDApKSB7XG4gICAgICAgICAgaWYgKGRlYnVnKVxuICAgICAgICAgICAgZG9jdW1lbnQud3JpdGUoXCJyZXQxXCIpO1xuICAgICAgICAgIHJldHVybiBYLmIxOyAvKiBJZiBsZWFmIG5vZGUsIHJldHVybiBkYXRhICovXG4gICAgICAgIH1cbiAgICAgICAgWCA9IFguanVtcDtcbiAgICAgICAgbGVuID0gY3VycmVudFRyZWUubGVuZ3RoO1xuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgbGVuOyBpKyspIHtcbiAgICAgICAgICBpZiAoY3VycmVudFRyZWVbaV0gPT09IFgpIHtcbiAgICAgICAgICAgIHh0cmVlcG9zID0gaTtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICAvL3h0cmVlcG9zKys7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBpZiAoIShYLmIwICYgMHg4MDAwKSkge1xuICAgICAgICAgIGlmIChkZWJ1ZylcbiAgICAgICAgICAgIGRvY3VtZW50LndyaXRlKFwicmV0MlwiKTtcbiAgICAgICAgICByZXR1cm4gWC5iMDsgLyogSWYgbGVhZiBub2RlLCByZXR1cm4gZGF0YSAqL1xuICAgICAgICB9XG4gICAgICAgIC8vWCsrOyAvLz8/Pz8/Pz8/Pz8/Pz8/Pz8/P1xuICAgICAgICB4dHJlZXBvcysrO1xuICAgICAgICBYID0gY3VycmVudFRyZWVbeHRyZWVwb3NdO1xuICAgICAgfVxuICAgIH1cbiAgfTtcblxuICBmdW5jdGlvbiBEZWZsYXRlTG9vcCgpIHtcbiAgICB2YXIgbGFzdCwgYywgdHlwZSwgaSwgbGVuO1xuXG4gICAgZG8ge1xuICAgICAgLyppZigobGFzdCA9IHJlYWRCaXQoKSkpe1xuICAgICAgICAgICAgZnByaW50ZihlcnJmcCwgXCJMYXN0IEJsb2NrOiBcIik7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBmcHJpbnRmKGVycmZwLCBcIk5vdCBMYXN0IEJsb2NrOiBcIik7XG4gICAgICAgIH0qL1xuICAgICAgbGFzdCA9IHJlYWRCaXQoKTtcbiAgICAgIHR5cGUgPSByZWFkQml0cygyKTtcbiAgICAgIHN3aXRjaCAodHlwZSkge1xuICAgICAgICBjYXNlIDA6XG4gICAgICAgICAgaWYgKGRlYnVnKVxuICAgICAgICAgICAgYWxlcnQoXCJTdG9yZWRcXG5cIik7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgMTpcbiAgICAgICAgICBpZiAoZGVidWcpXG4gICAgICAgICAgICBhbGVydChcIkZpeGVkIEh1ZmZtYW4gY29kZXNcXG5cIik7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgMjpcbiAgICAgICAgICBpZiAoZGVidWcpXG4gICAgICAgICAgICBhbGVydChcIkR5bmFtaWMgSHVmZm1hbiBjb2Rlc1xcblwiKTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSAzOlxuICAgICAgICAgIGlmIChkZWJ1ZylcbiAgICAgICAgICAgIGFsZXJ0KFwiUmVzZXJ2ZWQgYmxvY2sgdHlwZSEhXFxuXCIpO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgIGlmIChkZWJ1ZylcbiAgICAgICAgICAgIGFsZXJ0KFwiVW5leHBlY3RlZCB2YWx1ZSAlZCFcXG5cIiwgdHlwZSk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICB9XG5cbiAgICAgIGlmICh0eXBlID09IDApIHtcbiAgICAgICAgdmFyIGJsb2NrTGVuLCBjU3VtO1xuXG4gICAgICAgIC8vIFN0b3JlZCBcbiAgICAgICAgYnl0ZUFsaWduKCk7XG4gICAgICAgIGJsb2NrTGVuID0gcmVhZEJ5dGUoKTtcbiAgICAgICAgYmxvY2tMZW4gfD0gKHJlYWRCeXRlKCkgPDwgOCk7XG5cbiAgICAgICAgY1N1bSA9IHJlYWRCeXRlKCk7XG4gICAgICAgIGNTdW0gfD0gKHJlYWRCeXRlKCkgPDwgOCk7XG5cbiAgICAgICAgaWYgKCgoYmxvY2tMZW4gXiB+Y1N1bSkgJiAweGZmZmYpKSB7XG4gICAgICAgICAgZG9jdW1lbnQud3JpdGUoXCJCbG9ja0xlbiBjaGVja3N1bSBtaXNtYXRjaFxcblwiKTtcbiAgICAgICAgfVxuICAgICAgICB3aGlsZSAoYmxvY2tMZW4tLSkge1xuICAgICAgICAgIGMgPSByZWFkQnl0ZSgpO1xuICAgICAgICAgIGFkZEJ1ZmZlcihjKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmICh0eXBlID09IDEpIHtcbiAgICAgICAgdmFyIGo7XG5cbiAgICAgICAgLyogRml4ZWQgSHVmZm1hbiB0YWJsZXMgLS0gZml4ZWQgZGVjb2RlIHJvdXRpbmUgKi9cbiAgICAgICAgd2hpbGUgKDEpIHtcbiAgICAgICAgICAvKlxuICAgICAgICAgICAgICAgIDI1NiAgICAwMDAwMDAwICAgICAgICAwXG4gICAgICAgICAgICAgICAgOiAgIDogICAgIDpcbiAgICAgICAgICAgICAgICAyNzkgICAgMDAxMDExMSAgICAgICAgMjNcbiAgICAgICAgICAgICAgICAwICAgMDAxMTAwMDAgICAgNDhcbiAgICAgICAgICAgICAgICA6ICAgIDogICAgICA6XG4gICAgICAgICAgICAgICAgMTQzICAgIDEwMTExMTExICAgIDE5MVxuICAgICAgICAgICAgICAgIDI4MCAxMTAwMDAwMCAgICAxOTJcbiAgICAgICAgICAgICAgICA6ICAgIDogICAgICA6XG4gICAgICAgICAgICAgICAgMjg3IDExMDAwMTExICAgIDE5OVxuICAgICAgICAgICAgICAgIDE0NCAgICAxMTAwMTAwMDAgICAgNDAwXG4gICAgICAgICAgICAgICAgOiAgICA6ICAgICAgIDpcbiAgICAgICAgICAgICAgICAyNTUgICAgMTExMTExMTExICAgIDUxMVxuICAgIFxuICAgICAgICAgICAgICAgIE5vdGUgdGhlIGJpdCBvcmRlciFcbiAgICAgICAgICAgICAgICAqL1xuXG4gICAgICAgICAgaiA9IChiaXRSZXZlcnNlW3JlYWRCaXRzKDcpXSA+PiAxKTtcbiAgICAgICAgICBpZiAoaiA+IDIzKSB7XG4gICAgICAgICAgICBqID0gKGogPDwgMSkgfCByZWFkQml0KCk7IC8qIDQ4Li4yNTUgKi9cblxuICAgICAgICAgICAgaWYgKGogPiAxOTkpIHsgLyogMjAwLi4yNTUgKi9cbiAgICAgICAgICAgICAgaiAtPSAxMjg7IC8qICA3Mi4uMTI3ICovXG4gICAgICAgICAgICAgIGogPSAoaiA8PCAxKSB8IHJlYWRCaXQoKTsgLyogMTQ0Li4yNTUgPDwgKi9cbiAgICAgICAgICAgIH0gZWxzZSB7IC8qICA0OC4uMTk5ICovXG4gICAgICAgICAgICAgIGogLT0gNDg7IC8qICAgMC4uMTUxICovXG4gICAgICAgICAgICAgIGlmIChqID4gMTQzKSB7XG4gICAgICAgICAgICAgICAgaiA9IGogKyAxMzY7IC8qIDI4MC4uMjg3IDw8ICovXG4gICAgICAgICAgICAgICAgLyogICAwLi4xNDMgPDwgKi9cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gZWxzZSB7IC8qICAgMC4uMjMgKi9cbiAgICAgICAgICAgIGogKz0gMjU2OyAvKiAyNTYuLjI3OSA8PCAqL1xuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAoaiA8IDI1Nikge1xuICAgICAgICAgICAgYWRkQnVmZmVyKGopO1xuICAgICAgICAgICAgLy9kb2N1bWVudC53cml0ZShcIm91dDpcIitTdHJpbmcuZnJvbUNoYXJDb2RlKGopKTtcbiAgICAgICAgICAgIC8qZnByaW50ZihlcnJmcCwgXCJAJWQgJTAyeFxcblwiLCBTSVpFLCBqKTsqL1xuICAgICAgICAgIH0gZWxzZSBpZiAoaiA9PSAyNTYpIHtcbiAgICAgICAgICAgIC8qIEVPRiAqL1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHZhciBsZW4sIGRpc3Q7XG5cbiAgICAgICAgICAgIGogLT0gMjU2ICsgMTsgLyogYnl0ZXMgKyBFT0YgKi9cbiAgICAgICAgICAgIGxlbiA9IHJlYWRCaXRzKGNwbGV4dFtqXSkgKyBjcGxlbnNbal07XG5cbiAgICAgICAgICAgIGogPSBiaXRSZXZlcnNlW3JlYWRCaXRzKDUpXSA+PiAzO1xuICAgICAgICAgICAgaWYgKGNwZGV4dFtqXSA+IDgpIHtcbiAgICAgICAgICAgICAgZGlzdCA9IHJlYWRCaXRzKDgpO1xuICAgICAgICAgICAgICBkaXN0IHw9IChyZWFkQml0cyhjcGRleHRbal0gLSA4KSA8PCA4KTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIGRpc3QgPSByZWFkQml0cyhjcGRleHRbal0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZGlzdCArPSBjcGRpc3Rbal07XG5cbiAgICAgICAgICAgIC8qZnByaW50ZihlcnJmcCwgXCJAJWQgKGwlMDJ4LGQlMDR4KVxcblwiLCBTSVpFLCBsZW4sIGRpc3QpOyovXG4gICAgICAgICAgICBmb3IgKGogPSAwOyBqIDwgbGVuOyBqKyspIHtcbiAgICAgICAgICAgICAgdmFyIGMgPSBidWYzMmtbKGJJZHggLSBkaXN0KSAmIDB4N2ZmZl07XG4gICAgICAgICAgICAgIGFkZEJ1ZmZlcihjKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0gLy8gd2hpbGVcbiAgICAgIH0gZWxzZSBpZiAodHlwZSA9PSAyKSB7XG4gICAgICAgIHZhciBqLCBuLCBsaXRlcmFsQ29kZXMsIGRpc3RDb2RlcywgbGVuQ29kZXM7XG4gICAgICAgIHZhciBsbCA9IG5ldyBBcnJheSgyODggKyAzMik7IC8vIFwic3RhdGljXCIganVzdCB0byBwcmVzZXJ2ZSBzdGFja1xuXG4gICAgICAgIC8vIER5bmFtaWMgSHVmZm1hbiB0YWJsZXMgXG5cbiAgICAgICAgbGl0ZXJhbENvZGVzID0gMjU3ICsgcmVhZEJpdHMoNSk7XG4gICAgICAgIGRpc3RDb2RlcyA9IDEgKyByZWFkQml0cyg1KTtcbiAgICAgICAgbGVuQ29kZXMgPSA0ICsgcmVhZEJpdHMoNCk7XG4gICAgICAgIC8vZG9jdW1lbnQud3JpdGUoXCI8YnI+cGFyYW06IFwiK2xpdGVyYWxDb2RlcytcIiBcIitkaXN0Q29kZXMrXCIgXCIrbGVuQ29kZXMrXCI8YnI+XCIpO1xuICAgICAgICBmb3IgKGogPSAwOyBqIDwgMTk7IGorKykge1xuICAgICAgICAgIGxsW2pdID0gMDtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEdldCB0aGUgZGVjb2RlIHRyZWUgY29kZSBsZW5ndGhzXG5cbiAgICAgICAgLy9kb2N1bWVudC53cml0ZShcIjxicj5cIik7XG4gICAgICAgIGZvciAoaiA9IDA7IGogPCBsZW5Db2RlczsgaisrKSB7XG4gICAgICAgICAgbGxbYm9yZGVyW2pdXSA9IHJlYWRCaXRzKDMpO1xuICAgICAgICAgIC8vZG9jdW1lbnQud3JpdGUobGxbYm9yZGVyW2pdXStcIiBcIik7XG4gICAgICAgIH1cbiAgICAgICAgLy9mcHJpbnRmKGVycmZwLCBcIlxcblwiKTtcbiAgICAgICAgLy9kb2N1bWVudC53cml0ZSgnPGJyPmxsOicrbGwpO1xuICAgICAgICBsZW4gPSBkaXN0YW5jZVRyZWUubGVuZ3RoO1xuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgbGVuOyBpKyspXG4gICAgICAgICAgZGlzdGFuY2VUcmVlW2ldID0gbmV3IEh1Zk5vZGUoKTtcbiAgICAgICAgaWYgKENyZWF0ZVRyZWUoZGlzdGFuY2VUcmVlLCAxOSwgbGwsIDApKSB7XG4gICAgICAgICAgZmx1c2hCdWZmZXIoKTtcbiAgICAgICAgICByZXR1cm4gMTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoZGVidWcpIHtcbiAgICAgICAgICBkb2N1bWVudC53cml0ZShcIjxicj5kaXN0YW5jZVRyZWVcIik7XG4gICAgICAgICAgZm9yICh2YXIgYSA9IDA7IGEgPCBkaXN0YW5jZVRyZWUubGVuZ3RoOyBhKyspIHtcbiAgICAgICAgICAgIGRvY3VtZW50LndyaXRlKFwiPGJyPlwiICsgZGlzdGFuY2VUcmVlW2FdLmIwICsgXCIgXCIgKyBkaXN0YW5jZVRyZWVbYV0uYjEgKyBcIiBcIiArIGRpc3RhbmNlVHJlZVthXS5qdW1wICsgXCIgXCIgK1xuICAgICAgICAgICAgICBkaXN0YW5jZVRyZWVbYV0uanVtcHBvcyk7XG4gICAgICAgICAgICAvKmlmIChkaXN0YW5jZVRyZWVbYV0uanVtcHBvcyE9LTEpXG4gICAgICAgICAgICAgICAgICAgIFx0ZG9jdW1lbnQud3JpdGUoXCIgXCIrZGlzdGFuY2VUcmVlW2FdLmp1bXAuYjArXCIgXCIrZGlzdGFuY2VUcmVlW2FdLmp1bXAuYjEpO1xuICAgICAgICAgICAgICAgIFx0Ki9cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgLy9kb2N1bWVudC53cml0ZSgnPEJSPnRyZWUgY3JlYXRlZCcpO1xuXG4gICAgICAgIC8vcmVhZCBpbiBsaXRlcmFsIGFuZCBkaXN0YW5jZSBjb2RlIGxlbmd0aHNcbiAgICAgICAgbiA9IGxpdGVyYWxDb2RlcyArIGRpc3RDb2RlcztcbiAgICAgICAgaSA9IDA7XG4gICAgICAgIHZhciB6ID0gLTE7XG4gICAgICAgIGlmIChkZWJ1ZylcbiAgICAgICAgICBkb2N1bWVudC53cml0ZShcIjxicj5uPVwiICsgbiArIFwiIGJpdHM6IFwiICsgYml0cyArIFwiPGJyPlwiKTtcbiAgICAgICAgd2hpbGUgKGkgPCBuKSB7XG4gICAgICAgICAgeisrO1xuICAgICAgICAgIGogPSBEZWNvZGVWYWx1ZShkaXN0YW5jZVRyZWUpO1xuICAgICAgICAgIGlmIChkZWJ1ZylcbiAgICAgICAgICAgIGRvY3VtZW50LndyaXRlKFwiPGJyPlwiICsgeiArIFwiIGk6XCIgKyBpICsgXCIgZGVjb2RlOiBcIiArIGogKyBcIiAgICBiaXRzIFwiICsgYml0cyArIFwiPGJyPlwiKTtcbiAgICAgICAgICBpZiAoaiA8IDE2KSB7IC8vIGxlbmd0aCBvZiBjb2RlIGluIGJpdHMgKDAuLjE1KVxuICAgICAgICAgICAgbGxbaSsrXSA9IGo7XG4gICAgICAgICAgfSBlbHNlIGlmIChqID09IDE2KSB7IC8vIHJlcGVhdCBsYXN0IGxlbmd0aCAzIHRvIDYgdGltZXMgXG4gICAgICAgICAgICB2YXIgbDtcbiAgICAgICAgICAgIGogPSAzICsgcmVhZEJpdHMoMik7XG4gICAgICAgICAgICBpZiAoaSArIGogPiBuKSB7XG4gICAgICAgICAgICAgIGZsdXNoQnVmZmVyKCk7XG4gICAgICAgICAgICAgIHJldHVybiAxO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgbCA9IGkgPyBsbFtpIC0gMV0gOiAwO1xuICAgICAgICAgICAgd2hpbGUgKGotLSkge1xuICAgICAgICAgICAgICBsbFtpKytdID0gbDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgaWYgKGogPT0gMTcpIHsgLy8gMyB0byAxMCB6ZXJvIGxlbmd0aCBjb2Rlc1xuICAgICAgICAgICAgICBqID0gMyArIHJlYWRCaXRzKDMpO1xuICAgICAgICAgICAgfSBlbHNlIHsgLy8gaiA9PSAxODogMTEgdG8gMTM4IHplcm8gbGVuZ3RoIGNvZGVzIFxuICAgICAgICAgICAgICBqID0gMTEgKyByZWFkQml0cyg3KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChpICsgaiA+IG4pIHtcbiAgICAgICAgICAgICAgZmx1c2hCdWZmZXIoKTtcbiAgICAgICAgICAgICAgcmV0dXJuIDE7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB3aGlsZSAoai0tKSB7XG4gICAgICAgICAgICAgIGxsW2krK10gPSAwO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICAvKmZvcihqPTA7IGo8bGl0ZXJhbENvZGVzK2Rpc3RDb2RlczsgaisrKSB7XG4gICAgICAgICAgICAgICAgLy9mcHJpbnRmKGVycmZwLCBcIiVkIFwiLCBsbFtqXSk7XG4gICAgICAgICAgICAgICAgaWYgKChqJjcpPT03KVxuICAgICAgICAgICAgICAgICAgICBmcHJpbnRmKGVycmZwLCBcIlxcblwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGZwcmludGYoZXJyZnAsIFwiXFxuXCIpOyovXG4gICAgICAgIC8vIENhbiBvdmVyd3JpdGUgdHJlZSBkZWNvZGUgdHJlZSBhcyBpdCBpcyBub3QgdXNlZCBhbnltb3JlXG4gICAgICAgIGxlbiA9IGxpdGVyYWxUcmVlLmxlbmd0aDtcbiAgICAgICAgZm9yIChpID0gMDsgaSA8IGxlbjsgaSsrKVxuICAgICAgICAgIGxpdGVyYWxUcmVlW2ldID0gbmV3IEh1Zk5vZGUoKTtcbiAgICAgICAgaWYgKENyZWF0ZVRyZWUobGl0ZXJhbFRyZWUsIGxpdGVyYWxDb2RlcywgbGwsIDApKSB7XG4gICAgICAgICAgZmx1c2hCdWZmZXIoKTtcbiAgICAgICAgICByZXR1cm4gMTtcbiAgICAgICAgfVxuICAgICAgICBsZW4gPSBsaXRlcmFsVHJlZS5sZW5ndGg7XG4gICAgICAgIGZvciAoaSA9IDA7IGkgPCBsZW47IGkrKylcbiAgICAgICAgICBkaXN0YW5jZVRyZWVbaV0gPSBuZXcgSHVmTm9kZSgpO1xuICAgICAgICB2YXIgbGwyID0gbmV3IEFycmF5KCk7XG4gICAgICAgIGZvciAoaSA9IGxpdGVyYWxDb2RlczsgaSA8IGxsLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgbGwyW2kgLSBsaXRlcmFsQ29kZXNdID0gbGxbaV07XG4gICAgICAgIH1cbiAgICAgICAgaWYgKENyZWF0ZVRyZWUoZGlzdGFuY2VUcmVlLCBkaXN0Q29kZXMsIGxsMiwgMCkpIHtcbiAgICAgICAgICBmbHVzaEJ1ZmZlcigpO1xuICAgICAgICAgIHJldHVybiAxO1xuICAgICAgICB9XG4gICAgICAgIGlmIChkZWJ1ZylcbiAgICAgICAgICBkb2N1bWVudC53cml0ZShcIjxicj5saXRlcmFsVHJlZVwiKTtcbiAgICAgICAgb3V0ZXI6IHdoaWxlICgxKSB7XG4gICAgICAgICAgaiA9IERlY29kZVZhbHVlKGxpdGVyYWxUcmVlKTtcbiAgICAgICAgICBpZiAoaiA+PSAyNTYpIHsgLy8gSW4gQzY0OiBpZiBjYXJyeSBzZXRcbiAgICAgICAgICAgIHZhciBsZW4sIGRpc3Q7XG4gICAgICAgICAgICBqIC09IDI1NjtcbiAgICAgICAgICAgIGlmIChqID09IDApIHtcbiAgICAgICAgICAgICAgLy8gRU9GXG4gICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgai0tO1xuICAgICAgICAgICAgbGVuID0gcmVhZEJpdHMoY3BsZXh0W2pdKSArIGNwbGVuc1tqXTtcblxuICAgICAgICAgICAgaiA9IERlY29kZVZhbHVlKGRpc3RhbmNlVHJlZSk7XG4gICAgICAgICAgICBpZiAoY3BkZXh0W2pdID4gOCkge1xuICAgICAgICAgICAgICBkaXN0ID0gcmVhZEJpdHMoOCk7XG4gICAgICAgICAgICAgIGRpc3QgfD0gKHJlYWRCaXRzKGNwZGV4dFtqXSAtIDgpIDw8IDgpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgZGlzdCA9IHJlYWRCaXRzKGNwZGV4dFtqXSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBkaXN0ICs9IGNwZGlzdFtqXTtcbiAgICAgICAgICAgIHdoaWxlIChsZW4tLSkge1xuICAgICAgICAgICAgICBpZiAoYklkeCAtIGRpc3QgPCAwKSB7XG4gICAgICAgICAgICAgICAgYnJlYWsgb3V0ZXI7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgdmFyIGMgPSBidWYzMmtbKGJJZHggLSBkaXN0KSAmIDB4N2ZmZl07XG4gICAgICAgICAgICAgIGFkZEJ1ZmZlcihjKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgYWRkQnVmZmVyKGopO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gd2hpbGUgKCFsYXN0KTtcbiAgICBmbHVzaEJ1ZmZlcigpO1xuXG4gICAgYnl0ZUFsaWduKCk7XG4gICAgcmV0dXJuIDA7XG4gIH07XG5cbiAgSlhHLlV0aWwuVW56aXAucHJvdG90eXBlLnVuemlwRmlsZSA9IGZ1bmN0aW9uKG5hbWUpIHtcbiAgICB2YXIgaTtcbiAgICB0aGlzLnVuemlwKCk7XG4gICAgLy9hbGVydCh1bnppcHBlZFswXVsxXSk7XG4gICAgZm9yIChpID0gMDsgaSA8IHVuemlwcGVkLmxlbmd0aDsgaSsrKSB7XG4gICAgICBpZiAodW56aXBwZWRbaV1bMV0gPT0gbmFtZSkge1xuICAgICAgICByZXR1cm4gdW56aXBwZWRbaV1bMF07XG4gICAgICB9XG4gICAgfVxuXG4gIH07XG5cbiAgSlhHLlV0aWwuVW56aXAucHJvdG90eXBlLmRlZmxhdGUgPSBmdW5jdGlvbigpIHtcbiAgICBvdXRwdXRBcnIgPSBbXTtcbiAgICB2YXIgdG1wID0gW107XG4gICAgbW9kZVpJUCA9IGZhbHNlO1xuICAgIERlZmxhdGVMb29wKCk7XG4gICAgaWYgKGRlYnVnKVxuICAgICAgYWxlcnQob3V0cHV0QXJyLmpvaW4oJycpKTtcbiAgICB1bnppcHBlZFtmaWxlc10gPSBuZXcgQXJyYXkoMik7XG4gICAgdW56aXBwZWRbZmlsZXNdWzBdID0gb3V0cHV0QXJyLmpvaW4oJycpO1xuICAgIHVuemlwcGVkW2ZpbGVzXVsxXSA9IFwiREVGTEFURVwiO1xuICAgIGZpbGVzKys7XG4gICAgcmV0dXJuIHVuemlwcGVkO1xuICB9XG5cbiAgSlhHLlV0aWwuVW56aXAucHJvdG90eXBlLnVuemlwID0gZnVuY3Rpb24oKSB7XG4gICAgLy9jb252ZXJ0VG9CeXRlQXJyYXkoaW5wdXQpO1xuICAgIGlmIChkZWJ1ZylcbiAgICAgIGFsZXJ0KGJBKTtcbiAgICAvKmZvciAoaT0wO2k8YkEubGVuZ3RoKjg7aSsrKXtcblx0XHRkb2N1bWVudC53cml0ZShyZWFkQml0KCkpO1xuXHRcdGlmICgoaSsxKSU4PT0wKVxuXHRcdFx0ZG9jdW1lbnQud3JpdGUoXCIgXCIpO1xuXHR9Ki9cbiAgICAvKmZvciAoaT0wO2k8YkEubGVuZ3RoO2krKyl7XG5cdFx0ZG9jdW1lbnQud3JpdGUocmVhZEJ5dGUoKStcIiBcIik7XG5cdFx0aWYgKChpKzEpJTg9PTApXG5cdFx0XHRkb2N1bWVudC53cml0ZShcIiBcIik7XG5cdH1cblx0Zm9yIChpPTA7aTxiQS5sZW5ndGg7aSsrKXtcblx0XHRkb2N1bWVudC53cml0ZShiQVtpXStcIiBcIik7XG5cdFx0aWYgKChpKzEpJTE2PT0wKVxuXHRcdFx0ZG9jdW1lbnQud3JpdGUoXCI8YnI+XCIpO1xuXHR9XHRcblx0Ki9cbiAgICAvL2FsZXJ0KGJBKTtcbiAgICBuZXh0RmlsZSgpO1xuICAgIHJldHVybiB1bnppcHBlZDtcbiAgfTtcblxuICBmdW5jdGlvbiBuZXh0RmlsZSgpIHtcbiAgICBpZiAoZGVidWcpXG4gICAgICBhbGVydChcIk5FWFRGSUxFXCIpO1xuICAgIG91dHB1dEFyciA9IFtdO1xuICAgIHZhciB0bXAgPSBbXTtcbiAgICBtb2RlWklQID0gZmFsc2U7XG4gICAgdG1wWzBdID0gcmVhZEJ5dGUoKTtcbiAgICB0bXBbMV0gPSByZWFkQnl0ZSgpO1xuICAgIGlmIChkZWJ1ZylcbiAgICAgIGFsZXJ0KFwidHlwZTogXCIgKyB0bXBbMF0gKyBcIiBcIiArIHRtcFsxXSk7XG4gICAgaWYgKHRtcFswXSA9PSBwYXJzZUludChcIjc4XCIsIDE2KSAmJiB0bXBbMV0gPT0gcGFyc2VJbnQoXCJkYVwiLCAxNikpIHsgLy9HWklQXG4gICAgICBpZiAoZGVidWcpXG4gICAgICAgIGFsZXJ0KFwiR0VPTkV4VC1HWklQXCIpO1xuICAgICAgRGVmbGF0ZUxvb3AoKTtcbiAgICAgIGlmIChkZWJ1ZylcbiAgICAgICAgYWxlcnQob3V0cHV0QXJyLmpvaW4oJycpKTtcbiAgICAgIHVuemlwcGVkW2ZpbGVzXSA9IG5ldyBBcnJheSgyKTtcbiAgICAgIHVuemlwcGVkW2ZpbGVzXVswXSA9IG91dHB1dEFyci5qb2luKCcnKTtcbiAgICAgIHVuemlwcGVkW2ZpbGVzXVsxXSA9IFwiZ2VvbmV4dC5neHRcIjtcbiAgICAgIGZpbGVzKys7XG4gICAgfVxuICAgIGlmICh0bXBbMF0gPT0gcGFyc2VJbnQoXCI3OFwiLCAxNikgJiYgdG1wWzFdID09IHBhcnNlSW50KFwiOWNcIiwgMTYpKSB7IC8vWkxJQlxuICAgICAgaWYgKGRlYnVnKVxuICAgICAgICBhbGVydChcIlpMSUJcIik7XG4gICAgICBEZWZsYXRlTG9vcCgpO1xuICAgICAgaWYgKGRlYnVnKVxuICAgICAgICBhbGVydChvdXRwdXRBcnIuam9pbignJykpO1xuICAgICAgdW56aXBwZWRbZmlsZXNdID0gbmV3IEFycmF5KDIpO1xuICAgICAgdW56aXBwZWRbZmlsZXNdWzBdID0gb3V0cHV0QXJyLmpvaW4oJycpO1xuICAgICAgdW56aXBwZWRbZmlsZXNdWzFdID0gXCJaTElCXCI7XG4gICAgICBmaWxlcysrO1xuICAgIH1cbiAgICBpZiAodG1wWzBdID09IHBhcnNlSW50KFwiMWZcIiwgMTYpICYmIHRtcFsxXSA9PSBwYXJzZUludChcIjhiXCIsIDE2KSkgeyAvL0daSVBcbiAgICAgIGlmIChkZWJ1ZylcbiAgICAgICAgYWxlcnQoXCJHWklQXCIpO1xuICAgICAgLy9EZWZsYXRlTG9vcCgpO1xuICAgICAgc2tpcGRpcigpO1xuICAgICAgaWYgKGRlYnVnKVxuICAgICAgICBhbGVydChvdXRwdXRBcnIuam9pbignJykpO1xuICAgICAgdW56aXBwZWRbZmlsZXNdID0gbmV3IEFycmF5KDIpO1xuICAgICAgdW56aXBwZWRbZmlsZXNdWzBdID0gb3V0cHV0QXJyLmpvaW4oJycpO1xuICAgICAgdW56aXBwZWRbZmlsZXNdWzFdID0gXCJmaWxlXCI7XG4gICAgICBmaWxlcysrO1xuICAgIH1cbiAgICBpZiAodG1wWzBdID09IHBhcnNlSW50KFwiNTBcIiwgMTYpICYmIHRtcFsxXSA9PSBwYXJzZUludChcIjRiXCIsIDE2KSkgeyAvL1pJUFxuICAgICAgbW9kZVpJUCA9IHRydWU7XG4gICAgICB0bXBbMl0gPSByZWFkQnl0ZSgpO1xuICAgICAgdG1wWzNdID0gcmVhZEJ5dGUoKTtcbiAgICAgIGlmICh0bXBbMl0gPT0gcGFyc2VJbnQoXCIzXCIsIDE2KSAmJiB0bXBbM10gPT0gcGFyc2VJbnQoXCI0XCIsIDE2KSkge1xuICAgICAgICAvL01PREVfWklQXG4gICAgICAgIHRtcFswXSA9IHJlYWRCeXRlKCk7XG4gICAgICAgIHRtcFsxXSA9IHJlYWRCeXRlKCk7XG4gICAgICAgIGlmIChkZWJ1ZylcbiAgICAgICAgICBhbGVydChcIlpJUC1WZXJzaW9uOiBcIiArIHRtcFsxXSArIFwiIFwiICsgdG1wWzBdIC8gMTAgKyBcIi5cIiArIHRtcFswXSAlIDEwKTtcblxuICAgICAgICBncGZsYWdzID0gcmVhZEJ5dGUoKTtcbiAgICAgICAgZ3BmbGFncyB8PSAocmVhZEJ5dGUoKSA8PCA4KTtcbiAgICAgICAgaWYgKGRlYnVnKVxuICAgICAgICAgIGFsZXJ0KFwiZ3BmbGFnczogXCIgKyBncGZsYWdzKTtcblxuICAgICAgICB2YXIgbWV0aG9kID0gcmVhZEJ5dGUoKTtcbiAgICAgICAgbWV0aG9kIHw9IChyZWFkQnl0ZSgpIDw8IDgpO1xuICAgICAgICBpZiAoZGVidWcpXG4gICAgICAgICAgYWxlcnQoXCJtZXRob2Q6IFwiICsgbWV0aG9kKTtcblxuICAgICAgICByZWFkQnl0ZSgpO1xuICAgICAgICByZWFkQnl0ZSgpO1xuICAgICAgICByZWFkQnl0ZSgpO1xuICAgICAgICByZWFkQnl0ZSgpO1xuXG4gICAgICAgIHZhciBjcmMgPSByZWFkQnl0ZSgpO1xuICAgICAgICBjcmMgfD0gKHJlYWRCeXRlKCkgPDwgOCk7XG4gICAgICAgIGNyYyB8PSAocmVhZEJ5dGUoKSA8PCAxNik7XG4gICAgICAgIGNyYyB8PSAocmVhZEJ5dGUoKSA8PCAyNCk7XG5cbiAgICAgICAgdmFyIGNvbXBTaXplID0gcmVhZEJ5dGUoKTtcbiAgICAgICAgY29tcFNpemUgfD0gKHJlYWRCeXRlKCkgPDwgOCk7XG4gICAgICAgIGNvbXBTaXplIHw9IChyZWFkQnl0ZSgpIDw8IDE2KTtcbiAgICAgICAgY29tcFNpemUgfD0gKHJlYWRCeXRlKCkgPDwgMjQpO1xuXG4gICAgICAgIHZhciBzaXplID0gcmVhZEJ5dGUoKTtcbiAgICAgICAgc2l6ZSB8PSAocmVhZEJ5dGUoKSA8PCA4KTtcbiAgICAgICAgc2l6ZSB8PSAocmVhZEJ5dGUoKSA8PCAxNik7XG4gICAgICAgIHNpemUgfD0gKHJlYWRCeXRlKCkgPDwgMjQpO1xuXG4gICAgICAgIGlmIChkZWJ1ZylcbiAgICAgICAgICBhbGVydChcImxvY2FsIENSQzogXCIgKyBjcmMgKyBcIlxcbmxvY2FsIFNpemU6IFwiICsgc2l6ZSArIFwiXFxubG9jYWwgQ29tcFNpemU6IFwiICsgY29tcFNpemUpO1xuXG4gICAgICAgIHZhciBmaWxlbGVuID0gcmVhZEJ5dGUoKTtcbiAgICAgICAgZmlsZWxlbiB8PSAocmVhZEJ5dGUoKSA8PCA4KTtcblxuICAgICAgICB2YXIgZXh0cmFsZW4gPSByZWFkQnl0ZSgpO1xuICAgICAgICBleHRyYWxlbiB8PSAocmVhZEJ5dGUoKSA8PCA4KTtcblxuICAgICAgICBpZiAoZGVidWcpXG4gICAgICAgICAgYWxlcnQoXCJmaWxlbGVuIFwiICsgZmlsZWxlbik7XG4gICAgICAgIGkgPSAwO1xuICAgICAgICBuYW1lQnVmID0gW107XG4gICAgICAgIHdoaWxlIChmaWxlbGVuLS0pIHtcbiAgICAgICAgICB2YXIgYyA9IHJlYWRCeXRlKCk7XG4gICAgICAgICAgaWYgKGMgPT0gXCIvXCIgfCBjID09IFwiOlwiKSB7XG4gICAgICAgICAgICBpID0gMDtcbiAgICAgICAgICB9IGVsc2UgaWYgKGkgPCBOQU1FTUFYIC0gMSlcbiAgICAgICAgICAgIG5hbWVCdWZbaSsrXSA9IFN0cmluZy5mcm9tQ2hhckNvZGUoYyk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGRlYnVnKVxuICAgICAgICAgIGFsZXJ0KFwibmFtZUJ1ZjogXCIgKyBuYW1lQnVmKTtcblxuICAgICAgICAvL25hbWVCdWZbaV0gPSBcIlxcMFwiO1xuICAgICAgICBpZiAoIWZpbGVvdXQpXG4gICAgICAgICAgZmlsZW91dCA9IG5hbWVCdWY7XG5cbiAgICAgICAgdmFyIGkgPSAwO1xuICAgICAgICB3aGlsZSAoaSA8IGV4dHJhbGVuKSB7XG4gICAgICAgICAgYyA9IHJlYWRCeXRlKCk7XG4gICAgICAgICAgaSsrO1xuICAgICAgICB9XG5cbiAgICAgICAgQ1JDID0gMHhmZmZmZmZmZjtcbiAgICAgICAgU0laRSA9IDA7XG5cbiAgICAgICAgaWYgKHNpemUgPT0gMCAmJiBmaWxlT3V0LmNoYXJBdChmaWxlb3V0Lmxlbmd0aCAtIDEpID09IFwiL1wiKSB7XG4gICAgICAgICAgLy9za2lwZGlyXG4gICAgICAgICAgaWYgKGRlYnVnKVxuICAgICAgICAgICAgYWxlcnQoXCJza2lwZGlyXCIpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChtZXRob2QgPT0gOCkge1xuICAgICAgICAgIERlZmxhdGVMb29wKCk7XG4gICAgICAgICAgaWYgKGRlYnVnKVxuICAgICAgICAgICAgYWxlcnQob3V0cHV0QXJyLmpvaW4oJycpKTtcbiAgICAgICAgICB1bnppcHBlZFtmaWxlc10gPSBuZXcgQXJyYXkoMik7XG4gICAgICAgICAgdW56aXBwZWRbZmlsZXNdWzBdID0gb3V0cHV0QXJyLmpvaW4oJycpO1xuICAgICAgICAgIHVuemlwcGVkW2ZpbGVzXVsxXSA9IG5hbWVCdWYuam9pbignJyk7XG4gICAgICAgICAgZmlsZXMrKztcbiAgICAgICAgICAvL3JldHVybiBvdXRwdXRBcnIuam9pbignJyk7XG4gICAgICAgIH1cbiAgICAgICAgc2tpcGRpcigpO1xuICAgICAgfVxuICAgIH1cbiAgfTtcblxuICBmdW5jdGlvbiBza2lwZGlyKCkge1xuICAgIHZhciBjcmMsXG4gICAgICB0bXAgPSBbXSxcbiAgICAgIGNvbXBTaXplLCBzaXplLCBvcywgaSwgYztcblxuICAgIGlmICgoZ3BmbGFncyAmIDgpKSB7XG4gICAgICB0bXBbMF0gPSByZWFkQnl0ZSgpO1xuICAgICAgdG1wWzFdID0gcmVhZEJ5dGUoKTtcbiAgICAgIHRtcFsyXSA9IHJlYWRCeXRlKCk7XG4gICAgICB0bXBbM10gPSByZWFkQnl0ZSgpO1xuXG4gICAgICBpZiAodG1wWzBdID09IHBhcnNlSW50KFwiNTBcIiwgMTYpICYmXG4gICAgICAgIHRtcFsxXSA9PSBwYXJzZUludChcIjRiXCIsIDE2KSAmJlxuICAgICAgICB0bXBbMl0gPT0gcGFyc2VJbnQoXCIwN1wiLCAxNikgJiZcbiAgICAgICAgdG1wWzNdID09IHBhcnNlSW50KFwiMDhcIiwgMTYpKSB7XG4gICAgICAgIGNyYyA9IHJlYWRCeXRlKCk7XG4gICAgICAgIGNyYyB8PSAocmVhZEJ5dGUoKSA8PCA4KTtcbiAgICAgICAgY3JjIHw9IChyZWFkQnl0ZSgpIDw8IDE2KTtcbiAgICAgICAgY3JjIHw9IChyZWFkQnl0ZSgpIDw8IDI0KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNyYyA9IHRtcFswXSB8ICh0bXBbMV0gPDwgOCkgfCAodG1wWzJdIDw8IDE2KSB8ICh0bXBbM10gPDwgMjQpO1xuICAgICAgfVxuXG4gICAgICBjb21wU2l6ZSA9IHJlYWRCeXRlKCk7XG4gICAgICBjb21wU2l6ZSB8PSAocmVhZEJ5dGUoKSA8PCA4KTtcbiAgICAgIGNvbXBTaXplIHw9IChyZWFkQnl0ZSgpIDw8IDE2KTtcbiAgICAgIGNvbXBTaXplIHw9IChyZWFkQnl0ZSgpIDw8IDI0KTtcblxuICAgICAgc2l6ZSA9IHJlYWRCeXRlKCk7XG4gICAgICBzaXplIHw9IChyZWFkQnl0ZSgpIDw8IDgpO1xuICAgICAgc2l6ZSB8PSAocmVhZEJ5dGUoKSA8PCAxNik7XG4gICAgICBzaXplIHw9IChyZWFkQnl0ZSgpIDw8IDI0KTtcblxuICAgICAgaWYgKGRlYnVnKVxuICAgICAgICBhbGVydChcIkNSQzpcIik7XG4gICAgfVxuXG4gICAgaWYgKG1vZGVaSVApXG4gICAgICBuZXh0RmlsZSgpO1xuXG4gICAgdG1wWzBdID0gcmVhZEJ5dGUoKTtcbiAgICBpZiAodG1wWzBdICE9IDgpIHtcbiAgICAgIGlmIChkZWJ1ZylcbiAgICAgICAgYWxlcnQoXCJVbmtub3duIGNvbXByZXNzaW9uIG1ldGhvZCFcIik7XG4gICAgICByZXR1cm4gMDtcbiAgICB9XG5cbiAgICBncGZsYWdzID0gcmVhZEJ5dGUoKTtcbiAgICBpZiAoZGVidWcpIHtcbiAgICAgIGlmICgoZ3BmbGFncyAmIH4ocGFyc2VJbnQoXCIxZlwiLCAxNikpKSlcbiAgICAgICAgYWxlcnQoXCJVbmtub3duIGZsYWdzIHNldCFcIik7XG4gICAgfVxuXG4gICAgcmVhZEJ5dGUoKTtcbiAgICByZWFkQnl0ZSgpO1xuICAgIHJlYWRCeXRlKCk7XG4gICAgcmVhZEJ5dGUoKTtcblxuICAgIHJlYWRCeXRlKCk7XG4gICAgb3MgPSByZWFkQnl0ZSgpO1xuXG4gICAgaWYgKChncGZsYWdzICYgNCkpIHtcbiAgICAgIHRtcFswXSA9IHJlYWRCeXRlKCk7XG4gICAgICB0bXBbMl0gPSByZWFkQnl0ZSgpO1xuICAgICAgbGVuID0gdG1wWzBdICsgMjU2ICogdG1wWzFdO1xuICAgICAgaWYgKGRlYnVnKVxuICAgICAgICBhbGVydChcIkV4dHJhIGZpZWxkIHNpemU6IFwiICsgbGVuKTtcbiAgICAgIGZvciAoaSA9IDA7IGkgPCBsZW47IGkrKylcbiAgICAgICAgcmVhZEJ5dGUoKTtcbiAgICB9XG5cbiAgICBpZiAoKGdwZmxhZ3MgJiA4KSkge1xuICAgICAgaSA9IDA7XG4gICAgICBuYW1lQnVmID0gW107XG4gICAgICB3aGlsZSAoYyA9IHJlYWRCeXRlKCkpIHtcbiAgICAgICAgaWYgKGMgPT0gXCI3XCIgfHwgYyA9PSBcIjpcIilcbiAgICAgICAgICBpID0gMDtcbiAgICAgICAgaWYgKGkgPCBOQU1FTUFYIC0gMSlcbiAgICAgICAgICBuYW1lQnVmW2krK10gPSBjO1xuICAgICAgfVxuICAgICAgLy9uYW1lQnVmW2ldID0gXCJcXDBcIjtcbiAgICAgIGlmIChkZWJ1ZylcbiAgICAgICAgYWxlcnQoXCJvcmlnaW5hbCBmaWxlIG5hbWU6IFwiICsgbmFtZUJ1Zik7XG4gICAgfVxuXG4gICAgaWYgKChncGZsYWdzICYgMTYpKSB7XG4gICAgICB3aGlsZSAoYyA9IHJlYWRCeXRlKCkpIHtcbiAgICAgICAgLy9GSUxFIENPTU1FTlRcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoKGdwZmxhZ3MgJiAyKSkge1xuICAgICAgcmVhZEJ5dGUoKTtcbiAgICAgIHJlYWRCeXRlKCk7XG4gICAgfVxuXG4gICAgRGVmbGF0ZUxvb3AoKTtcblxuICAgIGNyYyA9IHJlYWRCeXRlKCk7XG4gICAgY3JjIHw9IChyZWFkQnl0ZSgpIDw8IDgpO1xuICAgIGNyYyB8PSAocmVhZEJ5dGUoKSA8PCAxNik7XG4gICAgY3JjIHw9IChyZWFkQnl0ZSgpIDw8IDI0KTtcblxuICAgIHNpemUgPSByZWFkQnl0ZSgpO1xuICAgIHNpemUgfD0gKHJlYWRCeXRlKCkgPDwgOCk7XG4gICAgc2l6ZSB8PSAocmVhZEJ5dGUoKSA8PCAxNik7XG4gICAgc2l6ZSB8PSAocmVhZEJ5dGUoKSA8PCAyNCk7XG5cbiAgICBpZiAobW9kZVpJUClcbiAgICAgIG5leHRGaWxlKCk7XG5cbiAgfTtcblxufTtcblxuLyoqXG4gKiAgQmFzZTY0IGVuY29kaW5nIC8gZGVjb2RpbmdcbiAqICB7QGxpbmsgaHR0cDovL3d3dy53ZWJ0b29sa2l0LmluZm8vfVxuICovXG5KWEcuVXRpbC5CYXNlNjQgPSB7XG5cbiAgLy8gcHJpdmF0ZSBwcm9wZXJ0eVxuICBfa2V5U3RyOiBcIkFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5Ky89XCIsXG5cbiAgLy8gcHVibGljIG1ldGhvZCBmb3IgZW5jb2RpbmdcbiAgZW5jb2RlOiBmdW5jdGlvbihpbnB1dCkge1xuICAgIHZhciBvdXRwdXQgPSBbXSxcbiAgICAgIGNocjEsIGNocjIsIGNocjMsIGVuYzEsIGVuYzIsIGVuYzMsIGVuYzQsXG4gICAgICBpID0gMDtcblxuICAgIGlucHV0ID0gSlhHLlV0aWwuQmFzZTY0Ll91dGY4X2VuY29kZShpbnB1dCk7XG5cbiAgICB3aGlsZSAoaSA8IGlucHV0Lmxlbmd0aCkge1xuXG4gICAgICBjaHIxID0gaW5wdXQuY2hhckNvZGVBdChpKyspO1xuICAgICAgY2hyMiA9IGlucHV0LmNoYXJDb2RlQXQoaSsrKTtcbiAgICAgIGNocjMgPSBpbnB1dC5jaGFyQ29kZUF0KGkrKyk7XG5cbiAgICAgIGVuYzEgPSBjaHIxID4+IDI7XG4gICAgICBlbmMyID0gKChjaHIxICYgMykgPDwgNCkgfCAoY2hyMiA+PiA0KTtcbiAgICAgIGVuYzMgPSAoKGNocjIgJiAxNSkgPDwgMikgfCAoY2hyMyA+PiA2KTtcbiAgICAgIGVuYzQgPSBjaHIzICYgNjM7XG5cbiAgICAgIGlmIChpc05hTihjaHIyKSkge1xuICAgICAgICBlbmMzID0gZW5jNCA9IDY0O1xuICAgICAgfSBlbHNlIGlmIChpc05hTihjaHIzKSkge1xuICAgICAgICBlbmM0ID0gNjQ7XG4gICAgICB9XG5cbiAgICAgIG91dHB1dC5wdXNoKFt0aGlzLl9rZXlTdHIuY2hhckF0KGVuYzEpLFxuICAgICAgICAgIHRoaXMuX2tleVN0ci5jaGFyQXQoZW5jMiksXG4gICAgICAgICAgdGhpcy5fa2V5U3RyLmNoYXJBdChlbmMzKSxcbiAgICAgICAgICB0aGlzLl9rZXlTdHIuY2hhckF0KGVuYzQpXG4gICAgICBdLmpvaW4oJycpKTtcbiAgICB9XG5cbiAgICByZXR1cm4gb3V0cHV0LmpvaW4oJycpO1xuICB9LFxuXG4gIC8vIHB1YmxpYyBtZXRob2QgZm9yIGRlY29kaW5nXG4gIGRlY29kZTogZnVuY3Rpb24oaW5wdXQsIHV0ZjgpIHtcbiAgICB2YXIgb3V0cHV0ID0gW10sXG4gICAgICBjaHIxLCBjaHIyLCBjaHIzLFxuICAgICAgZW5jMSwgZW5jMiwgZW5jMywgZW5jNCxcbiAgICAgIGkgPSAwO1xuXG4gICAgaW5wdXQgPSBpbnB1dC5yZXBsYWNlKC9bXkEtWmEtejAtOVxcK1xcL1xcPV0vZywgXCJcIik7XG5cbiAgICB3aGlsZSAoaSA8IGlucHV0Lmxlbmd0aCkge1xuXG4gICAgICBlbmMxID0gdGhpcy5fa2V5U3RyLmluZGV4T2YoaW5wdXQuY2hhckF0KGkrKykpO1xuICAgICAgZW5jMiA9IHRoaXMuX2tleVN0ci5pbmRleE9mKGlucHV0LmNoYXJBdChpKyspKTtcbiAgICAgIGVuYzMgPSB0aGlzLl9rZXlTdHIuaW5kZXhPZihpbnB1dC5jaGFyQXQoaSsrKSk7XG4gICAgICBlbmM0ID0gdGhpcy5fa2V5U3RyLmluZGV4T2YoaW5wdXQuY2hhckF0KGkrKykpO1xuXG4gICAgICBjaHIxID0gKGVuYzEgPDwgMikgfCAoZW5jMiA+PiA0KTtcbiAgICAgIGNocjIgPSAoKGVuYzIgJiAxNSkgPDwgNCkgfCAoZW5jMyA+PiAyKTtcbiAgICAgIGNocjMgPSAoKGVuYzMgJiAzKSA8PCA2KSB8IGVuYzQ7XG5cbiAgICAgIG91dHB1dC5wdXNoKFN0cmluZy5mcm9tQ2hhckNvZGUoY2hyMSkpO1xuXG4gICAgICBpZiAoZW5jMyAhPSA2NCkge1xuICAgICAgICBvdXRwdXQucHVzaChTdHJpbmcuZnJvbUNoYXJDb2RlKGNocjIpKTtcbiAgICAgIH1cbiAgICAgIGlmIChlbmM0ICE9IDY0KSB7XG4gICAgICAgIG91dHB1dC5wdXNoKFN0cmluZy5mcm9tQ2hhckNvZGUoY2hyMykpO1xuICAgICAgfVxuICAgIH1cblxuICAgIG91dHB1dCA9IG91dHB1dC5qb2luKCcnKTtcblxuICAgIGlmICh1dGY4KSB7XG4gICAgICBvdXRwdXQgPSBKWEcuVXRpbC5CYXNlNjQuX3V0ZjhfZGVjb2RlKG91dHB1dCk7XG4gICAgfVxuICAgIHJldHVybiBvdXRwdXQ7XG5cbiAgfSxcblxuICAvLyBwcml2YXRlIG1ldGhvZCBmb3IgVVRGLTggZW5jb2RpbmdcbiAgX3V0ZjhfZW5jb2RlOiBmdW5jdGlvbihzdHJpbmcpIHtcbiAgICBzdHJpbmcgPSBzdHJpbmcucmVwbGFjZSgvXFxyXFxuL2csIFwiXFxuXCIpO1xuICAgIHZhciB1dGZ0ZXh0ID0gXCJcIjtcblxuICAgIGZvciAodmFyIG4gPSAwOyBuIDwgc3RyaW5nLmxlbmd0aDsgbisrKSB7XG5cbiAgICAgIHZhciBjID0gc3RyaW5nLmNoYXJDb2RlQXQobik7XG5cbiAgICAgIGlmIChjIDwgMTI4KSB7XG4gICAgICAgIHV0ZnRleHQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShjKTtcbiAgICAgIH0gZWxzZSBpZiAoKGMgPiAxMjcpICYmIChjIDwgMjA0OCkpIHtcbiAgICAgICAgdXRmdGV4dCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKChjID4+IDYpIHwgMTkyKTtcbiAgICAgICAgdXRmdGV4dCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKChjICYgNjMpIHwgMTI4KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHV0ZnRleHQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSgoYyA+PiAxMikgfCAyMjQpO1xuICAgICAgICB1dGZ0ZXh0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoKChjID4+IDYpICYgNjMpIHwgMTI4KTtcbiAgICAgICAgdXRmdGV4dCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKChjICYgNjMpIHwgMTI4KTtcbiAgICAgIH1cblxuICAgIH1cblxuICAgIHJldHVybiB1dGZ0ZXh0O1xuICB9LFxuXG4gIC8vIHByaXZhdGUgbWV0aG9kIGZvciBVVEYtOCBkZWNvZGluZ1xuICBfdXRmOF9kZWNvZGU6IGZ1bmN0aW9uKHV0ZnRleHQpIHtcbiAgICB2YXIgc3RyaW5nID0gW10sXG4gICAgICBpID0gMCxcbiAgICAgIGMgPSAwLFxuICAgICAgYzIgPSAwLFxuICAgICAgYzMgPSAwO1xuXG4gICAgd2hpbGUgKGkgPCB1dGZ0ZXh0Lmxlbmd0aCkge1xuICAgICAgYyA9IHV0ZnRleHQuY2hhckNvZGVBdChpKTtcbiAgICAgIGlmIChjIDwgMTI4KSB7XG4gICAgICAgIHN0cmluZy5wdXNoKFN0cmluZy5mcm9tQ2hhckNvZGUoYykpO1xuICAgICAgICBpKys7XG4gICAgICB9IGVsc2UgaWYgKChjID4gMTkxKSAmJiAoYyA8IDIyNCkpIHtcbiAgICAgICAgYzIgPSB1dGZ0ZXh0LmNoYXJDb2RlQXQoaSArIDEpO1xuICAgICAgICBzdHJpbmcucHVzaChTdHJpbmcuZnJvbUNoYXJDb2RlKCgoYyAmIDMxKSA8PCA2KSB8IChjMiAmIDYzKSkpO1xuICAgICAgICBpICs9IDI7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjMiA9IHV0ZnRleHQuY2hhckNvZGVBdChpICsgMSk7XG4gICAgICAgIGMzID0gdXRmdGV4dC5jaGFyQ29kZUF0KGkgKyAyKTtcbiAgICAgICAgc3RyaW5nLnB1c2goU3RyaW5nLmZyb21DaGFyQ29kZSgoKGMgJiAxNSkgPDwgMTIpIHwgKChjMiAmIDYzKSA8PCA2KSB8IChjMyAmIDYzKSkpO1xuICAgICAgICBpICs9IDM7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBzdHJpbmcuam9pbignJyk7XG4gIH0sXG5cbiAgX2Rlc3RyaXA6IGZ1bmN0aW9uKHN0cmlwcGVkLCB3cmFwKSB7XG4gICAgdmFyIGxpbmVzID0gW10sXG4gICAgICBsaW5lbm8sIGksXG4gICAgICBkZXN0cmlwcGVkID0gW107XG5cbiAgICBpZiAod3JhcCA9PSBudWxsKVxuICAgICAgd3JhcCA9IDc2O1xuXG4gICAgc3RyaXBwZWQucmVwbGFjZSgvIC9nLCBcIlwiKTtcbiAgICBsaW5lbm8gPSBzdHJpcHBlZC5sZW5ndGggLyB3cmFwO1xuICAgIGZvciAoaSA9IDA7IGkgPCBsaW5lbm87IGkrKylcbiAgICAgIGxpbmVzW2ldID0gc3RyaXBwZWQuc3Vic3RyKGkgKiB3cmFwLCB3cmFwKTtcbiAgICBpZiAobGluZW5vICE9IHN0cmlwcGVkLmxlbmd0aCAvIHdyYXApXG4gICAgICBsaW5lc1tsaW5lcy5sZW5ndGhdID0gc3RyaXBwZWQuc3Vic3RyKGxpbmVubyAqIHdyYXAsIHN0cmlwcGVkLmxlbmd0aCAtIChsaW5lbm8gKiB3cmFwKSk7XG5cbiAgICBmb3IgKGkgPSAwOyBpIDwgbGluZXMubGVuZ3RoOyBpKyspXG4gICAgICBkZXN0cmlwcGVkLnB1c2gobGluZXNbaV0pO1xuICAgIHJldHVybiBkZXN0cmlwcGVkLmpvaW4oJ1xcbicpO1xuICB9LFxuXG4gIGRlY29kZUFzQXJyYXk6IGZ1bmN0aW9uKGlucHV0KSB7XG4gICAgdmFyIGRlYyA9IHRoaXMuZGVjb2RlKGlucHV0KSxcbiAgICAgIGFyID0gW10sXG4gICAgICBpO1xuICAgIGZvciAoaSA9IDA7IGkgPCBkZWMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGFyW2ldID0gZGVjLmNoYXJDb2RlQXQoaSk7XG4gICAgfVxuICAgIHJldHVybiBhcjtcbiAgfSxcblxuICBkZWNvZGVHRU9ORXhUOiBmdW5jdGlvbihpbnB1dCkge1xuICAgIHJldHVybiBkZWNvZGVBc0FycmF5KGRlc3RyaXAoaW5wdXQpLCBmYWxzZSk7XG4gIH1cbn07XG5cbi8qKlxuICogQHByaXZhdGVcbiAqL1xuSlhHLlV0aWwuYXNjaWlDaGFyQ29kZUF0ID0gZnVuY3Rpb24oc3RyLCBpKSB7XG4gIHZhciBjID0gc3RyLmNoYXJDb2RlQXQoaSk7XG4gIGlmIChjID4gMjU1KSB7XG4gICAgc3dpdGNoIChjKSB7XG4gICAgICBjYXNlIDgzNjQ6XG4gICAgICAgIGMgPSAxMjg7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSA4MjE4OlxuICAgICAgICBjID0gMTMwO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgNDAyOlxuICAgICAgICBjID0gMTMxO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgODIyMjpcbiAgICAgICAgYyA9IDEzMjtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIDgyMzA6XG4gICAgICAgIGMgPSAxMzM7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSA4MjI0OlxuICAgICAgICBjID0gMTM0O1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgODIyNTpcbiAgICAgICAgYyA9IDEzNTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIDcxMDpcbiAgICAgICAgYyA9IDEzNjtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIDgyNDA6XG4gICAgICAgIGMgPSAxMzc7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAzNTI6XG4gICAgICAgIGMgPSAxMzg7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSA4MjQ5OlxuICAgICAgICBjID0gMTM5O1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgMzM4OlxuICAgICAgICBjID0gMTQwO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgMzgxOlxuICAgICAgICBjID0gMTQyO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgODIxNjpcbiAgICAgICAgYyA9IDE0NTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIDgyMTc6XG4gICAgICAgIGMgPSAxNDY7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSA4MjIwOlxuICAgICAgICBjID0gMTQ3O1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgODIyMTpcbiAgICAgICAgYyA9IDE0ODtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIDgyMjY6XG4gICAgICAgIGMgPSAxNDk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSA4MjExOlxuICAgICAgICBjID0gMTUwO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgODIxMjpcbiAgICAgICAgYyA9IDE1MTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIDczMjpcbiAgICAgICAgYyA9IDE1MjtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIDg0ODI6XG4gICAgICAgIGMgPSAxNTM7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAzNTM6XG4gICAgICAgIGMgPSAxNTQ7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSA4MjUwOlxuICAgICAgICBjID0gMTU1O1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgMzM5OlxuICAgICAgICBjID0gMTU2O1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgMzgyOlxuICAgICAgICBjID0gMTU4O1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgMzc2OlxuICAgICAgICBjID0gMTU5O1xuICAgICAgICBicmVhaztcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIGJyZWFrO1xuICAgIH1cbiAgfVxuICByZXR1cm4gYztcbn07XG5cbi8qKlxuICogRGVjb2Rpbmcgc3RyaW5nIGludG8gdXRmLThcbiAqIEBwYXJhbSB7U3RyaW5nfSBzdHJpbmcgdG8gZGVjb2RlXG4gKiBAcmV0dXJuIHtTdHJpbmd9IHV0ZjggZGVjb2RlZCBzdHJpbmdcbiAqL1xuSlhHLlV0aWwudXRmOERlY29kZSA9IGZ1bmN0aW9uKHV0ZnRleHQpIHtcbiAgdmFyIHN0cmluZyA9IFtdO1xuICB2YXIgaSA9IDA7XG4gIHZhciBjID0gMCxcbiAgICBjMSA9IDAsXG4gICAgYzIgPSAwLFxuICAgIGMzO1xuICBpZiAoIUpYRy5leGlzdHModXRmdGV4dCkpIHJldHVybiAnJztcblxuICB3aGlsZSAoaSA8IHV0ZnRleHQubGVuZ3RoKSB7XG4gICAgYyA9IHV0ZnRleHQuY2hhckNvZGVBdChpKTtcblxuICAgIGlmIChjIDwgMTI4KSB7XG4gICAgICBzdHJpbmcucHVzaChTdHJpbmcuZnJvbUNoYXJDb2RlKGMpKTtcbiAgICAgIGkrKztcbiAgICB9IGVsc2UgaWYgKChjID4gMTkxKSAmJiAoYyA8IDIyNCkpIHtcbiAgICAgIGMyID0gdXRmdGV4dC5jaGFyQ29kZUF0KGkgKyAxKTtcbiAgICAgIHN0cmluZy5wdXNoKFN0cmluZy5mcm9tQ2hhckNvZGUoKChjICYgMzEpIDw8IDYpIHwgKGMyICYgNjMpKSk7XG4gICAgICBpICs9IDI7XG4gICAgfSBlbHNlIHtcbiAgICAgIGMyID0gdXRmdGV4dC5jaGFyQ29kZUF0KGkgKyAxKTtcbiAgICAgIGMzID0gdXRmdGV4dC5jaGFyQ29kZUF0KGkgKyAyKTtcbiAgICAgIHN0cmluZy5wdXNoKFN0cmluZy5mcm9tQ2hhckNvZGUoKChjICYgMTUpIDw8IDEyKSB8ICgoYzIgJiA2MykgPDwgNikgfCAoYzMgJiA2MykpKTtcbiAgICAgIGkgKz0gMztcbiAgICB9XG4gIH07XG4gIHJldHVybiBzdHJpbmcuam9pbignJyk7XG59O1xuXG4vKipcbiAqIEdlbmVyYXRlIGEgcmFuZG9tIHV1aWQuXG4gKiBodHRwOi8vd3d3LmJyb29mYS5jb21cbiAqIG1haWx0bzpyb2JlcnRAYnJvb2ZhLmNvbVxuICpcbiAqIENvcHlyaWdodCAoYykgMjAxMCBSb2JlcnQgS2llZmZlclxuICogRHVhbCBsaWNlbnNlZCB1bmRlciB0aGUgTUlUIGFuZCBHUEwgbGljZW5zZXMuXG4gKlxuICogRVhBTVBMRVM6XG4gKiAgID4+PiBNYXRoLnV1aWQoKVxuICogICBcIjkyMzI5RDM5LTZGNUMtNDUyMC1BQkZDLUFBQjY0NTQ0RTE3MlwiXG4gKi9cbkpYRy5VdGlsLmdlblVVSUQgPSBmdW5jdGlvbigpIHtcbiAgLy8gUHJpdmF0ZSBhcnJheSBvZiBjaGFycyB0byB1c2VcbiAgdmFyIGNoYXJzID0gJzAxMjM0NTY3ODlBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWmFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6Jy5zcGxpdCgnJyksXG4gICAgdXVpZCA9IG5ldyBBcnJheSgzNiksXG4gICAgcm5kID0gMCxcbiAgICByO1xuXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgMzY7IGkrKykge1xuICAgIGlmIChpID09IDggfHwgaSA9PSAxMyB8fCBpID09IDE4IHx8IGkgPT0gMjMpIHtcbiAgICAgIHV1aWRbaV0gPSAnLSc7XG4gICAgfSBlbHNlIGlmIChpID09IDE0KSB7XG4gICAgICB1dWlkW2ldID0gJzQnO1xuICAgIH0gZWxzZSB7XG4gICAgICBpZiAocm5kIDw9IDB4MDIpIHJuZCA9IDB4MjAwMDAwMCArIChNYXRoLnJhbmRvbSgpICogMHgxMDAwMDAwKSB8IDA7XG4gICAgICByID0gcm5kICYgMHhmO1xuICAgICAgcm5kID0gcm5kID4+IDQ7XG4gICAgICB1dWlkW2ldID0gY2hhcnNbKGkgPT0gMTkpID8gKHIgJiAweDMpIHwgMHg4IDogcl07XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHV1aWQuam9pbignJyk7XG59O1xuXG5cbm1vZHVsZS5leHBvcnRzID0gSlhHO1xuIiwiLy8gR1BHNEJyb3dzZXJzIC0gQW4gT3BlblBHUCBpbXBsZW1lbnRhdGlvbiBpbiBqYXZhc2NyaXB0XG4vLyBDb3B5cmlnaHQgKEMpIDIwMTEgUmVjdXJpdHkgTGFicyBHbWJIXG4vL1xuLy8gVGhpcyBsaWJyYXJ5IGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vclxuLy8gbW9kaWZ5IGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyXG4vLyB2ZXJzaW9uIDIuMSBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cbi8vXG4vLyBUaGlzIGxpYnJhcnkgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbi8vIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4vLyBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlIEdOVVxuLy8gTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cbi8vXG4vLyBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFsb25nIHdpdGggdGhpcyBsaWJyYXJ5OyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlXG4vLyBGb3VuZGF0aW9uLCBJbmMuLCA1MSBGcmFua2xpbiBTdHJlZXQsIEZpZnRoIEZsb29yLCBCb3N0b24sIE1BICAwMjExMC0xMzAxICBVU0FcblxudmFyIGVudW1zID0gcmVxdWlyZSgnLi4vZW51bXMuanMnKTtcblxuLyoqXG4gKlxuICogVGhpcyBvYmplY3QgY29udGFpbnMgY29uZmlndXJhdGlvbiB2YWx1ZXMgYW5kIGltcGxlbWVudHNcbiAqIHN0b3JpbmcgYW5kIHJldHJpZXZpbmcgY29uZmlndXJhdGlvbiB0aGVtIGZyb20gSFRNTDUgbG9jYWwgc3RvcmFnZS5cbiAqXG4gKiBUaGlzIG9iamVjdCBjYW4gYmUgYWNjZXNzZWQgYWZ0ZXIgY2FsbGluZyBvcGVucGdwLmluaXQoKVxuICogdXNpbmcgb3BlbnBncC5jb25maWdcbiAqIFN0b3JlZCBjb25maWcgcGFyYW1ldGVycyBjYW4gYmUgYWNjZXNzZWQgdXNpbmdcbiAqIG9wZW5wZ3AuY29uZmlnLmNvbmZpZ1xuICogQGNsYXNzXG4gKiBAY2xhc3NkZXNjIEltcGxlbWVudGF0aW9uIG9mIHRoZSBHUEc0QnJvd3NlcnMgY29uZmlnIG9iamVjdFxuICovXG52YXIgY29uZmlnID0gZnVuY3Rpb24oKSB7XG4gIC8qKlxuICAgKiBAcHJvcGVydHkge0ludGVnZXJ9IHByZWZlcl9oYXNoX2FsZ29yaXRobVxuICAgKiBAcHJvcGVydHkge0ludGVnZXJ9IGVuY3J5cHRpb25fY2lwaGVyXG4gICAqIEBwcm9wZXJ0eSB7SW50ZWdlcn0gY29tcHJlc3Npb25cbiAgICogQHByb3BlcnR5IHtCb29sZWFufSBzaG93X3ZlcnNpb25cbiAgICogQHByb3BlcnR5IHtCb29sZWFufSBzaG93X2NvbW1lbnRcbiAgICogQHByb3BlcnR5IHtCb29sZWFufSBpbnRlZ3JpdHlfcHJvdGVjdFxuICAgKiBAcHJvcGVydHkge1N0cmluZ30ga2V5c2VydmVyXG4gICAqL1xuICB0aGlzLnByZWZlcl9oYXNoX2FsZ29yaXRobSA9IGVudW1zLmhhc2guc2hhMjU2O1xuICB0aGlzLmVuY3J5cHRpb25fY2lwaGVyID0gZW51bXMuc3ltbWV0cmljLmFlczI1NjtcbiAgdGhpcy5jb21wcmVzc2lvbiA9IGVudW1zLmNvbXByZXNzaW9uLnppcDtcbiAgdGhpcy5zaG93X3ZlcnNpb24gPSB0cnVlO1xuICB0aGlzLnNob3dfY29tbWVudCA9IHRydWU7XG4gIHRoaXMuaW50ZWdyaXR5X3Byb3RlY3QgPSB0cnVlO1xuICB0aGlzLmtleXNlcnZlciA9IFwia2V5c2VydmVyLmxpbnV4Lml0XCI7IC8vIFwicGdwLm1pdC5lZHU6MTEzNzFcIlxuXG4gIHRoaXMudmVyc2lvbnN0cmluZyA9IFwiT3BlblBHUC5qcyBWRVJTSU9OXCI7XG4gIHRoaXMuY29tbWVudHN0cmluZyA9IFwiaHR0cDovL29wZW5wZ3Bqcy5vcmdcIjtcblxuICAvKipcbiAgICogSWYgZW5hYmxlZCwgZGVidWcgbWVzc2FnZXMgd2lsbCBiZSBwcmludGVkXG4gICAqL1xuICB0aGlzLmRlYnVnID0gZmFsc2U7XG5cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gbmV3IGNvbmZpZygpO1xuIiwiLy8gTW9kaWZpZWQgYnkgUmVjdXJpdHkgTGFicyBHbWJIIFxuXG4vLyBtb2RpZmllZCB2ZXJzaW9uIG9mIGh0dHA6Ly93d3cuaGFuZXdpbi5uZXQvZW5jcnlwdC9QR2RlY29kZS5qczpcblxuLyogT3BlblBHUCBlbmNyeXB0aW9uIHVzaW5nIFJTQS9BRVNcbiAqIENvcHlyaWdodCAyMDA1LTIwMDYgSGVyYmVydCBIYW5ld2lua2VsLCB3d3cuaGFuZVdJTi5kZVxuICogdmVyc2lvbiAyLjAsIGNoZWNrIHd3dy5oYW5lV0lOLmRlIGZvciB0aGUgbGF0ZXN0IHZlcnNpb25cblxuICogVGhpcyBzb2Z0d2FyZSBpcyBwcm92aWRlZCBhcy1pcywgd2l0aG91dCBleHByZXNzIG9yIGltcGxpZWQgd2FycmFudHkuICBcbiAqIFBlcm1pc3Npb24gdG8gdXNlLCBjb3B5LCBtb2RpZnksIGRpc3RyaWJ1dGUgb3Igc2VsbCB0aGlzIHNvZnR3YXJlLCB3aXRoIG9yXG4gKiB3aXRob3V0IGZlZSwgZm9yIGFueSBwdXJwb3NlIGFuZCBieSBhbnkgaW5kaXZpZHVhbCBvciBvcmdhbml6YXRpb24sIGlzIGhlcmVieVxuICogZ3JhbnRlZCwgcHJvdmlkZWQgdGhhdCB0aGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcyBwYXJhZ3JhcGggYXBwZWFyIFxuICogaW4gYWxsIGNvcGllcy4gRGlzdHJpYnV0aW9uIGFzIGEgcGFydCBvZiBhbiBhcHBsaWNhdGlvbiBvciBiaW5hcnkgbXVzdFxuICogaW5jbHVkZSB0aGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBpbiB0aGUgZG9jdW1lbnRhdGlvbiBhbmQvb3Igb3RoZXJcbiAqIG1hdGVyaWFscyBwcm92aWRlZCB3aXRoIHRoZSBhcHBsaWNhdGlvbiBvciBkaXN0cmlidXRpb24uXG4gKi9cblxudmFyIHV0aWwgPSByZXF1aXJlKCcuLi91dGlsJyksXG4gIGNpcGhlciA9IHJlcXVpcmUoJy4vY2lwaGVyJyk7XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuXG4gIC8qKlxuICAgKiBBbiBhcnJheSBvZiBieXRlcywgdGhhdCBpcyBpbnRlZ2VycyB3aXRoIHZhbHVlcyBmcm9tIDAgdG8gMjU1XG4gICAqIEB0eXBlZGVmIHsoQXJyYXl8VWludDhBcnJheSl9IG9wZW5wZ3BfYnl0ZV9hcnJheVxuICAgKi9cblxuICAvKipcbiAgICogQmxvY2sgY2lwaGVyIGZ1bmN0aW9uXG4gICAqIEBjYWxsYmFjayBvcGVucGdwX2NpcGhlcl9ibG9ja19mblxuICAgKiBAcGFyYW0ge29wZW5wZ3BfYnl0ZV9hcnJheX0gYmxvY2sgQSBibG9jayB0byBwZXJmb3JtIG9wZXJhdGlvbnMgb25cbiAgICogQHBhcmFtIHtvcGVucGdwX2J5dGVfYXJyYXl9IGtleSB0byB1c2UgaW4gZW5jcnlwdGlvbi9kZWNyeXB0aW9uXG4gICAqIEByZXR1cm4ge29wZW5wZ3BfYnl0ZV9hcnJheX0gRW5jcnlwdGVkL2RlY3J5cHRlZCBibG9ja1xuICAgKi9cblxuXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gIC8qKlxuICAgKiBUaGlzIGZ1bmN0aW9uIGVuY3J5cHRzIGEgZ2l2ZW4gd2l0aCB0aGUgc3BlY2lmaWVkIHByZWZpeHJhbmRvbSBcbiAgICogdXNpbmcgdGhlIHNwZWNpZmllZCBibG9ja2NpcGhlciB0byBlbmNyeXB0IGEgbWVzc2FnZVxuICAgKiBAcGFyYW0ge1N0cmluZ30gcHJlZml4cmFuZG9tIHJhbmRvbSBieXRlcyBvZiBibG9ja19zaXplIGxlbmd0aCBwcm92aWRlZCBcbiAgICogIGFzIGEgc3RyaW5nIHRvIGJlIHVzZWQgaW4gcHJlZml4aW5nIHRoZSBkYXRhXG4gICAqIEBwYXJhbSB7b3BlbnBncF9jaXBoZXJfYmxvY2tfZm59IGJsb2NrY2lwaGVyZm4gdGhlIGFsZ29yaXRobSBlbmNyeXB0IGZ1bmN0aW9uIHRvIGVuY3J5cHRcbiAgICogIGRhdGEgaW4gb25lIGJsb2NrX3NpemUgZW5jcnlwdGlvbi4gXG4gICAqIEBwYXJhbSB7SW50ZWdlcn0gYmxvY2tfc2l6ZSB0aGUgYmxvY2sgc2l6ZSBpbiBieXRlcyBvZiB0aGUgYWxnb3JpdGhtIHVzZWRcbiAgICogQHBhcmFtIHtTdHJpbmd9IHBsYWludGV4dCBkYXRhIHRvIGJlIGVuY3J5cHRlZCBwcm92aWRlZCBhcyBhIHN0cmluZ1xuICAgKiBAcGFyYW0ge29wZW5wZ3BfYnl0ZV9hcnJheX0ga2V5IGtleSB0byBiZSB1c2VkIHRvIGVuY3J5cHQgdGhlIGRhdGEuIFRoaXMgd2lsbCBiZSBwYXNzZWQgdG8gdGhlIFxuICAgKiAgYmxvY2tjaXBoZXJmblxuICAgKiBAcGFyYW0ge0Jvb2xlYW59IHJlc3luYyBhIGJvb2xlYW4gdmFsdWUgc3BlY2lmeWluZyBpZiBhIHJlc3luYyBvZiB0aGUgXG4gICAqICBJViBzaG91bGQgYmUgdXNlZCBvciBub3QuIFRoZSBlbmNyeXB0ZWRkYXRhcGFja2V0IHVzZXMgdGhlIFxuICAgKiAgXCJvbGRcIiBzdHlsZSB3aXRoIGEgcmVzeW5jLiBFbmNyeXB0aW9uIHdpdGhpbiBhbiBcbiAgICogIGVuY3J5cHRlZGludGVncml0eXByb3RlY3RlZGRhdGEgcGFja2V0IGlzIG5vdCByZXN5bmNpbmcgdGhlIElWLlxuICAgKiBAcmV0dXJuIHtTdHJpbmd9IGEgc3RyaW5nIHdpdGggdGhlIGVuY3J5cHRlZCBkYXRhXG4gICAqL1xuICBlbmNyeXB0OiBmdW5jdGlvbihwcmVmaXhyYW5kb20sIGNpcGhlcmZuLCBwbGFpbnRleHQsIGtleSwgcmVzeW5jKSB7XG4gICAgY2lwaGVyZm4gPSBuZXcgY2lwaGVyW2NpcGhlcmZuXShrZXkpO1xuICAgIHZhciBibG9ja19zaXplID0gY2lwaGVyZm4uYmxvY2tTaXplO1xuXG4gICAgdmFyIEZSID0gbmV3IEFycmF5KGJsb2NrX3NpemUpO1xuICAgIHZhciBGUkUgPSBuZXcgQXJyYXkoYmxvY2tfc2l6ZSk7XG5cbiAgICBwcmVmaXhyYW5kb20gPSBwcmVmaXhyYW5kb20gKyBwcmVmaXhyYW5kb20uY2hhckF0KGJsb2NrX3NpemUgLSAyKSArIHByZWZpeHJhbmRvbS5jaGFyQXQoYmxvY2tfc2l6ZSAtIDEpO1xuICAgIHV0aWwucHJpbnRfZGVidWcoXCJwcmVmaXhyYW5kb206XCIgKyB1dGlsLmhleHN0cmR1bXAocHJlZml4cmFuZG9tKSk7XG4gICAgdmFyIGNpcGhlcnRleHQgPSBcIlwiO1xuICAgIC8vIDEuICBUaGUgZmVlZGJhY2sgcmVnaXN0ZXIgKEZSKSBpcyBzZXQgdG8gdGhlIElWLCB3aGljaCBpcyBhbGwgemVyb3MuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBibG9ja19zaXplOyBpKyspIEZSW2ldID0gMDtcblxuICAgIC8vIDIuICBGUiBpcyBlbmNyeXB0ZWQgdG8gcHJvZHVjZSBGUkUgKEZSIEVuY3J5cHRlZCkuICBUaGlzIGlzIHRoZVxuICAgIC8vICAgICBlbmNyeXB0aW9uIG9mIGFuIGFsbC16ZXJvIHZhbHVlLlxuICAgIEZSRSA9IGNpcGhlcmZuLmVuY3J5cHQoRlIpO1xuICAgIC8vIDMuICBGUkUgaXMgeG9yZWQgd2l0aCB0aGUgZmlyc3QgQlMgb2N0ZXRzIG9mIHJhbmRvbSBkYXRhIHByZWZpeGVkIHRvXG4gICAgLy8gICAgIHRoZSBwbGFpbnRleHQgdG8gcHJvZHVjZSBDWzFdIHRocm91Z2ggQ1tCU10sIHRoZSBmaXJzdCBCUyBvY3RldHNcbiAgICAvLyAgICAgb2YgY2lwaGVydGV4dC5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGJsb2NrX3NpemU7IGkrKykgY2lwaGVydGV4dCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKEZSRVtpXSBeIHByZWZpeHJhbmRvbS5jaGFyQ29kZUF0KGkpKTtcblxuICAgIC8vIDQuICBGUiBpcyBsb2FkZWQgd2l0aCBDWzFdIHRocm91Z2ggQ1tCU10uXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBibG9ja19zaXplOyBpKyspIEZSW2ldID0gY2lwaGVydGV4dC5jaGFyQ29kZUF0KGkpO1xuXG4gICAgLy8gNS4gIEZSIGlzIGVuY3J5cHRlZCB0byBwcm9kdWNlIEZSRSwgdGhlIGVuY3J5cHRpb24gb2YgdGhlIGZpcnN0IEJTXG4gICAgLy8gXHQgICBvY3RldHMgb2YgY2lwaGVydGV4dC5cbiAgICBGUkUgPSBjaXBoZXJmbi5lbmNyeXB0KEZSKTtcblxuICAgIC8vIDYuICBUaGUgbGVmdCB0d28gb2N0ZXRzIG9mIEZSRSBnZXQgeG9yZWQgd2l0aCB0aGUgbmV4dCB0d28gb2N0ZXRzIG9mXG4gICAgLy8gICAgIGRhdGEgdGhhdCB3ZXJlIHByZWZpeGVkIHRvIHRoZSBwbGFpbnRleHQuICBUaGlzIHByb2R1Y2VzIENbQlMrMV1cbiAgICAvLyAgICAgYW5kIENbQlMrMl0sIHRoZSBuZXh0IHR3byBvY3RldHMgb2YgY2lwaGVydGV4dC5cbiAgICBjaXBoZXJ0ZXh0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoRlJFWzBdIF4gcHJlZml4cmFuZG9tLmNoYXJDb2RlQXQoYmxvY2tfc2l6ZSkpO1xuICAgIGNpcGhlcnRleHQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShGUkVbMV0gXiBwcmVmaXhyYW5kb20uY2hhckNvZGVBdChibG9ja19zaXplICsgMSkpO1xuXG4gICAgaWYgKHJlc3luYykge1xuICAgICAgLy8gNy4gIChUaGUgcmVzeW5jIHN0ZXApIEZSIGlzIGxvYWRlZCB3aXRoIEMzLUMxMC5cbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgYmxvY2tfc2l6ZTsgaSsrKSBGUltpXSA9IGNpcGhlcnRleHQuY2hhckNvZGVBdChpICsgMik7XG4gICAgfSBlbHNlIHtcbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgYmxvY2tfc2l6ZTsgaSsrKSBGUltpXSA9IGNpcGhlcnRleHQuY2hhckNvZGVBdChpKTtcbiAgICB9XG4gICAgLy8gOC4gIEZSIGlzIGVuY3J5cHRlZCB0byBwcm9kdWNlIEZSRS5cbiAgICBGUkUgPSBjaXBoZXJmbi5lbmNyeXB0KEZSLCBrZXkpO1xuXG4gICAgaWYgKHJlc3luYykge1xuICAgICAgLy8gOS4gIEZSRSBpcyB4b3JlZCB3aXRoIHRoZSBmaXJzdCA4IG9jdGV0cyBvZiB0aGUgZ2l2ZW4gcGxhaW50ZXh0LCBub3dcbiAgICAgIC8vXHQgICB0aGF0IHdlIGhhdmUgZmluaXNoZWQgZW5jcnlwdGluZyB0aGUgMTAgb2N0ZXRzIG9mIHByZWZpeGVkIGRhdGEuXG4gICAgICAvLyBcdCAgIFRoaXMgcHJvZHVjZXMgQzExLUMxOCwgdGhlIG5leHQgOCBvY3RldHMgb2YgY2lwaGVydGV4dC5cbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgYmxvY2tfc2l6ZTsgaSsrKVxuICAgICAgICBjaXBoZXJ0ZXh0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoRlJFW2ldIF4gcGxhaW50ZXh0LmNoYXJDb2RlQXQoaSkpO1xuICAgICAgZm9yIChuID0gYmxvY2tfc2l6ZSArIDI7IG4gPCBwbGFpbnRleHQubGVuZ3RoOyBuICs9IGJsb2NrX3NpemUpIHtcbiAgICAgICAgLy8gMTAuIEZSIGlzIGxvYWRlZCB3aXRoIEMxMS1DMThcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBibG9ja19zaXplOyBpKyspIEZSW2ldID0gY2lwaGVydGV4dC5jaGFyQ29kZUF0KG4gKyBpKTtcblxuICAgICAgICAvLyAxMS4gRlIgaXMgZW5jcnlwdGVkIHRvIHByb2R1Y2UgRlJFLlxuICAgICAgICBGUkUgPSBjaXBoZXJmbi5lbmNyeXB0KEZSKTtcblxuICAgICAgICAvLyAxMi4gRlJFIGlzIHhvcmVkIHdpdGggdGhlIG5leHQgOCBvY3RldHMgb2YgcGxhaW50ZXh0LCB0byBwcm9kdWNlIHRoZVxuICAgICAgICAvLyBuZXh0IDggb2N0ZXRzIG9mIGNpcGhlcnRleHQuICBUaGVzZSBhcmUgbG9hZGVkIGludG8gRlIgYW5kIHRoZVxuICAgICAgICAvLyBwcm9jZXNzIGlzIHJlcGVhdGVkIHVudGlsIHRoZSBwbGFpbnRleHQgaXMgdXNlZCB1cC5cbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBibG9ja19zaXplOyBpKyspIGNpcGhlcnRleHQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShGUkVbaV0gXiBwbGFpbnRleHQuY2hhckNvZGVBdCgobiAtIDIpICtcbiAgICAgICAgICAgIGkpKTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgcGxhaW50ZXh0ID0gXCIgIFwiICsgcGxhaW50ZXh0O1xuICAgICAgLy8gOS4gIEZSRSBpcyB4b3JlZCB3aXRoIHRoZSBmaXJzdCA4IG9jdGV0cyBvZiB0aGUgZ2l2ZW4gcGxhaW50ZXh0LCBub3dcbiAgICAgIC8vXHQgICB0aGF0IHdlIGhhdmUgZmluaXNoZWQgZW5jcnlwdGluZyB0aGUgMTAgb2N0ZXRzIG9mIHByZWZpeGVkIGRhdGEuXG4gICAgICAvLyBcdCAgIFRoaXMgcHJvZHVjZXMgQzExLUMxOCwgdGhlIG5leHQgOCBvY3RldHMgb2YgY2lwaGVydGV4dC5cbiAgICAgIGZvciAodmFyIGkgPSAyOyBpIDwgYmxvY2tfc2l6ZTsgaSsrKSBjaXBoZXJ0ZXh0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoRlJFW2ldIF4gcGxhaW50ZXh0LmNoYXJDb2RlQXQoaSkpO1xuICAgICAgdmFyIHRlbXBDaXBoZXJ0ZXh0ID0gY2lwaGVydGV4dC5zdWJzdHJpbmcoMCwgMiAqIGJsb2NrX3NpemUpLnNwbGl0KCcnKTtcbiAgICAgIHZhciB0ZW1wQ2lwaGVydGV4dFN0cmluZyA9IGNpcGhlcnRleHQuc3Vic3RyaW5nKGJsb2NrX3NpemUpO1xuICAgICAgZm9yIChuID0gYmxvY2tfc2l6ZTsgbiA8IHBsYWludGV4dC5sZW5ndGg7IG4gKz0gYmxvY2tfc2l6ZSkge1xuICAgICAgICAvLyAxMC4gRlIgaXMgbG9hZGVkIHdpdGggQzExLUMxOFxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGJsb2NrX3NpemU7IGkrKykgRlJbaV0gPSB0ZW1wQ2lwaGVydGV4dFN0cmluZy5jaGFyQ29kZUF0KGkpO1xuICAgICAgICB0ZW1wQ2lwaGVydGV4dFN0cmluZyA9ICcnO1xuXG4gICAgICAgIC8vIDExLiBGUiBpcyBlbmNyeXB0ZWQgdG8gcHJvZHVjZSBGUkUuXG4gICAgICAgIEZSRSA9IGNpcGhlcmZuLmVuY3J5cHQoRlIpO1xuXG4gICAgICAgIC8vIDEyLiBGUkUgaXMgeG9yZWQgd2l0aCB0aGUgbmV4dCA4IG9jdGV0cyBvZiBwbGFpbnRleHQsIHRvIHByb2R1Y2UgdGhlXG4gICAgICAgIC8vICAgICBuZXh0IDggb2N0ZXRzIG9mIGNpcGhlcnRleHQuICBUaGVzZSBhcmUgbG9hZGVkIGludG8gRlIgYW5kIHRoZVxuICAgICAgICAvLyAgICAgcHJvY2VzcyBpcyByZXBlYXRlZCB1bnRpbCB0aGUgcGxhaW50ZXh0IGlzIHVzZWQgdXAuXG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgYmxvY2tfc2l6ZTsgaSsrKSB7XG4gICAgICAgICAgdGVtcENpcGhlcnRleHQucHVzaChTdHJpbmcuZnJvbUNoYXJDb2RlKEZSRVtpXSBeIHBsYWludGV4dC5jaGFyQ29kZUF0KG4gKyBpKSkpO1xuICAgICAgICAgIHRlbXBDaXBoZXJ0ZXh0U3RyaW5nICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoRlJFW2ldIF4gcGxhaW50ZXh0LmNoYXJDb2RlQXQobiArIGkpKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgY2lwaGVydGV4dCA9IHRlbXBDaXBoZXJ0ZXh0LmpvaW4oJycpO1xuXG4gICAgfVxuXG4gICAgY2lwaGVydGV4dCA9IGNpcGhlcnRleHQuc3Vic3RyaW5nKDAsIHBsYWludGV4dC5sZW5ndGggKyAyICsgYmxvY2tfc2l6ZSk7XG5cbiAgICByZXR1cm4gY2lwaGVydGV4dDtcbiAgfSxcblxuICAvKipcbiAgICogRGVjcnlwdHMgdGhlIHByZWZpeGVkIGRhdGEgZm9yIHRoZSBNb2RpZmljYXRpb24gRGV0ZWN0aW9uIENvZGUgKE1EQykgY29tcHV0YXRpb25cbiAgICogQHBhcmFtIHtvcGVucGdwX2Jsb2NrX2NpcGhlcl9mbn0gY2lwaGVyZm4uZW5jcnlwdCBDaXBoZXIgZnVuY3Rpb24gdG8gdXNlXG4gICAqIEBwYXJhbSB7SW50ZWdlcn0gYmxvY2tfc2l6ZSBCbG9ja3NpemUgb2YgdGhlIGFsZ29yaXRobVxuICAgKiBAcGFyYW0ge29wZW5wZ3BfYnl0ZV9hcnJheX0ga2V5IFRoZSBrZXkgZm9yIGVuY3J5cHRpb25cbiAgICogQHBhcmFtIHtTdHJpbmd9IGNpcGhlcnRleHQgVGhlIGVuY3J5cHRlZCBkYXRhXG4gICAqIEByZXR1cm4ge1N0cmluZ30gcGxhaW50ZXh0IERhdGEgb2YgRChjaXBoZXJ0ZXh0KSB3aXRoIGJsb2Nrc2l6ZSBsZW5ndGggKzJcbiAgICovXG4gIG1kYzogZnVuY3Rpb24oY2lwaGVyZm4sIGtleSwgY2lwaGVydGV4dCkge1xuICAgIGNpcGhlcmZuID0gbmV3IGNpcGhlcltjaXBoZXJmbl0oa2V5KTtcbiAgICB2YXIgYmxvY2tfc2l6ZSA9IGNpcGhlcmZuLmJsb2NrU2l6ZTtcblxuICAgIHZhciBpYmxvY2sgPSBuZXcgQXJyYXkoYmxvY2tfc2l6ZSk7XG4gICAgdmFyIGFibG9jayA9IG5ldyBBcnJheShibG9ja19zaXplKTtcbiAgICB2YXIgaTtcblxuXG4gICAgLy8gaW5pdGlhbGlzYXRpb24gdmVjdG9yXG4gICAgZm9yIChpID0gMDsgaSA8IGJsb2NrX3NpemU7IGkrKykgaWJsb2NrW2ldID0gMDtcblxuICAgIGlibG9jayA9IGNpcGhlcmZuLmVuY3J5cHQoaWJsb2NrKTtcbiAgICBmb3IgKGkgPSAwOyBpIDwgYmxvY2tfc2l6ZTsgaSsrKSB7XG4gICAgICBhYmxvY2tbaV0gPSBjaXBoZXJ0ZXh0LmNoYXJDb2RlQXQoaSk7XG4gICAgICBpYmxvY2tbaV0gXj0gYWJsb2NrW2ldO1xuICAgIH1cblxuICAgIGFibG9jayA9IGNpcGhlcmZuLmVuY3J5cHQoYWJsb2NrKTtcblxuICAgIHJldHVybiB1dGlsLmJpbjJzdHIoaWJsb2NrKSArXG4gICAgICBTdHJpbmcuZnJvbUNoYXJDb2RlKGFibG9ja1swXSBeIGNpcGhlcnRleHQuY2hhckNvZGVBdChibG9ja19zaXplKSkgK1xuICAgICAgU3RyaW5nLmZyb21DaGFyQ29kZShhYmxvY2tbMV0gXiBjaXBoZXJ0ZXh0LmNoYXJDb2RlQXQoYmxvY2tfc2l6ZSArIDEpKTtcbiAgfSxcbiAgLyoqXG4gICAqIFRoaXMgZnVuY3Rpb24gZGVjcnlwdHMgYSBnaXZlbiBwbGFpbnRleHQgdXNpbmcgdGhlIHNwZWNpZmllZFxuICAgKiBibG9ja2NpcGhlciB0byBkZWNyeXB0IGEgbWVzc2FnZVxuICAgKiBAcGFyYW0ge29wZW5wZ3BfY2lwaGVyX2Jsb2NrX2ZufSBibG9ja2NpcGhlcmZuIFRoZSBhbGdvcml0aG0gX2VuY3J5cHRfIGZ1bmN0aW9uIHRvIGVuY3J5cHRcbiAgICogIGRhdGEgaW4gb25lIGJsb2NrX3NpemUgZW5jcnlwdGlvbi5cbiAgICogQHBhcmFtIHtJbnRlZ2VyfSBibG9ja19zaXplIHRoZSBibG9jayBzaXplIGluIGJ5dGVzIG9mIHRoZSBhbGdvcml0aG0gdXNlZFxuICAgKiBAcGFyYW0ge1N0cmluZ30gcGxhaW50ZXh0IGNpcGhlcnRleHQgdG8gYmUgZGVjcnlwdGVkIHByb3ZpZGVkIGFzIGEgc3RyaW5nXG4gICAqIEBwYXJhbSB7b3BlbnBncF9ieXRlX2FycmF5fSBrZXkga2V5IHRvIGJlIHVzZWQgdG8gZGVjcnlwdCB0aGUgY2lwaGVydGV4dC4gVGhpcyB3aWxsIGJlIHBhc3NlZCB0byB0aGUgXG4gICAqICBibG9ja2NpcGhlcmZuXG4gICAqIEBwYXJhbSB7Qm9vbGVhbn0gcmVzeW5jIGEgYm9vbGVhbiB2YWx1ZSBzcGVjaWZ5aW5nIGlmIGEgcmVzeW5jIG9mIHRoZSBcbiAgICogIElWIHNob3VsZCBiZSB1c2VkIG9yIG5vdC4gVGhlIGVuY3J5cHRlZGRhdGFwYWNrZXQgdXNlcyB0aGUgXG4gICAqICBcIm9sZFwiIHN0eWxlIHdpdGggYSByZXN5bmMuIERlY3J5cHRpb24gd2l0aGluIGFuIFxuICAgKiAgZW5jcnlwdGVkaW50ZWdyaXR5cHJvdGVjdGVkZGF0YSBwYWNrZXQgaXMgbm90IHJlc3luY2luZyB0aGUgSVYuXG4gICAqIEByZXR1cm4ge1N0cmluZ30gYSBzdHJpbmcgd2l0aCB0aGUgcGxhaW50ZXh0IGRhdGFcbiAgICovXG5cbiAgZGVjcnlwdDogZnVuY3Rpb24oY2lwaGVyZm4sIGtleSwgY2lwaGVydGV4dCwgcmVzeW5jKSB7XG4gICAgY2lwaGVyZm4gPSBuZXcgY2lwaGVyW2NpcGhlcmZuXShrZXkpO1xuICAgIHZhciBibG9ja19zaXplID0gY2lwaGVyZm4uYmxvY2tTaXplO1xuXG4gICAgdmFyIGlibG9jayA9IG5ldyBBcnJheShibG9ja19zaXplKTtcbiAgICB2YXIgYWJsb2NrID0gbmV3IEFycmF5KGJsb2NrX3NpemUpO1xuICAgIHZhciBpLCBuID0gJyc7XG4gICAgdmFyIHRleHQgPSBbXTtcblxuICAgIC8vIGluaXRpYWxpc2F0aW9uIHZlY3RvclxuICAgIGZvciAoaSA9IDA7IGkgPCBibG9ja19zaXplOyBpKyspIGlibG9ja1tpXSA9IDA7XG5cbiAgICBpYmxvY2sgPSBjaXBoZXJmbi5lbmNyeXB0KGlibG9jaywga2V5KTtcbiAgICBmb3IgKGkgPSAwOyBpIDwgYmxvY2tfc2l6ZTsgaSsrKSB7XG4gICAgICBhYmxvY2tbaV0gPSBjaXBoZXJ0ZXh0LmNoYXJDb2RlQXQoaSk7XG4gICAgICBpYmxvY2tbaV0gXj0gYWJsb2NrW2ldO1xuICAgIH1cblxuICAgIGFibG9jayA9IGNpcGhlcmZuLmVuY3J5cHQoYWJsb2NrLCBrZXkpO1xuXG4gICAgLy8gdGVzdCBjaGVjayBvY3RldHNcbiAgICBpZiAoaWJsb2NrW2Jsb2NrX3NpemUgLSAyXSAhPSAoYWJsb2NrWzBdIF4gY2lwaGVydGV4dC5jaGFyQ29kZUF0KGJsb2NrX3NpemUpKSB8fCBpYmxvY2tbYmxvY2tfc2l6ZSAtIDFdICE9IChhYmxvY2tbXG4gICAgICAxXSBeIGNpcGhlcnRleHQuY2hhckNvZGVBdChibG9ja19zaXplICsgMSkpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgZGF0YS4nKTtcbiAgICB9XG5cbiAgICAvKiAgUkZDNDg4MDogVGFnIDE4IGFuZCBSZXN5bmM6XG5cdFx0ICogIFsuLi5dIFVubGlrZSB0aGUgU3ltbWV0cmljYWxseSBFbmNyeXB0ZWQgRGF0YSBQYWNrZXQsIG5vXG5cdFx0ICogIHNwZWNpYWwgQ0ZCIHJlc3luY2hyb25pemF0aW9uIGlzIGRvbmUgYWZ0ZXIgZW5jcnlwdGluZyB0aGlzIHByZWZpeFxuXHRcdCAqICBkYXRhLiAgU2VlIFwiT3BlblBHUCBDRkIgTW9kZVwiIGJlbG93IGZvciBtb3JlIGRldGFpbHMuXG5cblx0XHQgKi9cblxuICAgIGlmIChyZXN5bmMpIHtcbiAgICAgIGZvciAoaSA9IDA7IGkgPCBibG9ja19zaXplOyBpKyspIGlibG9ja1tpXSA9IGNpcGhlcnRleHQuY2hhckNvZGVBdChpICsgMik7XG4gICAgICBmb3IgKG4gPSBibG9ja19zaXplICsgMjsgbiA8IGNpcGhlcnRleHQubGVuZ3RoOyBuICs9IGJsb2NrX3NpemUpIHtcbiAgICAgICAgYWJsb2NrID0gY2lwaGVyZm4uZW5jcnlwdChpYmxvY2spO1xuXG4gICAgICAgIGZvciAoaSA9IDA7IGkgPCBibG9ja19zaXplICYmIGkgKyBuIDwgY2lwaGVydGV4dC5sZW5ndGg7IGkrKykge1xuICAgICAgICAgIGlibG9ja1tpXSA9IGNpcGhlcnRleHQuY2hhckNvZGVBdChuICsgaSk7XG4gICAgICAgICAgdGV4dC5wdXNoKFN0cmluZy5mcm9tQ2hhckNvZGUoYWJsb2NrW2ldIF4gaWJsb2NrW2ldKSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgZm9yIChpID0gMDsgaSA8IGJsb2NrX3NpemU7IGkrKykgaWJsb2NrW2ldID0gY2lwaGVydGV4dC5jaGFyQ29kZUF0KGkpO1xuICAgICAgZm9yIChuID0gYmxvY2tfc2l6ZTsgbiA8IGNpcGhlcnRleHQubGVuZ3RoOyBuICs9IGJsb2NrX3NpemUpIHtcbiAgICAgICAgYWJsb2NrID0gY2lwaGVyZm4uZW5jcnlwdChpYmxvY2spO1xuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgYmxvY2tfc2l6ZSAmJiBpICsgbiA8IGNpcGhlcnRleHQubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICBpYmxvY2tbaV0gPSBjaXBoZXJ0ZXh0LmNoYXJDb2RlQXQobiArIGkpO1xuICAgICAgICAgIHRleHQucHVzaChTdHJpbmcuZnJvbUNoYXJDb2RlKGFibG9ja1tpXSBeIGlibG9ja1tpXSkpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgdmFyIG4gPSByZXN5bmMgPyAwIDogMjtcblxuICAgIHRleHQgPSB0ZXh0LmpvaW4oJycpO1xuXG4gICAgdGV4dCA9IHRleHQuc3Vic3RyaW5nKG4sIGNpcGhlcnRleHQubGVuZ3RoIC0gYmxvY2tfc2l6ZSAtIDIgKyBuKTtcblxuXG4gICAgcmV0dXJuIHRleHQ7XG4gIH0sXG5cblxuICBub3JtYWxFbmNyeXB0OiBmdW5jdGlvbihjaXBoZXJmbiwga2V5LCBwbGFpbnRleHQsIGl2KSB7XG4gICAgY2lwaGVyZm4gPSBuZXcgY2lwaGVyW2NpcGhlcmZuXShrZXkpO1xuICAgIHZhciBibG9ja19zaXplID0gY2lwaGVyZm4uYmxvY2tTaXplO1xuXG4gICAgdmFyIGJsb2NraSA9IFwiXCI7XG4gICAgdmFyIGJsb2NrYyA9IFwiXCI7XG4gICAgdmFyIHBvcyA9IDA7XG4gICAgdmFyIGN5cGhlcnRleHQgPSBbXTtcbiAgICB2YXIgdGVtcEJsb2NrID0gW107XG4gICAgYmxvY2tjID0gaXYuc3Vic3RyaW5nKDAsIGJsb2NrX3NpemUpO1xuICAgIHdoaWxlIChwbGFpbnRleHQubGVuZ3RoID4gYmxvY2tfc2l6ZSAqIHBvcykge1xuICAgICAgdmFyIGVuY2Jsb2NrID0gY2lwaGVyZm4uZW5jcnlwdCh1dGlsLnN0cjJiaW4oYmxvY2tjKSk7XG4gICAgICBibG9ja2kgPSBwbGFpbnRleHQuc3Vic3RyaW5nKChwb3MgKiBibG9ja19zaXplKSwgKHBvcyAqIGJsb2NrX3NpemUpICsgYmxvY2tfc2l6ZSk7XG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGJsb2NraS5sZW5ndGg7IGkrKylcbiAgICAgICAgdGVtcEJsb2NrLnB1c2goU3RyaW5nLmZyb21DaGFyQ29kZShibG9ja2kuY2hhckNvZGVBdChpKSBeIGVuY2Jsb2NrW2ldKSk7XG4gICAgICBibG9ja2MgPSB0ZW1wQmxvY2suam9pbignJyk7XG4gICAgICB0ZW1wQmxvY2sgPSBbXTtcbiAgICAgIGN5cGhlcnRleHQucHVzaChibG9ja2MpO1xuICAgICAgcG9zKys7XG4gICAgfVxuICAgIHJldHVybiBjeXBoZXJ0ZXh0LmpvaW4oJycpO1xuICB9LFxuXG4gIG5vcm1hbERlY3J5cHQ6IGZ1bmN0aW9uKGNpcGhlcmZuLCBrZXksIGNpcGhlcnRleHQsIGl2KSB7XG4gICAgY2lwaGVyZm4gPSBuZXcgY2lwaGVyW2NpcGhlcmZuXShrZXkpO1xuICAgIHZhciBibG9ja19zaXplID0gY2lwaGVyZm4uYmxvY2tTaXplO1xuXG4gICAgdmFyIGJsb2NrcCA9IFwiXCI7XG4gICAgdmFyIHBvcyA9IDA7XG4gICAgdmFyIHBsYWludGV4dCA9IFtdO1xuICAgIHZhciBvZmZzZXQgPSAwO1xuICAgIGlmIChpdiA9PSBudWxsKVxuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBibG9ja19zaXplOyBpKyspIGJsb2NrcCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKDApO1xuICAgIGVsc2VcbiAgICAgIGJsb2NrcCA9IGl2LnN1YnN0cmluZygwLCBibG9ja19zaXplKTtcbiAgICB3aGlsZSAoY2lwaGVydGV4dC5sZW5ndGggPiAoYmxvY2tfc2l6ZSAqIHBvcykpIHtcbiAgICAgIHZhciBkZWNibG9jayA9IGNpcGhlcmZuLmVuY3J5cHQodXRpbC5zdHIyYmluKGJsb2NrcCkpO1xuICAgICAgYmxvY2twID0gY2lwaGVydGV4dC5zdWJzdHJpbmcoKHBvcyAqIChibG9ja19zaXplKSkgKyBvZmZzZXQsIChwb3MgKiAoYmxvY2tfc2l6ZSkpICsgKGJsb2NrX3NpemUpICsgb2Zmc2V0KTtcbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgYmxvY2twLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHBsYWludGV4dC5wdXNoKFN0cmluZy5mcm9tQ2hhckNvZGUoYmxvY2twLmNoYXJDb2RlQXQoaSkgXiBkZWNibG9ja1tpXSkpO1xuICAgICAgfVxuICAgICAgcG9zKys7XG4gICAgfVxuXG4gICAgcmV0dXJuIHBsYWludGV4dC5qb2luKCcnKTtcbiAgfVxufVxuIiwiLyogUmlqbmRhZWwgKEFFUykgRW5jcnlwdGlvblxuICogQ29weXJpZ2h0IDIwMDUgSGVyYmVydCBIYW5ld2lua2VsLCB3d3cuaGFuZVdJTi5kZVxuICogdmVyc2lvbiAxLjEsIGNoZWNrIHd3dy5oYW5lV0lOLmRlIGZvciB0aGUgbGF0ZXN0IHZlcnNpb25cblxuICogVGhpcyBzb2Z0d2FyZSBpcyBwcm92aWRlZCBhcy1pcywgd2l0aG91dCBleHByZXNzIG9yIGltcGxpZWQgd2FycmFudHkuICBcbiAqIFBlcm1pc3Npb24gdG8gdXNlLCBjb3B5LCBtb2RpZnksIGRpc3RyaWJ1dGUgb3Igc2VsbCB0aGlzIHNvZnR3YXJlLCB3aXRoIG9yXG4gKiB3aXRob3V0IGZlZSwgZm9yIGFueSBwdXJwb3NlIGFuZCBieSBhbnkgaW5kaXZpZHVhbCBvciBvcmdhbml6YXRpb24sIGlzIGhlcmVieVxuICogZ3JhbnRlZCwgcHJvdmlkZWQgdGhhdCB0aGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcyBwYXJhZ3JhcGggYXBwZWFyIFxuICogaW4gYWxsIGNvcGllcy4gRGlzdHJpYnV0aW9uIGFzIGEgcGFydCBvZiBhbiBhcHBsaWNhdGlvbiBvciBiaW5hcnkgbXVzdFxuICogaW5jbHVkZSB0aGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBpbiB0aGUgZG9jdW1lbnRhdGlvbiBhbmQvb3Igb3RoZXJcbiAqIG1hdGVyaWFscyBwcm92aWRlZCB3aXRoIHRoZSBhcHBsaWNhdGlvbiBvciBkaXN0cmlidXRpb24uXG4gKi9cblxudmFyIHV0aWwgPSByZXF1aXJlKCcuLi8uLi91dGlsJyk7XG5cbi8vIFRoZSByb3VuZCBjb25zdGFudHMgdXNlZCBpbiBzdWJrZXkgZXhwYW5zaW9uXG52YXIgUmNvbiA9IFtcbiAgICAweDAxLCAweDAyLCAweDA0LCAweDA4LCAweDEwLCAweDIwLCAweDQwLCAweDgwLCAweDFiLCAweDM2LCAweDZjLCAweGQ4LFxuICAgIDB4YWIsIDB4NGQsIDB4OWEsIDB4MmYsIDB4NWUsIDB4YmMsIDB4NjMsIDB4YzYsIDB4OTcsIDB4MzUsIDB4NmEsIDB4ZDQsXG4gICAgMHhiMywgMHg3ZCwgMHhmYSwgMHhlZiwgMHhjNSwgMHg5MVxuXTtcblxuLy8gUHJlY29tcHV0ZWQgbG9va3VwIHRhYmxlIGZvciB0aGUgU0JveFxudmFyIFMgPSBbXG4gICAgOTksIDEyNCwgMTE5LCAxMjMsIDI0MiwgMTA3LCAxMTEsIDE5NywgNDgsIDEsIDEwMywgNDMsIDI1NCwgMjE1LCAxNzEsXG4gICAgMTE4LCAyMDIsIDEzMCwgMjAxLCAxMjUsIDI1MCwgODksIDcxLCAyNDAsIDE3MywgMjEyLCAxNjIsIDE3NSwgMTU2LCAxNjQsXG4gICAgMTE0LCAxOTIsIDE4MywgMjUzLCAxNDcsIDM4LCA1NCwgNjMsIDI0NywgMjA0LCA1MiwgMTY1LCAyMjksIDI0MSwgMTEzLFxuICAgIDIxNiwgNDksIDIxLCA0LCAxOTksIDM1LCAxOTUsIDI0LCAxNTAsIDUsIDE1NCwgNywgMTgsIDEyOCwgMjI2LFxuICAgIDIzNSwgMzksIDE3OCwgMTE3LCA5LCAxMzEsIDQ0LCAyNiwgMjcsIDExMCwgOTAsIDE2MCwgODIsIDU5LCAyMTQsXG4gICAgMTc5LCA0MSwgMjI3LCA0NywgMTMyLCA4MywgMjA5LCAwLCAyMzcsIDMyLCAyNTIsIDE3NywgOTEsIDEwNiwgMjAzLFxuICAgIDE5MCwgNTcsIDc0LCA3NiwgODgsIDIwNywgMjA4LCAyMzksIDE3MCwgMjUxLCA2NywgNzcsIDUxLCAxMzMsIDY5LFxuICAgIDI0OSwgMiwgMTI3LCA4MCwgNjAsIDE1OSwgMTY4LCA4MSwgMTYzLCA2NCwgMTQzLCAxNDYsIDE1NywgNTYsIDI0NSxcbiAgICAxODgsIDE4MiwgMjE4LCAzMywgMTYsIDI1NSwgMjQzLCAyMTAsIDIwNSwgMTIsIDE5LCAyMzYsIDk1LCAxNTEsIDY4LFxuICAgIDIzLCAxOTYsIDE2NywgMTI2LCA2MSwgMTAwLCA5MywgMjUsIDExNSwgOTYsIDEyOSwgNzksIDIyMCwgMzQsIDQyLFxuICAgIDE0NCwgMTM2LCA3MCwgMjM4LCAxODQsIDIwLCAyMjIsIDk0LCAxMSwgMjE5LCAyMjQsIDUwLCA1OCwgMTAsIDczLFxuICAgIDYsIDM2LCA5MiwgMTk0LCAyMTEsIDE3MiwgOTgsIDE0NSwgMTQ5LCAyMjgsIDEyMSwgMjMxLCAyMDAsIDU1LCAxMDksXG4gICAgMTQxLCAyMTMsIDc4LCAxNjksIDEwOCwgODYsIDI0NCwgMjM0LCAxMDEsIDEyMiwgMTc0LCA4LCAxODYsIDEyMCwgMzcsXG4gICAgNDYsIDI4LCAxNjYsIDE4MCwgMTk4LCAyMzIsIDIyMSwgMTE2LCAzMSwgNzUsIDE4OSwgMTM5LCAxMzgsIDExMiwgNjIsXG4gICAgMTgxLCAxMDIsIDcyLCAzLCAyNDYsIDE0LCA5NywgNTMsIDg3LCAxODUsIDEzNCwgMTkzLCAyOSwgMTU4LCAyMjUsXG4gICAgMjQ4LCAxNTIsIDE3LCAxMDUsIDIxNywgMTQyLCAxNDgsIDE1NSwgMzAsIDEzNSwgMjMzLCAyMDYsIDg1LCA0MCwgMjIzLFxuICAgIDE0MCwgMTYxLCAxMzcsIDEzLCAxOTEsIDIzMCwgNjYsIDEwNCwgNjUsIDE1MywgNDUsIDE1LCAxNzYsIDg0LCAxODcsXG4gICAgMjJcbl07XG5cbnZhciBUMSA9IFtcbiAgICAweGE1NjM2M2M2LCAweDg0N2M3Y2Y4LCAweDk5Nzc3N2VlLCAweDhkN2I3YmY2LFxuICAgIDB4MGRmMmYyZmYsIDB4YmQ2YjZiZDYsIDB4YjE2ZjZmZGUsIDB4NTRjNWM1OTEsXG4gICAgMHg1MDMwMzA2MCwgMHgwMzAxMDEwMiwgMHhhOTY3NjdjZSwgMHg3ZDJiMmI1NixcbiAgICAweDE5ZmVmZWU3LCAweDYyZDdkN2I1LCAweGU2YWJhYjRkLCAweDlhNzY3NmVjLFxuICAgIDB4NDVjYWNhOGYsIDB4OWQ4MjgyMWYsIDB4NDBjOWM5ODksIDB4ODc3ZDdkZmEsXG4gICAgMHgxNWZhZmFlZiwgMHhlYjU5NTliMiwgMHhjOTQ3NDc4ZSwgMHgwYmYwZjBmYixcbiAgICAweGVjYWRhZDQxLCAweDY3ZDRkNGIzLCAweGZkYTJhMjVmLCAweGVhYWZhZjQ1LFxuICAgIDB4YmY5YzljMjMsIDB4ZjdhNGE0NTMsIDB4OTY3MjcyZTQsIDB4NWJjMGMwOWIsXG4gICAgMHhjMmI3Yjc3NSwgMHgxY2ZkZmRlMSwgMHhhZTkzOTMzZCwgMHg2YTI2MjY0YyxcbiAgICAweDVhMzYzNjZjLCAweDQxM2YzZjdlLCAweDAyZjdmN2Y1LCAweDRmY2NjYzgzLFxuICAgIDB4NWMzNDM0NjgsIDB4ZjRhNWE1NTEsIDB4MzRlNWU1ZDEsIDB4MDhmMWYxZjksXG4gICAgMHg5MzcxNzFlMiwgMHg3M2Q4ZDhhYiwgMHg1MzMxMzE2MiwgMHgzZjE1MTUyYSxcbiAgICAweDBjMDQwNDA4LCAweDUyYzdjNzk1LCAweDY1MjMyMzQ2LCAweDVlYzNjMzlkLFxuICAgIDB4MjgxODE4MzAsIDB4YTE5Njk2MzcsIDB4MGYwNTA1MGEsIDB4YjU5YTlhMmYsXG4gICAgMHgwOTA3MDcwZSwgMHgzNjEyMTIyNCwgMHg5YjgwODAxYiwgMHgzZGUyZTJkZixcbiAgICAweDI2ZWJlYmNkLCAweDY5MjcyNzRlLCAweGNkYjJiMjdmLCAweDlmNzU3NWVhLFxuICAgIDB4MWIwOTA5MTIsIDB4OWU4MzgzMWQsIDB4NzQyYzJjNTgsIDB4MmUxYTFhMzQsXG4gICAgMHgyZDFiMWIzNiwgMHhiMjZlNmVkYywgMHhlZTVhNWFiNCwgMHhmYmEwYTA1YixcbiAgICAweGY2NTI1MmE0LCAweDRkM2IzYjc2LCAweDYxZDZkNmI3LCAweGNlYjNiMzdkLFxuICAgIDB4N2IyOTI5NTIsIDB4M2VlM2UzZGQsIDB4NzEyZjJmNWUsIDB4OTc4NDg0MTMsXG4gICAgMHhmNTUzNTNhNiwgMHg2OGQxZDFiOSwgMHgwMDAwMDAwMCwgMHgyY2VkZWRjMSxcbiAgICAweDYwMjAyMDQwLCAweDFmZmNmY2UzLCAweGM4YjFiMTc5LCAweGVkNWI1YmI2LFxuICAgIDB4YmU2YTZhZDQsIDB4NDZjYmNiOGQsIDB4ZDliZWJlNjcsIDB4NGIzOTM5NzIsXG4gICAgMHhkZTRhNGE5NCwgMHhkNDRjNGM5OCwgMHhlODU4NThiMCwgMHg0YWNmY2Y4NSxcbiAgICAweDZiZDBkMGJiLCAweDJhZWZlZmM1LCAweGU1YWFhYTRmLCAweDE2ZmJmYmVkLFxuICAgIDB4YzU0MzQzODYsIDB4ZDc0ZDRkOWEsIDB4NTUzMzMzNjYsIDB4OTQ4NTg1MTEsXG4gICAgMHhjZjQ1NDU4YSwgMHgxMGY5ZjllOSwgMHgwNjAyMDIwNCwgMHg4MTdmN2ZmZSxcbiAgICAweGYwNTA1MGEwLCAweDQ0M2MzYzc4LCAweGJhOWY5ZjI1LCAweGUzYThhODRiLFxuICAgIDB4ZjM1MTUxYTIsIDB4ZmVhM2EzNWQsIDB4YzA0MDQwODAsIDB4OGE4ZjhmMDUsXG4gICAgMHhhZDkyOTIzZiwgMHhiYzlkOWQyMSwgMHg0ODM4Mzg3MCwgMHgwNGY1ZjVmMSxcbiAgICAweGRmYmNiYzYzLCAweGMxYjZiNjc3LCAweDc1ZGFkYWFmLCAweDYzMjEyMTQyLFxuICAgIDB4MzAxMDEwMjAsIDB4MWFmZmZmZTUsIDB4MGVmM2YzZmQsIDB4NmRkMmQyYmYsXG4gICAgMHg0Y2NkY2Q4MSwgMHgxNDBjMGMxOCwgMHgzNTEzMTMyNiwgMHgyZmVjZWNjMyxcbiAgICAweGUxNWY1ZmJlLCAweGEyOTc5NzM1LCAweGNjNDQ0NDg4LCAweDM5MTcxNzJlLFxuICAgIDB4NTdjNGM0OTMsIDB4ZjJhN2E3NTUsIDB4ODI3ZTdlZmMsIDB4NDczZDNkN2EsXG4gICAgMHhhYzY0NjRjOCwgMHhlNzVkNWRiYSwgMHgyYjE5MTkzMiwgMHg5NTczNzNlNixcbiAgICAweGEwNjA2MGMwLCAweDk4ODE4MTE5LCAweGQxNGY0ZjllLCAweDdmZGNkY2EzLFxuICAgIDB4NjYyMjIyNDQsIDB4N2UyYTJhNTQsIDB4YWI5MDkwM2IsIDB4ODM4ODg4MGIsXG4gICAgMHhjYTQ2NDY4YywgMHgyOWVlZWVjNywgMHhkM2I4Yjg2YiwgMHgzYzE0MTQyOCxcbiAgICAweDc5ZGVkZWE3LCAweGUyNWU1ZWJjLCAweDFkMGIwYjE2LCAweDc2ZGJkYmFkLFxuICAgIDB4M2JlMGUwZGIsIDB4NTYzMjMyNjQsIDB4NGUzYTNhNzQsIDB4MWUwYTBhMTQsXG4gICAgMHhkYjQ5NDk5MiwgMHgwYTA2MDYwYywgMHg2YzI0MjQ0OCwgMHhlNDVjNWNiOCxcbiAgICAweDVkYzJjMjlmLCAweDZlZDNkM2JkLCAweGVmYWNhYzQzLCAweGE2NjI2MmM0LFxuICAgIDB4YTg5MTkxMzksIDB4YTQ5NTk1MzEsIDB4MzdlNGU0ZDMsIDB4OGI3OTc5ZjIsXG4gICAgMHgzMmU3ZTdkNSwgMHg0M2M4Yzg4YiwgMHg1OTM3Mzc2ZSwgMHhiNzZkNmRkYSxcbiAgICAweDhjOGQ4ZDAxLCAweDY0ZDVkNWIxLCAweGQyNGU0ZTljLCAweGUwYTlhOTQ5LFxuICAgIDB4YjQ2YzZjZDgsIDB4ZmE1NjU2YWMsIDB4MDdmNGY0ZjMsIDB4MjVlYWVhY2YsXG4gICAgMHhhZjY1NjVjYSwgMHg4ZTdhN2FmNCwgMHhlOWFlYWU0NywgMHgxODA4MDgxMCxcbiAgICAweGQ1YmFiYTZmLCAweDg4Nzg3OGYwLCAweDZmMjUyNTRhLCAweDcyMmUyZTVjLFxuICAgIDB4MjQxYzFjMzgsIDB4ZjFhNmE2NTcsIDB4YzdiNGI0NzMsIDB4NTFjNmM2OTcsXG4gICAgMHgyM2U4ZThjYiwgMHg3Y2RkZGRhMSwgMHg5Yzc0NzRlOCwgMHgyMTFmMWYzZSxcbiAgICAweGRkNGI0Yjk2LCAweGRjYmRiZDYxLCAweDg2OGI4YjBkLCAweDg1OGE4YTBmLFxuICAgIDB4OTA3MDcwZTAsIDB4NDIzZTNlN2MsIDB4YzRiNWI1NzEsIDB4YWE2NjY2Y2MsXG4gICAgMHhkODQ4NDg5MCwgMHgwNTAzMDMwNiwgMHgwMWY2ZjZmNywgMHgxMjBlMGUxYyxcbiAgICAweGEzNjE2MWMyLCAweDVmMzUzNTZhLCAweGY5NTc1N2FlLCAweGQwYjliOTY5LFxuICAgIDB4OTE4Njg2MTcsIDB4NThjMWMxOTksIDB4MjcxZDFkM2EsIDB4Yjk5ZTllMjcsXG4gICAgMHgzOGUxZTFkOSwgMHgxM2Y4ZjhlYiwgMHhiMzk4OTgyYiwgMHgzMzExMTEyMixcbiAgICAweGJiNjk2OWQyLCAweDcwZDlkOWE5LCAweDg5OGU4ZTA3LCAweGE3OTQ5NDMzLFxuICAgIDB4YjY5YjliMmQsIDB4MjIxZTFlM2MsIDB4OTI4Nzg3MTUsIDB4MjBlOWU5YzksXG4gICAgMHg0OWNlY2U4NywgMHhmZjU1NTVhYSwgMHg3ODI4Mjg1MCwgMHg3YWRmZGZhNSxcbiAgICAweDhmOGM4YzAzLCAweGY4YTFhMTU5LCAweDgwODk4OTA5LCAweDE3MGQwZDFhLFxuICAgIDB4ZGFiZmJmNjUsIDB4MzFlNmU2ZDcsIDB4YzY0MjQyODQsIDB4Yjg2ODY4ZDAsXG4gICAgMHhjMzQxNDE4MiwgMHhiMDk5OTkyOSwgMHg3NzJkMmQ1YSwgMHgxMTBmMGYxZSxcbiAgICAweGNiYjBiMDdiLCAweGZjNTQ1NGE4LCAweGQ2YmJiYjZkLCAweDNhMTYxNjJjXG5dO1xuXG52YXIgVDIgPSBbXG4gICAgMHg2MzYzYzZhNSwgMHg3YzdjZjg4NCwgMHg3Nzc3ZWU5OSwgMHg3YjdiZjY4ZCxcbiAgICAweGYyZjJmZjBkLCAweDZiNmJkNmJkLCAweDZmNmZkZWIxLCAweGM1YzU5MTU0LFxuICAgIDB4MzAzMDYwNTAsIDB4MDEwMTAyMDMsIDB4Njc2N2NlYTksIDB4MmIyYjU2N2QsXG4gICAgMHhmZWZlZTcxOSwgMHhkN2Q3YjU2MiwgMHhhYmFiNGRlNiwgMHg3Njc2ZWM5YSxcbiAgICAweGNhY2E4ZjQ1LCAweDgyODIxZjlkLCAweGM5Yzk4OTQwLCAweDdkN2RmYTg3LFxuICAgIDB4ZmFmYWVmMTUsIDB4NTk1OWIyZWIsIDB4NDc0NzhlYzksIDB4ZjBmMGZiMGIsXG4gICAgMHhhZGFkNDFlYywgMHhkNGQ0YjM2NywgMHhhMmEyNWZmZCwgMHhhZmFmNDVlYSxcbiAgICAweDljOWMyM2JmLCAweGE0YTQ1M2Y3LCAweDcyNzJlNDk2LCAweGMwYzA5YjViLFxuICAgIDB4YjdiNzc1YzIsIDB4ZmRmZGUxMWMsIDB4OTM5MzNkYWUsIDB4MjYyNjRjNmEsXG4gICAgMHgzNjM2NmM1YSwgMHgzZjNmN2U0MSwgMHhmN2Y3ZjUwMiwgMHhjY2NjODM0ZixcbiAgICAweDM0MzQ2ODVjLCAweGE1YTU1MWY0LCAweGU1ZTVkMTM0LCAweGYxZjFmOTA4LFxuICAgIDB4NzE3MWUyOTMsIDB4ZDhkOGFiNzMsIDB4MzEzMTYyNTMsIDB4MTUxNTJhM2YsXG4gICAgMHgwNDA0MDgwYywgMHhjN2M3OTU1MiwgMHgyMzIzNDY2NSwgMHhjM2MzOWQ1ZSxcbiAgICAweDE4MTgzMDI4LCAweDk2OTYzN2ExLCAweDA1MDUwYTBmLCAweDlhOWEyZmI1LFxuICAgIDB4MDcwNzBlMDksIDB4MTIxMjI0MzYsIDB4ODA4MDFiOWIsIDB4ZTJlMmRmM2QsXG4gICAgMHhlYmViY2QyNiwgMHgyNzI3NGU2OSwgMHhiMmIyN2ZjZCwgMHg3NTc1ZWE5ZixcbiAgICAweDA5MDkxMjFiLCAweDgzODMxZDllLCAweDJjMmM1ODc0LCAweDFhMWEzNDJlLFxuICAgIDB4MWIxYjM2MmQsIDB4NmU2ZWRjYjIsIDB4NWE1YWI0ZWUsIDB4YTBhMDViZmIsXG4gICAgMHg1MjUyYTRmNiwgMHgzYjNiNzY0ZCwgMHhkNmQ2Yjc2MSwgMHhiM2IzN2RjZSxcbiAgICAweDI5Mjk1MjdiLCAweGUzZTNkZDNlLCAweDJmMmY1ZTcxLCAweDg0ODQxMzk3LFxuICAgIDB4NTM1M2E2ZjUsIDB4ZDFkMWI5NjgsIDB4MDAwMDAwMDAsIDB4ZWRlZGMxMmMsXG4gICAgMHgyMDIwNDA2MCwgMHhmY2ZjZTMxZiwgMHhiMWIxNzljOCwgMHg1YjViYjZlZCxcbiAgICAweDZhNmFkNGJlLCAweGNiY2I4ZDQ2LCAweGJlYmU2N2Q5LCAweDM5Mzk3MjRiLFxuICAgIDB4NGE0YTk0ZGUsIDB4NGM0Yzk4ZDQsIDB4NTg1OGIwZTgsIDB4Y2ZjZjg1NGEsXG4gICAgMHhkMGQwYmI2YiwgMHhlZmVmYzUyYSwgMHhhYWFhNGZlNSwgMHhmYmZiZWQxNixcbiAgICAweDQzNDM4NmM1LCAweDRkNGQ5YWQ3LCAweDMzMzM2NjU1LCAweDg1ODUxMTk0LFxuICAgIDB4NDU0NThhY2YsIDB4ZjlmOWU5MTAsIDB4MDIwMjA0MDYsIDB4N2Y3ZmZlODEsXG4gICAgMHg1MDUwYTBmMCwgMHgzYzNjNzg0NCwgMHg5ZjlmMjViYSwgMHhhOGE4NGJlMyxcbiAgICAweDUxNTFhMmYzLCAweGEzYTM1ZGZlLCAweDQwNDA4MGMwLCAweDhmOGYwNThhLFxuICAgIDB4OTI5MjNmYWQsIDB4OWQ5ZDIxYmMsIDB4MzgzODcwNDgsIDB4ZjVmNWYxMDQsXG4gICAgMHhiY2JjNjNkZiwgMHhiNmI2NzdjMSwgMHhkYWRhYWY3NSwgMHgyMTIxNDI2MyxcbiAgICAweDEwMTAyMDMwLCAweGZmZmZlNTFhLCAweGYzZjNmZDBlLCAweGQyZDJiZjZkLFxuICAgIDB4Y2RjZDgxNGMsIDB4MGMwYzE4MTQsIDB4MTMxMzI2MzUsIDB4ZWNlY2MzMmYsXG4gICAgMHg1ZjVmYmVlMSwgMHg5Nzk3MzVhMiwgMHg0NDQ0ODhjYywgMHgxNzE3MmUzOSxcbiAgICAweGM0YzQ5MzU3LCAweGE3YTc1NWYyLCAweDdlN2VmYzgyLCAweDNkM2Q3YTQ3LFxuICAgIDB4NjQ2NGM4YWMsIDB4NWQ1ZGJhZTcsIDB4MTkxOTMyMmIsIDB4NzM3M2U2OTUsXG4gICAgMHg2MDYwYzBhMCwgMHg4MTgxMTk5OCwgMHg0ZjRmOWVkMSwgMHhkY2RjYTM3ZixcbiAgICAweDIyMjI0NDY2LCAweDJhMmE1NDdlLCAweDkwOTAzYmFiLCAweDg4ODgwYjgzLFxuICAgIDB4NDY0NjhjY2EsIDB4ZWVlZWM3MjksIDB4YjhiODZiZDMsIDB4MTQxNDI4M2MsXG4gICAgMHhkZWRlYTc3OSwgMHg1ZTVlYmNlMiwgMHgwYjBiMTYxZCwgMHhkYmRiYWQ3NixcbiAgICAweGUwZTBkYjNiLCAweDMyMzI2NDU2LCAweDNhM2E3NDRlLCAweDBhMGExNDFlLFxuICAgIDB4NDk0OTkyZGIsIDB4MDYwNjBjMGEsIDB4MjQyNDQ4NmMsIDB4NWM1Y2I4ZTQsXG4gICAgMHhjMmMyOWY1ZCwgMHhkM2QzYmQ2ZSwgMHhhY2FjNDNlZiwgMHg2MjYyYzRhNixcbiAgICAweDkxOTEzOWE4LCAweDk1OTUzMWE0LCAweGU0ZTRkMzM3LCAweDc5NzlmMjhiLFxuICAgIDB4ZTdlN2Q1MzIsIDB4YzhjODhiNDMsIDB4MzczNzZlNTksIDB4NmQ2ZGRhYjcsXG4gICAgMHg4ZDhkMDE4YywgMHhkNWQ1YjE2NCwgMHg0ZTRlOWNkMiwgMHhhOWE5NDllMCxcbiAgICAweDZjNmNkOGI0LCAweDU2NTZhY2ZhLCAweGY0ZjRmMzA3LCAweGVhZWFjZjI1LFxuICAgIDB4NjU2NWNhYWYsIDB4N2E3YWY0OGUsIDB4YWVhZTQ3ZTksIDB4MDgwODEwMTgsXG4gICAgMHhiYWJhNmZkNSwgMHg3ODc4ZjA4OCwgMHgyNTI1NGE2ZiwgMHgyZTJlNWM3MixcbiAgICAweDFjMWMzODI0LCAweGE2YTY1N2YxLCAweGI0YjQ3M2M3LCAweGM2YzY5NzUxLFxuICAgIDB4ZThlOGNiMjMsIDB4ZGRkZGExN2MsIDB4NzQ3NGU4OWMsIDB4MWYxZjNlMjEsXG4gICAgMHg0YjRiOTZkZCwgMHhiZGJkNjFkYywgMHg4YjhiMGQ4NiwgMHg4YThhMGY4NSxcbiAgICAweDcwNzBlMDkwLCAweDNlM2U3YzQyLCAweGI1YjU3MWM0LCAweDY2NjZjY2FhLFxuICAgIDB4NDg0ODkwZDgsIDB4MDMwMzA2MDUsIDB4ZjZmNmY3MDEsIDB4MGUwZTFjMTIsXG4gICAgMHg2MTYxYzJhMywgMHgzNTM1NmE1ZiwgMHg1NzU3YWVmOSwgMHhiOWI5NjlkMCxcbiAgICAweDg2ODYxNzkxLCAweGMxYzE5OTU4LCAweDFkMWQzYTI3LCAweDllOWUyN2I5LFxuICAgIDB4ZTFlMWQ5MzgsIDB4ZjhmOGViMTMsIDB4OTg5ODJiYjMsIDB4MTExMTIyMzMsXG4gICAgMHg2OTY5ZDJiYiwgMHhkOWQ5YTk3MCwgMHg4ZThlMDc4OSwgMHg5NDk0MzNhNyxcbiAgICAweDliOWIyZGI2LCAweDFlMWUzYzIyLCAweDg3ODcxNTkyLCAweGU5ZTljOTIwLFxuICAgIDB4Y2VjZTg3NDksIDB4NTU1NWFhZmYsIDB4MjgyODUwNzgsIDB4ZGZkZmE1N2EsXG4gICAgMHg4YzhjMDM4ZiwgMHhhMWExNTlmOCwgMHg4OTg5MDk4MCwgMHgwZDBkMWExNyxcbiAgICAweGJmYmY2NWRhLCAweGU2ZTZkNzMxLCAweDQyNDI4NGM2LCAweDY4NjhkMGI4LFxuICAgIDB4NDE0MTgyYzMsIDB4OTk5OTI5YjAsIDB4MmQyZDVhNzcsIDB4MGYwZjFlMTEsXG4gICAgMHhiMGIwN2JjYiwgMHg1NDU0YThmYywgMHhiYmJiNmRkNiwgMHgxNjE2MmMzYVxuXTtcblxudmFyIFQzID0gW1xuICAgIDB4NjNjNmE1NjMsIDB4N2NmODg0N2MsIDB4NzdlZTk5NzcsIDB4N2JmNjhkN2IsXG4gICAgMHhmMmZmMGRmMiwgMHg2YmQ2YmQ2YiwgMHg2ZmRlYjE2ZiwgMHhjNTkxNTRjNSxcbiAgICAweDMwNjA1MDMwLCAweDAxMDIwMzAxLCAweDY3Y2VhOTY3LCAweDJiNTY3ZDJiLFxuICAgIDB4ZmVlNzE5ZmUsIDB4ZDdiNTYyZDcsIDB4YWI0ZGU2YWIsIDB4NzZlYzlhNzYsXG4gICAgMHhjYThmNDVjYSwgMHg4MjFmOWQ4MiwgMHhjOTg5NDBjOSwgMHg3ZGZhODc3ZCxcbiAgICAweGZhZWYxNWZhLCAweDU5YjJlYjU5LCAweDQ3OGVjOTQ3LCAweGYwZmIwYmYwLFxuICAgIDB4YWQ0MWVjYWQsIDB4ZDRiMzY3ZDQsIDB4YTI1ZmZkYTIsIDB4YWY0NWVhYWYsXG4gICAgMHg5YzIzYmY5YywgMHhhNDUzZjdhNCwgMHg3MmU0OTY3MiwgMHhjMDliNWJjMCxcbiAgICAweGI3NzVjMmI3LCAweGZkZTExY2ZkLCAweDkzM2RhZTkzLCAweDI2NGM2YTI2LFxuICAgIDB4MzY2YzVhMzYsIDB4M2Y3ZTQxM2YsIDB4ZjdmNTAyZjcsIDB4Y2M4MzRmY2MsXG4gICAgMHgzNDY4NWMzNCwgMHhhNTUxZjRhNSwgMHhlNWQxMzRlNSwgMHhmMWY5MDhmMSxcbiAgICAweDcxZTI5MzcxLCAweGQ4YWI3M2Q4LCAweDMxNjI1MzMxLCAweDE1MmEzZjE1LFxuICAgIDB4MDQwODBjMDQsIDB4Yzc5NTUyYzcsIDB4MjM0NjY1MjMsIDB4YzM5ZDVlYzMsXG4gICAgMHgxODMwMjgxOCwgMHg5NjM3YTE5NiwgMHgwNTBhMGYwNSwgMHg5YTJmYjU5YSxcbiAgICAweDA3MGUwOTA3LCAweDEyMjQzNjEyLCAweDgwMWI5YjgwLCAweGUyZGYzZGUyLFxuICAgIDB4ZWJjZDI2ZWIsIDB4Mjc0ZTY5MjcsIDB4YjI3ZmNkYjIsIDB4NzVlYTlmNzUsXG4gICAgMHgwOTEyMWIwOSwgMHg4MzFkOWU4MywgMHgyYzU4NzQyYywgMHgxYTM0MmUxYSxcbiAgICAweDFiMzYyZDFiLCAweDZlZGNiMjZlLCAweDVhYjRlZTVhLCAweGEwNWJmYmEwLFxuICAgIDB4NTJhNGY2NTIsIDB4M2I3NjRkM2IsIDB4ZDZiNzYxZDYsIDB4YjM3ZGNlYjMsXG4gICAgMHgyOTUyN2IyOSwgMHhlM2RkM2VlMywgMHgyZjVlNzEyZiwgMHg4NDEzOTc4NCxcbiAgICAweDUzYTZmNTUzLCAweGQxYjk2OGQxLCAweDAwMDAwMDAwLCAweGVkYzEyY2VkLFxuICAgIDB4MjA0MDYwMjAsIDB4ZmNlMzFmZmMsIDB4YjE3OWM4YjEsIDB4NWJiNmVkNWIsXG4gICAgMHg2YWQ0YmU2YSwgMHhjYjhkNDZjYiwgMHhiZTY3ZDliZSwgMHgzOTcyNGIzOSxcbiAgICAweDRhOTRkZTRhLCAweDRjOThkNDRjLCAweDU4YjBlODU4LCAweGNmODU0YWNmLFxuICAgIDB4ZDBiYjZiZDAsIDB4ZWZjNTJhZWYsIDB4YWE0ZmU1YWEsIDB4ZmJlZDE2ZmIsXG4gICAgMHg0Mzg2YzU0MywgMHg0ZDlhZDc0ZCwgMHgzMzY2NTUzMywgMHg4NTExOTQ4NSxcbiAgICAweDQ1OGFjZjQ1LCAweGY5ZTkxMGY5LCAweDAyMDQwNjAyLCAweDdmZmU4MTdmLFxuICAgIDB4NTBhMGYwNTAsIDB4M2M3ODQ0M2MsIDB4OWYyNWJhOWYsIDB4YTg0YmUzYTgsXG4gICAgMHg1MWEyZjM1MSwgMHhhMzVkZmVhMywgMHg0MDgwYzA0MCwgMHg4ZjA1OGE4ZixcbiAgICAweDkyM2ZhZDkyLCAweDlkMjFiYzlkLCAweDM4NzA0ODM4LCAweGY1ZjEwNGY1LFxuICAgIDB4YmM2M2RmYmMsIDB4YjY3N2MxYjYsIDB4ZGFhZjc1ZGEsIDB4MjE0MjYzMjEsXG4gICAgMHgxMDIwMzAxMCwgMHhmZmU1MWFmZiwgMHhmM2ZkMGVmMywgMHhkMmJmNmRkMixcbiAgICAweGNkODE0Y2NkLCAweDBjMTgxNDBjLCAweDEzMjYzNTEzLCAweGVjYzMyZmVjLFxuICAgIDB4NWZiZWUxNWYsIDB4OTczNWEyOTcsIDB4NDQ4OGNjNDQsIDB4MTcyZTM5MTcsXG4gICAgMHhjNDkzNTdjNCwgMHhhNzU1ZjJhNywgMHg3ZWZjODI3ZSwgMHgzZDdhNDczZCxcbiAgICAweDY0YzhhYzY0LCAweDVkYmFlNzVkLCAweDE5MzIyYjE5LCAweDczZTY5NTczLFxuICAgIDB4NjBjMGEwNjAsIDB4ODExOTk4ODEsIDB4NGY5ZWQxNGYsIDB4ZGNhMzdmZGMsXG4gICAgMHgyMjQ0NjYyMiwgMHgyYTU0N2UyYSwgMHg5MDNiYWI5MCwgMHg4ODBiODM4OCxcbiAgICAweDQ2OGNjYTQ2LCAweGVlYzcyOWVlLCAweGI4NmJkM2I4LCAweDE0MjgzYzE0LFxuICAgIDB4ZGVhNzc5ZGUsIDB4NWViY2UyNWUsIDB4MGIxNjFkMGIsIDB4ZGJhZDc2ZGIsXG4gICAgMHhlMGRiM2JlMCwgMHgzMjY0NTYzMiwgMHgzYTc0NGUzYSwgMHgwYTE0MWUwYSxcbiAgICAweDQ5OTJkYjQ5LCAweDA2MGMwYTA2LCAweDI0NDg2YzI0LCAweDVjYjhlNDVjLFxuICAgIDB4YzI5ZjVkYzIsIDB4ZDNiZDZlZDMsIDB4YWM0M2VmYWMsIDB4NjJjNGE2NjIsXG4gICAgMHg5MTM5YTg5MSwgMHg5NTMxYTQ5NSwgMHhlNGQzMzdlNCwgMHg3OWYyOGI3OSxcbiAgICAweGU3ZDUzMmU3LCAweGM4OGI0M2M4LCAweDM3NmU1OTM3LCAweDZkZGFiNzZkLFxuICAgIDB4OGQwMThjOGQsIDB4ZDViMTY0ZDUsIDB4NGU5Y2QyNGUsIDB4YTk0OWUwYTksXG4gICAgMHg2Y2Q4YjQ2YywgMHg1NmFjZmE1NiwgMHhmNGYzMDdmNCwgMHhlYWNmMjVlYSxcbiAgICAweDY1Y2FhZjY1LCAweDdhZjQ4ZTdhLCAweGFlNDdlOWFlLCAweDA4MTAxODA4LFxuICAgIDB4YmE2ZmQ1YmEsIDB4NzhmMDg4NzgsIDB4MjU0YTZmMjUsIDB4MmU1YzcyMmUsXG4gICAgMHgxYzM4MjQxYywgMHhhNjU3ZjFhNiwgMHhiNDczYzdiNCwgMHhjNjk3NTFjNixcbiAgICAweGU4Y2IyM2U4LCAweGRkYTE3Y2RkLCAweDc0ZTg5Yzc0LCAweDFmM2UyMTFmLFxuICAgIDB4NGI5NmRkNGIsIDB4YmQ2MWRjYmQsIDB4OGIwZDg2OGIsIDB4OGEwZjg1OGEsXG4gICAgMHg3MGUwOTA3MCwgMHgzZTdjNDIzZSwgMHhiNTcxYzRiNSwgMHg2NmNjYWE2NixcbiAgICAweDQ4OTBkODQ4LCAweDAzMDYwNTAzLCAweGY2ZjcwMWY2LCAweDBlMWMxMjBlLFxuICAgIDB4NjFjMmEzNjEsIDB4MzU2YTVmMzUsIDB4NTdhZWY5NTcsIDB4Yjk2OWQwYjksXG4gICAgMHg4NjE3OTE4NiwgMHhjMTk5NThjMSwgMHgxZDNhMjcxZCwgMHg5ZTI3Yjk5ZSxcbiAgICAweGUxZDkzOGUxLCAweGY4ZWIxM2Y4LCAweDk4MmJiMzk4LCAweDExMjIzMzExLFxuICAgIDB4NjlkMmJiNjksIDB4ZDlhOTcwZDksIDB4OGUwNzg5OGUsIDB4OTQzM2E3OTQsXG4gICAgMHg5YjJkYjY5YiwgMHgxZTNjMjIxZSwgMHg4NzE1OTI4NywgMHhlOWM5MjBlOSxcbiAgICAweGNlODc0OWNlLCAweDU1YWFmZjU1LCAweDI4NTA3ODI4LCAweGRmYTU3YWRmLFxuICAgIDB4OGMwMzhmOGMsIDB4YTE1OWY4YTEsIDB4ODkwOTgwODksIDB4MGQxYTE3MGQsXG4gICAgMHhiZjY1ZGFiZiwgMHhlNmQ3MzFlNiwgMHg0Mjg0YzY0MiwgMHg2OGQwYjg2OCxcbiAgICAweDQxODJjMzQxLCAweDk5MjliMDk5LCAweDJkNWE3NzJkLCAweDBmMWUxMTBmLFxuICAgIDB4YjA3YmNiYjAsIDB4NTRhOGZjNTQsIDB4YmI2ZGQ2YmIsIDB4MTYyYzNhMTZcbl07XG5cbnZhciBUNCA9IFtcbiAgICAweGM2YTU2MzYzLCAweGY4ODQ3YzdjLCAweGVlOTk3Nzc3LCAweGY2OGQ3YjdiLFxuICAgIDB4ZmYwZGYyZjIsIDB4ZDZiZDZiNmIsIDB4ZGViMTZmNmYsIDB4OTE1NGM1YzUsXG4gICAgMHg2MDUwMzAzMCwgMHgwMjAzMDEwMSwgMHhjZWE5Njc2NywgMHg1NjdkMmIyYixcbiAgICAweGU3MTlmZWZlLCAweGI1NjJkN2Q3LCAweDRkZTZhYmFiLCAweGVjOWE3Njc2LFxuICAgIDB4OGY0NWNhY2EsIDB4MWY5ZDgyODIsIDB4ODk0MGM5YzksIDB4ZmE4NzdkN2QsXG4gICAgMHhlZjE1ZmFmYSwgMHhiMmViNTk1OSwgMHg4ZWM5NDc0NywgMHhmYjBiZjBmMCxcbiAgICAweDQxZWNhZGFkLCAweGIzNjdkNGQ0LCAweDVmZmRhMmEyLCAweDQ1ZWFhZmFmLFxuICAgIDB4MjNiZjljOWMsIDB4NTNmN2E0YTQsIDB4ZTQ5NjcyNzIsIDB4OWI1YmMwYzAsXG4gICAgMHg3NWMyYjdiNywgMHhlMTFjZmRmZCwgMHgzZGFlOTM5MywgMHg0YzZhMjYyNixcbiAgICAweDZjNWEzNjM2LCAweDdlNDEzZjNmLCAweGY1MDJmN2Y3LCAweDgzNGZjY2NjLFxuICAgIDB4Njg1YzM0MzQsIDB4NTFmNGE1YTUsIDB4ZDEzNGU1ZTUsIDB4ZjkwOGYxZjEsXG4gICAgMHhlMjkzNzE3MSwgMHhhYjczZDhkOCwgMHg2MjUzMzEzMSwgMHgyYTNmMTUxNSxcbiAgICAweDA4MGMwNDA0LCAweDk1NTJjN2M3LCAweDQ2NjUyMzIzLCAweDlkNWVjM2MzLFxuICAgIDB4MzAyODE4MTgsIDB4MzdhMTk2OTYsIDB4MGEwZjA1MDUsIDB4MmZiNTlhOWEsXG4gICAgMHgwZTA5MDcwNywgMHgyNDM2MTIxMiwgMHgxYjliODA4MCwgMHhkZjNkZTJlMixcbiAgICAweGNkMjZlYmViLCAweDRlNjkyNzI3LCAweDdmY2RiMmIyLCAweGVhOWY3NTc1LFxuICAgIDB4MTIxYjA5MDksIDB4MWQ5ZTgzODMsIDB4NTg3NDJjMmMsIDB4MzQyZTFhMWEsXG4gICAgMHgzNjJkMWIxYiwgMHhkY2IyNmU2ZSwgMHhiNGVlNWE1YSwgMHg1YmZiYTBhMCxcbiAgICAweGE0ZjY1MjUyLCAweDc2NGQzYjNiLCAweGI3NjFkNmQ2LCAweDdkY2ViM2IzLFxuICAgIDB4NTI3YjI5MjksIDB4ZGQzZWUzZTMsIDB4NWU3MTJmMmYsIDB4MTM5Nzg0ODQsXG4gICAgMHhhNmY1NTM1MywgMHhiOTY4ZDFkMSwgMHgwMDAwMDAwMCwgMHhjMTJjZWRlZCxcbiAgICAweDQwNjAyMDIwLCAweGUzMWZmY2ZjLCAweDc5YzhiMWIxLCAweGI2ZWQ1YjViLFxuICAgIDB4ZDRiZTZhNmEsIDB4OGQ0NmNiY2IsIDB4NjdkOWJlYmUsIDB4NzI0YjM5MzksXG4gICAgMHg5NGRlNGE0YSwgMHg5OGQ0NGM0YywgMHhiMGU4NTg1OCwgMHg4NTRhY2ZjZixcbiAgICAweGJiNmJkMGQwLCAweGM1MmFlZmVmLCAweDRmZTVhYWFhLCAweGVkMTZmYmZiLFxuICAgIDB4ODZjNTQzNDMsIDB4OWFkNzRkNGQsIDB4NjY1NTMzMzMsIDB4MTE5NDg1ODUsXG4gICAgMHg4YWNmNDU0NSwgMHhlOTEwZjlmOSwgMHgwNDA2MDIwMiwgMHhmZTgxN2Y3ZixcbiAgICAweGEwZjA1MDUwLCAweDc4NDQzYzNjLCAweDI1YmE5ZjlmLCAweDRiZTNhOGE4LFxuICAgIDB4YTJmMzUxNTEsIDB4NWRmZWEzYTMsIDB4ODBjMDQwNDAsIDB4MDU4YThmOGYsXG4gICAgMHgzZmFkOTI5MiwgMHgyMWJjOWQ5ZCwgMHg3MDQ4MzgzOCwgMHhmMTA0ZjVmNSxcbiAgICAweDYzZGZiY2JjLCAweDc3YzFiNmI2LCAweGFmNzVkYWRhLCAweDQyNjMyMTIxLFxuICAgIDB4MjAzMDEwMTAsIDB4ZTUxYWZmZmYsIDB4ZmQwZWYzZjMsIDB4YmY2ZGQyZDIsXG4gICAgMHg4MTRjY2RjZCwgMHgxODE0MGMwYywgMHgyNjM1MTMxMywgMHhjMzJmZWNlYyxcbiAgICAweGJlZTE1ZjVmLCAweDM1YTI5Nzk3LCAweDg4Y2M0NDQ0LCAweDJlMzkxNzE3LFxuICAgIDB4OTM1N2M0YzQsIDB4NTVmMmE3YTcsIDB4ZmM4MjdlN2UsIDB4N2E0NzNkM2QsXG4gICAgMHhjOGFjNjQ2NCwgMHhiYWU3NWQ1ZCwgMHgzMjJiMTkxOSwgMHhlNjk1NzM3MyxcbiAgICAweGMwYTA2MDYwLCAweDE5OTg4MTgxLCAweDllZDE0ZjRmLCAweGEzN2ZkY2RjLFxuICAgIDB4NDQ2NjIyMjIsIDB4NTQ3ZTJhMmEsIDB4M2JhYjkwOTAsIDB4MGI4Mzg4ODgsXG4gICAgMHg4Y2NhNDY0NiwgMHhjNzI5ZWVlZSwgMHg2YmQzYjhiOCwgMHgyODNjMTQxNCxcbiAgICAweGE3NzlkZWRlLCAweGJjZTI1ZTVlLCAweDE2MWQwYjBiLCAweGFkNzZkYmRiLFxuICAgIDB4ZGIzYmUwZTAsIDB4NjQ1NjMyMzIsIDB4NzQ0ZTNhM2EsIDB4MTQxZTBhMGEsXG4gICAgMHg5MmRiNDk0OSwgMHgwYzBhMDYwNiwgMHg0ODZjMjQyNCwgMHhiOGU0NWM1YyxcbiAgICAweDlmNWRjMmMyLCAweGJkNmVkM2QzLCAweDQzZWZhY2FjLCAweGM0YTY2MjYyLFxuICAgIDB4MzlhODkxOTEsIDB4MzFhNDk1OTUsIDB4ZDMzN2U0ZTQsIDB4ZjI4Yjc5NzksXG4gICAgMHhkNTMyZTdlNywgMHg4YjQzYzhjOCwgMHg2ZTU5MzczNywgMHhkYWI3NmQ2ZCxcbiAgICAweDAxOGM4ZDhkLCAweGIxNjRkNWQ1LCAweDljZDI0ZTRlLCAweDQ5ZTBhOWE5LFxuICAgIDB4ZDhiNDZjNmMsIDB4YWNmYTU2NTYsIDB4ZjMwN2Y0ZjQsIDB4Y2YyNWVhZWEsXG4gICAgMHhjYWFmNjU2NSwgMHhmNDhlN2E3YSwgMHg0N2U5YWVhZSwgMHgxMDE4MDgwOCxcbiAgICAweDZmZDViYWJhLCAweGYwODg3ODc4LCAweDRhNmYyNTI1LCAweDVjNzIyZTJlLFxuICAgIDB4MzgyNDFjMWMsIDB4NTdmMWE2YTYsIDB4NzNjN2I0YjQsIDB4OTc1MWM2YzYsXG4gICAgMHhjYjIzZThlOCwgMHhhMTdjZGRkZCwgMHhlODljNzQ3NCwgMHgzZTIxMWYxZixcbiAgICAweDk2ZGQ0YjRiLCAweDYxZGNiZGJkLCAweDBkODY4YjhiLCAweDBmODU4YThhLFxuICAgIDB4ZTA5MDcwNzAsIDB4N2M0MjNlM2UsIDB4NzFjNGI1YjUsIDB4Y2NhYTY2NjYsXG4gICAgMHg5MGQ4NDg0OCwgMHgwNjA1MDMwMywgMHhmNzAxZjZmNiwgMHgxYzEyMGUwZSxcbiAgICAweGMyYTM2MTYxLCAweDZhNWYzNTM1LCAweGFlZjk1NzU3LCAweDY5ZDBiOWI5LFxuICAgIDB4MTc5MTg2ODYsIDB4OTk1OGMxYzEsIDB4M2EyNzFkMWQsIDB4MjdiOTllOWUsXG4gICAgMHhkOTM4ZTFlMSwgMHhlYjEzZjhmOCwgMHgyYmIzOTg5OCwgMHgyMjMzMTExMSxcbiAgICAweGQyYmI2OTY5LCAweGE5NzBkOWQ5LCAweDA3ODk4ZThlLCAweDMzYTc5NDk0LFxuICAgIDB4MmRiNjliOWIsIDB4M2MyMjFlMWUsIDB4MTU5Mjg3ODcsIDB4YzkyMGU5ZTksXG4gICAgMHg4NzQ5Y2VjZSwgMHhhYWZmNTU1NSwgMHg1MDc4MjgyOCwgMHhhNTdhZGZkZixcbiAgICAweDAzOGY4YzhjLCAweDU5ZjhhMWExLCAweDA5ODA4OTg5LCAweDFhMTcwZDBkLFxuICAgIDB4NjVkYWJmYmYsIDB4ZDczMWU2ZTYsIDB4ODRjNjQyNDIsIDB4ZDBiODY4NjgsXG4gICAgMHg4MmMzNDE0MSwgMHgyOWIwOTk5OSwgMHg1YTc3MmQyZCwgMHgxZTExMGYwZixcbiAgICAweDdiY2JiMGIwLCAweGE4ZmM1NDU0LCAweDZkZDZiYmJiLCAweDJjM2ExNjE2XG5dO1xuXG5mdW5jdGlvbiBCMCh4KSB7XG4gIHJldHVybiAoeCAmIDI1NSk7XG59XG5cbmZ1bmN0aW9uIEIxKHgpIHtcbiAgcmV0dXJuICgoeCA+PiA4KSAmIDI1NSk7XG59XG5cbmZ1bmN0aW9uIEIyKHgpIHtcbiAgcmV0dXJuICgoeCA+PiAxNikgJiAyNTUpO1xufVxuXG5mdW5jdGlvbiBCMyh4KSB7XG4gIHJldHVybiAoKHggPj4gMjQpICYgMjU1KTtcbn1cblxuZnVuY3Rpb24gRjEoeDAsIHgxLCB4MiwgeDMpIHtcbiAgcmV0dXJuIEIxKFQxW3gwICYgMjU1XSkgfCAoQjEoVDFbKHgxID4+IDgpICYgMjU1XSkgPDwgOCkgfCAoQjEoVDFbKHgyID4+IDE2KSAmIDI1NV0pIDw8IDE2KSB8IChCMShUMVt4MyA+Pj4gMjRdKSA8PFxuICAgIDI0KTtcbn1cblxuZnVuY3Rpb24gcGFja0J5dGVzKG9jdGV0cykge1xuICB2YXIgaSwgajtcbiAgdmFyIGxlbiA9IG9jdGV0cy5sZW5ndGg7XG4gIHZhciBiID0gbmV3IEFycmF5KGxlbiAvIDQpO1xuXG4gIGlmICghb2N0ZXRzIHx8IGxlbiAlIDQpIHJldHVybjtcblxuICBmb3IgKGkgPSAwLCBqID0gMDsgaiA8IGxlbjsgaiArPSA0KVxuICAgIGJbaSsrXSA9IG9jdGV0c1tqXSB8IChvY3RldHNbaiArIDFdIDw8IDgpIHwgKG9jdGV0c1tqICsgMl0gPDwgMTYpIHwgKG9jdGV0c1tqICsgM10gPDwgMjQpO1xuXG4gIHJldHVybiBiO1xufVxuXG5mdW5jdGlvbiB1bnBhY2tCeXRlcyhwYWNrZWQpIHtcbiAgdmFyIGo7XG4gIHZhciBpID0gMCxcbiAgICBsID0gcGFja2VkLmxlbmd0aDtcbiAgdmFyIHIgPSBuZXcgQXJyYXkobCAqIDQpO1xuXG4gIGZvciAoaiA9IDA7IGogPCBsOyBqKyspIHtcbiAgICByW2krK10gPSBCMChwYWNrZWRbal0pO1xuICAgIHJbaSsrXSA9IEIxKHBhY2tlZFtqXSk7XG4gICAgcltpKytdID0gQjIocGFja2VkW2pdKTtcbiAgICByW2krK10gPSBCMyhwYWNrZWRbal0pO1xuICB9XG4gIHJldHVybiByO1xufVxuXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxudmFyIG1heGtjID0gODtcbnZhciBtYXhyayA9IDE0O1xuXG5mdW5jdGlvbiBrZXlFeHBhbnNpb24oa2V5KSB7XG4gIHZhciBrYywgaSwgaiwgciwgdDtcbiAgdmFyIHJvdW5kcztcbiAgdmFyIGtleVNjaGVkID0gbmV3IEFycmF5KG1heHJrICsgMSk7XG4gIHZhciBrZXlsZW4gPSBrZXkubGVuZ3RoO1xuICB2YXIgayA9IG5ldyBBcnJheShtYXhrYyk7XG4gIHZhciB0ayA9IG5ldyBBcnJheShtYXhrYyk7XG4gIHZhciByY29ucG9pbnRlciA9IDA7XG5cbiAgaWYgKGtleWxlbiA9PSAxNikge1xuICAgIHJvdW5kcyA9IDEwO1xuICAgIGtjID0gNDtcbiAgfSBlbHNlIGlmIChrZXlsZW4gPT0gMjQpIHtcbiAgICByb3VuZHMgPSAxMjtcbiAgICBrYyA9IDY7XG4gIH0gZWxzZSBpZiAoa2V5bGVuID09IDMyKSB7XG4gICAgcm91bmRzID0gMTQ7XG4gICAga2MgPSA4O1xuICB9IGVsc2Uge1xuICAgIHV0aWwucHJpbnRfZXJyb3IoJ2Flcy5qczogSW52YWxpZCBrZXktbGVuZ3RoIGZvciBBRVMga2V5OicgKyBrZXlsZW4pO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGZvciAoaSA9IDA7IGkgPCBtYXhyayArIDE7IGkrKykga2V5U2NoZWRbaV0gPSBuZXcgQXJyYXkoNCk7XG5cbiAgZm9yIChpID0gMCwgaiA9IDA7IGogPCBrZXlsZW47IGorKywgaSArPSA0KVxuICAgIGtbal0gPSBrZXkuY2hhckNvZGVBdChpKSB8IChrZXkuY2hhckNvZGVBdChpICsgMSkgPDwgOCkgfCAoa2V5LmNoYXJDb2RlQXQoaSArIDIpIDw8IDE2KSB8IChrZXkuY2hhckNvZGVBdChpICsgMykgPDxcbiAgICAgIDI0KTtcblxuICBmb3IgKGogPSBrYyAtIDE7IGogPj0gMDsgai0tKSB0a1tqXSA9IGtbal07XG5cbiAgciA9IDA7XG4gIHQgPSAwO1xuICBmb3IgKGogPSAwO1xuICAoaiA8IGtjKSAmJiAociA8IHJvdW5kcyArIDEpOykge1xuICAgIGZvciAoO1xuICAgIChqIDwga2MpICYmICh0IDwgNCk7IGorKywgdCsrKSB7XG4gICAgICBrZXlTY2hlZFtyXVt0XSA9IHRrW2pdO1xuICAgIH1cbiAgICBpZiAodCA9PSA0KSB7XG4gICAgICByKys7XG4gICAgICB0ID0gMDtcbiAgICB9XG4gIH1cblxuICB3aGlsZSAociA8IHJvdW5kcyArIDEpIHtcbiAgICB2YXIgdGVtcCA9IHRrW2tjIC0gMV07XG5cbiAgICB0a1swXSBePSBTW0IxKHRlbXApXSB8IChTW0IyKHRlbXApXSA8PCA4KSB8IChTW0IzKHRlbXApXSA8PCAxNikgfCAoU1tCMCh0ZW1wKV0gPDwgMjQpO1xuICAgIHRrWzBdIF49IFJjb25bcmNvbnBvaW50ZXIrK107XG5cbiAgICBpZiAoa2MgIT0gOCkge1xuICAgICAgZm9yIChqID0gMTsgaiA8IGtjOyBqKyspIHRrW2pdIF49IHRrW2ogLSAxXTtcbiAgICB9IGVsc2Uge1xuICAgICAgZm9yIChqID0gMTsgaiA8IGtjIC8gMjsgaisrKSB0a1tqXSBePSB0a1tqIC0gMV07XG5cbiAgICAgIHRlbXAgPSB0a1trYyAvIDIgLSAxXTtcbiAgICAgIHRrW2tjIC8gMl0gXj0gU1tCMCh0ZW1wKV0gfCAoU1tCMSh0ZW1wKV0gPDwgOCkgfCAoU1tCMih0ZW1wKV0gPDwgMTYpIHwgKFNbQjModGVtcCldIDw8IDI0KTtcblxuICAgICAgZm9yIChqID0ga2MgLyAyICsgMTsgaiA8IGtjOyBqKyspIHRrW2pdIF49IHRrW2ogLSAxXTtcbiAgICB9XG5cbiAgICBmb3IgKGogPSAwO1xuICAgIChqIDwga2MpICYmIChyIDwgcm91bmRzICsgMSk7KSB7XG4gICAgICBmb3IgKDtcbiAgICAgIChqIDwga2MpICYmICh0IDwgNCk7IGorKywgdCsrKSB7XG4gICAgICAgIGtleVNjaGVkW3JdW3RdID0gdGtbal07XG4gICAgICB9XG4gICAgICBpZiAodCA9PSA0KSB7XG4gICAgICAgIHIrKztcbiAgICAgICAgdCA9IDA7XG4gICAgICB9XG4gICAgfVxuICB9XG4gIHRoaXMucm91bmRzID0gcm91bmRzO1xuICB0aGlzLnJrID0ga2V5U2NoZWQ7XG4gIHJldHVybiB0aGlzO1xufVxuXG5mdW5jdGlvbiBBRVNlbmNyeXB0KGJsb2NrLCBjdHgpIHtcbiAgdmFyIHI7XG4gIHZhciB0MCwgdDEsIHQyLCB0MztcblxuICB2YXIgYiA9IHBhY2tCeXRlcyhibG9jayk7XG4gIHZhciByb3VuZHMgPSBjdHgucm91bmRzO1xuICB2YXIgYjAgPSBiWzBdO1xuICB2YXIgYjEgPSBiWzFdO1xuICB2YXIgYjIgPSBiWzJdO1xuICB2YXIgYjMgPSBiWzNdO1xuXG4gIGZvciAociA9IDA7IHIgPCByb3VuZHMgLSAxOyByKyspIHtcbiAgICB0MCA9IGIwIF4gY3R4LnJrW3JdWzBdO1xuICAgIHQxID0gYjEgXiBjdHgucmtbcl1bMV07XG4gICAgdDIgPSBiMiBeIGN0eC5ya1tyXVsyXTtcbiAgICB0MyA9IGIzIF4gY3R4LnJrW3JdWzNdO1xuXG4gICAgYjAgPSBUMVt0MCAmIDI1NV0gXiBUMlsodDEgPj4gOCkgJiAyNTVdIF4gVDNbKHQyID4+IDE2KSAmIDI1NV0gXiBUNFt0MyA+Pj4gMjRdO1xuICAgIGIxID0gVDFbdDEgJiAyNTVdIF4gVDJbKHQyID4+IDgpICYgMjU1XSBeIFQzWyh0MyA+PiAxNikgJiAyNTVdIF4gVDRbdDAgPj4+IDI0XTtcbiAgICBiMiA9IFQxW3QyICYgMjU1XSBeIFQyWyh0MyA+PiA4KSAmIDI1NV0gXiBUM1sodDAgPj4gMTYpICYgMjU1XSBeIFQ0W3QxID4+PiAyNF07XG4gICAgYjMgPSBUMVt0MyAmIDI1NV0gXiBUMlsodDAgPj4gOCkgJiAyNTVdIF4gVDNbKHQxID4+IDE2KSAmIDI1NV0gXiBUNFt0MiA+Pj4gMjRdO1xuICB9XG5cbiAgLy8gbGFzdCByb3VuZCBpcyBzcGVjaWFsXG4gIHIgPSByb3VuZHMgLSAxO1xuXG4gIHQwID0gYjAgXiBjdHgucmtbcl1bMF07XG4gIHQxID0gYjEgXiBjdHgucmtbcl1bMV07XG4gIHQyID0gYjIgXiBjdHgucmtbcl1bMl07XG4gIHQzID0gYjMgXiBjdHgucmtbcl1bM107XG5cbiAgYlswXSA9IEYxKHQwLCB0MSwgdDIsIHQzKSBeIGN0eC5ya1tyb3VuZHNdWzBdO1xuICBiWzFdID0gRjEodDEsIHQyLCB0MywgdDApIF4gY3R4LnJrW3JvdW5kc11bMV07XG4gIGJbMl0gPSBGMSh0MiwgdDMsIHQwLCB0MSkgXiBjdHgucmtbcm91bmRzXVsyXTtcbiAgYlszXSA9IEYxKHQzLCB0MCwgdDEsIHQyKSBeIGN0eC5ya1tyb3VuZHNdWzNdO1xuXG4gIHJldHVybiB1bnBhY2tCeXRlcyhiKTtcbn1cblxuZnVuY3Rpb24gbWFrZUNsYXNzKGxlbmd0aCkge1xuXG4gIHZhciBjID0gZnVuY3Rpb24oa2V5KSB7XG4gICAgdGhpcy5rZXkgPSBrZXlFeHBhbnNpb24oa2V5KTtcblxuICAgIHRoaXMuZW5jcnlwdCA9IGZ1bmN0aW9uKGJsb2NrKSB7XG4gICAgICByZXR1cm4gQUVTZW5jcnlwdChibG9jaywgdGhpcy5rZXkpO1xuICAgIH1cbiAgfVxuXG4gIGMuYmxvY2tTaXplID0gYy5wcm90b3R5cGUuYmxvY2tTaXplID0gMTY7XG4gIGMua2V5U2l6ZSA9IGMucHJvdG90eXBlLmtleVNpemUgPSBsZW5ndGggLyA4O1xuXG4gIHJldHVybiBjO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHt9XG5cbnZhciB0eXBlcyA9IFsxMjgsIDE5MiwgMjU2XTtcblxuZm9yICh2YXIgaSBpbiB0eXBlcykge1xuICBtb2R1bGUuZXhwb3J0c1t0eXBlc1tpXV0gPSBtYWtlQ2xhc3ModHlwZXNbaV0pO1xufVxuIiwiLyogTW9kaWZpZWQgYnkgUmVjdXJpdHkgTGFicyBHbWJIIFxuICogXG4gKiBPcmlnaW5hbGx5IHdyaXR0ZW4gYnkgbmtsZWluIHNvZnR3YXJlIChua2xlaW4uY29tKVxuICovXG5cbi8qIFxuICogSmF2YXNjcmlwdCBpbXBsZW1lbnRhdGlvbiBiYXNlZCBvbiBCcnVjZSBTY2huZWllcidzIHJlZmVyZW5jZSBpbXBsZW1lbnRhdGlvbi5cbiAqXG4gKlxuICogVGhlIGNvbnN0cnVjdG9yIGRvZXNuJ3QgZG8gbXVjaCBvZiBhbnl0aGluZy4gIEl0J3MganVzdCBoZXJlXG4gKiBzbyB3ZSBjYW4gc3RhcnQgZGVmaW5pbmcgcHJvcGVydGllcyBhbmQgbWV0aG9kcyBhbmQgc3VjaC5cbiAqL1xuZnVuY3Rpb24gQmxvd2Zpc2goKSB7fTtcblxuLypcbiAqIERlY2xhcmUgdGhlIGJsb2NrIHNpemUgc28gdGhhdCBwcm90b2NvbHMga25vdyB3aGF0IHNpemVcbiAqIEluaXRpYWxpemF0aW9uIFZlY3RvciAoSVYpIHRoZXkgd2lsbCBuZWVkLlxuICovXG5CbG93ZmlzaC5wcm90b3R5cGUuQkxPQ0tTSVpFID0gODtcblxuLypcbiAqIFRoZXNlIGFyZSB0aGUgZGVmYXVsdCBTQk9YRVMuXG4gKi9cbkJsb3dmaXNoLnByb3RvdHlwZS5TQk9YRVMgPSBbXG4gIFtcbiAgICAgIDB4ZDEzMTBiYTYsIDB4OThkZmI1YWMsIDB4MmZmZDcyZGIsIDB4ZDAxYWRmYjcsIDB4YjhlMWFmZWQsIDB4NmEyNjdlOTYsXG4gICAgICAweGJhN2M5MDQ1LCAweGYxMmM3Zjk5LCAweDI0YTE5OTQ3LCAweGIzOTE2Y2Y3LCAweDA4MDFmMmUyLCAweDg1OGVmYzE2LFxuICAgICAgMHg2MzY5MjBkOCwgMHg3MTU3NGU2OSwgMHhhNDU4ZmVhMywgMHhmNDkzM2Q3ZSwgMHgwZDk1NzQ4ZiwgMHg3MjhlYjY1OCxcbiAgICAgIDB4NzE4YmNkNTgsIDB4ODIxNTRhZWUsIDB4N2I1NGE0MWQsIDB4YzI1YTU5YjUsIDB4OWMzMGQ1MzksIDB4MmFmMjYwMTMsXG4gICAgICAweGM1ZDFiMDIzLCAweDI4NjA4NWYwLCAweGNhNDE3OTE4LCAweGI4ZGIzOGVmLCAweDhlNzlkY2IwLCAweDYwM2ExODBlLFxuICAgICAgMHg2YzllMGU4YiwgMHhiMDFlOGEzZSwgMHhkNzE1NzdjMSwgMHhiZDMxNGIyNywgMHg3OGFmMmZkYSwgMHg1NTYwNWM2MCxcbiAgICAgIDB4ZTY1NTI1ZjMsIDB4YWE1NWFiOTQsIDB4NTc0ODk4NjIsIDB4NjNlODE0NDAsIDB4NTVjYTM5NmEsIDB4MmFhYjEwYjYsXG4gICAgICAweGI0Y2M1YzM0LCAweDExNDFlOGNlLCAweGExNTQ4NmFmLCAweDdjNzJlOTkzLCAweGIzZWUxNDExLCAweDYzNmZiYzJhLFxuICAgICAgMHgyYmE5YzU1ZCwgMHg3NDE4MzFmNiwgMHhjZTVjM2UxNiwgMHg5Yjg3OTMxZSwgMHhhZmQ2YmEzMywgMHg2YzI0Y2Y1YyxcbiAgICAgIDB4N2EzMjUzODEsIDB4Mjg5NTg2NzcsIDB4M2I4ZjQ4OTgsIDB4NmI0YmI5YWYsIDB4YzRiZmU4MWIsIDB4NjYyODIxOTMsXG4gICAgICAweDYxZDgwOWNjLCAweGZiMjFhOTkxLCAweDQ4N2NhYzYwLCAweDVkZWM4MDMyLCAweGVmODQ1ZDVkLCAweGU5ODU3NWIxLFxuICAgICAgMHhkYzI2MjMwMiwgMHhlYjY1MWI4OCwgMHgyMzg5M2U4MSwgMHhkMzk2YWNjNSwgMHgwZjZkNmZmMywgMHg4M2Y0NDIzOSxcbiAgICAgIDB4MmUwYjQ0ODIsIDB4YTQ4NDIwMDQsIDB4NjljOGYwNGEsIDB4OWUxZjliNWUsIDB4MjFjNjY4NDIsIDB4ZjZlOTZjOWEsXG4gICAgICAweDY3MGM5YzYxLCAweGFiZDM4OGYwLCAweDZhNTFhMGQyLCAweGQ4NTQyZjY4LCAweDk2MGZhNzI4LCAweGFiNTEzM2EzLFxuICAgICAgMHg2ZWVmMGI2YywgMHgxMzdhM2JlNCwgMHhiYTNiZjA1MCwgMHg3ZWZiMmE5OCwgMHhhMWYxNjUxZCwgMHgzOWFmMDE3NixcbiAgICAgIDB4NjZjYTU5M2UsIDB4ODI0MzBlODgsIDB4OGNlZTg2MTksIDB4NDU2ZjlmYjQsIDB4N2Q4NGE1YzMsIDB4M2I4YjVlYmUsXG4gICAgICAweGUwNmY3NWQ4LCAweDg1YzEyMDczLCAweDQwMWE0NDlmLCAweDU2YzE2YWE2LCAweDRlZDNhYTYyLCAweDM2M2Y3NzA2LFxuICAgICAgMHgxYmZlZGY3MiwgMHg0MjliMDIzZCwgMHgzN2QwZDcyNCwgMHhkMDBhMTI0OCwgMHhkYjBmZWFkMywgMHg0OWYxYzA5YixcbiAgICAgIDB4MDc1MzcyYzksIDB4ODA5OTFiN2IsIDB4MjVkNDc5ZDgsIDB4ZjZlOGRlZjcsIDB4ZTNmZTUwMWEsIDB4YjY3OTRjM2IsXG4gICAgICAweDk3NmNlMGJkLCAweDA0YzAwNmJhLCAweGMxYTk0ZmI2LCAweDQwOWY2MGM0LCAweDVlNWM5ZWMyLCAweDE5NmEyNDYzLFxuICAgICAgMHg2OGZiNmZhZiwgMHgzZTZjNTNiNSwgMHgxMzM5YjJlYiwgMHgzYjUyZWM2ZiwgMHg2ZGZjNTExZiwgMHg5YjMwOTUyYyxcbiAgICAgIDB4Y2M4MTQ1NDQsIDB4YWY1ZWJkMDksIDB4YmVlM2QwMDQsIDB4ZGUzMzRhZmQsIDB4NjYwZjI4MDcsIDB4MTkyZTRiYjMsXG4gICAgICAweGMwY2JhODU3LCAweDQ1Yzg3NDBmLCAweGQyMGI1ZjM5LCAweGI5ZDNmYmRiLCAweDU1NzljMGJkLCAweDFhNjAzMjBhLFxuICAgICAgMHhkNmExMDBjNiwgMHg0MDJjNzI3OSwgMHg2NzlmMjVmZSwgMHhmYjFmYTNjYywgMHg4ZWE1ZTlmOCwgMHhkYjMyMjJmOCxcbiAgICAgIDB4M2M3NTE2ZGYsIDB4ZmQ2MTZiMTUsIDB4MmY1MDFlYzgsIDB4YWQwNTUyYWIsIDB4MzIzZGI1ZmEsIDB4ZmQyMzg3NjAsXG4gICAgICAweDUzMzE3YjQ4LCAweDNlMDBkZjgyLCAweDllNWM1N2JiLCAweGNhNmY4Y2EwLCAweDFhODc1NjJlLCAweGRmMTc2OWRiLFxuICAgICAgMHhkNTQyYThmNiwgMHgyODdlZmZjMywgMHhhYzY3MzJjNiwgMHg4YzRmNTU3MywgMHg2OTViMjdiMCwgMHhiYmNhNThjOCxcbiAgICAgIDB4ZTFmZmEzNWQsIDB4YjhmMDExYTAsIDB4MTBmYTNkOTgsIDB4ZmQyMTgzYjgsIDB4NGFmY2I1NmMsIDB4MmRkMWQzNWIsXG4gICAgICAweDlhNTNlNDc5LCAweGI2Zjg0NTY1LCAweGQyOGU0OWJjLCAweDRiZmI5NzkwLCAweGUxZGRmMmRhLCAweGE0Y2I3ZTMzLFxuICAgICAgMHg2MmZiMTM0MSwgMHhjZWU0YzZlOCwgMHhlZjIwY2FkYSwgMHgzNjc3NGMwMSwgMHhkMDdlOWVmZSwgMHgyYmYxMWZiNCxcbiAgICAgIDB4OTVkYmRhNGQsIDB4YWU5MDkxOTgsIDB4ZWFhZDhlNzEsIDB4NmI5M2Q1YTAsIDB4ZDA4ZWQxZDAsIDB4YWZjNzI1ZTAsXG4gICAgICAweDhlM2M1YjJmLCAweDhlNzU5NGI3LCAweDhmZjZlMmZiLCAweGYyMTIyYjY0LCAweDg4ODhiODEyLCAweDkwMGRmMDFjLFxuICAgICAgMHg0ZmFkNWVhMCwgMHg2ODhmYzMxYywgMHhkMWNmZjE5MSwgMHhiM2E4YzFhZCwgMHgyZjJmMjIxOCwgMHhiZTBlMTc3NyxcbiAgICAgIDB4ZWE3NTJkZmUsIDB4OGIwMjFmYTEsIDB4ZTVhMGNjMGYsIDB4YjU2Zjc0ZTgsIDB4MThhY2YzZDYsIDB4Y2U4OWUyOTksXG4gICAgICAweGI0YTg0ZmUwLCAweGZkMTNlMGI3LCAweDdjYzQzYjgxLCAweGQyYWRhOGQ5LCAweDE2NWZhMjY2LCAweDgwOTU3NzA1LFxuICAgICAgMHg5M2NjNzMxNCwgMHgyMTFhMTQ3NywgMHhlNmFkMjA2NSwgMHg3N2I1ZmE4NiwgMHhjNzU0NDJmNSwgMHhmYjlkMzVjZixcbiAgICAgIDB4ZWJjZGFmMGMsIDB4N2IzZTg5YTAsIDB4ZDY0MTFiZDMsIDB4YWUxZTdlNDksIDB4MDAyNTBlMmQsIDB4MjA3MWIzNWUsXG4gICAgICAweDIyNjgwMGJiLCAweDU3YjhlMGFmLCAweDI0NjQzNjliLCAweGYwMDliOTFlLCAweDU1NjM5MTFkLCAweDU5ZGZhNmFhLFxuICAgICAgMHg3OGMxNDM4OSwgMHhkOTVhNTM3ZiwgMHgyMDdkNWJhMiwgMHgwMmU1YjljNSwgMHg4MzI2MDM3NiwgMHg2Mjk1Y2ZhOSxcbiAgICAgIDB4MTFjODE5NjgsIDB4NGU3MzRhNDEsIDB4YjM0NzJkY2EsIDB4N2IxNGE5NGEsIDB4MWI1MTAwNTIsIDB4OWE1MzI5MTUsXG4gICAgICAweGQ2MGY1NzNmLCAweGJjOWJjNmU0LCAweDJiNjBhNDc2LCAweDgxZTY3NDAwLCAweDA4YmE2ZmI1LCAweDU3MWJlOTFmLFxuICAgICAgMHhmMjk2ZWM2YiwgMHgyYTBkZDkxNSwgMHhiNjYzNjUyMSwgMHhlN2I5ZjliNiwgMHhmZjM0MDUyZSwgMHhjNTg1NTY2NCxcbiAgICAgIDB4NTNiMDJkNWQsIDB4YTk5ZjhmYTEsIDB4MDhiYTQ3OTksIDB4NmU4NTA3NmFcbiAgXSxcbiAgW1xuICAgICAgMHg0YjdhNzBlOSwgMHhiNWIzMjk0NCwgMHhkYjc1MDkyZSwgMHhjNDE5MjYyMywgMHhhZDZlYTZiMCwgMHg0OWE3ZGY3ZCxcbiAgICAgIDB4OWNlZTYwYjgsIDB4OGZlZGIyNjYsIDB4ZWNhYThjNzEsIDB4Njk5YTE3ZmYsIDB4NTY2NDUyNmMsIDB4YzJiMTllZTEsXG4gICAgICAweDE5MzYwMmE1LCAweDc1MDk0YzI5LCAweGEwNTkxMzQwLCAweGU0MTgzYTNlLCAweDNmNTQ5ODlhLCAweDViNDI5ZDY1LFxuICAgICAgMHg2YjhmZTRkNiwgMHg5OWY3M2ZkNiwgMHhhMWQyOWMwNywgMHhlZmU4MzBmNSwgMHg0ZDJkMzhlNiwgMHhmMDI1NWRjMSxcbiAgICAgIDB4NGNkZDIwODYsIDB4ODQ3MGViMjYsIDB4NjM4MmU5YzYsIDB4MDIxZWNjNWUsIDB4MDk2ODZiM2YsIDB4M2ViYWVmYzksXG4gICAgICAweDNjOTcxODE0LCAweDZiNmE3MGExLCAweDY4N2YzNTg0LCAweDUyYTBlMjg2LCAweGI3OWM1MzA1LCAweGFhNTAwNzM3LFxuICAgICAgMHgzZTA3ODQxYywgMHg3ZmRlYWU1YywgMHg4ZTdkNDRlYywgMHg1NzE2ZjJiOCwgMHhiMDNhZGEzNywgMHhmMDUwMGMwZCxcbiAgICAgIDB4ZjAxYzFmMDQsIDB4MDIwMGIzZmYsIDB4YWUwY2Y1MWEsIDB4M2NiNTc0YjIsIDB4MjU4MzdhNTgsIDB4ZGMwOTIxYmQsXG4gICAgICAweGQxOTExM2Y5LCAweDdjYTkyZmY2LCAweDk0MzI0NzczLCAweDIyZjU0NzAxLCAweDNhZTVlNTgxLCAweDM3YzJkYWRjLFxuICAgICAgMHhjOGI1NzYzNCwgMHg5YWYzZGRhNywgMHhhOTQ0NjE0NiwgMHgwZmQwMDMwZSwgMHhlY2M4YzczZSwgMHhhNDc1MWU0MSxcbiAgICAgIDB4ZTIzOGNkOTksIDB4M2JlYTBlMmYsIDB4MzI4MGJiYTEsIDB4MTgzZWIzMzEsIDB4NGU1NDhiMzgsIDB4NGY2ZGI5MDgsXG4gICAgICAweDZmNDIwZDAzLCAweGY2MGEwNGJmLCAweDJjYjgxMjkwLCAweDI0OTc3Yzc5LCAweDU2NzliMDcyLCAweGJjYWY4OWFmLFxuICAgICAgMHhkZTlhNzcxZiwgMHhkOTkzMDgxMCwgMHhiMzhiYWUxMiwgMHhkY2NmM2YyZSwgMHg1NTEyNzIxZiwgMHgyZTZiNzEyNCxcbiAgICAgIDB4NTAxYWRkZTYsIDB4OWY4NGNkODcsIDB4N2E1ODQ3MTgsIDB4NzQwOGRhMTcsIDB4YmM5ZjlhYmMsIDB4ZTk0YjdkOGMsXG4gICAgICAweGVjN2FlYzNhLCAweGRiODUxZGZhLCAweDYzMDk0MzY2LCAweGM0NjRjM2QyLCAweGVmMWMxODQ3LCAweDMyMTVkOTA4LFxuICAgICAgMHhkZDQzM2IzNywgMHgyNGMyYmExNiwgMHgxMmExNGQ0MywgMHgyYTY1YzQ1MSwgMHg1MDk0MDAwMiwgMHgxMzNhZTRkZCxcbiAgICAgIDB4NzFkZmY4OWUsIDB4MTAzMTRlNTUsIDB4ODFhYzc3ZDYsIDB4NWYxMTE5OWIsIDB4MDQzNTU2ZjEsIDB4ZDdhM2M3NmIsXG4gICAgICAweDNjMTExODNiLCAweDU5MjRhNTA5LCAweGYyOGZlNmVkLCAweDk3ZjFmYmZhLCAweDllYmFiZjJjLCAweDFlMTUzYzZlLFxuICAgICAgMHg4NmUzNDU3MCwgMHhlYWU5NmZiMSwgMHg4NjBlNWUwYSwgMHg1YTNlMmFiMywgMHg3NzFmZTcxYywgMHg0ZTNkMDZmYSxcbiAgICAgIDB4Mjk2NWRjYjksIDB4OTllNzFkMGYsIDB4ODAzZTg5ZDYsIDB4NTI2NmM4MjUsIDB4MmU0Y2M5NzgsIDB4OWMxMGIzNmEsXG4gICAgICAweGM2MTUwZWJhLCAweDk0ZTJlYTc4LCAweGE1ZmMzYzUzLCAweDFlMGEyZGY0LCAweGYyZjc0ZWE3LCAweDM2MWQyYjNkLFxuICAgICAgMHgxOTM5MjYwZiwgMHgxOWMyNzk2MCwgMHg1MjIzYTcwOCwgMHhmNzEzMTJiNiwgMHhlYmFkZmU2ZSwgMHhlYWMzMWY2NixcbiAgICAgIDB4ZTNiYzQ1OTUsIDB4YTY3YmM4ODMsIDB4YjE3ZjM3ZDEsIDB4MDE4Y2ZmMjgsIDB4YzMzMmRkZWYsIDB4YmU2YzVhYTUsXG4gICAgICAweDY1NTgyMTg1LCAweDY4YWI5ODAyLCAweGVlY2VhNTBmLCAweGRiMmY5NTNiLCAweDJhZWY3ZGFkLCAweDViNmUyZjg0LFxuICAgICAgMHgxNTIxYjYyOCwgMHgyOTA3NjE3MCwgMHhlY2RkNDc3NSwgMHg2MTlmMTUxMCwgMHgxM2NjYTgzMCwgMHhlYjYxYmQ5NixcbiAgICAgIDB4MDMzNGZlMWUsIDB4YWEwMzYzY2YsIDB4YjU3MzVjOTAsIDB4NGM3MGEyMzksIDB4ZDU5ZTllMGIsIDB4Y2JhYWRlMTQsXG4gICAgICAweGVlY2M4NmJjLCAweDYwNjIyY2E3LCAweDljYWI1Y2FiLCAweGIyZjM4NDZlLCAweDY0OGIxZWFmLCAweDE5YmRmMGNhLFxuICAgICAgMHhhMDIzNjliOSwgMHg2NTVhYmI1MCwgMHg0MDY4NWEzMiwgMHgzYzJhYjRiMywgMHgzMTllZTlkNSwgMHhjMDIxYjhmNyxcbiAgICAgIDB4OWI1NDBiMTksIDB4ODc1ZmEwOTksIDB4OTVmNzk5N2UsIDB4NjIzZDdkYTgsIDB4ZjgzNzg4OWEsIDB4OTdlMzJkNzcsXG4gICAgICAweDExZWQ5MzVmLCAweDE2NjgxMjgxLCAweDBlMzU4ODI5LCAweGM3ZTYxZmQ2LCAweDk2ZGVkZmExLCAweDc4NThiYTk5LFxuICAgICAgMHg1N2Y1ODRhNSwgMHgxYjIyNzI2MywgMHg5YjgzYzNmZiwgMHgxYWMyNDY5NiwgMHhjZGIzMGFlYiwgMHg1MzJlMzA1NCxcbiAgICAgIDB4OGZkOTQ4ZTQsIDB4NmRiYzMxMjgsIDB4NThlYmYyZWYsIDB4MzRjNmZmZWEsIDB4ZmUyOGVkNjEsIDB4ZWU3YzNjNzMsXG4gICAgICAweDVkNGExNGQ5LCAweGU4NjRiN2UzLCAweDQyMTA1ZDE0LCAweDIwM2UxM2UwLCAweDQ1ZWVlMmI2LCAweGEzYWFhYmVhLFxuICAgICAgMHhkYjZjNGYxNSwgMHhmYWNiNGZkMCwgMHhjNzQyZjQ0MiwgMHhlZjZhYmJiNSwgMHg2NTRmM2IxZCwgMHg0MWNkMjEwNSxcbiAgICAgIDB4ZDgxZTc5OWUsIDB4ODY4NTRkYzcsIDB4ZTQ0YjQ3NmEsIDB4M2Q4MTYyNTAsIDB4Y2Y2MmExZjIsIDB4NWI4ZDI2NDYsXG4gICAgICAweGZjODg4M2EwLCAweGMxYzdiNmEzLCAweDdmMTUyNGMzLCAweDY5Y2I3NDkyLCAweDQ3ODQ4YTBiLCAweDU2OTJiMjg1LFxuICAgICAgMHgwOTViYmYwMCwgMHhhZDE5NDg5ZCwgMHgxNDYyYjE3NCwgMHgyMzgyMGUwMCwgMHg1ODQyOGQyYSwgMHgwYzU1ZjVlYSxcbiAgICAgIDB4MWRhZGY0M2UsIDB4MjMzZjcwNjEsIDB4MzM3MmYwOTIsIDB4OGQ5MzdlNDEsIDB4ZDY1ZmVjZjEsIDB4NmMyMjNiZGIsXG4gICAgICAweDdjZGUzNzU5LCAweGNiZWU3NDYwLCAweDQwODVmMmE3LCAweGNlNzczMjZlLCAweGE2MDc4MDg0LCAweDE5Zjg1MDllLFxuICAgICAgMHhlOGVmZDg1NSwgMHg2MWQ5OTczNSwgMHhhOTY5YTdhYSwgMHhjNTBjMDZjMiwgMHg1YTA0YWJmYywgMHg4MDBiY2FkYyxcbiAgICAgIDB4OWU0NDdhMmUsIDB4YzM0NTM0ODQsIDB4ZmRkNTY3MDUsIDB4MGUxZTllYzksIDB4ZGI3M2RiZDMsIDB4MTA1NTg4Y2QsXG4gICAgICAweDY3NWZkYTc5LCAweGUzNjc0MzQwLCAweGM1YzQzNDY1LCAweDcxM2UzOGQ4LCAweDNkMjhmODllLCAweGYxNmRmZjIwLFxuICAgICAgMHgxNTNlMjFlNywgMHg4ZmIwM2Q0YSwgMHhlNmUzOWYyYiwgMHhkYjgzYWRmN1xuICBdLFxuICBbXG4gICAgICAweGU5M2Q1YTY4LCAweDk0ODE0MGY3LCAweGY2NGMyNjFjLCAweDk0NjkyOTM0LCAweDQxMTUyMGY3LCAweDc2MDJkNGY3LFxuICAgICAgMHhiY2Y0NmIyZSwgMHhkNGEyMDA2OCwgMHhkNDA4MjQ3MSwgMHgzMzIwZjQ2YSwgMHg0M2I3ZDRiNywgMHg1MDAwNjFhZixcbiAgICAgIDB4MWUzOWY2MmUsIDB4OTcyNDQ1NDYsIDB4MTQyMTRmNzQsIDB4YmY4Yjg4NDAsIDB4NGQ5NWZjMWQsIDB4OTZiNTkxYWYsXG4gICAgICAweDcwZjRkZGQzLCAweDY2YTAyZjQ1LCAweGJmYmMwOWVjLCAweDAzYmQ5Nzg1LCAweDdmYWM2ZGQwLCAweDMxY2I4NTA0LFxuICAgICAgMHg5NmViMjdiMywgMHg1NWZkMzk0MSwgMHhkYTI1NDdlNiwgMHhhYmNhMGE5YSwgMHgyODUwNzgyNSwgMHg1MzA0MjlmNCxcbiAgICAgIDB4MGEyYzg2ZGEsIDB4ZTliNjZkZmIsIDB4NjhkYzE0NjIsIDB4ZDc0ODY5MDAsIDB4NjgwZWMwYTQsIDB4MjdhMThkZWUsXG4gICAgICAweDRmM2ZmZWEyLCAweGU4ODdhZDhjLCAweGI1OGNlMDA2LCAweDdhZjRkNmI2LCAweGFhY2UxZTdjLCAweGQzMzc1ZmVjLFxuICAgICAgMHhjZTc4YTM5OSwgMHg0MDZiMmE0MiwgMHgyMGZlOWUzNSwgMHhkOWYzODViOSwgMHhlZTM5ZDdhYiwgMHgzYjEyNGU4YixcbiAgICAgIDB4MWRjOWZhZjcsIDB4NGI2ZDE4NTYsIDB4MjZhMzY2MzEsIDB4ZWFlMzk3YjIsIDB4M2E2ZWZhNzQsIDB4ZGQ1YjQzMzIsXG4gICAgICAweDY4NDFlN2Y3LCAweGNhNzgyMGZiLCAweGZiMGFmNTRlLCAweGQ4ZmViMzk3LCAweDQ1NDA1NmFjLCAweGJhNDg5NTI3LFxuICAgICAgMHg1NTUzM2EzYSwgMHgyMDgzOGQ4NywgMHhmZTZiYTliNywgMHhkMDk2OTU0YiwgMHg1NWE4NjdiYywgMHhhMTE1OWE1OCxcbiAgICAgIDB4Y2NhOTI5NjMsIDB4OTllMWRiMzMsIDB4YTYyYTRhNTYsIDB4M2YzMTI1ZjksIDB4NWVmNDdlMWMsIDB4OTAyOTMxN2MsXG4gICAgICAweGZkZjhlODAyLCAweDA0MjcyZjcwLCAweDgwYmIxNTVjLCAweDA1MjgyY2UzLCAweDk1YzExNTQ4LCAweGU0YzY2ZDIyLFxuICAgICAgMHg0OGMxMTMzZiwgMHhjNzBmODZkYywgMHgwN2Y5YzllZSwgMHg0MTA0MWYwZiwgMHg0MDQ3NzlhNCwgMHg1ZDg4NmUxNyxcbiAgICAgIDB4MzI1ZjUxZWIsIDB4ZDU5YmMwZDEsIDB4ZjJiY2MxOGYsIDB4NDExMTM1NjQsIDB4MjU3Yjc4MzQsIDB4NjAyYTljNjAsXG4gICAgICAweGRmZjhlOGEzLCAweDFmNjM2YzFiLCAweDBlMTJiNGMyLCAweDAyZTEzMjllLCAweGFmNjY0ZmQxLCAweGNhZDE4MTE1LFxuICAgICAgMHg2YjIzOTVlMCwgMHgzMzNlOTJlMSwgMHgzYjI0MGI2MiwgMHhlZWJlYjkyMiwgMHg4NWIyYTIwZSwgMHhlNmJhMGQ5OSxcbiAgICAgIDB4ZGU3MjBjOGMsIDB4MmRhMmY3MjgsIDB4ZDAxMjc4NDUsIDB4OTViNzk0ZmQsIDB4NjQ3ZDA4NjIsIDB4ZTdjY2Y1ZjAsXG4gICAgICAweDU0NDlhMzZmLCAweDg3N2Q0OGZhLCAweGMzOWRmZDI3LCAweGYzM2U4ZDFlLCAweDBhNDc2MzQxLCAweDk5MmVmZjc0LFxuICAgICAgMHgzYTZmNmVhYiwgMHhmNGY4ZmQzNywgMHhhODEyZGM2MCwgMHhhMWViZGRmOCwgMHg5OTFiZTE0YywgMHhkYjZlNmIwZCxcbiAgICAgIDB4YzY3YjU1MTAsIDB4NmQ2NzJjMzcsIDB4Mjc2NWQ0M2IsIDB4ZGNkMGU4MDQsIDB4ZjEyOTBkYzcsIDB4Y2MwMGZmYTMsXG4gICAgICAweGI1MzkwZjkyLCAweDY5MGZlZDBiLCAweDY2N2I5ZmZiLCAweGNlZGI3ZDljLCAweGEwOTFjZjBiLCAweGQ5MTU1ZWEzLFxuICAgICAgMHhiYjEzMmY4OCwgMHg1MTViYWQyNCwgMHg3Yjk0NzliZiwgMHg3NjNiZDZlYiwgMHgzNzM5MmViMywgMHhjYzExNTk3OSxcbiAgICAgIDB4ODAyNmUyOTcsIDB4ZjQyZTMxMmQsIDB4Njg0MmFkYTcsIDB4YzY2YTJiM2IsIDB4MTI3NTRjY2MsIDB4NzgyZWYxMWMsXG4gICAgICAweDZhMTI0MjM3LCAweGI3OTI1MWU3LCAweDA2YTFiYmU2LCAweDRiZmI2MzUwLCAweDFhNmIxMDE4LCAweDExY2FlZGZhLFxuICAgICAgMHgzZDI1YmRkOCwgMHhlMmUxYzNjOSwgMHg0NDQyMTY1OSwgMHgwYTEyMTM4NiwgMHhkOTBjZWM2ZSwgMHhkNWFiZWEyYSxcbiAgICAgIDB4NjRhZjY3NGUsIDB4ZGE4NmE4NWYsIDB4YmViZmU5ODgsIDB4NjRlNGMzZmUsIDB4OWRiYzgwNTcsIDB4ZjBmN2MwODYsXG4gICAgICAweDYwNzg3YmY4LCAweDYwMDM2MDRkLCAweGQxZmQ4MzQ2LCAweGY2MzgxZmIwLCAweDc3NDVhZTA0LCAweGQ3MzZmY2NjLFxuICAgICAgMHg4MzQyNmIzMywgMHhmMDFlYWI3MSwgMHhiMDgwNDE4NywgMHgzYzAwNWU1ZiwgMHg3N2EwNTdiZSwgMHhiZGU4YWUyNCxcbiAgICAgIDB4NTU0NjQyOTksIDB4YmY1ODJlNjEsIDB4NGU1OGY0OGYsIDB4ZjJkZGZkYTIsIDB4ZjQ3NGVmMzgsIDB4ODc4OWJkYzIsXG4gICAgICAweDUzNjZmOWMzLCAweGM4YjM4ZTc0LCAweGI0NzVmMjU1LCAweDQ2ZmNkOWI5LCAweDdhZWIyNjYxLCAweDhiMWRkZjg0LFxuICAgICAgMHg4NDZhMGU3OSwgMHg5MTVmOTVlMiwgMHg0NjZlNTk4ZSwgMHgyMGI0NTc3MCwgMHg4Y2Q1NTU5MSwgMHhjOTAyZGU0YyxcbiAgICAgIDB4YjkwYmFjZTEsIDB4YmI4MjA1ZDAsIDB4MTFhODYyNDgsIDB4NzU3NGE5OWUsIDB4Yjc3ZjE5YjYsIDB4ZTBhOWRjMDksXG4gICAgICAweDY2MmQwOWExLCAweGM0MzI0NjMzLCAweGU4NWExZjAyLCAweDA5ZjBiZThjLCAweDRhOTlhMDI1LCAweDFkNmVmZTEwLFxuICAgICAgMHgxYWI5M2QxZCwgMHgwYmE1YTRkZiwgMHhhMTg2ZjIwZiwgMHgyODY4ZjE2OSwgMHhkY2I3ZGE4MywgMHg1NzM5MDZmZSxcbiAgICAgIDB4YTFlMmNlOWIsIDB4NGZjZDdmNTIsIDB4NTAxMTVlMDEsIDB4YTcwNjgzZmEsIDB4YTAwMmI1YzQsIDB4MGRlNmQwMjcsXG4gICAgICAweDlhZjg4YzI3LCAweDc3M2Y4NjQxLCAweGMzNjA0YzA2LCAweDYxYTgwNmI1LCAweGYwMTc3YTI4LCAweGMwZjU4NmUwLFxuICAgICAgMHgwMDYwNThhYSwgMHgzMGRjN2Q2MiwgMHgxMWU2OWVkNywgMHgyMzM4ZWE2MywgMHg1M2MyZGQ5NCwgMHhjMmMyMTYzNCxcbiAgICAgIDB4YmJjYmVlNTYsIDB4OTBiY2I2ZGUsIDB4ZWJmYzdkYTEsIDB4Y2U1OTFkNzYsIDB4NmYwNWU0MDksIDB4NGI3YzAxODgsXG4gICAgICAweDM5NzIwYTNkLCAweDdjOTI3YzI0LCAweDg2ZTM3MjVmLCAweDcyNGQ5ZGI5LCAweDFhYzE1YmI0LCAweGQzOWViOGZjLFxuICAgICAgMHhlZDU0NTU3OCwgMHgwOGZjYTViNSwgMHhkODNkN2NkMywgMHg0ZGFkMGZjNCwgMHgxZTUwZWY1ZSwgMHhiMTYxZTZmOCxcbiAgICAgIDB4YTI4NTE0ZDksIDB4NmM1MTEzM2MsIDB4NmZkNWM3ZTcsIDB4NTZlMTRlYzQsIDB4MzYyYWJmY2UsIDB4ZGRjNmM4MzcsXG4gICAgICAweGQ3OWEzMjM0LCAweDkyNjM4MjEyLCAweDY3MGVmYThlLCAweDQwNjAwMGUwXG4gIF0sXG4gIFtcbiAgICAgIDB4M2EzOWNlMzcsIDB4ZDNmYWY1Y2YsIDB4YWJjMjc3MzcsIDB4NWFjNTJkMWIsIDB4NWNiMDY3OWUsIDB4NGZhMzM3NDIsXG4gICAgICAweGQzODIyNzQwLCAweDk5YmM5YmJlLCAweGQ1MTE4ZTlkLCAweGJmMGY3MzE1LCAweGQ2MmQxYzdlLCAweGM3MDBjNDdiLFxuICAgICAgMHhiNzhjMWI2YiwgMHgyMWExOTA0NSwgMHhiMjZlYjFiZSwgMHg2YTM2NmViNCwgMHg1NzQ4YWIyZiwgMHhiYzk0NmU3OSxcbiAgICAgIDB4YzZhMzc2ZDIsIDB4NjU0OWMyYzgsIDB4NTMwZmY4ZWUsIDB4NDY4ZGRlN2QsIDB4ZDU3MzBhMWQsIDB4NGNkMDRkYzYsXG4gICAgICAweDI5MzliYmRiLCAweGE5YmE0NjUwLCAweGFjOTUyNmU4LCAweGJlNWVlMzA0LCAweGExZmFkNWYwLCAweDZhMmQ1MTlhLFxuICAgICAgMHg2M2VmOGNlMiwgMHg5YTg2ZWUyMiwgMHhjMDg5YzJiOCwgMHg0MzI0MmVmNiwgMHhhNTFlMDNhYSwgMHg5Y2YyZDBhNCxcbiAgICAgIDB4ODNjMDYxYmEsIDB4OWJlOTZhNGQsIDB4OGZlNTE1NTAsIDB4YmE2NDViZDYsIDB4MjgyNmEyZjksIDB4YTczYTNhZTEsXG4gICAgICAweDRiYTk5NTg2LCAweGVmNTU2MmU5LCAweGM3MmZlZmQzLCAweGY3NTJmN2RhLCAweDNmMDQ2ZjY5LCAweDc3ZmEwYTU5LFxuICAgICAgMHg4MGU0YTkxNSwgMHg4N2IwODYwMSwgMHg5YjA5ZTZhZCwgMHgzYjNlZTU5MywgMHhlOTkwZmQ1YSwgMHg5ZTM0ZDc5NyxcbiAgICAgIDB4MmNmMGI3ZDksIDB4MDIyYjhiNTEsIDB4OTZkNWFjM2EsIDB4MDE3ZGE2N2QsIDB4ZDFjZjNlZDYsIDB4N2M3ZDJkMjgsXG4gICAgICAweDFmOWYyNWNmLCAweGFkZjJiODliLCAweDVhZDZiNDcyLCAweDVhODhmNTRjLCAweGUwMjlhYzcxLCAweGUwMTlhNWU2LFxuICAgICAgMHg0N2IwYWNmZCwgMHhlZDkzZmE5YiwgMHhlOGQzYzQ4ZCwgMHgyODNiNTdjYywgMHhmOGQ1NjYyOSwgMHg3OTEzMmUyOCxcbiAgICAgIDB4Nzg1ZjAxOTEsIDB4ZWQ3NTYwNTUsIDB4Zjc5NjBlNDQsIDB4ZTNkMzVlOGMsIDB4MTUwNTZkZDQsIDB4ODhmNDZkYmEsXG4gICAgICAweDAzYTE2MTI1LCAweDA1NjRmMGJkLCAweGMzZWI5ZTE1LCAweDNjOTA1N2EyLCAweDk3MjcxYWVjLCAweGE5M2EwNzJhLFxuICAgICAgMHgxYjNmNmQ5YiwgMHgxZTYzMjFmNSwgMHhmNTljNjZmYiwgMHgyNmRjZjMxOSwgMHg3NTMzZDkyOCwgMHhiMTU1ZmRmNSxcbiAgICAgIDB4MDM1NjM0ODIsIDB4OGFiYTNjYmIsIDB4Mjg1MTc3MTEsIDB4YzIwYWQ5ZjgsIDB4YWJjYzUxNjcsIDB4Y2NhZDkyNWYsXG4gICAgICAweDRkZTgxNzUxLCAweDM4MzBkYzhlLCAweDM3OWQ1ODYyLCAweDkzMjBmOTkxLCAweGVhN2E5MGMyLCAweGZiM2U3YmNlLFxuICAgICAgMHg1MTIxY2U2NCwgMHg3NzRmYmUzMiwgMHhhOGI2ZTM3ZSwgMHhjMzI5M2Q0NiwgMHg0OGRlNTM2OSwgMHg2NDEzZTY4MCxcbiAgICAgIDB4YTJhZTA4MTAsIDB4ZGQ2ZGIyMjQsIDB4Njk4NTJkZmQsIDB4MDkwNzIxNjYsIDB4YjM5YTQ2MGEsIDB4NjQ0NWMwZGQsXG4gICAgICAweDU4NmNkZWNmLCAweDFjMjBjOGFlLCAweDViYmVmN2RkLCAweDFiNTg4ZDQwLCAweGNjZDIwMTdmLCAweDZiYjRlM2JiLFxuICAgICAgMHhkZGEyNmE3ZSwgMHgzYTU5ZmY0NSwgMHgzZTM1MGE0NCwgMHhiY2I0Y2RkNSwgMHg3MmVhY2VhOCwgMHhmYTY0ODRiYixcbiAgICAgIDB4OGQ2NjEyYWUsIDB4YmYzYzZmNDcsIDB4ZDI5YmU0NjMsIDB4NTQyZjVkOWUsIDB4YWVjMjc3MWIsIDB4ZjY0ZTYzNzAsXG4gICAgICAweDc0MGUwZDhkLCAweGU3NWIxMzU3LCAweGY4NzIxNjcxLCAweGFmNTM3ZDVkLCAweDQwNDBjYjA4LCAweDRlYjRlMmNjLFxuICAgICAgMHgzNGQyNDY2YSwgMHgwMTE1YWY4NCwgMHhlMWIwMDQyOCwgMHg5NTk4M2ExZCwgMHgwNmI4OWZiNCwgMHhjZTZlYTA0OCxcbiAgICAgIDB4NmYzZjNiODIsIDB4MzUyMGFiODIsIDB4MDExYTFkNGIsIDB4Mjc3MjI3ZjgsIDB4NjExNTYwYjEsIDB4ZTc5MzNmZGMsXG4gICAgICAweGJiM2E3OTJiLCAweDM0NDUyNWJkLCAweGEwODgzOWUxLCAweDUxY2U3OTRiLCAweDJmMzJjOWI3LCAweGEwMWZiYWM5LFxuICAgICAgMHhlMDFjYzg3ZSwgMHhiY2M3ZDFmNiwgMHhjZjAxMTFjMywgMHhhMWU4YWFjNywgMHgxYTkwODc0OSwgMHhkNDRmYmQ5YSxcbiAgICAgIDB4ZDBkYWRlY2IsIDB4ZDUwYWRhMzgsIDB4MDMzOWMzMmEsIDB4YzY5MTM2NjcsIDB4OGRmOTMxN2MsIDB4ZTBiMTJiNGYsXG4gICAgICAweGY3OWU1OWI3LCAweDQzZjViYjNhLCAweGYyZDUxOWZmLCAweDI3ZDk0NTljLCAweGJmOTcyMjJjLCAweDE1ZTZmYzJhLFxuICAgICAgMHgwZjkxZmM3MSwgMHg5Yjk0MTUyNSwgMHhmYWU1OTM2MSwgMHhjZWI2OWNlYiwgMHhjMmE4NjQ1OSwgMHgxMmJhYThkMSxcbiAgICAgIDB4YjZjMTA3NWUsIDB4ZTMwNTZhMGMsIDB4MTBkMjUwNjUsIDB4Y2IwM2E0NDIsIDB4ZTBlYzZlMGUsIDB4MTY5OGRiM2IsXG4gICAgICAweDRjOThhMGJlLCAweDMyNzhlOTY0LCAweDlmMWY5NTMyLCAweGUwZDM5MmRmLCAweGQzYTAzNDJiLCAweDg5NzFmMjFlLFxuICAgICAgMHgxYjBhNzQ0MSwgMHg0YmEzMzQ4YywgMHhjNWJlNzEyMCwgMHhjMzc2MzJkOCwgMHhkZjM1OWY4ZCwgMHg5Yjk5MmYyZSxcbiAgICAgIDB4ZTYwYjZmNDcsIDB4MGZlM2YxMWQsIDB4ZTU0Y2RhNTQsIDB4MWVkYWQ4OTEsIDB4Y2U2Mjc5Y2YsIDB4Y2QzZTdlNmYsXG4gICAgICAweDE2MThiMTY2LCAweGZkMmMxZDA1LCAweDg0OGZkMmM1LCAweGY2ZmIyMjk5LCAweGY1MjNmMzU3LCAweGE2MzI3NjIzLFxuICAgICAgMHg5M2E4MzUzMSwgMHg1NmNjY2QwMiwgMHhhY2YwODE2MiwgMHg1YTc1ZWJiNSwgMHg2ZTE2MzY5NywgMHg4OGQyNzNjYyxcbiAgICAgIDB4ZGU5NjYyOTIsIDB4ODFiOTQ5ZDAsIDB4NGM1MDkwMWIsIDB4NzFjNjU2MTQsIDB4ZTZjNmM3YmQsIDB4MzI3YTE0MGEsXG4gICAgICAweDQ1ZTFkMDA2LCAweGMzZjI3YjlhLCAweGM5YWE1M2ZkLCAweDYyYTgwZjAwLCAweGJiMjViZmUyLCAweDM1YmRkMmY2LFxuICAgICAgMHg3MTEyNjkwNSwgMHhiMjA0MDIyMiwgMHhiNmNiY2Y3YywgMHhjZDc2OWMyYiwgMHg1MzExM2VjMCwgMHgxNjQwZTNkMyxcbiAgICAgIDB4MzhhYmJkNjAsIDB4MjU0N2FkZjAsIDB4YmEzODIwOWMsIDB4Zjc0NmNlNzYsIDB4NzdhZmExYzUsIDB4MjA3NTYwNjAsXG4gICAgICAweDg1Y2JmZTRlLCAweDhhZTg4ZGQ4LCAweDdhYWFmOWIwLCAweDRjZjlhYTdlLCAweDE5NDhjMjVjLCAweDAyZmI4YThjLFxuICAgICAgMHgwMWMzNmFlNCwgMHhkNmViZTFmOSwgMHg5MGQ0Zjg2OSwgMHhhNjVjZGVhMCwgMHgzZjA5MjUyZCwgMHhjMjA4ZTY5ZixcbiAgICAgIDB4Yjc0ZTYxMzIsIDB4Y2U3N2UyNWIsIDB4NTc4ZmRmZTMsIDB4M2FjMzcyZTZcbiAgXVxuXTtcblxuLy8qXG4vLyogVGhpcyBpcyB0aGUgZGVmYXVsdCBQQVJSQVlcbi8vKlxuQmxvd2Zpc2gucHJvdG90eXBlLlBBUlJBWSA9IFtcbiAgICAweDI0M2Y2YTg4LCAweDg1YTMwOGQzLCAweDEzMTk4YTJlLCAweDAzNzA3MzQ0LCAweGE0MDkzODIyLCAweDI5OWYzMWQwLFxuICAgIDB4MDgyZWZhOTgsIDB4ZWM0ZTZjODksIDB4NDUyODIxZTYsIDB4MzhkMDEzNzcsIDB4YmU1NDY2Y2YsIDB4MzRlOTBjNmMsXG4gICAgMHhjMGFjMjliNywgMHhjOTdjNTBkZCwgMHgzZjg0ZDViNSwgMHhiNTQ3MDkxNywgMHg5MjE2ZDVkOSwgMHg4OTc5ZmIxYlxuXTtcblxuLy8qXG4vLyogVGhpcyBpcyB0aGUgbnVtYmVyIG9mIHJvdW5kcyB0aGUgY2lwaGVyIHdpbGwgZ29cbi8vKlxuQmxvd2Zpc2gucHJvdG90eXBlLk5OID0gMTY7XG5cbi8vKlxuLy8qIFRoaXMgZnVuY3Rpb24gaXMgbmVlZGVkIHRvIGdldCByaWQgb2YgcHJvYmxlbXNcbi8vKiB3aXRoIHRoZSBoaWdoLWJpdCBnZXR0aW5nIHNldC4gIElmIHdlIGRvbid0IGRvXG4vLyogdGhpcywgdGhlbiBzb21ldGltZXMgKCBhYSAmIDB4MDBGRkZGRkZGRiApIGlzIG5vdFxuLy8qIGVxdWFsIHRvICggYmIgJiAweDAwRkZGRkZGRkYgKSBldmVuIHdoZW4gdGhleVxuLy8qIGFncmVlIGJpdC1mb3ItYml0IGZvciB0aGUgZmlyc3QgMzIgYml0cy5cbi8vKlxuQmxvd2Zpc2gucHJvdG90eXBlLl9jbGVhbiA9IGZ1bmN0aW9uKHh4KSB7XG4gIGlmICh4eCA8IDApIHtcbiAgICB2YXIgeXkgPSB4eCAmIDB4N0ZGRkZGRkY7XG4gICAgeHggPSB5eSArIDB4ODAwMDAwMDA7XG4gIH1cbiAgcmV0dXJuIHh4O1xufTtcblxuLy8qXG4vLyogVGhpcyBpcyB0aGUgbWl4aW5nIGZ1bmN0aW9uIHRoYXQgdXNlcyB0aGUgc2JveGVzXG4vLypcbkJsb3dmaXNoLnByb3RvdHlwZS5fRiA9IGZ1bmN0aW9uKHh4KSB7XG4gIHZhciBhYTtcbiAgdmFyIGJiO1xuICB2YXIgY2M7XG4gIHZhciBkZDtcbiAgdmFyIHl5O1xuXG4gIGRkID0geHggJiAweDAwRkY7XG4gIHh4ID4+Pj0gODtcbiAgY2MgPSB4eCAmIDB4MDBGRjtcbiAgeHggPj4+PSA4O1xuICBiYiA9IHh4ICYgMHgwMEZGO1xuICB4eCA+Pj49IDg7XG4gIGFhID0geHggJiAweDAwRkY7XG5cbiAgeXkgPSB0aGlzLnNib3hlc1swXVthYV0gKyB0aGlzLnNib3hlc1sxXVtiYl07XG4gIHl5ID0geXkgXiB0aGlzLnNib3hlc1syXVtjY107XG4gIHl5ID0geXkgKyB0aGlzLnNib3hlc1szXVtkZF07XG5cbiAgcmV0dXJuIHl5O1xufTtcblxuLy8qXG4vLyogVGhpcyBtZXRob2QgdGFrZXMgYW4gYXJyYXkgd2l0aCB0d28gdmFsdWVzLCBsZWZ0IGFuZCByaWdodFxuLy8qIGFuZCBkb2VzIE5OIHJvdW5kcyBvZiBCbG93ZmlzaCBvbiB0aGVtLlxuLy8qXG5CbG93ZmlzaC5wcm90b3R5cGUuX2VuY3J5cHRfYmxvY2sgPSBmdW5jdGlvbih2YWxzKSB7XG4gIHZhciBkYXRhTCA9IHZhbHNbMF07XG4gIHZhciBkYXRhUiA9IHZhbHNbMV07XG5cbiAgdmFyIGlpO1xuXG4gIGZvciAoaWkgPSAwOyBpaSA8IHRoaXMuTk47ICsraWkpIHtcbiAgICBkYXRhTCA9IGRhdGFMIF4gdGhpcy5wYXJyYXlbaWldO1xuICAgIGRhdGFSID0gdGhpcy5fRihkYXRhTCkgXiBkYXRhUjtcblxuICAgIHZhciB0bXAgPSBkYXRhTDtcbiAgICBkYXRhTCA9IGRhdGFSO1xuICAgIGRhdGFSID0gdG1wO1xuICB9XG5cbiAgZGF0YUwgPSBkYXRhTCBeIHRoaXMucGFycmF5W3RoaXMuTk4gKyAwXTtcbiAgZGF0YVIgPSBkYXRhUiBeIHRoaXMucGFycmF5W3RoaXMuTk4gKyAxXTtcblxuICB2YWxzWzBdID0gdGhpcy5fY2xlYW4oZGF0YVIpO1xuICB2YWxzWzFdID0gdGhpcy5fY2xlYW4oZGF0YUwpO1xufTtcblxuLy8qXG4vLyogVGhpcyBtZXRob2QgdGFrZXMgYSB2ZWN0b3Igb2YgbnVtYmVycyBhbmQgdHVybnMgdGhlbVxuLy8qIGludG8gbG9uZyB3b3JkcyBzbyB0aGF0IHRoZXkgY2FuIGJlIHByb2Nlc3NlZCBieSB0aGVcbi8vKiByZWFsIGFsZ29yaXRobS5cbi8vKlxuLy8qIE1heWJlIEkgc2hvdWxkIG1ha2UgdGhlIHJlYWwgYWxnb3JpdGhtIGFib3ZlIHRha2UgYSB2ZWN0b3Jcbi8vKiBpbnN0ZWFkLiAgVGhhdCB3aWxsIGludm9sdmUgbW9yZSBsb29waW5nLCBidXQgaXQgd29uJ3QgcmVxdWlyZVxuLy8qIHRoZSBGKCkgbWV0aG9kIHRvIGRlY29uc3RydWN0IHRoZSB2ZWN0b3IuXG4vLypcbkJsb3dmaXNoLnByb3RvdHlwZS5lbmNyeXB0X2Jsb2NrID0gZnVuY3Rpb24odmVjdG9yKSB7XG4gIHZhciBpaTtcbiAgdmFyIHZhbHMgPSBbMCwgMF07XG4gIHZhciBvZmYgPSB0aGlzLkJMT0NLU0laRSAvIDI7XG4gIGZvciAoaWkgPSAwOyBpaSA8IHRoaXMuQkxPQ0tTSVpFIC8gMjsgKytpaSkge1xuICAgIHZhbHNbMF0gPSAodmFsc1swXSA8PCA4KSB8ICh2ZWN0b3JbaWkgKyAwXSAmIDB4MDBGRik7XG4gICAgdmFsc1sxXSA9ICh2YWxzWzFdIDw8IDgpIHwgKHZlY3RvcltpaSArIG9mZl0gJiAweDAwRkYpO1xuICB9XG5cbiAgdGhpcy5fZW5jcnlwdF9ibG9jayh2YWxzKTtcblxuICB2YXIgcmV0ID0gW107XG4gIGZvciAoaWkgPSAwOyBpaSA8IHRoaXMuQkxPQ0tTSVpFIC8gMjsgKytpaSkge1xuICAgIHJldFtpaSArIDBdID0gKHZhbHNbMF0gPj4+ICgyNCAtIDggKiAoaWkpKSAmIDB4MDBGRik7XG4gICAgcmV0W2lpICsgb2ZmXSA9ICh2YWxzWzFdID4+PiAoMjQgLSA4ICogKGlpKSkgJiAweDAwRkYpO1xuICAgIC8vIHZhbHNbIDAgXSA9ICggdmFsc1sgMCBdID4+PiA4ICk7XG4gICAgLy8gdmFsc1sgMSBdID0gKCB2YWxzWyAxIF0gPj4+IDggKTtcbiAgfVxuXG4gIHJldHVybiByZXQ7XG59O1xuXG4vLypcbi8vKiBUaGlzIG1ldGhvZCB0YWtlcyBhbiBhcnJheSB3aXRoIHR3byB2YWx1ZXMsIGxlZnQgYW5kIHJpZ2h0XG4vLyogYW5kIHVuZG9lcyBOTiByb3VuZHMgb2YgQmxvd2Zpc2ggb24gdGhlbS5cbi8vKlxuQmxvd2Zpc2gucHJvdG90eXBlLl9kZWNyeXB0X2Jsb2NrID0gZnVuY3Rpb24odmFscykge1xuICB2YXIgZGF0YUwgPSB2YWxzWzBdO1xuICB2YXIgZGF0YVIgPSB2YWxzWzFdO1xuXG4gIHZhciBpaTtcblxuICBmb3IgKGlpID0gdGhpcy5OTiArIDE7IGlpID4gMTsgLS1paSkge1xuICAgIGRhdGFMID0gZGF0YUwgXiB0aGlzLnBhcnJheVtpaV07XG4gICAgZGF0YVIgPSB0aGlzLl9GKGRhdGFMKSBeIGRhdGFSO1xuXG4gICAgdmFyIHRtcCA9IGRhdGFMO1xuICAgIGRhdGFMID0gZGF0YVI7XG4gICAgZGF0YVIgPSB0bXA7XG4gIH1cblxuICBkYXRhTCA9IGRhdGFMIF4gdGhpcy5wYXJyYXlbMV07XG4gIGRhdGFSID0gZGF0YVIgXiB0aGlzLnBhcnJheVswXTtcblxuICB2YWxzWzBdID0gdGhpcy5fY2xlYW4oZGF0YVIpO1xuICB2YWxzWzFdID0gdGhpcy5fY2xlYW4oZGF0YUwpO1xufTtcblxuLy8qXG4vLyogVGhpcyBtZXRob2QgdGFrZXMgYSBrZXkgYXJyYXkgYW5kIGluaXRpYWxpemVzIHRoZVxuLy8qIHNib3hlcyBhbmQgcGFycmF5IGZvciB0aGlzIGVuY3J5cHRpb24uXG4vLypcbkJsb3dmaXNoLnByb3RvdHlwZS5pbml0ID0gZnVuY3Rpb24oa2V5KSB7XG4gIHZhciBpaTtcbiAgdmFyIGpqID0gMDtcblxuICB0aGlzLnBhcnJheSA9IFtdO1xuICBmb3IgKGlpID0gMDsgaWkgPCB0aGlzLk5OICsgMjsgKytpaSkge1xuICAgIHZhciBkYXRhID0gMHgwMDAwMDAwMDtcbiAgICB2YXIga2s7XG4gICAgZm9yIChrayA9IDA7IGtrIDwgNDsgKytraykge1xuICAgICAgZGF0YSA9IChkYXRhIDw8IDgpIHwgKGtleVtqal0gJiAweDAwRkYpO1xuICAgICAgaWYgKCsramogPj0ga2V5Lmxlbmd0aCkge1xuICAgICAgICBqaiA9IDA7XG4gICAgICB9XG4gICAgfVxuICAgIHRoaXMucGFycmF5W2lpXSA9IHRoaXMuUEFSUkFZW2lpXSBeIGRhdGE7XG4gIH1cblxuICB0aGlzLnNib3hlcyA9IFtdO1xuICBmb3IgKGlpID0gMDsgaWkgPCA0OyArK2lpKSB7XG4gICAgdGhpcy5zYm94ZXNbaWldID0gW107XG4gICAgZm9yIChqaiA9IDA7IGpqIDwgMjU2OyArK2pqKSB7XG4gICAgICB0aGlzLnNib3hlc1tpaV1bampdID0gdGhpcy5TQk9YRVNbaWldW2pqXTtcbiAgICB9XG4gIH1cblxuICB2YXIgdmFscyA9IFsweDAwMDAwMDAwLCAweDAwMDAwMDAwXTtcblxuICBmb3IgKGlpID0gMDsgaWkgPCB0aGlzLk5OICsgMjsgaWkgKz0gMikge1xuICAgIHRoaXMuX2VuY3J5cHRfYmxvY2sodmFscyk7XG4gICAgdGhpcy5wYXJyYXlbaWkgKyAwXSA9IHZhbHNbMF07XG4gICAgdGhpcy5wYXJyYXlbaWkgKyAxXSA9IHZhbHNbMV07XG4gIH1cblxuICBmb3IgKGlpID0gMDsgaWkgPCA0OyArK2lpKSB7XG4gICAgZm9yIChqaiA9IDA7IGpqIDwgMjU2OyBqaiArPSAyKSB7XG4gICAgICB0aGlzLl9lbmNyeXB0X2Jsb2NrKHZhbHMpO1xuICAgICAgdGhpcy5zYm94ZXNbaWldW2pqICsgMF0gPSB2YWxzWzBdO1xuICAgICAgdGhpcy5zYm94ZXNbaWldW2pqICsgMV0gPSB2YWxzWzFdO1xuICAgIH1cbiAgfVxufTtcblxudmFyIHV0aWwgPSByZXF1aXJlKCcuLi8uLi91dGlsJyk7XG5cbi8vIGFkZGVkIGJ5IFJlY3VyaXR5IExhYnNcblxuZnVuY3Rpb24gQkZlbmNyeXB0KGJsb2NrLCBrZXkpIHtcbiAgdmFyIGJmID0gbmV3IEJsb3dmaXNoKCk7XG4gIGJmLmluaXQodXRpbC5zdHIyYmluKGtleSkpO1xuICByZXR1cm4gYmYuZW5jcnlwdF9ibG9jayhibG9jayk7XG59XG5cbmZ1bmN0aW9uIEJGKGtleSkge1xuICB0aGlzLmJmID0gbmV3IEJsb3dmaXNoKCk7XG4gIHRoaXMuYmYuaW5pdCh1dGlsLnN0cjJiaW4oa2V5KSk7XG5cbiAgdGhpcy5lbmNyeXB0ID0gZnVuY3Rpb24oYmxvY2spIHtcbiAgICByZXR1cm4gdGhpcy5iZi5lbmNyeXB0X2Jsb2NrKGJsb2NrKTtcbiAgfVxufVxuXG5cbm1vZHVsZS5leHBvcnRzID0gQkY7XG5tb2R1bGUuZXhwb3J0cy5rZXlTaXplID0gQkYucHJvdG90eXBlLmtleVNpemUgPSAxNjtcbm1vZHVsZS5leHBvcnRzLmJsb2NrU2l6ZSA9IEJGLnByb3RvdHlwZS5ibG9ja1NpemUgPSAxNjtcbiIsIi8vIFVzZSBvZiB0aGlzIHNvdXJjZSBjb2RlIGlzIGdvdmVybmVkIGJ5IGEgQlNELXN0eWxlXG4vLyBsaWNlbnNlIHRoYXQgY2FuIGJlIGZvdW5kIGluIHRoZSBMSUNFTlNFIGZpbGUuXG5cbi8vIENvcHlyaWdodCAyMDEwIHBqYWNvYnNAeGVla3IuY29tIC4gQWxsIHJpZ2h0cyByZXNlcnZlZC5cblxuLy8gTW9kaWZpZWQgYnkgUmVjdXJpdHkgTGFicyBHbWJIXG5cbi8vIGZpeGVkL21vZGlmaWVkIGJ5IEhlcmJlcnQgSGFuZXdpbmtlbCwgd3d3LmhhbmVXSU4uZGVcbi8vIGNoZWNrIHd3dy5oYW5lV0lOLmRlIGZvciB0aGUgbGF0ZXN0IHZlcnNpb25cblxuLy8gY2FzdDUuanMgaXMgYSBKYXZhc2NyaXB0IGltcGxlbWVudGF0aW9uIG9mIENBU1QtMTI4LCBhcyBkZWZpbmVkIGluIFJGQyAyMTQ0LlxuLy8gQ0FTVC0xMjggaXMgYSBjb21tb24gT3BlblBHUCBjaXBoZXIuXG5cblxuLy8gQ0FTVDUgY29uc3RydWN0b3JcblxuXG5cbmZ1bmN0aW9uIG9wZW5wZ3Bfc3ltZW5jX2Nhc3Q1KCkge1xuICB0aGlzLkJsb2NrU2l6ZSA9IDg7XG4gIHRoaXMuS2V5U2l6ZSA9IDE2O1xuXG4gIHRoaXMuc2V0S2V5ID0gZnVuY3Rpb24oa2V5KSB7XG4gICAgdGhpcy5tYXNraW5nID0gbmV3IEFycmF5KDE2KTtcbiAgICB0aGlzLnJvdGF0ZSA9IG5ldyBBcnJheSgxNik7XG5cbiAgICB0aGlzLnJlc2V0KCk7XG5cbiAgICBpZiAoa2V5Lmxlbmd0aCA9PSB0aGlzLktleVNpemUpIHtcbiAgICAgIHRoaXMua2V5U2NoZWR1bGUoa2V5KTtcbiAgICB9IGVsc2Uge1xuICAgICAgdXRpbC5wcmludF9lcnJvcignY2FzdDUuanM6IENBU1QtMTI4OiBrZXlzIG11c3QgYmUgMTYgYnl0ZXMnKTtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgcmV0dXJuIHRydWU7XG4gIH07XG5cbiAgdGhpcy5yZXNldCA9IGZ1bmN0aW9uKCkge1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgMTY7IGkrKykge1xuICAgICAgdGhpcy5tYXNraW5nW2ldID0gMDtcbiAgICAgIHRoaXMucm90YXRlW2ldID0gMDtcbiAgICB9XG4gIH07XG5cbiAgdGhpcy5nZXRCbG9ja1NpemUgPSBmdW5jdGlvbigpIHtcbiAgICByZXR1cm4gQmxvY2tTaXplO1xuICB9O1xuXG4gIHRoaXMuZW5jcnlwdCA9IGZ1bmN0aW9uKHNyYykge1xuICAgIHZhciBkc3QgPSBuZXcgQXJyYXkoc3JjLmxlbmd0aCk7XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHNyYy5sZW5ndGg7IGkgKz0gOCkge1xuICAgICAgdmFyIGwgPSBzcmNbaV0gPDwgMjQgfCBzcmNbaSArIDFdIDw8IDE2IHwgc3JjW2kgKyAyXSA8PCA4IHwgc3JjW2kgKyAzXTtcbiAgICAgIHZhciByID0gc3JjW2kgKyA0XSA8PCAyNCB8IHNyY1tpICsgNV0gPDwgMTYgfCBzcmNbaSArIDZdIDw8IDggfCBzcmNbaSArIDddO1xuICAgICAgdmFyIHQ7XG5cbiAgICAgIHQgPSByO1xuICAgICAgciA9IGwgXiBmMShyLCB0aGlzLm1hc2tpbmdbMF0sIHRoaXMucm90YXRlWzBdKTtcbiAgICAgIGwgPSB0O1xuICAgICAgdCA9IHI7XG4gICAgICByID0gbCBeIGYyKHIsIHRoaXMubWFza2luZ1sxXSwgdGhpcy5yb3RhdGVbMV0pO1xuICAgICAgbCA9IHQ7XG4gICAgICB0ID0gcjtcbiAgICAgIHIgPSBsIF4gZjMociwgdGhpcy5tYXNraW5nWzJdLCB0aGlzLnJvdGF0ZVsyXSk7XG4gICAgICBsID0gdDtcbiAgICAgIHQgPSByO1xuICAgICAgciA9IGwgXiBmMShyLCB0aGlzLm1hc2tpbmdbM10sIHRoaXMucm90YXRlWzNdKTtcbiAgICAgIGwgPSB0O1xuXG4gICAgICB0ID0gcjtcbiAgICAgIHIgPSBsIF4gZjIociwgdGhpcy5tYXNraW5nWzRdLCB0aGlzLnJvdGF0ZVs0XSk7XG4gICAgICBsID0gdDtcbiAgICAgIHQgPSByO1xuICAgICAgciA9IGwgXiBmMyhyLCB0aGlzLm1hc2tpbmdbNV0sIHRoaXMucm90YXRlWzVdKTtcbiAgICAgIGwgPSB0O1xuICAgICAgdCA9IHI7XG4gICAgICByID0gbCBeIGYxKHIsIHRoaXMubWFza2luZ1s2XSwgdGhpcy5yb3RhdGVbNl0pO1xuICAgICAgbCA9IHQ7XG4gICAgICB0ID0gcjtcbiAgICAgIHIgPSBsIF4gZjIociwgdGhpcy5tYXNraW5nWzddLCB0aGlzLnJvdGF0ZVs3XSk7XG4gICAgICBsID0gdDtcblxuICAgICAgdCA9IHI7XG4gICAgICByID0gbCBeIGYzKHIsIHRoaXMubWFza2luZ1s4XSwgdGhpcy5yb3RhdGVbOF0pO1xuICAgICAgbCA9IHQ7XG4gICAgICB0ID0gcjtcbiAgICAgIHIgPSBsIF4gZjEociwgdGhpcy5tYXNraW5nWzldLCB0aGlzLnJvdGF0ZVs5XSk7XG4gICAgICBsID0gdDtcbiAgICAgIHQgPSByO1xuICAgICAgciA9IGwgXiBmMihyLCB0aGlzLm1hc2tpbmdbMTBdLCB0aGlzLnJvdGF0ZVsxMF0pO1xuICAgICAgbCA9IHQ7XG4gICAgICB0ID0gcjtcbiAgICAgIHIgPSBsIF4gZjMociwgdGhpcy5tYXNraW5nWzExXSwgdGhpcy5yb3RhdGVbMTFdKTtcbiAgICAgIGwgPSB0O1xuXG4gICAgICB0ID0gcjtcbiAgICAgIHIgPSBsIF4gZjEociwgdGhpcy5tYXNraW5nWzEyXSwgdGhpcy5yb3RhdGVbMTJdKTtcbiAgICAgIGwgPSB0O1xuICAgICAgdCA9IHI7XG4gICAgICByID0gbCBeIGYyKHIsIHRoaXMubWFza2luZ1sxM10sIHRoaXMucm90YXRlWzEzXSk7XG4gICAgICBsID0gdDtcbiAgICAgIHQgPSByO1xuICAgICAgciA9IGwgXiBmMyhyLCB0aGlzLm1hc2tpbmdbMTRdLCB0aGlzLnJvdGF0ZVsxNF0pO1xuICAgICAgbCA9IHQ7XG4gICAgICB0ID0gcjtcbiAgICAgIHIgPSBsIF4gZjEociwgdGhpcy5tYXNraW5nWzE1XSwgdGhpcy5yb3RhdGVbMTVdKTtcbiAgICAgIGwgPSB0O1xuXG4gICAgICBkc3RbaV0gPSAociA+Pj4gMjQpICYgMjU1O1xuICAgICAgZHN0W2kgKyAxXSA9IChyID4+PiAxNikgJiAyNTU7XG4gICAgICBkc3RbaSArIDJdID0gKHIgPj4+IDgpICYgMjU1O1xuICAgICAgZHN0W2kgKyAzXSA9IHIgJiAyNTU7XG4gICAgICBkc3RbaSArIDRdID0gKGwgPj4+IDI0KSAmIDI1NTtcbiAgICAgIGRzdFtpICsgNV0gPSAobCA+Pj4gMTYpICYgMjU1O1xuICAgICAgZHN0W2kgKyA2XSA9IChsID4+PiA4KSAmIDI1NTtcbiAgICAgIGRzdFtpICsgN10gPSBsICYgMjU1O1xuICAgIH1cblxuICAgIHJldHVybiBkc3Q7XG4gIH07XG5cbiAgdGhpcy5kZWNyeXB0ID0gZnVuY3Rpb24oc3JjKSB7XG4gICAgdmFyIGRzdCA9IG5ldyBBcnJheShzcmMubGVuZ3RoKTtcblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgc3JjLmxlbmd0aDsgaSArPSA4KSB7XG4gICAgICB2YXIgbCA9IHNyY1tpXSA8PCAyNCB8IHNyY1tpICsgMV0gPDwgMTYgfCBzcmNbaSArIDJdIDw8IDggfCBzcmNbaSArIDNdO1xuICAgICAgdmFyIHIgPSBzcmNbaSArIDRdIDw8IDI0IHwgc3JjW2kgKyA1XSA8PCAxNiB8IHNyY1tpICsgNl0gPDwgOCB8IHNyY1tpICsgN107XG4gICAgICB2YXIgdDtcblxuICAgICAgdCA9IHI7XG4gICAgICByID0gbCBeIGYxKHIsIHRoaXMubWFza2luZ1sxNV0sIHRoaXMucm90YXRlWzE1XSk7XG4gICAgICBsID0gdDtcbiAgICAgIHQgPSByO1xuICAgICAgciA9IGwgXiBmMyhyLCB0aGlzLm1hc2tpbmdbMTRdLCB0aGlzLnJvdGF0ZVsxNF0pO1xuICAgICAgbCA9IHQ7XG4gICAgICB0ID0gcjtcbiAgICAgIHIgPSBsIF4gZjIociwgdGhpcy5tYXNraW5nWzEzXSwgdGhpcy5yb3RhdGVbMTNdKTtcbiAgICAgIGwgPSB0O1xuICAgICAgdCA9IHI7XG4gICAgICByID0gbCBeIGYxKHIsIHRoaXMubWFza2luZ1sxMl0sIHRoaXMucm90YXRlWzEyXSk7XG4gICAgICBsID0gdDtcblxuICAgICAgdCA9IHI7XG4gICAgICByID0gbCBeIGYzKHIsIHRoaXMubWFza2luZ1sxMV0sIHRoaXMucm90YXRlWzExXSk7XG4gICAgICBsID0gdDtcbiAgICAgIHQgPSByO1xuICAgICAgciA9IGwgXiBmMihyLCB0aGlzLm1hc2tpbmdbMTBdLCB0aGlzLnJvdGF0ZVsxMF0pO1xuICAgICAgbCA9IHQ7XG4gICAgICB0ID0gcjtcbiAgICAgIHIgPSBsIF4gZjEociwgdGhpcy5tYXNraW5nWzldLCB0aGlzLnJvdGF0ZVs5XSk7XG4gICAgICBsID0gdDtcbiAgICAgIHQgPSByO1xuICAgICAgciA9IGwgXiBmMyhyLCB0aGlzLm1hc2tpbmdbOF0sIHRoaXMucm90YXRlWzhdKTtcbiAgICAgIGwgPSB0O1xuXG4gICAgICB0ID0gcjtcbiAgICAgIHIgPSBsIF4gZjIociwgdGhpcy5tYXNraW5nWzddLCB0aGlzLnJvdGF0ZVs3XSk7XG4gICAgICBsID0gdDtcbiAgICAgIHQgPSByO1xuICAgICAgciA9IGwgXiBmMShyLCB0aGlzLm1hc2tpbmdbNl0sIHRoaXMucm90YXRlWzZdKTtcbiAgICAgIGwgPSB0O1xuICAgICAgdCA9IHI7XG4gICAgICByID0gbCBeIGYzKHIsIHRoaXMubWFza2luZ1s1XSwgdGhpcy5yb3RhdGVbNV0pO1xuICAgICAgbCA9IHQ7XG4gICAgICB0ID0gcjtcbiAgICAgIHIgPSBsIF4gZjIociwgdGhpcy5tYXNraW5nWzRdLCB0aGlzLnJvdGF0ZVs0XSk7XG4gICAgICBsID0gdDtcblxuICAgICAgdCA9IHI7XG4gICAgICByID0gbCBeIGYxKHIsIHRoaXMubWFza2luZ1szXSwgdGhpcy5yb3RhdGVbM10pO1xuICAgICAgbCA9IHQ7XG4gICAgICB0ID0gcjtcbiAgICAgIHIgPSBsIF4gZjMociwgdGhpcy5tYXNraW5nWzJdLCB0aGlzLnJvdGF0ZVsyXSk7XG4gICAgICBsID0gdDtcbiAgICAgIHQgPSByO1xuICAgICAgciA9IGwgXiBmMihyLCB0aGlzLm1hc2tpbmdbMV0sIHRoaXMucm90YXRlWzFdKTtcbiAgICAgIGwgPSB0O1xuICAgICAgdCA9IHI7XG4gICAgICByID0gbCBeIGYxKHIsIHRoaXMubWFza2luZ1swXSwgdGhpcy5yb3RhdGVbMF0pO1xuICAgICAgbCA9IHQ7XG5cbiAgICAgIGRzdFtpXSA9IChyID4+PiAyNCkgJiAyNTU7XG4gICAgICBkc3RbaSArIDFdID0gKHIgPj4+IDE2KSAmIDI1NTtcbiAgICAgIGRzdFtpICsgMl0gPSAociA+Pj4gOCkgJiAyNTU7XG4gICAgICBkc3RbaSArIDNdID0gciAmIDI1NTtcbiAgICAgIGRzdFtpICsgNF0gPSAobCA+Pj4gMjQpICYgMjU1O1xuICAgICAgZHN0W2kgKyA1XSA9IChsID4+IDE2KSAmIDI1NTtcbiAgICAgIGRzdFtpICsgNl0gPSAobCA+PiA4KSAmIDI1NTtcbiAgICAgIGRzdFtpICsgN10gPSBsICYgMjU1O1xuICAgIH1cblxuICAgIHJldHVybiBkc3Q7XG4gIH07XG4gIHZhciBzY2hlZHVsZUEgPSBuZXcgQXJyYXkoNCk7XG5cbiAgc2NoZWR1bGVBWzBdID0gbmV3IEFycmF5KDQpO1xuICBzY2hlZHVsZUFbMF1bMF0gPSBuZXcgQXJyYXkoNCwgMCwgMHhkLCAweGYsIDB4YywgMHhlLCAweDgpO1xuICBzY2hlZHVsZUFbMF1bMV0gPSBuZXcgQXJyYXkoNSwgMiwgMTYgKyAwLCAxNiArIDIsIDE2ICsgMSwgMTYgKyAzLCAweGEpO1xuICBzY2hlZHVsZUFbMF1bMl0gPSBuZXcgQXJyYXkoNiwgMywgMTYgKyA3LCAxNiArIDYsIDE2ICsgNSwgMTYgKyA0LCA5KTtcbiAgc2NoZWR1bGVBWzBdWzNdID0gbmV3IEFycmF5KDcsIDEsIDE2ICsgMHhhLCAxNiArIDksIDE2ICsgMHhiLCAxNiArIDgsIDB4Yik7XG5cbiAgc2NoZWR1bGVBWzFdID0gbmV3IEFycmF5KDQpO1xuICBzY2hlZHVsZUFbMV1bMF0gPSBuZXcgQXJyYXkoMCwgNiwgMTYgKyA1LCAxNiArIDcsIDE2ICsgNCwgMTYgKyA2LCAxNiArIDApO1xuICBzY2hlZHVsZUFbMV1bMV0gPSBuZXcgQXJyYXkoMSwgNCwgMCwgMiwgMSwgMywgMTYgKyAyKTtcbiAgc2NoZWR1bGVBWzFdWzJdID0gbmV3IEFycmF5KDIsIDUsIDcsIDYsIDUsIDQsIDE2ICsgMSk7XG4gIHNjaGVkdWxlQVsxXVszXSA9IG5ldyBBcnJheSgzLCA3LCAweGEsIDksIDB4YiwgOCwgMTYgKyAzKTtcblxuICBzY2hlZHVsZUFbMl0gPSBuZXcgQXJyYXkoNCk7XG4gIHNjaGVkdWxlQVsyXVswXSA9IG5ldyBBcnJheSg0LCAwLCAweGQsIDB4ZiwgMHhjLCAweGUsIDgpO1xuICBzY2hlZHVsZUFbMl1bMV0gPSBuZXcgQXJyYXkoNSwgMiwgMTYgKyAwLCAxNiArIDIsIDE2ICsgMSwgMTYgKyAzLCAweGEpO1xuICBzY2hlZHVsZUFbMl1bMl0gPSBuZXcgQXJyYXkoNiwgMywgMTYgKyA3LCAxNiArIDYsIDE2ICsgNSwgMTYgKyA0LCA5KTtcbiAgc2NoZWR1bGVBWzJdWzNdID0gbmV3IEFycmF5KDcsIDEsIDE2ICsgMHhhLCAxNiArIDksIDE2ICsgMHhiLCAxNiArIDgsIDB4Yik7XG5cblxuICBzY2hlZHVsZUFbM10gPSBuZXcgQXJyYXkoNCk7XG4gIHNjaGVkdWxlQVszXVswXSA9IG5ldyBBcnJheSgwLCA2LCAxNiArIDUsIDE2ICsgNywgMTYgKyA0LCAxNiArIDYsIDE2ICsgMCk7XG4gIHNjaGVkdWxlQVszXVsxXSA9IG5ldyBBcnJheSgxLCA0LCAwLCAyLCAxLCAzLCAxNiArIDIpO1xuICBzY2hlZHVsZUFbM11bMl0gPSBuZXcgQXJyYXkoMiwgNSwgNywgNiwgNSwgNCwgMTYgKyAxKTtcbiAgc2NoZWR1bGVBWzNdWzNdID0gbmV3IEFycmF5KDMsIDcsIDB4YSwgOSwgMHhiLCA4LCAxNiArIDMpO1xuXG4gIHZhciBzY2hlZHVsZUIgPSBuZXcgQXJyYXkoNCk7XG5cbiAgc2NoZWR1bGVCWzBdID0gbmV3IEFycmF5KDQpO1xuICBzY2hlZHVsZUJbMF1bMF0gPSBuZXcgQXJyYXkoMTYgKyA4LCAxNiArIDksIDE2ICsgNywgMTYgKyA2LCAxNiArIDIpO1xuICBzY2hlZHVsZUJbMF1bMV0gPSBuZXcgQXJyYXkoMTYgKyAweGEsIDE2ICsgMHhiLCAxNiArIDUsIDE2ICsgNCwgMTYgKyA2KTtcbiAgc2NoZWR1bGVCWzBdWzJdID0gbmV3IEFycmF5KDE2ICsgMHhjLCAxNiArIDB4ZCwgMTYgKyAzLCAxNiArIDIsIDE2ICsgOSk7XG4gIHNjaGVkdWxlQlswXVszXSA9IG5ldyBBcnJheSgxNiArIDB4ZSwgMTYgKyAweGYsIDE2ICsgMSwgMTYgKyAwLCAxNiArIDB4Yyk7XG5cbiAgc2NoZWR1bGVCWzFdID0gbmV3IEFycmF5KDQpO1xuICBzY2hlZHVsZUJbMV1bMF0gPSBuZXcgQXJyYXkoMywgMiwgMHhjLCAweGQsIDgpO1xuICBzY2hlZHVsZUJbMV1bMV0gPSBuZXcgQXJyYXkoMSwgMCwgMHhlLCAweGYsIDB4ZCk7XG4gIHNjaGVkdWxlQlsxXVsyXSA9IG5ldyBBcnJheSg3LCA2LCA4LCA5LCAzKTtcbiAgc2NoZWR1bGVCWzFdWzNdID0gbmV3IEFycmF5KDUsIDQsIDB4YSwgMHhiLCA3KTtcblxuXG4gIHNjaGVkdWxlQlsyXSA9IG5ldyBBcnJheSg0KTtcbiAgc2NoZWR1bGVCWzJdWzBdID0gbmV3IEFycmF5KDE2ICsgMywgMTYgKyAyLCAxNiArIDB4YywgMTYgKyAweGQsIDE2ICsgOSk7XG4gIHNjaGVkdWxlQlsyXVsxXSA9IG5ldyBBcnJheSgxNiArIDEsIDE2ICsgMCwgMTYgKyAweGUsIDE2ICsgMHhmLCAxNiArIDB4Yyk7XG4gIHNjaGVkdWxlQlsyXVsyXSA9IG5ldyBBcnJheSgxNiArIDcsIDE2ICsgNiwgMTYgKyA4LCAxNiArIDksIDE2ICsgMik7XG4gIHNjaGVkdWxlQlsyXVszXSA9IG5ldyBBcnJheSgxNiArIDUsIDE2ICsgNCwgMTYgKyAweGEsIDE2ICsgMHhiLCAxNiArIDYpO1xuXG5cbiAgc2NoZWR1bGVCWzNdID0gbmV3IEFycmF5KDQpO1xuICBzY2hlZHVsZUJbM11bMF0gPSBuZXcgQXJyYXkoOCwgOSwgNywgNiwgMyk7XG4gIHNjaGVkdWxlQlszXVsxXSA9IG5ldyBBcnJheSgweGEsIDB4YiwgNSwgNCwgNyk7XG4gIHNjaGVkdWxlQlszXVsyXSA9IG5ldyBBcnJheSgweGMsIDB4ZCwgMywgMiwgOCk7XG4gIHNjaGVkdWxlQlszXVszXSA9IG5ldyBBcnJheSgweGUsIDB4ZiwgMSwgMCwgMHhkKTtcblxuICAvLyBjaGFuZ2VkICdpbicgdG8gJ2lubicgKGluIGphdmFzY3JpcHQgJ2luJyBpcyBhIHJlc2VydmVkIHdvcmQpXG4gIHRoaXMua2V5U2NoZWR1bGUgPSBmdW5jdGlvbihpbm4pIHtcbiAgICB2YXIgdCA9IG5ldyBBcnJheSg4KTtcbiAgICB2YXIgayA9IG5ldyBBcnJheSgzMik7XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IDQ7IGkrKykge1xuICAgICAgdmFyIGogPSBpICogNDtcbiAgICAgIHRbaV0gPSBpbm5bal0gPDwgMjQgfCBpbm5baiArIDFdIDw8IDE2IHwgaW5uW2ogKyAyXSA8PCA4IHwgaW5uW2ogKyAzXTtcbiAgICB9XG5cbiAgICB2YXIgeCA9IFs2LCA3LCA0LCA1XTtcbiAgICB2YXIga2kgPSAwO1xuXG4gICAgZm9yICh2YXIgaGFsZiA9IDA7IGhhbGYgPCAyOyBoYWxmKyspIHtcbiAgICAgIGZvciAodmFyIHJvdW5kID0gMDsgcm91bmQgPCA0OyByb3VuZCsrKSB7XG4gICAgICAgIGZvciAodmFyIGogPSAwOyBqIDwgNDsgaisrKSB7XG4gICAgICAgICAgdmFyIGEgPSBzY2hlZHVsZUFbcm91bmRdW2pdO1xuICAgICAgICAgIHZhciB3ID0gdFthWzFdXTtcblxuICAgICAgICAgIHcgXj0gc0JveFs0XVsodFthWzJdID4+PiAyXSA+Pj4gKDI0IC0gOCAqIChhWzJdICYgMykpKSAmIDB4ZmZdO1xuICAgICAgICAgIHcgXj0gc0JveFs1XVsodFthWzNdID4+PiAyXSA+Pj4gKDI0IC0gOCAqIChhWzNdICYgMykpKSAmIDB4ZmZdO1xuICAgICAgICAgIHcgXj0gc0JveFs2XVsodFthWzRdID4+PiAyXSA+Pj4gKDI0IC0gOCAqIChhWzRdICYgMykpKSAmIDB4ZmZdO1xuICAgICAgICAgIHcgXj0gc0JveFs3XVsodFthWzVdID4+PiAyXSA+Pj4gKDI0IC0gOCAqIChhWzVdICYgMykpKSAmIDB4ZmZdO1xuICAgICAgICAgIHcgXj0gc0JveFt4W2pdXVsodFthWzZdID4+PiAyXSA+Pj4gKDI0IC0gOCAqIChhWzZdICYgMykpKSAmIDB4ZmZdO1xuICAgICAgICAgIHRbYVswXV0gPSB3O1xuICAgICAgICB9XG5cbiAgICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCA0OyBqKyspIHtcbiAgICAgICAgICB2YXIgYiA9IHNjaGVkdWxlQltyb3VuZF1bal07XG4gICAgICAgICAgdmFyIHcgPSBzQm94WzRdWyh0W2JbMF0gPj4+IDJdID4+PiAoMjQgLSA4ICogKGJbMF0gJiAzKSkpICYgMHhmZl07XG5cbiAgICAgICAgICB3IF49IHNCb3hbNV1bKHRbYlsxXSA+Pj4gMl0gPj4+ICgyNCAtIDggKiAoYlsxXSAmIDMpKSkgJiAweGZmXTtcbiAgICAgICAgICB3IF49IHNCb3hbNl1bKHRbYlsyXSA+Pj4gMl0gPj4+ICgyNCAtIDggKiAoYlsyXSAmIDMpKSkgJiAweGZmXTtcbiAgICAgICAgICB3IF49IHNCb3hbN11bKHRbYlszXSA+Pj4gMl0gPj4+ICgyNCAtIDggKiAoYlszXSAmIDMpKSkgJiAweGZmXTtcbiAgICAgICAgICB3IF49IHNCb3hbNCArIGpdWyh0W2JbNF0gPj4+IDJdID4+PiAoMjQgLSA4ICogKGJbNF0gJiAzKSkpICYgMHhmZl07XG4gICAgICAgICAga1traV0gPSB3O1xuICAgICAgICAgIGtpKys7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IDE2OyBpKyspIHtcbiAgICAgIHRoaXMubWFza2luZ1tpXSA9IGtbaV07XG4gICAgICB0aGlzLnJvdGF0ZVtpXSA9IGtbMTYgKyBpXSAmIDB4MWY7XG4gICAgfVxuICB9O1xuXG4gIC8vIFRoZXNlIGFyZSB0aGUgdGhyZWUgJ2YnIGZ1bmN0aW9ucy4gU2VlIFJGQyAyMTQ0LCBzZWN0aW9uIDIuMi5cblxuICBmdW5jdGlvbiBmMShkLCBtLCByKSB7XG4gICAgdmFyIHQgPSBtICsgZDtcbiAgICB2YXIgSSA9ICh0IDw8IHIpIHwgKHQgPj4+ICgzMiAtIHIpKTtcbiAgICByZXR1cm4gKChzQm94WzBdW0kgPj4+IDI0XSBeIHNCb3hbMV1bKEkgPj4+IDE2KSAmIDI1NV0pIC0gc0JveFsyXVsoSSA+Pj4gOCkgJiAyNTVdKSArIHNCb3hbM11bSSAmIDI1NV07XG4gIH1cblxuICBmdW5jdGlvbiBmMihkLCBtLCByKSB7XG4gICAgdmFyIHQgPSBtIF4gZDtcbiAgICB2YXIgSSA9ICh0IDw8IHIpIHwgKHQgPj4+ICgzMiAtIHIpKTtcbiAgICByZXR1cm4gKChzQm94WzBdW0kgPj4+IDI0XSAtIHNCb3hbMV1bKEkgPj4+IDE2KSAmIDI1NV0pICsgc0JveFsyXVsoSSA+Pj4gOCkgJiAyNTVdKSBeIHNCb3hbM11bSSAmIDI1NV07XG4gIH1cblxuICBmdW5jdGlvbiBmMyhkLCBtLCByKSB7XG4gICAgdmFyIHQgPSBtIC0gZDtcbiAgICB2YXIgSSA9ICh0IDw8IHIpIHwgKHQgPj4+ICgzMiAtIHIpKTtcbiAgICByZXR1cm4gKChzQm94WzBdW0kgPj4+IDI0XSArIHNCb3hbMV1bKEkgPj4+IDE2KSAmIDI1NV0pIF4gc0JveFsyXVsoSSA+Pj4gOCkgJiAyNTVdKSAtIHNCb3hbM11bSSAmIDI1NV07XG4gIH1cblxuICB2YXIgc0JveCA9IG5ldyBBcnJheSg4KTtcbiAgc0JveFswXSA9IG5ldyBBcnJheShcbiAgICAweDMwZmI0MGQ0LCAweDlmYTBmZjBiLCAweDZiZWNjZDJmLCAweDNmMjU4YzdhLCAweDFlMjEzZjJmLCAweDljMDA0ZGQzLCAweDYwMDNlNTQwLCAweGNmOWZjOTQ5LFxuICAgIDB4YmZkNGFmMjcsIDB4ODhiYmJkYjUsIDB4ZTIwMzQwOTAsIDB4OThkMDk2NzUsIDB4NmU2M2EwZTAsIDB4MTVjMzYxZDIsIDB4YzJlNzY2MWQsIDB4MjJkNGZmOGUsXG4gICAgMHgyODY4M2I2ZiwgMHhjMDdmZDA1OSwgMHhmZjIzNzljOCwgMHg3NzVmNTBlMiwgMHg0M2MzNDBkMywgMHhkZjJmODY1NiwgMHg4ODdjYTQxYSwgMHhhMmQyYmQyZCxcbiAgICAweGExYzllMGQ2LCAweDM0NmM0ODE5LCAweDYxYjc2ZDg3LCAweDIyNTQwZjJmLCAweDJhYmUzMmUxLCAweGFhNTQxNjZiLCAweDIyNTY4ZTNhLCAweGEyZDM0MWQwLFxuICAgIDB4NjZkYjQwYzgsIDB4YTc4NDM5MmYsIDB4MDA0ZGZmMmYsIDB4MmRiOWQyZGUsIDB4OTc5NDNmYWMsIDB4NGE5N2MxZDgsIDB4NTI3NjQ0YjcsIDB4YjVmNDM3YTcsXG4gICAgMHhiODJjYmFlZiwgMHhkNzUxZDE1OSwgMHg2ZmY3ZjBlZCwgMHg1YTA5N2ExZiwgMHg4MjdiNjhkMCwgMHg5MGVjZjUyZSwgMHgyMmIwYzA1NCwgMHhiYzhlNTkzNSxcbiAgICAweDRiNmQyZjdmLCAweDUwYmI2NGEyLCAweGQyNjY0OTEwLCAweGJlZTU4MTJkLCAweGI3MzMyMjkwLCAweGU5M2IxNTlmLCAweGI0OGVlNDExLCAweDRiZmYzNDVkLFxuICAgIDB4ZmQ0NWMyNDAsIDB4YWQzMTk3M2YsIDB4YzRmNmQwMmUsIDB4NTVmYzgxNjUsIDB4ZDViMWNhYWQsIDB4YTFhYzJkYWUsIDB4YTJkNGI3NmQsIDB4YzE5YjBjNTAsXG4gICAgMHg4ODIyNDBmMiwgMHgwYzZlNGYzOCwgMHhhNGU0YmZkNywgMHg0ZjViYTI3MiwgMHg1NjRjMWQyZiwgMHhjNTljNTMxOSwgMHhiOTQ5ZTM1NCwgMHhiMDQ2NjlmZSxcbiAgICAweGIxYjZhYjhhLCAweGM3MTM1OGRkLCAweDYzODVjNTQ1LCAweDExMGY5MzVkLCAweDU3NTM4YWQ1LCAweDZhMzkwNDkzLCAweGU2M2QzN2UwLCAweDJhNTRmNmIzLFxuICAgIDB4M2E3ODdkNWYsIDB4NjI3NmEwYjUsIDB4MTlhNmZjZGYsIDB4N2E0MjIwNmEsIDB4MjlmOWQ0ZDUsIDB4ZjYxYjE4OTEsIDB4YmI3MjI3NWUsIDB4YWE1MDgxNjcsXG4gICAgMHgzODkwMTA5MSwgMHhjNmI1MDVlYiwgMHg4NGM3Y2I4YywgMHgyYWQ3NWEwZiwgMHg4NzRhMTQyNywgMHhhMmQxOTM2YiwgMHgyYWQyODZhZiwgMHhhYTU2ZDI5MSxcbiAgICAweGQ3ODk0MzYwLCAweDQyNWM3NTBkLCAweDkzYjM5ZTI2LCAweDE4NzE4NGM5LCAweDZjMDBiMzJkLCAweDczZTJiYjE0LCAweGEwYmViYzNjLCAweDU0NjIzNzc5LFxuICAgIDB4NjQ0NTllYWIsIDB4M2YzMjhiODIsIDB4NzcxOGNmODIsIDB4NTlhMmNlYTYsIDB4MDRlZTAwMmUsIDB4ODlmZTc4ZTYsIDB4M2ZhYjA5NTAsIDB4MzI1ZmY2YzIsXG4gICAgMHg4MTM4M2YwNSwgMHg2OTYzYzVjOCwgMHg3NmNiNWFkNiwgMHhkNDk5NzRjOSwgMHhjYTE4MGRjZiwgMHgzODA3ODJkNSwgMHhjN2ZhNWNmNiwgMHg4YWMzMTUxMSxcbiAgICAweDM1ZTc5ZTEzLCAweDQ3ZGE5MWQwLCAweGY0MGY5MDg2LCAweGE3ZTI0MTllLCAweDMxMzY2MjQxLCAweDA1MWVmNDk1LCAweGFhNTczYjA0LCAweDRhODA1ZDhkLFxuICAgIDB4NTQ4MzAwZDAsIDB4MDAzMjJhM2MsIDB4YmY2NGNkZGYsIDB4YmE1N2E2OGUsIDB4NzVjNjM3MmIsIDB4NTBhZmQzNDEsIDB4YTdjMTMyNzUsIDB4OTE1YTBiZjUsXG4gICAgMHg2YjU0YmZhYiwgMHgyYjBiMTQyNiwgMHhhYjRjYzlkNywgMHg0NDljY2Q4MiwgMHhmN2ZiZjI2NSwgMHhhYjg1YzVmMywgMHgxYjU1ZGI5NCwgMHhhYWQ0ZTMyNCxcbiAgICAweGNmYTRiZDNmLCAweDJkZWFhM2UyLCAweDllMjA0ZDAyLCAweGM4YmQyNWFjLCAweGVhZGY1NWIzLCAweGQ1YmQ5ZTk4LCAweGUzMTIzMWIyLCAweDJhZDVhZDZjLFxuICAgIDB4OTU0MzI5ZGUsIDB4YWRiZTQ1MjgsIDB4ZDg3MTBmNjksIDB4YWE1MWM5MGYsIDB4YWE3ODZiZjYsIDB4MjI1MTNmMWUsIDB4YWE1MWE3OWIsIDB4MmFkMzQ0Y2MsXG4gICAgMHg3YjVhNDFmMCwgMHhkMzdjZmJhZCwgMHgxYjA2OTUwNSwgMHg0MWVjZTQ5MSwgMHhiNGMzMzJlNiwgMHgwMzIyNjhkNCwgMHhjOTYwMGFjYywgMHhjZTM4N2U2ZCxcbiAgICAweGJmNmJiMTZjLCAweDZhNzBmYjc4LCAweDBkMDNkOWM5LCAweGQ0ZGYzOWRlLCAweGUwMTA2M2RhLCAweDQ3MzZmNDY0LCAweDVhZDMyOGQ4LCAweGIzNDdjYzk2LFxuICAgIDB4NzViYjBmYzMsIDB4OTg1MTFiZmIsIDB4NGZmYmNjMzUsIDB4YjU4YmNmNmEsIDB4ZTExZjBhYmMsIDB4YmZjNWZlNGEsIDB4YTcwYWVjMTAsIDB4YWMzOTU3MGEsXG4gICAgMHgzZjA0NDQyZiwgMHg2MTg4YjE1MywgMHhlMDM5N2EyZSwgMHg1NzI3Y2I3OSwgMHg5Y2ViNDE4ZiwgMHgxY2FjZDY4ZCwgMHgyYWQzN2M5NiwgMHgwMTc1Y2I5ZCxcbiAgICAweGM2OWRmZjA5LCAweGM3NWI2NWYwLCAweGQ5ZGI0MGQ4LCAweGVjMGU3Nzc5LCAweDQ3NDRlYWQ0LCAweGIxMWMzMjc0LCAweGRkMjRjYjllLCAweDdlMWM1NGJkLFxuICAgIDB4ZjAxMTQ0ZjksIDB4ZDIyNDBlYjEsIDB4OTY3NWIzZmQsIDB4YTNhYzM3NTUsIDB4ZDQ3YzI3YWYsIDB4NTFjODVmNGQsIDB4NTY5MDc1OTYsIDB4YTViYjE1ZTYsXG4gICAgMHg1ODAzMDRmMCwgMHhjYTA0MmNmMSwgMHgwMTFhMzdlYSwgMHg4ZGJmYWFkYiwgMHgzNWJhM2U0YSwgMHgzNTI2ZmZhMCwgMHhjMzdiNGQwOSwgMHhiYzMwNmVkOSxcbiAgICAweDk4YTUyNjY2LCAweDU2NDhmNzI1LCAweGZmNWU1NjlkLCAweDBjZWQ2M2QwLCAweDdjNjNiMmNmLCAweDcwMGI0NWUxLCAweGQ1ZWE1MGYxLCAweDg1YTkyODcyLFxuICAgIDB4YWYxZmJkYTcsIDB4ZDQyMzQ4NzAsIDB4YTc4NzBiZjMsIDB4MmQzYjRkNzksIDB4NDJlMDQxOTgsIDB4MGNkMGVkZTcsIDB4MjY0NzBkYjgsIDB4Zjg4MTgxNGMsXG4gICAgMHg0NzRkNmFkNywgMHg3YzBjNWU1YywgMHhkMTIzMTk1OSwgMHgzODFiNzI5OCwgMHhmNWQyZjRkYiwgMHhhYjgzODY1MywgMHg2ZTJmMWUyMywgMHg4MzcxOWM5ZSxcbiAgICAweGJkOTFlMDQ2LCAweDlhNTY0NTZlLCAweGRjMzkyMDBjLCAweDIwYzhjNTcxLCAweDk2MmJkYTFjLCAweGUxZTY5NmZmLCAweGIxNDFhYjA4LCAweDdjY2E4OWI5LFxuICAgIDB4MWE2OWU3ODMsIDB4MDJjYzQ4NDMsIDB4YTJmN2M1NzksIDB4NDI5ZWY0N2QsIDB4NDI3YjE2OWMsIDB4NWFjOWYwNDksIDB4ZGQ4ZjBmMDAsIDB4NWM4MTY1YmYpO1xuXG4gIHNCb3hbMV0gPSBuZXcgQXJyYXkoXG4gICAgMHgxZjIwMTA5NCwgMHhlZjBiYTc1YiwgMHg2OWUzY2Y3ZSwgMHgzOTNmNDM4MCwgMHhmZTYxY2Y3YSwgMHhlZWM1MjA3YSwgMHg1NTg4OWM5NCwgMHg3MmZjMDY1MSxcbiAgICAweGFkYTdlZjc5LCAweDRlMWQ3MjM1LCAweGQ1NWE2M2NlLCAweGRlMDQzNmJhLCAweDk5YzQzMGVmLCAweDVmMGMwNzk0LCAweDE4ZGNkYjdkLCAweGExZDZlZmYzLFxuICAgIDB4YTBiNTJmN2IsIDB4NTllODM2MDUsIDB4ZWUxNWIwOTQsIDB4ZTlmZmQ5MDksIDB4ZGM0NDAwODYsIDB4ZWY5NDQ0NTksIDB4YmE4M2NjYjMsIDB4ZTBjM2NkZmIsXG4gICAgMHhkMWRhNDE4MSwgMHgzYjA5MmFiMSwgMHhmOTk3ZjFjMSwgMHhhNWU2Y2Y3YiwgMHgwMTQyMGRkYiwgMHhlNGU3ZWY1YiwgMHgyNWExZmY0MSwgMHhlMTgwZjgwNixcbiAgICAweDFmYzQxMDgwLCAweDE3OWJlZTdhLCAweGQzN2FjNmE5LCAweGZlNTgzMGE0LCAweDk4ZGU4YjdmLCAweDc3ZTgzZjRlLCAweDc5OTI5MjY5LCAweDI0ZmE5ZjdiLFxuICAgIDB4ZTExM2M4NWIsIDB4YWNjNDAwODMsIDB4ZDc1MDM1MjUsIDB4ZjdlYTYxNWYsIDB4NjIxNDMxNTQsIDB4MGQ1NTRiNjMsIDB4NWQ2ODExMjEsIDB4Yzg2NmMzNTksXG4gICAgMHgzZDYzY2Y3MywgMHhjZWUyMzRjMCwgMHhkNGQ4N2U4NywgMHg1YzY3MmIyMSwgMHgwNzFmNjE4MSwgMHgzOWY3NjI3ZiwgMHgzNjFlMzA4NCwgMHhlNGViNTczYixcbiAgICAweDYwMmY2NGE0LCAweGQ2M2FjZDljLCAweDFiYmM0NjM1LCAweDllODEwMzJkLCAweDI3MDFmNTBjLCAweDk5ODQ3YWI0LCAweGEwZTNkZjc5LCAweGJhNmNmMzhjLFxuICAgIDB4MTA4NDMwOTQsIDB4MjUzN2E5NWUsIDB4ZjQ2ZjZmZmUsIDB4YTFmZjNiMWYsIDB4MjA4Y2ZiNmEsIDB4OGY0NThjNzQsIDB4ZDllMGEyMjcsIDB4NGVjNzNhMzQsXG4gICAgMHhmYzg4NGY2OSwgMHgzZTRkZThkZiwgMHhlZjBlMDA4OCwgMHgzNTU5NjQ4ZCwgMHg4YTQ1Mzg4YywgMHgxZDgwNDM2NiwgMHg3MjFkOWJmZCwgMHhhNTg2ODRiYixcbiAgICAweGU4MjU2MzMzLCAweDg0NGU4MjEyLCAweDEyOGQ4MDk4LCAweGZlZDMzZmI0LCAweGNlMjgwYWUxLCAweDI3ZTE5YmE1LCAweGQ1YTZjMjUyLCAweGU0OTc1NGJkLFxuICAgIDB4YzVkNjU1ZGQsIDB4ZWI2NjcwNjQsIDB4Nzc4NDBiNGQsIDB4YTFiNmE4MDEsIDB4ODRkYjI2YTksIDB4ZTBiNTY3MTQsIDB4MjFmMDQzYjcsIDB4ZTVkMDU4NjAsXG4gICAgMHg1NGYwMzA4NCwgMHgwNjZmZjQ3MiwgMHhhMzFhYTE1MywgMHhkYWRjNDc1NSwgMHhiNTYyNWRiZiwgMHg2ODU2MWJlNiwgMHg4M2NhNmI5NCwgMHgyZDZlZDIzYixcbiAgICAweGVjY2YwMWRiLCAweGE2ZDNkMGJhLCAweGI2ODAzZDVjLCAweGFmNzdhNzA5LCAweDMzYjRhMzRjLCAweDM5N2JjOGQ2LCAweDVlZTIyYjk1LCAweDVmMGU1MzA0LFxuICAgIDB4ODFlZDZmNjEsIDB4MjBlNzQzNjQsIDB4YjQ1ZTEzNzgsIDB4ZGUxODYzOWIsIDB4ODgxY2ExMjIsIDB4Yjk2NzI2ZDEsIDB4ODA0OWE3ZTgsIDB4MjJiN2RhN2IsXG4gICAgMHg1ZTU1MmQyNSwgMHg1MjcyZDIzNywgMHg3OWQyOTUxYywgMHhjNjBkODk0YywgMHg0ODhjYjQwMiwgMHgxYmE0ZmU1YiwgMHhhNGIwOWY2YiwgMHgxY2E4MTVjZixcbiAgICAweGEyMGMzMDA1LCAweDg4NzFkZjYzLCAweGI5ZGUyZmNiLCAweDBjYzZjOWU5LCAweDBiZWVmZjUzLCAweGUzMjE0NTE3LCAweGI0NTQyODM1LCAweDlmNjMyOTNjLFxuICAgIDB4ZWU0MWU3MjksIDB4NmUxZDJkN2MsIDB4NTAwNDUyODYsIDB4MWU2Njg1ZjMsIDB4ZjMzNDAxYzYsIDB4MzBhMjJjOTUsIDB4MzFhNzA4NTAsIDB4NjA5MzBmMTMsXG4gICAgMHg3M2Y5ODQxNywgMHhhMTI2OTg1OSwgMHhlYzY0NWM0NCwgMHg1MmM4NzdhOSwgMHhjZGZmMzNhNiwgMHhhMDJiMTc0MSwgMHg3Y2JhZDlhMiwgMHgyMTgwMDM2ZixcbiAgICAweDUwZDk5YzA4LCAweGNiM2Y0ODYxLCAweGMyNmJkNzY1LCAweDY0YTNmNmFiLCAweDgwMzQyNjc2LCAweDI1YTc1ZTdiLCAweGU0ZTZkMWZjLCAweDIwYzcxMGU2LFxuICAgIDB4Y2RmMGI2ODAsIDB4MTc4NDRkM2IsIDB4MzFlZWY4NGQsIDB4N2UwODI0ZTQsIDB4MmNjYjQ5ZWIsIDB4ODQ2YTNiYWUsIDB4OGZmNzc4ODgsIDB4ZWU1ZDYwZjYsXG4gICAgMHg3YWY3NTY3MywgMHgyZmRkNWNkYiwgMHhhMTE2MzFjMSwgMHgzMGY2NmY0MywgMHhiM2ZhZWM1NCwgMHgxNTdmZDdmYSwgMHhlZjg1NzljYywgMHhkMTUyZGU1OCxcbiAgICAweGRiMmZmZDVlLCAweDhmMzJjZTE5LCAweDMwNmFmOTdhLCAweDAyZjAzZWY4LCAweDk5MzE5YWQ1LCAweGMyNDJmYTBmLCAweGE3ZTNlYmIwLCAweGM2OGU0OTA2LFxuICAgIDB4YjhkYTIzMGMsIDB4ODA4MjMwMjgsIDB4ZGNkZWYzYzgsIDB4ZDM1ZmIxNzEsIDB4MDg4YTFiYzgsIDB4YmVjMGM1NjAsIDB4NjFhM2M5ZTgsIDB4YmNhOGY1NGQsXG4gICAgMHhjNzJmZWZmYSwgMHgyMjgyMmU5OSwgMHg4MmM1NzBiNCwgMHhkOGQ5NGU4OSwgMHg4YjFjMzRiYywgMHgzMDFlMTZlNiwgMHgyNzNiZTk3OSwgMHhiMGZmZWFhNixcbiAgICAweDYxZDliOGM2LCAweDAwYjI0ODY5LCAweGI3ZmZjZTNmLCAweDA4ZGMyODNiLCAweDQzZGFmNjVhLCAweGY3ZTE5Nzk4LCAweDc2MTliNzJmLCAweDhmMWM5YmE0LFxuICAgIDB4ZGM4NjM3YTAsIDB4MTZhN2QzYjEsIDB4OWZjMzkzYjcsIDB4YTcxMzZlZWIsIDB4YzZiY2M2M2UsIDB4MWE1MTM3NDIsIDB4ZWY2ODI4YmMsIDB4NTIwMzY1ZDYsXG4gICAgMHgyZDZhNzdhYiwgMHgzNTI3ZWQ0YiwgMHg4MjFmZDIxNiwgMHgwOTVjNmUyZSwgMHhkYjkyZjJmYiwgMHg1ZWVhMjljYiwgMHgxNDU4OTJmNSwgMHg5MTU4NGY3ZixcbiAgICAweDU0ODM2OTdiLCAweDI2NjdhOGNjLCAweDg1MTk2MDQ4LCAweDhjNGJhY2VhLCAweDgzMzg2MGQ0LCAweDBkMjNlMGY5LCAweDZjMzg3ZThhLCAweDBhZTZkMjQ5LFxuICAgIDB4YjI4NDYwMGMsIDB4ZDgzNTczMWQsIDB4ZGNiMWM2NDcsIDB4YWM0YzU2ZWEsIDB4M2ViZDgxYjMsIDB4MjMwZWFiYjAsIDB4NjQzOGJjODcsIDB4ZjBiNWIxZmEsXG4gICAgMHg4ZjVlYTJiMywgMHhmYzE4NDY0MiwgMHgwYTAzNmI3YSwgMHg0ZmIwODliZCwgMHg2NDlkYTU4OSwgMHhhMzQ1NDE1ZSwgMHg1YzAzODMyMywgMHgzZTVkM2JiOSxcbiAgICAweDQzZDc5NTcyLCAweDdlNmRkMDdjLCAweDA2ZGZkZjFlLCAweDZjNmNjNGVmLCAweDcxNjBhNTM5LCAweDczYmZiZTcwLCAweDgzODc3NjA1LCAweDQ1MjNlY2YxKTtcblxuICBzQm94WzJdID0gbmV3IEFycmF5KFxuICAgIDB4OGRlZmMyNDAsIDB4MjVmYTVkOWYsIDB4ZWI5MDNkYmYsIDB4ZTgxMGM5MDcsIDB4NDc2MDdmZmYsIDB4MzY5ZmU0NGIsIDB4OGMxZmM2NDQsIDB4YWVjZWNhOTAsXG4gICAgMHhiZWIxZjliZiwgMHhlZWZiY2FlYSwgMHhlOGNmMTk1MCwgMHg1MWRmMDdhZSwgMHg5MjBlODgwNiwgMHhmMGFkMDU0OCwgMHhlMTNjOGQ4MywgMHg5MjcwMTBkNSxcbiAgICAweDExMTA3ZDlmLCAweDA3NjQ3ZGI5LCAweGIyZTNlNGQ0LCAweDNkNGYyODVlLCAweGI5YWZhODIwLCAweGZhZGU4MmUwLCAweGEwNjcyNjhiLCAweDgyNzI3OTJlLFxuICAgIDB4NTUzZmIyYzAsIDB4NDg5YWUyMmIsIDB4ZDRlZjk3OTQsIDB4MTI1ZTNmYmMsIDB4MjFmZmZjZWUsIDB4ODI1YjFiZmQsIDB4OTI1NWM1ZWQsIDB4MTI1N2EyNDAsXG4gICAgMHg0ZTFhODMwMiwgMHhiYWUwN2ZmZiwgMHg1MjgyNDZlNywgMHg4ZTU3MTQwZSwgMHgzMzczZjdiZiwgMHg4YzlmODE4OCwgMHhhNmZjNGVlOCwgMHhjOTgyYjVhNSxcbiAgICAweGE4YzAxZGI3LCAweDU3OWZjMjY0LCAweDY3MDk0ZjMxLCAweGYyYmQzZjVmLCAweDQwZmZmN2MxLCAweDFmYjc4ZGZjLCAweDhlNmJkMmMxLCAweDQzN2JlNTliLFxuICAgIDB4OTliMDNkYmYsIDB4YjVkYmM2NGIsIDB4NjM4ZGMwZTYsIDB4NTU4MTlkOTksIDB4YTE5N2M4MWMsIDB4NGEwMTJkNmUsIDB4YzU4ODRhMjgsIDB4Y2NjMzZmNzEsXG4gICAgMHhiODQzYzIxMywgMHg2YzA3NDNmMSwgMHg4MzA5ODkzYywgMHgwZmVkZGQ1ZiwgMHgyZjdmZTg1MCwgMHhkN2MwN2Y3ZSwgMHgwMjUwN2ZiZiwgMHg1YWZiOWEwNCxcbiAgICAweGE3NDdkMmQwLCAweDE2NTExOTJlLCAweGFmNzBiZjNlLCAweDU4YzMxMzgwLCAweDVmOTgzMDJlLCAweDcyN2NjM2M0LCAweDBhMGZiNDAyLCAweDBmN2ZlZjgyLFxuICAgIDB4OGM5NmZkYWQsIDB4NWQyYzJhYWUsIDB4OGVlOTlhNDksIDB4NTBkYTg4YjgsIDB4ODQyN2Y0YTAsIDB4MWVhYzU3OTAsIDB4Nzk2ZmI0NDksIDB4ODI1MmRjMTUsXG4gICAgMHhlZmJkN2Q5YiwgMHhhNjcyNTk3ZCwgMHhhZGE4NDBkOCwgMHg0NWY1NDUwNCwgMHhmYTVkNzQwMywgMHhlODNlYzMwNSwgMHg0ZjkxNzUxYSwgMHg5MjU2NjljMixcbiAgICAweDIzZWZlOTQxLCAweGE5MDNmMTJlLCAweDYwMjcwZGYyLCAweDAyNzZlNGI2LCAweDk0ZmQ2NTc0LCAweDkyNzk4NWIyLCAweDgyNzZkYmNiLCAweDAyNzc4MTc2LFxuICAgIDB4ZjhhZjkxOGQsIDB4NGU0OGY3OWUsIDB4OGY2MTZkZGYsIDB4ZTI5ZDg0MGUsIDB4ODQyZjdkODMsIDB4MzQwY2U1YzgsIDB4OTZiYmI2ODIsIDB4OTNiNGIxNDgsXG4gICAgMHhlZjMwM2NhYiwgMHg5ODRmYWYyOCwgMHg3NzlmYWY5YiwgMHg5MmRjNTYwZCwgMHgyMjRkMWUyMCwgMHg4NDM3YWE4OCwgMHg3ZDI5ZGM5NiwgMHgyNzU2ZDNkYyxcbiAgICAweDhiOTA3Y2VlLCAweGI1MWZkMjQwLCAweGU3YzA3Y2UzLCAweGU1NjZiNGExLCAweGMzZTk2MTVlLCAweDNjZjgyMDlkLCAweDYwOTRkMWUzLCAweGNkOWNhMzQxLFxuICAgIDB4NWM3NjQ2MGUsIDB4MDBlYTk4M2IsIDB4ZDRkNjc4ODEsIDB4ZmQ0NzU3MmMsIDB4Zjc2Y2VkZDksIDB4YmRhODIyOWMsIDB4MTI3ZGFkYWEsIDB4NDM4YTA3NGUsXG4gICAgMHgxZjk3YzA5MCwgMHgwODFiZGI4YSwgMHg5M2EwN2ViZSwgMHhiOTM4Y2ExNSwgMHg5N2IwM2NmZiwgMHgzZGMyYzBmOCwgMHg4ZDFhYjJlYywgMHg2NDM4MGU1MSxcbiAgICAweDY4Y2M3YmZiLCAweGQ5MGYyNzg4LCAweDEyNDkwMTgxLCAweDVkZTVmZmQ0LCAweGRkN2VmODZhLCAweDc2YTJlMjE0LCAweGI5YTQwMzY4LCAweDkyNWQ5NThmLFxuICAgIDB4NGIzOWZmZmEsIDB4YmEzOWFlZTksIDB4YTRmZmQzMGIsIDB4ZmFmNzkzM2IsIDB4NmQ0OTg2MjMsIDB4MTkzY2JjZmEsIDB4Mjc2Mjc1NDUsIDB4ODI1Y2Y0N2EsXG4gICAgMHg2MWJkOGJhMCwgMHhkMTFlNDJkMSwgMHhjZWFkMDRmNCwgMHgxMjdlYTM5MiwgMHgxMDQyOGRiNywgMHg4MjcyYTk3MiwgMHg5MjcwYzRhOCwgMHgxMjdkZTUwYixcbiAgICAweDI4NWJhMWM4LCAweDNjNjJmNDRmLCAweDM1YzBlYWE1LCAweGU4MDVkMjMxLCAweDQyODkyOWZiLCAweGI0ZmNkZjgyLCAweDRmYjY2YTUzLCAweDBlN2RjMTViLFxuICAgIDB4MWYwODFmYWIsIDB4MTA4NjE4YWUsIDB4ZmNmZDA4NmQsIDB4ZjlmZjI4ODksIDB4Njk0YmNjMTEsIDB4MjM2YTVjYWUsIDB4MTJkZWNhNGQsIDB4MmMzZjhjYzUsXG4gICAgMHhkMmQwMmRmZSwgMHhmOGVmNTg5NiwgMHhlNGNmNTJkYSwgMHg5NTE1NWI2NywgMHg0OTRhNDg4YywgMHhiOWI2YTgwYywgMHg1YzhmODJiYywgMHg4OWQzNmI0NSxcbiAgICAweDNhNjA5NDM3LCAweGVjMDBjOWE5LCAweDQ0NzE1MjUzLCAweDBhODc0YjQ5LCAweGQ3NzNiYzQwLCAweDdjMzQ2NzFjLCAweDAyNzE3ZWY2LCAweDRmZWI1NTM2LFxuICAgIDB4YTJkMDJmZmYsIDB4ZDJiZjYwYzQsIDB4ZDQzZjAzYzAsIDB4NTBiNGVmNmQsIDB4MDc0NzhjZDEsIDB4MDA2ZTE4ODgsIDB4YTJlNTNmNTUsIDB4YjllNmQ0YmMsXG4gICAgMHhhMjA0ODAxNiwgMHg5NzU3MzgzMywgMHhkNzIwN2Q2NywgMHhkZTBmOGYzZCwgMHg3MmY4N2IzMywgMHhhYmNjNGYzMywgMHg3Njg4YzU1ZCwgMHg3YjAwYTZiMCxcbiAgICAweDk0N2IwMDAxLCAweDU3MDA3NWQyLCAweGY5YmI4OGY4LCAweDg5NDIwMTllLCAweDQyNjRhNWZmLCAweDg1NjMwMmUwLCAweDcyZGJkOTJiLCAweGVlOTcxYjY5LFxuICAgIDB4NmVhMjJmZGUsIDB4NWYwOGFlMmIsIDB4YWY3YTYxNmQsIDB4ZTVjOTg3NjcsIDB4Y2YxZmViZDIsIDB4NjFlZmM4YzIsIDB4ZjFhYzI1NzEsIDB4Y2M4MjM5YzIsXG4gICAgMHg2NzIxNGNiOCwgMHhiMWU1ODNkMSwgMHhiN2RjM2U2MiwgMHg3ZjEwYmRjZSwgMHhmOTBhNWMzOCwgMHgwZmYwNDQzZCwgMHg2MDZlNmRjNiwgMHg2MDU0M2E0OSxcbiAgICAweDU3MjdjMTQ4LCAweDJiZTk4YTFkLCAweDhhYjQxNzM4LCAweDIwZTFiZTI0LCAweGFmOTZkYTBmLCAweDY4NDU4NDI1LCAweDk5ODMzYmU1LCAweDYwMGQ0NTdkLFxuICAgIDB4MjgyZjkzNTAsIDB4ODMzNGIzNjIsIDB4ZDkxZDExMjAsIDB4MmI2ZDhkYTAsIDB4NjQyYjFlMzEsIDB4OWMzMDVhMDAsIDB4NTJiY2U2ODgsIDB4MWIwMzU4OGEsXG4gICAgMHhmN2JhZWZkNSwgMHg0MTQyZWQ5YywgMHhhNDMxNWMxMSwgMHg4MzMyM2VjNSwgMHhkZmVmNDYzNiwgMHhhMTMzYzUwMSwgMHhlOWQzNTMxYywgMHhlZTM1Mzc4Myk7XG5cbiAgc0JveFszXSA9IG5ldyBBcnJheShcbiAgICAweDlkYjMwNDIwLCAweDFmYjZlOWRlLCAweGE3YmU3YmVmLCAweGQyNzNhMjk4LCAweDRhNGY3YmRiLCAweDY0YWQ4YzU3LCAweDg1NTEwNDQzLCAweGZhMDIwZWQxLFxuICAgIDB4N2UyODdhZmYsIDB4ZTYwZmI2NjMsIDB4MDk1ZjM1YTEsIDB4NzllYmYxMjAsIDB4ZmQwNTlkNDMsIDB4NjQ5N2I3YjEsIDB4ZjM2NDFmNjMsIDB4MjQxZTRhZGYsXG4gICAgMHgyODE0N2Y1ZiwgMHg0ZmEyYjhjZCwgMHhjOTQzMDA0MCwgMHgwY2MzMjIyMCwgMHhmZGQzMGIzMCwgMHhjMGE1Mzc0ZiwgMHgxZDJkMDBkOSwgMHgyNDE0N2IxNSxcbiAgICAweGVlNGQxMTFhLCAweDBmY2E1MTY3LCAweDcxZmY5MDRjLCAweDJkMTk1ZmZlLCAweDFhMDU2NDVmLCAweDBjMTNmZWZlLCAweDA4MWIwOGNhLCAweDA1MTcwMTIxLFxuICAgIDB4ODA1MzAxMDAsIDB4ZTgzZTVlZmUsIDB4YWM5YWY0ZjgsIDB4N2ZlNzI3MDEsIDB4ZDJiOGVlNWYsIDB4MDZkZjQyNjEsIDB4YmI5ZTliOGEsIDB4NzI5M2VhMjUsXG4gICAgMHhjZTg0ZmZkZiwgMHhmNTcxODgwMSwgMHgzZGQ2NGIwNCwgMHhhMjZmMjYzYiwgMHg3ZWQ0ODQwMCwgMHg1NDdlZWJlNiwgMHg0NDZkNGNhMCwgMHg2Y2YzZDZmNSxcbiAgICAweDI2NDlhYmRmLCAweGFlYTBjN2Y1LCAweDM2MzM4Y2MxLCAweDUwM2Y3ZTkzLCAweGQzNzcyMDYxLCAweDExYjYzOGUxLCAweDcyNTAwZTAzLCAweGY4MGViMmJiLFxuICAgIDB4YWJlMDUwMmUsIDB4ZWM4ZDc3ZGUsIDB4NTc5NzFlODEsIDB4ZTE0ZjY3NDYsIDB4YzkzMzU0MDAsIDB4NjkyMDMxOGYsIDB4MDgxZGJiOTksIDB4ZmZjMzA0YTUsXG4gICAgMHg0ZDM1MTgwNSwgMHg3ZjNkNWNlMywgMHhhNmM4NjZjNiwgMHg1ZDViY2NhOSwgMHhkYWVjNmZlYSwgMHg5ZjkyNmY5MSwgMHg5ZjQ2MjIyZiwgMHgzOTkxNDY3ZCxcbiAgICAweGE1YmY2ZDhlLCAweDExNDNjNDRmLCAweDQzOTU4MzAyLCAweGQwMjE0ZWViLCAweDAyMjA4M2I4LCAweDNmYjYxODBjLCAweDE4Zjg5MzFlLCAweDI4MTY1OGU2LFxuICAgIDB4MjY0ODZlM2UsIDB4OGJkNzhhNzAsIDB4NzQ3N2U0YzEsIDB4YjUwNmUwN2MsIDB4ZjMyZDBhMjUsIDB4NzkwOThiMDIsIDB4ZTRlYWJiODEsIDB4MjgxMjNiMjMsXG4gICAgMHg2OWRlYWQzOCwgMHgxNTc0Y2ExNiwgMHhkZjg3MWI2MiwgMHgyMTFjNDBiNywgMHhhNTFhOWVmOSwgMHgwMDE0Mzc3YiwgMHgwNDFlOGFjOCwgMHgwOTExNDAwMyxcbiAgICAweGJkNTllNGQyLCAweGUzZDE1NmQ1LCAweDRmZTg3NmQ1LCAweDJmOTFhMzQwLCAweDU1N2JlOGRlLCAweDAwZWFlNGE3LCAweDBjZTVjMmVjLCAweDRkYjRiYmE2LFxuICAgIDB4ZTc1NmJkZmYsIDB4ZGQzMzY5YWMsIDB4ZWMxN2IwMzUsIDB4MDY1NzIzMjcsIDB4OTlhZmM4YjAsIDB4NTZjOGMzOTEsIDB4NmI2NTgxMWMsIDB4NWUxNDYxMTksXG4gICAgMHg2ZTg1Y2I3NSwgMHhiZTA3YzAwMiwgMHhjMjMyNTU3NywgMHg4OTNmZjRlYywgMHg1YmJmYzkyZCwgMHhkMGVjM2IyNSwgMHhiNzgwMWFiNywgMHg4ZDZkM2IyNCxcbiAgICAweDIwYzc2M2VmLCAweGMzNjZhNWZjLCAweDljMzgyODgwLCAweDBhY2UzMjA1LCAweGFhYzk1NDhhLCAweGVjYTFkN2M3LCAweDA0MWFmYTMyLCAweDFkMTY2MjVhLFxuICAgIDB4NjcwMTkwMmMsIDB4OWI3NTdhNTQsIDB4MzFkNDc3ZjcsIDB4OTEyNmIwMzEsIDB4MzZjYzZmZGIsIDB4YzcwYjhiNDYsIDB4ZDllNjZhNDgsIDB4NTZlNTVhNzksXG4gICAgMHgwMjZhNGNlYiwgMHg1MjQzN2VmZiwgMHgyZjhmNzZiNCwgMHgwZGY5ODBhNSwgMHg4Njc0Y2RlMywgMHhlZGRhMDRlYiwgMHgxN2E5YmUwNCwgMHgyYzE4ZjRkZixcbiAgICAweGI3NzQ3ZjlkLCAweGFiMmFmN2I0LCAweGVmYzM0ZDIwLCAweDJlMDk2YjdjLCAweDE3NDFhMjU0LCAweGU1YjZhMDM1LCAweDIxM2Q0MmY2LCAweDJjMWM3YzI2LFxuICAgIDB4NjFjMmY1MGYsIDB4NjU1MmRhZjksIDB4ZDJjMjMxZjgsIDB4MjUxMzBmNjksIDB4ZDgxNjdmYTIsIDB4MDQxOGYyYzgsIDB4MDAxYTk2YTYsIDB4MGQxNTI2YWIsXG4gICAgMHg2MzMxNWMyMSwgMHg1ZTBhNzJlYywgMHg0OWJhZmVmZCwgMHgxODc5MDhkOSwgMHg4ZDBkYmQ4NiwgMHgzMTExNzBhNywgMHgzZTliNjQwYywgMHhjYzNlMTBkNyxcbiAgICAweGQ1Y2FkM2I2LCAweDBjYWVjMzg4LCAweGY3MzAwMWUxLCAweDZjNzI4YWZmLCAweDcxZWFlMmExLCAweDFmOWFmMzZlLCAweGNmY2JkMTJmLCAweGMxZGU4NDE3LFxuICAgIDB4YWMwN2JlNmIsIDB4Y2I0NGExZDgsIDB4OGI5YjBmNTYsIDB4MDEzOTg4YzMsIDB4YjFjNTJmY2EsIDB4YjRiZTMxY2QsIDB4ZDg3ODI4MDYsIDB4MTJhM2E0ZTIsXG4gICAgMHg2ZjdkZTUzMiwgMHg1OGZkN2ViNiwgMHhkMDFlZTkwMCwgMHgyNGFkZmZjMiwgMHhmNDk5MGZjNSwgMHg5NzExYWFjNSwgMHgwMDFkN2I5NSwgMHg4MmU1ZTdkMixcbiAgICAweDEwOTg3M2Y2LCAweDAwNjEzMDk2LCAweGMzMmQ5NTIxLCAweGFkYTEyMWZmLCAweDI5OTA4NDE1LCAweDdmYmI5NzdmLCAweGFmOWViM2RiLCAweDI5YzllZDJhLFxuICAgIDB4NWNlMmE0NjUsIDB4YTczMGYzMmMsIDB4ZDBhYTNmZTgsIDB4OGE1Y2MwOTEsIDB4ZDQ5ZTJjZTcsIDB4MGNlNDU0YTksIDB4ZDYwYWNkODYsIDB4MDE1ZjE5MTksXG4gICAgMHg3NzA3OTEwMywgMHhkZWEwM2FmNiwgMHg3OGE4NTY1ZSwgMHhkZWUzNTZkZiwgMHgyMWYwNWNiZSwgMHg4Yjc1ZTM4NywgMHhiM2M1MDY1MSwgMHhiOGE1YzNlZixcbiAgICAweGQ4ZWViNmQyLCAweGU1MjNiZTc3LCAweGMyMTU0NTI5LCAweDJmNjllZmRmLCAweGFmZTY3YWZiLCAweGY0NzBjNGIyLCAweGYzZTBlYjViLCAweGQ2Y2M5ODc2LFxuICAgIDB4MzllNDQ2MGMsIDB4MWZkYTg1MzgsIDB4MTk4NzgzMmYsIDB4Y2EwMDczNjcsIDB4YTk5MTQ0ZjgsIDB4Mjk2YjI5OWUsIDB4NDkyZmMyOTUsIDB4OTI2NmJlYWIsXG4gICAgMHhiNTY3NmU2OSwgMHg5YmQzZGRkYSwgMHhkZjdlMDUyZiwgMHhkYjI1NzAxYywgMHgxYjVlNTFlZSwgMHhmNjUzMjRlNiwgMHg2YWZjZTM2YywgMHgwMzE2Y2MwNCxcbiAgICAweDg2NDQyMTNlLCAweGI3ZGM1OWQwLCAweDc5NjUyOTFmLCAweGNjZDZmZDQzLCAweDQxODIzOTc5LCAweDkzMmJjZGY2LCAweGI2NTdjMzRkLCAweDRlZGZkMjgyLFxuICAgIDB4N2FlNTI5MGMsIDB4M2NiOTUzNmIsIDB4ODUxZTIwZmUsIDB4OTgzMzU1N2UsIDB4MTNlY2YwYjAsIDB4ZDNmZmIzNzIsIDB4M2Y4NWM1YzEsIDB4MGFlZjdlZDIpO1xuXG4gIHNCb3hbNF0gPSBuZXcgQXJyYXkoXG4gICAgMHg3ZWM5MGMwNCwgMHgyYzZlNzRiOSwgMHg5YjBlNjZkZiwgMHhhNjMzNzkxMSwgMHhiODZhN2ZmZiwgMHgxZGQzNThmNSwgMHg0NGRkOWQ0NCwgMHgxNzMxMTY3ZixcbiAgICAweDA4ZmJmMWZhLCAweGU3ZjUxMWNjLCAweGQyMDUxYjAwLCAweDczNWFiYTAwLCAweDJhYjcyMmQ4LCAweDM4NjM4MWNiLCAweGFjZjYyNDNhLCAweDY5YmVmZDdhLFxuICAgIDB4ZTZhMmU3N2YsIDB4ZjBjNzIwY2QsIDB4YzQ0OTQ4MTYsIDB4Y2NmNWMxODAsIDB4Mzg4NTE2NDAsIDB4MTViMGE4NDgsIDB4ZTY4YjE4Y2IsIDB4NGNhYWRlZmYsXG4gICAgMHg1ZjQ4MGEwMSwgMHgwNDEyYjJhYSwgMHgyNTk4MTRmYywgMHg0MWQwZWZlMiwgMHg0ZTQwYjQ4ZCwgMHgyNDhlYjZmYiwgMHg4ZGJhMWNmZSwgMHg0MWE5OWIwMixcbiAgICAweDFhNTUwYTA0LCAweGJhOGY2NWNiLCAweDcyNTFmNGU3LCAweDk1YTUxNzI1LCAweGMxMDZlY2Q3LCAweDk3YTU5ODBhLCAweGM1MzliOWFhLCAweDRkNzlmZTZhLFxuICAgIDB4ZjJmM2Y3NjMsIDB4NjhhZjgwNDAsIDB4ZWQwYzllNTYsIDB4MTFiNDk1OGIsIDB4ZTFlYjVhODgsIDB4ODcwOWU2YjAsIDB4ZDdlMDcxNTYsIDB4NGUyOWZlYTcsXG4gICAgMHg2MzY2ZTUyZCwgMHgwMmQxYzAwMCwgMHhjNGFjOGUwNSwgMHg5Mzc3ZjU3MSwgMHgwYzA1MzcyYSwgMHg1Nzg1MzVmMiwgMHgyMjYxYmUwMiwgMHhkNjQyYTBjOSxcbiAgICAweGRmMTNhMjgwLCAweDc0YjU1YmQyLCAweDY4MjE5OWMwLCAweGQ0MjFlNWVjLCAweDUzZmIzY2U4LCAweGM4YWRlZGIzLCAweDI4YTg3ZmM5LCAweDNkOTU5OTgxLFxuICAgIDB4NWMxZmY5MDAsIDB4ZmUzOGQzOTksIDB4MGM0ZWZmMGIsIDB4MDYyNDA3ZWEsIDB4YWEyZjRmYjEsIDB4NGZiOTY5NzYsIDB4OTBjNzk1MDUsIDB4YjBhOGE3NzQsXG4gICAgMHhlZjU1YTFmZiwgMHhlNTljYTJjMiwgMHhhNmI2MmQyNywgMHhlNjZhNDI2MywgMHhkZjY1MDAxZiwgMHgwZWM1MDk2NiwgMHhkZmRkNTViYywgMHgyOWRlMDY1NSxcbiAgICAweDkxMWU3MzlhLCAweDE3YWY4OTc1LCAweDMyYzc5MTFjLCAweDg5Zjg5NDY4LCAweDBkMDFlOTgwLCAweDUyNDc1NWY0LCAweDAzYjYzY2M5LCAweDBjYzg0NGIyLFxuICAgIDB4YmNmM2YwYWEsIDB4ODdhYzM2ZTksIDB4ZTUzYTc0MjYsIDB4MDFiM2Q4MmIsIDB4MWE5ZTc0NDksIDB4NjRlZTJkN2UsIDB4Y2RkYmIxZGEsIDB4MDFjOTQ5MTAsXG4gICAgMHhiODY4YmY4MCwgMHgwZDI2ZjNmZCwgMHg5MzQyZWRlNywgMHgwNGE1YzI4NCwgMHg2MzY3MzdiNiwgMHg1MGY1YjYxNiwgMHhmMjQ3NjZlMywgMHg4ZWNhMzZjMSxcbiAgICAweDEzNmUwNWRiLCAweGZlZjE4MzkxLCAweGZiODg3YTM3LCAweGQ2ZTdmN2Q0LCAweGM3ZmI3ZGM5LCAweDMwNjNmY2RmLCAweGI2ZjU4OWRlLCAweGVjMjk0MWRhLFxuICAgIDB4MjZlNDY2OTUsIDB4Yjc1NjY0MTksIDB4ZjY1NGVmYzUsIDB4ZDA4ZDU4YjcsIDB4NDg5MjU0MDEsIDB4YzFiYWNiN2YsIDB4ZTVmZjU1MGYsIDB4YjYwODMwNDksXG4gICAgMHg1YmI1ZDBlOCwgMHg4N2Q3MmU1YSwgMHhhYjZhNmVlMSwgMHgyMjNhNjZjZSwgMHhjNjJiZjNjZCwgMHg5ZTA4ODVmOSwgMHg2OGNiM2U0NywgMHgwODZjMDEwZixcbiAgICAweGEyMWRlODIwLCAweGQxOGI2OWRlLCAweGYzZjY1Nzc3LCAweGZhMDJjM2Y2LCAweDQwN2VkYWMzLCAweGNiYjNkNTUwLCAweDE3OTMwODRkLCAweGIwZDcwZWJhLFxuICAgIDB4MGFiMzc4ZDUsIDB4ZDk1MWZiMGMsIDB4ZGVkN2RhNTYsIDB4NDEyNGJiZTQsIDB4OTRjYTBiNTYsIDB4MGY1NzU1ZDEsIDB4ZTBlMWU1NmUsIDB4NjE4NGI1YmUsXG4gICAgMHg1ODBhMjQ5ZiwgMHg5NGY3NGJjMCwgMHhlMzI3ODg4ZSwgMHg5ZjdiNTU2MSwgMHhjM2RjMDI4MCwgMHgwNTY4NzcxNSwgMHg2NDZjNmJkNywgMHg0NDkwNGRiMyxcbiAgICAweDY2YjRmMGEzLCAweGMwZjE2NDhhLCAweDY5N2VkNWFmLCAweDQ5ZTkyZmY2LCAweDMwOWUzNzRmLCAweDJjYjYzNTZhLCAweDg1ODA4NTczLCAweDQ5OTFmODQwLFxuICAgIDB4NzZmMGFlMDIsIDB4MDgzYmU4NGQsIDB4Mjg0MjFjOWEsIDB4NDQ0ODk0MDYsIDB4NzM2ZTRjYjgsIDB4YzEwOTI5MTAsIDB4OGJjOTVmYzYsIDB4N2Q4NjljZjQsXG4gICAgMHgxMzRmNjE2ZiwgMHgyZTc3MTE4ZCwgMHhiMzFiMmJlMSwgMHhhYTkwYjQ3MiwgMHgzY2E1ZDcxNywgMHg3ZDE2MWJiYSwgMHg5Y2FkOTAxMCwgMHhhZjQ2MmJhMixcbiAgICAweDlmZTQ1OWQyLCAweDQ1ZDM0NTU5LCAweGQ5ZjJkYTEzLCAweGRiYzY1NDg3LCAweGYzZTRmOTRlLCAweDE3NmQ0ODZmLCAweDA5N2MxM2VhLCAweDYzMWRhNWM3LFxuICAgIDB4NDQ1ZjczODIsIDB4MTc1NjgzZjQsIDB4Y2RjNjZhOTcsIDB4NzBiZTAyODgsIDB4YjNjZGNmNzIsIDB4NmU1ZGQyZjMsIDB4MjA5MzYwNzksIDB4NDU5YjgwYTUsXG4gICAgMHhiZTYwZTJkYiwgMHhhOWMyMzEwMSwgMHhlYmE1MzE1YywgMHgyMjRlNDJmMiwgMHgxYzVjMTU3MiwgMHhmNjcyMWIyYywgMHgxYWQyZmZmMywgMHg4YzI1NDA0ZSxcbiAgICAweDMyNGVkNzJmLCAweDQwNjdiN2ZkLCAweDA1MjMxMzhlLCAweDVjYTNiYzc4LCAweGRjMGZkNjZlLCAweDc1OTIyMjgzLCAweDc4NGQ2YjE3LCAweDU4ZWJiMTZlLFxuICAgIDB4NDQwOTRmODUsIDB4M2Y0ODFkODcsIDB4ZmNmZWFlN2IsIDB4NzdiNWZmNzYsIDB4OGMyMzAyYmYsIDB4YWFmNDc1NTYsIDB4NWY0NmIwMmEsIDB4MmIwOTI4MDEsXG4gICAgMHgzZDM4ZjVmNywgMHgwY2E4MWYzNiwgMHg1MmFmNGE4YSwgMHg2NmQ1ZTdjMCwgMHhkZjNiMDg3NCwgMHg5NTA1NTExMCwgMHgxYjVhZDdhOCwgMHhmNjFlZDVhZCxcbiAgICAweDZjZjZlNDc5LCAweDIwNzU4MTg0LCAweGQwY2VmYTY1LCAweDg4ZjdiZTU4LCAweDRhMDQ2ODI2LCAweDBmZjZmOGYzLCAweGEwOWM3ZjcwLCAweDUzNDZhYmEwLFxuICAgIDB4NWNlOTZjMjgsIDB4ZTE3NmVkYTMsIDB4NmJhYzMwN2YsIDB4Mzc2ODI5ZDIsIDB4ODUzNjBmYTksIDB4MTdlM2ZlMmEsIDB4MjRiNzk3NjcsIDB4ZjVhOTZiMjAsXG4gICAgMHhkNmNkMjU5NSwgMHg2OGZmMWViZiwgMHg3NTU1NDQyYywgMHhmMTlmMDZiZSwgMHhmOWUwNjU5YSwgMHhlZWI5NDkxZCwgMHgzNDAxMDcxOCwgMHhiYjMwY2FiOCxcbiAgICAweGU4MjJmZTE1LCAweDg4NTcwOTgzLCAweDc1MGU2MjQ5LCAweGRhNjI3ZTU1LCAweDVlNzZmZmE4LCAweGIxNTM0NTQ2LCAweDZkNDdkZTA4LCAweGVmZTllN2Q0KTtcblxuICBzQm94WzVdID0gbmV3IEFycmF5KFxuICAgIDB4ZjZmYThmOWQsIDB4MmNhYzZjZTEsIDB4NGNhMzQ4NjcsIDB4ZTIzMzdmN2MsIDB4OTVkYjA4ZTcsIDB4MDE2ODQzYjQsIDB4ZWNlZDVjYmMsIDB4MzI1NTUzYWMsXG4gICAgMHhiZjlmMDk2MCwgMHhkZmExZTJlZCwgMHg4M2YwNTc5ZCwgMHg2M2VkODZiOSwgMHgxYWI2YTZiOCwgMHhkZTVlYmUzOSwgMHhmMzhmZjczMiwgMHg4OTg5YjEzOCxcbiAgICAweDMzZjE0OTYxLCAweGMwMTkzN2JkLCAweGY1MDZjNmRhLCAweGU0NjI1ZTdlLCAweGEzMDhlYTk5LCAweDRlMjNlMzNjLCAweDc5Y2JkN2NjLCAweDQ4YTE0MzY3LFxuICAgIDB4YTMxNDk2MTksIDB4ZmVjOTRiZDUsIDB4YTExNDE3NGEsIDB4ZWFhMDE4NjYsIDB4YTA4NGRiMmQsIDB4MDlhODQ4NmYsIDB4YTg4ODYxNGEsIDB4MjkwMGFmOTgsXG4gICAgMHgwMTY2NTk5MSwgMHhlMTk5Mjg2MywgMHhjOGYzMGM2MCwgMHgyZTc4ZWYzYywgMHhkMGQ1MTkzMiwgMHhjZjBmZWMxNCwgMHhmN2NhMDdkMiwgMHhkMGE4MjA3MixcbiAgICAweGZkNDExOTdlLCAweDkzMDVhNmIwLCAweGU4NmJlM2RhLCAweDc0YmVkM2NkLCAweDM3MmRhNTNjLCAweDRjN2Y0NDQ4LCAweGRhYjVkNDQwLCAweDZkYmEwZWMzLFxuICAgIDB4MDgzOTE5YTcsIDB4OWZiYWVlZDksIDB4NDlkYmNmYjAsIDB4NGU2NzBjNTMsIDB4NWMzZDljMDEsIDB4NjRiZGI5NDEsIDB4MmMwZTYzNmEsIDB4YmE3ZGQ5Y2QsXG4gICAgMHhlYTZmNzM4OCwgMHhlNzBiYzc2MiwgMHgzNWYyOWFkYiwgMHg1YzRjZGQ4ZCwgMHhmMGQ0OGQ4YywgMHhiODgxNTNlMiwgMHgwOGExOTg2NiwgMHgxYWUyZWFjOCxcbiAgICAweDI4NGNhZjg5LCAweGFhOTI4MjIzLCAweDkzMzRiZTUzLCAweDNiM2EyMWJmLCAweDE2NDM0YmUzLCAweDlhZWEzOTA2LCAweGVmZThjMzZlLCAweGY4OTBjZGQ5LFxuICAgIDB4ODAyMjZkYWUsIDB4YzM0MGE0YTMsIDB4ZGY3ZTljMDksIDB4YTY5NGE4MDcsIDB4NWI3YzVlY2MsIDB4MjIxZGIzYTYsIDB4OWE2OWEwMmYsIDB4Njg4MThhNTQsXG4gICAgMHhjZWIyMjk2ZiwgMHg1M2MwODQzYSwgMHhmZTg5MzY1NSwgMHgyNWJmZTY4YSwgMHhiNDYyOGFiYywgMHhjZjIyMmViZiwgMHgyNWFjNmY0OCwgMHhhOWE5OTM4NyxcbiAgICAweDUzYmRkYjY1LCAweGU3NmZmYmU3LCAweGU5NjdmZDc4LCAweDBiYTkzNTYzLCAweDhlMzQyYmMxLCAweGU4YTExYmU5LCAweDQ5ODA3NDBkLCAweGM4MDg3ZGZjLFxuICAgIDB4OGRlNGJmOTksIDB4YTExMTAxYTAsIDB4N2ZkMzc5NzUsIDB4ZGE1YTI2YzAsIDB4ZTgxZjk5NGYsIDB4OTUyOGNkODksIDB4ZmQzMzlmZWQsIDB4Yjg3ODM0YmYsXG4gICAgMHg1ZjA0NDU2ZCwgMHgyMjI1ODY5OCwgMHhjOWM0YzgzYiwgMHgyZGMxNTZiZSwgMHg0ZjYyOGRhYSwgMHg1N2Y1NWVjNSwgMHhlMjIyMGFiZSwgMHhkMjkxNmViZixcbiAgICAweDRlYzc1Yjk1LCAweDI0ZjJjM2MwLCAweDQyZDE1ZDk5LCAweGNkMGQ3ZmEwLCAweDdiNmUyN2ZmLCAweGE4ZGM4YWYwLCAweDczNDVjMTA2LCAweGY0MWUyMzJmLFxuICAgIDB4MzUxNjIzODYsIDB4ZTZlYTg5MjYsIDB4MzMzM2IwOTQsIDB4MTU3ZWM2ZjIsIDB4MzcyYjc0YWYsIDB4NjkyNTczZTQsIDB4ZTlhOWQ4NDgsIDB4ZjMxNjAyODksXG4gICAgMHgzYTYyZWYxZCwgMHhhNzg3ZTIzOCwgMHhmM2E1ZjY3NiwgMHg3NDM2NDg1MywgMHgyMDk1MTA2MywgMHg0NTc2Njk4ZCwgMHhiNmZhZDQwNywgMHg1OTJhZjk1MCxcbiAgICAweDM2ZjczNTIzLCAweDRjZmI2ZTg3LCAweDdkYTRjZWMwLCAweDZjMTUyZGFhLCAweGNiMDM5NmE4LCAweGM1MGRmZTVkLCAweGZjZDcwN2FiLCAweDA5MjFjNDJmLFxuICAgIDB4ODlkZmYwYmIsIDB4NWZlMmJlNzgsIDB4NDQ4ZjRmMzMsIDB4NzU0NjEzYzksIDB4MmIwNWQwOGQsIDB4NDhiOWQ1ODUsIDB4ZGMwNDk0NDEsIDB4YzgwOThmOWIsXG4gICAgMHg3ZGVkZTc4NiwgMHhjMzlhMzM3MywgMHg0MjQxMDAwNSwgMHg2YTA5MTc1MSwgMHgwZWYzYzhhNiwgMHg4OTAwNzJkNiwgMHgyODIwNzY4MiwgMHhhOWE5ZjdiZSxcbiAgICAweGJmMzI2NzlkLCAweGQ0NWI1Yjc1LCAweGIzNTNmZDAwLCAweGNiYjBlMzU4LCAweDgzMGYyMjBhLCAweDFmOGZiMjE0LCAweGQzNzJjZjA4LCAweGNjM2M0YTEzLFxuICAgIDB4OGNmNjMxNjYsIDB4MDYxYzg3YmUsIDB4ODhjOThmODgsIDB4NjA2MmUzOTcsIDB4NDdjZjhlN2EsIDB4YjZjODUyODMsIDB4M2NjMmFjZmIsIDB4M2ZjMDY5NzYsXG4gICAgMHg0ZThmMDI1MiwgMHg2NGQ4MzE0ZCwgMHhkYTM4NzBlMywgMHgxZTY2NTQ1OSwgMHhjMTA5MDhmMCwgMHg1MTMwMjFhNSwgMHg2YzViNjhiNywgMHg4MjJmOGFhMCxcbiAgICAweDMwMDdjZDNlLCAweDc0NzE5ZWVmLCAweGRjODcyNjgxLCAweDA3MzM0MGQ0LCAweDdlNDMyZmQ5LCAweDBjNWVjMjQxLCAweDg4MDkyODZjLCAweGY1OTJkODkxLFxuICAgIDB4MDhhOTMwZjYsIDB4OTU3ZWYzMDUsIDB4YjdmYmZmYmQsIDB4YzI2NmU5NmYsIDB4NmZlNGFjOTgsIDB4YjE3M2VjYzAsIDB4YmM2MGI0MmEsIDB4OTUzNDk4ZGEsXG4gICAgMHhmYmExYWUxMiwgMHgyZDRiZDczNiwgMHgwZjI1ZmFhYiwgMHhhNGYzZmNlYiwgMHhlMjk2OTEyMywgMHgyNTdmMGMzZCwgMHg5MzQ4YWY0OSwgMHgzNjE0MDBiYyxcbiAgICAweGU4ODE2ZjRhLCAweDM4MTRmMjAwLCAweGEzZjk0MDQzLCAweDljN2E1NGMyLCAweGJjNzA0ZjU3LCAweGRhNDFlN2Y5LCAweGMyNWFkMzNhLCAweDU0ZjRhMDg0LFxuICAgIDB4YjE3ZjU1MDUsIDB4NTkzNTdjYmUsIDB4ZWRiZDE1YzgsIDB4N2Y5N2M1YWIsIDB4YmE1YWM3YjUsIDB4YjZmNmRlYWYsIDB4M2E0NzljM2EsIDB4NTMwMmRhMjUsXG4gICAgMHg2NTNkN2U2YSwgMHg1NDI2OGQ0OSwgMHg1MWE0NzdlYSwgMHg1MDE3ZDU1YiwgMHhkN2QyNWQ4OCwgMHg0NDEzNmM3NiwgMHgwNDA0YThjOCwgMHhiOGU1YTEyMSxcbiAgICAweGI4MWE5MjhhLCAweDYwZWQ1ODY5LCAweDk3YzU1Yjk2LCAweGVhZWM5OTFiLCAweDI5OTM1OTEzLCAweDAxZmRiN2YxLCAweDA4OGU4ZGZhLCAweDlhYjZmNmY1LFxuICAgIDB4M2I0Y2JmOWYsIDB4NGE1ZGUzYWIsIDB4ZTYwNTFkMzUsIDB4YTBlMWQ4NTUsIDB4ZDM2YjRjZjEsIDB4ZjU0NGVkZWIsIDB4YjBlOTM1MjQsIDB4YmViYjhmYmQsXG4gICAgMHhhMmQ3NjJjZiwgMHg0OWM5MmY1NCwgMHgzOGI1ZjMzMSwgMHg3MTI4YTQ1NCwgMHg0ODM5MjkwNSwgMHhhNjViMWRiOCwgMHg4NTFjOTdiZCwgMHhkNjc1Y2YyZik7XG5cbiAgc0JveFs2XSA9IG5ldyBBcnJheShcbiAgICAweDg1ZTA0MDE5LCAweDMzMmJmNTY3LCAweDY2MmRiZmZmLCAweGNmYzY1NjkzLCAweDJhOGQ3ZjZmLCAweGFiOWJjOTEyLCAweGRlNjAwOGExLCAweDIwMjhkYTFmLFxuICAgIDB4MDIyN2JjZTcsIDB4NGQ2NDI5MTYsIDB4MThmYWMzMDAsIDB4NTBmMThiODIsIDB4MmNiMmNiMTEsIDB4YjIzMmU3NWMsIDB4NGIzNjk1ZjIsIDB4YjI4NzA3ZGUsXG4gICAgMHhhMDVmYmNmNiwgMHhjZDQxODFlOSwgMHhlMTUwMjEwYywgMHhlMjRlZjFiZCwgMHhiMTY4YzM4MSwgMHhmZGU0ZTc4OSwgMHg1Yzc5YjBkOCwgMHgxZThiZmQ0MyxcbiAgICAweDRkNDk1MDAxLCAweDM4YmU0MzQxLCAweDkxM2NlZTFkLCAweDkyYTc5YzNmLCAweDA4OTc2NmJlLCAweGJhZWVhZGY0LCAweDEyODZiZWNmLCAweGI2ZWFjYjE5LFxuICAgIDB4MjY2MGMyMDAsIDB4NzU2NWJkZTQsIDB4NjQyNDFmN2EsIDB4ODI0OGRjYTksIDB4YzNiM2FkNjYsIDB4MjgxMzYwODYsIDB4MGJkOGRmYTgsIDB4MzU2ZDFjZjIsXG4gICAgMHgxMDc3ODliZSwgMHhiM2IyZTljZSwgMHgwNTAyYWE4ZiwgMHgwYmMwMzUxZSwgMHgxNjZiZjUyYSwgMHhlYjEyZmY4MiwgMHhlMzQ4NjkxMSwgMHhkMzRkNzUxNixcbiAgICAweDRlN2IzYWZmLCAweDVmNDM2NzFiLCAweDljZjZlMDM3LCAweDQ5ODFhYzgzLCAweDMzNDI2NmNlLCAweDhjOTM0MWI3LCAweGQwZDg1NGMwLCAweGNiM2E2Yzg4LFxuICAgIDB4NDdiYzI4MjksIDB4NDcyNWJhMzcsIDB4YTY2YWQyMmIsIDB4N2FkNjFmMWUsIDB4MGM1Y2JhZmEsIDB4NDQzN2YxMDcsIDB4YjZlNzk5NjIsIDB4NDJkMmQ4MTYsXG4gICAgMHgwYTk2MTI4OCwgMHhlMWE1YzA2ZSwgMHgxMzc0OWU2NywgMHg3MmZjMDgxYSwgMHhiMWQxMzlmNywgMHhmOTU4Mzc0NSwgMHhjZjE5ZGY1OCwgMHhiZWMzZjc1NixcbiAgICAweGMwNmViYTMwLCAweDA3MjExYjI0LCAweDQ1YzI4ODI5LCAweGM5NWUzMTdmLCAweGJjOGVjNTExLCAweDM4YmM0NmU5LCAweGM2ZTZmYTE0LCAweGJhZTg1ODRhLFxuICAgIDB4YWQ0ZWJjNDYsIDB4NDY4ZjUwOGIsIDB4NzgyOTQzNWYsIDB4ZjEyNDE4M2IsIDB4ODIxZGJhOWYsIDB4YWZmNjBmZjQsIDB4ZWEyYzRlNmQsIDB4MTZlMzkyNjQsXG4gICAgMHg5MjU0NGE4YiwgMHgwMDliNGZjMywgMHhhYmE2OGNlZCwgMHg5YWM5NmY3OCwgMHgwNmE1Yjc5YSwgMHhiMjg1NmU2ZSwgMHgxYWVjM2NhOSwgMHhiZTgzODY4OCxcbiAgICAweDBlMDgwNGU5LCAweDU1ZjFiZTU2LCAweGU3ZTUzNjNiLCAweGIzYTFmMjVkLCAweGY3ZGViYjg1LCAweDYxZmUwMzNjLCAweDE2NzQ2MjMzLCAweDNjMDM0YzI4LFxuICAgIDB4ZGE2ZDBjNzQsIDB4NzlhYWM1NmMsIDB4M2NlNGUxYWQsIDB4NTFmMGM4MDIsIDB4OThmOGYzNWEsIDB4MTYyNmE0OWYsIDB4ZWVkODJiMjksIDB4MWQzODJmZTMsXG4gICAgMHgwYzRmYjk5YSwgMHhiYjMyNTc3OCwgMHgzZWM2ZDk3YiwgMHg2ZTc3YTZhOSwgMHhjYjY1OGI1YywgMHhkNDUyMzBjNywgMHgyYmQxNDA4YiwgMHg2MGMwM2ViNyxcbiAgICAweGI5MDY4ZDc4LCAweGEzMzc1NGY0LCAweGY0MzBjODdkLCAweGM4YTcxMzAyLCAweGI5NmQ4YzMyLCAweGViZDRlN2JlLCAweGJlOGI5ZDJkLCAweDc5NzlmYjA2LFxuICAgIDB4ZTcyMjUzMDgsIDB4OGI3NWNmNzcsIDB4MTFlZjhkYTQsIDB4ZTA4M2M4NTgsIDB4OGQ2Yjc4NmYsIDB4NWE2MzE3YTYsIDB4ZmE1Y2Y3YTAsIDB4NWRkYTAwMzMsXG4gICAgMHhmMjhlYmZiMCwgMHhmNWI5YzMxMCwgMHhhMGVhYzI4MCwgMHgwOGI5NzY3YSwgMHhhM2Q5ZDJiMCwgMHg3OWQzNDIxNywgMHgwMjFhNzE4ZCwgMHg5YWM2MzM2YSxcbiAgICAweDI3MTFmZDYwLCAweDQzODA1MGUzLCAweDA2OTkwOGE4LCAweDNkN2ZlZGM0LCAweDgyNmQyYmVmLCAweDRlZWI4NDc2LCAweDQ4OGRjZjI1LCAweDM2YzlkNTY2LFxuICAgIDB4MjhlNzRlNDEsIDB4YzI2MTBhY2EsIDB4M2Q0OWE5Y2YsIDB4YmFlM2I5ZGYsIDB4YjY1ZjhkZTYsIDB4OTJhZWFmNjQsIDB4M2FjN2Q1ZTYsIDB4OWVhODA1MDksXG4gICAgMHhmMjJiMDE3ZCwgMHhhNDE3M2Y3MCwgMHhkZDFlMTZjMywgMHgxNWUwZDdmOSwgMHg1MGIxYjg4NywgMHgyYjlmNGZkNSwgMHg2MjVhYmE4MiwgMHg2YTAxNzk2MixcbiAgICAweDJlYzAxYjljLCAweDE1NDg4YWE5LCAweGQ3MTZlNzQwLCAweDQwMDU1YTJjLCAweDkzZDI5YTIyLCAweGUzMmRiZjlhLCAweDA1ODc0NWI5LCAweDM0NTNkYzFlLFxuICAgIDB4ZDY5OTI5NmUsIDB4NDk2Y2ZmNmYsIDB4MWM5ZjQ5ODYsIDB4ZGZlMmVkMDcsIDB4Yjg3MjQyZDEsIDB4MTlkZTdlYWUsIDB4MDUzZTU2MWEsIDB4MTVhZDZmOGMsXG4gICAgMHg2NjYyNmMxYywgMHg3MTU0YzI0YywgMHhlYTA4MmIyYSwgMHg5M2ViMjkzOSwgMHgxN2RjYjBmMCwgMHg1OGQ0ZjJhZSwgMHg5ZWEyOTRmYiwgMHg1MmNmNTY0YyxcbiAgICAweDk4ODNmZTY2LCAweDJlYzQwNTgxLCAweDc2Mzk1M2MzLCAweDAxZDY2OTJlLCAweGQzYTBjMTA4LCAweGExZTcxNjBlLCAweGU0ZjJkZmE2LCAweDY5M2VkMjg1LFxuICAgIDB4NzQ5MDQ2OTgsIDB4NGMyYjBlZGQsIDB4NGY3NTc2NTYsIDB4NWQzOTMzNzgsIDB4YTEzMjIzNGYsIDB4M2QzMjFjNWQsIDB4YzNmNWUxOTQsIDB4NGIyNjkzMDEsXG4gICAgMHhjNzlmMDIyZiwgMHgzYzk5N2U3ZSwgMHg1ZTRmOTUwNCwgMHgzZmZhZmJiZCwgMHg3NmY3YWQwZSwgMHgyOTY2OTNmNCwgMHgzZDFmY2U2ZiwgMHhjNjFlNDViZSxcbiAgICAweGQzYjVhYjM0LCAweGY3MmJmOWI3LCAweDFiMDQzNGMwLCAweDRlNzJiNTY3LCAweDU1OTJhMzNkLCAweGI1MjI5MzAxLCAweGNmZDJhODdmLCAweDYwYWViNzY3LFxuICAgIDB4MTgxNDM4NmIsIDB4MzBiY2MzM2QsIDB4MzhhMGMwN2QsIDB4ZmQxNjA2ZjIsIDB4YzM2MzUxOWIsIDB4NTg5ZGQzOTAsIDB4NTQ3OWY4ZTYsIDB4MWNiOGQ2NDcsXG4gICAgMHg5N2ZkNjFhOSwgMHhlYTc3NTlmNCwgMHgyZDU3NTM5ZCwgMHg1NjlhNThjZiwgMHhlODRlNjNhZCwgMHg0NjJlMWI3OCwgMHg2NTgwZjg3ZSwgMHhmMzgxNzkxNCxcbiAgICAweDkxZGE1NWY0LCAweDQwYTIzMGYzLCAweGQxOTg4ZjM1LCAweGI2ZTMxOGQyLCAweDNmZmE1MGJjLCAweDNkNDBmMDIxLCAweGMzYzBiZGFlLCAweDQ5NThjMjRjLFxuICAgIDB4NTE4ZjM2YjIsIDB4ODRiMWQzNzAsIDB4MGZlZGNlODMsIDB4ODc4ZGRhZGEsIDB4ZjJhMjc5YzcsIDB4OTRlMDFiZTgsIDB4OTA3MTZmNGIsIDB4OTU0YjhhYTMpO1xuXG4gIHNCb3hbN10gPSBuZXcgQXJyYXkoXG4gICAgMHhlMjE2MzAwZCwgMHhiYmRkZmZmYywgMHhhN2ViZGFiZCwgMHgzNTY0ODA5NSwgMHg3Nzg5ZjhiNywgMHhlNmMxMTIxYiwgMHgwZTI0MTYwMCwgMHgwNTJjZThiNSxcbiAgICAweDExYTljZmIwLCAweGU1OTUyZjExLCAweGVjZTc5OTBhLCAweDkzODZkMTc0LCAweDJhNDI5MzFjLCAweDc2ZTM4MTExLCAweGIxMmRlZjNhLCAweDM3ZGRkZGZjLFxuICAgIDB4ZGU5YWRlYjEsIDB4MGEwY2MzMmMsIDB4YmUxOTcwMjksIDB4ODRhMDA5NDAsIDB4YmIyNDNhMGYsIDB4YjRkMTM3Y2YsIDB4YjQ0ZTc5ZjAsIDB4MDQ5ZWVkZmQsXG4gICAgMHgwYjE1YTE1ZCwgMHg0ODBkMzE2OCwgMHg4YmJiZGU1YSwgMHg2NjlkZWQ0MiwgMHhjN2VjZTgzMSwgMHgzZjhmOTVlNywgMHg3MmRmMTkxYiwgMHg3NTgwMzMwZCxcbiAgICAweDk0MDc0MjUxLCAweDVjN2RjZGZhLCAweGFiYmU2ZDYzLCAweGFhNDAyMTY0LCAweGIzMDFkNDBhLCAweDAyZTdkMWNhLCAweDUzNTcxZGFlLCAweDdhMzE4MmEyLFxuICAgIDB4MTJhOGRkZWMsIDB4ZmRhYTMzNWQsIDB4MTc2ZjQzZTgsIDB4NzFmYjQ2ZDQsIDB4MzgxMjkwMjIsIDB4Y2U5NDlhZDQsIDB4Yjg0NzY5YWQsIDB4OTY1YmQ4NjIsXG4gICAgMHg4MmYzZDA1NSwgMHg2NmZiOTc2NywgMHgxNWI4MGI0ZSwgMHgxZDViNDdhMCwgMHg0Y2ZkZTA2ZiwgMHhjMjhlYzRiOCwgMHg1N2U4NzI2ZSwgMHg2NDdhNzhmYyxcbiAgICAweDk5ODY1ZDQ0LCAweDYwOGJkNTkzLCAweDZjMjAwZTAzLCAweDM5ZGM1ZmY2LCAweDVkMGIwMGEzLCAweGFlNjNhZmYyLCAweDdlOGJkNjMyLCAweDcwMTA4YzBjLFxuICAgIDB4YmJkMzUwNDksIDB4Mjk5OGRmMDQsIDB4OTgwY2Y0MmEsIDB4OWI2ZGY0OTEsIDB4OWU3ZWRkNTMsIDB4MDY5MTg1NDgsIDB4NThjYjdlMDcsIDB4M2I3NGVmMmUsXG4gICAgMHg1MjJmZmZiMSwgMHhkMjQ3MDhjYywgMHgxYzdlMjdjZCwgMHhhNGViMjE1YiwgMHgzY2YxZDJlMiwgMHgxOWI0N2EzOCwgMHg0MjRmNzYxOCwgMHgzNTg1NjAzOSxcbiAgICAweDlkMTdkZWU3LCAweDI3ZWIzNWU2LCAweGM5YWZmNjdiLCAweDM2YmFmNWI4LCAweDA5YzQ2N2NkLCAweGMxODkxMGIxLCAweGUxMWRiZjdiLCAweDA2Y2QxYWY4LFxuICAgIDB4NzE3MGM2MDgsIDB4MmQ1ZTMzNTQsIDB4ZDRkZTQ5NWEsIDB4NjRjNmQwMDYsIDB4YmNjMGM2MmMsIDB4M2RkMDBkYjMsIDB4NzA4ZjhmMzQsIDB4NzdkNTFiNDIsXG4gICAgMHgyNjRmNjIwZiwgMHgyNGI4ZDJiZiwgMHgxNWMxYjc5ZSwgMHg0NmE1MjU2NCwgMHhmOGQ3ZTU0ZSwgMHgzZTM3ODE2MCwgMHg3ODk1Y2RhNSwgMHg4NTljMTVhNSxcbiAgICAweGU2NDU5Nzg4LCAweGMzN2JjNzVmLCAweGRiMDdiYTBjLCAweDA2NzZhM2FiLCAweDdmMjI5YjFlLCAweDMxODQyZTdiLCAweDI0MjU5ZmQ3LCAweGY4YmVmNDcyLFxuICAgIDB4ODM1ZmZjYjgsIDB4NmRmNGMxZjIsIDB4OTZmNWIxOTUsIDB4ZmQwYWYwZmMsIDB4YjBmZTEzNGMsIDB4ZTI1MDZkM2QsIDB4NGY5YjEyZWEsIDB4ZjIxNWYyMjUsXG4gICAgMHhhMjIzNzM2ZiwgMHg5ZmI0YzQyOCwgMHgyNWQwNDk3OSwgMHgzNGM3MTNmOCwgMHhjNDYxODE4NywgMHhlYTdhNmU5OCwgMHg3Y2QxNmVmYywgMHgxNDM2ODc2YyxcbiAgICAweGYxNTQ0MTA3LCAweGJlZGVlZTE0LCAweDU2ZTlhZjI3LCAweGEwNGFhNDQxLCAweDNjZjdjODk5LCAweDkyZWNiYWU2LCAweGRkNjcwMTZkLCAweDE1MTY4MmViLFxuICAgIDB4YTg0MmVlZGYsIDB4ZmRiYTYwYjQsIDB4ZjE5MDdiNzUsIDB4MjBlMzAzMGYsIDB4MjRkOGMyOWUsIDB4ZTEzOTY3M2IsIDB4ZWZhNjNmYjgsIDB4NzE4NzMwNTQsXG4gICAgMHhiNmYyY2YzYiwgMHg5ZjMyNjQ0MiwgMHhjYjE1YTRjYywgMHhiMDFhNDUwNCwgMHhmMWU0N2Q4ZCwgMHg4NDRhMWJlNSwgMHhiYWU3ZGZkYywgMHg0MmNiZGE3MCxcbiAgICAweGNkN2RhZTBhLCAweDU3ZTg1YjdhLCAweGQ1M2Y1YWY2LCAweDIwY2Y0ZDhjLCAweGNlYTRkNDI4LCAweDc5ZDEzMGE0LCAweDM0ODZlYmZiLCAweDMzZDNjZGRjLFxuICAgIDB4Nzc4NTNiNTMsIDB4MzdlZmZjYjUsIDB4YzUwNjg3NzgsIDB4ZTU4MGIzZTYsIDB4NGU2OGI4ZjQsIDB4YzVjOGIzN2UsIDB4MGQ4MDllYTIsIDB4Mzk4ZmViN2MsXG4gICAgMHgxMzJhNGY5NCwgMHg0M2I3OTUwZSwgMHgyZmVlN2QxYywgMHgyMjM2MTNiZCwgMHhkZDA2Y2FhMiwgMHgzN2RmOTMyYiwgMHhjNDI0ODI4OSwgMHhhY2YzZWJjMyxcbiAgICAweDU3MTVmNmI3LCAweGVmMzQ3OGRkLCAweGYyNjc2MTZmLCAweGMxNDhjYmU0LCAweDkwNTI4MTVlLCAweDVlNDEwZmFiLCAweGI0OGEyNDY1LCAweDJlZGE3ZmE0LFxuICAgIDB4ZTg3YjQwZTQsIDB4ZTk4ZWEwODQsIDB4NTg4OWU5ZTEsIDB4ZWZkMzkwZmMsIDB4ZGQwN2QzNWIsIDB4ZGI0ODU2OTQsIDB4MzhkN2U1YjIsIDB4NTc3MjAxMDEsXG4gICAgMHg3MzBlZGViYywgMHg1YjY0MzExMywgMHg5NDkxN2U0ZiwgMHg1MDNjMmZiYSwgMHg2NDZmMTI4MiwgMHg3NTIzZDI0YSwgMHhlMDc3OTY5NSwgMHhmOWMxN2E4ZixcbiAgICAweDdhNWIyMTIxLCAweGQxODdiODk2LCAweDI5MjYzYTRkLCAweGJhNTEwY2RmLCAweDgxZjQ3YzlmLCAweGFkMTE2M2VkLCAweGVhN2I1OTY1LCAweDFhMDA3MjZlLFxuICAgIDB4MTE0MDMwOTIsIDB4MDBkYTZkNzcsIDB4NGEwY2RkNjEsIDB4YWQxZjQ2MDMsIDB4NjA1YmRmYjAsIDB4OWVlZGMzNjQsIDB4MjJlYmU2YTgsIDB4Y2VlN2QyOGEsXG4gICAgMHhhMGU3MzZhMCwgMHg1NTY0YTZiOSwgMHgxMDg1MzIwOSwgMHhjN2ViOGYzNywgMHgyZGU3MDVjYSwgMHg4OTUxNTcwZiwgMHhkZjA5ODIyYiwgMHhiZDY5MWE2YyxcbiAgICAweGFhMTJlNGYyLCAweDg3NDUxYzBmLCAweGUwZjZhMjdhLCAweDNhZGE0ODE5LCAweDRjZjE3NjRmLCAweDBkNzcxYzJiLCAweDY3Y2RiMTU2LCAweDM1MGQ4Mzg0LFxuICAgIDB4NTkzOGZhMGYsIDB4NDIzOTllZjMsIDB4MzY5OTdiMDcsIDB4MGU4NDA5M2QsIDB4NGFhOTNlNjEsIDB4ODM2MGQ4N2IsIDB4MWZhOThiMGMsIDB4MTE0OTM4MmMsXG4gICAgMHhlOTc2MjVhNSwgMHgwNjE0ZDFiNywgMHgwZTI1MjQ0YiwgMHgwYzc2ODM0NywgMHg1ODllOGQ4MiwgMHgwZDIwNTlkMSwgMHhhNDY2YmIxZSwgMHhmOGRhMGE4MixcbiAgICAweDA0ZjE5MTMwLCAweGJhNmU0ZWMwLCAweDk5MjY1MTY0LCAweDFlZTcyMzBkLCAweDUwYjJhZDgwLCAweGVhZWU2ODAxLCAweDhkYjJhMjgzLCAweGVhOGJmNTllKTtcblxufTtcblxudmFyIHV0aWwgPSByZXF1aXJlKCcuLi8uLi91dGlsJyk7XG5cbmZ1bmN0aW9uIGNhc3Q1KGtleSkge1xuICB0aGlzLmNhc3Q1ID0gbmV3IG9wZW5wZ3Bfc3ltZW5jX2Nhc3Q1KCk7XG4gIHRoaXMuY2FzdDUuc2V0S2V5KHV0aWwuc3RyMmJpbihrZXkpKTtcblxuICB0aGlzLmVuY3J5cHQgPSBmdW5jdGlvbihibG9jaykge1xuICAgIHJldHVybiB0aGlzLmNhc3Q1LmVuY3J5cHQoYmxvY2spO1xuICB9XG59XG5cbm1vZHVsZS5leHBvcnRzID0gY2FzdDU7XG5tb2R1bGUuZXhwb3J0cy5ibG9ja1NpemUgPSBjYXN0NS5wcm90b3R5cGUuYmxvY2tTaXplID0gODtcbm1vZHVsZS5leHBvcnRzLmtleVNpemUgPSBjYXN0NS5wcm90b3R5cGUua2V5U2l6ZSA9IDE2O1xuIiwiLy9QYXVsIFRlcm8sIEp1bHkgMjAwMVxuLy9odHRwOi8vd3d3LnRlcm8uY28udWsvZGVzL1xuLy9cbi8vT3B0aW1pc2VkIGZvciBwZXJmb3JtYW5jZSB3aXRoIGxhcmdlIGJsb2NrcyBieSBNaWNoYWVsIEhheXdvcnRoLCBOb3ZlbWJlciAyMDAxXG4vL2h0dHA6Ly93d3cubmV0ZGVhbGluZy5jb21cbi8vXG4vLyBNb2RpZmllZCBieSBSZWN1cml0eSBMYWJzIEdtYkhcblxuLy9USElTIFNPRlRXQVJFIElTIFBST1ZJREVEIFwiQVMgSVNcIiBBTkRcbi8vQU5ZIEVYUFJFU1MgT1IgSU1QTElFRCBXQVJSQU5USUVTLCBJTkNMVURJTkcsIEJVVCBOT1QgTElNSVRFRCBUTywgVEhFXG4vL0lNUExJRUQgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFkgQU5EIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFXG4vL0FSRSBESVNDTEFJTUVELiAgSU4gTk8gRVZFTlQgU0hBTEwgVEhFIEFVVEhPUiBPUiBDT05UUklCVVRPUlMgQkUgTElBQkxFXG4vL0ZPUiBBTlkgRElSRUNULCBJTkRJUkVDVCwgSU5DSURFTlRBTCwgU1BFQ0lBTCwgRVhFTVBMQVJZLCBPUiBDT05TRVFVRU5USUFMXG4vL0RBTUFHRVMgKElOQ0xVRElORywgQlVUIE5PVCBMSU1JVEVEIFRPLCBQUk9DVVJFTUVOVCBPRiBTVUJTVElUVVRFIEdPT0RTXG4vL09SIFNFUlZJQ0VTOyBMT1NTIE9GIFVTRSwgREFUQSwgT1IgUFJPRklUUzsgT1IgQlVTSU5FU1MgSU5URVJSVVBUSU9OKVxuLy9IT1dFVkVSIENBVVNFRCBBTkQgT04gQU5ZIFRIRU9SWSBPRiBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQ09OVFJBQ1QsIFNUUklDVFxuLy9MSUFCSUxJVFksIE9SIFRPUlQgKElOQ0xVRElORyBORUdMSUdFTkNFIE9SIE9USEVSV0lTRSkgQVJJU0lORyBJTiBBTlkgV0FZXG4vL09VVCBPRiBUSEUgVVNFIE9GIFRISVMgU09GVFdBUkUsIEVWRU4gSUYgQURWSVNFRCBPRiBUSEUgUE9TU0lCSUxJVFkgT0Zcbi8vU1VDSCBEQU1BR0UuXG5cbi8vZGVzXG4vL3RoaXMgdGFrZXMgdGhlIGtleSwgdGhlIG1lc3NhZ2UsIGFuZCB3aGV0aGVyIHRvIGVuY3J5cHQgb3IgZGVjcnlwdFxuXG5cblxuXG5mdW5jdGlvbiBkZXMoa2V5cywgbWVzc2FnZSwgZW5jcnlwdCwgbW9kZSwgaXYsIHBhZGRpbmcpIHtcbiAgLy9kZWNsYXJpbmcgdGhpcyBsb2NhbGx5IHNwZWVkcyB0aGluZ3MgdXAgYSBiaXRcbiAgdmFyIHNwZnVuY3Rpb24xID0gbmV3IEFycmF5KDB4MTAxMDQwMCwgMCwgMHgxMDAwMCwgMHgxMDEwNDA0LCAweDEwMTAwMDQsIDB4MTA0MDQsIDB4NCwgMHgxMDAwMCwgMHg0MDAsIDB4MTAxMDQwMCxcbiAgICAweDEwMTA0MDQsIDB4NDAwLCAweDEwMDA0MDQsIDB4MTAxMDAwNCwgMHgxMDAwMDAwLCAweDQsIDB4NDA0LCAweDEwMDA0MDAsIDB4MTAwMDQwMCwgMHgxMDQwMCwgMHgxMDQwMCwgMHgxMDEwMDAwLFxuICAgIDB4MTAxMDAwMCwgMHgxMDAwNDA0LCAweDEwMDA0LCAweDEwMDAwMDQsIDB4MTAwMDAwNCwgMHgxMDAwNCwgMCwgMHg0MDQsIDB4MTA0MDQsIDB4MTAwMDAwMCwgMHgxMDAwMCwgMHgxMDEwNDA0LCAweDQsXG4gICAgMHgxMDEwMDAwLCAweDEwMTA0MDAsIDB4MTAwMDAwMCwgMHgxMDAwMDAwLCAweDQwMCwgMHgxMDEwMDA0LCAweDEwMDAwLCAweDEwNDAwLCAweDEwMDAwMDQsIDB4NDAwLCAweDQsIDB4MTAwMDQwNCxcbiAgICAweDEwNDA0LCAweDEwMTA0MDQsIDB4MTAwMDQsIDB4MTAxMDAwMCwgMHgxMDAwNDA0LCAweDEwMDAwMDQsIDB4NDA0LCAweDEwNDA0LCAweDEwMTA0MDAsIDB4NDA0LCAweDEwMDA0MDAsXG4gICAgMHgxMDAwNDAwLCAwLCAweDEwMDA0LCAweDEwNDAwLCAwLCAweDEwMTAwMDQpO1xuICB2YXIgc3BmdW5jdGlvbjIgPSBuZXcgQXJyYXkoLTB4N2ZlZjdmZTAsIC0weDdmZmY4MDAwLCAweDgwMDAsIDB4MTA4MDIwLCAweDEwMDAwMCwgMHgyMCwgLTB4N2ZlZmZmZTAsIC0weDdmZmY3ZmUwLCAtXG4gICAgMHg3ZmZmZmZlMCwgLTB4N2ZlZjdmZTAsIC0weDdmZWY4MDAwLCAtMHg4MDAwMDAwMCwgLTB4N2ZmZjgwMDAsIDB4MTAwMDAwLCAweDIwLCAtMHg3ZmVmZmZlMCwgMHgxMDgwMDAsIDB4MTAwMDIwLCAtXG4gICAgMHg3ZmZmN2ZlMCwgMCwgLTB4ODAwMDAwMDAsIDB4ODAwMCwgMHgxMDgwMjAsIC0weDdmZjAwMDAwLCAweDEwMDAyMCwgLTB4N2ZmZmZmZTAsIDAsIDB4MTA4MDAwLCAweDgwMjAsIC0weDdmZWY4MDAwLCAtXG4gICAgMHg3ZmYwMDAwMCwgMHg4MDIwLCAwLCAweDEwODAyMCwgLTB4N2ZlZmZmZTAsIDB4MTAwMDAwLCAtMHg3ZmZmN2ZlMCwgLTB4N2ZmMDAwMDAsIC0weDdmZWY4MDAwLCAweDgwMDAsIC0weDdmZjAwMDAwLCAtXG4gICAgMHg3ZmZmODAwMCwgMHgyMCwgLTB4N2ZlZjdmZTAsIDB4MTA4MDIwLCAweDIwLCAweDgwMDAsIC0weDgwMDAwMDAwLCAweDgwMjAsIC0weDdmZWY4MDAwLCAweDEwMDAwMCwgLTB4N2ZmZmZmZTAsXG4gICAgMHgxMDAwMjAsIC0weDdmZmY3ZmUwLCAtMHg3ZmZmZmZlMCwgMHgxMDAwMjAsIDB4MTA4MDAwLCAwLCAtMHg3ZmZmODAwMCwgMHg4MDIwLCAtMHg4MDAwMDAwMCwgLTB4N2ZlZmZmZTAsIC1cbiAgICAweDdmZWY3ZmUwLCAweDEwODAwMCk7XG4gIHZhciBzcGZ1bmN0aW9uMyA9IG5ldyBBcnJheSgweDIwOCwgMHg4MDIwMjAwLCAwLCAweDgwMjAwMDgsIDB4ODAwMDIwMCwgMCwgMHgyMDIwOCwgMHg4MDAwMjAwLCAweDIwMDA4LCAweDgwMDAwMDgsXG4gICAgMHg4MDAwMDA4LCAweDIwMDAwLCAweDgwMjAyMDgsIDB4MjAwMDgsIDB4ODAyMDAwMCwgMHgyMDgsIDB4ODAwMDAwMCwgMHg4LCAweDgwMjAyMDAsIDB4MjAwLCAweDIwMjAwLCAweDgwMjAwMDAsXG4gICAgMHg4MDIwMDA4LCAweDIwMjA4LCAweDgwMDAyMDgsIDB4MjAyMDAsIDB4MjAwMDAsIDB4ODAwMDIwOCwgMHg4LCAweDgwMjAyMDgsIDB4MjAwLCAweDgwMDAwMDAsIDB4ODAyMDIwMCwgMHg4MDAwMDAwLFxuICAgIDB4MjAwMDgsIDB4MjA4LCAweDIwMDAwLCAweDgwMjAyMDAsIDB4ODAwMDIwMCwgMCwgMHgyMDAsIDB4MjAwMDgsIDB4ODAyMDIwOCwgMHg4MDAwMjAwLCAweDgwMDAwMDgsIDB4MjAwLCAwLFxuICAgIDB4ODAyMDAwOCwgMHg4MDAwMjA4LCAweDIwMDAwLCAweDgwMDAwMDAsIDB4ODAyMDIwOCwgMHg4LCAweDIwMjA4LCAweDIwMjAwLCAweDgwMDAwMDgsIDB4ODAyMDAwMCwgMHg4MDAwMjA4LCAweDIwOCxcbiAgICAweDgwMjAwMDAsIDB4MjAyMDgsIDB4OCwgMHg4MDIwMDA4LCAweDIwMjAwKTtcbiAgdmFyIHNwZnVuY3Rpb240ID0gbmV3IEFycmF5KDB4ODAyMDAxLCAweDIwODEsIDB4MjA4MSwgMHg4MCwgMHg4MDIwODAsIDB4ODAwMDgxLCAweDgwMDAwMSwgMHgyMDAxLCAwLCAweDgwMjAwMCxcbiAgICAweDgwMjAwMCwgMHg4MDIwODEsIDB4ODEsIDAsIDB4ODAwMDgwLCAweDgwMDAwMSwgMHgxLCAweDIwMDAsIDB4ODAwMDAwLCAweDgwMjAwMSwgMHg4MCwgMHg4MDAwMDAsIDB4MjAwMSwgMHgyMDgwLFxuICAgIDB4ODAwMDgxLCAweDEsIDB4MjA4MCwgMHg4MDAwODAsIDB4MjAwMCwgMHg4MDIwODAsIDB4ODAyMDgxLCAweDgxLCAweDgwMDA4MCwgMHg4MDAwMDEsIDB4ODAyMDAwLCAweDgwMjA4MSwgMHg4MSwgMCxcbiAgICAwLCAweDgwMjAwMCwgMHgyMDgwLCAweDgwMDA4MCwgMHg4MDAwODEsIDB4MSwgMHg4MDIwMDEsIDB4MjA4MSwgMHgyMDgxLCAweDgwLCAweDgwMjA4MSwgMHg4MSwgMHgxLCAweDIwMDAsIDB4ODAwMDAxLFxuICAgIDB4MjAwMSwgMHg4MDIwODAsIDB4ODAwMDgxLCAweDIwMDEsIDB4MjA4MCwgMHg4MDAwMDAsIDB4ODAyMDAxLCAweDgwLCAweDgwMDAwMCwgMHgyMDAwLCAweDgwMjA4MCk7XG4gIHZhciBzcGZ1bmN0aW9uNSA9IG5ldyBBcnJheSgweDEwMCwgMHgyMDgwMTAwLCAweDIwODAwMDAsIDB4NDIwMDAxMDAsIDB4ODAwMDAsIDB4MTAwLCAweDQwMDAwMDAwLCAweDIwODAwMDAsXG4gICAgMHg0MDA4MDEwMCwgMHg4MDAwMCwgMHgyMDAwMTAwLCAweDQwMDgwMTAwLCAweDQyMDAwMTAwLCAweDQyMDgwMDAwLCAweDgwMTAwLCAweDQwMDAwMDAwLCAweDIwMDAwMDAsIDB4NDAwODAwMDAsXG4gICAgMHg0MDA4MDAwMCwgMCwgMHg0MDAwMDEwMCwgMHg0MjA4MDEwMCwgMHg0MjA4MDEwMCwgMHgyMDAwMTAwLCAweDQyMDgwMDAwLCAweDQwMDAwMTAwLCAwLCAweDQyMDAwMDAwLCAweDIwODAxMDAsXG4gICAgMHgyMDAwMDAwLCAweDQyMDAwMDAwLCAweDgwMTAwLCAweDgwMDAwLCAweDQyMDAwMTAwLCAweDEwMCwgMHgyMDAwMDAwLCAweDQwMDAwMDAwLCAweDIwODAwMDAsIDB4NDIwMDAxMDAsXG4gICAgMHg0MDA4MDEwMCwgMHgyMDAwMTAwLCAweDQwMDAwMDAwLCAweDQyMDgwMDAwLCAweDIwODAxMDAsIDB4NDAwODAxMDAsIDB4MTAwLCAweDIwMDAwMDAsIDB4NDIwODAwMDAsIDB4NDIwODAxMDAsXG4gICAgMHg4MDEwMCwgMHg0MjAwMDAwMCwgMHg0MjA4MDEwMCwgMHgyMDgwMDAwLCAwLCAweDQwMDgwMDAwLCAweDQyMDAwMDAwLCAweDgwMTAwLCAweDIwMDAxMDAsIDB4NDAwMDAxMDAsIDB4ODAwMDAsIDAsXG4gICAgMHg0MDA4MDAwMCwgMHgyMDgwMTAwLCAweDQwMDAwMTAwKTtcbiAgdmFyIHNwZnVuY3Rpb242ID0gbmV3IEFycmF5KDB4MjAwMDAwMTAsIDB4MjA0MDAwMDAsIDB4NDAwMCwgMHgyMDQwNDAxMCwgMHgyMDQwMDAwMCwgMHgxMCwgMHgyMDQwNDAxMCwgMHg0MDAwMDAsXG4gICAgMHgyMDAwNDAwMCwgMHg0MDQwMTAsIDB4NDAwMDAwLCAweDIwMDAwMDEwLCAweDQwMDAxMCwgMHgyMDAwNDAwMCwgMHgyMDAwMDAwMCwgMHg0MDEwLCAwLCAweDQwMDAxMCwgMHgyMDAwNDAxMCxcbiAgICAweDQwMDAsIDB4NDA0MDAwLCAweDIwMDA0MDEwLCAweDEwLCAweDIwNDAwMDEwLCAweDIwNDAwMDEwLCAwLCAweDQwNDAxMCwgMHgyMDQwNDAwMCwgMHg0MDEwLCAweDQwNDAwMCwgMHgyMDQwNDAwMCxcbiAgICAweDIwMDAwMDAwLCAweDIwMDA0MDAwLCAweDEwLCAweDIwNDAwMDEwLCAweDQwNDAwMCwgMHgyMDQwNDAxMCwgMHg0MDAwMDAsIDB4NDAxMCwgMHgyMDAwMDAxMCwgMHg0MDAwMDAsIDB4MjAwMDQwMDAsXG4gICAgMHgyMDAwMDAwMCwgMHg0MDEwLCAweDIwMDAwMDEwLCAweDIwNDA0MDEwLCAweDQwNDAwMCwgMHgyMDQwMDAwMCwgMHg0MDQwMTAsIDB4MjA0MDQwMDAsIDAsIDB4MjA0MDAwMTAsIDB4MTAsIDB4NDAwMCxcbiAgICAweDIwNDAwMDAwLCAweDQwNDAxMCwgMHg0MDAwLCAweDQwMDAxMCwgMHgyMDAwNDAxMCwgMCwgMHgyMDQwNDAwMCwgMHgyMDAwMDAwMCwgMHg0MDAwMTAsIDB4MjAwMDQwMTApO1xuICB2YXIgc3BmdW5jdGlvbjcgPSBuZXcgQXJyYXkoMHgyMDAwMDAsIDB4NDIwMDAwMiwgMHg0MDAwODAyLCAwLCAweDgwMCwgMHg0MDAwODAyLCAweDIwMDgwMiwgMHg0MjAwODAwLCAweDQyMDA4MDIsXG4gICAgMHgyMDAwMDAsIDAsIDB4NDAwMDAwMiwgMHgyLCAweDQwMDAwMDAsIDB4NDIwMDAwMiwgMHg4MDIsIDB4NDAwMDgwMCwgMHgyMDA4MDIsIDB4MjAwMDAyLCAweDQwMDA4MDAsIDB4NDAwMDAwMixcbiAgICAweDQyMDAwMDAsIDB4NDIwMDgwMCwgMHgyMDAwMDIsIDB4NDIwMDAwMCwgMHg4MDAsIDB4ODAyLCAweDQyMDA4MDIsIDB4MjAwODAwLCAweDIsIDB4NDAwMDAwMCwgMHgyMDA4MDAsIDB4NDAwMDAwMCxcbiAgICAweDIwMDgwMCwgMHgyMDAwMDAsIDB4NDAwMDgwMiwgMHg0MDAwODAyLCAweDQyMDAwMDIsIDB4NDIwMDAwMiwgMHgyLCAweDIwMDAwMiwgMHg0MDAwMDAwLCAweDQwMDA4MDAsIDB4MjAwMDAwLFxuICAgIDB4NDIwMDgwMCwgMHg4MDIsIDB4MjAwODAyLCAweDQyMDA4MDAsIDB4ODAyLCAweDQwMDAwMDIsIDB4NDIwMDgwMiwgMHg0MjAwMDAwLCAweDIwMDgwMCwgMCwgMHgyLCAweDQyMDA4MDIsIDAsXG4gICAgMHgyMDA4MDIsIDB4NDIwMDAwMCwgMHg4MDAsIDB4NDAwMDAwMiwgMHg0MDAwODAwLCAweDgwMCwgMHgyMDAwMDIpO1xuICB2YXIgc3BmdW5jdGlvbjggPSBuZXcgQXJyYXkoMHgxMDAwMTA0MCwgMHgxMDAwLCAweDQwMDAwLCAweDEwMDQxMDQwLCAweDEwMDAwMDAwLCAweDEwMDAxMDQwLCAweDQwLCAweDEwMDAwMDAwLFxuICAgIDB4NDAwNDAsIDB4MTAwNDAwMDAsIDB4MTAwNDEwNDAsIDB4NDEwMDAsIDB4MTAwNDEwMDAsIDB4NDEwNDAsIDB4MTAwMCwgMHg0MCwgMHgxMDA0MDAwMCwgMHgxMDAwMDA0MCwgMHgxMDAwMTAwMCxcbiAgICAweDEwNDAsIDB4NDEwMDAsIDB4NDAwNDAsIDB4MTAwNDAwNDAsIDB4MTAwNDEwMDAsIDB4MTA0MCwgMCwgMCwgMHgxMDA0MDA0MCwgMHgxMDAwMDA0MCwgMHgxMDAwMTAwMCwgMHg0MTA0MCxcbiAgICAweDQwMDAwLCAweDQxMDQwLCAweDQwMDAwLCAweDEwMDQxMDAwLCAweDEwMDAsIDB4NDAsIDB4MTAwNDAwNDAsIDB4MTAwMCwgMHg0MTA0MCwgMHgxMDAwMTAwMCwgMHg0MCwgMHgxMDAwMDA0MCxcbiAgICAweDEwMDQwMDAwLCAweDEwMDQwMDQwLCAweDEwMDAwMDAwLCAweDQwMDAwLCAweDEwMDAxMDQwLCAwLCAweDEwMDQxMDQwLCAweDQwMDQwLCAweDEwMDAwMDQwLCAweDEwMDQwMDAwLCAweDEwMDAxMDAwLFxuICAgIDB4MTAwMDEwNDAsIDAsIDB4MTAwNDEwNDAsIDB4NDEwMDAsIDB4NDEwMDAsIDB4MTA0MCwgMHgxMDQwLCAweDQwMDQwLCAweDEwMDAwMDAwLCAweDEwMDQxMDAwKTtcblxuICAvL2NyZWF0ZSB0aGUgMTYgb3IgNDggc3Via2V5cyB3ZSB3aWxsIG5lZWRcbiAgdmFyIG0gPSAwLFxuICAgIGksIGosIHRlbXAsIHRlbXAyLCByaWdodDEsIHJpZ2h0MiwgbGVmdCwgcmlnaHQsIGxvb3Bpbmc7XG4gIHZhciBjYmNsZWZ0LCBjYmNsZWZ0MiwgY2JjcmlnaHQsIGNiY3JpZ2h0MlxuICB2YXIgZW5kbG9vcCwgbG9vcGluYztcbiAgdmFyIGxlbiA9IG1lc3NhZ2UubGVuZ3RoO1xuICB2YXIgY2h1bmsgPSAwO1xuICAvL3NldCB1cCB0aGUgbG9vcHMgZm9yIHNpbmdsZSBhbmQgdHJpcGxlIGRlc1xuICB2YXIgaXRlcmF0aW9ucyA9IGtleXMubGVuZ3RoID09IDMyID8gMyA6IDk7IC8vc2luZ2xlIG9yIHRyaXBsZSBkZXNcbiAgaWYgKGl0ZXJhdGlvbnMgPT0gMykge1xuICAgIGxvb3BpbmcgPSBlbmNyeXB0ID8gbmV3IEFycmF5KDAsIDMyLCAyKSA6IG5ldyBBcnJheSgzMCwgLTIsIC0yKTtcbiAgfSBlbHNlIHtcbiAgICBsb29waW5nID0gZW5jcnlwdCA/IG5ldyBBcnJheSgwLCAzMiwgMiwgNjIsIDMwLCAtMiwgNjQsIDk2LCAyKSA6IG5ldyBBcnJheSg5NCwgNjIsIC0yLCAzMiwgNjQsIDIsIDMwLCAtMiwgLTIpO1xuICB9XG5cbiAgLy9wYWQgdGhlIG1lc3NhZ2UgZGVwZW5kaW5nIG9uIHRoZSBwYWRkaW5nIHBhcmFtZXRlclxuICAvL29ubHkgYWRkIHBhZGRpbmcgaWYgZW5jcnlwdGluZyAtIG5vdGUgdGhhdCB5b3UgbmVlZCB0byB1c2UgdGhlIHNhbWUgcGFkZGluZyBvcHRpb24gZm9yIGJvdGggZW5jcnlwdCBhbmQgZGVjcnlwdFxuICBpZiAoZW5jcnlwdCkge1xuICAgIG1lc3NhZ2UgPSBkZXNfYWRkUGFkZGluZyhtZXNzYWdlLCBwYWRkaW5nKTtcbiAgICBsZW4gPSBtZXNzYWdlLmxlbmd0aDtcbiAgfVxuXG4gIC8vc3RvcmUgdGhlIHJlc3VsdCBoZXJlXG4gIHJlc3VsdCA9IFwiXCI7XG4gIHRlbXByZXN1bHQgPSBcIlwiO1xuXG4gIGlmIChtb2RlID09IDEpIHsgLy9DQkMgbW9kZVxuICAgIGNiY2xlZnQgPSAoaXYuY2hhckNvZGVBdChtKyspIDw8IDI0KSB8IChpdi5jaGFyQ29kZUF0KG0rKykgPDwgMTYpIHwgKGl2LmNoYXJDb2RlQXQobSsrKSA8PCA4KSB8IGl2LmNoYXJDb2RlQXQobSsrKTtcbiAgICBjYmNyaWdodCA9IChpdi5jaGFyQ29kZUF0KG0rKykgPDwgMjQpIHwgKGl2LmNoYXJDb2RlQXQobSsrKSA8PCAxNikgfCAoaXYuY2hhckNvZGVBdChtKyspIDw8IDgpIHwgaXYuY2hhckNvZGVBdChtKyspO1xuICAgIG0gPSAwO1xuICB9XG5cbiAgLy9sb29wIHRocm91Z2ggZWFjaCA2NCBiaXQgY2h1bmsgb2YgdGhlIG1lc3NhZ2VcbiAgd2hpbGUgKG0gPCBsZW4pIHtcbiAgICBsZWZ0ID0gKG1lc3NhZ2UuY2hhckNvZGVBdChtKyspIDw8IDI0KSB8IChtZXNzYWdlLmNoYXJDb2RlQXQobSsrKSA8PCAxNikgfCAobWVzc2FnZS5jaGFyQ29kZUF0KG0rKykgPDwgOCkgfCBtZXNzYWdlXG4gICAgICAuY2hhckNvZGVBdChtKyspO1xuICAgIHJpZ2h0ID0gKG1lc3NhZ2UuY2hhckNvZGVBdChtKyspIDw8IDI0KSB8IChtZXNzYWdlLmNoYXJDb2RlQXQobSsrKSA8PCAxNikgfCAobWVzc2FnZS5jaGFyQ29kZUF0KG0rKykgPDwgOCkgfFxuICAgICAgbWVzc2FnZS5jaGFyQ29kZUF0KG0rKyk7XG5cbiAgICAvL2ZvciBDaXBoZXIgQmxvY2sgQ2hhaW5pbmcgbW9kZSwgeG9yIHRoZSBtZXNzYWdlIHdpdGggdGhlIHByZXZpb3VzIHJlc3VsdFxuICAgIGlmIChtb2RlID09IDEpIHtcbiAgICAgIGlmIChlbmNyeXB0KSB7XG4gICAgICAgIGxlZnQgXj0gY2JjbGVmdDtcbiAgICAgICAgcmlnaHQgXj0gY2JjcmlnaHQ7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjYmNsZWZ0MiA9IGNiY2xlZnQ7XG4gICAgICAgIGNiY3JpZ2h0MiA9IGNiY3JpZ2h0O1xuICAgICAgICBjYmNsZWZ0ID0gbGVmdDtcbiAgICAgICAgY2JjcmlnaHQgPSByaWdodDtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvL2ZpcnN0IGVhY2ggNjQgYnV0IGNodW5rIG9mIHRoZSBtZXNzYWdlIG11c3QgYmUgcGVybXV0ZWQgYWNjb3JkaW5nIHRvIElQXG4gICAgdGVtcCA9ICgobGVmdCA+Pj4gNCkgXiByaWdodCkgJiAweDBmMGYwZjBmO1xuICAgIHJpZ2h0IF49IHRlbXA7XG4gICAgbGVmdCBePSAodGVtcCA8PCA0KTtcbiAgICB0ZW1wID0gKChsZWZ0ID4+PiAxNikgXiByaWdodCkgJiAweDAwMDBmZmZmO1xuICAgIHJpZ2h0IF49IHRlbXA7XG4gICAgbGVmdCBePSAodGVtcCA8PCAxNik7XG4gICAgdGVtcCA9ICgocmlnaHQgPj4+IDIpIF4gbGVmdCkgJiAweDMzMzMzMzMzO1xuICAgIGxlZnQgXj0gdGVtcDtcbiAgICByaWdodCBePSAodGVtcCA8PCAyKTtcbiAgICB0ZW1wID0gKChyaWdodCA+Pj4gOCkgXiBsZWZ0KSAmIDB4MDBmZjAwZmY7XG4gICAgbGVmdCBePSB0ZW1wO1xuICAgIHJpZ2h0IF49ICh0ZW1wIDw8IDgpO1xuICAgIHRlbXAgPSAoKGxlZnQgPj4+IDEpIF4gcmlnaHQpICYgMHg1NTU1NTU1NTtcbiAgICByaWdodCBePSB0ZW1wO1xuICAgIGxlZnQgXj0gKHRlbXAgPDwgMSk7XG5cbiAgICBsZWZ0ID0gKChsZWZ0IDw8IDEpIHwgKGxlZnQgPj4+IDMxKSk7XG4gICAgcmlnaHQgPSAoKHJpZ2h0IDw8IDEpIHwgKHJpZ2h0ID4+PiAzMSkpO1xuXG4gICAgLy9kbyB0aGlzIGVpdGhlciAxIG9yIDMgdGltZXMgZm9yIGVhY2ggY2h1bmsgb2YgdGhlIG1lc3NhZ2VcbiAgICBmb3IgKGogPSAwOyBqIDwgaXRlcmF0aW9uczsgaiArPSAzKSB7XG4gICAgICBlbmRsb29wID0gbG9vcGluZ1tqICsgMV07XG4gICAgICBsb29waW5jID0gbG9vcGluZ1tqICsgMl07XG4gICAgICAvL25vdyBnbyB0aHJvdWdoIGFuZCBwZXJmb3JtIHRoZSBlbmNyeXB0aW9uIG9yIGRlY3J5cHRpb24gIFxuICAgICAgZm9yIChpID0gbG9vcGluZ1tqXTsgaSAhPSBlbmRsb29wOyBpICs9IGxvb3BpbmMpIHsgLy9mb3IgZWZmaWNpZW5jeVxuICAgICAgICByaWdodDEgPSByaWdodCBeIGtleXNbaV07XG4gICAgICAgIHJpZ2h0MiA9ICgocmlnaHQgPj4+IDQpIHwgKHJpZ2h0IDw8IDI4KSkgXiBrZXlzW2kgKyAxXTtcbiAgICAgICAgLy90aGUgcmVzdWx0IGlzIGF0dGFpbmVkIGJ5IHBhc3NpbmcgdGhlc2UgYnl0ZXMgdGhyb3VnaCB0aGUgUyBzZWxlY3Rpb24gZnVuY3Rpb25zXG4gICAgICAgIHRlbXAgPSBsZWZ0O1xuICAgICAgICBsZWZ0ID0gcmlnaHQ7XG4gICAgICAgIHJpZ2h0ID0gdGVtcCBeIChzcGZ1bmN0aW9uMlsocmlnaHQxID4+PiAyNCkgJiAweDNmXSB8IHNwZnVuY3Rpb240WyhyaWdodDEgPj4+IDE2KSAmIDB4M2ZdIHwgc3BmdW5jdGlvbjZbKHJpZ2h0MSA+Pj5cbiAgICAgICAgICA4KSAmIDB4M2ZdIHwgc3BmdW5jdGlvbjhbcmlnaHQxICYgMHgzZl0gfCBzcGZ1bmN0aW9uMVsocmlnaHQyID4+PiAyNCkgJiAweDNmXSB8IHNwZnVuY3Rpb24zWyhyaWdodDIgPj4+IDE2KSAmXG4gICAgICAgICAgMHgzZl0gfCBzcGZ1bmN0aW9uNVsocmlnaHQyID4+PiA4KSAmIDB4M2ZdIHwgc3BmdW5jdGlvbjdbcmlnaHQyICYgMHgzZl0pO1xuICAgICAgfVxuICAgICAgdGVtcCA9IGxlZnQ7XG4gICAgICBsZWZ0ID0gcmlnaHQ7XG4gICAgICByaWdodCA9IHRlbXA7IC8vdW5yZXZlcnNlIGxlZnQgYW5kIHJpZ2h0XG4gICAgfSAvL2ZvciBlaXRoZXIgMSBvciAzIGl0ZXJhdGlvbnNcblxuICAgIC8vbW92ZSB0aGVuIGVhY2ggb25lIGJpdCB0byB0aGUgcmlnaHRcbiAgICBsZWZ0ID0gKChsZWZ0ID4+PiAxKSB8IChsZWZ0IDw8IDMxKSk7XG4gICAgcmlnaHQgPSAoKHJpZ2h0ID4+PiAxKSB8IChyaWdodCA8PCAzMSkpO1xuXG4gICAgLy9ub3cgcGVyZm9ybSBJUC0xLCB3aGljaCBpcyBJUCBpbiB0aGUgb3Bwb3NpdGUgZGlyZWN0aW9uXG4gICAgdGVtcCA9ICgobGVmdCA+Pj4gMSkgXiByaWdodCkgJiAweDU1NTU1NTU1O1xuICAgIHJpZ2h0IF49IHRlbXA7XG4gICAgbGVmdCBePSAodGVtcCA8PCAxKTtcbiAgICB0ZW1wID0gKChyaWdodCA+Pj4gOCkgXiBsZWZ0KSAmIDB4MDBmZjAwZmY7XG4gICAgbGVmdCBePSB0ZW1wO1xuICAgIHJpZ2h0IF49ICh0ZW1wIDw8IDgpO1xuICAgIHRlbXAgPSAoKHJpZ2h0ID4+PiAyKSBeIGxlZnQpICYgMHgzMzMzMzMzMztcbiAgICBsZWZ0IF49IHRlbXA7XG4gICAgcmlnaHQgXj0gKHRlbXAgPDwgMik7XG4gICAgdGVtcCA9ICgobGVmdCA+Pj4gMTYpIF4gcmlnaHQpICYgMHgwMDAwZmZmZjtcbiAgICByaWdodCBePSB0ZW1wO1xuICAgIGxlZnQgXj0gKHRlbXAgPDwgMTYpO1xuICAgIHRlbXAgPSAoKGxlZnQgPj4+IDQpIF4gcmlnaHQpICYgMHgwZjBmMGYwZjtcbiAgICByaWdodCBePSB0ZW1wO1xuICAgIGxlZnQgXj0gKHRlbXAgPDwgNCk7XG5cbiAgICAvL2ZvciBDaXBoZXIgQmxvY2sgQ2hhaW5pbmcgbW9kZSwgeG9yIHRoZSBtZXNzYWdlIHdpdGggdGhlIHByZXZpb3VzIHJlc3VsdFxuICAgIGlmIChtb2RlID09IDEpIHtcbiAgICAgIGlmIChlbmNyeXB0KSB7XG4gICAgICAgIGNiY2xlZnQgPSBsZWZ0O1xuICAgICAgICBjYmNyaWdodCA9IHJpZ2h0O1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgbGVmdCBePSBjYmNsZWZ0MjtcbiAgICAgICAgcmlnaHQgXj0gY2JjcmlnaHQyO1xuICAgICAgfVxuICAgIH1cbiAgICB0ZW1wcmVzdWx0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoKGxlZnQgPj4+IDI0KSwgKChsZWZ0ID4+PiAxNikgJiAweGZmKSwgKChsZWZ0ID4+PiA4KSAmIDB4ZmYpLCAobGVmdCAmIDB4ZmYpLCAoXG4gICAgICByaWdodCA+Pj4gMjQpLCAoKHJpZ2h0ID4+PiAxNikgJiAweGZmKSwgKChyaWdodCA+Pj4gOCkgJiAweGZmKSwgKHJpZ2h0ICYgMHhmZikpO1xuXG4gICAgY2h1bmsgKz0gODtcbiAgICBpZiAoY2h1bmsgPT0gNTEyKSB7XG4gICAgICByZXN1bHQgKz0gdGVtcHJlc3VsdDtcbiAgICAgIHRlbXByZXN1bHQgPSBcIlwiO1xuICAgICAgY2h1bmsgPSAwO1xuICAgIH1cbiAgfSAvL2ZvciBldmVyeSA4IGNoYXJhY3RlcnMsIG9yIDY0IGJpdHMgaW4gdGhlIG1lc3NhZ2VcblxuICAvL3JldHVybiB0aGUgcmVzdWx0IGFzIGFuIGFycmF5XG4gIHJlc3VsdCArPSB0ZW1wcmVzdWx0O1xuXG4gIC8vb25seSByZW1vdmUgcGFkZGluZyBpZiBkZWNyeXB0aW5nIC0gbm90ZSB0aGF0IHlvdSBuZWVkIHRvIHVzZSB0aGUgc2FtZSBwYWRkaW5nIG9wdGlvbiBmb3IgYm90aCBlbmNyeXB0IGFuZCBkZWNyeXB0XG4gIGlmICghZW5jcnlwdCkge1xuICAgIHJlc3VsdCA9IGRlc19yZW1vdmVQYWRkaW5nKHJlc3VsdCwgcGFkZGluZyk7XG4gIH1cblxuICByZXR1cm4gcmVzdWx0O1xufSAvL2VuZCBvZiBkZXNcblxuXG5cbi8vZGVzX2NyZWF0ZUtleXNcbi8vdGhpcyB0YWtlcyBhcyBpbnB1dCBhIDY0IGJpdCBrZXkgKGV2ZW4gdGhvdWdoIG9ubHkgNTYgYml0cyBhcmUgdXNlZClcbi8vYXMgYW4gYXJyYXkgb2YgMiBpbnRlZ2VycywgYW5kIHJldHVybnMgMTYgNDggYml0IGtleXNcblxuZnVuY3Rpb24gZGVzX2NyZWF0ZUtleXMoa2V5KSB7XG4gIC8vZGVjbGFyaW5nIHRoaXMgbG9jYWxseSBzcGVlZHMgdGhpbmdzIHVwIGEgYml0XG4gIHBjMmJ5dGVzMCA9IG5ldyBBcnJheSgwLCAweDQsIDB4MjAwMDAwMDAsIDB4MjAwMDAwMDQsIDB4MTAwMDAsIDB4MTAwMDQsIDB4MjAwMTAwMDAsIDB4MjAwMTAwMDQsIDB4MjAwLCAweDIwNCxcbiAgICAweDIwMDAwMjAwLCAweDIwMDAwMjA0LCAweDEwMjAwLCAweDEwMjA0LCAweDIwMDEwMjAwLCAweDIwMDEwMjA0KTtcbiAgcGMyYnl0ZXMxID0gbmV3IEFycmF5KDAsIDB4MSwgMHgxMDAwMDAsIDB4MTAwMDAxLCAweDQwMDAwMDAsIDB4NDAwMDAwMSwgMHg0MTAwMDAwLCAweDQxMDAwMDEsIDB4MTAwLCAweDEwMSwgMHgxMDAxMDAsXG4gICAgMHgxMDAxMDEsIDB4NDAwMDEwMCwgMHg0MDAwMTAxLCAweDQxMDAxMDAsIDB4NDEwMDEwMSk7XG4gIHBjMmJ5dGVzMiA9IG5ldyBBcnJheSgwLCAweDgsIDB4ODAwLCAweDgwOCwgMHgxMDAwMDAwLCAweDEwMDAwMDgsIDB4MTAwMDgwMCwgMHgxMDAwODA4LCAwLCAweDgsIDB4ODAwLCAweDgwOCxcbiAgICAweDEwMDAwMDAsIDB4MTAwMDAwOCwgMHgxMDAwODAwLCAweDEwMDA4MDgpO1xuICBwYzJieXRlczMgPSBuZXcgQXJyYXkoMCwgMHgyMDAwMDAsIDB4ODAwMDAwMCwgMHg4MjAwMDAwLCAweDIwMDAsIDB4MjAyMDAwLCAweDgwMDIwMDAsIDB4ODIwMjAwMCwgMHgyMDAwMCwgMHgyMjAwMDAsXG4gICAgMHg4MDIwMDAwLCAweDgyMjAwMDAsIDB4MjIwMDAsIDB4MjIyMDAwLCAweDgwMjIwMDAsIDB4ODIyMjAwMCk7XG4gIHBjMmJ5dGVzNCA9IG5ldyBBcnJheSgwLCAweDQwMDAwLCAweDEwLCAweDQwMDEwLCAwLCAweDQwMDAwLCAweDEwLCAweDQwMDEwLCAweDEwMDAsIDB4NDEwMDAsIDB4MTAxMCwgMHg0MTAxMCwgMHgxMDAwLFxuICAgIDB4NDEwMDAsIDB4MTAxMCwgMHg0MTAxMCk7XG4gIHBjMmJ5dGVzNSA9IG5ldyBBcnJheSgwLCAweDQwMCwgMHgyMCwgMHg0MjAsIDAsIDB4NDAwLCAweDIwLCAweDQyMCwgMHgyMDAwMDAwLCAweDIwMDA0MDAsIDB4MjAwMDAyMCwgMHgyMDAwNDIwLFxuICAgIDB4MjAwMDAwMCwgMHgyMDAwNDAwLCAweDIwMDAwMjAsIDB4MjAwMDQyMCk7XG4gIHBjMmJ5dGVzNiA9IG5ldyBBcnJheSgwLCAweDEwMDAwMDAwLCAweDgwMDAwLCAweDEwMDgwMDAwLCAweDIsIDB4MTAwMDAwMDIsIDB4ODAwMDIsIDB4MTAwODAwMDIsIDAsIDB4MTAwMDAwMDAsXG4gICAgMHg4MDAwMCwgMHgxMDA4MDAwMCwgMHgyLCAweDEwMDAwMDAyLCAweDgwMDAyLCAweDEwMDgwMDAyKTtcbiAgcGMyYnl0ZXM3ID0gbmV3IEFycmF5KDAsIDB4MTAwMDAsIDB4ODAwLCAweDEwODAwLCAweDIwMDAwMDAwLCAweDIwMDEwMDAwLCAweDIwMDAwODAwLCAweDIwMDEwODAwLCAweDIwMDAwLCAweDMwMDAwLFxuICAgIDB4MjA4MDAsIDB4MzA4MDAsIDB4MjAwMjAwMDAsIDB4MjAwMzAwMDAsIDB4MjAwMjA4MDAsIDB4MjAwMzA4MDApO1xuICBwYzJieXRlczggPSBuZXcgQXJyYXkoMCwgMHg0MDAwMCwgMCwgMHg0MDAwMCwgMHgyLCAweDQwMDAyLCAweDIsIDB4NDAwMDIsIDB4MjAwMDAwMCwgMHgyMDQwMDAwLCAweDIwMDAwMDAsIDB4MjA0MDAwMCxcbiAgICAweDIwMDAwMDIsIDB4MjA0MDAwMiwgMHgyMDAwMDAyLCAweDIwNDAwMDIpO1xuICBwYzJieXRlczkgPSBuZXcgQXJyYXkoMCwgMHgxMDAwMDAwMCwgMHg4LCAweDEwMDAwMDA4LCAwLCAweDEwMDAwMDAwLCAweDgsIDB4MTAwMDAwMDgsIDB4NDAwLCAweDEwMDAwNDAwLCAweDQwOCxcbiAgICAweDEwMDAwNDA4LCAweDQwMCwgMHgxMDAwMDQwMCwgMHg0MDgsIDB4MTAwMDA0MDgpO1xuICBwYzJieXRlczEwID0gbmV3IEFycmF5KDAsIDB4MjAsIDAsIDB4MjAsIDB4MTAwMDAwLCAweDEwMDAyMCwgMHgxMDAwMDAsIDB4MTAwMDIwLCAweDIwMDAsIDB4MjAyMCwgMHgyMDAwLCAweDIwMjAsXG4gICAgMHgxMDIwMDAsIDB4MTAyMDIwLCAweDEwMjAwMCwgMHgxMDIwMjApO1xuICBwYzJieXRlczExID0gbmV3IEFycmF5KDAsIDB4MTAwMDAwMCwgMHgyMDAsIDB4MTAwMDIwMCwgMHgyMDAwMDAsIDB4MTIwMDAwMCwgMHgyMDAyMDAsIDB4MTIwMDIwMCwgMHg0MDAwMDAwLCAweDUwMDAwMDAsXG4gICAgMHg0MDAwMjAwLCAweDUwMDAyMDAsIDB4NDIwMDAwMCwgMHg1MjAwMDAwLCAweDQyMDAyMDAsIDB4NTIwMDIwMCk7XG4gIHBjMmJ5dGVzMTIgPSBuZXcgQXJyYXkoMCwgMHgxMDAwLCAweDgwMDAwMDAsIDB4ODAwMTAwMCwgMHg4MDAwMCwgMHg4MTAwMCwgMHg4MDgwMDAwLCAweDgwODEwMDAsIDB4MTAsIDB4MTAxMCxcbiAgICAweDgwMDAwMTAsIDB4ODAwMTAxMCwgMHg4MDAxMCwgMHg4MTAxMCwgMHg4MDgwMDEwLCAweDgwODEwMTApO1xuICBwYzJieXRlczEzID0gbmV3IEFycmF5KDAsIDB4NCwgMHgxMDAsIDB4MTA0LCAwLCAweDQsIDB4MTAwLCAweDEwNCwgMHgxLCAweDUsIDB4MTAxLCAweDEwNSwgMHgxLCAweDUsIDB4MTAxLCAweDEwNSk7XG5cbiAgLy9ob3cgbWFueSBpdGVyYXRpb25zICgxIGZvciBkZXMsIDMgZm9yIHRyaXBsZSBkZXMpXG4gIHZhciBpdGVyYXRpb25zID0ga2V5Lmxlbmd0aCA+IDggPyAzIDogMTsgLy9jaGFuZ2VkIGJ5IFBhdWwgMTYvNi8yMDA3IHRvIHVzZSBUcmlwbGUgREVTIGZvciA5KyBieXRlIGtleXNcbiAgLy9zdG9yZXMgdGhlIHJldHVybiBrZXlzXG4gIHZhciBrZXlzID0gbmV3IEFycmF5KDMyICogaXRlcmF0aW9ucyk7XG4gIC8vbm93IGRlZmluZSB0aGUgbGVmdCBzaGlmdHMgd2hpY2ggbmVlZCB0byBiZSBkb25lXG4gIHZhciBzaGlmdHMgPSBuZXcgQXJyYXkoMCwgMCwgMSwgMSwgMSwgMSwgMSwgMSwgMCwgMSwgMSwgMSwgMSwgMSwgMSwgMCk7XG4gIC8vb3RoZXIgdmFyaWFibGVzXG4gIHZhciBsZWZ0dGVtcCwgcmlnaHR0ZW1wLCBtID0gMCxcbiAgICBuID0gMCxcbiAgICB0ZW1wO1xuXG4gIGZvciAodmFyIGogPSAwOyBqIDwgaXRlcmF0aW9uczsgaisrKSB7IC8vZWl0aGVyIDEgb3IgMyBpdGVyYXRpb25zXG4gICAgbGVmdCA9IChrZXkuY2hhckNvZGVBdChtKyspIDw8IDI0KSB8IChrZXkuY2hhckNvZGVBdChtKyspIDw8IDE2KSB8IChrZXkuY2hhckNvZGVBdChtKyspIDw8IDgpIHwga2V5LmNoYXJDb2RlQXQobSsrKTtcbiAgICByaWdodCA9IChrZXkuY2hhckNvZGVBdChtKyspIDw8IDI0KSB8IChrZXkuY2hhckNvZGVBdChtKyspIDw8IDE2KSB8IChrZXkuY2hhckNvZGVBdChtKyspIDw8IDgpIHwga2V5LmNoYXJDb2RlQXQobSsrKTtcblxuICAgIHRlbXAgPSAoKGxlZnQgPj4+IDQpIF4gcmlnaHQpICYgMHgwZjBmMGYwZjtcbiAgICByaWdodCBePSB0ZW1wO1xuICAgIGxlZnQgXj0gKHRlbXAgPDwgNCk7XG4gICAgdGVtcCA9ICgocmlnaHQgPj4+IC0xNikgXiBsZWZ0KSAmIDB4MDAwMGZmZmY7XG4gICAgbGVmdCBePSB0ZW1wO1xuICAgIHJpZ2h0IF49ICh0ZW1wIDw8IC0xNik7XG4gICAgdGVtcCA9ICgobGVmdCA+Pj4gMikgXiByaWdodCkgJiAweDMzMzMzMzMzO1xuICAgIHJpZ2h0IF49IHRlbXA7XG4gICAgbGVmdCBePSAodGVtcCA8PCAyKTtcbiAgICB0ZW1wID0gKChyaWdodCA+Pj4gLTE2KSBeIGxlZnQpICYgMHgwMDAwZmZmZjtcbiAgICBsZWZ0IF49IHRlbXA7XG4gICAgcmlnaHQgXj0gKHRlbXAgPDwgLTE2KTtcbiAgICB0ZW1wID0gKChsZWZ0ID4+PiAxKSBeIHJpZ2h0KSAmIDB4NTU1NTU1NTU7XG4gICAgcmlnaHQgXj0gdGVtcDtcbiAgICBsZWZ0IF49ICh0ZW1wIDw8IDEpO1xuICAgIHRlbXAgPSAoKHJpZ2h0ID4+PiA4KSBeIGxlZnQpICYgMHgwMGZmMDBmZjtcbiAgICBsZWZ0IF49IHRlbXA7XG4gICAgcmlnaHQgXj0gKHRlbXAgPDwgOCk7XG4gICAgdGVtcCA9ICgobGVmdCA+Pj4gMSkgXiByaWdodCkgJiAweDU1NTU1NTU1O1xuICAgIHJpZ2h0IF49IHRlbXA7XG4gICAgbGVmdCBePSAodGVtcCA8PCAxKTtcblxuICAgIC8vdGhlIHJpZ2h0IHNpZGUgbmVlZHMgdG8gYmUgc2hpZnRlZCBhbmQgdG8gZ2V0IHRoZSBsYXN0IGZvdXIgYml0cyBvZiB0aGUgbGVmdCBzaWRlXG4gICAgdGVtcCA9IChsZWZ0IDw8IDgpIHwgKChyaWdodCA+Pj4gMjApICYgMHgwMDAwMDBmMCk7XG4gICAgLy9sZWZ0IG5lZWRzIHRvIGJlIHB1dCB1cHNpZGUgZG93blxuICAgIGxlZnQgPSAocmlnaHQgPDwgMjQpIHwgKChyaWdodCA8PCA4KSAmIDB4ZmYwMDAwKSB8ICgocmlnaHQgPj4+IDgpICYgMHhmZjAwKSB8ICgocmlnaHQgPj4+IDI0KSAmIDB4ZjApO1xuICAgIHJpZ2h0ID0gdGVtcDtcblxuICAgIC8vbm93IGdvIHRocm91Z2ggYW5kIHBlcmZvcm0gdGhlc2Ugc2hpZnRzIG9uIHRoZSBsZWZ0IGFuZCByaWdodCBrZXlzXG4gICAgZm9yIChpID0gMDsgaSA8IHNoaWZ0cy5sZW5ndGg7IGkrKykge1xuICAgICAgLy9zaGlmdCB0aGUga2V5cyBlaXRoZXIgb25lIG9yIHR3byBiaXRzIHRvIHRoZSBsZWZ0XG4gICAgICBpZiAoc2hpZnRzW2ldKSB7XG4gICAgICAgIGxlZnQgPSAobGVmdCA8PCAyKSB8IChsZWZ0ID4+PiAyNik7XG4gICAgICAgIHJpZ2h0ID0gKHJpZ2h0IDw8IDIpIHwgKHJpZ2h0ID4+PiAyNik7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBsZWZ0ID0gKGxlZnQgPDwgMSkgfCAobGVmdCA+Pj4gMjcpO1xuICAgICAgICByaWdodCA9IChyaWdodCA8PCAxKSB8IChyaWdodCA+Pj4gMjcpO1xuICAgICAgfVxuICAgICAgbGVmdCAmPSAtMHhmO1xuICAgICAgcmlnaHQgJj0gLTB4ZjtcblxuICAgICAgLy9ub3cgYXBwbHkgUEMtMiwgaW4gc3VjaCBhIHdheSB0aGF0IEUgaXMgZWFzaWVyIHdoZW4gZW5jcnlwdGluZyBvciBkZWNyeXB0aW5nXG4gICAgICAvL3RoaXMgY29udmVyc2lvbiB3aWxsIGxvb2sgbGlrZSBQQy0yIGV4Y2VwdCBvbmx5IHRoZSBsYXN0IDYgYml0cyBvZiBlYWNoIGJ5dGUgYXJlIHVzZWRcbiAgICAgIC8vcmF0aGVyIHRoYW4gNDggY29uc2VjdXRpdmUgYml0cyBhbmQgdGhlIG9yZGVyIG9mIGxpbmVzIHdpbGwgYmUgYWNjb3JkaW5nIHRvIFxuICAgICAgLy9ob3cgdGhlIFMgc2VsZWN0aW9uIGZ1bmN0aW9ucyB3aWxsIGJlIGFwcGxpZWQ6IFMyLCBTNCwgUzYsIFM4LCBTMSwgUzMsIFM1LCBTN1xuICAgICAgbGVmdHRlbXAgPSBwYzJieXRlczBbbGVmdCA+Pj4gMjhdIHwgcGMyYnl0ZXMxWyhsZWZ0ID4+PiAyNCkgJiAweGZdIHwgcGMyYnl0ZXMyWyhsZWZ0ID4+PiAyMCkgJiAweGZdIHwgcGMyYnl0ZXMzWyhcbiAgICAgICAgbGVmdCA+Pj4gMTYpICYgMHhmXSB8IHBjMmJ5dGVzNFsobGVmdCA+Pj4gMTIpICYgMHhmXSB8IHBjMmJ5dGVzNVsobGVmdCA+Pj4gOCkgJiAweGZdIHwgcGMyYnl0ZXM2WyhsZWZ0ID4+PiA0KSAmXG4gICAgICAgIDB4Zl07XG4gICAgICByaWdodHRlbXAgPSBwYzJieXRlczdbcmlnaHQgPj4+IDI4XSB8IHBjMmJ5dGVzOFsocmlnaHQgPj4+IDI0KSAmIDB4Zl0gfCBwYzJieXRlczlbKHJpZ2h0ID4+PiAyMCkgJiAweGZdIHxcbiAgICAgICAgcGMyYnl0ZXMxMFsocmlnaHQgPj4+IDE2KSAmIDB4Zl0gfCBwYzJieXRlczExWyhyaWdodCA+Pj4gMTIpICYgMHhmXSB8IHBjMmJ5dGVzMTJbKHJpZ2h0ID4+PiA4KSAmIDB4Zl0gfFxuICAgICAgICBwYzJieXRlczEzWyhyaWdodCA+Pj4gNCkgJiAweGZdO1xuICAgICAgdGVtcCA9ICgocmlnaHR0ZW1wID4+PiAxNikgXiBsZWZ0dGVtcCkgJiAweDAwMDBmZmZmO1xuICAgICAga2V5c1tuKytdID0gbGVmdHRlbXAgXiB0ZW1wO1xuICAgICAga2V5c1tuKytdID0gcmlnaHR0ZW1wIF4gKHRlbXAgPDwgMTYpO1xuICAgIH1cbiAgfSAvL2ZvciBlYWNoIGl0ZXJhdGlvbnNcbiAgLy9yZXR1cm4gdGhlIGtleXMgd2UndmUgY3JlYXRlZFxuICByZXR1cm4ga2V5cztcbn0gLy9lbmQgb2YgZGVzX2NyZWF0ZUtleXNcblxuXG5mdW5jdGlvbiBkZXNfYWRkUGFkZGluZyhtZXNzYWdlLCBwYWRkaW5nKSB7XG4gIHZhciBwYWRMZW5ndGggPSA4IC0gKG1lc3NhZ2UubGVuZ3RoICUgOCk7XG4gIGlmICgocGFkZGluZyA9PSAyKSAmJiAocGFkTGVuZ3RoIDwgOCkpIHsgLy9wYWQgdGhlIG1lc3NhZ2Ugd2l0aCBzcGFjZXNcbiAgICBtZXNzYWdlICs9IFwiICAgICAgICBcIi5zdWJzdHIoMCwgcGFkTGVuZ3RoKTtcbiAgfSBlbHNlIGlmIChwYWRkaW5nID09IDEpIHsgLy9QS0NTNyBwYWRkaW5nXG4gICAgbWVzc2FnZSArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKHBhZExlbmd0aCwgcGFkTGVuZ3RoLCBwYWRMZW5ndGgsIHBhZExlbmd0aCwgcGFkTGVuZ3RoLCBwYWRMZW5ndGgsIHBhZExlbmd0aCxcbiAgICAgIHBhZExlbmd0aCkuc3Vic3RyKDAsIHBhZExlbmd0aCk7XG4gIH0gZWxzZSBpZiAoIXBhZGRpbmcgJiYgKHBhZExlbmd0aCA8IDgpKSB7IC8vcGFkIHRoZSBtZXNzYWdlIG91dCB3aXRoIG51bGwgYnl0ZXNcbiAgICBtZXNzYWdlICs9IFwiXFwwXFwwXFwwXFwwXFwwXFwwXFwwXFwwXCIuc3Vic3RyKDAsIHBhZExlbmd0aCk7XG4gIH1cbiAgcmV0dXJuIG1lc3NhZ2U7XG59XG5cbmZ1bmN0aW9uIGRlc19yZW1vdmVQYWRkaW5nKG1lc3NhZ2UsIHBhZGRpbmcpIHtcbiAgaWYgKHBhZGRpbmcgPT0gMikgeyAvLyBzcGFjZSBwYWRkZWRcbiAgICBtZXNzYWdlID0gbWVzc2FnZS5yZXBsYWNlKC8gKiQvZywgXCJcIik7XG4gIH0gZWxzZSBpZiAocGFkZGluZyA9PSAxKSB7IC8vIFBLQ1M3XG4gICAgdmFyIHBhZENvdW50ID0gbWVzc2FnZS5jaGFyQ29kZUF0KG1lc3NhZ2UubGVuZ3RoIC0gMSk7XG4gICAgbWVzc2FnZSA9IG1lc3NhZ2Uuc3Vic3RyKDAsIG1lc3NhZ2UubGVuZ3RoIC0gcGFkQ291bnQpO1xuICB9IGVsc2UgaWYgKCFwYWRkaW5nKSB7IC8vIG51bGwgcGFkZGluZ1xuICAgIG1lc3NhZ2UgPSBtZXNzYWdlLnJlcGxhY2UoL1xcMCokL2csIFwiXCIpO1xuICB9XG4gIHJldHVybiBtZXNzYWdlO1xufVxuXG5cbnZhciB1dGlsID0gcmVxdWlyZSgnLi4vLi4vdXRpbCcpO1xuXG4vLyBhZGRlZCBieSBSZWN1cml0eSBMYWJzXG5cbmZ1bmN0aW9uIERlcyhrZXkpIHtcbiAgdGhpcy5rZXkgPSBbXTtcblxuICBmb3IgKHZhciBpID0gMDsgaSA8IDM7IGkrKykge1xuICAgIHRoaXMua2V5LnB1c2goa2V5LnN1YnN0cihpICogOCwgOCkpO1xuICB9XG5cbiAgdGhpcy5lbmNyeXB0ID0gZnVuY3Rpb24oYmxvY2spIHtcbiAgICByZXR1cm4gdXRpbC5zdHIyYmluKGRlcyhkZXNfY3JlYXRlS2V5cyh0aGlzLmtleVsyXSksXG4gICAgICBkZXMoZGVzX2NyZWF0ZUtleXModGhpcy5rZXlbMV0pLFxuICAgICAgZGVzKGRlc19jcmVhdGVLZXlzKHRoaXMua2V5WzBdKSxcbiAgICAgIHV0aWwuYmluMnN0cihibG9jayksIHRydWUsIDAsIG51bGwsIG51bGwpLFxuICAgICAgZmFsc2UsIDAsIG51bGwsIG51bGwpLCB0cnVlLCAwLCBudWxsLCBudWxsKSk7XG4gIH1cbn1cblxuRGVzLmtleVNpemUgPSBEZXMucHJvdG90eXBlLmtleVNpemUgPSAyNDtcbkRlcy5ibG9ja1NpemUgPSBEZXMucHJvdG90eXBlLmJsb2NrU2l6ZSA9IDg7XG5cbi8vIFRoaXMgaXMgXCJvcmlnaW5hbFwiIERFUyAtIERlcyBpcyBhY3R1YWxseSBUcmlwbGUgREVTLlxuLy8gVGhpcyBpcyBvbmx5IGV4cG9ydGVkIHNvIHdlIGNhbiB1bml0IHRlc3QuXG5cbmZ1bmN0aW9uIE9yaWdpbmFsRGVzKGtleSkge1xuICB0aGlzLmtleSA9IGtleTtcblxuICB0aGlzLmVuY3J5cHQgPSBmdW5jdGlvbihibG9jaywgcGFkZGluZykge1xuICAgIHZhciBrZXlzID0gZGVzX2NyZWF0ZUtleXModGhpcy5rZXkpO1xuICAgIHJldHVybiB1dGlsLnN0cjJiaW4oZGVzKGtleXMsIHV0aWwuYmluMnN0cihibG9jayksIHRydWUsIDAsIG51bGwsIHBhZGRpbmcpKTtcbiAgfVxuXG4gIHRoaXMuZGVjcnlwdCA9IGZ1bmN0aW9uKGJsb2NrLCBwYWRkaW5nKSB7XG4gICAgdmFyIGtleXMgPSBkZXNfY3JlYXRlS2V5cyh0aGlzLmtleSk7XG4gICAgcmV0dXJuIHV0aWwuc3RyMmJpbihkZXMoa2V5cywgdXRpbC5iaW4yc3RyKGJsb2NrKSwgZmFsc2UsIDAsIG51bGwsIHBhZGRpbmcpKTtcbiAgfVxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgZGVzOiBEZXMsXG4gIG9yaWdpbmFsRGVzOiBPcmlnaW5hbERlc1xufVxuIiwidmFyIGRlc01vZHVsZSA9IHJlcXVpcmUoJy4vZGVzLmpzJyk7XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICBkZXM6IGRlc01vZHVsZVsnZGVzJ10sXG4gIG9yaWdpbmFsRGVzOiBkZXNNb2R1bGVbJ29yaWdpbmFsRGVzJ10sXG4gIGNhc3Q1OiByZXF1aXJlKCcuL2Nhc3Q1LmpzJyksXG4gIHR3b2Zpc2g6IHJlcXVpcmUoJy4vdHdvZmlzaC5qcycpLFxuICBibG93ZmlzaDogcmVxdWlyZSgnLi9ibG93ZmlzaC5qcycpXG59XG5cbnZhciBhZXMgPSByZXF1aXJlKCcuL2Flcy5qcycpO1xuXG5mb3IgKHZhciBpIGluIGFlcykge1xuICBtb2R1bGUuZXhwb3J0c1snYWVzJyArIGldID0gYWVzW2ldO1xufVxuIiwiLyogTW9kaWZpZWQgYnkgUmVjdXJpdHkgTGFicyBHbWJIIFxuICogXG4gKiBDaXBoZXIuanNcbiAqIEEgYmxvY2stY2lwaGVyIGFsZ29yaXRobSBpbXBsZW1lbnRhdGlvbiBvbiBKYXZhU2NyaXB0XG4gKiBTZWUgQ2lwaGVyLnJlYWRtZS50eHQgZm9yIGZ1cnRoZXIgaW5mb3JtYXRpb24uXG4gKlxuICogQ29weXJpZ2h0KGMpIDIwMDkgQXRzdXNoaSBPa2EgWyBodHRwOi8vb2thLm51LyBdXG4gKiBUaGlzIHNjcmlwdCBmaWxlIGlzIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMR1BMXG4gKlxuICogQUNLTk9XTEVER01FTlRcbiAqXG4gKiAgICAgVGhlIG1haW4gc3Vicm91dGluZXMgYXJlIHdyaXR0ZW4gYnkgTWljaGllbCB2YW4gRXZlcmRpbmdlbi5cbiAqIFxuICogICAgIE1pY2hpZWwgdmFuIEV2ZXJkaW5nZW5cbiAqICAgICBodHRwOi8vaG9tZS52ZXJzYXRlbC5ubC9NQXZhbkV2ZXJkaW5nZW4vaW5kZXguaHRtbFxuICogXG4gKiAgICAgQWxsIHJpZ2h0cyBmb3IgdGhlc2Ugcm91dGluZXMgYXJlIHJlc2VydmVkIHRvIE1pY2hpZWwgdmFuIEV2ZXJkaW5nZW4uXG4gKlxuICovXG5cblxuXG4vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy9cbi8vTWF0aFxuLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vXG5cbnZhciBNQVhJTlQgPSAweEZGRkZGRkZGO1xuXG5mdW5jdGlvbiByb3RiKGIsIG4pIHtcbiAgcmV0dXJuIChiIDw8IG4gfCBiID4+PiAoOCAtIG4pKSAmIDB4RkY7XG59XG5cbmZ1bmN0aW9uIHJvdHcodywgbikge1xuICByZXR1cm4gKHcgPDwgbiB8IHcgPj4+ICgzMiAtIG4pKSAmIE1BWElOVDtcbn1cblxuZnVuY3Rpb24gZ2V0VyhhLCBpKSB7XG4gIHJldHVybiBhW2ldIHwgYVtpICsgMV0gPDwgOCB8IGFbaSArIDJdIDw8IDE2IHwgYVtpICsgM10gPDwgMjQ7XG59XG5cbmZ1bmN0aW9uIHNldFcoYSwgaSwgdykge1xuICBhLnNwbGljZShpLCA0LCB3ICYgMHhGRiwgKHcgPj4+IDgpICYgMHhGRiwgKHcgPj4+IDE2KSAmIDB4RkYsICh3ID4+PiAyNCkgJiAweEZGKTtcbn1cblxuZnVuY3Rpb24gc2V0V0ludihhLCBpLCB3KSB7XG4gIGEuc3BsaWNlKGksIDQsICh3ID4+PiAyNCkgJiAweEZGLCAodyA+Pj4gMTYpICYgMHhGRiwgKHcgPj4+IDgpICYgMHhGRiwgdyAmIDB4RkYpO1xufVxuXG5mdW5jdGlvbiBnZXRCKHgsIG4pIHtcbiAgcmV0dXJuICh4ID4+PiAobiAqIDgpKSAmIDB4RkY7XG59XG5cbmZ1bmN0aW9uIGdldE5yQml0cyhpKSB7XG4gIHZhciBuID0gMDtcbiAgd2hpbGUgKGkgPiAwKSB7XG4gICAgbisrO1xuICAgIGkgPj4+PSAxO1xuICB9XG4gIHJldHVybiBuO1xufVxuXG5mdW5jdGlvbiBnZXRNYXNrKG4pIHtcbiAgcmV0dXJuICgxIDw8IG4pIC0gMTtcbn1cblxuLy9hZGRlZCAyMDA4LzExLzEzIFhYWCBNVVNUIFVTRSBPTkUtV0FZIEhBU0ggRlVOQ1RJT04gRk9SIFNFQ1VSSVRZIFJFQVNPTlxuXG5mdW5jdGlvbiByYW5kQnl0ZSgpIHtcbiAgcmV0dXJuIE1hdGguZmxvb3IoTWF0aC5yYW5kb20oKSAqIDI1Nik7XG59XG4vLyAvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vXG4vLyBUd29maXNoXG4vLyAvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vXG5cbmZ1bmN0aW9uIGNyZWF0ZVR3b2Zpc2goKSB7XG4gIC8vXG4gIHZhciBrZXlCeXRlcyA9IG51bGw7XG4gIHZhciBkYXRhQnl0ZXMgPSBudWxsO1xuICB2YXIgZGF0YU9mZnNldCA9IC0xO1xuICAvLyB2YXIgZGF0YUxlbmd0aCA9IC0xO1xuICB2YXIgYWxnb3JpdGhtTmFtZSA9IG51bGw7XG4gIC8vIHZhciBpZHgyID0gLTE7XG4gIC8vXG5cbiAgYWxnb3JpdGhtTmFtZSA9IFwidHdvZmlzaFwiO1xuXG4gIHZhciB0ZnNLZXkgPSBbXTtcbiAgdmFyIHRmc00gPSBbXG4gICAgW10sXG4gICAgW10sXG4gICAgW10sXG4gICAgW11cbiAgXTtcblxuICBmdW5jdGlvbiB0ZnNJbml0KGtleSkge1xuICAgIGtleUJ5dGVzID0ga2V5O1xuICAgIHZhciBpLCBhLCBiLCBjLCBkLCBtZUtleSA9IFtdLFxuICAgICAgbW9LZXkgPSBbXSxcbiAgICAgIGluS2V5ID0gW107XG4gICAgdmFyIGtMZW47XG4gICAgdmFyIHNLZXkgPSBbXTtcbiAgICB2YXIgZjAxLCBmNWIsIGZlZjtcblxuICAgIHZhciBxMCA9IFtcbiAgICAgIFs4LCAxLCA3LCAxMywgNiwgMTUsIDMsIDIsIDAsIDExLCA1LCA5LCAxNCwgMTIsIDEwLCA0XSxcbiAgICAgIFsyLCA4LCAxMSwgMTMsIDE1LCA3LCA2LCAxNCwgMywgMSwgOSwgNCwgMCwgMTAsIDEyLCA1XVxuICAgIF07XG4gICAgdmFyIHExID0gW1xuICAgICAgWzE0LCAxMiwgMTEsIDgsIDEsIDIsIDMsIDUsIDE1LCA0LCAxMCwgNiwgNywgMCwgOSwgMTNdLFxuICAgICAgWzEsIDE0LCAyLCAxMSwgNCwgMTIsIDMsIDcsIDYsIDEzLCAxMCwgNSwgMTUsIDksIDAsIDhdXG4gICAgXTtcbiAgICB2YXIgcTIgPSBbXG4gICAgICBbMTEsIDEwLCA1LCAxNCwgNiwgMTMsIDksIDAsIDEyLCA4LCAxNSwgMywgMiwgNCwgNywgMV0sXG4gICAgICBbNCwgMTIsIDcsIDUsIDEsIDYsIDksIDEwLCAwLCAxNCwgMTMsIDgsIDIsIDExLCAzLCAxNV1cbiAgICBdO1xuICAgIHZhciBxMyA9IFtcbiAgICAgIFsxMywgNywgMTUsIDQsIDEsIDIsIDYsIDE0LCA5LCAxMSwgMywgMCwgOCwgNSwgMTIsIDEwXSxcbiAgICAgIFsxMSwgOSwgNSwgMSwgMTIsIDMsIDEzLCAxNCwgNiwgNCwgNywgMTUsIDIsIDAsIDgsIDEwXVxuICAgIF07XG4gICAgdmFyIHJvcjQgPSBbMCwgOCwgMSwgOSwgMiwgMTAsIDMsIDExLCA0LCAxMiwgNSwgMTMsIDYsIDE0LCA3LCAxNV07XG4gICAgdmFyIGFzaHggPSBbMCwgOSwgMiwgMTEsIDQsIDEzLCA2LCAxNSwgOCwgMSwgMTAsIDMsIDEyLCA1LCAxNCwgN107XG4gICAgdmFyIHEgPSBbXG4gICAgICBbXSxcbiAgICAgIFtdXG4gICAgXTtcbiAgICB2YXIgbSA9IFtcbiAgICAgIFtdLFxuICAgICAgW10sXG4gICAgICBbXSxcbiAgICAgIFtdXG4gICAgXTtcblxuICAgIGZ1bmN0aW9uIGZmbTViKHgpIHtcbiAgICAgIHJldHVybiB4IF4gKHggPj4gMikgXiBbMCwgOTAsIDE4MCwgMjM4XVt4ICYgM107XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gZmZtRWYoeCkge1xuICAgICAgcmV0dXJuIHggXiAoeCA+PiAxKSBeICh4ID4+IDIpIF4gWzAsIDIzOCwgMTgwLCA5MF1beCAmIDNdO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIG1kc1JlbShwLCBxKSB7XG4gICAgICB2YXIgaSwgdCwgdTtcbiAgICAgIGZvciAoaSA9IDA7IGkgPCA4OyBpKyspIHtcbiAgICAgICAgdCA9IHEgPj4+IDI0O1xuICAgICAgICBxID0gKChxIDw8IDgpICYgTUFYSU5UKSB8IHAgPj4+IDI0O1xuICAgICAgICBwID0gKHAgPDwgOCkgJiBNQVhJTlQ7XG4gICAgICAgIHUgPSB0IDw8IDE7XG4gICAgICAgIGlmICh0ICYgMTI4KSB7XG4gICAgICAgICAgdSBePSAzMzM7XG4gICAgICAgIH1cbiAgICAgICAgcSBePSB0IF4gKHUgPDwgMTYpO1xuICAgICAgICB1IF49IHQgPj4+IDE7XG4gICAgICAgIGlmICh0ICYgMSkge1xuICAgICAgICAgIHUgXj0gMTY2O1xuICAgICAgICB9XG4gICAgICAgIHEgXj0gdSA8PCAyNCB8IHUgPDwgODtcbiAgICAgIH1cbiAgICAgIHJldHVybiBxO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIHFwKG4sIHgpIHtcbiAgICAgIHZhciBhLCBiLCBjLCBkO1xuICAgICAgYSA9IHggPj4gNDtcbiAgICAgIGIgPSB4ICYgMTU7XG4gICAgICBjID0gcTBbbl1bYSBeIGJdO1xuICAgICAgZCA9IHExW25dW3JvcjRbYl0gXiBhc2h4W2FdXTtcbiAgICAgIHJldHVybiBxM1tuXVtyb3I0W2RdIF4gYXNoeFtjXV0gPDwgNCB8IHEyW25dW2MgXiBkXTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBoRnVuKHgsIGtleSkge1xuICAgICAgdmFyIGEgPSBnZXRCKHgsIDApLFxuICAgICAgICBiID0gZ2V0Qih4LCAxKSxcbiAgICAgICAgYyA9IGdldEIoeCwgMiksXG4gICAgICAgIGQgPSBnZXRCKHgsIDMpO1xuICAgICAgc3dpdGNoIChrTGVuKSB7XG4gICAgICAgIGNhc2UgNDpcbiAgICAgICAgICBhID0gcVsxXVthXSBeIGdldEIoa2V5WzNdLCAwKTtcbiAgICAgICAgICBiID0gcVswXVtiXSBeIGdldEIoa2V5WzNdLCAxKTtcbiAgICAgICAgICBjID0gcVswXVtjXSBeIGdldEIoa2V5WzNdLCAyKTtcbiAgICAgICAgICBkID0gcVsxXVtkXSBeIGdldEIoa2V5WzNdLCAzKTtcbiAgICAgICAgY2FzZSAzOlxuICAgICAgICAgIGEgPSBxWzFdW2FdIF4gZ2V0QihrZXlbMl0sIDApO1xuICAgICAgICAgIGIgPSBxWzFdW2JdIF4gZ2V0QihrZXlbMl0sIDEpO1xuICAgICAgICAgIGMgPSBxWzBdW2NdIF4gZ2V0QihrZXlbMl0sIDIpO1xuICAgICAgICAgIGQgPSBxWzBdW2RdIF4gZ2V0QihrZXlbMl0sIDMpO1xuICAgICAgICBjYXNlIDI6XG4gICAgICAgICAgYSA9IHFbMF1bcVswXVthXSBeIGdldEIoa2V5WzFdLCAwKV0gXiBnZXRCKGtleVswXSwgMCk7XG4gICAgICAgICAgYiA9IHFbMF1bcVsxXVtiXSBeIGdldEIoa2V5WzFdLCAxKV0gXiBnZXRCKGtleVswXSwgMSk7XG4gICAgICAgICAgYyA9IHFbMV1bcVswXVtjXSBeIGdldEIoa2V5WzFdLCAyKV0gXiBnZXRCKGtleVswXSwgMik7XG4gICAgICAgICAgZCA9IHFbMV1bcVsxXVtkXSBeIGdldEIoa2V5WzFdLCAzKV0gXiBnZXRCKGtleVswXSwgMyk7XG4gICAgICB9XG4gICAgICByZXR1cm4gbVswXVthXSBeIG1bMV1bYl0gXiBtWzJdW2NdIF4gbVszXVtkXTtcbiAgICB9XG5cbiAgICBrZXlCeXRlcyA9IGtleUJ5dGVzLnNsaWNlKDAsIDMyKTtcbiAgICBpID0ga2V5Qnl0ZXMubGVuZ3RoO1xuICAgIHdoaWxlIChpICE9IDE2ICYmIGkgIT0gMjQgJiYgaSAhPSAzMilcbiAgICAgIGtleUJ5dGVzW2krK10gPSAwO1xuXG4gICAgZm9yIChpID0gMDsgaSA8IGtleUJ5dGVzLmxlbmd0aDsgaSArPSA0KSB7XG4gICAgICBpbktleVtpID4+IDJdID0gZ2V0VyhrZXlCeXRlcywgaSk7XG4gICAgfVxuICAgIGZvciAoaSA9IDA7IGkgPCAyNTY7IGkrKykge1xuICAgICAgcVswXVtpXSA9IHFwKDAsIGkpO1xuICAgICAgcVsxXVtpXSA9IHFwKDEsIGkpO1xuICAgIH1cbiAgICBmb3IgKGkgPSAwOyBpIDwgMjU2OyBpKyspIHtcbiAgICAgIGYwMSA9IHFbMV1baV07XG4gICAgICBmNWIgPSBmZm01YihmMDEpO1xuICAgICAgZmVmID0gZmZtRWYoZjAxKTtcbiAgICAgIG1bMF1baV0gPSBmMDEgKyAoZjViIDw8IDgpICsgKGZlZiA8PCAxNikgKyAoZmVmIDw8IDI0KTtcbiAgICAgIG1bMl1baV0gPSBmNWIgKyAoZmVmIDw8IDgpICsgKGYwMSA8PCAxNikgKyAoZmVmIDw8IDI0KTtcbiAgICAgIGYwMSA9IHFbMF1baV07XG4gICAgICBmNWIgPSBmZm01YihmMDEpO1xuICAgICAgZmVmID0gZmZtRWYoZjAxKTtcbiAgICAgIG1bMV1baV0gPSBmZWYgKyAoZmVmIDw8IDgpICsgKGY1YiA8PCAxNikgKyAoZjAxIDw8IDI0KTtcbiAgICAgIG1bM11baV0gPSBmNWIgKyAoZjAxIDw8IDgpICsgKGZlZiA8PCAxNikgKyAoZjViIDw8IDI0KTtcbiAgICB9XG5cbiAgICBrTGVuID0gaW5LZXkubGVuZ3RoIC8gMjtcbiAgICBmb3IgKGkgPSAwOyBpIDwga0xlbjsgaSsrKSB7XG4gICAgICBhID0gaW5LZXlbaSArIGldO1xuICAgICAgbWVLZXlbaV0gPSBhO1xuICAgICAgYiA9IGluS2V5W2kgKyBpICsgMV07XG4gICAgICBtb0tleVtpXSA9IGI7XG4gICAgICBzS2V5W2tMZW4gLSBpIC0gMV0gPSBtZHNSZW0oYSwgYik7XG4gICAgfVxuICAgIGZvciAoaSA9IDA7IGkgPCA0MDsgaSArPSAyKSB7XG4gICAgICBhID0gMHgxMDEwMTAxICogaTtcbiAgICAgIGIgPSBhICsgMHgxMDEwMTAxO1xuICAgICAgYSA9IGhGdW4oYSwgbWVLZXkpO1xuICAgICAgYiA9IHJvdHcoaEZ1bihiLCBtb0tleSksIDgpO1xuICAgICAgdGZzS2V5W2ldID0gKGEgKyBiKSAmIE1BWElOVDtcbiAgICAgIHRmc0tleVtpICsgMV0gPSByb3R3KGEgKyAyICogYiwgOSk7XG4gICAgfVxuICAgIGZvciAoaSA9IDA7IGkgPCAyNTY7IGkrKykge1xuICAgICAgYSA9IGIgPSBjID0gZCA9IGk7XG4gICAgICBzd2l0Y2ggKGtMZW4pIHtcbiAgICAgICAgY2FzZSA0OlxuICAgICAgICAgIGEgPSBxWzFdW2FdIF4gZ2V0QihzS2V5WzNdLCAwKTtcbiAgICAgICAgICBiID0gcVswXVtiXSBeIGdldEIoc0tleVszXSwgMSk7XG4gICAgICAgICAgYyA9IHFbMF1bY10gXiBnZXRCKHNLZXlbM10sIDIpO1xuICAgICAgICAgIGQgPSBxWzFdW2RdIF4gZ2V0QihzS2V5WzNdLCAzKTtcbiAgICAgICAgY2FzZSAzOlxuICAgICAgICAgIGEgPSBxWzFdW2FdIF4gZ2V0QihzS2V5WzJdLCAwKTtcbiAgICAgICAgICBiID0gcVsxXVtiXSBeIGdldEIoc0tleVsyXSwgMSk7XG4gICAgICAgICAgYyA9IHFbMF1bY10gXiBnZXRCKHNLZXlbMl0sIDIpO1xuICAgICAgICAgIGQgPSBxWzBdW2RdIF4gZ2V0QihzS2V5WzJdLCAzKTtcbiAgICAgICAgY2FzZSAyOlxuICAgICAgICAgIHRmc01bMF1baV0gPSBtWzBdW3FbMF1bcVswXVthXSBeIGdldEIoc0tleVsxXSwgMCldIF4gZ2V0QihzS2V5WzBdLCAwKV07XG4gICAgICAgICAgdGZzTVsxXVtpXSA9IG1bMV1bcVswXVtxWzFdW2JdIF4gZ2V0QihzS2V5WzFdLCAxKV0gXiBnZXRCKHNLZXlbMF0sIDEpXTtcbiAgICAgICAgICB0ZnNNWzJdW2ldID0gbVsyXVtxWzFdW3FbMF1bY10gXiBnZXRCKHNLZXlbMV0sIDIpXSBeIGdldEIoc0tleVswXSwgMildO1xuICAgICAgICAgIHRmc01bM11baV0gPSBtWzNdW3FbMV1bcVsxXVtkXSBeIGdldEIoc0tleVsxXSwgMyldIF4gZ2V0QihzS2V5WzBdLCAzKV07XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgZnVuY3Rpb24gdGZzRzAoeCkge1xuICAgIHJldHVybiB0ZnNNWzBdW2dldEIoeCwgMCldIF4gdGZzTVsxXVtnZXRCKHgsIDEpXSBeIHRmc01bMl1bZ2V0Qih4LCAyKV0gXiB0ZnNNWzNdW2dldEIoeCwgMyldO1xuICB9XG5cbiAgZnVuY3Rpb24gdGZzRzEoeCkge1xuICAgIHJldHVybiB0ZnNNWzBdW2dldEIoeCwgMyldIF4gdGZzTVsxXVtnZXRCKHgsIDApXSBeIHRmc01bMl1bZ2V0Qih4LCAxKV0gXiB0ZnNNWzNdW2dldEIoeCwgMildO1xuICB9XG5cbiAgZnVuY3Rpb24gdGZzRnJuZChyLCBibGspIHtcbiAgICB2YXIgYSA9IHRmc0cwKGJsa1swXSk7XG4gICAgdmFyIGIgPSB0ZnNHMShibGtbMV0pO1xuICAgIGJsa1syXSA9IHJvdHcoYmxrWzJdIF4gKGEgKyBiICsgdGZzS2V5WzQgKiByICsgOF0pICYgTUFYSU5ULCAzMSk7XG4gICAgYmxrWzNdID0gcm90dyhibGtbM10sIDEpIF4gKGEgKyAyICogYiArIHRmc0tleVs0ICogciArIDldKSAmIE1BWElOVDtcbiAgICBhID0gdGZzRzAoYmxrWzJdKTtcbiAgICBiID0gdGZzRzEoYmxrWzNdKTtcbiAgICBibGtbMF0gPSByb3R3KGJsa1swXSBeIChhICsgYiArIHRmc0tleVs0ICogciArIDEwXSkgJiBNQVhJTlQsIDMxKTtcbiAgICBibGtbMV0gPSByb3R3KGJsa1sxXSwgMSkgXiAoYSArIDIgKiBiICsgdGZzS2V5WzQgKiByICsgMTFdKSAmIE1BWElOVDtcbiAgfVxuXG4gIGZ1bmN0aW9uIHRmc0lybmQoaSwgYmxrKSB7XG4gICAgdmFyIGEgPSB0ZnNHMChibGtbMF0pO1xuICAgIHZhciBiID0gdGZzRzEoYmxrWzFdKTtcbiAgICBibGtbMl0gPSByb3R3KGJsa1syXSwgMSkgXiAoYSArIGIgKyB0ZnNLZXlbNCAqIGkgKyAxMF0pICYgTUFYSU5UO1xuICAgIGJsa1szXSA9IHJvdHcoYmxrWzNdIF4gKGEgKyAyICogYiArIHRmc0tleVs0ICogaSArIDExXSkgJiBNQVhJTlQsIDMxKTtcbiAgICBhID0gdGZzRzAoYmxrWzJdKTtcbiAgICBiID0gdGZzRzEoYmxrWzNdKTtcbiAgICBibGtbMF0gPSByb3R3KGJsa1swXSwgMSkgXiAoYSArIGIgKyB0ZnNLZXlbNCAqIGkgKyA4XSkgJiBNQVhJTlQ7XG4gICAgYmxrWzFdID0gcm90dyhibGtbMV0gXiAoYSArIDIgKiBiICsgdGZzS2V5WzQgKiBpICsgOV0pICYgTUFYSU5ULCAzMSk7XG4gIH1cblxuICBmdW5jdGlvbiB0ZnNDbG9zZSgpIHtcbiAgICB0ZnNLZXkgPSBbXTtcbiAgICB0ZnNNID0gW1xuICAgICAgW10sXG4gICAgICBbXSxcbiAgICAgIFtdLFxuICAgICAgW11cbiAgICBdO1xuICB9XG5cbiAgZnVuY3Rpb24gdGZzRW5jcnlwdChkYXRhLCBvZmZzZXQpIHtcbiAgICBkYXRhQnl0ZXMgPSBkYXRhO1xuICAgIGRhdGFPZmZzZXQgPSBvZmZzZXQ7XG4gICAgdmFyIGJsayA9IFtnZXRXKGRhdGFCeXRlcywgZGF0YU9mZnNldCkgXiB0ZnNLZXlbMF0sXG4gICAgICAgIGdldFcoZGF0YUJ5dGVzLCBkYXRhT2Zmc2V0ICsgNCkgXiB0ZnNLZXlbMV0sXG4gICAgICAgIGdldFcoZGF0YUJ5dGVzLCBkYXRhT2Zmc2V0ICsgOCkgXiB0ZnNLZXlbMl0sXG4gICAgICAgIGdldFcoZGF0YUJ5dGVzLCBkYXRhT2Zmc2V0ICsgMTIpIF4gdGZzS2V5WzNdXG4gICAgXTtcbiAgICBmb3IgKHZhciBqID0gMDsgaiA8IDg7IGorKykge1xuICAgICAgdGZzRnJuZChqLCBibGspO1xuICAgIH1cbiAgICBzZXRXKGRhdGFCeXRlcywgZGF0YU9mZnNldCwgYmxrWzJdIF4gdGZzS2V5WzRdKTtcbiAgICBzZXRXKGRhdGFCeXRlcywgZGF0YU9mZnNldCArIDQsIGJsa1szXSBeIHRmc0tleVs1XSk7XG4gICAgc2V0VyhkYXRhQnl0ZXMsIGRhdGFPZmZzZXQgKyA4LCBibGtbMF0gXiB0ZnNLZXlbNl0pO1xuICAgIHNldFcoZGF0YUJ5dGVzLCBkYXRhT2Zmc2V0ICsgMTIsIGJsa1sxXSBeIHRmc0tleVs3XSk7XG4gICAgZGF0YU9mZnNldCArPSAxNjtcbiAgICByZXR1cm4gZGF0YUJ5dGVzO1xuICB9XG5cbiAgZnVuY3Rpb24gdGZzRGVjcnlwdChkYXRhLCBvZmZzZXQpIHtcbiAgICBkYXRhQnl0ZXMgPSBkYXRhO1xuICAgIGRhdGFPZmZzZXQgPSBvZmZzZXQ7XG4gICAgdmFyIGJsayA9IFtnZXRXKGRhdGFCeXRlcywgZGF0YU9mZnNldCkgXiB0ZnNLZXlbNF0sXG4gICAgICAgIGdldFcoZGF0YUJ5dGVzLCBkYXRhT2Zmc2V0ICsgNCkgXiB0ZnNLZXlbNV0sXG4gICAgICAgIGdldFcoZGF0YUJ5dGVzLCBkYXRhT2Zmc2V0ICsgOCkgXiB0ZnNLZXlbNl0sXG4gICAgICAgIGdldFcoZGF0YUJ5dGVzLCBkYXRhT2Zmc2V0ICsgMTIpIF4gdGZzS2V5WzddXG4gICAgXTtcbiAgICBmb3IgKHZhciBqID0gNzsgaiA+PSAwOyBqLS0pIHtcbiAgICAgIHRmc0lybmQoaiwgYmxrKTtcbiAgICB9XG4gICAgc2V0VyhkYXRhQnl0ZXMsIGRhdGFPZmZzZXQsIGJsa1syXSBeIHRmc0tleVswXSk7XG4gICAgc2V0VyhkYXRhQnl0ZXMsIGRhdGFPZmZzZXQgKyA0LCBibGtbM10gXiB0ZnNLZXlbMV0pO1xuICAgIHNldFcoZGF0YUJ5dGVzLCBkYXRhT2Zmc2V0ICsgOCwgYmxrWzBdIF4gdGZzS2V5WzJdKTtcbiAgICBzZXRXKGRhdGFCeXRlcywgZGF0YU9mZnNldCArIDEyLCBibGtbMV0gXiB0ZnNLZXlbM10pO1xuICAgIGRhdGFPZmZzZXQgKz0gMTY7XG4gIH1cblxuICAvLyBhZGRlZCBieSBSZWN1cml0eSBMYWJzXG5cbiAgZnVuY3Rpb24gdGZzRmluYWwoKSB7XG4gICAgcmV0dXJuIGRhdGFCeXRlcztcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgbmFtZTogXCJ0d29maXNoXCIsXG4gICAgYmxvY2tzaXplOiAxMjggLyA4LFxuICAgIG9wZW46IHRmc0luaXQsXG4gICAgY2xvc2U6IHRmc0Nsb3NlLFxuICAgIGVuY3J5cHQ6IHRmc0VuY3J5cHQsXG4gICAgZGVjcnlwdDogdGZzRGVjcnlwdCxcbiAgICAvLyBhZGRlZCBieSBSZWN1cml0eSBMYWJzXG4gICAgZmluYWxpemU6IHRmc0ZpbmFsXG4gIH07XG59XG5cbnZhciB1dGlsID0gcmVxdWlyZSgnLi4vLi4vdXRpbCcpO1xuXG4vLyBhZGRlZCBieSBSZWN1cml0eSBMYWJzXG5cbmZ1bmN0aW9uIFRGZW5jcnlwdChibG9jaywga2V5KSB7XG4gIHZhciBibG9ja19jb3B5ID0gW10uY29uY2F0KGJsb2NrKTtcbiAgdmFyIHRmID0gY3JlYXRlVHdvZmlzaCgpO1xuICB0Zi5vcGVuKHV0aWwuc3RyMmJpbihrZXkpLCAwKTtcbiAgdmFyIHJlc3VsdCA9IHRmLmVuY3J5cHQoYmxvY2tfY29weSwgMCk7XG4gIHRmLmNsb3NlKCk7XG4gIHJldHVybiByZXN1bHQ7XG59XG5cbmZ1bmN0aW9uIFRGKGtleSkge1xuICB0aGlzLnRmID0gY3JlYXRlVHdvZmlzaCgpO1xuICB0aGlzLnRmLm9wZW4odXRpbC5zdHIyYmluKGtleSksIDApO1xuXG4gIHRoaXMuZW5jcnlwdCA9IGZ1bmN0aW9uKGJsb2NrKSB7XG4gICAgcmV0dXJuIHRoaXMudGYuZW5jcnlwdChbXS5jb25jYXQoYmxvY2spLCAwKTtcbiAgfVxufVxuXG5cbm1vZHVsZS5leHBvcnRzID0gVEY7XG5tb2R1bGUuZXhwb3J0cy5rZXlTaXplID0gVEYucHJvdG90eXBlLmtleVNpemUgPSAzMjtcbm1vZHVsZS5leHBvcnRzLmJsb2NrU2l6ZSA9IFRGLnByb3RvdHlwZS5ibG9ja1NpemUgPSAxNjtcbiIsIi8vIEdQRzRCcm93c2VycyAtIEFuIE9wZW5QR1AgaW1wbGVtZW50YXRpb24gaW4gamF2YXNjcmlwdFxuLy8gQ29weXJpZ2h0IChDKSAyMDExIFJlY3VyaXR5IExhYnMgR21iSFxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yXG4vLyBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uOyBlaXRoZXJcbi8vIHZlcnNpb24gMi4xIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbi8vIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4vLyBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlIEdOVVxuLy8gTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cbi8vIFxuLy8gWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhbG9uZyB3aXRoIHRoaXMgbGlicmFyeTsgaWYgbm90LCB3cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZVxuLy8gRm91bmRhdGlvbiwgSW5jLiwgNTEgRnJhbmtsaW4gU3RyZWV0LCBGaWZ0aCBGbG9vciwgQm9zdG9uLCBNQSAgMDIxMTAtMTMwMSAgVVNBIFxuXG4vLyBUaGUgR1BHNEJyb3dzZXJzIGNyeXB0byBpbnRlcmZhY2VcblxudmFyIHJhbmRvbSA9IHJlcXVpcmUoJy4vcmFuZG9tLmpzJyksXG4gIGNpcGhlciA9IHJlcXVpcmUoJy4vY2lwaGVyJyksXG4gIHB1YmxpY0tleSA9IHJlcXVpcmUoJy4vcHVibGljX2tleScpLFxuICB0eXBlX21waSA9IHJlcXVpcmUoJy4uL3R5cGUvbXBpLmpzJyk7XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAvKipcbiAgICogRW5jcnlwdHMgZGF0YSB1c2luZyB0aGUgc3BlY2lmaWVkIHB1YmxpYyBrZXkgbXVsdGlwcmVjaXNpb24gaW50ZWdlcnMgXG4gICAqIGFuZCB0aGUgc3BlY2lmaWVkIGFsZ29yaXRobS5cbiAgICogQHBhcmFtIHtJbnRlZ2VyfSBhbGdvIEFsZ29yaXRobSB0byBiZSB1c2VkIChTZWUgUkZDNDg4MCA5LjEpXG4gICAqIEBwYXJhbSB7b3BlbnBncF90eXBlX21waVtdfSBwdWJsaWNNUElzIEFsZ29yaXRobSBkZXBlbmRlbnQgbXVsdGlwcmVjaXNpb24gaW50ZWdlcnNcbiAgICogQHBhcmFtIHtvcGVucGdwX3R5cGVfbXBpfSBkYXRhIERhdGEgdG8gYmUgZW5jcnlwdGVkIGFzIE1QSVxuICAgKiBAcmV0dXJuIHtvcGVucGdwX3R5cGVfbXBpW119IGlmIFJTQSBhbiBvcGVucGdwX3R5cGVfbXBpOyBcbiAgICogaWYgZWxnYW1hbCBlbmNyeXB0aW9uIGFuIGFycmF5IG9mIHR3byBvcGVucGdwX3R5cGVfbXBpIGlzIHJldHVybmVkOyBvdGhlcndpc2UgbnVsbFxuICAgKi9cbiAgcHVibGljS2V5RW5jcnlwdDogZnVuY3Rpb24oYWxnbywgcHVibGljTVBJcywgZGF0YSkge1xuICAgIHZhciByZXN1bHQgPSAoZnVuY3Rpb24oKSB7XG4gICAgICBzd2l0Y2ggKGFsZ28pIHtcbiAgICAgICAgY2FzZSAncnNhX2VuY3J5cHQnOlxuICAgICAgICBjYXNlICdyc2FfZW5jcnlwdF9zaWduJzpcbiAgICAgICAgICB2YXIgcnNhID0gbmV3IHB1YmxpY0tleS5yc2EoKTtcbiAgICAgICAgICB2YXIgbiA9IHB1YmxpY01QSXNbMF0udG9CaWdJbnRlZ2VyKCk7XG4gICAgICAgICAgdmFyIGUgPSBwdWJsaWNNUElzWzFdLnRvQmlnSW50ZWdlcigpO1xuICAgICAgICAgIHZhciBtID0gZGF0YS50b0JpZ0ludGVnZXIoKTtcbiAgICAgICAgICByZXR1cm4gW3JzYS5lbmNyeXB0KG0sIGUsIG4pXTtcblxuICAgICAgICBjYXNlICdlbGdhbWFsJzpcbiAgICAgICAgICB2YXIgZWxnYW1hbCA9IG5ldyBwdWJsaWNLZXkuZWxnYW1hbCgpO1xuICAgICAgICAgIHZhciBwID0gcHVibGljTVBJc1swXS50b0JpZ0ludGVnZXIoKTtcbiAgICAgICAgICB2YXIgZyA9IHB1YmxpY01QSXNbMV0udG9CaWdJbnRlZ2VyKCk7XG4gICAgICAgICAgdmFyIHkgPSBwdWJsaWNNUElzWzJdLnRvQmlnSW50ZWdlcigpO1xuICAgICAgICAgIHZhciBtID0gZGF0YS50b0JpZ0ludGVnZXIoKTtcbiAgICAgICAgICByZXR1cm4gZWxnYW1hbC5lbmNyeXB0KG0sIGcsIHAsIHkpO1xuXG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgcmV0dXJuIFtdO1xuICAgICAgfVxuICAgIH0pKCk7XG5cbiAgICByZXR1cm4gcmVzdWx0Lm1hcChmdW5jdGlvbihibikge1xuICAgICAgdmFyIG1waSA9IG5ldyB0eXBlX21waSgpO1xuICAgICAgbXBpLmZyb21CaWdJbnRlZ2VyKGJuKTtcbiAgICAgIHJldHVybiBtcGk7XG4gICAgfSk7XG4gIH0sXG5cbiAgLyoqXG4gICAqIERlY3J5cHRzIGRhdGEgdXNpbmcgdGhlIHNwZWNpZmllZCBwdWJsaWMga2V5IG11bHRpcHJlY2lzaW9uIGludGVnZXJzIG9mIHRoZSBwcml2YXRlIGtleSxcbiAgICogdGhlIHNwZWNpZmllZCBzZWNyZXRNUElzIG9mIHRoZSBwcml2YXRlIGtleSBhbmQgdGhlIHNwZWNpZmllZCBhbGdvcml0aG0uXG4gICAqIEBwYXJhbSB7SW50ZWdlcn0gYWxnbyBBbGdvcml0aG0gdG8gYmUgdXNlZCAoU2VlIFJGQzQ4ODAgOS4xKVxuICAgKiBAcGFyYW0ge29wZW5wZ3BfdHlwZV9tcGlbXX0gcHVibGljTVBJcyBBbGdvcml0aG0gZGVwZW5kZW50IG11bHRpcHJlY2lzaW9uIGludGVnZXJzIFxuICAgKiBvZiB0aGUgcHVibGljIGtleSBwYXJ0IG9mIHRoZSBwcml2YXRlIGtleVxuICAgKiBAcGFyYW0ge29wZW5wZ3BfdHlwZV9tcGlbXX0gc2VjcmV0TVBJcyBBbGdvcml0aG0gZGVwZW5kZW50IG11bHRpcHJlY2lzaW9uIGludGVnZXJzIFxuICAgKiBvZiB0aGUgcHJpdmF0ZSBrZXkgdXNlZFxuICAgKiBAcGFyYW0ge29wZW5wZ3BfdHlwZV9tcGl9IGRhdGEgRGF0YSB0byBiZSBlbmNyeXB0ZWQgYXMgTVBJXG4gICAqIEByZXR1cm4ge29wZW5wZ3BfdHlwZV9tcGl9IHJldHVybnMgYSBiaWcgaW50ZWdlciBjb250YWluaW5nIHRoZSBkZWNyeXB0ZWQgZGF0YTsgb3RoZXJ3aXNlIG51bGxcbiAgICovXG5cbiAgcHVibGljS2V5RGVjcnlwdDogZnVuY3Rpb24oYWxnbywga2V5SW50ZWdlcnMsIGRhdGFJbnRlZ2Vycykge1xuICAgIHZhciBibiA9IChmdW5jdGlvbigpIHtcbiAgICAgIHN3aXRjaCAoYWxnbykge1xuICAgICAgICBjYXNlICdyc2FfZW5jcnlwdF9zaWduJzpcbiAgICAgICAgY2FzZSAncnNhX2VuY3J5cHQnOlxuICAgICAgICAgIHZhciByc2EgPSBuZXcgcHVibGljS2V5LnJzYSgpO1xuICAgICAgICAgIC8vIDAgYW5kIDEgYXJlIHRoZSBwdWJsaWMga2V5LlxuICAgICAgICAgIHZhciBkID0ga2V5SW50ZWdlcnNbMl0udG9CaWdJbnRlZ2VyKCk7XG4gICAgICAgICAgdmFyIHAgPSBrZXlJbnRlZ2Vyc1szXS50b0JpZ0ludGVnZXIoKTtcbiAgICAgICAgICB2YXIgcSA9IGtleUludGVnZXJzWzRdLnRvQmlnSW50ZWdlcigpO1xuICAgICAgICAgIHZhciB1ID0ga2V5SW50ZWdlcnNbNV0udG9CaWdJbnRlZ2VyKCk7XG4gICAgICAgICAgdmFyIG0gPSBkYXRhSW50ZWdlcnNbMF0udG9CaWdJbnRlZ2VyKCk7XG4gICAgICAgICAgcmV0dXJuIHJzYS5kZWNyeXB0KG0sIGQsIHAsIHEsIHUpO1xuICAgICAgICBjYXNlICdlbGdhbWFsJzpcbiAgICAgICAgICB2YXIgZWxnYW1hbCA9IG5ldyBwdWJsaWNLZXkuZWxnYW1hbCgpO1xuICAgICAgICAgIHZhciB4ID0ga2V5SW50ZWdlcnNbM10udG9CaWdJbnRlZ2VyKCk7XG4gICAgICAgICAgdmFyIGMxID0gZGF0YUludGVnZXJzWzBdLnRvQmlnSW50ZWdlcigpO1xuICAgICAgICAgIHZhciBjMiA9IGRhdGFJbnRlZ2Vyc1sxXS50b0JpZ0ludGVnZXIoKTtcbiAgICAgICAgICB2YXIgcCA9IGtleUludGVnZXJzWzBdLnRvQmlnSW50ZWdlcigpO1xuICAgICAgICAgIHJldHVybiBlbGdhbWFsLmRlY3J5cHQoYzEsIGMyLCBwLCB4KTtcbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgIH1cbiAgICB9KSgpO1xuXG4gICAgdmFyIHJlc3VsdCA9IG5ldyB0eXBlX21waSgpO1xuICAgIHJlc3VsdC5mcm9tQmlnSW50ZWdlcihibik7XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfSxcblxuICAvKiogUmV0dXJucyB0aGUgbnVtYmVyIG9mIGludGVnZXJzIGNvbXByaXNpbmcgdGhlIHByaXZhdGUga2V5IG9mIGFuIGFsZ29yaXRobVxuICAgKiBAcGFyYW0ge29wZW5wZ3AucHVibGlja2V5fSBhbGdvIFRoZSBwdWJsaWMga2V5IGFsZ29yaXRobVxuICAgKiBAcmV0dXJuIHtJbnRlZ2VyfSBUaGUgbnVtYmVyIG9mIGludGVnZXJzLlxuICAgKi9cbiAgZ2V0UHJpdmF0ZU1waUNvdW50OiBmdW5jdGlvbihhbGdvKSB7XG4gICAgc3dpdGNoIChhbGdvKSB7XG4gICAgICBjYXNlICdyc2FfZW5jcnlwdCc6XG4gICAgICBjYXNlICdyc2FfZW5jcnlwdF9zaWduJzpcbiAgICAgIGNhc2UgJ3JzYV9zaWduJzpcbiAgICAgICAgLy8gICBBbGdvcml0aG0tU3BlY2lmaWMgRmllbGRzIGZvciBSU0Egc2VjcmV0IGtleXM6XG4gICAgICAgIC8vICAgLSBtdWx0aXByZWNpc2lvbiBpbnRlZ2VyIChNUEkpIG9mIFJTQSBzZWNyZXQgZXhwb25lbnQgZC5cbiAgICAgICAgLy8gICAtIE1QSSBvZiBSU0Egc2VjcmV0IHByaW1lIHZhbHVlIHAuXG4gICAgICAgIC8vICAgLSBNUEkgb2YgUlNBIHNlY3JldCBwcmltZSB2YWx1ZSBxIChwIDwgcSkuXG4gICAgICAgIC8vICAgLSBNUEkgb2YgdSwgdGhlIG11bHRpcGxpY2F0aXZlIGludmVyc2Ugb2YgcCwgbW9kIHEuXG4gICAgICAgIHJldHVybiA0O1xuICAgICAgY2FzZSAnZWxnYW1hbCc6XG4gICAgICAgIC8vIEFsZ29yaXRobS1TcGVjaWZpYyBGaWVsZHMgZm9yIEVsZ2FtYWwgc2VjcmV0IGtleXM6XG4gICAgICAgIC8vICAgLSBNUEkgb2YgRWxnYW1hbCBzZWNyZXQgZXhwb25lbnQgeC5cbiAgICAgICAgcmV0dXJuIDE7XG4gICAgICBjYXNlICdkc2EnOlxuICAgICAgICAvLyBBbGdvcml0aG0tU3BlY2lmaWMgRmllbGRzIGZvciBEU0Egc2VjcmV0IGtleXM6XG4gICAgICAgIC8vICAgLSBNUEkgb2YgRFNBIHNlY3JldCBleHBvbmVudCB4LlxuICAgICAgICByZXR1cm4gMTtcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignVW5rbm93biBhbGdvcml0aG0nKTtcbiAgICB9XG4gIH0sXG5cbiAgZ2V0UHVibGljTXBpQ291bnQ6IGZ1bmN0aW9uKGFsZ28pIHtcbiAgICAvLyAtIEEgc2VyaWVzIG9mIG11bHRpcHJlY2lzaW9uIGludGVnZXJzIGNvbXByaXNpbmcgdGhlIGtleSBtYXRlcmlhbDpcbiAgICAvLyAgIEFsZ29yaXRobS1TcGVjaWZpYyBGaWVsZHMgZm9yIFJTQSBwdWJsaWMga2V5czpcbiAgICAvLyAgICAgICAtIGEgbXVsdGlwcmVjaXNpb24gaW50ZWdlciAoTVBJKSBvZiBSU0EgcHVibGljIG1vZHVsdXMgbjtcbiAgICAvLyAgICAgICAtIGFuIE1QSSBvZiBSU0EgcHVibGljIGVuY3J5cHRpb24gZXhwb25lbnQgZS5cbiAgICBzd2l0Y2ggKGFsZ28pIHtcbiAgICAgIGNhc2UgJ3JzYV9lbmNyeXB0JzpcbiAgICAgIGNhc2UgJ3JzYV9lbmNyeXB0X3NpZ24nOlxuICAgICAgY2FzZSAncnNhX3NpZ24nOlxuICAgICAgICByZXR1cm4gMjtcblxuICAgICAgICAvLyAgIEFsZ29yaXRobS1TcGVjaWZpYyBGaWVsZHMgZm9yIEVsZ2FtYWwgcHVibGljIGtleXM6XG4gICAgICAgIC8vICAgICAtIE1QSSBvZiBFbGdhbWFsIHByaW1lIHA7XG4gICAgICAgIC8vICAgICAtIE1QSSBvZiBFbGdhbWFsIGdyb3VwIGdlbmVyYXRvciBnO1xuICAgICAgICAvLyAgICAgLSBNUEkgb2YgRWxnYW1hbCBwdWJsaWMga2V5IHZhbHVlIHkgKD0gZyoqeCBtb2QgcCB3aGVyZSB4ICBpcyBzZWNyZXQpLlxuICAgICAgY2FzZSAnZWxnYW1hbCc6XG4gICAgICAgIHJldHVybiAzO1xuXG4gICAgICAgIC8vICAgQWxnb3JpdGhtLVNwZWNpZmljIEZpZWxkcyBmb3IgRFNBIHB1YmxpYyBrZXlzOlxuICAgICAgICAvLyAgICAgICAtIE1QSSBvZiBEU0EgcHJpbWUgcDtcbiAgICAgICAgLy8gICAgICAgLSBNUEkgb2YgRFNBIGdyb3VwIG9yZGVyIHEgKHEgaXMgYSBwcmltZSBkaXZpc29yIG9mIHAtMSk7XG4gICAgICAgIC8vICAgICAgIC0gTVBJIG9mIERTQSBncm91cCBnZW5lcmF0b3IgZztcbiAgICAgICAgLy8gICAgICAgLSBNUEkgb2YgRFNBIHB1YmxpYy1rZXkgdmFsdWUgeSAoPSBnKip4IG1vZCBwIHdoZXJlIHggIGlzIHNlY3JldCkuXG4gICAgICBjYXNlICdkc2EnOlxuICAgICAgICByZXR1cm4gNDtcblxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdVbmtub3duIGFsZ29yaXRobS4nKTtcbiAgICB9XG4gIH0sXG5cbiAgZ2VuZXJhdGVNcGk6IGZ1bmN0aW9uKGFsZ28sIGJpdHMpIHtcbiAgICB2YXIgcmVzdWx0ID0gKGZ1bmN0aW9uKCkge1xuICAgICAgc3dpdGNoIChhbGdvKSB7XG4gICAgICAgIGNhc2UgJ3JzYV9lbmNyeXB0JzpcbiAgICAgICAgY2FzZSAncnNhX2VuY3J5cHRfc2lnbic6XG4gICAgICAgIGNhc2UgJ3JzYV9zaWduJzpcbiAgICAgICAgICAvL3JlbWVtYmVyIFwicHVibGljS2V5XCIgcmVmZXJzIHRvIHRoZSBjcnlwdG8vcHVibGljX2tleSBkaXJcbiAgICAgICAgICB2YXIgcnNhID0gbmV3IHB1YmxpY0tleS5yc2EoKTtcbiAgICAgICAgICB2YXIga2V5T2JqZWN0ID0gcnNhLmdlbmVyYXRlKGJpdHMsIFwiMTAwMDFcIik7XG4gICAgICAgICAgdmFyIG91dHB1dCA9IFtdO1xuICAgICAgICAgIG91dHB1dC5wdXNoKGtleU9iamVjdC5uKTtcbiAgICAgICAgICBvdXRwdXQucHVzaChrZXlPYmplY3QuZWUpO1xuICAgICAgICAgIG91dHB1dC5wdXNoKGtleU9iamVjdC5kKTtcbiAgICAgICAgICBvdXRwdXQucHVzaChrZXlPYmplY3QucCk7XG4gICAgICAgICAgb3V0cHV0LnB1c2goa2V5T2JqZWN0LnEpO1xuICAgICAgICAgIG91dHB1dC5wdXNoKGtleU9iamVjdC51KTtcbiAgICAgICAgICByZXR1cm4gb3V0cHV0O1xuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgIHRocm93IG5ldyBFcnJvcignVW5zdXBwb3J0ZWQgYWxnb3JpdGhtIGZvciBrZXkgZ2VuZXJhdGlvbi4nKTtcbiAgICAgIH1cbiAgICB9KSgpO1xuXG4gICAgcmV0dXJuIHJlc3VsdC5tYXAoZnVuY3Rpb24oYm4pIHtcbiAgICAgIHZhciBtcGkgPSBuZXcgdHlwZV9tcGkoKTtcbiAgICAgIG1waS5mcm9tQmlnSW50ZWdlcihibik7XG4gICAgICByZXR1cm4gbXBpO1xuICAgIH0pO1xuICB9LFxuXG5cbiAgLyoqXG4gICAqIGdlbmVyYXRlIHJhbmRvbSBieXRlIHByZWZpeCBhcyBzdHJpbmcgZm9yIHRoZSBzcGVjaWZpZWQgYWxnb3JpdGhtXG4gICAqIEBwYXJhbSB7SW50ZWdlcn0gYWxnbyBBbGdvcml0aG0gdG8gdXNlIChzZWUgUkZDNDg4MCA5LjIpXG4gICAqIEByZXR1cm4ge1N0cmluZ30gUmFuZG9tIGJ5dGVzIHdpdGggbGVuZ3RoIGVxdWFsIHRvIHRoZSBibG9ja1xuICAgKiBzaXplIG9mIHRoZSBjaXBoZXJcbiAgICovXG4gIGdldFByZWZpeFJhbmRvbTogZnVuY3Rpb24oYWxnbykge1xuICAgIHJldHVybiByYW5kb20uZ2V0UmFuZG9tQnl0ZXMoY2lwaGVyW2FsZ29dLmJsb2NrU2l6ZSk7XG4gIH0sXG5cbiAgLyoqXG4gICAqIEdlbmVyYXRpbmcgYSBzZXNzaW9uIGtleSBmb3IgdGhlIHNwZWNpZmllZCBzeW1tZXRyaWMgYWxnb3JpdGhtXG4gICAqIEBwYXJhbSB7SW50ZWdlcn0gYWxnbyBBbGdvcml0aG0gdG8gdXNlIChzZWUgUkZDNDg4MCA5LjIpXG4gICAqIEByZXR1cm4ge1N0cmluZ30gUmFuZG9tIGJ5dGVzIGFzIGEgc3RyaW5nIHRvIGJlIHVzZWQgYXMgYSBrZXlcbiAgICovXG4gIGdlbmVyYXRlU2Vzc2lvbktleTogZnVuY3Rpb24oYWxnbykge1xuICAgIHJldHVybiByYW5kb20uZ2V0UmFuZG9tQnl0ZXMoY2lwaGVyW2FsZ29dLmtleVNpemUpO1xuICB9LFxuXG59O1xuIiwidmFyIHNoYSA9IHJlcXVpcmUoJy4vc2hhLmpzJyk7XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICBtZDU6IHJlcXVpcmUoJy4vbWQ1LmpzJyksXG4gIHNoYTE6IHNoYS5zaGExLFxuICBzaGEyNTY6IHNoYS5zaGEyNTYsXG4gIHNoYTIyNDogc2hhLnNoYTIyNCxcbiAgc2hhMzg0OiBzaGEuc2hhMzg0LFxuICBzaGE1MTI6IHNoYS5zaGE1MTIsXG4gIHJpcGVtZDogcmVxdWlyZSgnLi9yaXBlLW1kLmpzJyksXG5cbiAgLyoqXG4gICAqIENyZWF0ZSBhIGhhc2ggb24gdGhlIHNwZWNpZmllZCBkYXRhIHVzaW5nIHRoZSBzcGVjaWZpZWQgYWxnb3JpdGhtXG4gICAqIEBwYXJhbSB7SW50ZWdlcn0gYWxnbyBIYXNoIGFsZ29yaXRobSB0eXBlIChzZWUgUkZDNDg4MCA5LjQpXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBkYXRhIERhdGEgdG8gYmUgaGFzaGVkXG4gICAqIEByZXR1cm4ge1N0cmluZ30gaGFzaCB2YWx1ZVxuICAgKi9cbiAgZGlnZXN0OiBmdW5jdGlvbihhbGdvLCBkYXRhKSB7XG4gICAgc3dpdGNoIChhbGdvKSB7XG4gICAgICBjYXNlIDE6XG4gICAgICAgIC8vIC0gTUQ1IFtIQUNdXG4gICAgICAgIHJldHVybiB0aGlzLm1kNShkYXRhKTtcbiAgICAgIGNhc2UgMjpcbiAgICAgICAgLy8gLSBTSEEtMSBbRklQUzE4MF1cbiAgICAgICAgcmV0dXJuIHRoaXMuc2hhMShkYXRhKTtcbiAgICAgIGNhc2UgMzpcbiAgICAgICAgLy8gLSBSSVBFLU1ELzE2MCBbSEFDXVxuICAgICAgICByZXR1cm4gdGhpcy5yaXBlbWQoZGF0YSk7XG4gICAgICBjYXNlIDg6XG4gICAgICAgIC8vIC0gU0hBMjU2IFtGSVBTMTgwXVxuICAgICAgICByZXR1cm4gdGhpcy5zaGEyNTYoZGF0YSk7XG4gICAgICBjYXNlIDk6XG4gICAgICAgIC8vIC0gU0hBMzg0IFtGSVBTMTgwXVxuICAgICAgICByZXR1cm4gdGhpcy5zaGEzODQoZGF0YSk7XG4gICAgICBjYXNlIDEwOlxuICAgICAgICAvLyAtIFNIQTUxMiBbRklQUzE4MF1cbiAgICAgICAgcmV0dXJuIHRoaXMuc2hhNTEyKGRhdGEpO1xuICAgICAgY2FzZSAxMTpcbiAgICAgICAgLy8gLSBTSEEyMjQgW0ZJUFMxODBdXG4gICAgICAgIHJldHVybiB0aGlzLnNoYTIyNChkYXRhKTtcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBoYXNoIGZ1bmN0aW9uLicpO1xuICAgIH1cbiAgfSxcblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgaGFzaCBzaXplIGluIGJ5dGVzIG9mIHRoZSBzcGVjaWZpZWQgaGFzaCBhbGdvcml0aG0gdHlwZVxuICAgKiBAcGFyYW0ge0ludGVnZXJ9IGFsZ28gSGFzaCBhbGdvcml0aG0gdHlwZSAoU2VlIFJGQzQ4ODAgOS40KVxuICAgKiBAcmV0dXJuIHtJbnRlZ2VyfSBTaXplIGluIGJ5dGVzIG9mIHRoZSByZXN1bHRpbmcgaGFzaFxuICAgKi9cbiAgZ2V0SGFzaEJ5dGVMZW5ndGg6IGZ1bmN0aW9uKGFsZ28pIHtcbiAgICBzd2l0Y2ggKGFsZ28pIHtcbiAgICAgIGNhc2UgMTpcbiAgICAgICAgLy8gLSBNRDUgW0hBQ11cbiAgICAgICAgcmV0dXJuIDE2O1xuICAgICAgY2FzZSAyOlxuICAgICAgICAvLyAtIFNIQS0xIFtGSVBTMTgwXVxuICAgICAgY2FzZSAzOlxuICAgICAgICAvLyAtIFJJUEUtTUQvMTYwIFtIQUNdXG4gICAgICAgIHJldHVybiAyMDtcbiAgICAgIGNhc2UgODpcbiAgICAgICAgLy8gLSBTSEEyNTYgW0ZJUFMxODBdXG4gICAgICAgIHJldHVybiAzMjtcbiAgICAgIGNhc2UgOTpcbiAgICAgICAgLy8gLSBTSEEzODQgW0ZJUFMxODBdXG4gICAgICAgIHJldHVybiA0OFxuICAgICAgY2FzZSAxMDpcbiAgICAgICAgLy8gLSBTSEE1MTIgW0ZJUFMxODBdXG4gICAgICAgIHJldHVybiA2NDtcbiAgICAgIGNhc2UgMTE6XG4gICAgICAgIC8vIC0gU0hBMjI0IFtGSVBTMTgwXVxuICAgICAgICByZXR1cm4gMjg7XG4gICAgICBkZWZhdWx0OlxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgaGFzaCBhbGdvcml0aG0uJyk7XG4gICAgfVxuICB9XG5cbn1cbiIsIi8qKlxuICogQSBmYXN0IE1ENSBKYXZhU2NyaXB0IGltcGxlbWVudGF0aW9uXG4gKiBDb3B5cmlnaHQgKGMpIDIwMTIgSm9zZXBoIE15ZXJzXG4gKiBodHRwOi8vd3d3Lm15ZXJzZGFpbHkub3JnL2pvc2VwaC9qYXZhc2NyaXB0L21kNS10ZXh0Lmh0bWxcbiAqXG4gKiBQZXJtaXNzaW9uIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBhbmQgZGlzdHJpYnV0ZSB0aGlzIHNvZnR3YXJlXG4gKiBhbmQgaXRzIGRvY3VtZW50YXRpb24gZm9yIGFueSBwdXJwb3NlcyBhbmQgd2l0aG91dFxuICogZmVlIGlzIGhlcmVieSBncmFudGVkIHByb3ZpZGVkIHRoYXQgdGhpcyBjb3B5cmlnaHQgbm90aWNlXG4gKiBhcHBlYXJzIGluIGFsbCBjb3BpZXMuXG4gKlxuICogT2YgY291cnNlLCB0aGlzIHNvZnQgaXMgcHJvdmlkZWQgXCJhcyBpc1wiIHdpdGhvdXQgZXhwcmVzcyBvciBpbXBsaWVkXG4gKiB3YXJyYW50eSBvZiBhbnkga2luZC5cbiAqL1xuXG52YXIgdXRpbCA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvdXRpbC5qcycpO1xuXG5mdW5jdGlvbiBNRDUoZW50cmVlKSB7XG4gIHZhciBoZXggPSBtZDUoZW50cmVlKTtcbiAgdmFyIGJpbiA9IHV0aWwuaGV4MmJpbihoZXgpO1xuICByZXR1cm4gYmluO1xufVxuXG5mdW5jdGlvbiBtZDVjeWNsZSh4LCBrKSB7XG4gIHZhciBhID0geFswXSxcbiAgICBiID0geFsxXSxcbiAgICBjID0geFsyXSxcbiAgICBkID0geFszXTtcblxuICBhID0gZmYoYSwgYiwgYywgZCwga1swXSwgNywgLTY4MDg3NjkzNik7XG4gIGQgPSBmZihkLCBhLCBiLCBjLCBrWzFdLCAxMiwgLTM4OTU2NDU4Nik7XG4gIGMgPSBmZihjLCBkLCBhLCBiLCBrWzJdLCAxNywgNjA2MTA1ODE5KTtcbiAgYiA9IGZmKGIsIGMsIGQsIGEsIGtbM10sIDIyLCAtMTA0NDUyNTMzMCk7XG4gIGEgPSBmZihhLCBiLCBjLCBkLCBrWzRdLCA3LCAtMTc2NDE4ODk3KTtcbiAgZCA9IGZmKGQsIGEsIGIsIGMsIGtbNV0sIDEyLCAxMjAwMDgwNDI2KTtcbiAgYyA9IGZmKGMsIGQsIGEsIGIsIGtbNl0sIDE3LCAtMTQ3MzIzMTM0MSk7XG4gIGIgPSBmZihiLCBjLCBkLCBhLCBrWzddLCAyMiwgLTQ1NzA1OTgzKTtcbiAgYSA9IGZmKGEsIGIsIGMsIGQsIGtbOF0sIDcsIDE3NzAwMzU0MTYpO1xuICBkID0gZmYoZCwgYSwgYiwgYywga1s5XSwgMTIsIC0xOTU4NDE0NDE3KTtcbiAgYyA9IGZmKGMsIGQsIGEsIGIsIGtbMTBdLCAxNywgLTQyMDYzKTtcbiAgYiA9IGZmKGIsIGMsIGQsIGEsIGtbMTFdLCAyMiwgLTE5OTA0MDQxNjIpO1xuICBhID0gZmYoYSwgYiwgYywgZCwga1sxMl0sIDcsIDE4MDQ2MDM2ODIpO1xuICBkID0gZmYoZCwgYSwgYiwgYywga1sxM10sIDEyLCAtNDAzNDExMDEpO1xuICBjID0gZmYoYywgZCwgYSwgYiwga1sxNF0sIDE3LCAtMTUwMjAwMjI5MCk7XG4gIGIgPSBmZihiLCBjLCBkLCBhLCBrWzE1XSwgMjIsIDEyMzY1MzUzMjkpO1xuXG4gIGEgPSBnZyhhLCBiLCBjLCBkLCBrWzFdLCA1LCAtMTY1Nzk2NTEwKTtcbiAgZCA9IGdnKGQsIGEsIGIsIGMsIGtbNl0sIDksIC0xMDY5NTAxNjMyKTtcbiAgYyA9IGdnKGMsIGQsIGEsIGIsIGtbMTFdLCAxNCwgNjQzNzE3NzEzKTtcbiAgYiA9IGdnKGIsIGMsIGQsIGEsIGtbMF0sIDIwLCAtMzczODk3MzAyKTtcbiAgYSA9IGdnKGEsIGIsIGMsIGQsIGtbNV0sIDUsIC03MDE1NTg2OTEpO1xuICBkID0gZ2coZCwgYSwgYiwgYywga1sxMF0sIDksIDM4MDE2MDgzKTtcbiAgYyA9IGdnKGMsIGQsIGEsIGIsIGtbMTVdLCAxNCwgLTY2MDQ3ODMzNSk7XG4gIGIgPSBnZyhiLCBjLCBkLCBhLCBrWzRdLCAyMCwgLTQwNTUzNzg0OCk7XG4gIGEgPSBnZyhhLCBiLCBjLCBkLCBrWzldLCA1LCA1Njg0NDY0MzgpO1xuICBkID0gZ2coZCwgYSwgYiwgYywga1sxNF0sIDksIC0xMDE5ODAzNjkwKTtcbiAgYyA9IGdnKGMsIGQsIGEsIGIsIGtbM10sIDE0LCAtMTg3MzYzOTYxKTtcbiAgYiA9IGdnKGIsIGMsIGQsIGEsIGtbOF0sIDIwLCAxMTYzNTMxNTAxKTtcbiAgYSA9IGdnKGEsIGIsIGMsIGQsIGtbMTNdLCA1LCAtMTQ0NDY4MTQ2Nyk7XG4gIGQgPSBnZyhkLCBhLCBiLCBjLCBrWzJdLCA5LCAtNTE0MDM3ODQpO1xuICBjID0gZ2coYywgZCwgYSwgYiwga1s3XSwgMTQsIDE3MzUzMjg0NzMpO1xuICBiID0gZ2coYiwgYywgZCwgYSwga1sxMl0sIDIwLCAtMTkyNjYwNzczNCk7XG5cbiAgYSA9IGhoKGEsIGIsIGMsIGQsIGtbNV0sIDQsIC0zNzg1NTgpO1xuICBkID0gaGgoZCwgYSwgYiwgYywga1s4XSwgMTEsIC0yMDIyNTc0NDYzKTtcbiAgYyA9IGhoKGMsIGQsIGEsIGIsIGtbMTFdLCAxNiwgMTgzOTAzMDU2Mik7XG4gIGIgPSBoaChiLCBjLCBkLCBhLCBrWzE0XSwgMjMsIC0zNTMwOTU1Nik7XG4gIGEgPSBoaChhLCBiLCBjLCBkLCBrWzFdLCA0LCAtMTUzMDk5MjA2MCk7XG4gIGQgPSBoaChkLCBhLCBiLCBjLCBrWzRdLCAxMSwgMTI3Mjg5MzM1Myk7XG4gIGMgPSBoaChjLCBkLCBhLCBiLCBrWzddLCAxNiwgLTE1NTQ5NzYzMik7XG4gIGIgPSBoaChiLCBjLCBkLCBhLCBrWzEwXSwgMjMsIC0xMDk0NzMwNjQwKTtcbiAgYSA9IGhoKGEsIGIsIGMsIGQsIGtbMTNdLCA0LCA2ODEyNzkxNzQpO1xuICBkID0gaGgoZCwgYSwgYiwgYywga1swXSwgMTEsIC0zNTg1MzcyMjIpO1xuICBjID0gaGgoYywgZCwgYSwgYiwga1szXSwgMTYsIC03MjI1MjE5NzkpO1xuICBiID0gaGgoYiwgYywgZCwgYSwga1s2XSwgMjMsIDc2MDI5MTg5KTtcbiAgYSA9IGhoKGEsIGIsIGMsIGQsIGtbOV0sIDQsIC02NDAzNjQ0ODcpO1xuICBkID0gaGgoZCwgYSwgYiwgYywga1sxMl0sIDExLCAtNDIxODE1ODM1KTtcbiAgYyA9IGhoKGMsIGQsIGEsIGIsIGtbMTVdLCAxNiwgNTMwNzQyNTIwKTtcbiAgYiA9IGhoKGIsIGMsIGQsIGEsIGtbMl0sIDIzLCAtOTk1MzM4NjUxKTtcblxuICBhID0gaWkoYSwgYiwgYywgZCwga1swXSwgNiwgLTE5ODYzMDg0NCk7XG4gIGQgPSBpaShkLCBhLCBiLCBjLCBrWzddLCAxMCwgMTEyNjg5MTQxNSk7XG4gIGMgPSBpaShjLCBkLCBhLCBiLCBrWzE0XSwgMTUsIC0xNDE2MzU0OTA1KTtcbiAgYiA9IGlpKGIsIGMsIGQsIGEsIGtbNV0sIDIxLCAtNTc0MzQwNTUpO1xuICBhID0gaWkoYSwgYiwgYywgZCwga1sxMl0sIDYsIDE3MDA0ODU1NzEpO1xuICBkID0gaWkoZCwgYSwgYiwgYywga1szXSwgMTAsIC0xODk0OTg2NjA2KTtcbiAgYyA9IGlpKGMsIGQsIGEsIGIsIGtbMTBdLCAxNSwgLTEwNTE1MjMpO1xuICBiID0gaWkoYiwgYywgZCwgYSwga1sxXSwgMjEsIC0yMDU0OTIyNzk5KTtcbiAgYSA9IGlpKGEsIGIsIGMsIGQsIGtbOF0sIDYsIDE4NzMzMTMzNTkpO1xuICBkID0gaWkoZCwgYSwgYiwgYywga1sxNV0sIDEwLCAtMzA2MTE3NDQpO1xuICBjID0gaWkoYywgZCwgYSwgYiwga1s2XSwgMTUsIC0xNTYwMTk4MzgwKTtcbiAgYiA9IGlpKGIsIGMsIGQsIGEsIGtbMTNdLCAyMSwgMTMwOTE1MTY0OSk7XG4gIGEgPSBpaShhLCBiLCBjLCBkLCBrWzRdLCA2LCAtMTQ1NTIzMDcwKTtcbiAgZCA9IGlpKGQsIGEsIGIsIGMsIGtbMTFdLCAxMCwgLTExMjAyMTAzNzkpO1xuICBjID0gaWkoYywgZCwgYSwgYiwga1syXSwgMTUsIDcxODc4NzI1OSk7XG4gIGIgPSBpaShiLCBjLCBkLCBhLCBrWzldLCAyMSwgLTM0MzQ4NTU1MSk7XG5cbiAgeFswXSA9IGFkZDMyKGEsIHhbMF0pO1xuICB4WzFdID0gYWRkMzIoYiwgeFsxXSk7XG4gIHhbMl0gPSBhZGQzMihjLCB4WzJdKTtcbiAgeFszXSA9IGFkZDMyKGQsIHhbM10pO1xuXG59XG5cbmZ1bmN0aW9uIGNtbihxLCBhLCBiLCB4LCBzLCB0KSB7XG4gIGEgPSBhZGQzMihhZGQzMihhLCBxKSwgYWRkMzIoeCwgdCkpO1xuICByZXR1cm4gYWRkMzIoKGEgPDwgcykgfCAoYSA+Pj4gKDMyIC0gcykpLCBiKTtcbn1cblxuZnVuY3Rpb24gZmYoYSwgYiwgYywgZCwgeCwgcywgdCkge1xuICByZXR1cm4gY21uKChiICYgYykgfCAoKH5iKSAmIGQpLCBhLCBiLCB4LCBzLCB0KTtcbn1cblxuZnVuY3Rpb24gZ2coYSwgYiwgYywgZCwgeCwgcywgdCkge1xuICByZXR1cm4gY21uKChiICYgZCkgfCAoYyAmICh+ZCkpLCBhLCBiLCB4LCBzLCB0KTtcbn1cblxuZnVuY3Rpb24gaGgoYSwgYiwgYywgZCwgeCwgcywgdCkge1xuICByZXR1cm4gY21uKGIgXiBjIF4gZCwgYSwgYiwgeCwgcywgdCk7XG59XG5cbmZ1bmN0aW9uIGlpKGEsIGIsIGMsIGQsIHgsIHMsIHQpIHtcbiAgcmV0dXJuIGNtbihjIF4gKGIgfCAofmQpKSwgYSwgYiwgeCwgcywgdCk7XG59XG5cbmZ1bmN0aW9uIG1kNTEocykge1xuICB0eHQgPSAnJztcbiAgdmFyIG4gPSBzLmxlbmd0aCxcbiAgICBzdGF0ZSA9IFsxNzMyNTg0MTkzLCAtMjcxNzMzODc5LCAtMTczMjU4NDE5NCwgMjcxNzMzODc4XSxcbiAgICBpO1xuICBmb3IgKGkgPSA2NDsgaSA8PSBzLmxlbmd0aDsgaSArPSA2NCkge1xuICAgIG1kNWN5Y2xlKHN0YXRlLCBtZDVibGsocy5zdWJzdHJpbmcoaSAtIDY0LCBpKSkpO1xuICB9XG4gIHMgPSBzLnN1YnN0cmluZyhpIC0gNjQpO1xuICB2YXIgdGFpbCA9IFswLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwXTtcbiAgZm9yIChpID0gMDsgaSA8IHMubGVuZ3RoOyBpKyspXG4gICAgdGFpbFtpID4+IDJdIHw9IHMuY2hhckNvZGVBdChpKSA8PCAoKGkgJSA0KSA8PCAzKTtcbiAgdGFpbFtpID4+IDJdIHw9IDB4ODAgPDwgKChpICUgNCkgPDwgMyk7XG4gIGlmIChpID4gNTUpIHtcbiAgICBtZDVjeWNsZShzdGF0ZSwgdGFpbCk7XG4gICAgZm9yIChpID0gMDsgaSA8IDE2OyBpKyspIHRhaWxbaV0gPSAwO1xuICB9XG4gIHRhaWxbMTRdID0gbiAqIDg7XG4gIG1kNWN5Y2xlKHN0YXRlLCB0YWlsKTtcbiAgcmV0dXJuIHN0YXRlO1xufVxuXG4vKiB0aGVyZSBuZWVkcyB0byBiZSBzdXBwb3J0IGZvciBVbmljb2RlIGhlcmUsXG4gKiB1bmxlc3Mgd2UgcHJldGVuZCB0aGF0IHdlIGNhbiByZWRlZmluZSB0aGUgTUQtNVxuICogYWxnb3JpdGhtIGZvciBtdWx0aS1ieXRlIGNoYXJhY3RlcnMgKHBlcmhhcHNcbiAqIGJ5IGFkZGluZyBldmVyeSBmb3VyIDE2LWJpdCBjaGFyYWN0ZXJzIGFuZFxuICogc2hvcnRlbmluZyB0aGUgc3VtIHRvIDMyIGJpdHMpLiBPdGhlcndpc2VcbiAqIEkgc3VnZ2VzdCBwZXJmb3JtaW5nIE1ELTUgYXMgaWYgZXZlcnkgY2hhcmFjdGVyXG4gKiB3YXMgdHdvIGJ5dGVzLS1lLmcuLCAwMDQwIDAwMjUgPSBAJS0tYnV0IHRoZW5cbiAqIGhvdyB3aWxsIGFuIG9yZGluYXJ5IE1ELTUgc3VtIGJlIG1hdGNoZWQ/XG4gKiBUaGVyZSBpcyBubyB3YXkgdG8gc3RhbmRhcmRpemUgdGV4dCB0byBzb21ldGhpbmdcbiAqIGxpa2UgVVRGLTggYmVmb3JlIHRyYW5zZm9ybWF0aW9uOyBzcGVlZCBjb3N0IGlzXG4gKiB1dHRlcmx5IHByb2hpYml0aXZlLiBUaGUgSmF2YVNjcmlwdCBzdGFuZGFyZFxuICogaXRzZWxmIG5lZWRzIHRvIGxvb2sgYXQgdGhpczogaXQgc2hvdWxkIHN0YXJ0XG4gKiBwcm92aWRpbmcgYWNjZXNzIHRvIHN0cmluZ3MgYXMgcHJlZm9ybWVkIFVURi04XG4gKiA4LWJpdCB1bnNpZ25lZCB2YWx1ZSBhcnJheXMuXG4gKi9cbmZ1bmN0aW9uIG1kNWJsayhzKSB7IC8qIEkgZmlndXJlZCBnbG9iYWwgd2FzIGZhc3Rlci4gICAqL1xuICB2YXIgbWQ1YmxrcyA9IFtdLFxuICAgIGk7IC8qIEFuZHkgS2luZyBzYWlkIGRvIGl0IHRoaXMgd2F5LiAqL1xuICBmb3IgKGkgPSAwOyBpIDwgNjQ7IGkgKz0gNCkge1xuICAgIG1kNWJsa3NbaSA+PiAyXSA9IHMuY2hhckNvZGVBdChpKSArIChzLmNoYXJDb2RlQXQoaSArIDEpIDw8IDgpICsgKHMuY2hhckNvZGVBdChpICsgMikgPDwgMTYpICsgKHMuY2hhckNvZGVBdChpICsgMykgPDxcbiAgICAgIDI0KTtcbiAgfVxuICByZXR1cm4gbWQ1Ymxrcztcbn1cblxudmFyIGhleF9jaHIgPSAnMDEyMzQ1Njc4OWFiY2RlZicuc3BsaXQoJycpO1xuXG5mdW5jdGlvbiByaGV4KG4pIHtcbiAgdmFyIHMgPSAnJyxcbiAgICBqID0gMDtcbiAgZm9yICg7IGogPCA0OyBqKyspXG4gICAgcyArPSBoZXhfY2hyWyhuID4+IChqICogOCArIDQpKSAmIDB4MEZdICsgaGV4X2NoclsobiA+PiAoaiAqIDgpKSAmIDB4MEZdO1xuICByZXR1cm4gcztcbn1cblxuZnVuY3Rpb24gaGV4KHgpIHtcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCB4Lmxlbmd0aDsgaSsrKVxuICAgIHhbaV0gPSByaGV4KHhbaV0pO1xuICByZXR1cm4geC5qb2luKCcnKTtcbn1cblxuZnVuY3Rpb24gbWQ1KHMpIHtcbiAgcmV0dXJuIGhleChtZDUxKHMpKTtcbn1cblxuLyogdGhpcyBmdW5jdGlvbiBpcyBtdWNoIGZhc3RlcixcbnNvIGlmIHBvc3NpYmxlIHdlIHVzZSBpdC4gU29tZSBJRXNcbmFyZSB0aGUgb25seSBvbmVzIEkga25vdyBvZiB0aGF0XG5uZWVkIHRoZSBpZGlvdGljIHNlY29uZCBmdW5jdGlvbixcbmdlbmVyYXRlZCBieSBhbiBpZiBjbGF1c2UuICAqL1xuXG5mdW5jdGlvbiBhZGQzMihhLCBiKSB7XG4gIHJldHVybiAoYSArIGIpICYgMHhGRkZGRkZGRjtcbn1cblxuaWYgKG1kNSgnaGVsbG8nKSAhPSAnNWQ0MTQwMmFiYzRiMmE3NmI5NzE5ZDkxMTAxN2M1OTInKSB7XG4gIGZ1bmN0aW9uIGFkZDMyKHgsIHkpIHtcbiAgICB2YXIgbHN3ID0gKHggJiAweEZGRkYpICsgKHkgJiAweEZGRkYpLFxuICAgICAgbXN3ID0gKHggPj4gMTYpICsgKHkgPj4gMTYpICsgKGxzdyA+PiAxNik7XG4gICAgcmV0dXJuIChtc3cgPDwgMTYpIHwgKGxzdyAmIDB4RkZGRik7XG4gIH1cbn1cblxubW9kdWxlLmV4cG9ydHMgPSBNRDVcbiIsIi8qXG4gKiBDcnlwdG9NWCBUb29sc1xuICogQ29weXJpZ2h0IChDKSAyMDA0IC0gMjAwNiBEZXJlayBCdWl0ZW5odWlzXG4gKlxuICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vclxuICogbW9kaWZ5IGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAqIGFzIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uOyBlaXRoZXIgdmVyc2lvbiAyXG4gKiBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cbiAqXG4gKiBUaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbiAqIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4gKiBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlXG4gKiBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuICpcbiAqIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlXG4gKiBhbG9uZyB3aXRoIHRoaXMgcHJvZ3JhbTsgaWYgbm90LCB3cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZVxuICogRm91bmRhdGlvbiwgSW5jLiwgNTkgVGVtcGxlIFBsYWNlIC0gU3VpdGUgMzMwLCBCb3N0b24sIE1BICAwMjExMS0xMzA3LCBVU0EuXG4gKi9cblxuLyogTW9kaWZpZWQgYnkgUmVjdXJpdHkgTGFicyBHbWJIXG4gKi9cblxudmFyIFJNRHNpemUgPSAxNjA7XG52YXIgWCA9IG5ldyBBcnJheSgpO1xuXG5mdW5jdGlvbiBST0woeCwgbikge1xuICByZXR1cm4gbmV3IE51bWJlcigoeCA8PCBuKSB8ICh4ID4+PiAoMzIgLSBuKSkpO1xufVxuXG5mdW5jdGlvbiBGKHgsIHksIHopIHtcbiAgcmV0dXJuIG5ldyBOdW1iZXIoeCBeIHkgXiB6KTtcbn1cblxuZnVuY3Rpb24gRyh4LCB5LCB6KSB7XG4gIHJldHVybiBuZXcgTnVtYmVyKCh4ICYgeSkgfCAofnggJiB6KSk7XG59XG5cbmZ1bmN0aW9uIEgoeCwgeSwgeikge1xuICByZXR1cm4gbmV3IE51bWJlcigoeCB8IH55KSBeIHopO1xufVxuXG5mdW5jdGlvbiBJKHgsIHksIHopIHtcbiAgcmV0dXJuIG5ldyBOdW1iZXIoKHggJiB6KSB8ICh5ICYgfnopKTtcbn1cblxuZnVuY3Rpb24gSih4LCB5LCB6KSB7XG4gIHJldHVybiBuZXcgTnVtYmVyKHggXiAoeSB8IH56KSk7XG59XG5cbmZ1bmN0aW9uIG1peE9uZVJvdW5kKGEsIGIsIGMsIGQsIGUsIHgsIHMsIHJvdW5kTnVtYmVyKSB7XG4gIHN3aXRjaCAocm91bmROdW1iZXIpIHtcbiAgICBjYXNlIDA6XG4gICAgICBhICs9IEYoYiwgYywgZCkgKyB4ICsgMHgwMDAwMDAwMDtcbiAgICAgIGJyZWFrO1xuICAgIGNhc2UgMTpcbiAgICAgIGEgKz0gRyhiLCBjLCBkKSArIHggKyAweDVhODI3OTk5O1xuICAgICAgYnJlYWs7XG4gICAgY2FzZSAyOlxuICAgICAgYSArPSBIKGIsIGMsIGQpICsgeCArIDB4NmVkOWViYTE7XG4gICAgICBicmVhaztcbiAgICBjYXNlIDM6XG4gICAgICBhICs9IEkoYiwgYywgZCkgKyB4ICsgMHg4ZjFiYmNkYztcbiAgICAgIGJyZWFrO1xuICAgIGNhc2UgNDpcbiAgICAgIGEgKz0gSihiLCBjLCBkKSArIHggKyAweGE5NTNmZDRlO1xuICAgICAgYnJlYWs7XG4gICAgY2FzZSA1OlxuICAgICAgYSArPSBKKGIsIGMsIGQpICsgeCArIDB4NTBhMjhiZTY7XG4gICAgICBicmVhaztcbiAgICBjYXNlIDY6XG4gICAgICBhICs9IEkoYiwgYywgZCkgKyB4ICsgMHg1YzRkZDEyNDtcbiAgICAgIGJyZWFrO1xuICAgIGNhc2UgNzpcbiAgICAgIGEgKz0gSChiLCBjLCBkKSArIHggKyAweDZkNzAzZWYzO1xuICAgICAgYnJlYWs7XG4gICAgY2FzZSA4OlxuICAgICAgYSArPSBHKGIsIGMsIGQpICsgeCArIDB4N2E2ZDc2ZTk7XG4gICAgICBicmVhaztcbiAgICBjYXNlIDk6XG4gICAgICBhICs9IEYoYiwgYywgZCkgKyB4ICsgMHgwMDAwMDAwMDtcbiAgICAgIGJyZWFrO1xuXG4gICAgZGVmYXVsdDpcbiAgICAgIGRvY3VtZW50LndyaXRlKFwiQm9ndXMgcm91bmQgbnVtYmVyXCIpO1xuICAgICAgYnJlYWs7XG4gIH1cblxuICBhID0gUk9MKGEsIHMpICsgZTtcbiAgYyA9IFJPTChjLCAxMCk7XG5cbiAgYSAmPSAweGZmZmZmZmZmO1xuICBiICY9IDB4ZmZmZmZmZmY7XG4gIGMgJj0gMHhmZmZmZmZmZjtcbiAgZCAmPSAweGZmZmZmZmZmO1xuICBlICY9IDB4ZmZmZmZmZmY7XG5cbiAgdmFyIHJldEJsb2NrID0gbmV3IEFycmF5KCk7XG4gIHJldEJsb2NrWzBdID0gYTtcbiAgcmV0QmxvY2tbMV0gPSBiO1xuICByZXRCbG9ja1syXSA9IGM7XG4gIHJldEJsb2NrWzNdID0gZDtcbiAgcmV0QmxvY2tbNF0gPSBlO1xuICByZXRCbG9ja1s1XSA9IHg7XG4gIHJldEJsb2NrWzZdID0gcztcblxuICByZXR1cm4gcmV0QmxvY2s7XG59XG5cbmZ1bmN0aW9uIE1EaW5pdChNRGJ1Zikge1xuICBNRGJ1ZlswXSA9IDB4Njc0NTIzMDE7XG4gIE1EYnVmWzFdID0gMHhlZmNkYWI4OTtcbiAgTURidWZbMl0gPSAweDk4YmFkY2ZlO1xuICBNRGJ1ZlszXSA9IDB4MTAzMjU0NzY7XG4gIE1EYnVmWzRdID0gMHhjM2QyZTFmMDtcbn1cblxudmFyIFJPTHMgPSBbXG4gIFsxMSwgMTQsIDE1LCAxMiwgNSwgOCwgNywgOSwgMTEsIDEzLCAxNCwgMTUsIDYsIDcsIDksIDhdLFxuICBbNywgNiwgOCwgMTMsIDExLCA5LCA3LCAxNSwgNywgMTIsIDE1LCA5LCAxMSwgNywgMTMsIDEyXSxcbiAgWzExLCAxMywgNiwgNywgMTQsIDksIDEzLCAxNSwgMTQsIDgsIDEzLCA2LCA1LCAxMiwgNywgNV0sXG4gIFsxMSwgMTIsIDE0LCAxNSwgMTQsIDE1LCA5LCA4LCA5LCAxNCwgNSwgNiwgOCwgNiwgNSwgMTJdLFxuICBbOSwgMTUsIDUsIDExLCA2LCA4LCAxMywgMTIsIDUsIDEyLCAxMywgMTQsIDExLCA4LCA1LCA2XSxcbiAgWzgsIDksIDksIDExLCAxMywgMTUsIDE1LCA1LCA3LCA3LCA4LCAxMSwgMTQsIDE0LCAxMiwgNl0sXG4gIFs5LCAxMywgMTUsIDcsIDEyLCA4LCA5LCAxMSwgNywgNywgMTIsIDcsIDYsIDE1LCAxMywgMTFdLFxuICBbOSwgNywgMTUsIDExLCA4LCA2LCA2LCAxNCwgMTIsIDEzLCA1LCAxNCwgMTMsIDEzLCA3LCA1XSxcbiAgWzE1LCA1LCA4LCAxMSwgMTQsIDE0LCA2LCAxNCwgNiwgOSwgMTIsIDksIDEyLCA1LCAxNSwgOF0sXG4gIFs4LCA1LCAxMiwgOSwgMTIsIDUsIDE0LCA2LCA4LCAxMywgNiwgNSwgMTUsIDEzLCAxMSwgMTFdXG5dO1xuXG52YXIgaW5kZXhlcyA9IFtcbiAgWzAsIDEsIDIsIDMsIDQsIDUsIDYsIDcsIDgsIDksIDEwLCAxMSwgMTIsIDEzLCAxNCwgMTVdLFxuICBbNywgNCwgMTMsIDEsIDEwLCA2LCAxNSwgMywgMTIsIDAsIDksIDUsIDIsIDE0LCAxMSwgOF0sXG4gIFszLCAxMCwgMTQsIDQsIDksIDE1LCA4LCAxLCAyLCA3LCAwLCA2LCAxMywgMTEsIDUsIDEyXSxcbiAgWzEsIDksIDExLCAxMCwgMCwgOCwgMTIsIDQsIDEzLCAzLCA3LCAxNSwgMTQsIDUsIDYsIDJdLFxuICBbNCwgMCwgNSwgOSwgNywgMTIsIDIsIDEwLCAxNCwgMSwgMywgOCwgMTEsIDYsIDE1LCAxM10sXG4gIFs1LCAxNCwgNywgMCwgOSwgMiwgMTEsIDQsIDEzLCA2LCAxNSwgOCwgMSwgMTAsIDMsIDEyXSxcbiAgWzYsIDExLCAzLCA3LCAwLCAxMywgNSwgMTAsIDE0LCAxNSwgOCwgMTIsIDQsIDksIDEsIDJdLFxuICBbMTUsIDUsIDEsIDMsIDcsIDE0LCA2LCA5LCAxMSwgOCwgMTIsIDIsIDEwLCAwLCA0LCAxM10sXG4gIFs4LCA2LCA0LCAxLCAzLCAxMSwgMTUsIDAsIDUsIDEyLCAyLCAxMywgOSwgNywgMTAsIDE0XSxcbiAgWzEyLCAxNSwgMTAsIDQsIDEsIDUsIDgsIDcsIDYsIDIsIDEzLCAxNCwgMCwgMywgOSwgMTFdXG5dO1xuXG5mdW5jdGlvbiBjb21wcmVzcyhNRGJ1ZiwgWCkge1xuICBibG9ja0EgPSBuZXcgQXJyYXkoKTtcbiAgYmxvY2tCID0gbmV3IEFycmF5KCk7XG5cbiAgdmFyIHJldEJsb2NrO1xuXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgNTsgaSsrKSB7XG4gICAgYmxvY2tBW2ldID0gbmV3IE51bWJlcihNRGJ1ZltpXSk7XG4gICAgYmxvY2tCW2ldID0gbmV3IE51bWJlcihNRGJ1ZltpXSk7XG4gIH1cblxuICB2YXIgc3RlcCA9IDA7XG4gIGZvciAodmFyIGogPSAwOyBqIDwgNTsgaisrKSB7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCAxNjsgaSsrKSB7XG4gICAgICByZXRCbG9jayA9IG1peE9uZVJvdW5kKFxuICAgICAgICBibG9ja0FbKHN0ZXAgKyAwKSAlIDVdLFxuICAgICAgICBibG9ja0FbKHN0ZXAgKyAxKSAlIDVdLFxuICAgICAgICBibG9ja0FbKHN0ZXAgKyAyKSAlIDVdLFxuICAgICAgICBibG9ja0FbKHN0ZXAgKyAzKSAlIDVdLFxuICAgICAgICBibG9ja0FbKHN0ZXAgKyA0KSAlIDVdLFxuICAgICAgICBYW2luZGV4ZXNbal1baV1dLFxuICAgICAgICBST0xzW2pdW2ldLFxuICAgICAgICBqKTtcblxuICAgICAgYmxvY2tBWyhzdGVwICsgMCkgJSA1XSA9IHJldEJsb2NrWzBdO1xuICAgICAgYmxvY2tBWyhzdGVwICsgMSkgJSA1XSA9IHJldEJsb2NrWzFdO1xuICAgICAgYmxvY2tBWyhzdGVwICsgMikgJSA1XSA9IHJldEJsb2NrWzJdO1xuICAgICAgYmxvY2tBWyhzdGVwICsgMykgJSA1XSA9IHJldEJsb2NrWzNdO1xuICAgICAgYmxvY2tBWyhzdGVwICsgNCkgJSA1XSA9IHJldEJsb2NrWzRdO1xuXG4gICAgICBzdGVwICs9IDQ7XG4gICAgfVxuICB9XG5cbiAgc3RlcCA9IDA7XG4gIGZvciAodmFyIGogPSA1OyBqIDwgMTA7IGorKykge1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgMTY7IGkrKykge1xuICAgICAgcmV0QmxvY2sgPSBtaXhPbmVSb3VuZChcbiAgICAgICAgYmxvY2tCWyhzdGVwICsgMCkgJSA1XSxcbiAgICAgICAgYmxvY2tCWyhzdGVwICsgMSkgJSA1XSxcbiAgICAgICAgYmxvY2tCWyhzdGVwICsgMikgJSA1XSxcbiAgICAgICAgYmxvY2tCWyhzdGVwICsgMykgJSA1XSxcbiAgICAgICAgYmxvY2tCWyhzdGVwICsgNCkgJSA1XSxcbiAgICAgICAgWFtpbmRleGVzW2pdW2ldXSxcbiAgICAgICAgUk9Mc1tqXVtpXSxcbiAgICAgICAgaik7XG5cbiAgICAgIGJsb2NrQlsoc3RlcCArIDApICUgNV0gPSByZXRCbG9ja1swXTtcbiAgICAgIGJsb2NrQlsoc3RlcCArIDEpICUgNV0gPSByZXRCbG9ja1sxXTtcbiAgICAgIGJsb2NrQlsoc3RlcCArIDIpICUgNV0gPSByZXRCbG9ja1syXTtcbiAgICAgIGJsb2NrQlsoc3RlcCArIDMpICUgNV0gPSByZXRCbG9ja1szXTtcbiAgICAgIGJsb2NrQlsoc3RlcCArIDQpICUgNV0gPSByZXRCbG9ja1s0XTtcblxuICAgICAgc3RlcCArPSA0O1xuICAgIH1cbiAgfVxuXG4gIGJsb2NrQlszXSArPSBibG9ja0FbMl0gKyBNRGJ1ZlsxXTtcbiAgTURidWZbMV0gPSBNRGJ1ZlsyXSArIGJsb2NrQVszXSArIGJsb2NrQls0XTtcbiAgTURidWZbMl0gPSBNRGJ1ZlszXSArIGJsb2NrQVs0XSArIGJsb2NrQlswXTtcbiAgTURidWZbM10gPSBNRGJ1Zls0XSArIGJsb2NrQVswXSArIGJsb2NrQlsxXTtcbiAgTURidWZbNF0gPSBNRGJ1ZlswXSArIGJsb2NrQVsxXSArIGJsb2NrQlsyXTtcbiAgTURidWZbMF0gPSBibG9ja0JbM107XG59XG5cbmZ1bmN0aW9uIHplcm9YKFgpIHtcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCAxNjsgaSsrKSB7XG4gICAgWFtpXSA9IDA7XG4gIH1cbn1cblxuZnVuY3Rpb24gTURmaW5pc2goTURidWYsIHN0cnB0ciwgbHN3bGVuLCBtc3dsZW4pIHtcbiAgdmFyIFggPSBuZXcgQXJyYXkoMTYpO1xuICB6ZXJvWChYKTtcblxuICB2YXIgaiA9IDA7XG4gIGZvciAodmFyIGkgPSAwOyBpIDwgKGxzd2xlbiAmIDYzKTsgaSsrKSB7XG4gICAgWFtpID4+PiAyXSBePSAoc3RycHRyLmNoYXJDb2RlQXQoaisrKSAmIDI1NSkgPDwgKDggKiAoaSAmIDMpKTtcbiAgfVxuXG4gIFhbKGxzd2xlbiA+Pj4gMikgJiAxNV0gXj0gMSA8PCAoOCAqIChsc3dsZW4gJiAzKSArIDcpO1xuXG4gIGlmICgobHN3bGVuICYgNjMpID4gNTUpIHtcbiAgICBjb21wcmVzcyhNRGJ1ZiwgWCk7XG4gICAgdmFyIFggPSBuZXcgQXJyYXkoMTYpO1xuICAgIHplcm9YKFgpO1xuICB9XG5cbiAgWFsxNF0gPSBsc3dsZW4gPDwgMztcbiAgWFsxNV0gPSAobHN3bGVuID4+PiAyOSkgfCAobXN3bGVuIDw8IDMpO1xuXG4gIGNvbXByZXNzKE1EYnVmLCBYKTtcbn1cblxuZnVuY3Rpb24gQllURVNfVE9fRFdPUkQoZm91ckNoYXJzKSB7XG4gIHZhciB0bXAgPSAoZm91ckNoYXJzLmNoYXJDb2RlQXQoMykgJiAyNTUpIDw8IDI0O1xuICB0bXAgfD0gKGZvdXJDaGFycy5jaGFyQ29kZUF0KDIpICYgMjU1KSA8PCAxNjtcbiAgdG1wIHw9IChmb3VyQ2hhcnMuY2hhckNvZGVBdCgxKSAmIDI1NSkgPDwgODtcbiAgdG1wIHw9IChmb3VyQ2hhcnMuY2hhckNvZGVBdCgwKSAmIDI1NSk7XG5cbiAgcmV0dXJuIHRtcDtcbn1cblxuZnVuY3Rpb24gUk1EKG1lc3NhZ2UpIHtcbiAgdmFyIE1EYnVmID0gbmV3IEFycmF5KFJNRHNpemUgLyAzMik7XG4gIHZhciBoYXNoY29kZSA9IG5ldyBBcnJheShSTURzaXplIC8gOCk7XG4gIHZhciBsZW5ndGg7XG4gIHZhciBuYnl0ZXM7XG5cbiAgTURpbml0KE1EYnVmKTtcbiAgbGVuZ3RoID0gbWVzc2FnZS5sZW5ndGg7XG5cbiAgdmFyIFggPSBuZXcgQXJyYXkoMTYpO1xuICB6ZXJvWChYKTtcblxuICB2YXIgaiA9IDA7XG4gIGZvciAodmFyIG5ieXRlcyA9IGxlbmd0aDsgbmJ5dGVzID4gNjM7IG5ieXRlcyAtPSA2NCkge1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgMTY7IGkrKykge1xuICAgICAgWFtpXSA9IEJZVEVTX1RPX0RXT1JEKG1lc3NhZ2Uuc3Vic3RyKGosIDQpKTtcbiAgICAgIGogKz0gNDtcbiAgICB9XG4gICAgY29tcHJlc3MoTURidWYsIFgpO1xuICB9XG5cbiAgTURmaW5pc2goTURidWYsIG1lc3NhZ2Uuc3Vic3RyKGopLCBsZW5ndGgsIDApO1xuXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgUk1Ec2l6ZSAvIDg7IGkgKz0gNCkge1xuICAgIGhhc2hjb2RlW2ldID0gTURidWZbaSA+Pj4gMl0gJiAyNTU7XG4gICAgaGFzaGNvZGVbaSArIDFdID0gKE1EYnVmW2kgPj4+IDJdID4+PiA4KSAmIDI1NTtcbiAgICBoYXNoY29kZVtpICsgMl0gPSAoTURidWZbaSA+Pj4gMl0gPj4+IDE2KSAmIDI1NTtcbiAgICBoYXNoY29kZVtpICsgM10gPSAoTURidWZbaSA+Pj4gMl0gPj4+IDI0KSAmIDI1NTtcbiAgfVxuXG4gIHJldHVybiBoYXNoY29kZTtcbn1cblxuXG5mdW5jdGlvbiBSTURzdHJpbmcobWVzc2FnZSkge1xuICB2YXIgaGFzaGNvZGUgPSBSTUQobWVzc2FnZSk7XG4gIHZhciByZXRTdHJpbmcgPSBcIlwiO1xuXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgUk1Ec2l6ZSAvIDg7IGkrKykge1xuICAgIHJldFN0cmluZyArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGhhc2hjb2RlW2ldKTtcbiAgfVxuXG4gIHJldHVybiByZXRTdHJpbmc7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gUk1Ec3RyaW5nO1xuIiwiLyogQSBKYXZhU2NyaXB0IGltcGxlbWVudGF0aW9uIG9mIHRoZSBTSEEgZmFtaWx5IG9mIGhhc2hlcywgYXMgZGVmaW5lZCBpbiBGSVBTIFxuICogUFVCIDE4MC0yIGFzIHdlbGwgYXMgdGhlIGNvcnJlc3BvbmRpbmcgSE1BQyBpbXBsZW1lbnRhdGlvbiBhcyBkZWZpbmVkIGluXG4gKiBGSVBTIFBVQiAxOThhXG4gKlxuICogVmVyc2lvbiAxLjMgQ29weXJpZ2h0IEJyaWFuIFR1cmVrIDIwMDgtMjAxMFxuICogRGlzdHJpYnV0ZWQgdW5kZXIgdGhlIEJTRCBMaWNlbnNlXG4gKiBTZWUgaHR0cDovL2pzc2hhLnNvdXJjZWZvcmdlLm5ldC8gZm9yIG1vcmUgaW5mb3JtYXRpb25cbiAqXG4gKiBTZXZlcmFsIGZ1bmN0aW9ucyB0YWtlbiBmcm9tIFBhdWwgSm9obnNvblxuICovXG5cbi8qIE1vZGlmaWVkIGJ5IFJlY3VyaXR5IExhYnMgR21iSFxuICogXG4gKiBUaGlzIGNvZGUgaGFzIGJlZW4gc2xpZ2h0bHkgbW9kaWZpZWQgZGlyZWN0IHN0cmluZyBvdXRwdXQ6XG4gKiAtIGJpbjJic3RyIGhhcyBiZWVuIGFkZGVkXG4gKiAtIGZvbGxvd2luZyB3cmFwcGVycyBvZiB0aGlzIGxpYnJhcnkgaGF2ZSBiZWVuIGFkZGVkOlxuICogICAtIHN0cl9zaGExXG4gKiAgIC0gc3RyX3NoYTI1NlxuICogICAtIHN0cl9zaGEyMjRcbiAqICAgLSBzdHJfc2hhMzg0XG4gKiAgIC0gc3RyX3NoYTUxMlxuICovXG5cbnZhciBqc1NIQSA9IChmdW5jdGlvbigpIHtcblxuICAvKlxuICAgKiBDb25maWd1cmFibGUgdmFyaWFibGVzLiBEZWZhdWx0cyB0eXBpY2FsbHkgd29ya1xuICAgKi9cbiAgLyogTnVtYmVyIG9mIEJpdHMgUGVyIGNoYXJhY3RlciAoOCBmb3IgQVNDSUksIDE2IGZvciBVbmljb2RlKSAqL1xuICB2YXIgY2hhclNpemUgPSA4LFxuICAgIC8qIGJhc2UtNjQgcGFkIGNoYXJhY3Rlci4gXCI9XCIgZm9yIHN0cmljdCBSRkMgY29tcGxpYW5jZSAqL1xuICAgIGI2NHBhZCA9IFwiXCIsXG4gICAgLyogaGV4IG91dHB1dCBmb3JtYXQuIDAgLSBsb3dlcmNhc2U7IDEgLSB1cHBlcmNhc2UgKi9cbiAgICBoZXhDYXNlID0gMCxcblxuICAgIC8qXG4gICAgICogSW50XzY0IGlzIGEgb2JqZWN0IGZvciAyIDMyLWJpdCBudW1iZXJzIGVtdWxhdGluZyBhIDY0LWJpdCBudW1iZXJcbiAgICAgKlxuICAgICAqIEBjb25zdHJ1Y3RvclxuICAgICAqIEBwYXJhbSB7TnVtYmVyfSBtc2ludF8zMiBUaGUgbW9zdCBzaWduaWZpY2FudCAzMi1iaXRzIG9mIGEgNjQtYml0IG51bWJlclxuICAgICAqIEBwYXJhbSB7TnVtYmVyfSBsc2ludF8zMiBUaGUgbGVhc3Qgc2lnbmlmaWNhbnQgMzItYml0cyBvZiBhIDY0LWJpdCBudW1iZXJcbiAgICAgKi9cbiAgICBJbnRfNjQgPSBmdW5jdGlvbihtc2ludF8zMiwgbHNpbnRfMzIpIHtcbiAgICAgIHRoaXMuaGlnaE9yZGVyID0gbXNpbnRfMzI7XG4gICAgICB0aGlzLmxvd09yZGVyID0gbHNpbnRfMzI7XG4gICAgfSxcblxuICAgIC8qXG4gICAgICogQ29udmVydCBhIHN0cmluZyB0byBhbiBhcnJheSBvZiBiaWctZW5kaWFuIHdvcmRzXG4gICAgICogSWYgY2hhclNpemUgaXMgQVNDSUksIGNoYXJhY3RlcnMgPjI1NSBoYXZlIHRoZWlyIGhpLWJ5dGUgc2lsZW50bHlcbiAgICAgKiBpZ25vcmVkLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtTdHJpbmd9IHN0ciBTdHJpbmcgdG8gYmUgY29udmVydGVkIHRvIGJpbmFyeSByZXByZXNlbnRhdGlvblxuICAgICAqIEByZXR1cm4gSW50ZWdlciBhcnJheSByZXByZXNlbnRhdGlvbiBvZiB0aGUgcGFyYW1ldGVyXG4gICAgICovXG4gICAgc3RyMmJpbmIgPSBmdW5jdGlvbihzdHIpIHtcbiAgICAgIHZhciBiaW4gPSBbXSxcbiAgICAgICAgbWFzayA9ICgxIDw8IGNoYXJTaXplKSAtIDEsXG4gICAgICAgIGxlbmd0aCA9IHN0ci5sZW5ndGggKiBjaGFyU2l6ZSxcbiAgICAgICAgaTtcblxuICAgICAgZm9yIChpID0gMDsgaSA8IGxlbmd0aDsgaSArPSBjaGFyU2l6ZSkge1xuICAgICAgICBiaW5baSA+PiA1XSB8PSAoc3RyLmNoYXJDb2RlQXQoaSAvIGNoYXJTaXplKSAmIG1hc2spIDw8XG4gICAgICAgICAgKDMyIC0gY2hhclNpemUgLSAoaSAlIDMyKSk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBiaW47XG4gICAgfSxcblxuICAgIC8qXG4gICAgICogQ29udmVydCBhIGhleCBzdHJpbmcgdG8gYW4gYXJyYXkgb2YgYmlnLWVuZGlhbiB3b3Jkc1xuICAgICAqXG4gICAgICogQHBhcmFtIHtTdHJpbmd9IHN0ciBTdHJpbmcgdG8gYmUgY29udmVydGVkIHRvIGJpbmFyeSByZXByZXNlbnRhdGlvblxuICAgICAqIEByZXR1cm4gSW50ZWdlciBhcnJheSByZXByZXNlbnRhdGlvbiBvZiB0aGUgcGFyYW1ldGVyXG4gICAgICovXG4gICAgaGV4MmJpbmIgPSBmdW5jdGlvbihzdHIpIHtcbiAgICAgIHZhciBiaW4gPSBbXSxcbiAgICAgICAgbGVuZ3RoID0gc3RyLmxlbmd0aCxcbiAgICAgICAgaSwgbnVtO1xuXG4gICAgICBmb3IgKGkgPSAwOyBpIDwgbGVuZ3RoOyBpICs9IDIpIHtcbiAgICAgICAgbnVtID0gcGFyc2VJbnQoc3RyLnN1YnN0cihpLCAyKSwgMTYpO1xuICAgICAgICBpZiAoIWlzTmFOKG51bSkpIHtcbiAgICAgICAgICBiaW5baSA+PiAzXSB8PSBudW0gPDwgKDI0IC0gKDQgKiAoaSAlIDgpKSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgcmV0dXJuIFwiSU5WQUxJRCBIRVggU1RSSU5HXCI7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmV0dXJuIGJpbjtcbiAgICB9LFxuXG4gICAgLypcbiAgICAgKiBDb252ZXJ0IGFuIGFycmF5IG9mIGJpZy1lbmRpYW4gd29yZHMgdG8gYSBoZXggc3RyaW5nLlxuICAgICAqXG4gICAgICogQHByaXZhdGVcbiAgICAgKiBAcGFyYW0ge0FycmF5fSBiaW5hcnJheSBBcnJheSBvZiBpbnRlZ2VycyB0byBiZSBjb252ZXJ0ZWQgdG8gaGV4aWRlY2ltYWxcbiAgICAgKlx0IHJlcHJlc2VudGF0aW9uXG4gICAgICogQHJldHVybiBIZXhpZGVjaW1hbCByZXByZXNlbnRhdGlvbiBvZiB0aGUgcGFyYW1ldGVyIGluIFN0cmluZyBmb3JtXG4gICAgICovXG4gICAgYmluYjJoZXggPSBmdW5jdGlvbihiaW5hcnJheSkge1xuICAgICAgdmFyIGhleF90YWIgPSAoaGV4Q2FzZSkgPyBcIjAxMjM0NTY3ODlBQkNERUZcIiA6IFwiMDEyMzQ1Njc4OWFiY2RlZlwiLFxuICAgICAgICBzdHIgPSBcIlwiLFxuICAgICAgICBsZW5ndGggPSBiaW5hcnJheS5sZW5ndGggKiA0LFxuICAgICAgICBpLCBzcmNCeXRlO1xuXG4gICAgICBmb3IgKGkgPSAwOyBpIDwgbGVuZ3RoOyBpICs9IDEpIHtcbiAgICAgICAgc3JjQnl0ZSA9IGJpbmFycmF5W2kgPj4gMl0gPj4gKCgzIC0gKGkgJSA0KSkgKiA4KTtcbiAgICAgICAgc3RyICs9IGhleF90YWIuY2hhckF0KChzcmNCeXRlID4+IDQpICYgMHhGKSArXG4gICAgICAgICAgaGV4X3RhYi5jaGFyQXQoc3JjQnl0ZSAmIDB4Rik7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBzdHI7XG4gICAgfSxcblxuICAgIC8qXG4gICAgICogQ29udmVydCBhbiBhcnJheSBvZiBiaWctZW5kaWFuIHdvcmRzIHRvIGEgYmFzZS02NCBzdHJpbmdcbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICogQHBhcmFtIHtBcnJheX0gYmluYXJyYXkgQXJyYXkgb2YgaW50ZWdlcnMgdG8gYmUgY29udmVydGVkIHRvIGJhc2UtNjRcbiAgICAgKlx0IHJlcHJlc2VudGF0aW9uXG4gICAgICogQHJldHVybiBCYXNlLTY0IGVuY29kZWQgcmVwcmVzZW50YXRpb24gb2YgdGhlIHBhcmFtZXRlciBpbiBTdHJpbmcgZm9ybVxuICAgICAqL1xuICAgIGJpbmIyYjY0ID0gZnVuY3Rpb24oYmluYXJyYXkpIHtcbiAgICAgIHZhciB0YWIgPSBcIkFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpcIiArXG4gICAgICAgIFwiMDEyMzQ1Njc4OSsvXCIsXG4gICAgICAgIHN0ciA9IFwiXCIsXG4gICAgICAgIGxlbmd0aCA9IGJpbmFycmF5Lmxlbmd0aCAqIDQsXG4gICAgICAgIGksIGosXG4gICAgICAgIHRyaXBsZXQ7XG5cbiAgICAgIGZvciAoaSA9IDA7IGkgPCBsZW5ndGg7IGkgKz0gMykge1xuICAgICAgICB0cmlwbGV0ID0gKCgoYmluYXJyYXlbaSA+PiAyXSA+PiA4ICogKDMgLSBpICUgNCkpICYgMHhGRikgPDwgMTYpIHxcbiAgICAgICAgICAoKChiaW5hcnJheVtpICsgMSA+PiAyXSA+PiA4ICogKDMgLSAoaSArIDEpICUgNCkpICYgMHhGRikgPDwgOCkgfFxuICAgICAgICAgICgoYmluYXJyYXlbaSArIDIgPj4gMl0gPj4gOCAqICgzIC0gKGkgKyAyKSAlIDQpKSAmIDB4RkYpO1xuICAgICAgICBmb3IgKGogPSAwOyBqIDwgNDsgaiArPSAxKSB7XG4gICAgICAgICAgaWYgKGkgKiA4ICsgaiAqIDYgPD0gYmluYXJyYXkubGVuZ3RoICogMzIpIHtcbiAgICAgICAgICAgIHN0ciArPSB0YWIuY2hhckF0KCh0cmlwbGV0ID4+IDYgKiAoMyAtIGopKSAmIDB4M0YpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBzdHIgKz0gYjY0cGFkO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgcmV0dXJuIHN0cjtcbiAgICB9LFxuXG4gICAgLypcbiAgICAgKiBDb252ZXJ0IGFuIGFycmF5IG9mIGJpZy1lbmRpYW4gd29yZHMgdG8gYSBzdHJpbmdcbiAgICAgKi9cbiAgICBiaW5iMnN0ciA9IGZ1bmN0aW9uKGJpbikge1xuICAgICAgdmFyIHN0ciA9IFwiXCI7XG4gICAgICB2YXIgbWFzayA9ICgxIDw8IDgpIC0gMTtcbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgYmluLmxlbmd0aCAqIDMyOyBpICs9IDgpXG4gICAgICAgIHN0ciArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKChiaW5baSA+PiA1XSA+Pj4gKDI0IC0gaSAlIDMyKSkgJiBtYXNrKTtcbiAgICAgIHJldHVybiBzdHI7XG4gICAgfSxcbiAgICAvKlxuICAgICAqIFRoZSAzMi1iaXQgaW1wbGVtZW50YXRpb24gb2YgY2lyY3VsYXIgcm90YXRlIGxlZnRcbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICogQHBhcmFtIHtOdW1iZXJ9IHggVGhlIDMyLWJpdCBpbnRlZ2VyIGFyZ3VtZW50XG4gICAgICogQHBhcmFtIHtOdW1iZXJ9IG4gVGhlIG51bWJlciBvZiBiaXRzIHRvIHNoaWZ0XG4gICAgICogQHJldHVybiBUaGUgeCBzaGlmdGVkIGNpcmN1bGFybHkgYnkgbiBiaXRzXG4gICAgICovXG4gICAgcm90bF8zMiA9IGZ1bmN0aW9uKHgsIG4pIHtcbiAgICAgIHJldHVybiAoeCA8PCBuKSB8ICh4ID4+PiAoMzIgLSBuKSk7XG4gICAgfSxcblxuICAgIC8qXG4gICAgICogVGhlIDMyLWJpdCBpbXBsZW1lbnRhdGlvbiBvZiBjaXJjdWxhciByb3RhdGUgcmlnaHRcbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICogQHBhcmFtIHtOdW1iZXJ9IHggVGhlIDMyLWJpdCBpbnRlZ2VyIGFyZ3VtZW50XG4gICAgICogQHBhcmFtIHtOdW1iZXJ9IG4gVGhlIG51bWJlciBvZiBiaXRzIHRvIHNoaWZ0XG4gICAgICogQHJldHVybiBUaGUgeCBzaGlmdGVkIGNpcmN1bGFybHkgYnkgbiBiaXRzXG4gICAgICovXG4gICAgcm90cl8zMiA9IGZ1bmN0aW9uKHgsIG4pIHtcbiAgICAgIHJldHVybiAoeCA+Pj4gbikgfCAoeCA8PCAoMzIgLSBuKSk7XG4gICAgfSxcblxuICAgIC8qXG4gICAgICogVGhlIDY0LWJpdCBpbXBsZW1lbnRhdGlvbiBvZiBjaXJjdWxhciByb3RhdGUgcmlnaHRcbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICogQHBhcmFtIHtJbnRfNjR9IHggVGhlIDY0LWJpdCBpbnRlZ2VyIGFyZ3VtZW50XG4gICAgICogQHBhcmFtIHtOdW1iZXJ9IG4gVGhlIG51bWJlciBvZiBiaXRzIHRvIHNoaWZ0XG4gICAgICogQHJldHVybiBUaGUgeCBzaGlmdGVkIGNpcmN1bGFybHkgYnkgbiBiaXRzXG4gICAgICovXG4gICAgcm90cl82NCA9IGZ1bmN0aW9uKHgsIG4pIHtcbiAgICAgIGlmIChuIDw9IDMyKSB7XG4gICAgICAgIHJldHVybiBuZXcgSW50XzY0KFxuICAgICAgICAoeC5oaWdoT3JkZXIgPj4+IG4pIHwgKHgubG93T3JkZXIgPDwgKDMyIC0gbikpLCAoeC5sb3dPcmRlciA+Pj4gbikgfCAoeC5oaWdoT3JkZXIgPDwgKDMyIC0gbikpKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiBuZXcgSW50XzY0KFxuICAgICAgICAoeC5sb3dPcmRlciA+Pj4gbikgfCAoeC5oaWdoT3JkZXIgPDwgKDMyIC0gbikpLCAoeC5oaWdoT3JkZXIgPj4+IG4pIHwgKHgubG93T3JkZXIgPDwgKDMyIC0gbikpKTtcbiAgICAgIH1cbiAgICB9LFxuXG4gICAgLypcbiAgICAgKiBUaGUgMzItYml0IGltcGxlbWVudGF0aW9uIG9mIHNoaWZ0IHJpZ2h0XG4gICAgICpcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqIEBwYXJhbSB7TnVtYmVyfSB4IFRoZSAzMi1iaXQgaW50ZWdlciBhcmd1bWVudFxuICAgICAqIEBwYXJhbSB7TnVtYmVyfSBuIFRoZSBudW1iZXIgb2YgYml0cyB0byBzaGlmdFxuICAgICAqIEByZXR1cm4gVGhlIHggc2hpZnRlZCBieSBuIGJpdHNcbiAgICAgKi9cbiAgICBzaHJfMzIgPSBmdW5jdGlvbih4LCBuKSB7XG4gICAgICByZXR1cm4geCA+Pj4gbjtcbiAgICB9LFxuXG4gICAgLypcbiAgICAgKiBUaGUgNjQtYml0IGltcGxlbWVudGF0aW9uIG9mIHNoaWZ0IHJpZ2h0XG4gICAgICpcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqIEBwYXJhbSB7SW50XzY0fSB4IFRoZSA2NC1iaXQgaW50ZWdlciBhcmd1bWVudFxuICAgICAqIEBwYXJhbSB7TnVtYmVyfSBuIFRoZSBudW1iZXIgb2YgYml0cyB0byBzaGlmdFxuICAgICAqIEByZXR1cm4gVGhlIHggc2hpZnRlZCBieSBuIGJpdHNcbiAgICAgKi9cbiAgICBzaHJfNjQgPSBmdW5jdGlvbih4LCBuKSB7XG4gICAgICBpZiAobiA8PSAzMikge1xuICAgICAgICByZXR1cm4gbmV3IEludF82NChcbiAgICAgICAgICB4LmhpZ2hPcmRlciA+Pj4gbixcbiAgICAgICAgICB4Lmxvd09yZGVyID4+PiBuIHwgKHguaGlnaE9yZGVyIDw8ICgzMiAtIG4pKSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4gbmV3IEludF82NChcbiAgICAgICAgICAwLFxuICAgICAgICAgIHguaGlnaE9yZGVyIDw8ICgzMiAtIG4pKTtcbiAgICAgIH1cbiAgICB9LFxuXG4gICAgLypcbiAgICAgKiBUaGUgMzItYml0IGltcGxlbWVudGF0aW9uIG9mIHRoZSBOSVNUIHNwZWNpZmllZCBQYXJpdHkgZnVuY3Rpb25cbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICogQHBhcmFtIHtOdW1iZXJ9IHggVGhlIGZpcnN0IDMyLWJpdCBpbnRlZ2VyIGFyZ3VtZW50XG4gICAgICogQHBhcmFtIHtOdW1iZXJ9IHkgVGhlIHNlY29uZCAzMi1iaXQgaW50ZWdlciBhcmd1bWVudFxuICAgICAqIEBwYXJhbSB7TnVtYmVyfSB6IFRoZSB0aGlyZCAzMi1iaXQgaW50ZWdlciBhcmd1bWVudFxuICAgICAqIEByZXR1cm4gVGhlIE5JU1Qgc3BlY2lmaWVkIG91dHB1dCBvZiB0aGUgZnVuY3Rpb25cbiAgICAgKi9cbiAgICBwYXJpdHlfMzIgPSBmdW5jdGlvbih4LCB5LCB6KSB7XG4gICAgICByZXR1cm4geCBeIHkgXiB6O1xuICAgIH0sXG5cbiAgICAvKlxuICAgICAqIFRoZSAzMi1iaXQgaW1wbGVtZW50YXRpb24gb2YgdGhlIE5JU1Qgc3BlY2lmaWVkIENoIGZ1bmN0aW9uXG4gICAgICpcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqIEBwYXJhbSB7TnVtYmVyfSB4IFRoZSBmaXJzdCAzMi1iaXQgaW50ZWdlciBhcmd1bWVudFxuICAgICAqIEBwYXJhbSB7TnVtYmVyfSB5IFRoZSBzZWNvbmQgMzItYml0IGludGVnZXIgYXJndW1lbnRcbiAgICAgKiBAcGFyYW0ge051bWJlcn0geiBUaGUgdGhpcmQgMzItYml0IGludGVnZXIgYXJndW1lbnRcbiAgICAgKiBAcmV0dXJuIFRoZSBOSVNUIHNwZWNpZmllZCBvdXRwdXQgb2YgdGhlIGZ1bmN0aW9uXG4gICAgICovXG4gICAgY2hfMzIgPSBmdW5jdGlvbih4LCB5LCB6KSB7XG4gICAgICByZXR1cm4gKHggJiB5KSBeICh+eCAmIHopO1xuICAgIH0sXG5cbiAgICAvKlxuICAgICAqIFRoZSA2NC1iaXQgaW1wbGVtZW50YXRpb24gb2YgdGhlIE5JU1Qgc3BlY2lmaWVkIENoIGZ1bmN0aW9uXG4gICAgICpcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqIEBwYXJhbSB7SW50XzY0fSB4IFRoZSBmaXJzdCA2NC1iaXQgaW50ZWdlciBhcmd1bWVudFxuICAgICAqIEBwYXJhbSB7SW50XzY0fSB5IFRoZSBzZWNvbmQgNjQtYml0IGludGVnZXIgYXJndW1lbnRcbiAgICAgKiBAcGFyYW0ge0ludF82NH0geiBUaGUgdGhpcmQgNjQtYml0IGludGVnZXIgYXJndW1lbnRcbiAgICAgKiBAcmV0dXJuIFRoZSBOSVNUIHNwZWNpZmllZCBvdXRwdXQgb2YgdGhlIGZ1bmN0aW9uXG4gICAgICovXG4gICAgY2hfNjQgPSBmdW5jdGlvbih4LCB5LCB6KSB7XG4gICAgICByZXR1cm4gbmV3IEludF82NChcbiAgICAgICh4LmhpZ2hPcmRlciAmIHkuaGlnaE9yZGVyKSBeICh+eC5oaWdoT3JkZXIgJiB6LmhpZ2hPcmRlciksICh4Lmxvd09yZGVyICYgeS5sb3dPcmRlcikgXiAofngubG93T3JkZXIgJiB6Lmxvd09yZGVyKSk7XG4gICAgfSxcblxuICAgIC8qXG4gICAgICogVGhlIDMyLWJpdCBpbXBsZW1lbnRhdGlvbiBvZiB0aGUgTklTVCBzcGVjaWZpZWQgTWFqIGZ1bmN0aW9uXG4gICAgICpcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqIEBwYXJhbSB7TnVtYmVyfSB4IFRoZSBmaXJzdCAzMi1iaXQgaW50ZWdlciBhcmd1bWVudFxuICAgICAqIEBwYXJhbSB7TnVtYmVyfSB5IFRoZSBzZWNvbmQgMzItYml0IGludGVnZXIgYXJndW1lbnRcbiAgICAgKiBAcGFyYW0ge051bWJlcn0geiBUaGUgdGhpcmQgMzItYml0IGludGVnZXIgYXJndW1lbnRcbiAgICAgKiBAcmV0dXJuIFRoZSBOSVNUIHNwZWNpZmllZCBvdXRwdXQgb2YgdGhlIGZ1bmN0aW9uXG4gICAgICovXG4gICAgbWFqXzMyID0gZnVuY3Rpb24oeCwgeSwgeikge1xuICAgICAgcmV0dXJuICh4ICYgeSkgXiAoeCAmIHopIF4gKHkgJiB6KTtcbiAgICB9LFxuXG4gICAgLypcbiAgICAgKiBUaGUgNjQtYml0IGltcGxlbWVudGF0aW9uIG9mIHRoZSBOSVNUIHNwZWNpZmllZCBNYWogZnVuY3Rpb25cbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICogQHBhcmFtIHtJbnRfNjR9IHggVGhlIGZpcnN0IDY0LWJpdCBpbnRlZ2VyIGFyZ3VtZW50XG4gICAgICogQHBhcmFtIHtJbnRfNjR9IHkgVGhlIHNlY29uZCA2NC1iaXQgaW50ZWdlciBhcmd1bWVudFxuICAgICAqIEBwYXJhbSB7SW50XzY0fSB6IFRoZSB0aGlyZCA2NC1iaXQgaW50ZWdlciBhcmd1bWVudFxuICAgICAqIEByZXR1cm4gVGhlIE5JU1Qgc3BlY2lmaWVkIG91dHB1dCBvZiB0aGUgZnVuY3Rpb25cbiAgICAgKi9cbiAgICBtYWpfNjQgPSBmdW5jdGlvbih4LCB5LCB6KSB7XG4gICAgICByZXR1cm4gbmV3IEludF82NChcbiAgICAgICh4LmhpZ2hPcmRlciAmIHkuaGlnaE9yZGVyKSBeXG4gICAgICAgICh4LmhpZ2hPcmRlciAmIHouaGlnaE9yZGVyKSBeXG4gICAgICAgICh5LmhpZ2hPcmRlciAmIHouaGlnaE9yZGVyKSwgKHgubG93T3JkZXIgJiB5Lmxvd09yZGVyKSBeXG4gICAgICAgICh4Lmxvd09yZGVyICYgei5sb3dPcmRlcikgXlxuICAgICAgICAoeS5sb3dPcmRlciAmIHoubG93T3JkZXIpKTtcbiAgICB9LFxuXG4gICAgLypcbiAgICAgKiBUaGUgMzItYml0IGltcGxlbWVudGF0aW9uIG9mIHRoZSBOSVNUIHNwZWNpZmllZCBTaWdtYTAgZnVuY3Rpb25cbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICogQHBhcmFtIHtOdW1iZXJ9IHggVGhlIDMyLWJpdCBpbnRlZ2VyIGFyZ3VtZW50XG4gICAgICogQHJldHVybiBUaGUgTklTVCBzcGVjaWZpZWQgb3V0cHV0IG9mIHRoZSBmdW5jdGlvblxuICAgICAqL1xuICAgIHNpZ21hMF8zMiA9IGZ1bmN0aW9uKHgpIHtcbiAgICAgIHJldHVybiByb3RyXzMyKHgsIDIpIF4gcm90cl8zMih4LCAxMykgXiByb3RyXzMyKHgsIDIyKTtcbiAgICB9LFxuXG4gICAgLypcbiAgICAgKiBUaGUgNjQtYml0IGltcGxlbWVudGF0aW9uIG9mIHRoZSBOSVNUIHNwZWNpZmllZCBTaWdtYTAgZnVuY3Rpb25cbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICogQHBhcmFtIHtJbnRfNjR9IHggVGhlIDY0LWJpdCBpbnRlZ2VyIGFyZ3VtZW50XG4gICAgICogQHJldHVybiBUaGUgTklTVCBzcGVjaWZpZWQgb3V0cHV0IG9mIHRoZSBmdW5jdGlvblxuICAgICAqL1xuICAgIHNpZ21hMF82NCA9IGZ1bmN0aW9uKHgpIHtcbiAgICAgIHZhciByb3RyMjggPSByb3RyXzY0KHgsIDI4KSxcbiAgICAgICAgcm90cjM0ID0gcm90cl82NCh4LCAzNCksXG4gICAgICAgIHJvdHIzOSA9IHJvdHJfNjQoeCwgMzkpO1xuXG4gICAgICByZXR1cm4gbmV3IEludF82NChcbiAgICAgICAgcm90cjI4LmhpZ2hPcmRlciBeIHJvdHIzNC5oaWdoT3JkZXIgXiByb3RyMzkuaGlnaE9yZGVyLFxuICAgICAgICByb3RyMjgubG93T3JkZXIgXiByb3RyMzQubG93T3JkZXIgXiByb3RyMzkubG93T3JkZXIpO1xuICAgIH0sXG5cbiAgICAvKlxuICAgICAqIFRoZSAzMi1iaXQgaW1wbGVtZW50YXRpb24gb2YgdGhlIE5JU1Qgc3BlY2lmaWVkIFNpZ21hMSBmdW5jdGlvblxuICAgICAqXG4gICAgICogQHByaXZhdGVcbiAgICAgKiBAcGFyYW0ge051bWJlcn0geCBUaGUgMzItYml0IGludGVnZXIgYXJndW1lbnRcbiAgICAgKiBAcmV0dXJuIFRoZSBOSVNUIHNwZWNpZmllZCBvdXRwdXQgb2YgdGhlIGZ1bmN0aW9uXG4gICAgICovXG4gICAgc2lnbWExXzMyID0gZnVuY3Rpb24oeCkge1xuICAgICAgcmV0dXJuIHJvdHJfMzIoeCwgNikgXiByb3RyXzMyKHgsIDExKSBeIHJvdHJfMzIoeCwgMjUpO1xuICAgIH0sXG5cbiAgICAvKlxuICAgICAqIFRoZSA2NC1iaXQgaW1wbGVtZW50YXRpb24gb2YgdGhlIE5JU1Qgc3BlY2lmaWVkIFNpZ21hMSBmdW5jdGlvblxuICAgICAqXG4gICAgICogQHByaXZhdGVcbiAgICAgKiBAcGFyYW0ge0ludF82NH0geCBUaGUgNjQtYml0IGludGVnZXIgYXJndW1lbnRcbiAgICAgKiBAcmV0dXJuIFRoZSBOSVNUIHNwZWNpZmllZCBvdXRwdXQgb2YgdGhlIGZ1bmN0aW9uXG4gICAgICovXG4gICAgc2lnbWExXzY0ID0gZnVuY3Rpb24oeCkge1xuICAgICAgdmFyIHJvdHIxNCA9IHJvdHJfNjQoeCwgMTQpLFxuICAgICAgICByb3RyMTggPSByb3RyXzY0KHgsIDE4KSxcbiAgICAgICAgcm90cjQxID0gcm90cl82NCh4LCA0MSk7XG5cbiAgICAgIHJldHVybiBuZXcgSW50XzY0KFxuICAgICAgICByb3RyMTQuaGlnaE9yZGVyIF4gcm90cjE4LmhpZ2hPcmRlciBeIHJvdHI0MS5oaWdoT3JkZXIsXG4gICAgICAgIHJvdHIxNC5sb3dPcmRlciBeIHJvdHIxOC5sb3dPcmRlciBeIHJvdHI0MS5sb3dPcmRlcik7XG4gICAgfSxcblxuICAgIC8qXG4gICAgICogVGhlIDMyLWJpdCBpbXBsZW1lbnRhdGlvbiBvZiB0aGUgTklTVCBzcGVjaWZpZWQgR2FtbWEwIGZ1bmN0aW9uXG4gICAgICpcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqIEBwYXJhbSB7TnVtYmVyfSB4IFRoZSAzMi1iaXQgaW50ZWdlciBhcmd1bWVudFxuICAgICAqIEByZXR1cm4gVGhlIE5JU1Qgc3BlY2lmaWVkIG91dHB1dCBvZiB0aGUgZnVuY3Rpb25cbiAgICAgKi9cbiAgICBnYW1tYTBfMzIgPSBmdW5jdGlvbih4KSB7XG4gICAgICByZXR1cm4gcm90cl8zMih4LCA3KSBeIHJvdHJfMzIoeCwgMTgpIF4gc2hyXzMyKHgsIDMpO1xuICAgIH0sXG5cbiAgICAvKlxuICAgICAqIFRoZSA2NC1iaXQgaW1wbGVtZW50YXRpb24gb2YgdGhlIE5JU1Qgc3BlY2lmaWVkIEdhbW1hMCBmdW5jdGlvblxuICAgICAqXG4gICAgICogQHByaXZhdGVcbiAgICAgKiBAcGFyYW0ge0ludF82NH0geCBUaGUgNjQtYml0IGludGVnZXIgYXJndW1lbnRcbiAgICAgKiBAcmV0dXJuIFRoZSBOSVNUIHNwZWNpZmllZCBvdXRwdXQgb2YgdGhlIGZ1bmN0aW9uXG4gICAgICovXG4gICAgZ2FtbWEwXzY0ID0gZnVuY3Rpb24oeCkge1xuICAgICAgdmFyIHJvdHIxID0gcm90cl82NCh4LCAxKSxcbiAgICAgICAgcm90cjggPSByb3RyXzY0KHgsIDgpLFxuICAgICAgICBzaHI3ID0gc2hyXzY0KHgsIDcpO1xuXG4gICAgICByZXR1cm4gbmV3IEludF82NChcbiAgICAgICAgcm90cjEuaGlnaE9yZGVyIF4gcm90cjguaGlnaE9yZGVyIF4gc2hyNy5oaWdoT3JkZXIsXG4gICAgICAgIHJvdHIxLmxvd09yZGVyIF4gcm90cjgubG93T3JkZXIgXiBzaHI3Lmxvd09yZGVyKTtcbiAgICB9LFxuXG4gICAgLypcbiAgICAgKiBUaGUgMzItYml0IGltcGxlbWVudGF0aW9uIG9mIHRoZSBOSVNUIHNwZWNpZmllZCBHYW1tYTEgZnVuY3Rpb25cbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICogQHBhcmFtIHtOdW1iZXJ9IHggVGhlIDMyLWJpdCBpbnRlZ2VyIGFyZ3VtZW50XG4gICAgICogQHJldHVybiBUaGUgTklTVCBzcGVjaWZpZWQgb3V0cHV0IG9mIHRoZSBmdW5jdGlvblxuICAgICAqL1xuICAgIGdhbW1hMV8zMiA9IGZ1bmN0aW9uKHgpIHtcbiAgICAgIHJldHVybiByb3RyXzMyKHgsIDE3KSBeIHJvdHJfMzIoeCwgMTkpIF4gc2hyXzMyKHgsIDEwKTtcbiAgICB9LFxuXG4gICAgLypcbiAgICAgKiBUaGUgNjQtYml0IGltcGxlbWVudGF0aW9uIG9mIHRoZSBOSVNUIHNwZWNpZmllZCBHYW1tYTEgZnVuY3Rpb25cbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICogQHBhcmFtIHtJbnRfNjR9IHggVGhlIDY0LWJpdCBpbnRlZ2VyIGFyZ3VtZW50XG4gICAgICogQHJldHVybiBUaGUgTklTVCBzcGVjaWZpZWQgb3V0cHV0IG9mIHRoZSBmdW5jdGlvblxuICAgICAqL1xuICAgIGdhbW1hMV82NCA9IGZ1bmN0aW9uKHgpIHtcbiAgICAgIHZhciByb3RyMTkgPSByb3RyXzY0KHgsIDE5KSxcbiAgICAgICAgcm90cjYxID0gcm90cl82NCh4LCA2MSksXG4gICAgICAgIHNocjYgPSBzaHJfNjQoeCwgNik7XG5cbiAgICAgIHJldHVybiBuZXcgSW50XzY0KFxuICAgICAgICByb3RyMTkuaGlnaE9yZGVyIF4gcm90cjYxLmhpZ2hPcmRlciBeIHNocjYuaGlnaE9yZGVyLFxuICAgICAgICByb3RyMTkubG93T3JkZXIgXiByb3RyNjEubG93T3JkZXIgXiBzaHI2Lmxvd09yZGVyKTtcbiAgICB9LFxuXG4gICAgLypcbiAgICAgKiBBZGQgdHdvIDMyLWJpdCBpbnRlZ2Vycywgd3JhcHBpbmcgYXQgMl4zMi4gVGhpcyB1c2VzIDE2LWJpdCBvcGVyYXRpb25zXG4gICAgICogaW50ZXJuYWxseSB0byB3b3JrIGFyb3VuZCBidWdzIGluIHNvbWUgSlMgaW50ZXJwcmV0ZXJzLlxuICAgICAqXG4gICAgICogQHByaXZhdGVcbiAgICAgKiBAcGFyYW0ge051bWJlcn0geCBUaGUgZmlyc3QgMzItYml0IGludGVnZXIgYXJndW1lbnQgdG8gYmUgYWRkZWRcbiAgICAgKiBAcGFyYW0ge051bWJlcn0geSBUaGUgc2Vjb25kIDMyLWJpdCBpbnRlZ2VyIGFyZ3VtZW50IHRvIGJlIGFkZGVkXG4gICAgICogQHJldHVybiBUaGUgc3VtIG9mIHggKyB5XG4gICAgICovXG4gICAgc2FmZUFkZF8zMl8yID0gZnVuY3Rpb24oeCwgeSkge1xuICAgICAgdmFyIGxzdyA9ICh4ICYgMHhGRkZGKSArICh5ICYgMHhGRkZGKSxcbiAgICAgICAgbXN3ID0gKHggPj4+IDE2KSArICh5ID4+PiAxNikgKyAobHN3ID4+PiAxNik7XG5cbiAgICAgIHJldHVybiAoKG1zdyAmIDB4RkZGRikgPDwgMTYpIHwgKGxzdyAmIDB4RkZGRik7XG4gICAgfSxcblxuICAgIC8qXG4gICAgICogQWRkIGZvdXIgMzItYml0IGludGVnZXJzLCB3cmFwcGluZyBhdCAyXjMyLiBUaGlzIHVzZXMgMTYtYml0IG9wZXJhdGlvbnNcbiAgICAgKiBpbnRlcm5hbGx5IHRvIHdvcmsgYXJvdW5kIGJ1Z3MgaW4gc29tZSBKUyBpbnRlcnByZXRlcnMuXG4gICAgICpcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqIEBwYXJhbSB7TnVtYmVyfSBhIFRoZSBmaXJzdCAzMi1iaXQgaW50ZWdlciBhcmd1bWVudCB0byBiZSBhZGRlZFxuICAgICAqIEBwYXJhbSB7TnVtYmVyfSBiIFRoZSBzZWNvbmQgMzItYml0IGludGVnZXIgYXJndW1lbnQgdG8gYmUgYWRkZWRcbiAgICAgKiBAcGFyYW0ge051bWJlcn0gYyBUaGUgdGhpcmQgMzItYml0IGludGVnZXIgYXJndW1lbnQgdG8gYmUgYWRkZWRcbiAgICAgKiBAcGFyYW0ge051bWJlcn0gZCBUaGUgZm91cnRoIDMyLWJpdCBpbnRlZ2VyIGFyZ3VtZW50IHRvIGJlIGFkZGVkXG4gICAgICogQHJldHVybiBUaGUgc3VtIG9mIGEgKyBiICsgYyArIGRcbiAgICAgKi9cbiAgICBzYWZlQWRkXzMyXzQgPSBmdW5jdGlvbihhLCBiLCBjLCBkKSB7XG4gICAgICB2YXIgbHN3ID0gKGEgJiAweEZGRkYpICsgKGIgJiAweEZGRkYpICsgKGMgJiAweEZGRkYpICsgKGQgJiAweEZGRkYpLFxuICAgICAgICBtc3cgPSAoYSA+Pj4gMTYpICsgKGIgPj4+IDE2KSArIChjID4+PiAxNikgKyAoZCA+Pj4gMTYpICtcbiAgICAgICAgICAobHN3ID4+PiAxNik7XG5cbiAgICAgIHJldHVybiAoKG1zdyAmIDB4RkZGRikgPDwgMTYpIHwgKGxzdyAmIDB4RkZGRik7XG4gICAgfSxcblxuICAgIC8qXG4gICAgICogQWRkIGZpdmUgMzItYml0IGludGVnZXJzLCB3cmFwcGluZyBhdCAyXjMyLiBUaGlzIHVzZXMgMTYtYml0IG9wZXJhdGlvbnNcbiAgICAgKiBpbnRlcm5hbGx5IHRvIHdvcmsgYXJvdW5kIGJ1Z3MgaW4gc29tZSBKUyBpbnRlcnByZXRlcnMuXG4gICAgICpcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqIEBwYXJhbSB7TnVtYmVyfSBhIFRoZSBmaXJzdCAzMi1iaXQgaW50ZWdlciBhcmd1bWVudCB0byBiZSBhZGRlZFxuICAgICAqIEBwYXJhbSB7TnVtYmVyfSBiIFRoZSBzZWNvbmQgMzItYml0IGludGVnZXIgYXJndW1lbnQgdG8gYmUgYWRkZWRcbiAgICAgKiBAcGFyYW0ge051bWJlcn0gYyBUaGUgdGhpcmQgMzItYml0IGludGVnZXIgYXJndW1lbnQgdG8gYmUgYWRkZWRcbiAgICAgKiBAcGFyYW0ge051bWJlcn0gZCBUaGUgZm91cnRoIDMyLWJpdCBpbnRlZ2VyIGFyZ3VtZW50IHRvIGJlIGFkZGVkXG4gICAgICogQHBhcmFtIHtOdW1iZXJ9IGUgVGhlIGZpZnRoIDMyLWJpdCBpbnRlZ2VyIGFyZ3VtZW50IHRvIGJlIGFkZGVkXG4gICAgICogQHJldHVybiBUaGUgc3VtIG9mIGEgKyBiICsgYyArIGQgKyBlXG4gICAgICovXG4gICAgc2FmZUFkZF8zMl81ID0gZnVuY3Rpb24oYSwgYiwgYywgZCwgZSkge1xuICAgICAgdmFyIGxzdyA9IChhICYgMHhGRkZGKSArIChiICYgMHhGRkZGKSArIChjICYgMHhGRkZGKSArIChkICYgMHhGRkZGKSArXG4gICAgICAgIChlICYgMHhGRkZGKSxcbiAgICAgICAgbXN3ID0gKGEgPj4+IDE2KSArIChiID4+PiAxNikgKyAoYyA+Pj4gMTYpICsgKGQgPj4+IDE2KSArXG4gICAgICAgICAgKGUgPj4+IDE2KSArIChsc3cgPj4+IDE2KTtcblxuICAgICAgcmV0dXJuICgobXN3ICYgMHhGRkZGKSA8PCAxNikgfCAobHN3ICYgMHhGRkZGKTtcbiAgICB9LFxuXG4gICAgLypcbiAgICAgKiBBZGQgdHdvIDY0LWJpdCBpbnRlZ2Vycywgd3JhcHBpbmcgYXQgMl42NC4gVGhpcyB1c2VzIDE2LWJpdCBvcGVyYXRpb25zXG4gICAgICogaW50ZXJuYWxseSB0byB3b3JrIGFyb3VuZCBidWdzIGluIHNvbWUgSlMgaW50ZXJwcmV0ZXJzLlxuICAgICAqXG4gICAgICogQHByaXZhdGVcbiAgICAgKiBAcGFyYW0ge0ludF82NH0geCBUaGUgZmlyc3QgNjQtYml0IGludGVnZXIgYXJndW1lbnQgdG8gYmUgYWRkZWRcbiAgICAgKiBAcGFyYW0ge0ludF82NH0geSBUaGUgc2Vjb25kIDY0LWJpdCBpbnRlZ2VyIGFyZ3VtZW50IHRvIGJlIGFkZGVkXG4gICAgICogQHJldHVybiBUaGUgc3VtIG9mIHggKyB5XG4gICAgICovXG4gICAgc2FmZUFkZF82NF8yID0gZnVuY3Rpb24oeCwgeSkge1xuICAgICAgdmFyIGxzdywgbXN3LCBsb3dPcmRlciwgaGlnaE9yZGVyO1xuXG4gICAgICBsc3cgPSAoeC5sb3dPcmRlciAmIDB4RkZGRikgKyAoeS5sb3dPcmRlciAmIDB4RkZGRik7XG4gICAgICBtc3cgPSAoeC5sb3dPcmRlciA+Pj4gMTYpICsgKHkubG93T3JkZXIgPj4+IDE2KSArIChsc3cgPj4+IDE2KTtcbiAgICAgIGxvd09yZGVyID0gKChtc3cgJiAweEZGRkYpIDw8IDE2KSB8IChsc3cgJiAweEZGRkYpO1xuXG4gICAgICBsc3cgPSAoeC5oaWdoT3JkZXIgJiAweEZGRkYpICsgKHkuaGlnaE9yZGVyICYgMHhGRkZGKSArIChtc3cgPj4+IDE2KTtcbiAgICAgIG1zdyA9ICh4LmhpZ2hPcmRlciA+Pj4gMTYpICsgKHkuaGlnaE9yZGVyID4+PiAxNikgKyAobHN3ID4+PiAxNik7XG4gICAgICBoaWdoT3JkZXIgPSAoKG1zdyAmIDB4RkZGRikgPDwgMTYpIHwgKGxzdyAmIDB4RkZGRik7XG5cbiAgICAgIHJldHVybiBuZXcgSW50XzY0KGhpZ2hPcmRlciwgbG93T3JkZXIpO1xuICAgIH0sXG5cbiAgICAvKlxuICAgICAqIEFkZCBmb3VyIDY0LWJpdCBpbnRlZ2Vycywgd3JhcHBpbmcgYXQgMl42NC4gVGhpcyB1c2VzIDE2LWJpdCBvcGVyYXRpb25zXG4gICAgICogaW50ZXJuYWxseSB0byB3b3JrIGFyb3VuZCBidWdzIGluIHNvbWUgSlMgaW50ZXJwcmV0ZXJzLlxuICAgICAqXG4gICAgICogQHByaXZhdGVcbiAgICAgKiBAcGFyYW0ge0ludF82NH0gYSBUaGUgZmlyc3QgNjQtYml0IGludGVnZXIgYXJndW1lbnQgdG8gYmUgYWRkZWRcbiAgICAgKiBAcGFyYW0ge0ludF82NH0gYiBUaGUgc2Vjb25kIDY0LWJpdCBpbnRlZ2VyIGFyZ3VtZW50IHRvIGJlIGFkZGVkXG4gICAgICogQHBhcmFtIHtJbnRfNjR9IGMgVGhlIHRoaXJkIDY0LWJpdCBpbnRlZ2VyIGFyZ3VtZW50IHRvIGJlIGFkZGVkXG4gICAgICogQHBhcmFtIHtJbnRfNjR9IGQgVGhlIGZvdXRoIDY0LWJpdCBpbnRlZ2VyIGFyZ3VtZW50IHRvIGJlIGFkZGVkXG4gICAgICogQHJldHVybiBUaGUgc3VtIG9mIGEgKyBiICsgYyArIGRcbiAgICAgKi9cbiAgICBzYWZlQWRkXzY0XzQgPSBmdW5jdGlvbihhLCBiLCBjLCBkKSB7XG4gICAgICB2YXIgbHN3LCBtc3csIGxvd09yZGVyLCBoaWdoT3JkZXI7XG5cbiAgICAgIGxzdyA9IChhLmxvd09yZGVyICYgMHhGRkZGKSArIChiLmxvd09yZGVyICYgMHhGRkZGKSArXG4gICAgICAgIChjLmxvd09yZGVyICYgMHhGRkZGKSArIChkLmxvd09yZGVyICYgMHhGRkZGKTtcbiAgICAgIG1zdyA9IChhLmxvd09yZGVyID4+PiAxNikgKyAoYi5sb3dPcmRlciA+Pj4gMTYpICtcbiAgICAgICAgKGMubG93T3JkZXIgPj4+IDE2KSArIChkLmxvd09yZGVyID4+PiAxNikgKyAobHN3ID4+PiAxNik7XG4gICAgICBsb3dPcmRlciA9ICgobXN3ICYgMHhGRkZGKSA8PCAxNikgfCAobHN3ICYgMHhGRkZGKTtcblxuICAgICAgbHN3ID0gKGEuaGlnaE9yZGVyICYgMHhGRkZGKSArIChiLmhpZ2hPcmRlciAmIDB4RkZGRikgK1xuICAgICAgICAoYy5oaWdoT3JkZXIgJiAweEZGRkYpICsgKGQuaGlnaE9yZGVyICYgMHhGRkZGKSArIChtc3cgPj4+IDE2KTtcbiAgICAgIG1zdyA9IChhLmhpZ2hPcmRlciA+Pj4gMTYpICsgKGIuaGlnaE9yZGVyID4+PiAxNikgK1xuICAgICAgICAoYy5oaWdoT3JkZXIgPj4+IDE2KSArIChkLmhpZ2hPcmRlciA+Pj4gMTYpICsgKGxzdyA+Pj4gMTYpO1xuICAgICAgaGlnaE9yZGVyID0gKChtc3cgJiAweEZGRkYpIDw8IDE2KSB8IChsc3cgJiAweEZGRkYpO1xuXG4gICAgICByZXR1cm4gbmV3IEludF82NChoaWdoT3JkZXIsIGxvd09yZGVyKTtcbiAgICB9LFxuXG4gICAgLypcbiAgICAgKiBBZGQgZml2ZSA2NC1iaXQgaW50ZWdlcnMsIHdyYXBwaW5nIGF0IDJeNjQuIFRoaXMgdXNlcyAxNi1iaXQgb3BlcmF0aW9uc1xuICAgICAqIGludGVybmFsbHkgdG8gd29yayBhcm91bmQgYnVncyBpbiBzb21lIEpTIGludGVycHJldGVycy5cbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICogQHBhcmFtIHtJbnRfNjR9IGEgVGhlIGZpcnN0IDY0LWJpdCBpbnRlZ2VyIGFyZ3VtZW50IHRvIGJlIGFkZGVkXG4gICAgICogQHBhcmFtIHtJbnRfNjR9IGIgVGhlIHNlY29uZCA2NC1iaXQgaW50ZWdlciBhcmd1bWVudCB0byBiZSBhZGRlZFxuICAgICAqIEBwYXJhbSB7SW50XzY0fSBjIFRoZSB0aGlyZCA2NC1iaXQgaW50ZWdlciBhcmd1bWVudCB0byBiZSBhZGRlZFxuICAgICAqIEBwYXJhbSB7SW50XzY0fSBkIFRoZSBmb3V0aCA2NC1iaXQgaW50ZWdlciBhcmd1bWVudCB0byBiZSBhZGRlZFxuICAgICAqIEBwYXJhbSB7SW50XzY0fSBlIFRoZSBmb3V0aCA2NC1iaXQgaW50ZWdlciBhcmd1bWVudCB0byBiZSBhZGRlZFxuICAgICAqIEByZXR1cm4gVGhlIHN1bSBvZiBhICsgYiArIGMgKyBkICsgZVxuICAgICAqL1xuICAgIHNhZmVBZGRfNjRfNSA9IGZ1bmN0aW9uKGEsIGIsIGMsIGQsIGUpIHtcbiAgICAgIHZhciBsc3csIG1zdywgbG93T3JkZXIsIGhpZ2hPcmRlcjtcblxuICAgICAgbHN3ID0gKGEubG93T3JkZXIgJiAweEZGRkYpICsgKGIubG93T3JkZXIgJiAweEZGRkYpICtcbiAgICAgICAgKGMubG93T3JkZXIgJiAweEZGRkYpICsgKGQubG93T3JkZXIgJiAweEZGRkYpICtcbiAgICAgICAgKGUubG93T3JkZXIgJiAweEZGRkYpO1xuICAgICAgbXN3ID0gKGEubG93T3JkZXIgPj4+IDE2KSArIChiLmxvd09yZGVyID4+PiAxNikgK1xuICAgICAgICAoYy5sb3dPcmRlciA+Pj4gMTYpICsgKGQubG93T3JkZXIgPj4+IDE2KSArIChlLmxvd09yZGVyID4+PiAxNikgK1xuICAgICAgICAobHN3ID4+PiAxNik7XG4gICAgICBsb3dPcmRlciA9ICgobXN3ICYgMHhGRkZGKSA8PCAxNikgfCAobHN3ICYgMHhGRkZGKTtcblxuICAgICAgbHN3ID0gKGEuaGlnaE9yZGVyICYgMHhGRkZGKSArIChiLmhpZ2hPcmRlciAmIDB4RkZGRikgK1xuICAgICAgICAoYy5oaWdoT3JkZXIgJiAweEZGRkYpICsgKGQuaGlnaE9yZGVyICYgMHhGRkZGKSArXG4gICAgICAgIChlLmhpZ2hPcmRlciAmIDB4RkZGRikgKyAobXN3ID4+PiAxNik7XG4gICAgICBtc3cgPSAoYS5oaWdoT3JkZXIgPj4+IDE2KSArIChiLmhpZ2hPcmRlciA+Pj4gMTYpICtcbiAgICAgICAgKGMuaGlnaE9yZGVyID4+PiAxNikgKyAoZC5oaWdoT3JkZXIgPj4+IDE2KSArXG4gICAgICAgIChlLmhpZ2hPcmRlciA+Pj4gMTYpICsgKGxzdyA+Pj4gMTYpO1xuICAgICAgaGlnaE9yZGVyID0gKChtc3cgJiAweEZGRkYpIDw8IDE2KSB8IChsc3cgJiAweEZGRkYpO1xuXG4gICAgICByZXR1cm4gbmV3IEludF82NChoaWdoT3JkZXIsIGxvd09yZGVyKTtcbiAgICB9LFxuXG4gICAgLypcbiAgICAgKiBDYWxjdWxhdGVzIHRoZSBTSEEtMSBoYXNoIG9mIHRoZSBzdHJpbmcgc2V0IGF0IGluc3RhbnRpYXRpb25cbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICogQHBhcmFtIHtBcnJheX0gbWVzc2FnZSBUaGUgYmluYXJ5IGFycmF5IHJlcHJlc2VudGF0aW9uIG9mIHRoZSBzdHJpbmcgdG9cbiAgICAgKlx0IGhhc2hcbiAgICAgKiBAcGFyYW0ge051bWJlcn0gbWVzc2FnZUxlbiBUaGUgbnVtYmVyIG9mIGJpdHMgaW4gdGhlIG1lc3NhZ2VcbiAgICAgKiBAcmV0dXJuIFRoZSBhcnJheSBvZiBpbnRlZ2VycyByZXByZXNlbnRpbmcgdGhlIFNIQS0xIGhhc2ggb2YgbWVzc2FnZVxuICAgICAqL1xuICAgIGNvcmVTSEExID0gZnVuY3Rpb24obWVzc2FnZSwgbWVzc2FnZUxlbikge1xuICAgICAgdmFyIFcgPSBbXSxcbiAgICAgICAgYSwgYiwgYywgZCwgZSwgVCwgY2ggPSBjaF8zMixcbiAgICAgICAgcGFyaXR5ID0gcGFyaXR5XzMyLFxuICAgICAgICBtYWogPSBtYWpfMzIsXG4gICAgICAgIHJvdGwgPSByb3RsXzMyLFxuICAgICAgICBzYWZlQWRkXzIgPSBzYWZlQWRkXzMyXzIsXG4gICAgICAgIGksIHQsXG4gICAgICAgIHNhZmVBZGRfNSA9IHNhZmVBZGRfMzJfNSxcbiAgICAgICAgYXBwZW5kZWRNZXNzYWdlTGVuZ3RoLFxuICAgICAgICBIID0gW1xuICAgICAgICAgICAgMHg2NzQ1MjMwMSwgMHhlZmNkYWI4OSwgMHg5OGJhZGNmZSwgMHgxMDMyNTQ3NiwgMHhjM2QyZTFmMFxuICAgICAgICBdLFxuICAgICAgICBLID0gW1xuICAgICAgICAgICAgMHg1YTgyNzk5OSwgMHg1YTgyNzk5OSwgMHg1YTgyNzk5OSwgMHg1YTgyNzk5OSxcbiAgICAgICAgICAgIDB4NWE4Mjc5OTksIDB4NWE4Mjc5OTksIDB4NWE4Mjc5OTksIDB4NWE4Mjc5OTksXG4gICAgICAgICAgICAweDVhODI3OTk5LCAweDVhODI3OTk5LCAweDVhODI3OTk5LCAweDVhODI3OTk5LFxuICAgICAgICAgICAgMHg1YTgyNzk5OSwgMHg1YTgyNzk5OSwgMHg1YTgyNzk5OSwgMHg1YTgyNzk5OSxcbiAgICAgICAgICAgIDB4NWE4Mjc5OTksIDB4NWE4Mjc5OTksIDB4NWE4Mjc5OTksIDB4NWE4Mjc5OTksXG4gICAgICAgICAgICAweDZlZDllYmExLCAweDZlZDllYmExLCAweDZlZDllYmExLCAweDZlZDllYmExLFxuICAgICAgICAgICAgMHg2ZWQ5ZWJhMSwgMHg2ZWQ5ZWJhMSwgMHg2ZWQ5ZWJhMSwgMHg2ZWQ5ZWJhMSxcbiAgICAgICAgICAgIDB4NmVkOWViYTEsIDB4NmVkOWViYTEsIDB4NmVkOWViYTEsIDB4NmVkOWViYTEsXG4gICAgICAgICAgICAweDZlZDllYmExLCAweDZlZDllYmExLCAweDZlZDllYmExLCAweDZlZDllYmExLFxuICAgICAgICAgICAgMHg2ZWQ5ZWJhMSwgMHg2ZWQ5ZWJhMSwgMHg2ZWQ5ZWJhMSwgMHg2ZWQ5ZWJhMSxcbiAgICAgICAgICAgIDB4OGYxYmJjZGMsIDB4OGYxYmJjZGMsIDB4OGYxYmJjZGMsIDB4OGYxYmJjZGMsXG4gICAgICAgICAgICAweDhmMWJiY2RjLCAweDhmMWJiY2RjLCAweDhmMWJiY2RjLCAweDhmMWJiY2RjLFxuICAgICAgICAgICAgMHg4ZjFiYmNkYywgMHg4ZjFiYmNkYywgMHg4ZjFiYmNkYywgMHg4ZjFiYmNkYyxcbiAgICAgICAgICAgIDB4OGYxYmJjZGMsIDB4OGYxYmJjZGMsIDB4OGYxYmJjZGMsIDB4OGYxYmJjZGMsXG4gICAgICAgICAgICAweDhmMWJiY2RjLCAweDhmMWJiY2RjLCAweDhmMWJiY2RjLCAweDhmMWJiY2RjLFxuICAgICAgICAgICAgMHhjYTYyYzFkNiwgMHhjYTYyYzFkNiwgMHhjYTYyYzFkNiwgMHhjYTYyYzFkNixcbiAgICAgICAgICAgIDB4Y2E2MmMxZDYsIDB4Y2E2MmMxZDYsIDB4Y2E2MmMxZDYsIDB4Y2E2MmMxZDYsXG4gICAgICAgICAgICAweGNhNjJjMWQ2LCAweGNhNjJjMWQ2LCAweGNhNjJjMWQ2LCAweGNhNjJjMWQ2LFxuICAgICAgICAgICAgMHhjYTYyYzFkNiwgMHhjYTYyYzFkNiwgMHhjYTYyYzFkNiwgMHhjYTYyYzFkNixcbiAgICAgICAgICAgIDB4Y2E2MmMxZDYsIDB4Y2E2MmMxZDYsIDB4Y2E2MmMxZDYsIDB4Y2E2MmMxZDZcbiAgICAgICAgXTtcblxuICAgICAgLyogQXBwZW5kICcxJyBhdCB0aGUgZW5kIG9mIHRoZSBiaW5hcnkgc3RyaW5nICovXG4gICAgICBtZXNzYWdlW21lc3NhZ2VMZW4gPj4gNV0gfD0gMHg4MCA8PCAoMjQgLSAobWVzc2FnZUxlbiAlIDMyKSk7XG4gICAgICAvKiBBcHBlbmQgbGVuZ3RoIG9mIGJpbmFyeSBzdHJpbmcgaW4gdGhlIHBvc2l0aW9uIHN1Y2ggdGhhdCB0aGUgbmV3XG5cdFx0bGVuZ3RoIGlzIGEgbXVsdGlwbGUgb2YgNTEyLiAgTG9naWMgZG9lcyBub3Qgd29yayBmb3IgZXZlbiBtdWx0aXBsZXNcblx0XHRvZiA1MTIgYnV0IHRoZXJlIGNhbiBuZXZlciBiZSBldmVuIG11bHRpcGxlcyBvZiA1MTIgKi9cbiAgICAgIG1lc3NhZ2VbKCgobWVzc2FnZUxlbiArIDY1KSA+PiA5KSA8PCA0KSArIDE1XSA9IG1lc3NhZ2VMZW47XG5cbiAgICAgIGFwcGVuZGVkTWVzc2FnZUxlbmd0aCA9IG1lc3NhZ2UubGVuZ3RoO1xuXG4gICAgICBmb3IgKGkgPSAwOyBpIDwgYXBwZW5kZWRNZXNzYWdlTGVuZ3RoOyBpICs9IDE2KSB7XG4gICAgICAgIGEgPSBIWzBdO1xuICAgICAgICBiID0gSFsxXTtcbiAgICAgICAgYyA9IEhbMl07XG4gICAgICAgIGQgPSBIWzNdO1xuICAgICAgICBlID0gSFs0XTtcblxuICAgICAgICBmb3IgKHQgPSAwOyB0IDwgODA7IHQgKz0gMSkge1xuICAgICAgICAgIGlmICh0IDwgMTYpIHtcbiAgICAgICAgICAgIFdbdF0gPSBtZXNzYWdlW3QgKyBpXTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgV1t0XSA9IHJvdGwoV1t0IC0gM10gXiBXW3QgLSA4XSBeIFdbdCAtIDE0XSBeIFdbdCAtIDE2XSwgMSk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKHQgPCAyMCkge1xuICAgICAgICAgICAgVCA9IHNhZmVBZGRfNShyb3RsKGEsIDUpLCBjaChiLCBjLCBkKSwgZSwgS1t0XSwgV1t0XSk7XG4gICAgICAgICAgfSBlbHNlIGlmICh0IDwgNDApIHtcbiAgICAgICAgICAgIFQgPSBzYWZlQWRkXzUocm90bChhLCA1KSwgcGFyaXR5KGIsIGMsIGQpLCBlLCBLW3RdLCBXW3RdKTtcbiAgICAgICAgICB9IGVsc2UgaWYgKHQgPCA2MCkge1xuICAgICAgICAgICAgVCA9IHNhZmVBZGRfNShyb3RsKGEsIDUpLCBtYWooYiwgYywgZCksIGUsIEtbdF0sIFdbdF0pO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBUID0gc2FmZUFkZF81KHJvdGwoYSwgNSksIHBhcml0eShiLCBjLCBkKSwgZSwgS1t0XSwgV1t0XSk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgZSA9IGQ7XG4gICAgICAgICAgZCA9IGM7XG4gICAgICAgICAgYyA9IHJvdGwoYiwgMzApO1xuICAgICAgICAgIGIgPSBhO1xuICAgICAgICAgIGEgPSBUO1xuICAgICAgICB9XG5cbiAgICAgICAgSFswXSA9IHNhZmVBZGRfMihhLCBIWzBdKTtcbiAgICAgICAgSFsxXSA9IHNhZmVBZGRfMihiLCBIWzFdKTtcbiAgICAgICAgSFsyXSA9IHNhZmVBZGRfMihjLCBIWzJdKTtcbiAgICAgICAgSFszXSA9IHNhZmVBZGRfMihkLCBIWzNdKTtcbiAgICAgICAgSFs0XSA9IHNhZmVBZGRfMihlLCBIWzRdKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIEg7XG4gICAgfSxcblxuICAgIC8qXG4gICAgICogQ2FsY3VsYXRlcyB0aGUgZGVzaXJlZCBTSEEtMiBoYXNoIG9mIHRoZSBzdHJpbmcgc2V0IGF0IGluc3RhbnRpYXRpb25cbiAgICAgKlxuICAgICAqIEBwcml2YXRlXG4gICAgICogQHBhcmFtIHtBcnJheX0gVGhlIGJpbmFyeSBhcnJheSByZXByZXNlbnRhdGlvbiBvZiB0aGUgc3RyaW5nIHRvIGhhc2hcbiAgICAgKiBAcGFyYW0ge051bWJlcn0gVGhlIG51bWJlciBvZiBiaXRzIGluIG1lc3NhZ2VcbiAgICAgKiBAcGFyYW0ge1N0cmluZ30gdmFyaWFudCBUaGUgZGVzaXJlZCBTSEEtMiB2YXJpYW50XG4gICAgICogQHJldHVybiBUaGUgYXJyYXkgb2YgaW50ZWdlcnMgcmVwcmVzZW50aW5nIHRoZSBTSEEtMiBoYXNoIG9mIG1lc3NhZ2VcbiAgICAgKi9cbiAgICBjb3JlU0hBMiA9IGZ1bmN0aW9uKG1lc3NhZ2UsIG1lc3NhZ2VMZW4sIHZhcmlhbnQpIHtcbiAgICAgIHZhciBhLCBiLCBjLCBkLCBlLCBmLCBnLCBoLCBUMSwgVDIsIEgsIG51bVJvdW5kcywgbGVuZ3RoUG9zaXRpb24sIGksIHQsXG4gICAgICAgIGJpbmFyeVN0cmluZ0luYywgYmluYXJ5U3RyaW5nTXVsdCwgc2FmZUFkZF8yLCBzYWZlQWRkXzQsIHNhZmVBZGRfNSxcbiAgICAgICAgZ2FtbWEwLCBnYW1tYTEsIHNpZ21hMCwgc2lnbWExLCBjaCwgbWFqLCBJbnQsIEssIFcgPSBbXSxcbiAgICAgICAgYXBwZW5kZWRNZXNzYWdlTGVuZ3RoO1xuXG4gICAgICAvKiBTZXQgdXAgdGhlIHZhcmlvdXMgZnVuY3Rpb24gaGFuZGxlcyBhbmQgdmFyaWFibGUgZm9yIHRoZSBzcGVjaWZpYyBcbiAgICAgICAqIHZhcmlhbnQgKi9cbiAgICAgIGlmICh2YXJpYW50ID09PSBcIlNIQS0yMjRcIiB8fCB2YXJpYW50ID09PSBcIlNIQS0yNTZcIikge1xuICAgICAgICAvKiAzMi1iaXQgdmFyaWFudCAqL1xuICAgICAgICBudW1Sb3VuZHMgPSA2NDtcbiAgICAgICAgbGVuZ3RoUG9zaXRpb24gPSAoKChtZXNzYWdlTGVuICsgNjUpID4+IDkpIDw8IDQpICsgMTU7XG4gICAgICAgIGJpbmFyeVN0cmluZ0luYyA9IDE2O1xuICAgICAgICBiaW5hcnlTdHJpbmdNdWx0ID0gMTtcbiAgICAgICAgSW50ID0gTnVtYmVyO1xuICAgICAgICBzYWZlQWRkXzIgPSBzYWZlQWRkXzMyXzI7XG4gICAgICAgIHNhZmVBZGRfNCA9IHNhZmVBZGRfMzJfNDtcbiAgICAgICAgc2FmZUFkZF81ID0gc2FmZUFkZF8zMl81O1xuICAgICAgICBnYW1tYTAgPSBnYW1tYTBfMzI7XG4gICAgICAgIGdhbW1hMSA9IGdhbW1hMV8zMjtcbiAgICAgICAgc2lnbWEwID0gc2lnbWEwXzMyO1xuICAgICAgICBzaWdtYTEgPSBzaWdtYTFfMzI7XG4gICAgICAgIG1haiA9IG1hal8zMjtcbiAgICAgICAgY2ggPSBjaF8zMjtcbiAgICAgICAgSyA9IFtcbiAgICAgICAgICAgIDB4NDI4QTJGOTgsIDB4NzEzNzQ0OTEsIDB4QjVDMEZCQ0YsIDB4RTlCNURCQTUsXG4gICAgICAgICAgICAweDM5NTZDMjVCLCAweDU5RjExMUYxLCAweDkyM0Y4MkE0LCAweEFCMUM1RUQ1LFxuICAgICAgICAgICAgMHhEODA3QUE5OCwgMHgxMjgzNUIwMSwgMHgyNDMxODVCRSwgMHg1NTBDN0RDMyxcbiAgICAgICAgICAgIDB4NzJCRTVENzQsIDB4ODBERUIxRkUsIDB4OUJEQzA2QTcsIDB4QzE5QkYxNzQsXG4gICAgICAgICAgICAweEU0OUI2OUMxLCAweEVGQkU0Nzg2LCAweDBGQzE5REM2LCAweDI0MENBMUNDLFxuICAgICAgICAgICAgMHgyREU5MkM2RiwgMHg0QTc0ODRBQSwgMHg1Q0IwQTlEQywgMHg3NkY5ODhEQSxcbiAgICAgICAgICAgIDB4OTgzRTUxNTIsIDB4QTgzMUM2NkQsIDB4QjAwMzI3QzgsIDB4QkY1OTdGQzcsXG4gICAgICAgICAgICAweEM2RTAwQkYzLCAweEQ1QTc5MTQ3LCAweDA2Q0E2MzUxLCAweDE0MjkyOTY3LFxuICAgICAgICAgICAgMHgyN0I3MEE4NSwgMHgyRTFCMjEzOCwgMHg0RDJDNkRGQywgMHg1MzM4MEQxMyxcbiAgICAgICAgICAgIDB4NjUwQTczNTQsIDB4NzY2QTBBQkIsIDB4ODFDMkM5MkUsIDB4OTI3MjJDODUsXG4gICAgICAgICAgICAweEEyQkZFOEExLCAweEE4MUE2NjRCLCAweEMyNEI4QjcwLCAweEM3NkM1MUEzLFxuICAgICAgICAgICAgMHhEMTkyRTgxOSwgMHhENjk5MDYyNCwgMHhGNDBFMzU4NSwgMHgxMDZBQTA3MCxcbiAgICAgICAgICAgIDB4MTlBNEMxMTYsIDB4MUUzNzZDMDgsIDB4Mjc0ODc3NEMsIDB4MzRCMEJDQjUsXG4gICAgICAgICAgICAweDM5MUMwQ0IzLCAweDRFRDhBQTRBLCAweDVCOUNDQTRGLCAweDY4MkU2RkYzLFxuICAgICAgICAgICAgMHg3NDhGODJFRSwgMHg3OEE1NjM2RiwgMHg4NEM4NzgxNCwgMHg4Q0M3MDIwOCxcbiAgICAgICAgICAgIDB4OTBCRUZGRkEsIDB4QTQ1MDZDRUIsIDB4QkVGOUEzRjcsIDB4QzY3MTc4RjJcbiAgICAgICAgXTtcblxuICAgICAgICBpZiAodmFyaWFudCA9PT0gXCJTSEEtMjI0XCIpIHtcbiAgICAgICAgICBIID0gW1xuICAgICAgICAgICAgICAweGMxMDU5ZWQ4LCAweDM2N2NkNTA3LCAweDMwNzBkZDE3LCAweGY3MGU1OTM5LFxuICAgICAgICAgICAgICAweGZmYzAwYjMxLCAweDY4NTgxNTExLCAweDY0Zjk4ZmE3LCAweGJlZmE0ZmE0XG4gICAgICAgICAgXTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBIID0gW1xuICAgICAgICAgICAgICAweDZBMDlFNjY3LCAweEJCNjdBRTg1LCAweDNDNkVGMzcyLCAweEE1NEZGNTNBLFxuICAgICAgICAgICAgICAweDUxMEU1MjdGLCAweDlCMDU2ODhDLCAweDFGODNEOUFCLCAweDVCRTBDRDE5XG4gICAgICAgICAgXTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmICh2YXJpYW50ID09PSBcIlNIQS0zODRcIiB8fCB2YXJpYW50ID09PSBcIlNIQS01MTJcIikge1xuICAgICAgICAvKiA2NC1iaXQgdmFyaWFudCAqL1xuICAgICAgICBudW1Sb3VuZHMgPSA4MDtcbiAgICAgICAgbGVuZ3RoUG9zaXRpb24gPSAoKChtZXNzYWdlTGVuICsgMTI4KSA+PiAxMCkgPDwgNSkgKyAzMTtcbiAgICAgICAgYmluYXJ5U3RyaW5nSW5jID0gMzI7XG4gICAgICAgIGJpbmFyeVN0cmluZ011bHQgPSAyO1xuICAgICAgICBJbnQgPSBJbnRfNjQ7XG4gICAgICAgIHNhZmVBZGRfMiA9IHNhZmVBZGRfNjRfMjtcbiAgICAgICAgc2FmZUFkZF80ID0gc2FmZUFkZF82NF80O1xuICAgICAgICBzYWZlQWRkXzUgPSBzYWZlQWRkXzY0XzU7XG4gICAgICAgIGdhbW1hMCA9IGdhbW1hMF82NDtcbiAgICAgICAgZ2FtbWExID0gZ2FtbWExXzY0O1xuICAgICAgICBzaWdtYTAgPSBzaWdtYTBfNjQ7XG4gICAgICAgIHNpZ21hMSA9IHNpZ21hMV82NDtcbiAgICAgICAgbWFqID0gbWFqXzY0O1xuICAgICAgICBjaCA9IGNoXzY0O1xuXG4gICAgICAgIEsgPSBbXG4gICAgICAgICAgICBuZXcgSW50KDB4NDI4YTJmOTgsIDB4ZDcyOGFlMjIpLCBuZXcgSW50KDB4NzEzNzQ0OTEsIDB4MjNlZjY1Y2QpLFxuICAgICAgICAgICAgbmV3IEludCgweGI1YzBmYmNmLCAweGVjNGQzYjJmKSwgbmV3IEludCgweGU5YjVkYmE1LCAweDgxODlkYmJjKSxcbiAgICAgICAgICAgIG5ldyBJbnQoMHgzOTU2YzI1YiwgMHhmMzQ4YjUzOCksIG5ldyBJbnQoMHg1OWYxMTFmMSwgMHhiNjA1ZDAxOSksXG4gICAgICAgICAgICBuZXcgSW50KDB4OTIzZjgyYTQsIDB4YWYxOTRmOWIpLCBuZXcgSW50KDB4YWIxYzVlZDUsIDB4ZGE2ZDgxMTgpLFxuICAgICAgICAgICAgbmV3IEludCgweGQ4MDdhYTk4LCAweGEzMDMwMjQyKSwgbmV3IEludCgweDEyODM1YjAxLCAweDQ1NzA2ZmJlKSxcbiAgICAgICAgICAgIG5ldyBJbnQoMHgyNDMxODViZSwgMHg0ZWU0YjI4YyksIG5ldyBJbnQoMHg1NTBjN2RjMywgMHhkNWZmYjRlMiksXG4gICAgICAgICAgICBuZXcgSW50KDB4NzJiZTVkNzQsIDB4ZjI3Yjg5NmYpLCBuZXcgSW50KDB4ODBkZWIxZmUsIDB4M2IxNjk2YjEpLFxuICAgICAgICAgICAgbmV3IEludCgweDliZGMwNmE3LCAweDI1YzcxMjM1KSwgbmV3IEludCgweGMxOWJmMTc0LCAweGNmNjkyNjk0KSxcbiAgICAgICAgICAgIG5ldyBJbnQoMHhlNDliNjljMSwgMHg5ZWYxNGFkMiksIG5ldyBJbnQoMHhlZmJlNDc4NiwgMHgzODRmMjVlMyksXG4gICAgICAgICAgICBuZXcgSW50KDB4MGZjMTlkYzYsIDB4OGI4Y2Q1YjUpLCBuZXcgSW50KDB4MjQwY2ExY2MsIDB4NzdhYzljNjUpLFxuICAgICAgICAgICAgbmV3IEludCgweDJkZTkyYzZmLCAweDU5MmIwMjc1KSwgbmV3IEludCgweDRhNzQ4NGFhLCAweDZlYTZlNDgzKSxcbiAgICAgICAgICAgIG5ldyBJbnQoMHg1Y2IwYTlkYywgMHhiZDQxZmJkNCksIG5ldyBJbnQoMHg3NmY5ODhkYSwgMHg4MzExNTNiNSksXG4gICAgICAgICAgICBuZXcgSW50KDB4OTgzZTUxNTIsIDB4ZWU2NmRmYWIpLCBuZXcgSW50KDB4YTgzMWM2NmQsIDB4MmRiNDMyMTApLFxuICAgICAgICAgICAgbmV3IEludCgweGIwMDMyN2M4LCAweDk4ZmIyMTNmKSwgbmV3IEludCgweGJmNTk3ZmM3LCAweGJlZWYwZWU0KSxcbiAgICAgICAgICAgIG5ldyBJbnQoMHhjNmUwMGJmMywgMHgzZGE4OGZjMiksIG5ldyBJbnQoMHhkNWE3OTE0NywgMHg5MzBhYTcyNSksXG4gICAgICAgICAgICBuZXcgSW50KDB4MDZjYTYzNTEsIDB4ZTAwMzgyNmYpLCBuZXcgSW50KDB4MTQyOTI5NjcsIDB4MGEwZTZlNzApLFxuICAgICAgICAgICAgbmV3IEludCgweDI3YjcwYTg1LCAweDQ2ZDIyZmZjKSwgbmV3IEludCgweDJlMWIyMTM4LCAweDVjMjZjOTI2KSxcbiAgICAgICAgICAgIG5ldyBJbnQoMHg0ZDJjNmRmYywgMHg1YWM0MmFlZCksIG5ldyBJbnQoMHg1MzM4MGQxMywgMHg5ZDk1YjNkZiksXG4gICAgICAgICAgICBuZXcgSW50KDB4NjUwYTczNTQsIDB4OGJhZjYzZGUpLCBuZXcgSW50KDB4NzY2YTBhYmIsIDB4M2M3N2IyYTgpLFxuICAgICAgICAgICAgbmV3IEludCgweDgxYzJjOTJlLCAweDQ3ZWRhZWU2KSwgbmV3IEludCgweDkyNzIyYzg1LCAweDE0ODIzNTNiKSxcbiAgICAgICAgICAgIG5ldyBJbnQoMHhhMmJmZThhMSwgMHg0Y2YxMDM2NCksIG5ldyBJbnQoMHhhODFhNjY0YiwgMHhiYzQyMzAwMSksXG4gICAgICAgICAgICBuZXcgSW50KDB4YzI0YjhiNzAsIDB4ZDBmODk3OTEpLCBuZXcgSW50KDB4Yzc2YzUxYTMsIDB4MDY1NGJlMzApLFxuICAgICAgICAgICAgbmV3IEludCgweGQxOTJlODE5LCAweGQ2ZWY1MjE4KSwgbmV3IEludCgweGQ2OTkwNjI0LCAweDU1NjVhOTEwKSxcbiAgICAgICAgICAgIG5ldyBJbnQoMHhmNDBlMzU4NSwgMHg1NzcxMjAyYSksIG5ldyBJbnQoMHgxMDZhYTA3MCwgMHgzMmJiZDFiOCksXG4gICAgICAgICAgICBuZXcgSW50KDB4MTlhNGMxMTYsIDB4YjhkMmQwYzgpLCBuZXcgSW50KDB4MWUzNzZjMDgsIDB4NTE0MWFiNTMpLFxuICAgICAgICAgICAgbmV3IEludCgweDI3NDg3NzRjLCAweGRmOGVlYjk5KSwgbmV3IEludCgweDM0YjBiY2I1LCAweGUxOWI0OGE4KSxcbiAgICAgICAgICAgIG5ldyBJbnQoMHgzOTFjMGNiMywgMHhjNWM5NWE2MyksIG5ldyBJbnQoMHg0ZWQ4YWE0YSwgMHhlMzQxOGFjYiksXG4gICAgICAgICAgICBuZXcgSW50KDB4NWI5Y2NhNGYsIDB4Nzc2M2UzNzMpLCBuZXcgSW50KDB4NjgyZTZmZjMsIDB4ZDZiMmI4YTMpLFxuICAgICAgICAgICAgbmV3IEludCgweDc0OGY4MmVlLCAweDVkZWZiMmZjKSwgbmV3IEludCgweDc4YTU2MzZmLCAweDQzMTcyZjYwKSxcbiAgICAgICAgICAgIG5ldyBJbnQoMHg4NGM4NzgxNCwgMHhhMWYwYWI3MiksIG5ldyBJbnQoMHg4Y2M3MDIwOCwgMHgxYTY0MzllYyksXG4gICAgICAgICAgICBuZXcgSW50KDB4OTBiZWZmZmEsIDB4MjM2MzFlMjgpLCBuZXcgSW50KDB4YTQ1MDZjZWIsIDB4ZGU4MmJkZTkpLFxuICAgICAgICAgICAgbmV3IEludCgweGJlZjlhM2Y3LCAweGIyYzY3OTE1KSwgbmV3IEludCgweGM2NzE3OGYyLCAweGUzNzI1MzJiKSxcbiAgICAgICAgICAgIG5ldyBJbnQoMHhjYTI3M2VjZSwgMHhlYTI2NjE5YyksIG5ldyBJbnQoMHhkMTg2YjhjNywgMHgyMWMwYzIwNyksXG4gICAgICAgICAgICBuZXcgSW50KDB4ZWFkYTdkZDYsIDB4Y2RlMGViMWUpLCBuZXcgSW50KDB4ZjU3ZDRmN2YsIDB4ZWU2ZWQxNzgpLFxuICAgICAgICAgICAgbmV3IEludCgweDA2ZjA2N2FhLCAweDcyMTc2ZmJhKSwgbmV3IEludCgweDBhNjM3ZGM1LCAweGEyYzg5OGE2KSxcbiAgICAgICAgICAgIG5ldyBJbnQoMHgxMTNmOTgwNCwgMHhiZWY5MGRhZSksIG5ldyBJbnQoMHgxYjcxMGIzNSwgMHgxMzFjNDcxYiksXG4gICAgICAgICAgICBuZXcgSW50KDB4MjhkYjc3ZjUsIDB4MjMwNDdkODQpLCBuZXcgSW50KDB4MzJjYWFiN2IsIDB4NDBjNzI0OTMpLFxuICAgICAgICAgICAgbmV3IEludCgweDNjOWViZTBhLCAweDE1YzliZWJjKSwgbmV3IEludCgweDQzMWQ2N2M0LCAweDljMTAwZDRjKSxcbiAgICAgICAgICAgIG5ldyBJbnQoMHg0Y2M1ZDRiZSwgMHhjYjNlNDJiNiksIG5ldyBJbnQoMHg1OTdmMjk5YywgMHhmYzY1N2UyYSksXG4gICAgICAgICAgICBuZXcgSW50KDB4NWZjYjZmYWIsIDB4M2FkNmZhZWMpLCBuZXcgSW50KDB4NmM0NDE5OGMsIDB4NGE0NzU4MTcpXG4gICAgICAgIF07XG5cbiAgICAgICAgaWYgKHZhcmlhbnQgPT09IFwiU0hBLTM4NFwiKSB7XG4gICAgICAgICAgSCA9IFtcbiAgICAgICAgICAgICAgbmV3IEludCgweGNiYmI5ZDVkLCAweGMxMDU5ZWQ4KSwgbmV3IEludCgweDA2MjlhMjkyYSwgMHgzNjdjZDUwNyksXG4gICAgICAgICAgICAgIG5ldyBJbnQoMHg5MTU5MDE1YSwgMHgzMDcwZGQxNyksIG5ldyBJbnQoMHgwMTUyZmVjZDgsIDB4ZjcwZTU5MzkpLFxuICAgICAgICAgICAgICBuZXcgSW50KDB4NjczMzI2NjcsIDB4ZmZjMDBiMzEpLCBuZXcgSW50KDB4OThlYjQ0YTg3LCAweDY4NTgxNTExKSxcbiAgICAgICAgICAgICAgbmV3IEludCgweGRiMGMyZTBkLCAweDY0Zjk4ZmE3KSwgbmV3IEludCgweDA0N2I1NDgxZCwgMHhiZWZhNGZhNClcbiAgICAgICAgICBdO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIEggPSBbXG4gICAgICAgICAgICAgIG5ldyBJbnQoMHg2YTA5ZTY2NywgMHhmM2JjYzkwOCksIG5ldyBJbnQoMHhiYjY3YWU4NSwgMHg4NGNhYTczYiksXG4gICAgICAgICAgICAgIG5ldyBJbnQoMHgzYzZlZjM3MiwgMHhmZTk0ZjgyYiksIG5ldyBJbnQoMHhhNTRmZjUzYSwgMHg1ZjFkMzZmMSksXG4gICAgICAgICAgICAgIG5ldyBJbnQoMHg1MTBlNTI3ZiwgMHhhZGU2ODJkMSksIG5ldyBJbnQoMHg5YjA1Njg4YywgMHgyYjNlNmMxZiksXG4gICAgICAgICAgICAgIG5ldyBJbnQoMHgxZjgzZDlhYiwgMHhmYjQxYmQ2YiksIG5ldyBJbnQoMHg1YmUwY2QxOSwgMHgxMzdlMjE3OSlcbiAgICAgICAgICBdO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIC8qIEFwcGVuZCAnMScgYXQgdGhlIGVuZCBvZiB0aGUgYmluYXJ5IHN0cmluZyAqL1xuICAgICAgbWVzc2FnZVttZXNzYWdlTGVuID4+IDVdIHw9IDB4ODAgPDwgKDI0IC0gbWVzc2FnZUxlbiAlIDMyKTtcbiAgICAgIC8qIEFwcGVuZCBsZW5ndGggb2YgYmluYXJ5IHN0cmluZyBpbiB0aGUgcG9zaXRpb24gc3VjaCB0aGF0IHRoZSBuZXdcbiAgICAgICAqIGxlbmd0aCBpcyBjb3JyZWN0ICovXG4gICAgICBtZXNzYWdlW2xlbmd0aFBvc2l0aW9uXSA9IG1lc3NhZ2VMZW47XG5cbiAgICAgIGFwcGVuZGVkTWVzc2FnZUxlbmd0aCA9IG1lc3NhZ2UubGVuZ3RoO1xuXG4gICAgICBmb3IgKGkgPSAwOyBpIDwgYXBwZW5kZWRNZXNzYWdlTGVuZ3RoOyBpICs9IGJpbmFyeVN0cmluZ0luYykge1xuICAgICAgICBhID0gSFswXTtcbiAgICAgICAgYiA9IEhbMV07XG4gICAgICAgIGMgPSBIWzJdO1xuICAgICAgICBkID0gSFszXTtcbiAgICAgICAgZSA9IEhbNF07XG4gICAgICAgIGYgPSBIWzVdO1xuICAgICAgICBnID0gSFs2XTtcbiAgICAgICAgaCA9IEhbN107XG5cbiAgICAgICAgZm9yICh0ID0gMDsgdCA8IG51bVJvdW5kczsgdCArPSAxKSB7XG4gICAgICAgICAgaWYgKHQgPCAxNikge1xuICAgICAgICAgICAgLyogQml0IG9mIGEgaGFjayAtIGZvciAzMi1iaXQsIHRoZSBzZWNvbmQgdGVybSBpcyBpZ25vcmVkICovXG4gICAgICAgICAgICBXW3RdID0gbmV3IEludChtZXNzYWdlW3QgKiBiaW5hcnlTdHJpbmdNdWx0ICsgaV0sXG4gICAgICAgICAgICAgIG1lc3NhZ2VbdCAqIGJpbmFyeVN0cmluZ011bHQgKyBpICsgMV0pO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBXW3RdID0gc2FmZUFkZF80KFxuICAgICAgICAgICAgICBnYW1tYTEoV1t0IC0gMl0pLCBXW3QgLSA3XSxcbiAgICAgICAgICAgICAgZ2FtbWEwKFdbdCAtIDE1XSksIFdbdCAtIDE2XSk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgVDEgPSBzYWZlQWRkXzUoaCwgc2lnbWExKGUpLCBjaChlLCBmLCBnKSwgS1t0XSwgV1t0XSk7XG4gICAgICAgICAgVDIgPSBzYWZlQWRkXzIoc2lnbWEwKGEpLCBtYWooYSwgYiwgYykpO1xuICAgICAgICAgIGggPSBnO1xuICAgICAgICAgIGcgPSBmO1xuICAgICAgICAgIGYgPSBlO1xuICAgICAgICAgIGUgPSBzYWZlQWRkXzIoZCwgVDEpO1xuICAgICAgICAgIGQgPSBjO1xuICAgICAgICAgIGMgPSBiO1xuICAgICAgICAgIGIgPSBhO1xuICAgICAgICAgIGEgPSBzYWZlQWRkXzIoVDEsIFQyKTtcbiAgICAgICAgfVxuXG4gICAgICAgIEhbMF0gPSBzYWZlQWRkXzIoYSwgSFswXSk7XG4gICAgICAgIEhbMV0gPSBzYWZlQWRkXzIoYiwgSFsxXSk7XG4gICAgICAgIEhbMl0gPSBzYWZlQWRkXzIoYywgSFsyXSk7XG4gICAgICAgIEhbM10gPSBzYWZlQWRkXzIoZCwgSFszXSk7XG4gICAgICAgIEhbNF0gPSBzYWZlQWRkXzIoZSwgSFs0XSk7XG4gICAgICAgIEhbNV0gPSBzYWZlQWRkXzIoZiwgSFs1XSk7XG4gICAgICAgIEhbNl0gPSBzYWZlQWRkXzIoZywgSFs2XSk7XG4gICAgICAgIEhbN10gPSBzYWZlQWRkXzIoaCwgSFs3XSk7XG4gICAgICB9XG5cbiAgICAgIHN3aXRjaCAodmFyaWFudCkge1xuICAgICAgICBjYXNlIFwiU0hBLTIyNFwiOlxuICAgICAgICAgIHJldHVybiBbXG4gICAgICAgICAgICBIWzBdLCBIWzFdLCBIWzJdLCBIWzNdLFxuICAgICAgICAgICAgSFs0XSwgSFs1XSwgSFs2XV07XG4gICAgICAgIGNhc2UgXCJTSEEtMjU2XCI6XG4gICAgICAgICAgcmV0dXJuIEg7XG4gICAgICAgIGNhc2UgXCJTSEEtMzg0XCI6XG4gICAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICAgIEhbMF0uaGlnaE9yZGVyLCBIWzBdLmxvd09yZGVyLFxuICAgICAgICAgICAgSFsxXS5oaWdoT3JkZXIsIEhbMV0ubG93T3JkZXIsXG4gICAgICAgICAgICBIWzJdLmhpZ2hPcmRlciwgSFsyXS5sb3dPcmRlcixcbiAgICAgICAgICAgIEhbM10uaGlnaE9yZGVyLCBIWzNdLmxvd09yZGVyLFxuICAgICAgICAgICAgSFs0XS5oaWdoT3JkZXIsIEhbNF0ubG93T3JkZXIsXG4gICAgICAgICAgICBIWzVdLmhpZ2hPcmRlciwgSFs1XS5sb3dPcmRlcl07XG4gICAgICAgIGNhc2UgXCJTSEEtNTEyXCI6XG4gICAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICAgIEhbMF0uaGlnaE9yZGVyLCBIWzBdLmxvd09yZGVyLFxuICAgICAgICAgICAgSFsxXS5oaWdoT3JkZXIsIEhbMV0ubG93T3JkZXIsXG4gICAgICAgICAgICBIWzJdLmhpZ2hPcmRlciwgSFsyXS5sb3dPcmRlcixcbiAgICAgICAgICAgIEhbM10uaGlnaE9yZGVyLCBIWzNdLmxvd09yZGVyLFxuICAgICAgICAgICAgSFs0XS5oaWdoT3JkZXIsIEhbNF0ubG93T3JkZXIsXG4gICAgICAgICAgICBIWzVdLmhpZ2hPcmRlciwgSFs1XS5sb3dPcmRlcixcbiAgICAgICAgICAgIEhbNl0uaGlnaE9yZGVyLCBIWzZdLmxvd09yZGVyLFxuICAgICAgICAgICAgSFs3XS5oaWdoT3JkZXIsIEhbN10ubG93T3JkZXJdO1xuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgIC8qIFRoaXMgc2hvdWxkIG5ldmVyIGJlIHJlYWNoZWQgKi9cbiAgICAgICAgICByZXR1cm4gW107XG4gICAgICB9XG4gICAgfSxcblxuICAgIC8qXG4gICAgICoganNTSEEgaXMgdGhlIHdvcmtob3JzZSBvZiB0aGUgbGlicmFyeS4gIEluc3RhbnRpYXRlIGl0IHdpdGggdGhlIHN0cmluZyB0b1xuICAgICAqIGJlIGhhc2hlZCBhcyB0aGUgcGFyYW1ldGVyXG4gICAgICpcbiAgICAgKiBAY29uc3RydWN0b3JcbiAgICAgKiBAcGFyYW0ge1N0cmluZ30gc3JjU3RyaW5nIFRoZSBzdHJpbmcgdG8gYmUgaGFzaGVkXG4gICAgICogQHBhcmFtIHtTdHJpbmd9IGlucHV0Rm9ybWF0IFRoZSBmb3JtYXQgb2Ygc3JjU3RyaW5nLCBBU0NJSSBvciBIRVhcbiAgICAgKi9cbiAgICBqc1NIQSA9IGZ1bmN0aW9uKHNyY1N0cmluZywgaW5wdXRGb3JtYXQpIHtcblxuICAgICAgdGhpcy5zaGExID0gbnVsbDtcbiAgICAgIHRoaXMuc2hhMjI0ID0gbnVsbDtcbiAgICAgIHRoaXMuc2hhMjU2ID0gbnVsbDtcbiAgICAgIHRoaXMuc2hhMzg0ID0gbnVsbDtcbiAgICAgIHRoaXMuc2hhNTEyID0gbnVsbDtcblxuICAgICAgdGhpcy5zdHJCaW5MZW4gPSBudWxsO1xuICAgICAgdGhpcy5zdHJUb0hhc2ggPSBudWxsO1xuXG4gICAgICAvKiBDb252ZXJ0IHRoZSBpbnB1dCBzdHJpbmcgaW50byB0aGUgY29ycmVjdCB0eXBlICovXG4gICAgICBpZiAoXCJIRVhcIiA9PT0gaW5wdXRGb3JtYXQpIHtcbiAgICAgICAgaWYgKDAgIT09IChzcmNTdHJpbmcubGVuZ3RoICUgMikpIHtcbiAgICAgICAgICByZXR1cm4gXCJURVhUIE1VU1QgQkUgSU4gQllURSBJTkNSRU1FTlRTXCI7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5zdHJCaW5MZW4gPSBzcmNTdHJpbmcubGVuZ3RoICogNDtcbiAgICAgICAgdGhpcy5zdHJUb0hhc2ggPSBoZXgyYmluYihzcmNTdHJpbmcpO1xuICAgICAgfSBlbHNlIGlmICgoXCJBU0NJSVwiID09PSBpbnB1dEZvcm1hdCkgfHxcbiAgICAgICAgKCd1bmRlZmluZWQnID09PSB0eXBlb2YoaW5wdXRGb3JtYXQpKSkge1xuICAgICAgICB0aGlzLnN0ckJpbkxlbiA9IHNyY1N0cmluZy5sZW5ndGggKiBjaGFyU2l6ZTtcbiAgICAgICAgdGhpcy5zdHJUb0hhc2ggPSBzdHIyYmluYihzcmNTdHJpbmcpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuIFwiVU5LTk9XTiBURVhUIElOUFVUIFRZUEVcIjtcbiAgICAgIH1cbiAgICB9O1xuXG4gIGpzU0hBLnByb3RvdHlwZSA9IHtcbiAgICAvKlxuICAgICAqIFJldHVybnMgdGhlIGRlc2lyZWQgU0hBIGhhc2ggb2YgdGhlIHN0cmluZyBzcGVjaWZpZWQgYXQgaW5zdGFudGlhdGlvblxuICAgICAqIHVzaW5nIHRoZSBzcGVjaWZpZWQgcGFyYW1ldGVyc1xuICAgICAqXG4gICAgICogQHBhcmFtIHtTdHJpbmd9IHZhcmlhbnQgVGhlIGRlc2lyZWQgU0hBIHZhcmlhbnQgKFNIQS0xLCBTSEEtMjI0LFxuICAgICAqXHQgU0hBLTI1NiwgU0hBLTM4NCwgb3IgU0hBLTUxMilcbiAgICAgKiBAcGFyYW0ge1N0cmluZ30gZm9ybWF0IFRoZSBkZXNpcmVkIG91dHB1dCBmb3JtYXR0aW5nIChCNjQgb3IgSEVYKVxuICAgICAqIEByZXR1cm4gVGhlIHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiB0aGUgaGFzaCBpbiB0aGUgZm9ybWF0IHNwZWNpZmllZFxuICAgICAqL1xuICAgIGdldEhhc2g6IGZ1bmN0aW9uKHZhcmlhbnQsIGZvcm1hdCkge1xuICAgICAgdmFyIGZvcm1hdEZ1bmMgPSBudWxsLFxuICAgICAgICBtZXNzYWdlID0gdGhpcy5zdHJUb0hhc2guc2xpY2UoKTtcblxuICAgICAgc3dpdGNoIChmb3JtYXQpIHtcbiAgICAgICAgY2FzZSBcIkhFWFwiOlxuICAgICAgICAgIGZvcm1hdEZ1bmMgPSBiaW5iMmhleDtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSBcIkI2NFwiOlxuICAgICAgICAgIGZvcm1hdEZ1bmMgPSBiaW5iMmI2NDtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSBcIkFTQ0lJXCI6XG4gICAgICAgICAgZm9ybWF0RnVuYyA9IGJpbmIyc3RyO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgIHJldHVybiBcIkZPUk1BVCBOT1QgUkVDT0dOSVpFRFwiO1xuICAgICAgfVxuXG4gICAgICBzd2l0Y2ggKHZhcmlhbnQpIHtcbiAgICAgICAgY2FzZSBcIlNIQS0xXCI6XG4gICAgICAgICAgaWYgKG51bGwgPT09IHRoaXMuc2hhMSkge1xuICAgICAgICAgICAgdGhpcy5zaGExID0gY29yZVNIQTEobWVzc2FnZSwgdGhpcy5zdHJCaW5MZW4pO1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4gZm9ybWF0RnVuYyh0aGlzLnNoYTEpO1xuICAgICAgICBjYXNlIFwiU0hBLTIyNFwiOlxuICAgICAgICAgIGlmIChudWxsID09PSB0aGlzLnNoYTIyNCkge1xuICAgICAgICAgICAgdGhpcy5zaGEyMjQgPSBjb3JlU0hBMihtZXNzYWdlLCB0aGlzLnN0ckJpbkxlbiwgdmFyaWFudCk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybiBmb3JtYXRGdW5jKHRoaXMuc2hhMjI0KTtcbiAgICAgICAgY2FzZSBcIlNIQS0yNTZcIjpcbiAgICAgICAgICBpZiAobnVsbCA9PT0gdGhpcy5zaGEyNTYpIHtcbiAgICAgICAgICAgIHRoaXMuc2hhMjU2ID0gY29yZVNIQTIobWVzc2FnZSwgdGhpcy5zdHJCaW5MZW4sIHZhcmlhbnQpO1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4gZm9ybWF0RnVuYyh0aGlzLnNoYTI1Nik7XG4gICAgICAgIGNhc2UgXCJTSEEtMzg0XCI6XG4gICAgICAgICAgaWYgKG51bGwgPT09IHRoaXMuc2hhMzg0KSB7XG4gICAgICAgICAgICB0aGlzLnNoYTM4NCA9IGNvcmVTSEEyKG1lc3NhZ2UsIHRoaXMuc3RyQmluTGVuLCB2YXJpYW50KTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIGZvcm1hdEZ1bmModGhpcy5zaGEzODQpO1xuICAgICAgICBjYXNlIFwiU0hBLTUxMlwiOlxuICAgICAgICAgIGlmIChudWxsID09PSB0aGlzLnNoYTUxMikge1xuICAgICAgICAgICAgdGhpcy5zaGE1MTIgPSBjb3JlU0hBMihtZXNzYWdlLCB0aGlzLnN0ckJpbkxlbiwgdmFyaWFudCk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybiBmb3JtYXRGdW5jKHRoaXMuc2hhNTEyKTtcbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICByZXR1cm4gXCJIQVNIIE5PVCBSRUNPR05JWkVEXCI7XG4gICAgICB9XG4gICAgfSxcblxuICAgIC8qXG4gICAgICogUmV0dXJucyB0aGUgZGVzaXJlZCBITUFDIG9mIHRoZSBzdHJpbmcgc3BlY2lmaWVkIGF0IGluc3RhbnRpYXRpb25cbiAgICAgKiB1c2luZyB0aGUga2V5IGFuZCB2YXJpYW50IHBhcmFtLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtTdHJpbmd9IGtleSBUaGUga2V5IHVzZWQgdG8gY2FsY3VsYXRlIHRoZSBITUFDXG4gICAgICogQHBhcmFtIHtTdHJpbmd9IGlucHV0Rm9ybWF0IFRoZSBmb3JtYXQgb2Yga2V5LCBBU0NJSSBvciBIRVhcbiAgICAgKiBAcGFyYW0ge1N0cmluZ30gdmFyaWFudCBUaGUgZGVzaXJlZCBTSEEgdmFyaWFudCAoU0hBLTEsIFNIQS0yMjQsXG4gICAgICpcdCBTSEEtMjU2LCBTSEEtMzg0LCBvciBTSEEtNTEyKVxuICAgICAqIEBwYXJhbSB7U3RyaW5nfSBvdXRwdXRGb3JtYXQgVGhlIGRlc2lyZWQgb3V0cHV0IGZvcm1hdHRpbmdcbiAgICAgKlx0IChCNjQgb3IgSEVYKVxuICAgICAqIEByZXR1cm4gVGhlIHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiB0aGUgaGFzaCBpbiB0aGUgZm9ybWF0IHNwZWNpZmllZFxuICAgICAqL1xuICAgIGdldEhNQUM6IGZ1bmN0aW9uKGtleSwgaW5wdXRGb3JtYXQsIHZhcmlhbnQsIG91dHB1dEZvcm1hdCkge1xuICAgICAgdmFyIGZvcm1hdEZ1bmMsIGtleVRvVXNlLCBibG9ja0J5dGVTaXplLCBibG9ja0JpdFNpemUsIGksXG4gICAgICAgIHJldFZhbCwgbGFzdEFycmF5SW5kZXgsIGtleUJpbkxlbiwgaGFzaEJpdFNpemUsXG4gICAgICAgIGtleVdpdGhJUGFkID0gW10sXG4gICAgICAgIGtleVdpdGhPUGFkID0gW107XG5cbiAgICAgIC8qIFZhbGlkYXRlIHRoZSBvdXRwdXQgZm9ybWF0IHNlbGVjdGlvbiAqL1xuICAgICAgc3dpdGNoIChvdXRwdXRGb3JtYXQpIHtcbiAgICAgICAgY2FzZSBcIkhFWFwiOlxuICAgICAgICAgIGZvcm1hdEZ1bmMgPSBiaW5iMmhleDtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSBcIkI2NFwiOlxuICAgICAgICAgIGZvcm1hdEZ1bmMgPSBiaW5iMmI2NDtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSBcIkFTQ0lJXCI6XG4gICAgICAgICAgZm9ybWF0RnVuYyA9IGJpbmIyc3RyO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgIHJldHVybiBcIkZPUk1BVCBOT1QgUkVDT0dOSVpFRFwiO1xuICAgICAgfVxuXG4gICAgICAvKiBWYWxpZGF0ZSB0aGUgaGFzaCB2YXJpYW50IHNlbGVjdGlvbiBhbmQgc2V0IG5lZWRlZCB2YXJpYWJsZXMgKi9cbiAgICAgIHN3aXRjaCAodmFyaWFudCkge1xuICAgICAgICBjYXNlIFwiU0hBLTFcIjpcbiAgICAgICAgICBibG9ja0J5dGVTaXplID0gNjQ7XG4gICAgICAgICAgaGFzaEJpdFNpemUgPSAxNjA7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgXCJTSEEtMjI0XCI6XG4gICAgICAgICAgYmxvY2tCeXRlU2l6ZSA9IDY0O1xuICAgICAgICAgIGhhc2hCaXRTaXplID0gMjI0O1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlIFwiU0hBLTI1NlwiOlxuICAgICAgICAgIGJsb2NrQnl0ZVNpemUgPSA2NDtcbiAgICAgICAgICBoYXNoQml0U2l6ZSA9IDI1NjtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSBcIlNIQS0zODRcIjpcbiAgICAgICAgICBibG9ja0J5dGVTaXplID0gMTI4O1xuICAgICAgICAgIGhhc2hCaXRTaXplID0gMzg0O1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlIFwiU0hBLTUxMlwiOlxuICAgICAgICAgIGJsb2NrQnl0ZVNpemUgPSAxMjg7XG4gICAgICAgICAgaGFzaEJpdFNpemUgPSA1MTI7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgcmV0dXJuIFwiSEFTSCBOT1QgUkVDT0dOSVpFRFwiO1xuICAgICAgfVxuXG4gICAgICAvKiBWYWxpZGF0ZSBpbnB1dCBmb3JtYXQgc2VsZWN0aW9uICovXG4gICAgICBpZiAoXCJIRVhcIiA9PT0gaW5wdXRGb3JtYXQpIHtcbiAgICAgICAgLyogTmliYmxlcyBtdXN0IGNvbWUgaW4gcGFpcnMgKi9cbiAgICAgICAgaWYgKDAgIT09IChrZXkubGVuZ3RoICUgMikpIHtcbiAgICAgICAgICByZXR1cm4gXCJLRVkgTVVTVCBCRSBJTiBCWVRFIElOQ1JFTUVOVFNcIjtcbiAgICAgICAgfVxuICAgICAgICBrZXlUb1VzZSA9IGhleDJiaW5iKGtleSk7XG4gICAgICAgIGtleUJpbkxlbiA9IGtleS5sZW5ndGggKiA0O1xuICAgICAgfSBlbHNlIGlmIChcIkFTQ0lJXCIgPT09IGlucHV0Rm9ybWF0KSB7XG4gICAgICAgIGtleVRvVXNlID0gc3RyMmJpbmIoa2V5KTtcbiAgICAgICAga2V5QmluTGVuID0ga2V5Lmxlbmd0aCAqIGNoYXJTaXplO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuIFwiVU5LTk9XTiBLRVkgSU5QVVQgVFlQRVwiO1xuICAgICAgfVxuXG4gICAgICAvKiBUaGVzZSBhcmUgdXNlZCBtdWx0aXBsZSB0aW1lcywgY2FsY3VsYXRlIGFuZCBzdG9yZSB0aGVtICovXG4gICAgICBibG9ja0JpdFNpemUgPSBibG9ja0J5dGVTaXplICogODtcbiAgICAgIGxhc3RBcnJheUluZGV4ID0gKGJsb2NrQnl0ZVNpemUgLyA0KSAtIDE7XG5cbiAgICAgIC8qIEZpZ3VyZSBvdXQgd2hhdCB0byBkbyB3aXRoIHRoZSBrZXkgYmFzZWQgb24gaXRzIHNpemUgcmVsYXRpdmUgdG9cbiAgICAgICAqIHRoZSBoYXNoJ3MgYmxvY2sgc2l6ZSAqL1xuICAgICAgaWYgKGJsb2NrQnl0ZVNpemUgPCAoa2V5QmluTGVuIC8gOCkpIHtcbiAgICAgICAgaWYgKFwiU0hBLTFcIiA9PT0gdmFyaWFudCkge1xuICAgICAgICAgIGtleVRvVXNlID0gY29yZVNIQTEoa2V5VG9Vc2UsIGtleUJpbkxlbik7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAga2V5VG9Vc2UgPSBjb3JlU0hBMihrZXlUb1VzZSwga2V5QmluTGVuLCB2YXJpYW50KTtcbiAgICAgICAgfVxuICAgICAgICAvKiBGb3IgYWxsIHZhcmlhbnRzLCB0aGUgYmxvY2sgc2l6ZSBpcyBiaWdnZXIgdGhhbiB0aGUgb3V0cHV0XG4gICAgICAgICAqIHNpemUgc28gdGhlcmUgd2lsbCBuZXZlciBiZSBhIHVzZWZ1bCBieXRlIGF0IHRoZSBlbmQgb2YgdGhlXG4gICAgICAgICAqIHN0cmluZyAqL1xuICAgICAgICBrZXlUb1VzZVtsYXN0QXJyYXlJbmRleF0gJj0gMHhGRkZGRkYwMDtcbiAgICAgIH0gZWxzZSBpZiAoYmxvY2tCeXRlU2l6ZSA+IChrZXlCaW5MZW4gLyA4KSkge1xuICAgICAgICAvKiBJZiB0aGUgYmxvY2tCeXRlU2l6ZSBpcyBncmVhdGVyIHRoYW4gdGhlIGtleSBsZW5ndGgsIHRoZXJlXG4gICAgICAgICAqIHdpbGwgYWx3YXlzIGJlIGF0IExFQVNUIG9uZSBcInVzZWxlc3NcIiBieXRlIGF0IHRoZSBlbmQgb2YgdGhlXG4gICAgICAgICAqIHN0cmluZyAqL1xuICAgICAgICBrZXlUb1VzZVtsYXN0QXJyYXlJbmRleF0gJj0gMHhGRkZGRkYwMDtcbiAgICAgIH1cblxuICAgICAgLyogQ3JlYXRlIGlwYWQgYW5kIG9wYWQgKi9cbiAgICAgIGZvciAoaSA9IDA7IGkgPD0gbGFzdEFycmF5SW5kZXg7IGkgKz0gMSkge1xuICAgICAgICBrZXlXaXRoSVBhZFtpXSA9IGtleVRvVXNlW2ldIF4gMHgzNjM2MzYzNjtcbiAgICAgICAga2V5V2l0aE9QYWRbaV0gPSBrZXlUb1VzZVtpXSBeIDB4NUM1QzVDNUM7XG4gICAgICB9XG5cbiAgICAgIC8qIENhbGN1bGF0ZSB0aGUgSE1BQyAqL1xuICAgICAgaWYgKFwiU0hBLTFcIiA9PT0gdmFyaWFudCkge1xuICAgICAgICByZXRWYWwgPSBjb3JlU0hBMShcbiAgICAgICAgICBrZXlXaXRoSVBhZC5jb25jYXQodGhpcy5zdHJUb0hhc2gpLFxuICAgICAgICAgIGJsb2NrQml0U2l6ZSArIHRoaXMuc3RyQmluTGVuKTtcbiAgICAgICAgcmV0VmFsID0gY29yZVNIQTEoXG4gICAgICAgICAga2V5V2l0aE9QYWQuY29uY2F0KHJldFZhbCksXG4gICAgICAgICAgYmxvY2tCaXRTaXplICsgaGFzaEJpdFNpemUpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmV0VmFsID0gY29yZVNIQTIoXG4gICAgICAgICAga2V5V2l0aElQYWQuY29uY2F0KHRoaXMuc3RyVG9IYXNoKSxcbiAgICAgICAgICBibG9ja0JpdFNpemUgKyB0aGlzLnN0ckJpbkxlbiwgdmFyaWFudCk7XG4gICAgICAgIHJldFZhbCA9IGNvcmVTSEEyKFxuICAgICAgICAgIGtleVdpdGhPUGFkLmNvbmNhdChyZXRWYWwpLFxuICAgICAgICAgIGJsb2NrQml0U2l6ZSArIGhhc2hCaXRTaXplLCB2YXJpYW50KTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIChmb3JtYXRGdW5jKHJldFZhbCkpO1xuICAgIH1cbiAgfTtcblxuICByZXR1cm4ganNTSEE7XG59KCkpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgc2hhMTogZnVuY3Rpb24oc3RyKSB7XG4gICAgdmFyIHNoYU9iaiA9IG5ldyBqc1NIQShzdHIsIFwiQVNDSUlcIik7XG4gICAgcmV0dXJuIHNoYU9iai5nZXRIYXNoKFwiU0hBLTFcIiwgXCJBU0NJSVwiKTtcbiAgfSxcbiAgc2hhMjI0OiBmdW5jdGlvbihzdHIpIHtcbiAgICB2YXIgc2hhT2JqID0gbmV3IGpzU0hBKHN0ciwgXCJBU0NJSVwiKTtcbiAgICByZXR1cm4gc2hhT2JqLmdldEhhc2goXCJTSEEtMjI0XCIsIFwiQVNDSUlcIik7XG4gIH0sXG4gIHNoYTI1NjogZnVuY3Rpb24oc3RyKSB7XG4gICAgdmFyIHNoYU9iaiA9IG5ldyBqc1NIQShzdHIsIFwiQVNDSUlcIik7XG4gICAgcmV0dXJuIHNoYU9iai5nZXRIYXNoKFwiU0hBLTI1NlwiLCBcIkFTQ0lJXCIpO1xuICB9LFxuICBzaGEzODQ6IGZ1bmN0aW9uKHN0cikge1xuICAgIHZhciBzaGFPYmogPSBuZXcganNTSEEoc3RyLCBcIkFTQ0lJXCIpO1xuICAgIHJldHVybiBzaGFPYmouZ2V0SGFzaChcIlNIQS0zODRcIiwgXCJBU0NJSVwiKTtcblxuICB9LFxuICBzaGE1MTI6IGZ1bmN0aW9uKHN0cikge1xuICAgIHZhciBzaGFPYmogPSBuZXcganNTSEEoc3RyLCBcIkFTQ0lJXCIpO1xuICAgIHJldHVybiBzaGFPYmouZ2V0SGFzaChcIlNIQS01MTJcIiwgXCJBU0NJSVwiKTtcbiAgfVxufVxuIiwibW9kdWxlLmV4cG9ydHMgPSB7XG4gIGNpcGhlcjogcmVxdWlyZSgnLi9jaXBoZXInKSxcbiAgaGFzaDogcmVxdWlyZSgnLi9oYXNoJyksXG4gIGNmYjogcmVxdWlyZSgnLi9jZmIuanMnKSxcbiAgcHVibGljS2V5OiByZXF1aXJlKCcuL3B1YmxpY19rZXknKSxcbiAgc2lnbmF0dXJlOiByZXF1aXJlKCcuL3NpZ25hdHVyZS5qcycpLFxuICByYW5kb206IHJlcXVpcmUoJy4vcmFuZG9tLmpzJyksXG4gIHBrY3MxOiByZXF1aXJlKCcuL3BrY3MxLmpzJylcblxufVxuXG52YXIgY3J5cHRvID0gcmVxdWlyZSgnLi9jcnlwdG8uanMnKTtcblxuZm9yICh2YXIgaSBpbiBjcnlwdG8pXG4gIG1vZHVsZS5leHBvcnRzW2ldID0gY3J5cHRvW2ldO1xuIiwiLy8gR1BHNEJyb3dzZXJzIC0gQW4gT3BlblBHUCBpbXBsZW1lbnRhdGlvbiBpbiBqYXZhc2NyaXB0XG4vLyBDb3B5cmlnaHQgKEMpIDIwMTEgUmVjdXJpdHkgTGFicyBHbWJIXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3Jcbi8vIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlclxuLy8gdmVyc2lvbiAyLjEgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuLy8gYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2Zcbi8vIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUgR05VXG4vLyBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuLy8gXG4vLyBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFsb25nIHdpdGggdGhpcyBsaWJyYXJ5OyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlXG4vLyBGb3VuZGF0aW9uLCBJbmMuLCA1MSBGcmFua2xpbiBTdHJlZXQsIEZpZnRoIEZsb29yLCBCb3N0b24sIE1BICAwMjExMC0xMzAxICBVU0FcblxuLyoqXG4gKiBBU04xIG9iamVjdCBpZGVudGlmaWVycyBmb3IgaGFzaGVzIChTZWUgUkZDNDg4MCA1LjIuMilcbiAqL1xuaGFzaF9oZWFkZXJzID0gbmV3IEFycmF5KCk7XG5oYXNoX2hlYWRlcnNbMV0gPSBbMHgzMCwgMHgyMCwgMHgzMCwgMHgwYywgMHgwNiwgMHgwOCwgMHgyYSwgMHg4NiwgMHg0OCwgMHg4NiwgMHhmNywgMHgwZCwgMHgwMiwgMHgwNSwgMHgwNSwgMHgwMCwgMHgwNCxcbiAgICAweDEwXG5dO1xuaGFzaF9oZWFkZXJzWzNdID0gWzB4MzAsIDB4MjEsIDB4MzAsIDB4MDksIDB4MDYsIDB4MDUsIDB4MkIsIDB4MjQsIDB4MDMsIDB4MDIsIDB4MDEsIDB4MDUsIDB4MDAsIDB4MDQsIDB4MTRdO1xuaGFzaF9oZWFkZXJzWzJdID0gWzB4MzAsIDB4MjEsIDB4MzAsIDB4MDksIDB4MDYsIDB4MDUsIDB4MmIsIDB4MGUsIDB4MDMsIDB4MDIsIDB4MWEsIDB4MDUsIDB4MDAsIDB4MDQsIDB4MTRdO1xuaGFzaF9oZWFkZXJzWzhdID0gWzB4MzAsIDB4MzEsIDB4MzAsIDB4MGQsIDB4MDYsIDB4MDksIDB4NjAsIDB4ODYsIDB4NDgsIDB4MDEsIDB4NjUsIDB4MDMsIDB4MDQsIDB4MDIsIDB4MDEsIDB4MDUsIDB4MDAsXG4gICAgMHgwNCwgMHgyMFxuXTtcbmhhc2hfaGVhZGVyc1s5XSA9IFsweDMwLCAweDQxLCAweDMwLCAweDBkLCAweDA2LCAweDA5LCAweDYwLCAweDg2LCAweDQ4LCAweDAxLCAweDY1LCAweDAzLCAweDA0LCAweDAyLCAweDAyLCAweDA1LCAweDAwLFxuICAgIDB4MDQsIDB4MzBcbl07XG5oYXNoX2hlYWRlcnNbMTBdID0gWzB4MzAsIDB4NTEsIDB4MzAsIDB4MGQsIDB4MDYsIDB4MDksIDB4NjAsIDB4ODYsIDB4NDgsIDB4MDEsIDB4NjUsIDB4MDMsIDB4MDQsIDB4MDIsIDB4MDMsIDB4MDUsXG4gICAgMHgwMCwgMHgwNCwgMHg0MFxuXTtcbmhhc2hfaGVhZGVyc1sxMV0gPSBbMHgzMCwgMHgzMSwgMHgzMCwgMHgwZCwgMHgwNiwgMHgwOSwgMHg2MCwgMHg4NiwgMHg0OCwgMHgwMSwgMHg2NSwgMHgwMywgMHgwNCwgMHgwMiwgMHgwNCwgMHgwNSxcbiAgICAweDAwLCAweDA0LCAweDFDXG5dO1xuXG5cbnZhciBjcnlwdG8gPSByZXF1aXJlKCcuL2NyeXB0by5qcycpLFxuICByYW5kb20gPSByZXF1aXJlKCcuL3JhbmRvbS5qcycpLFxuICB1dGlsID0gcmVxdWlyZSgnLi4vdXRpbCcpLFxuICBCaWdJbnRlZ2VyID0gcmVxdWlyZSgnLi9wdWJsaWNfa2V5L2pzYm4uanMnKSxcbiAgaGFzaCA9IHJlcXVpcmUoJy4vaGFzaCcpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgZW1lOiB7XG4gICAgLyoqXG4gICAgICogY3JlYXRlIGEgRU1FLVBLQ1MxLXYxXzUgcGFkZGluZyAoU2VlIFJGQzQ4ODAgMTMuMS4xKVxuICAgICAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlIG1lc3NhZ2UgdG8gYmUgcGFkZGVkXG4gICAgICogQHBhcmFtIHtJbnRlZ2VyfSBsZW5ndGggTGVuZ3RoIHRvIHRoZSByZXN1bHRpbmcgbWVzc2FnZVxuICAgICAqIEByZXR1cm4ge1N0cmluZ30gRU1FLVBLQ1MxIHBhZGRlZCBtZXNzYWdlXG4gICAgICovXG4gICAgZW5jb2RlOiBmdW5jdGlvbihtZXNzYWdlLCBsZW5ndGgpIHtcbiAgICAgIGlmIChtZXNzYWdlLmxlbmd0aCA+IGxlbmd0aCAtIDExKVxuICAgICAgICByZXR1cm4gLTE7XG4gICAgICB2YXIgcmVzdWx0ID0gXCJcIjtcbiAgICAgIHJlc3VsdCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKDApO1xuICAgICAgcmVzdWx0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoMik7XG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aCAtIG1lc3NhZ2UubGVuZ3RoIC0gMzsgaSsrKSB7XG4gICAgICAgIHJlc3VsdCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKHJhbmRvbS5nZXRQc2V1ZG9SYW5kb20oMSwgMjU1KSk7XG4gICAgICB9XG4gICAgICByZXN1bHQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSgwKTtcbiAgICAgIHJlc3VsdCArPSBtZXNzYWdlO1xuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogZGVjb2RlcyBhIEVNRS1QS0NTMS12MV81IHBhZGRpbmcgKFNlZSBSRkM0ODgwIDEzLjEuMilcbiAgICAgKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZSBFTUUtUEtDUzEgcGFkZGVkIG1lc3NhZ2VcbiAgICAgKiBAcmV0dXJuIHtTdHJpbmd9IGRlY29kZWQgbWVzc2FnZSBcbiAgICAgKi9cbiAgICBkZWNvZGU6IGZ1bmN0aW9uKG1lc3NhZ2UsIGxlbikge1xuICAgICAgaWYgKG1lc3NhZ2UubGVuZ3RoIDwgbGVuKVxuICAgICAgICBtZXNzYWdlID0gU3RyaW5nLmZyb21DaGFyQ29kZSgwKSArIG1lc3NhZ2U7XG4gICAgICBpZiAobWVzc2FnZS5sZW5ndGggPCAxMiB8fCBtZXNzYWdlLmNoYXJDb2RlQXQoMCkgIT0gMCB8fCBtZXNzYWdlLmNoYXJDb2RlQXQoMSkgIT0gMilcbiAgICAgICAgcmV0dXJuIC0xO1xuICAgICAgdmFyIGkgPSAyO1xuICAgICAgd2hpbGUgKG1lc3NhZ2UuY2hhckNvZGVBdChpKSAhPSAwICYmIG1lc3NhZ2UubGVuZ3RoID4gaSlcbiAgICAgICAgaSsrO1xuICAgICAgcmV0dXJuIG1lc3NhZ2Uuc3Vic3RyaW5nKGkgKyAxLCBtZXNzYWdlLmxlbmd0aCk7XG4gICAgfSxcbiAgfSxcblxuICBlbXNhOiB7XG5cbiAgICAvKipcbiAgICAgKiBjcmVhdGUgYSBFTVNBLVBLQ1MxLXYxXzUgcGFkZGluZyAoU2VlIFJGQzQ4ODAgMTMuMS4zKVxuICAgICAqIEBwYXJhbSB7SW50ZWdlcn0gYWxnbyBIYXNoIGFsZ29yaXRobSB0eXBlIHVzZWRcbiAgICAgKiBAcGFyYW0ge1N0cmluZ30gZGF0YSBEYXRhIHRvIGJlIGhhc2hlZFxuICAgICAqIEBwYXJhbSB7SW50ZWdlcn0ga2V5bGVuZ3RoIEtleSBzaXplIG9mIHRoZSBwdWJsaWMgbXBpIGluIGJ5dGVzXG4gICAgICogQHJldHVybnMge1N0cmluZ30gSGFzaGNvZGUgd2l0aCBwa2NzMXBhZGRpbmcgYXMgc3RyaW5nXG4gICAgICovXG4gICAgZW5jb2RlOiBmdW5jdGlvbihhbGdvLCBkYXRhLCBrZXlsZW5ndGgpIHtcbiAgICAgIHZhciBkYXRhMiA9IFwiXCI7XG4gICAgICBkYXRhMiArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKDB4MDApO1xuICAgICAgZGF0YTIgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSgweDAxKTtcbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgKGtleWxlbmd0aCAtIGhhc2hfaGVhZGVyc1thbGdvXS5sZW5ndGggLSAzIC1cbiAgICAgICAgaGFzaC5nZXRIYXNoQnl0ZUxlbmd0aChhbGdvKSk7IGkrKylcblxuICAgICAgICBkYXRhMiArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKDB4ZmYpO1xuXG4gICAgICBkYXRhMiArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKDB4MDApO1xuXG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGhhc2hfaGVhZGVyc1thbGdvXS5sZW5ndGg7IGkrKylcbiAgICAgICAgZGF0YTIgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShoYXNoX2hlYWRlcnNbYWxnb11baV0pO1xuXG4gICAgICBkYXRhMiArPSBoYXNoLmRpZ2VzdChhbGdvLCBkYXRhKTtcbiAgICAgIHJldHVybiBuZXcgQmlnSW50ZWdlcih1dGlsLmhleHN0cmR1bXAoZGF0YTIpLCAxNik7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIGV4dHJhY3QgdGhlIGhhc2ggb3V0IG9mIGFuIEVNU0EtUEtDUzEtdjEuNSBwYWRkaW5nIChTZWUgUkZDNDg4MCAxMy4xLjMpIFxuICAgICAqIEBwYXJhbSB7U3RyaW5nfSBkYXRhIEhhc2ggaW4gcGtjczEgZW5jb2RpbmdcbiAgICAgKiBAcmV0dXJucyB7U3RyaW5nfSBUaGUgaGFzaCBhcyBzdHJpbmdcbiAgICAgKi9cbiAgICBkZWNvZGU6IGZ1bmN0aW9uKGFsZ28sIGRhdGEpIHtcbiAgICAgIHZhciBpID0gMDtcbiAgICAgIGlmIChkYXRhLmNoYXJDb2RlQXQoMCkgPT0gMCkgaSsrO1xuICAgICAgZWxzZSBpZiAoZGF0YS5jaGFyQ29kZUF0KDApICE9IDEpIHJldHVybiAtMTtcbiAgICAgIGVsc2UgaSsrO1xuXG4gICAgICB3aGlsZSAoZGF0YS5jaGFyQ29kZUF0KGkpID09IDB4RkYpIGkrKztcbiAgICAgIGlmIChkYXRhLmNoYXJDb2RlQXQoaSsrKSAhPSAwKSByZXR1cm4gLTE7XG4gICAgICB2YXIgaiA9IDA7XG4gICAgICBmb3IgKGogPSAwOyBqIDwgaGFzaF9oZWFkZXJzW2FsZ29dLmxlbmd0aCAmJiBqICsgaSA8IGRhdGEubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgaWYgKGRhdGEuY2hhckNvZGVBdChqICsgaSkgIT0gaGFzaF9oZWFkZXJzW2FsZ29dW2pdKSByZXR1cm4gLTE7XG4gICAgICB9XG4gICAgICBpICs9IGo7XG4gICAgICBpZiAoZGF0YS5zdWJzdHJpbmcoaSkubGVuZ3RoIDwgaGFzaC5nZXRIYXNoQnl0ZUxlbmd0aChhbGdvKSkgcmV0dXJuIC0xO1xuICAgICAgcmV0dXJuIGRhdGEuc3Vic3RyaW5nKGkpO1xuICAgIH1cbiAgfVxufVxuIiwiLy8gR1BHNEJyb3dzZXJzIC0gQW4gT3BlblBHUCBpbXBsZW1lbnRhdGlvbiBpbiBqYXZhc2NyaXB0XG4vLyBDb3B5cmlnaHQgKEMpIDIwMTEgUmVjdXJpdHkgTGFicyBHbWJIXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3Jcbi8vIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlclxuLy8gdmVyc2lvbiAyLjEgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuLy8gYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2Zcbi8vIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUgR05VXG4vLyBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuLy8gXG4vLyBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFsb25nIHdpdGggdGhpcyBsaWJyYXJ5OyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlXG4vLyBGb3VuZGF0aW9uLCBJbmMuLCA1MSBGcmFua2xpbiBTdHJlZXQsIEZpZnRoIEZsb29yLCBCb3N0b24sIE1BICAwMjExMC0xMzAxICBVU0Fcbi8vXG4vLyBBIERpZ2l0YWwgc2lnbmF0dXJlIGFsZ29yaXRobSBpbXBsZW1lbnRhdGlvblxuXG52YXIgQmlnSW50ZWdlciA9IHJlcXVpcmUoJy4vanNibi5qcycpLFxuICByYW5kb20gPSByZXF1aXJlKCcuLi9yYW5kb20uanMnKSxcbiAgaGFzaE1vZHVsZSA9IHJlcXVpcmUoJy4uL2hhc2gnKSxcbiAgdXRpbCA9IHJlcXVpcmUoJy4uLy4uL3V0aWwnKTtcblxuZnVuY3Rpb24gRFNBKCkge1xuICAvLyBzMSA9ICgoZyoqcykgbW9kIHApIG1vZCBxXG4gIC8vIHMxID0gKChzKiotMSkqKHNoYS0xKG0pKyhzMSp4KSBtb2QgcSlcbiAgZnVuY3Rpb24gc2lnbihoYXNoYWxnbywgbSwgZywgcCwgcSwgeCkge1xuICAgIC8vIElmIHRoZSBvdXRwdXQgc2l6ZSBvZiB0aGUgY2hvc2VuIGhhc2ggaXMgbGFyZ2VyIHRoYW4gdGhlIG51bWJlciBvZlxuICAgIC8vIGJpdHMgb2YgcSwgdGhlIGhhc2ggcmVzdWx0IGlzIHRydW5jYXRlZCB0byBmaXQgYnkgdGFraW5nIHRoZSBudW1iZXJcbiAgICAvLyBvZiBsZWZ0bW9zdCBiaXRzIGVxdWFsIHRvIHRoZSBudW1iZXIgb2YgYml0cyBvZiBxLiAgVGhpcyAocG9zc2libHlcbiAgICAvLyB0cnVuY2F0ZWQpIGhhc2ggZnVuY3Rpb24gcmVzdWx0IGlzIHRyZWF0ZWQgYXMgYSBudW1iZXIgYW5kIHVzZWRcbiAgICAvLyBkaXJlY3RseSBpbiB0aGUgRFNBIHNpZ25hdHVyZSBhbGdvcml0aG0uXG4gICAgdmFyIGhhc2hlZF9kYXRhID0gdXRpbC5nZXRMZWZ0TkJpdHMoaGFzaE1vZHVsZS5kaWdlc3QoaGFzaGFsZ28sIG0pLCBxLmJpdExlbmd0aCgpKTtcbiAgICB2YXIgaGFzaCA9IG5ldyBCaWdJbnRlZ2VyKHV0aWwuaGV4c3RyZHVtcChoYXNoZWRfZGF0YSksIDE2KTtcbiAgICB2YXIgayA9IHJhbmRvbS5nZXRSYW5kb21CaWdJbnRlZ2VySW5SYW5nZShCaWdJbnRlZ2VyLk9ORS5hZGQoQmlnSW50ZWdlci5PTkUpLCBxLnN1YnRyYWN0KEJpZ0ludGVnZXIuT05FKSk7XG4gICAgdmFyIHMxID0gKGcubW9kUG93KGssIHApKS5tb2QocSk7XG4gICAgdmFyIHMyID0gKGsubW9kSW52ZXJzZShxKS5tdWx0aXBseShoYXNoLmFkZCh4Lm11bHRpcGx5KHMxKSkpKS5tb2QocSk7XG4gICAgdmFyIHJlc3VsdCA9IG5ldyBBcnJheSgpO1xuICAgIHJlc3VsdFswXSA9IHMxLnRvTVBJKCk7XG4gICAgcmVzdWx0WzFdID0gczIudG9NUEkoKTtcbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG5cbiAgZnVuY3Rpb24gc2VsZWN0X2hhc2hfYWxnb3JpdGhtKHEpIHtcbiAgICB2YXIgdXNlcnNldHRpbmcgPSBvcGVucGdwLmNvbmZpZy5jb25maWcucHJlZmVyX2hhc2hfYWxnb3JpdGhtO1xuICAgIC8qXG4gICAgICogMTAyNC1iaXQga2V5LCAxNjAtYml0IHEsIFNIQS0xLCBTSEEtMjI0LCBTSEEtMjU2LCBTSEEtMzg0LCBvciBTSEEtNTEyIGhhc2hcbiAgICAgKiAyMDQ4LWJpdCBrZXksIDIyNC1iaXQgcSwgU0hBLTIyNCwgU0hBLTI1NiwgU0hBLTM4NCwgb3IgU0hBLTUxMiBoYXNoXG4gICAgICogMjA0OC1iaXQga2V5LCAyNTYtYml0IHEsIFNIQS0yNTYsIFNIQS0zODQsIG9yIFNIQS01MTIgaGFzaFxuICAgICAqIDMwNzItYml0IGtleSwgMjU2LWJpdCBxLCBTSEEtMjU2LCBTSEEtMzg0LCBvciBTSEEtNTEyIGhhc2hcbiAgICAgKi9cbiAgICBzd2l0Y2ggKE1hdGgucm91bmQocS5iaXRMZW5ndGgoKSAvIDgpKSB7XG4gICAgICBjYXNlIDIwOlxuICAgICAgICAvLyAxMDI0IGJpdFxuICAgICAgICBpZiAodXNlcnNldHRpbmcgIT0gMiAmJlxuICAgICAgICAgIHVzZXJzZXR0aW5nID4gMTEgJiZcbiAgICAgICAgICB1c2Vyc2V0dGluZyAhPSAxMCAmJlxuICAgICAgICAgIHVzZXJzZXR0aW5nIDwgOClcbiAgICAgICAgICByZXR1cm4gMjsgLy8gcHJlZmVyIHNoYTFcbiAgICAgICAgcmV0dXJuIHVzZXJzZXR0aW5nO1xuICAgICAgY2FzZSAyODpcbiAgICAgICAgLy8gMjA0OCBiaXRcbiAgICAgICAgaWYgKHVzZXJzZXR0aW5nID4gMTEgJiZcbiAgICAgICAgICB1c2Vyc2V0dGluZyA8IDgpXG4gICAgICAgICAgcmV0dXJuIDExO1xuICAgICAgICByZXR1cm4gdXNlcnNldHRpbmc7XG4gICAgICBjYXNlIDMyOlxuICAgICAgICAvLyA0MDk2IGJpdCAvLyBwcmVmZXIgc2hhMjI0XG4gICAgICAgIGlmICh1c2Vyc2V0dGluZyA+IDEwICYmXG4gICAgICAgICAgdXNlcnNldHRpbmcgPCA4KVxuICAgICAgICAgIHJldHVybiA4OyAvLyBwcmVmZXIgc2hhMjU2XG4gICAgICAgIHJldHVybiB1c2Vyc2V0dGluZztcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHV0aWwucHJpbnRfZGVidWcoXCJEU0Egc2VsZWN0IGhhc2ggYWxnb3JpdGhtOiByZXR1cm5pbmcgbnVsbCBmb3IgYW4gdW5rbm93biBsZW5ndGggb2YgcVwiKTtcbiAgICAgICAgcmV0dXJuIG51bGw7XG5cbiAgICB9XG4gIH1cbiAgdGhpcy5zZWxlY3RfaGFzaF9hbGdvcml0aG0gPSBzZWxlY3RfaGFzaF9hbGdvcml0aG07XG5cbiAgZnVuY3Rpb24gdmVyaWZ5KGhhc2hhbGdvLCBzMSwgczIsIG0sIHAsIHEsIGcsIHkpIHtcbiAgICB2YXIgaGFzaGVkX2RhdGEgPSB1dGlsLmdldExlZnROQml0cyhoYXNoTW9kdWxlLmRpZ2VzdChoYXNoYWxnbywgbSksIHEuYml0TGVuZ3RoKCkpO1xuICAgIHZhciBoYXNoID0gbmV3IEJpZ0ludGVnZXIodXRpbC5oZXhzdHJkdW1wKGhhc2hlZF9kYXRhKSwgMTYpO1xuICAgIGlmIChCaWdJbnRlZ2VyLlpFUk8uY29tcGFyZVRvKHMxKSA+IDAgfHxcbiAgICAgIHMxLmNvbXBhcmVUbyhxKSA+IDAgfHxcbiAgICAgIEJpZ0ludGVnZXIuWkVSTy5jb21wYXJlVG8oczIpID4gMCB8fFxuICAgICAgczIuY29tcGFyZVRvKHEpID4gMCkge1xuICAgICAgdXRpbC5wcmludF9lcnJvcihcImludmFsaWQgRFNBIFNpZ25hdHVyZVwiKTtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgICB2YXIgdyA9IHMyLm1vZEludmVyc2UocSk7XG4gICAgdmFyIHUxID0gaGFzaC5tdWx0aXBseSh3KS5tb2QocSk7XG4gICAgdmFyIHUyID0gczEubXVsdGlwbHkodykubW9kKHEpO1xuICAgIHJldHVybiBnLm1vZFBvdyh1MSwgcCkubXVsdGlwbHkoeS5tb2RQb3codTIsIHApKS5tb2QocCkubW9kKHEpO1xuICB9XG5cbiAgLypcblx0ICogdW51c2VkIGNvZGUuIFRoaXMgY2FuIGJlIHVzZWQgYXMgYSBzdGFydCB0byB3cml0ZSBhIGtleSBnZW5lcmF0b3Jcblx0ICogZnVuY3Rpb24uXG5cdFxuXHRmdW5jdGlvbiBnZW5lcmF0ZUtleShiaXRjb3VudCkge1xuXHQgICAgdmFyIHFpID0gbmV3IEJpZ0ludGVnZXIoYml0Y291bnQsIHByaW1lQ2VudGVyaWUpO1xuXHQgICAgdmFyIHBpID0gZ2VuZXJhdGVQKHEsIDUxMik7XG5cdCAgICB2YXIgZ2kgPSBnZW5lcmF0ZUcocCwgcSwgYml0Y291bnQpO1xuXHQgICAgdmFyIHhpO1xuXHQgICAgZG8ge1xuXHQgICAgICAgIHhpID0gbmV3IEJpZ0ludGVnZXIocS5iaXRDb3VudCgpLCByYW5kKTtcblx0ICAgIH0gd2hpbGUgKHguY29tcGFyZVRvKEJpZ0ludGVnZXIuWkVSTykgIT0gMSAmJiB4LmNvbXBhcmVUbyhxKSAhPSAtMSk7XG5cdCAgICB2YXIgeWkgPSBnLm1vZFBvdyh4LCBwKTtcblx0ICAgIHJldHVybiB7eDogeGksIHE6IHFpLCBwOiBwaSwgZzogZ2ksIHk6IHlpfTtcblx0fVxuXG5cdGZ1bmN0aW9uIGdlbmVyYXRlUChxLCBiaXRsZW5ndGgsIHJhbmRvbWZuKSB7XG5cdCAgICBpZiAoYml0bGVuZ3RoICUgNjQgIT0gMCkge1xuXHQgICAgXHRyZXR1cm4gZmFsc2U7XG5cdCAgICB9XG5cdCAgICB2YXIgcFRlbXA7XG5cdCAgICB2YXIgcFRlbXAyO1xuXHQgICAgZG8ge1xuXHQgICAgICAgIHBUZW1wID0gcmFuZG9tZm4oYml0Y291bnQsIHRydWUpO1xuXHQgICAgICAgIHBUZW1wMiA9IHBUZW1wLnN1YnRyYWN0KEJpZ0ludGVnZXIuT05FKTtcblx0ICAgICAgICBwVGVtcCA9IHBUZW1wLnN1YnRyYWN0KHBUZW1wMi5yZW1haW5kZXIocSkpO1xuXHQgICAgfSB3aGlsZSAoIXBUZW1wLmlzUHJvYmFibGVQcmltZShwcmltZUNlbnRlcmllKSB8fCBwVGVtcC5iaXRMZW5ndGgoKSAhPSBsKTtcblx0ICAgIHJldHVybiBwVGVtcDtcblx0fVxuXHRcblx0ZnVuY3Rpb24gZ2VuZXJhdGVHKHAsIHEsIGJpdGxlbmd0aCwgcmFuZG9tZm4pIHtcblx0ICAgIHZhciBhdXggPSBwLnN1YnRyYWN0KEJpZ0ludGVnZXIuT05FKTtcblx0ICAgIHZhciBwb3cgPSBhdXguZGl2aWRlKHEpO1xuXHQgICAgdmFyIGdUZW1wO1xuXHQgICAgZG8ge1xuXHQgICAgICAgIGdUZW1wID0gcmFuZG9tZm4oYml0bGVuZ3RoKTtcblx0ICAgIH0gd2hpbGUgKGdUZW1wLmNvbXBhcmVUbyhhdXgpICE9IC0xICYmIGdUZW1wLmNvbXBhcmVUbyhCaWdJbnRlZ2VyLk9ORSkgIT0gMSk7XG5cdCAgICByZXR1cm4gZ1RlbXAubW9kUG93KHBvdywgcCk7XG5cdH1cblxuXHRmdW5jdGlvbiBnZW5lcmF0ZUsocSwgYml0bGVuZ3RoLCByYW5kb21mbikge1xuXHQgICAgdmFyIHRlbXBLO1xuXHQgICAgZG8ge1xuXHQgICAgICAgIHRlbXBLID0gcmFuZG9tZm4oYml0bGVuZ3RoLCBmYWxzZSk7XG5cdCAgICB9IHdoaWxlICh0ZW1wSy5jb21wYXJlVG8ocSkgIT0gLTEgJiYgdGVtcEsuY29tcGFyZVRvKEJpZ0ludGVnZXIuWkVSTykgIT0gMSk7XG5cdCAgICByZXR1cm4gdGVtcEs7XG5cdH1cblxuXHRmdW5jdGlvbiBnZW5lcmF0ZVIocSxwKSB7XG5cdCAgICBrID0gZ2VuZXJhdGVLKHEpO1xuXHQgICAgdmFyIHIgPSBnLm1vZFBvdyhrLCBwKS5tb2QocSk7XG5cdCAgICByZXR1cm4gcjtcblx0fVxuXG5cdGZ1bmN0aW9uIGdlbmVyYXRlUyhoYXNoZm4sayxyLG0scSx4KSB7XG4gICAgICAgIHZhciBoYXNoID0gaGFzaGZuKG0pO1xuICAgICAgICBzID0gKGsubW9kSW52ZXJzZShxKS5tdWx0aXBseShoYXNoLmFkZCh4Lm11bHRpcGx5KHIpKSkpLm1vZChxKTtcblx0ICAgIHJldHVybiBzO1xuXHR9ICovXG4gIHRoaXMuc2lnbiA9IHNpZ247XG4gIHRoaXMudmVyaWZ5ID0gdmVyaWZ5O1xuICAvLyB0aGlzLmdlbmVyYXRlID0gZ2VuZXJhdGVLZXk7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gRFNBO1xuIiwiLy8gR1BHNEJyb3dzZXJzIC0gQW4gT3BlblBHUCBpbXBsZW1lbnRhdGlvbiBpbiBqYXZhc2NyaXB0XG4vLyBDb3B5cmlnaHQgKEMpIDIwMTEgUmVjdXJpdHkgTGFicyBHbWJIXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3Jcbi8vIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlclxuLy8gdmVyc2lvbiAyLjEgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuLy8gYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2Zcbi8vIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUgR05VXG4vLyBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuLy8gXG4vLyBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFsb25nIHdpdGggdGhpcyBsaWJyYXJ5OyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlXG4vLyBGb3VuZGF0aW9uLCBJbmMuLCA1MSBGcmFua2xpbiBTdHJlZXQsIEZpZnRoIEZsb29yLCBCb3N0b24sIE1BICAwMjExMC0xMzAxICBVU0Fcbi8vXG4vLyBFbEdhbWFsIGltcGxlbWVudGF0aW9uXG5cbnZhciBCaWdJbnRlZ2VyID0gcmVxdWlyZSgnLi9qc2JuLmpzJyksXG4gIHJhbmRvbSA9IHJlcXVpcmUoJy4uL3JhbmRvbS5qcycpLFxuICB1dGlsID0gcmVxdWlyZSgnLi4vLi4vdXRpbCcpO1xuXG5mdW5jdGlvbiBFbGdhbWFsKCkge1xuXG4gIGZ1bmN0aW9uIGVuY3J5cHQobSwgZywgcCwgeSkge1xuICAgIC8vICBjaG9vc2UgayBpbiB7MiwuLi4scC0yfVxuICAgIHZhciB0d28gPSBCaWdJbnRlZ2VyLk9ORS5hZGQoQmlnSW50ZWdlci5PTkUpO1xuICAgIHZhciBwTWludXMyID0gcC5zdWJ0cmFjdCh0d28pO1xuICAgIHZhciBrID0gcmFuZG9tLmdldFJhbmRvbUJpZ0ludGVnZXJJblJhbmdlKHR3bywgcE1pbnVzMik7XG4gICAgayA9IGsubW9kKHBNaW51czIpLmFkZChCaWdJbnRlZ2VyLk9ORSk7XG4gICAgdmFyIGMgPSBbXTtcbiAgICBjWzBdID0gZy5tb2RQb3coaywgcCk7XG4gICAgY1sxXSA9IHkubW9kUG93KGssIHApLm11bHRpcGx5KG0pLm1vZChwKTtcbiAgICByZXR1cm4gYztcbiAgfVxuXG4gIGZ1bmN0aW9uIGRlY3J5cHQoYzEsIGMyLCBwLCB4KSB7XG4gICAgdXRpbC5wcmludF9kZWJ1ZyhcIkVsZ2FtYWwgRGVjcnlwdDpcXG5jMTpcIiArIHV0aWwuaGV4c3RyZHVtcChjMS50b01QSSgpKSArIFwiXFxuXCIgK1xuICAgICAgXCJjMjpcIiArIHV0aWwuaGV4c3RyZHVtcChjMi50b01QSSgpKSArIFwiXFxuXCIgK1xuICAgICAgXCJwOlwiICsgdXRpbC5oZXhzdHJkdW1wKHAudG9NUEkoKSkgKyBcIlxcblwiICtcbiAgICAgIFwieDpcIiArIHV0aWwuaGV4c3RyZHVtcCh4LnRvTVBJKCkpKTtcbiAgICByZXR1cm4gKGMxLm1vZFBvdyh4LCBwKS5tb2RJbnZlcnNlKHApKS5tdWx0aXBseShjMikubW9kKHApO1xuICAgIC8vdmFyIGMgPSBjMS5wb3coeCkubW9kSW52ZXJzZShwKTsgLy8gYzBeLWEgbW9kIHBcbiAgICAvL3JldHVybiBjLm11bHRpcGx5KGMyKS5tb2QocCk7XG4gIH1cblxuICAvLyBzaWduaW5nIGFuZCBzaWduYXR1cmUgdmVyaWZpY2F0aW9uIHVzaW5nIEVsZ2FtYWwgaXMgbm90IHJlcXVpcmVkIGJ5IE9wZW5QR1AuXG4gIHRoaXMuZW5jcnlwdCA9IGVuY3J5cHQ7XG4gIHRoaXMuZGVjcnlwdCA9IGRlY3J5cHQ7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gRWxnYW1hbDtcbiIsIm1vZHVsZS5leHBvcnRzID0ge1xuICByc2E6IHJlcXVpcmUoJy4vcnNhLmpzJyksXG4gIGVsZ2FtYWw6IHJlcXVpcmUoJy4vZWxnYW1hbC5qcycpLFxuICBkc2E6IHJlcXVpcmUoJy4vZHNhLmpzJylcbn1cbiIsIi8qXG4gKiBDb3B5cmlnaHQgKGMpIDIwMDMtMjAwNSAgVG9tIFd1ICh0andAY3MuU3RhbmZvcmQuRURVKSBcbiAqIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4gKlxuICogTW9kaWZpZWQgYnkgUmVjdXJpdHkgTGFicyBHbWJIIFxuICogXG4gKiBQZXJtaXNzaW9uIGlzIGhlcmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55IHBlcnNvbiBvYnRhaW5pbmdcbiAqIGEgY29weSBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRvY3VtZW50YXRpb24gZmlsZXMgKHRoZVxuICogXCJTb2Z0d2FyZVwiKSwgdG8gZGVhbCBpbiB0aGUgU29mdHdhcmUgd2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nXG4gKiB3aXRob3V0IGxpbWl0YXRpb24gdGhlIHJpZ2h0cyB0byB1c2UsIGNvcHksIG1vZGlmeSwgbWVyZ2UsIHB1Ymxpc2gsXG4gKiBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLCBhbmQvb3Igc2VsbCBjb3BpZXMgb2YgdGhlIFNvZnR3YXJlLCBhbmQgdG9cbiAqIHBlcm1pdCBwZXJzb25zIHRvIHdob20gdGhlIFNvZnR3YXJlIGlzIGZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0b1xuICogdGhlIGZvbGxvd2luZyBjb25kaXRpb25zOlxuICpcbiAqIFRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlIHNoYWxsIGJlXG4gKiBpbmNsdWRlZCBpbiBhbGwgY29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS5cbiAqXG4gKiBUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgXCJBUy1JU1wiIEFORCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBcbiAqIEVYUFJFU1MsIElNUExJRUQgT1IgT1RIRVJXSVNFLCBJTkNMVURJTkcgV0lUSE9VVCBMSU1JVEFUSU9OLCBBTlkgXG4gKiBXQVJSQU5UWSBPRiBNRVJDSEFOVEFCSUxJVFkgT1IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBcbiAqXG4gKiBJTiBOTyBFVkVOVCBTSEFMTCBUT00gV1UgQkUgTElBQkxFIEZPUiBBTlkgU1BFQ0lBTCwgSU5DSURFTlRBTCxcbiAqIElORElSRUNUIE9SIENPTlNFUVVFTlRJQUwgREFNQUdFUyBPRiBBTlkgS0lORCwgT1IgQU5ZIERBTUFHRVMgV0hBVFNPRVZFUlxuICogUkVTVUxUSU5HIEZST00gTE9TUyBPRiBVU0UsIERBVEEgT1IgUFJPRklUUywgV0hFVEhFUiBPUiBOT1QgQURWSVNFRCBPRlxuICogVEhFIFBPU1NJQklMSVRZIE9GIERBTUFHRSwgQU5EIE9OIEFOWSBUSEVPUlkgT0YgTElBQklMSVRZLCBBUklTSU5HIE9VVFxuICogT0YgT1IgSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBVU0UgT1IgUEVSRk9STUFOQ0UgT0YgVEhJUyBTT0ZUV0FSRS5cbiAqXG4gKiBJbiBhZGRpdGlvbiwgdGhlIGZvbGxvd2luZyBjb25kaXRpb24gYXBwbGllczpcbiAqXG4gKiBBbGwgcmVkaXN0cmlidXRpb25zIG11c3QgcmV0YWluIGFuIGludGFjdCBjb3B5IG9mIHRoaXMgY29weXJpZ2h0IG5vdGljZVxuICogYW5kIGRpc2NsYWltZXIuXG4gKi9cblxuXG52YXIgdXRpbCA9IHJlcXVpcmUoJy4uLy4uL3V0aWwnKTtcblxuLy8gQmFzaWMgSmF2YVNjcmlwdCBCTiBsaWJyYXJ5IC0gc3Vic2V0IHVzZWZ1bCBmb3IgUlNBIGVuY3J5cHRpb24uXG5cbi8vIEJpdHMgcGVyIGRpZ2l0XG52YXIgZGJpdHM7XG5cbi8vIEphdmFTY3JpcHQgZW5naW5lIGFuYWx5c2lzXG52YXIgY2FuYXJ5ID0gMHhkZWFkYmVlZmNhZmU7XG52YXIgal9sbSA9ICgoY2FuYXJ5ICYgMHhmZmZmZmYpID09IDB4ZWZjYWZlKTtcblxuLy8gKHB1YmxpYykgQ29uc3RydWN0b3JcblxuZnVuY3Rpb24gQmlnSW50ZWdlcihhLCBiLCBjKSB7XG4gIGlmIChhICE9IG51bGwpXG4gICAgaWYgKFwibnVtYmVyXCIgPT0gdHlwZW9mIGEpIHRoaXMuZnJvbU51bWJlcihhLCBiLCBjKTtcbiAgICBlbHNlIGlmIChiID09IG51bGwgJiYgXCJzdHJpbmdcIiAhPSB0eXBlb2YgYSkgdGhpcy5mcm9tU3RyaW5nKGEsIDI1Nik7XG4gIGVsc2UgdGhpcy5mcm9tU3RyaW5nKGEsIGIpO1xufVxuXG4vLyByZXR1cm4gbmV3LCB1bnNldCBCaWdJbnRlZ2VyXG5cbmZ1bmN0aW9uIG5iaSgpIHtcbiAgcmV0dXJuIG5ldyBCaWdJbnRlZ2VyKG51bGwpO1xufVxuXG4vLyBhbTogQ29tcHV0ZSB3X2ogKz0gKHgqdGhpc19pKSwgcHJvcGFnYXRlIGNhcnJpZXMsXG4vLyBjIGlzIGluaXRpYWwgY2FycnksIHJldHVybnMgZmluYWwgY2FycnkuXG4vLyBjIDwgMypkdmFsdWUsIHggPCAyKmR2YWx1ZSwgdGhpc19pIDwgZHZhbHVlXG4vLyBXZSBuZWVkIHRvIHNlbGVjdCB0aGUgZmFzdGVzdCBvbmUgdGhhdCB3b3JrcyBpbiB0aGlzIGVudmlyb25tZW50LlxuXG4vLyBhbTE6IHVzZSBhIHNpbmdsZSBtdWx0IGFuZCBkaXZpZGUgdG8gZ2V0IHRoZSBoaWdoIGJpdHMsXG4vLyBtYXggZGlnaXQgYml0cyBzaG91bGQgYmUgMjYgYmVjYXVzZVxuLy8gbWF4IGludGVybmFsIHZhbHVlID0gMipkdmFsdWVeMi0yKmR2YWx1ZSAoPCAyXjUzKVxuXG5mdW5jdGlvbiBhbTEoaSwgeCwgdywgaiwgYywgbikge1xuICB3aGlsZSAoLS1uID49IDApIHtcbiAgICB2YXIgdiA9IHggKiB0aGlzW2krK10gKyB3W2pdICsgYztcbiAgICBjID0gTWF0aC5mbG9vcih2IC8gMHg0MDAwMDAwKTtcbiAgICB3W2orK10gPSB2ICYgMHgzZmZmZmZmO1xuICB9XG4gIHJldHVybiBjO1xufVxuLy8gYW0yIGF2b2lkcyBhIGJpZyBtdWx0LWFuZC1leHRyYWN0IGNvbXBsZXRlbHkuXG4vLyBNYXggZGlnaXQgYml0cyBzaG91bGQgYmUgPD0gMzAgYmVjYXVzZSB3ZSBkbyBiaXR3aXNlIG9wc1xuLy8gb24gdmFsdWVzIHVwIHRvIDIqaGR2YWx1ZV4yLWhkdmFsdWUtMSAoPCAyXjMxKVxuXG5mdW5jdGlvbiBhbTIoaSwgeCwgdywgaiwgYywgbikge1xuICB2YXIgeGwgPSB4ICYgMHg3ZmZmLFxuICAgIHhoID0geCA+PiAxNTtcbiAgd2hpbGUgKC0tbiA+PSAwKSB7XG4gICAgdmFyIGwgPSB0aGlzW2ldICYgMHg3ZmZmO1xuICAgIHZhciBoID0gdGhpc1tpKytdID4+IDE1O1xuICAgIHZhciBtID0geGggKiBsICsgaCAqIHhsO1xuICAgIGwgPSB4bCAqIGwgKyAoKG0gJiAweDdmZmYpIDw8IDE1KSArIHdbal0gKyAoYyAmIDB4M2ZmZmZmZmYpO1xuICAgIGMgPSAobCA+Pj4gMzApICsgKG0gPj4+IDE1KSArIHhoICogaCArIChjID4+PiAzMCk7XG4gICAgd1tqKytdID0gbCAmIDB4M2ZmZmZmZmY7XG4gIH1cbiAgcmV0dXJuIGM7XG59XG4vLyBBbHRlcm5hdGVseSwgc2V0IG1heCBkaWdpdCBiaXRzIHRvIDI4IHNpbmNlIHNvbWVcbi8vIGJyb3dzZXJzIHNsb3cgZG93biB3aGVuIGRlYWxpbmcgd2l0aCAzMi1iaXQgbnVtYmVycy5cblxuZnVuY3Rpb24gYW0zKGksIHgsIHcsIGosIGMsIG4pIHtcbiAgdmFyIHhsID0geCAmIDB4M2ZmZixcbiAgICB4aCA9IHggPj4gMTQ7XG4gIHdoaWxlICgtLW4gPj0gMCkge1xuICAgIHZhciBsID0gdGhpc1tpXSAmIDB4M2ZmZjtcbiAgICB2YXIgaCA9IHRoaXNbaSsrXSA+PiAxNDtcbiAgICB2YXIgbSA9IHhoICogbCArIGggKiB4bDtcbiAgICBsID0geGwgKiBsICsgKChtICYgMHgzZmZmKSA8PCAxNCkgKyB3W2pdICsgYztcbiAgICBjID0gKGwgPj4gMjgpICsgKG0gPj4gMTQpICsgeGggKiBoO1xuICAgIHdbaisrXSA9IGwgJiAweGZmZmZmZmY7XG4gIH1cbiAgcmV0dXJuIGM7XG59XG4vKmlmKGpfbG0gJiYgKG5hdmlnYXRvciAhPSB1bmRlZmluZWQgJiYgXG5cdG5hdmlnYXRvci5hcHBOYW1lID09IFwiTWljcm9zb2Z0IEludGVybmV0IEV4cGxvcmVyXCIpKSB7XG4gIEJpZ0ludGVnZXIucHJvdG90eXBlLmFtID0gYW0yO1xuICBkYml0cyA9IDMwO1xufVxuZWxzZSBpZihqX2xtICYmIChuYXZpZ2F0b3IgIT0gdW5kZWZpbmVkICYmIG5hdmlnYXRvci5hcHBOYW1lICE9IFwiTmV0c2NhcGVcIikpIHsqL1xuQmlnSW50ZWdlci5wcm90b3R5cGUuYW0gPSBhbTE7XG5kYml0cyA9IDI2O1xuLyp9XG5lbHNlIHsgLy8gTW96aWxsYS9OZXRzY2FwZSBzZWVtcyB0byBwcmVmZXIgYW0zXG4gIEJpZ0ludGVnZXIucHJvdG90eXBlLmFtID0gYW0zO1xuICBkYml0cyA9IDI4O1xufSovXG5cbkJpZ0ludGVnZXIucHJvdG90eXBlLkRCID0gZGJpdHM7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5ETSA9ICgoMSA8PCBkYml0cykgLSAxKTtcbkJpZ0ludGVnZXIucHJvdG90eXBlLkRWID0gKDEgPDwgZGJpdHMpO1xuXG52YXIgQklfRlAgPSA1MjtcbkJpZ0ludGVnZXIucHJvdG90eXBlLkZWID0gTWF0aC5wb3coMiwgQklfRlApO1xuQmlnSW50ZWdlci5wcm90b3R5cGUuRjEgPSBCSV9GUCAtIGRiaXRzO1xuQmlnSW50ZWdlci5wcm90b3R5cGUuRjIgPSAyICogZGJpdHMgLSBCSV9GUDtcblxuLy8gRGlnaXQgY29udmVyc2lvbnNcbnZhciBCSV9STSA9IFwiMDEyMzQ1Njc4OWFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6XCI7XG52YXIgQklfUkMgPSBuZXcgQXJyYXkoKTtcbnZhciByciwgdnY7XG5yciA9IFwiMFwiLmNoYXJDb2RlQXQoMCk7XG5mb3IgKHZ2ID0gMDsgdnYgPD0gOTsgKyt2dikgQklfUkNbcnIrK10gPSB2djtcbnJyID0gXCJhXCIuY2hhckNvZGVBdCgwKTtcbmZvciAodnYgPSAxMDsgdnYgPCAzNjsgKyt2dikgQklfUkNbcnIrK10gPSB2djtcbnJyID0gXCJBXCIuY2hhckNvZGVBdCgwKTtcbmZvciAodnYgPSAxMDsgdnYgPCAzNjsgKyt2dikgQklfUkNbcnIrK10gPSB2djtcblxuZnVuY3Rpb24gaW50MmNoYXIobikge1xuICByZXR1cm4gQklfUk0uY2hhckF0KG4pO1xufVxuXG5mdW5jdGlvbiBpbnRBdChzLCBpKSB7XG4gIHZhciBjID0gQklfUkNbcy5jaGFyQ29kZUF0KGkpXTtcbiAgcmV0dXJuIChjID09IG51bGwpID8gLTEgOiBjO1xufVxuXG4vLyAocHJvdGVjdGVkKSBjb3B5IHRoaXMgdG8gclxuXG5mdW5jdGlvbiBibnBDb3B5VG8ocikge1xuICBmb3IgKHZhciBpID0gdGhpcy50IC0gMTsgaSA+PSAwOyAtLWkpIHJbaV0gPSB0aGlzW2ldO1xuICByLnQgPSB0aGlzLnQ7XG4gIHIucyA9IHRoaXMucztcbn1cblxuLy8gKHByb3RlY3RlZCkgc2V0IGZyb20gaW50ZWdlciB2YWx1ZSB4LCAtRFYgPD0geCA8IERWXG5cbmZ1bmN0aW9uIGJucEZyb21JbnQoeCkge1xuICB0aGlzLnQgPSAxO1xuICB0aGlzLnMgPSAoeCA8IDApID8gLTEgOiAwO1xuICBpZiAoeCA+IDApIHRoaXNbMF0gPSB4O1xuICBlbHNlIGlmICh4IDwgLTEpIHRoaXNbMF0gPSB4ICsgRFY7XG4gIGVsc2UgdGhpcy50ID0gMDtcbn1cblxuLy8gcmV0dXJuIGJpZ2ludCBpbml0aWFsaXplZCB0byB2YWx1ZVxuXG5mdW5jdGlvbiBuYnYoaSkge1xuICB2YXIgciA9IG5iaSgpO1xuICByLmZyb21JbnQoaSk7XG4gIHJldHVybiByO1xufVxuXG4vLyAocHJvdGVjdGVkKSBzZXQgZnJvbSBzdHJpbmcgYW5kIHJhZGl4XG5cbmZ1bmN0aW9uIGJucEZyb21TdHJpbmcocywgYikge1xuICB2YXIgaztcbiAgaWYgKGIgPT0gMTYpIGsgPSA0O1xuICBlbHNlIGlmIChiID09IDgpIGsgPSAzO1xuICBlbHNlIGlmIChiID09IDI1NikgayA9IDg7IC8vIGJ5dGUgYXJyYXlcbiAgZWxzZSBpZiAoYiA9PSAyKSBrID0gMTtcbiAgZWxzZSBpZiAoYiA9PSAzMikgayA9IDU7XG4gIGVsc2UgaWYgKGIgPT0gNCkgayA9IDI7XG4gIGVsc2Uge1xuICAgIHRoaXMuZnJvbVJhZGl4KHMsIGIpO1xuICAgIHJldHVybjtcbiAgfVxuICB0aGlzLnQgPSAwO1xuICB0aGlzLnMgPSAwO1xuICB2YXIgaSA9IHMubGVuZ3RoLFxuICAgIG1pID0gZmFsc2UsXG4gICAgc2ggPSAwO1xuICB3aGlsZSAoLS1pID49IDApIHtcbiAgICB2YXIgeCA9IChrID09IDgpID8gc1tpXSAmIDB4ZmYgOiBpbnRBdChzLCBpKTtcbiAgICBpZiAoeCA8IDApIHtcbiAgICAgIGlmIChzLmNoYXJBdChpKSA9PSBcIi1cIikgbWkgPSB0cnVlO1xuICAgICAgY29udGludWU7XG4gICAgfVxuICAgIG1pID0gZmFsc2U7XG4gICAgaWYgKHNoID09IDApXG4gICAgICB0aGlzW3RoaXMudCsrXSA9IHg7XG4gICAgZWxzZSBpZiAoc2ggKyBrID4gdGhpcy5EQikge1xuICAgICAgdGhpc1t0aGlzLnQgLSAxXSB8PSAoeCAmICgoMSA8PCAodGhpcy5EQiAtIHNoKSkgLSAxKSkgPDwgc2g7XG4gICAgICB0aGlzW3RoaXMudCsrXSA9ICh4ID4+ICh0aGlzLkRCIC0gc2gpKTtcbiAgICB9IGVsc2VcbiAgICAgIHRoaXNbdGhpcy50IC0gMV0gfD0geCA8PCBzaDtcbiAgICBzaCArPSBrO1xuICAgIGlmIChzaCA+PSB0aGlzLkRCKSBzaCAtPSB0aGlzLkRCO1xuICB9XG4gIGlmIChrID09IDggJiYgKHNbMF0gJiAweDgwKSAhPSAwKSB7XG4gICAgdGhpcy5zID0gLTE7XG4gICAgaWYgKHNoID4gMCkgdGhpc1t0aGlzLnQgLSAxXSB8PSAoKDEgPDwgKHRoaXMuREIgLSBzaCkpIC0gMSkgPDwgc2g7XG4gIH1cbiAgdGhpcy5jbGFtcCgpO1xuICBpZiAobWkpIEJpZ0ludGVnZXIuWkVSTy5zdWJUbyh0aGlzLCB0aGlzKTtcbn1cblxuLy8gKHByb3RlY3RlZCkgY2xhbXAgb2ZmIGV4Y2VzcyBoaWdoIHdvcmRzXG5cbmZ1bmN0aW9uIGJucENsYW1wKCkge1xuICB2YXIgYyA9IHRoaXMucyAmIHRoaXMuRE07XG4gIHdoaWxlICh0aGlzLnQgPiAwICYmIHRoaXNbdGhpcy50IC0gMV0gPT0gYyktLXRoaXMudDtcbn1cblxuLy8gKHB1YmxpYykgcmV0dXJuIHN0cmluZyByZXByZXNlbnRhdGlvbiBpbiBnaXZlbiByYWRpeFxuXG5mdW5jdGlvbiBiblRvU3RyaW5nKGIpIHtcbiAgaWYgKHRoaXMucyA8IDApIHJldHVybiBcIi1cIiArIHRoaXMubmVnYXRlKCkudG9TdHJpbmcoYik7XG4gIHZhciBrO1xuICBpZiAoYiA9PSAxNikgayA9IDQ7XG4gIGVsc2UgaWYgKGIgPT0gOCkgayA9IDM7XG4gIGVsc2UgaWYgKGIgPT0gMikgayA9IDE7XG4gIGVsc2UgaWYgKGIgPT0gMzIpIGsgPSA1O1xuICBlbHNlIGlmIChiID09IDQpIGsgPSAyO1xuICBlbHNlIHJldHVybiB0aGlzLnRvUmFkaXgoYik7XG4gIHZhciBrbSA9ICgxIDw8IGspIC0gMSxcbiAgICBkLCBtID0gZmFsc2UsXG4gICAgciA9IFwiXCIsXG4gICAgaSA9IHRoaXMudDtcbiAgdmFyIHAgPSB0aGlzLkRCIC0gKGkgKiB0aGlzLkRCKSAlIGs7XG4gIGlmIChpLS0gPiAwKSB7XG4gICAgaWYgKHAgPCB0aGlzLkRCICYmIChkID0gdGhpc1tpXSA+PiBwKSA+IDApIHtcbiAgICAgIG0gPSB0cnVlO1xuICAgICAgciA9IGludDJjaGFyKGQpO1xuICAgIH1cbiAgICB3aGlsZSAoaSA+PSAwKSB7XG4gICAgICBpZiAocCA8IGspIHtcbiAgICAgICAgZCA9ICh0aGlzW2ldICYgKCgxIDw8IHApIC0gMSkpIDw8IChrIC0gcCk7XG4gICAgICAgIGQgfD0gdGhpc1stLWldID4+IChwICs9IHRoaXMuREIgLSBrKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGQgPSAodGhpc1tpXSA+PiAocCAtPSBrKSkgJiBrbTtcbiAgICAgICAgaWYgKHAgPD0gMCkge1xuICAgICAgICAgIHAgKz0gdGhpcy5EQjtcbiAgICAgICAgICAtLWk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIGlmIChkID4gMCkgbSA9IHRydWU7XG4gICAgICBpZiAobSkgciArPSBpbnQyY2hhcihkKTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIG0gPyByIDogXCIwXCI7XG59XG5cbi8vIChwdWJsaWMpIC10aGlzXG5cbmZ1bmN0aW9uIGJuTmVnYXRlKCkge1xuICB2YXIgciA9IG5iaSgpO1xuICBCaWdJbnRlZ2VyLlpFUk8uc3ViVG8odGhpcywgcik7XG4gIHJldHVybiByO1xufVxuXG4vLyAocHVibGljKSB8dGhpc3xcblxuZnVuY3Rpb24gYm5BYnMoKSB7XG4gIHJldHVybiAodGhpcy5zIDwgMCkgPyB0aGlzLm5lZ2F0ZSgpIDogdGhpcztcbn1cblxuLy8gKHB1YmxpYykgcmV0dXJuICsgaWYgdGhpcyA+IGEsIC0gaWYgdGhpcyA8IGEsIDAgaWYgZXF1YWxcblxuZnVuY3Rpb24gYm5Db21wYXJlVG8oYSkge1xuICB2YXIgciA9IHRoaXMucyAtIGEucztcbiAgaWYgKHIgIT0gMCkgcmV0dXJuIHI7XG4gIHZhciBpID0gdGhpcy50O1xuICByID0gaSAtIGEudDtcbiAgaWYgKHIgIT0gMCkgcmV0dXJuIHI7XG4gIHdoaWxlICgtLWkgPj0gMCkgaWYgKChyID0gdGhpc1tpXSAtIGFbaV0pICE9IDApIHJldHVybiByO1xuICByZXR1cm4gMDtcbn1cblxuLy8gcmV0dXJucyBiaXQgbGVuZ3RoIG9mIHRoZSBpbnRlZ2VyIHhcblxuZnVuY3Rpb24gbmJpdHMoeCkge1xuICB2YXIgciA9IDEsXG4gICAgdDtcbiAgaWYgKCh0ID0geCA+Pj4gMTYpICE9IDApIHtcbiAgICB4ID0gdDtcbiAgICByICs9IDE2O1xuICB9XG4gIGlmICgodCA9IHggPj4gOCkgIT0gMCkge1xuICAgIHggPSB0O1xuICAgIHIgKz0gODtcbiAgfVxuICBpZiAoKHQgPSB4ID4+IDQpICE9IDApIHtcbiAgICB4ID0gdDtcbiAgICByICs9IDQ7XG4gIH1cbiAgaWYgKCh0ID0geCA+PiAyKSAhPSAwKSB7XG4gICAgeCA9IHQ7XG4gICAgciArPSAyO1xuICB9XG4gIGlmICgodCA9IHggPj4gMSkgIT0gMCkge1xuICAgIHggPSB0O1xuICAgIHIgKz0gMTtcbiAgfVxuICByZXR1cm4gcjtcbn1cblxuLy8gKHB1YmxpYykgcmV0dXJuIHRoZSBudW1iZXIgb2YgYml0cyBpbiBcInRoaXNcIlxuXG5mdW5jdGlvbiBibkJpdExlbmd0aCgpIHtcbiAgaWYgKHRoaXMudCA8PSAwKSByZXR1cm4gMDtcbiAgcmV0dXJuIHRoaXMuREIgKiAodGhpcy50IC0gMSkgKyBuYml0cyh0aGlzW3RoaXMudCAtIDFdIF4gKHRoaXMucyAmIHRoaXMuRE0pKTtcbn1cblxuLy8gKHByb3RlY3RlZCkgciA9IHRoaXMgPDwgbipEQlxuXG5mdW5jdGlvbiBibnBETFNoaWZ0VG8obiwgcikge1xuICB2YXIgaTtcbiAgZm9yIChpID0gdGhpcy50IC0gMTsgaSA+PSAwOyAtLWkpIHJbaSArIG5dID0gdGhpc1tpXTtcbiAgZm9yIChpID0gbiAtIDE7IGkgPj0gMDsgLS1pKSByW2ldID0gMDtcbiAgci50ID0gdGhpcy50ICsgbjtcbiAgci5zID0gdGhpcy5zO1xufVxuXG4vLyAocHJvdGVjdGVkKSByID0gdGhpcyA+PiBuKkRCXG5cbmZ1bmN0aW9uIGJucERSU2hpZnRUbyhuLCByKSB7XG4gIGZvciAodmFyIGkgPSBuOyBpIDwgdGhpcy50OyArK2kpIHJbaSAtIG5dID0gdGhpc1tpXTtcbiAgci50ID0gTWF0aC5tYXgodGhpcy50IC0gbiwgMCk7XG4gIHIucyA9IHRoaXMucztcbn1cblxuLy8gKHByb3RlY3RlZCkgciA9IHRoaXMgPDwgblxuXG5mdW5jdGlvbiBibnBMU2hpZnRUbyhuLCByKSB7XG4gIHZhciBicyA9IG4gJSB0aGlzLkRCO1xuICB2YXIgY2JzID0gdGhpcy5EQiAtIGJzO1xuICB2YXIgYm0gPSAoMSA8PCBjYnMpIC0gMTtcbiAgdmFyIGRzID0gTWF0aC5mbG9vcihuIC8gdGhpcy5EQiksXG4gICAgYyA9ICh0aGlzLnMgPDwgYnMpICYgdGhpcy5ETSxcbiAgICBpO1xuICBmb3IgKGkgPSB0aGlzLnQgLSAxOyBpID49IDA7IC0taSkge1xuICAgIHJbaSArIGRzICsgMV0gPSAodGhpc1tpXSA+PiBjYnMpIHwgYztcbiAgICBjID0gKHRoaXNbaV0gJiBibSkgPDwgYnM7XG4gIH1cbiAgZm9yIChpID0gZHMgLSAxOyBpID49IDA7IC0taSkgcltpXSA9IDA7XG4gIHJbZHNdID0gYztcbiAgci50ID0gdGhpcy50ICsgZHMgKyAxO1xuICByLnMgPSB0aGlzLnM7XG4gIHIuY2xhbXAoKTtcbn1cblxuLy8gKHByb3RlY3RlZCkgciA9IHRoaXMgPj4gblxuXG5mdW5jdGlvbiBibnBSU2hpZnRUbyhuLCByKSB7XG4gIHIucyA9IHRoaXMucztcbiAgdmFyIGRzID0gTWF0aC5mbG9vcihuIC8gdGhpcy5EQik7XG4gIGlmIChkcyA+PSB0aGlzLnQpIHtcbiAgICByLnQgPSAwO1xuICAgIHJldHVybjtcbiAgfVxuICB2YXIgYnMgPSBuICUgdGhpcy5EQjtcbiAgdmFyIGNicyA9IHRoaXMuREIgLSBicztcbiAgdmFyIGJtID0gKDEgPDwgYnMpIC0gMTtcbiAgclswXSA9IHRoaXNbZHNdID4+IGJzO1xuICBmb3IgKHZhciBpID0gZHMgKyAxOyBpIDwgdGhpcy50OyArK2kpIHtcbiAgICByW2kgLSBkcyAtIDFdIHw9ICh0aGlzW2ldICYgYm0pIDw8IGNicztcbiAgICByW2kgLSBkc10gPSB0aGlzW2ldID4+IGJzO1xuICB9XG4gIGlmIChicyA+IDApIHJbdGhpcy50IC0gZHMgLSAxXSB8PSAodGhpcy5zICYgYm0pIDw8IGNicztcbiAgci50ID0gdGhpcy50IC0gZHM7XG4gIHIuY2xhbXAoKTtcbn1cblxuLy8gKHByb3RlY3RlZCkgciA9IHRoaXMgLSBhXG5cbmZ1bmN0aW9uIGJucFN1YlRvKGEsIHIpIHtcbiAgdmFyIGkgPSAwLFxuICAgIGMgPSAwLFxuICAgIG0gPSBNYXRoLm1pbihhLnQsIHRoaXMudCk7XG4gIHdoaWxlIChpIDwgbSkge1xuICAgIGMgKz0gdGhpc1tpXSAtIGFbaV07XG4gICAgcltpKytdID0gYyAmIHRoaXMuRE07XG4gICAgYyA+Pj0gdGhpcy5EQjtcbiAgfVxuICBpZiAoYS50IDwgdGhpcy50KSB7XG4gICAgYyAtPSBhLnM7XG4gICAgd2hpbGUgKGkgPCB0aGlzLnQpIHtcbiAgICAgIGMgKz0gdGhpc1tpXTtcbiAgICAgIHJbaSsrXSA9IGMgJiB0aGlzLkRNO1xuICAgICAgYyA+Pj0gdGhpcy5EQjtcbiAgICB9XG4gICAgYyArPSB0aGlzLnM7XG4gIH0gZWxzZSB7XG4gICAgYyArPSB0aGlzLnM7XG4gICAgd2hpbGUgKGkgPCBhLnQpIHtcbiAgICAgIGMgLT0gYVtpXTtcbiAgICAgIHJbaSsrXSA9IGMgJiB0aGlzLkRNO1xuICAgICAgYyA+Pj0gdGhpcy5EQjtcbiAgICB9XG4gICAgYyAtPSBhLnM7XG4gIH1cbiAgci5zID0gKGMgPCAwKSA/IC0xIDogMDtcbiAgaWYgKGMgPCAtMSkgcltpKytdID0gdGhpcy5EViArIGM7XG4gIGVsc2UgaWYgKGMgPiAwKSByW2krK10gPSBjO1xuICByLnQgPSBpO1xuICByLmNsYW1wKCk7XG59XG5cbi8vIChwcm90ZWN0ZWQpIHIgPSB0aGlzICogYSwgciAhPSB0aGlzLGEgKEhBQyAxNC4xMilcbi8vIFwidGhpc1wiIHNob3VsZCBiZSB0aGUgbGFyZ2VyIG9uZSBpZiBhcHByb3ByaWF0ZS5cblxuZnVuY3Rpb24gYm5wTXVsdGlwbHlUbyhhLCByKSB7XG4gIHZhciB4ID0gdGhpcy5hYnMoKSxcbiAgICB5ID0gYS5hYnMoKTtcbiAgdmFyIGkgPSB4LnQ7XG4gIHIudCA9IGkgKyB5LnQ7XG4gIHdoaWxlICgtLWkgPj0gMCkgcltpXSA9IDA7XG4gIGZvciAoaSA9IDA7IGkgPCB5LnQ7ICsraSkgcltpICsgeC50XSA9IHguYW0oMCwgeVtpXSwgciwgaSwgMCwgeC50KTtcbiAgci5zID0gMDtcbiAgci5jbGFtcCgpO1xuICBpZiAodGhpcy5zICE9IGEucykgQmlnSW50ZWdlci5aRVJPLnN1YlRvKHIsIHIpO1xufVxuXG4vLyAocHJvdGVjdGVkKSByID0gdGhpc14yLCByICE9IHRoaXMgKEhBQyAxNC4xNilcblxuZnVuY3Rpb24gYm5wU3F1YXJlVG8ocikge1xuICB2YXIgeCA9IHRoaXMuYWJzKCk7XG4gIHZhciBpID0gci50ID0gMiAqIHgudDtcbiAgd2hpbGUgKC0taSA+PSAwKSByW2ldID0gMDtcbiAgZm9yIChpID0gMDsgaSA8IHgudCAtIDE7ICsraSkge1xuICAgIHZhciBjID0geC5hbShpLCB4W2ldLCByLCAyICogaSwgMCwgMSk7XG4gICAgaWYgKChyW2kgKyB4LnRdICs9IHguYW0oaSArIDEsIDIgKiB4W2ldLCByLCAyICogaSArIDEsIGMsIHgudCAtIGkgLSAxKSkgPj0geC5EVikge1xuICAgICAgcltpICsgeC50XSAtPSB4LkRWO1xuICAgICAgcltpICsgeC50ICsgMV0gPSAxO1xuICAgIH1cbiAgfVxuICBpZiAoci50ID4gMCkgcltyLnQgLSAxXSArPSB4LmFtKGksIHhbaV0sIHIsIDIgKiBpLCAwLCAxKTtcbiAgci5zID0gMDtcbiAgci5jbGFtcCgpO1xufVxuXG4vLyAocHJvdGVjdGVkKSBkaXZpZGUgdGhpcyBieSBtLCBxdW90aWVudCBhbmQgcmVtYWluZGVyIHRvIHEsIHIgKEhBQyAxNC4yMClcbi8vIHIgIT0gcSwgdGhpcyAhPSBtLiAgcSBvciByIG1heSBiZSBudWxsLlxuXG5mdW5jdGlvbiBibnBEaXZSZW1UbyhtLCBxLCByKSB7XG4gIHZhciBwbSA9IG0uYWJzKCk7XG4gIGlmIChwbS50IDw9IDApIHJldHVybjtcbiAgdmFyIHB0ID0gdGhpcy5hYnMoKTtcbiAgaWYgKHB0LnQgPCBwbS50KSB7XG4gICAgaWYgKHEgIT0gbnVsbCkgcS5mcm9tSW50KDApO1xuICAgIGlmIChyICE9IG51bGwpIHRoaXMuY29weVRvKHIpO1xuICAgIHJldHVybjtcbiAgfVxuICBpZiAociA9PSBudWxsKSByID0gbmJpKCk7XG4gIHZhciB5ID0gbmJpKCksXG4gICAgdHMgPSB0aGlzLnMsXG4gICAgbXMgPSBtLnM7XG4gIHZhciBuc2ggPSB0aGlzLkRCIC0gbmJpdHMocG1bcG0udCAtIDFdKTsgLy8gbm9ybWFsaXplIG1vZHVsdXNcbiAgaWYgKG5zaCA+IDApIHtcbiAgICBwbS5sU2hpZnRUbyhuc2gsIHkpO1xuICAgIHB0LmxTaGlmdFRvKG5zaCwgcik7XG4gIH0gZWxzZSB7XG4gICAgcG0uY29weVRvKHkpO1xuICAgIHB0LmNvcHlUbyhyKTtcbiAgfVxuICB2YXIgeXMgPSB5LnQ7XG4gIHZhciB5MCA9IHlbeXMgLSAxXTtcbiAgaWYgKHkwID09IDApIHJldHVybjtcbiAgdmFyIHl0ID0geTAgKiAoMSA8PCB0aGlzLkYxKSArICgoeXMgPiAxKSA/IHlbeXMgLSAyXSA+PiB0aGlzLkYyIDogMCk7XG4gIHZhciBkMSA9IHRoaXMuRlYgLyB5dCxcbiAgICBkMiA9ICgxIDw8IHRoaXMuRjEpIC8geXQsXG4gICAgZSA9IDEgPDwgdGhpcy5GMjtcbiAgdmFyIGkgPSByLnQsXG4gICAgaiA9IGkgLSB5cyxcbiAgICB0ID0gKHEgPT0gbnVsbCkgPyBuYmkoKSA6IHE7XG4gIHkuZGxTaGlmdFRvKGosIHQpO1xuICBpZiAoci5jb21wYXJlVG8odCkgPj0gMCkge1xuICAgIHJbci50KytdID0gMTtcbiAgICByLnN1YlRvKHQsIHIpO1xuICB9XG4gIEJpZ0ludGVnZXIuT05FLmRsU2hpZnRUbyh5cywgdCk7XG4gIHQuc3ViVG8oeSwgeSk7IC8vIFwibmVnYXRpdmVcIiB5IHNvIHdlIGNhbiByZXBsYWNlIHN1YiB3aXRoIGFtIGxhdGVyXG4gIHdoaWxlICh5LnQgPCB5cykgeVt5LnQrK10gPSAwO1xuICB3aGlsZSAoLS1qID49IDApIHtcbiAgICAvLyBFc3RpbWF0ZSBxdW90aWVudCBkaWdpdFxuICAgIHZhciBxZCA9IChyWy0taV0gPT0geTApID8gdGhpcy5ETSA6IE1hdGguZmxvb3IocltpXSAqIGQxICsgKHJbaSAtIDFdICsgZSkgKiBkMik7XG4gICAgaWYgKChyW2ldICs9IHkuYW0oMCwgcWQsIHIsIGosIDAsIHlzKSkgPCBxZCkgeyAvLyBUcnkgaXQgb3V0XG4gICAgICB5LmRsU2hpZnRUbyhqLCB0KTtcbiAgICAgIHIuc3ViVG8odCwgcik7XG4gICAgICB3aGlsZSAocltpXSA8IC0tcWQpIHIuc3ViVG8odCwgcik7XG4gICAgfVxuICB9XG4gIGlmIChxICE9IG51bGwpIHtcbiAgICByLmRyU2hpZnRUbyh5cywgcSk7XG4gICAgaWYgKHRzICE9IG1zKSBCaWdJbnRlZ2VyLlpFUk8uc3ViVG8ocSwgcSk7XG4gIH1cbiAgci50ID0geXM7XG4gIHIuY2xhbXAoKTtcbiAgaWYgKG5zaCA+IDApIHIuclNoaWZ0VG8obnNoLCByKTsgLy8gRGVub3JtYWxpemUgcmVtYWluZGVyXG4gIGlmICh0cyA8IDApIEJpZ0ludGVnZXIuWkVSTy5zdWJUbyhyLCByKTtcbn1cblxuLy8gKHB1YmxpYykgdGhpcyBtb2QgYVxuXG5mdW5jdGlvbiBibk1vZChhKSB7XG4gIHZhciByID0gbmJpKCk7XG4gIHRoaXMuYWJzKCkuZGl2UmVtVG8oYSwgbnVsbCwgcik7XG4gIGlmICh0aGlzLnMgPCAwICYmIHIuY29tcGFyZVRvKEJpZ0ludGVnZXIuWkVSTykgPiAwKSBhLnN1YlRvKHIsIHIpO1xuICByZXR1cm4gcjtcbn1cblxuLy8gTW9kdWxhciByZWR1Y3Rpb24gdXNpbmcgXCJjbGFzc2ljXCIgYWxnb3JpdGhtXG5cbmZ1bmN0aW9uIENsYXNzaWMobSkge1xuICB0aGlzLm0gPSBtO1xufVxuXG5mdW5jdGlvbiBjQ29udmVydCh4KSB7XG4gIGlmICh4LnMgPCAwIHx8IHguY29tcGFyZVRvKHRoaXMubSkgPj0gMCkgcmV0dXJuIHgubW9kKHRoaXMubSk7XG4gIGVsc2UgcmV0dXJuIHg7XG59XG5cbmZ1bmN0aW9uIGNSZXZlcnQoeCkge1xuICByZXR1cm4geDtcbn1cblxuZnVuY3Rpb24gY1JlZHVjZSh4KSB7XG4gIHguZGl2UmVtVG8odGhpcy5tLCBudWxsLCB4KTtcbn1cblxuZnVuY3Rpb24gY011bFRvKHgsIHksIHIpIHtcbiAgeC5tdWx0aXBseVRvKHksIHIpO1xuICB0aGlzLnJlZHVjZShyKTtcbn1cblxuZnVuY3Rpb24gY1NxclRvKHgsIHIpIHtcbiAgeC5zcXVhcmVUbyhyKTtcbiAgdGhpcy5yZWR1Y2Uocik7XG59XG5cbkNsYXNzaWMucHJvdG90eXBlLmNvbnZlcnQgPSBjQ29udmVydDtcbkNsYXNzaWMucHJvdG90eXBlLnJldmVydCA9IGNSZXZlcnQ7XG5DbGFzc2ljLnByb3RvdHlwZS5yZWR1Y2UgPSBjUmVkdWNlO1xuQ2xhc3NpYy5wcm90b3R5cGUubXVsVG8gPSBjTXVsVG87XG5DbGFzc2ljLnByb3RvdHlwZS5zcXJUbyA9IGNTcXJUbztcblxuLy8gKHByb3RlY3RlZCkgcmV0dXJuIFwiLTEvdGhpcyAlIDJeREJcIjsgdXNlZnVsIGZvciBNb250LiByZWR1Y3Rpb25cbi8vIGp1c3RpZmljYXRpb246XG4vLyAgICAgICAgIHh5ID09IDEgKG1vZCBtKVxuLy8gICAgICAgICB4eSA9ICAxK2ttXG4vLyAgIHh5KDIteHkpID0gKDEra20pKDEta20pXG4vLyB4W3koMi14eSldID0gMS1rXjJtXjJcbi8vIHhbeSgyLXh5KV0gPT0gMSAobW9kIG1eMilcbi8vIGlmIHkgaXMgMS94IG1vZCBtLCB0aGVuIHkoMi14eSkgaXMgMS94IG1vZCBtXjJcbi8vIHNob3VsZCByZWR1Y2UgeCBhbmQgeSgyLXh5KSBieSBtXjIgYXQgZWFjaCBzdGVwIHRvIGtlZXAgc2l6ZSBib3VuZGVkLlxuLy8gSlMgbXVsdGlwbHkgXCJvdmVyZmxvd3NcIiBkaWZmZXJlbnRseSBmcm9tIEMvQysrLCBzbyBjYXJlIGlzIG5lZWRlZCBoZXJlLlxuXG5mdW5jdGlvbiBibnBJbnZEaWdpdCgpIHtcbiAgaWYgKHRoaXMudCA8IDEpIHJldHVybiAwO1xuICB2YXIgeCA9IHRoaXNbMF07XG4gIGlmICgoeCAmIDEpID09IDApIHJldHVybiAwO1xuICB2YXIgeSA9IHggJiAzOyAvLyB5ID09IDEveCBtb2QgMl4yXG4gIHkgPSAoeSAqICgyIC0gKHggJiAweGYpICogeSkpICYgMHhmOyAvLyB5ID09IDEveCBtb2QgMl40XG4gIHkgPSAoeSAqICgyIC0gKHggJiAweGZmKSAqIHkpKSAmIDB4ZmY7IC8vIHkgPT0gMS94IG1vZCAyXjhcbiAgeSA9ICh5ICogKDIgLSAoKCh4ICYgMHhmZmZmKSAqIHkpICYgMHhmZmZmKSkpICYgMHhmZmZmOyAvLyB5ID09IDEveCBtb2QgMl4xNlxuICAvLyBsYXN0IHN0ZXAgLSBjYWxjdWxhdGUgaW52ZXJzZSBtb2QgRFYgZGlyZWN0bHk7XG4gIC8vIGFzc3VtZXMgMTYgPCBEQiA8PSAzMiBhbmQgYXNzdW1lcyBhYmlsaXR5IHRvIGhhbmRsZSA0OC1iaXQgaW50c1xuICB5ID0gKHkgKiAoMiAtIHggKiB5ICUgdGhpcy5EVikpICUgdGhpcy5EVjsgLy8geSA9PSAxL3ggbW9kIDJeZGJpdHNcbiAgLy8gd2UgcmVhbGx5IHdhbnQgdGhlIG5lZ2F0aXZlIGludmVyc2UsIGFuZCAtRFYgPCB5IDwgRFZcbiAgcmV0dXJuICh5ID4gMCkgPyB0aGlzLkRWIC0geSA6IC15O1xufVxuXG4vLyBNb250Z29tZXJ5IHJlZHVjdGlvblxuXG5mdW5jdGlvbiBNb250Z29tZXJ5KG0pIHtcbiAgdGhpcy5tID0gbTtcbiAgdGhpcy5tcCA9IG0uaW52RGlnaXQoKTtcbiAgdGhpcy5tcGwgPSB0aGlzLm1wICYgMHg3ZmZmO1xuICB0aGlzLm1waCA9IHRoaXMubXAgPj4gMTU7XG4gIHRoaXMudW0gPSAoMSA8PCAobS5EQiAtIDE1KSkgLSAxO1xuICB0aGlzLm10MiA9IDIgKiBtLnQ7XG59XG5cbi8vIHhSIG1vZCBtXG5cbmZ1bmN0aW9uIG1vbnRDb252ZXJ0KHgpIHtcbiAgdmFyIHIgPSBuYmkoKTtcbiAgeC5hYnMoKS5kbFNoaWZ0VG8odGhpcy5tLnQsIHIpO1xuICByLmRpdlJlbVRvKHRoaXMubSwgbnVsbCwgcik7XG4gIGlmICh4LnMgPCAwICYmIHIuY29tcGFyZVRvKEJpZ0ludGVnZXIuWkVSTykgPiAwKSB0aGlzLm0uc3ViVG8ociwgcik7XG4gIHJldHVybiByO1xufVxuXG4vLyB4L1IgbW9kIG1cblxuZnVuY3Rpb24gbW9udFJldmVydCh4KSB7XG4gIHZhciByID0gbmJpKCk7XG4gIHguY29weVRvKHIpO1xuICB0aGlzLnJlZHVjZShyKTtcbiAgcmV0dXJuIHI7XG59XG5cbi8vIHggPSB4L1IgbW9kIG0gKEhBQyAxNC4zMilcblxuZnVuY3Rpb24gbW9udFJlZHVjZSh4KSB7XG4gIHdoaWxlICh4LnQgPD0gdGhpcy5tdDIpIC8vIHBhZCB4IHNvIGFtIGhhcyBlbm91Z2ggcm9vbSBsYXRlclxuICAgIHhbeC50KytdID0gMDtcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLm0udDsgKytpKSB7XG4gICAgLy8gZmFzdGVyIHdheSBvZiBjYWxjdWxhdGluZyB1MCA9IHhbaV0qbXAgbW9kIERWXG4gICAgdmFyIGogPSB4W2ldICYgMHg3ZmZmO1xuICAgIHZhciB1MCA9IChqICogdGhpcy5tcGwgKyAoKChqICogdGhpcy5tcGggKyAoeFtpXSA+PiAxNSkgKiB0aGlzLm1wbCkgJiB0aGlzLnVtKSA8PCAxNSkpICYgeC5ETTtcbiAgICAvLyB1c2UgYW0gdG8gY29tYmluZSB0aGUgbXVsdGlwbHktc2hpZnQtYWRkIGludG8gb25lIGNhbGxcbiAgICBqID0gaSArIHRoaXMubS50O1xuICAgIHhbal0gKz0gdGhpcy5tLmFtKDAsIHUwLCB4LCBpLCAwLCB0aGlzLm0udCk7XG4gICAgLy8gcHJvcGFnYXRlIGNhcnJ5XG4gICAgd2hpbGUgKHhbal0gPj0geC5EVikge1xuICAgICAgeFtqXSAtPSB4LkRWO1xuICAgICAgeFsrK2pdKys7XG4gICAgfVxuICB9XG4gIHguY2xhbXAoKTtcbiAgeC5kclNoaWZ0VG8odGhpcy5tLnQsIHgpO1xuICBpZiAoeC5jb21wYXJlVG8odGhpcy5tKSA+PSAwKSB4LnN1YlRvKHRoaXMubSwgeCk7XG59XG5cbi8vIHIgPSBcInheMi9SIG1vZCBtXCI7IHggIT0gclxuXG5mdW5jdGlvbiBtb250U3FyVG8oeCwgcikge1xuICB4LnNxdWFyZVRvKHIpO1xuICB0aGlzLnJlZHVjZShyKTtcbn1cblxuLy8gciA9IFwieHkvUiBtb2QgbVwiOyB4LHkgIT0gclxuXG5mdW5jdGlvbiBtb250TXVsVG8oeCwgeSwgcikge1xuICB4Lm11bHRpcGx5VG8oeSwgcik7XG4gIHRoaXMucmVkdWNlKHIpO1xufVxuXG5Nb250Z29tZXJ5LnByb3RvdHlwZS5jb252ZXJ0ID0gbW9udENvbnZlcnQ7XG5Nb250Z29tZXJ5LnByb3RvdHlwZS5yZXZlcnQgPSBtb250UmV2ZXJ0O1xuTW9udGdvbWVyeS5wcm90b3R5cGUucmVkdWNlID0gbW9udFJlZHVjZTtcbk1vbnRnb21lcnkucHJvdG90eXBlLm11bFRvID0gbW9udE11bFRvO1xuTW9udGdvbWVyeS5wcm90b3R5cGUuc3FyVG8gPSBtb250U3FyVG87XG5cbi8vIChwcm90ZWN0ZWQpIHRydWUgaWZmIHRoaXMgaXMgZXZlblxuXG5mdW5jdGlvbiBibnBJc0V2ZW4oKSB7XG4gIHJldHVybiAoKHRoaXMudCA+IDApID8gKHRoaXNbMF0gJiAxKSA6IHRoaXMucykgPT0gMDtcbn1cblxuLy8gKHByb3RlY3RlZCkgdGhpc15lLCBlIDwgMl4zMiwgZG9pbmcgc3FyIGFuZCBtdWwgd2l0aCBcInJcIiAoSEFDIDE0Ljc5KVxuXG5mdW5jdGlvbiBibnBFeHAoZSwgeikge1xuICBpZiAoZSA+IDB4ZmZmZmZmZmYgfHwgZSA8IDEpIHJldHVybiBCaWdJbnRlZ2VyLk9ORTtcbiAgdmFyIHIgPSBuYmkoKSxcbiAgICByMiA9IG5iaSgpLFxuICAgIGcgPSB6LmNvbnZlcnQodGhpcyksXG4gICAgaSA9IG5iaXRzKGUpIC0gMTtcbiAgZy5jb3B5VG8ocik7XG4gIHdoaWxlICgtLWkgPj0gMCkge1xuICAgIHouc3FyVG8ociwgcjIpO1xuICAgIGlmICgoZSAmICgxIDw8IGkpKSA+IDApIHoubXVsVG8ocjIsIGcsIHIpO1xuICAgIGVsc2Uge1xuICAgICAgdmFyIHQgPSByO1xuICAgICAgciA9IHIyO1xuICAgICAgcjIgPSB0O1xuICAgIH1cbiAgfVxuICByZXR1cm4gei5yZXZlcnQocik7XG59XG5cbi8vIChwdWJsaWMpIHRoaXNeZSAlIG0sIDAgPD0gZSA8IDJeMzJcblxuZnVuY3Rpb24gYm5Nb2RQb3dJbnQoZSwgbSkge1xuICB2YXIgejtcbiAgaWYgKGUgPCAyNTYgfHwgbS5pc0V2ZW4oKSkgeiA9IG5ldyBDbGFzc2ljKG0pO1xuICBlbHNlIHogPSBuZXcgTW9udGdvbWVyeShtKTtcbiAgcmV0dXJuIHRoaXMuZXhwKGUsIHopO1xufVxuXG4vLyBwcm90ZWN0ZWRcbkJpZ0ludGVnZXIucHJvdG90eXBlLmNvcHlUbyA9IGJucENvcHlUbztcbkJpZ0ludGVnZXIucHJvdG90eXBlLmZyb21JbnQgPSBibnBGcm9tSW50O1xuQmlnSW50ZWdlci5wcm90b3R5cGUuZnJvbVN0cmluZyA9IGJucEZyb21TdHJpbmc7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5jbGFtcCA9IGJucENsYW1wO1xuQmlnSW50ZWdlci5wcm90b3R5cGUuZGxTaGlmdFRvID0gYm5wRExTaGlmdFRvO1xuQmlnSW50ZWdlci5wcm90b3R5cGUuZHJTaGlmdFRvID0gYm5wRFJTaGlmdFRvO1xuQmlnSW50ZWdlci5wcm90b3R5cGUubFNoaWZ0VG8gPSBibnBMU2hpZnRUbztcbkJpZ0ludGVnZXIucHJvdG90eXBlLnJTaGlmdFRvID0gYm5wUlNoaWZ0VG87XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5zdWJUbyA9IGJucFN1YlRvO1xuQmlnSW50ZWdlci5wcm90b3R5cGUubXVsdGlwbHlUbyA9IGJucE11bHRpcGx5VG87XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5zcXVhcmVUbyA9IGJucFNxdWFyZVRvO1xuQmlnSW50ZWdlci5wcm90b3R5cGUuZGl2UmVtVG8gPSBibnBEaXZSZW1UbztcbkJpZ0ludGVnZXIucHJvdG90eXBlLmludkRpZ2l0ID0gYm5wSW52RGlnaXQ7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5pc0V2ZW4gPSBibnBJc0V2ZW47XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5leHAgPSBibnBFeHA7XG5cbi8vIHB1YmxpY1xuQmlnSW50ZWdlci5wcm90b3R5cGUudG9TdHJpbmcgPSBiblRvU3RyaW5nO1xuQmlnSW50ZWdlci5wcm90b3R5cGUubmVnYXRlID0gYm5OZWdhdGU7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5hYnMgPSBibkFicztcbkJpZ0ludGVnZXIucHJvdG90eXBlLmNvbXBhcmVUbyA9IGJuQ29tcGFyZVRvO1xuQmlnSW50ZWdlci5wcm90b3R5cGUuYml0TGVuZ3RoID0gYm5CaXRMZW5ndGg7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5tb2QgPSBibk1vZDtcbkJpZ0ludGVnZXIucHJvdG90eXBlLm1vZFBvd0ludCA9IGJuTW9kUG93SW50O1xuXG4vLyBcImNvbnN0YW50c1wiXG5CaWdJbnRlZ2VyLlpFUk8gPSBuYnYoMCk7XG5CaWdJbnRlZ2VyLk9ORSA9IG5idigxKTtcblxubW9kdWxlLmV4cG9ydHMgPSBCaWdJbnRlZ2VyO1xuXG5cblxuXG5cblxuXG5cblxuXG5cblxuXG5cblxuXG5cblxuXG4vKlxuICogQ29weXJpZ2h0IChjKSAyMDAzLTIwMDUgIFRvbSBXdSAodGp3QGNzLlN0YW5mb3JkLkVEVSkgXG4gKiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICpcbiAqIE1vZGlmaWVkIGJ5IFJlY3VyaXR5IExhYnMgR21iSFxuICpcbiAqIFBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZ1xuICogYSBjb3B5IG9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQgZG9jdW1lbnRhdGlvbiBmaWxlcyAodGhlXG4gKiBcIlNvZnR3YXJlXCIpLCB0byBkZWFsIGluIHRoZSBTb2Z0d2FyZSB3aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmdcbiAqIHdpdGhvdXQgbGltaXRhdGlvbiB0aGUgcmlnaHRzIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCxcbiAqIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsIGFuZC9vciBzZWxsIGNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0b1xuICogcGVybWl0IHBlcnNvbnMgdG8gd2hvbSB0aGUgU29mdHdhcmUgaXMgZnVybmlzaGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRvXG4gKiB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6XG4gKlxuICogVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmVcbiAqIGluY2x1ZGVkIGluIGFsbCBjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMgb2YgdGhlIFNvZnR3YXJlLlxuICpcbiAqIFRIRSBTT0ZUV0FSRSBJUyBQUk9WSURFRCBcIkFTLUlTXCIgQU5EIFdJVEhPVVQgV0FSUkFOVFkgT0YgQU5ZIEtJTkQsIFxuICogRVhQUkVTUywgSU1QTElFRCBPUiBPVEhFUldJU0UsIElOQ0xVRElORyBXSVRIT1VUIExJTUlUQVRJT04sIEFOWSBcbiAqIFdBUlJBTlRZIE9GIE1FUkNIQU5UQUJJTElUWSBPUiBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFxuICpcbiAqIElOIE5PIEVWRU5UIFNIQUxMIFRPTSBXVSBCRSBMSUFCTEUgRk9SIEFOWSBTUEVDSUFMLCBJTkNJREVOVEFMLFxuICogSU5ESVJFQ1QgT1IgQ09OU0VRVUVOVElBTCBEQU1BR0VTIE9GIEFOWSBLSU5ELCBPUiBBTlkgREFNQUdFUyBXSEFUU09FVkVSXG4gKiBSRVNVTFRJTkcgRlJPTSBMT1NTIE9GIFVTRSwgREFUQSBPUiBQUk9GSVRTLCBXSEVUSEVSIE9SIE5PVCBBRFZJU0VEIE9GXG4gKiBUSEUgUE9TU0lCSUxJVFkgT0YgREFNQUdFLCBBTkQgT04gQU5ZIFRIRU9SWSBPRiBMSUFCSUxJVFksIEFSSVNJTkcgT1VUXG4gKiBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFIFVTRSBPUiBQRVJGT1JNQU5DRSBPRiBUSElTIFNPRlRXQVJFLlxuICpcbiAqIEluIGFkZGl0aW9uLCB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbiBhcHBsaWVzOlxuICpcbiAqIEFsbCByZWRpc3RyaWJ1dGlvbnMgbXVzdCByZXRhaW4gYW4gaW50YWN0IGNvcHkgb2YgdGhpcyBjb3B5cmlnaHQgbm90aWNlXG4gKiBhbmQgZGlzY2xhaW1lci5cbiAqL1xuXG5cbi8vIEV4dGVuZGVkIEphdmFTY3JpcHQgQk4gZnVuY3Rpb25zLCByZXF1aXJlZCBmb3IgUlNBIHByaXZhdGUgb3BzLlxuXG4vLyBWZXJzaW9uIDEuMTogbmV3IEJpZ0ludGVnZXIoXCIwXCIsIDEwKSByZXR1cm5zIFwicHJvcGVyXCIgemVyb1xuLy8gVmVyc2lvbiAxLjI6IHNxdWFyZSgpIEFQSSwgaXNQcm9iYWJsZVByaW1lIGZpeFxuXG4vLyAocHVibGljKVxuZnVuY3Rpb24gYm5DbG9uZSgpIHtcbiAgdmFyIHIgPSBuYmkoKTtcbiAgdGhpcy5jb3B5VG8ocik7XG4gIHJldHVybiByO1xufVxuXG4vLyAocHVibGljKSByZXR1cm4gdmFsdWUgYXMgaW50ZWdlclxuXG5mdW5jdGlvbiBibkludFZhbHVlKCkge1xuICBpZiAodGhpcy5zIDwgMCkge1xuICAgIGlmICh0aGlzLnQgPT0gMSkgcmV0dXJuIHRoaXNbMF0gLSB0aGlzLkRWO1xuICAgIGVsc2UgaWYgKHRoaXMudCA9PSAwKSByZXR1cm4gLTE7XG4gIH0gZWxzZSBpZiAodGhpcy50ID09IDEpIHJldHVybiB0aGlzWzBdO1xuICBlbHNlIGlmICh0aGlzLnQgPT0gMCkgcmV0dXJuIDA7XG4gIC8vIGFzc3VtZXMgMTYgPCBEQiA8IDMyXG4gIHJldHVybiAoKHRoaXNbMV0gJiAoKDEgPDwgKDMyIC0gdGhpcy5EQikpIC0gMSkpIDw8IHRoaXMuREIpIHwgdGhpc1swXTtcbn1cblxuLy8gKHB1YmxpYykgcmV0dXJuIHZhbHVlIGFzIGJ5dGVcblxuZnVuY3Rpb24gYm5CeXRlVmFsdWUoKSB7XG4gIHJldHVybiAodGhpcy50ID09IDApID8gdGhpcy5zIDogKHRoaXNbMF0gPDwgMjQpID4+IDI0O1xufVxuXG4vLyAocHVibGljKSByZXR1cm4gdmFsdWUgYXMgc2hvcnQgKGFzc3VtZXMgREI+PTE2KVxuXG5mdW5jdGlvbiBiblNob3J0VmFsdWUoKSB7XG4gIHJldHVybiAodGhpcy50ID09IDApID8gdGhpcy5zIDogKHRoaXNbMF0gPDwgMTYpID4+IDE2O1xufVxuXG4vLyAocHJvdGVjdGVkKSByZXR1cm4geCBzLnQuIHJeeCA8IERWXG5cbmZ1bmN0aW9uIGJucENodW5rU2l6ZShyKSB7XG4gIHJldHVybiBNYXRoLmZsb29yKE1hdGguTE4yICogdGhpcy5EQiAvIE1hdGgubG9nKHIpKTtcbn1cblxuLy8gKHB1YmxpYykgMCBpZiB0aGlzID09IDAsIDEgaWYgdGhpcyA+IDBcblxuZnVuY3Rpb24gYm5TaWdOdW0oKSB7XG4gIGlmICh0aGlzLnMgPCAwKSByZXR1cm4gLTE7XG4gIGVsc2UgaWYgKHRoaXMudCA8PSAwIHx8ICh0aGlzLnQgPT0gMSAmJiB0aGlzWzBdIDw9IDApKSByZXR1cm4gMDtcbiAgZWxzZSByZXR1cm4gMTtcbn1cblxuLy8gKHByb3RlY3RlZCkgY29udmVydCB0byByYWRpeCBzdHJpbmdcblxuZnVuY3Rpb24gYm5wVG9SYWRpeChiKSB7XG4gIGlmIChiID09IG51bGwpIGIgPSAxMDtcbiAgaWYgKHRoaXMuc2lnbnVtKCkgPT0gMCB8fCBiIDwgMiB8fCBiID4gMzYpIHJldHVybiBcIjBcIjtcbiAgdmFyIGNzID0gdGhpcy5jaHVua1NpemUoYik7XG4gIHZhciBhID0gTWF0aC5wb3coYiwgY3MpO1xuICB2YXIgZCA9IG5idihhKSxcbiAgICB5ID0gbmJpKCksXG4gICAgeiA9IG5iaSgpLFxuICAgIHIgPSBcIlwiO1xuICB0aGlzLmRpdlJlbVRvKGQsIHksIHopO1xuICB3aGlsZSAoeS5zaWdudW0oKSA+IDApIHtcbiAgICByID0gKGEgKyB6LmludFZhbHVlKCkpLnRvU3RyaW5nKGIpLnN1YnN0cigxKSArIHI7XG4gICAgeS5kaXZSZW1UbyhkLCB5LCB6KTtcbiAgfVxuICByZXR1cm4gei5pbnRWYWx1ZSgpLnRvU3RyaW5nKGIpICsgcjtcbn1cblxuLy8gKHByb3RlY3RlZCkgY29udmVydCBmcm9tIHJhZGl4IHN0cmluZ1xuXG5mdW5jdGlvbiBibnBGcm9tUmFkaXgocywgYikge1xuICB0aGlzLmZyb21JbnQoMCk7XG4gIGlmIChiID09IG51bGwpIGIgPSAxMDtcbiAgdmFyIGNzID0gdGhpcy5jaHVua1NpemUoYik7XG4gIHZhciBkID0gTWF0aC5wb3coYiwgY3MpLFxuICAgIG1pID0gZmFsc2UsXG4gICAgaiA9IDAsXG4gICAgdyA9IDA7XG4gIGZvciAodmFyIGkgPSAwOyBpIDwgcy5sZW5ndGg7ICsraSkge1xuICAgIHZhciB4ID0gaW50QXQocywgaSk7XG4gICAgaWYgKHggPCAwKSB7XG4gICAgICBpZiAocy5jaGFyQXQoaSkgPT0gXCItXCIgJiYgdGhpcy5zaWdudW0oKSA9PSAwKSBtaSA9IHRydWU7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG4gICAgdyA9IGIgKiB3ICsgeDtcbiAgICBpZiAoKytqID49IGNzKSB7XG4gICAgICB0aGlzLmRNdWx0aXBseShkKTtcbiAgICAgIHRoaXMuZEFkZE9mZnNldCh3LCAwKTtcbiAgICAgIGogPSAwO1xuICAgICAgdyA9IDA7XG4gICAgfVxuICB9XG4gIGlmIChqID4gMCkge1xuICAgIHRoaXMuZE11bHRpcGx5KE1hdGgucG93KGIsIGopKTtcbiAgICB0aGlzLmRBZGRPZmZzZXQodywgMCk7XG4gIH1cbiAgaWYgKG1pKSBCaWdJbnRlZ2VyLlpFUk8uc3ViVG8odGhpcywgdGhpcyk7XG59XG5cbi8vIChwcm90ZWN0ZWQpIGFsdGVybmF0ZSBjb25zdHJ1Y3RvclxuXG5mdW5jdGlvbiBibnBGcm9tTnVtYmVyKGEsIGIsIGMpIHtcbiAgaWYgKFwibnVtYmVyXCIgPT0gdHlwZW9mIGIpIHtcbiAgICAvLyBuZXcgQmlnSW50ZWdlcihpbnQsaW50LFJORylcbiAgICBpZiAoYSA8IDIpIHRoaXMuZnJvbUludCgxKTtcbiAgICBlbHNlIHtcbiAgICAgIHRoaXMuZnJvbU51bWJlcihhLCBjKTtcbiAgICAgIGlmICghdGhpcy50ZXN0Qml0KGEgLSAxKSkgLy8gZm9yY2UgTVNCIHNldFxuICAgICAgICB0aGlzLmJpdHdpc2VUbyhCaWdJbnRlZ2VyLk9ORS5zaGlmdExlZnQoYSAtIDEpLCBvcF9vciwgdGhpcyk7XG4gICAgICBpZiAodGhpcy5pc0V2ZW4oKSkgdGhpcy5kQWRkT2Zmc2V0KDEsIDApOyAvLyBmb3JjZSBvZGRcbiAgICAgIHdoaWxlICghdGhpcy5pc1Byb2JhYmxlUHJpbWUoYikpIHtcbiAgICAgICAgdGhpcy5kQWRkT2Zmc2V0KDIsIDApO1xuICAgICAgICBpZiAodGhpcy5iaXRMZW5ndGgoKSA+IGEpIHRoaXMuc3ViVG8oQmlnSW50ZWdlci5PTkUuc2hpZnRMZWZ0KGEgLSAxKSwgdGhpcyk7XG4gICAgICB9XG4gICAgfVxuICB9IGVsc2Uge1xuICAgIC8vIG5ldyBCaWdJbnRlZ2VyKGludCxSTkcpXG4gICAgdmFyIHggPSBuZXcgQXJyYXkoKSxcbiAgICAgIHQgPSBhICYgNztcbiAgICB4Lmxlbmd0aCA9IChhID4+IDMpICsgMTtcbiAgICBiLm5leHRCeXRlcyh4KTtcbiAgICBpZiAodCA+IDApIHhbMF0gJj0gKCgxIDw8IHQpIC0gMSk7XG4gICAgZWxzZSB4WzBdID0gMDtcbiAgICB0aGlzLmZyb21TdHJpbmcoeCwgMjU2KTtcbiAgfVxufVxuXG4vLyAocHVibGljKSBjb252ZXJ0IHRvIGJpZ2VuZGlhbiBieXRlIGFycmF5XG5cbmZ1bmN0aW9uIGJuVG9CeXRlQXJyYXkoKSB7XG4gIHZhciBpID0gdGhpcy50LFxuICAgIHIgPSBuZXcgQXJyYXkoKTtcbiAgclswXSA9IHRoaXMucztcbiAgdmFyIHAgPSB0aGlzLkRCIC0gKGkgKiB0aGlzLkRCKSAlIDgsXG4gICAgZCwgayA9IDA7XG4gIGlmIChpLS0gPiAwKSB7XG4gICAgaWYgKHAgPCB0aGlzLkRCICYmIChkID0gdGhpc1tpXSA+PiBwKSAhPSAodGhpcy5zICYgdGhpcy5ETSkgPj4gcClcbiAgICAgIHJbaysrXSA9IGQgfCAodGhpcy5zIDw8ICh0aGlzLkRCIC0gcCkpO1xuICAgIHdoaWxlIChpID49IDApIHtcbiAgICAgIGlmIChwIDwgOCkge1xuICAgICAgICBkID0gKHRoaXNbaV0gJiAoKDEgPDwgcCkgLSAxKSkgPDwgKDggLSBwKTtcbiAgICAgICAgZCB8PSB0aGlzWy0taV0gPj4gKHAgKz0gdGhpcy5EQiAtIDgpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZCA9ICh0aGlzW2ldID4+IChwIC09IDgpKSAmIDB4ZmY7XG4gICAgICAgIGlmIChwIDw9IDApIHtcbiAgICAgICAgICBwICs9IHRoaXMuREI7XG4gICAgICAgICAgLS1pO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICAvL2lmKChkJjB4ODApICE9IDApIGQgfD0gLTI1NjtcbiAgICAgIC8vaWYoayA9PSAwICYmICh0aGlzLnMmMHg4MCkgIT0gKGQmMHg4MCkpICsraztcbiAgICAgIGlmIChrID4gMCB8fCBkICE9IHRoaXMucykgcltrKytdID0gZDtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHI7XG59XG5cbmZ1bmN0aW9uIGJuRXF1YWxzKGEpIHtcbiAgcmV0dXJuICh0aGlzLmNvbXBhcmVUbyhhKSA9PSAwKTtcbn1cblxuZnVuY3Rpb24gYm5NaW4oYSkge1xuICByZXR1cm4gKHRoaXMuY29tcGFyZVRvKGEpIDwgMCkgPyB0aGlzIDogYTtcbn1cblxuZnVuY3Rpb24gYm5NYXgoYSkge1xuICByZXR1cm4gKHRoaXMuY29tcGFyZVRvKGEpID4gMCkgPyB0aGlzIDogYTtcbn1cblxuLy8gKHByb3RlY3RlZCkgciA9IHRoaXMgb3AgYSAoYml0d2lzZSlcblxuZnVuY3Rpb24gYm5wQml0d2lzZVRvKGEsIG9wLCByKSB7XG4gIHZhciBpLCBmLCBtID0gTWF0aC5taW4oYS50LCB0aGlzLnQpO1xuICBmb3IgKGkgPSAwOyBpIDwgbTsgKytpKSByW2ldID0gb3AodGhpc1tpXSwgYVtpXSk7XG4gIGlmIChhLnQgPCB0aGlzLnQpIHtcbiAgICBmID0gYS5zICYgdGhpcy5ETTtcbiAgICBmb3IgKGkgPSBtOyBpIDwgdGhpcy50OyArK2kpIHJbaV0gPSBvcCh0aGlzW2ldLCBmKTtcbiAgICByLnQgPSB0aGlzLnQ7XG4gIH0gZWxzZSB7XG4gICAgZiA9IHRoaXMucyAmIHRoaXMuRE07XG4gICAgZm9yIChpID0gbTsgaSA8IGEudDsgKytpKSByW2ldID0gb3AoZiwgYVtpXSk7XG4gICAgci50ID0gYS50O1xuICB9XG4gIHIucyA9IG9wKHRoaXMucywgYS5zKTtcbiAgci5jbGFtcCgpO1xufVxuXG4vLyAocHVibGljKSB0aGlzICYgYVxuXG5mdW5jdGlvbiBvcF9hbmQoeCwgeSkge1xuICByZXR1cm4geCAmIHk7XG59XG5cbmZ1bmN0aW9uIGJuQW5kKGEpIHtcbiAgdmFyIHIgPSBuYmkoKTtcbiAgdGhpcy5iaXR3aXNlVG8oYSwgb3BfYW5kLCByKTtcbiAgcmV0dXJuIHI7XG59XG5cbi8vIChwdWJsaWMpIHRoaXMgfCBhXG5cbmZ1bmN0aW9uIG9wX29yKHgsIHkpIHtcbiAgcmV0dXJuIHggfCB5O1xufVxuXG5mdW5jdGlvbiBibk9yKGEpIHtcbiAgdmFyIHIgPSBuYmkoKTtcbiAgdGhpcy5iaXR3aXNlVG8oYSwgb3Bfb3IsIHIpO1xuICByZXR1cm4gcjtcbn1cblxuLy8gKHB1YmxpYykgdGhpcyBeIGFcblxuZnVuY3Rpb24gb3BfeG9yKHgsIHkpIHtcbiAgcmV0dXJuIHggXiB5O1xufVxuXG5mdW5jdGlvbiBiblhvcihhKSB7XG4gIHZhciByID0gbmJpKCk7XG4gIHRoaXMuYml0d2lzZVRvKGEsIG9wX3hvciwgcik7XG4gIHJldHVybiByO1xufVxuXG4vLyAocHVibGljKSB0aGlzICYgfmFcblxuZnVuY3Rpb24gb3BfYW5kbm90KHgsIHkpIHtcbiAgcmV0dXJuIHggJiB+eTtcbn1cblxuZnVuY3Rpb24gYm5BbmROb3QoYSkge1xuICB2YXIgciA9IG5iaSgpO1xuICB0aGlzLmJpdHdpc2VUbyhhLCBvcF9hbmRub3QsIHIpO1xuICByZXR1cm4gcjtcbn1cblxuLy8gKHB1YmxpYykgfnRoaXNcblxuZnVuY3Rpb24gYm5Ob3QoKSB7XG4gIHZhciByID0gbmJpKCk7XG4gIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy50OyArK2kpIHJbaV0gPSB0aGlzLkRNICYgfnRoaXNbaV07XG4gIHIudCA9IHRoaXMudDtcbiAgci5zID0gfnRoaXMucztcbiAgcmV0dXJuIHI7XG59XG5cbi8vIChwdWJsaWMpIHRoaXMgPDwgblxuXG5mdW5jdGlvbiBiblNoaWZ0TGVmdChuKSB7XG4gIHZhciByID0gbmJpKCk7XG4gIGlmIChuIDwgMCkgdGhpcy5yU2hpZnRUbygtbiwgcik7XG4gIGVsc2UgdGhpcy5sU2hpZnRUbyhuLCByKTtcbiAgcmV0dXJuIHI7XG59XG5cbi8vIChwdWJsaWMpIHRoaXMgPj4gblxuXG5mdW5jdGlvbiBiblNoaWZ0UmlnaHQobikge1xuICB2YXIgciA9IG5iaSgpO1xuICBpZiAobiA8IDApIHRoaXMubFNoaWZ0VG8oLW4sIHIpO1xuICBlbHNlIHRoaXMuclNoaWZ0VG8obiwgcik7XG4gIHJldHVybiByO1xufVxuXG4vLyByZXR1cm4gaW5kZXggb2YgbG93ZXN0IDEtYml0IGluIHgsIHggPCAyXjMxXG5cbmZ1bmN0aW9uIGxiaXQoeCkge1xuICBpZiAoeCA9PSAwKSByZXR1cm4gLTE7XG4gIHZhciByID0gMDtcbiAgaWYgKCh4ICYgMHhmZmZmKSA9PSAwKSB7XG4gICAgeCA+Pj0gMTY7XG4gICAgciArPSAxNjtcbiAgfVxuICBpZiAoKHggJiAweGZmKSA9PSAwKSB7XG4gICAgeCA+Pj0gODtcbiAgICByICs9IDg7XG4gIH1cbiAgaWYgKCh4ICYgMHhmKSA9PSAwKSB7XG4gICAgeCA+Pj0gNDtcbiAgICByICs9IDQ7XG4gIH1cbiAgaWYgKCh4ICYgMykgPT0gMCkge1xuICAgIHggPj49IDI7XG4gICAgciArPSAyO1xuICB9XG4gIGlmICgoeCAmIDEpID09IDApKytyO1xuICByZXR1cm4gcjtcbn1cblxuLy8gKHB1YmxpYykgcmV0dXJucyBpbmRleCBvZiBsb3dlc3QgMS1iaXQgKG9yIC0xIGlmIG5vbmUpXG5cbmZ1bmN0aW9uIGJuR2V0TG93ZXN0U2V0Qml0KCkge1xuICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMudDsgKytpKVxuICAgIGlmICh0aGlzW2ldICE9IDApIHJldHVybiBpICogdGhpcy5EQiArIGxiaXQodGhpc1tpXSk7XG4gIGlmICh0aGlzLnMgPCAwKSByZXR1cm4gdGhpcy50ICogdGhpcy5EQjtcbiAgcmV0dXJuIC0xO1xufVxuXG4vLyByZXR1cm4gbnVtYmVyIG9mIDEgYml0cyBpbiB4XG5cbmZ1bmN0aW9uIGNiaXQoeCkge1xuICB2YXIgciA9IDA7XG4gIHdoaWxlICh4ICE9IDApIHtcbiAgICB4ICY9IHggLSAxO1xuICAgICsrcjtcbiAgfVxuICByZXR1cm4gcjtcbn1cblxuLy8gKHB1YmxpYykgcmV0dXJuIG51bWJlciBvZiBzZXQgYml0c1xuXG5mdW5jdGlvbiBibkJpdENvdW50KCkge1xuICB2YXIgciA9IDAsXG4gICAgeCA9IHRoaXMucyAmIHRoaXMuRE07XG4gIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy50OyArK2kpIHIgKz0gY2JpdCh0aGlzW2ldIF4geCk7XG4gIHJldHVybiByO1xufVxuXG4vLyAocHVibGljKSB0cnVlIGlmZiBudGggYml0IGlzIHNldFxuXG5mdW5jdGlvbiBiblRlc3RCaXQobikge1xuICB2YXIgaiA9IE1hdGguZmxvb3IobiAvIHRoaXMuREIpO1xuICBpZiAoaiA+PSB0aGlzLnQpIHJldHVybiAodGhpcy5zICE9IDApO1xuICByZXR1cm4gKCh0aGlzW2pdICYgKDEgPDwgKG4gJSB0aGlzLkRCKSkpICE9IDApO1xufVxuXG4vLyAocHJvdGVjdGVkKSB0aGlzIG9wICgxPDxuKVxuXG5mdW5jdGlvbiBibnBDaGFuZ2VCaXQobiwgb3ApIHtcbiAgdmFyIHIgPSBCaWdJbnRlZ2VyLk9ORS5zaGlmdExlZnQobik7XG4gIHRoaXMuYml0d2lzZVRvKHIsIG9wLCByKTtcbiAgcmV0dXJuIHI7XG59XG5cbi8vIChwdWJsaWMpIHRoaXMgfCAoMTw8bilcblxuZnVuY3Rpb24gYm5TZXRCaXQobikge1xuICByZXR1cm4gdGhpcy5jaGFuZ2VCaXQobiwgb3Bfb3IpO1xufVxuXG4vLyAocHVibGljKSB0aGlzICYgfigxPDxuKVxuXG5mdW5jdGlvbiBibkNsZWFyQml0KG4pIHtcbiAgcmV0dXJuIHRoaXMuY2hhbmdlQml0KG4sIG9wX2FuZG5vdCk7XG59XG5cbi8vIChwdWJsaWMpIHRoaXMgXiAoMTw8bilcblxuZnVuY3Rpb24gYm5GbGlwQml0KG4pIHtcbiAgcmV0dXJuIHRoaXMuY2hhbmdlQml0KG4sIG9wX3hvcik7XG59XG5cbi8vIChwcm90ZWN0ZWQpIHIgPSB0aGlzICsgYVxuXG5mdW5jdGlvbiBibnBBZGRUbyhhLCByKSB7XG4gIHZhciBpID0gMCxcbiAgICBjID0gMCxcbiAgICBtID0gTWF0aC5taW4oYS50LCB0aGlzLnQpO1xuICB3aGlsZSAoaSA8IG0pIHtcbiAgICBjICs9IHRoaXNbaV0gKyBhW2ldO1xuICAgIHJbaSsrXSA9IGMgJiB0aGlzLkRNO1xuICAgIGMgPj49IHRoaXMuREI7XG4gIH1cbiAgaWYgKGEudCA8IHRoaXMudCkge1xuICAgIGMgKz0gYS5zO1xuICAgIHdoaWxlIChpIDwgdGhpcy50KSB7XG4gICAgICBjICs9IHRoaXNbaV07XG4gICAgICByW2krK10gPSBjICYgdGhpcy5ETTtcbiAgICAgIGMgPj49IHRoaXMuREI7XG4gICAgfVxuICAgIGMgKz0gdGhpcy5zO1xuICB9IGVsc2Uge1xuICAgIGMgKz0gdGhpcy5zO1xuICAgIHdoaWxlIChpIDwgYS50KSB7XG4gICAgICBjICs9IGFbaV07XG4gICAgICByW2krK10gPSBjICYgdGhpcy5ETTtcbiAgICAgIGMgPj49IHRoaXMuREI7XG4gICAgfVxuICAgIGMgKz0gYS5zO1xuICB9XG4gIHIucyA9IChjIDwgMCkgPyAtMSA6IDA7XG4gIGlmIChjID4gMCkgcltpKytdID0gYztcbiAgZWxzZSBpZiAoYyA8IC0xKSByW2krK10gPSB0aGlzLkRWICsgYztcbiAgci50ID0gaTtcbiAgci5jbGFtcCgpO1xufVxuXG4vLyAocHVibGljKSB0aGlzICsgYVxuXG5mdW5jdGlvbiBibkFkZChhKSB7XG4gIHZhciByID0gbmJpKCk7XG4gIHRoaXMuYWRkVG8oYSwgcik7XG4gIHJldHVybiByO1xufVxuXG4vLyAocHVibGljKSB0aGlzIC0gYVxuXG5mdW5jdGlvbiBiblN1YnRyYWN0KGEpIHtcbiAgdmFyIHIgPSBuYmkoKTtcbiAgdGhpcy5zdWJUbyhhLCByKTtcbiAgcmV0dXJuIHI7XG59XG5cbi8vIChwdWJsaWMpIHRoaXMgKiBhXG5cbmZ1bmN0aW9uIGJuTXVsdGlwbHkoYSkge1xuICB2YXIgciA9IG5iaSgpO1xuICB0aGlzLm11bHRpcGx5VG8oYSwgcik7XG4gIHJldHVybiByO1xufVxuXG4vLyAocHVibGljKSB0aGlzXjJcblxuZnVuY3Rpb24gYm5TcXVhcmUoKSB7XG4gIHZhciByID0gbmJpKCk7XG4gIHRoaXMuc3F1YXJlVG8ocik7XG4gIHJldHVybiByO1xufVxuXG4vLyAocHVibGljKSB0aGlzIC8gYVxuXG5mdW5jdGlvbiBibkRpdmlkZShhKSB7XG4gIHZhciByID0gbmJpKCk7XG4gIHRoaXMuZGl2UmVtVG8oYSwgciwgbnVsbCk7XG4gIHJldHVybiByO1xufVxuXG4vLyAocHVibGljKSB0aGlzICUgYVxuXG5mdW5jdGlvbiBiblJlbWFpbmRlcihhKSB7XG4gIHZhciByID0gbmJpKCk7XG4gIHRoaXMuZGl2UmVtVG8oYSwgbnVsbCwgcik7XG4gIHJldHVybiByO1xufVxuXG4vLyAocHVibGljKSBbdGhpcy9hLHRoaXMlYV1cblxuZnVuY3Rpb24gYm5EaXZpZGVBbmRSZW1haW5kZXIoYSkge1xuICB2YXIgcSA9IG5iaSgpLFxuICAgIHIgPSBuYmkoKTtcbiAgdGhpcy5kaXZSZW1UbyhhLCBxLCByKTtcbiAgcmV0dXJuIG5ldyBBcnJheShxLCByKTtcbn1cblxuLy8gKHByb3RlY3RlZCkgdGhpcyAqPSBuLCB0aGlzID49IDAsIDEgPCBuIDwgRFZcblxuZnVuY3Rpb24gYm5wRE11bHRpcGx5KG4pIHtcbiAgdGhpc1t0aGlzLnRdID0gdGhpcy5hbSgwLCBuIC0gMSwgdGhpcywgMCwgMCwgdGhpcy50KTtcbiAgKyt0aGlzLnQ7XG4gIHRoaXMuY2xhbXAoKTtcbn1cblxuLy8gKHByb3RlY3RlZCkgdGhpcyArPSBuIDw8IHcgd29yZHMsIHRoaXMgPj0gMFxuXG5mdW5jdGlvbiBibnBEQWRkT2Zmc2V0KG4sIHcpIHtcbiAgaWYgKG4gPT0gMCkgcmV0dXJuO1xuICB3aGlsZSAodGhpcy50IDw9IHcpIHRoaXNbdGhpcy50KytdID0gMDtcbiAgdGhpc1t3XSArPSBuO1xuICB3aGlsZSAodGhpc1t3XSA+PSB0aGlzLkRWKSB7XG4gICAgdGhpc1t3XSAtPSB0aGlzLkRWO1xuICAgIGlmICgrK3cgPj0gdGhpcy50KSB0aGlzW3RoaXMudCsrXSA9IDA7XG4gICAgKyt0aGlzW3ddO1xuICB9XG59XG5cbi8vIEEgXCJudWxsXCIgcmVkdWNlclxuXG5mdW5jdGlvbiBOdWxsRXhwKCkge31cblxuZnVuY3Rpb24gbk5vcCh4KSB7XG4gIHJldHVybiB4O1xufVxuXG5mdW5jdGlvbiBuTXVsVG8oeCwgeSwgcikge1xuICB4Lm11bHRpcGx5VG8oeSwgcik7XG59XG5cbmZ1bmN0aW9uIG5TcXJUbyh4LCByKSB7XG4gIHguc3F1YXJlVG8ocik7XG59XG5cbk51bGxFeHAucHJvdG90eXBlLmNvbnZlcnQgPSBuTm9wO1xuTnVsbEV4cC5wcm90b3R5cGUucmV2ZXJ0ID0gbk5vcDtcbk51bGxFeHAucHJvdG90eXBlLm11bFRvID0gbk11bFRvO1xuTnVsbEV4cC5wcm90b3R5cGUuc3FyVG8gPSBuU3FyVG87XG5cbi8vIChwdWJsaWMpIHRoaXNeZVxuXG5mdW5jdGlvbiBiblBvdyhlKSB7XG4gIHJldHVybiB0aGlzLmV4cChlLCBuZXcgTnVsbEV4cCgpKTtcbn1cblxuLy8gKHByb3RlY3RlZCkgciA9IGxvd2VyIG4gd29yZHMgb2YgXCJ0aGlzICogYVwiLCBhLnQgPD0gblxuLy8gXCJ0aGlzXCIgc2hvdWxkIGJlIHRoZSBsYXJnZXIgb25lIGlmIGFwcHJvcHJpYXRlLlxuXG5mdW5jdGlvbiBibnBNdWx0aXBseUxvd2VyVG8oYSwgbiwgcikge1xuICB2YXIgaSA9IE1hdGgubWluKHRoaXMudCArIGEudCwgbik7XG4gIHIucyA9IDA7IC8vIGFzc3VtZXMgYSx0aGlzID49IDBcbiAgci50ID0gaTtcbiAgd2hpbGUgKGkgPiAwKSByWy0taV0gPSAwO1xuICB2YXIgajtcbiAgZm9yIChqID0gci50IC0gdGhpcy50OyBpIDwgajsgKytpKSByW2kgKyB0aGlzLnRdID0gdGhpcy5hbSgwLCBhW2ldLCByLCBpLCAwLCB0aGlzLnQpO1xuICBmb3IgKGogPSBNYXRoLm1pbihhLnQsIG4pOyBpIDwgajsgKytpKSB0aGlzLmFtKDAsIGFbaV0sIHIsIGksIDAsIG4gLSBpKTtcbiAgci5jbGFtcCgpO1xufVxuXG4vLyAocHJvdGVjdGVkKSByID0gXCJ0aGlzICogYVwiIHdpdGhvdXQgbG93ZXIgbiB3b3JkcywgbiA+IDBcbi8vIFwidGhpc1wiIHNob3VsZCBiZSB0aGUgbGFyZ2VyIG9uZSBpZiBhcHByb3ByaWF0ZS5cblxuZnVuY3Rpb24gYm5wTXVsdGlwbHlVcHBlclRvKGEsIG4sIHIpIHtcbiAgLS1uO1xuICB2YXIgaSA9IHIudCA9IHRoaXMudCArIGEudCAtIG47XG4gIHIucyA9IDA7IC8vIGFzc3VtZXMgYSx0aGlzID49IDBcbiAgd2hpbGUgKC0taSA+PSAwKSByW2ldID0gMDtcbiAgZm9yIChpID0gTWF0aC5tYXgobiAtIHRoaXMudCwgMCk7IGkgPCBhLnQ7ICsraSlcbiAgICByW3RoaXMudCArIGkgLSBuXSA9IHRoaXMuYW0obiAtIGksIGFbaV0sIHIsIDAsIDAsIHRoaXMudCArIGkgLSBuKTtcbiAgci5jbGFtcCgpO1xuICByLmRyU2hpZnRUbygxLCByKTtcbn1cblxuLy8gQmFycmV0dCBtb2R1bGFyIHJlZHVjdGlvblxuXG5mdW5jdGlvbiBCYXJyZXR0KG0pIHtcbiAgLy8gc2V0dXAgQmFycmV0dFxuICB0aGlzLnIyID0gbmJpKCk7XG4gIHRoaXMucTMgPSBuYmkoKTtcbiAgQmlnSW50ZWdlci5PTkUuZGxTaGlmdFRvKDIgKiBtLnQsIHRoaXMucjIpO1xuICB0aGlzLm11ID0gdGhpcy5yMi5kaXZpZGUobSk7XG4gIHRoaXMubSA9IG07XG59XG5cbmZ1bmN0aW9uIGJhcnJldHRDb252ZXJ0KHgpIHtcbiAgaWYgKHgucyA8IDAgfHwgeC50ID4gMiAqIHRoaXMubS50KSByZXR1cm4geC5tb2QodGhpcy5tKTtcbiAgZWxzZSBpZiAoeC5jb21wYXJlVG8odGhpcy5tKSA8IDApIHJldHVybiB4O1xuICBlbHNlIHtcbiAgICB2YXIgciA9IG5iaSgpO1xuICAgIHguY29weVRvKHIpO1xuICAgIHRoaXMucmVkdWNlKHIpO1xuICAgIHJldHVybiByO1xuICB9XG59XG5cbmZ1bmN0aW9uIGJhcnJldHRSZXZlcnQoeCkge1xuICByZXR1cm4geDtcbn1cblxuLy8geCA9IHggbW9kIG0gKEhBQyAxNC40MilcblxuZnVuY3Rpb24gYmFycmV0dFJlZHVjZSh4KSB7XG4gIHguZHJTaGlmdFRvKHRoaXMubS50IC0gMSwgdGhpcy5yMik7XG4gIGlmICh4LnQgPiB0aGlzLm0udCArIDEpIHtcbiAgICB4LnQgPSB0aGlzLm0udCArIDE7XG4gICAgeC5jbGFtcCgpO1xuICB9XG4gIHRoaXMubXUubXVsdGlwbHlVcHBlclRvKHRoaXMucjIsIHRoaXMubS50ICsgMSwgdGhpcy5xMyk7XG4gIHRoaXMubS5tdWx0aXBseUxvd2VyVG8odGhpcy5xMywgdGhpcy5tLnQgKyAxLCB0aGlzLnIyKTtcbiAgd2hpbGUgKHguY29tcGFyZVRvKHRoaXMucjIpIDwgMCkgeC5kQWRkT2Zmc2V0KDEsIHRoaXMubS50ICsgMSk7XG4gIHguc3ViVG8odGhpcy5yMiwgeCk7XG4gIHdoaWxlICh4LmNvbXBhcmVUbyh0aGlzLm0pID49IDApIHguc3ViVG8odGhpcy5tLCB4KTtcbn1cblxuLy8gciA9IHheMiBtb2QgbTsgeCAhPSByXG5cbmZ1bmN0aW9uIGJhcnJldHRTcXJUbyh4LCByKSB7XG4gIHguc3F1YXJlVG8ocik7XG4gIHRoaXMucmVkdWNlKHIpO1xufVxuXG4vLyByID0geCp5IG1vZCBtOyB4LHkgIT0gclxuXG5mdW5jdGlvbiBiYXJyZXR0TXVsVG8oeCwgeSwgcikge1xuICB4Lm11bHRpcGx5VG8oeSwgcik7XG4gIHRoaXMucmVkdWNlKHIpO1xufVxuXG5CYXJyZXR0LnByb3RvdHlwZS5jb252ZXJ0ID0gYmFycmV0dENvbnZlcnQ7XG5CYXJyZXR0LnByb3RvdHlwZS5yZXZlcnQgPSBiYXJyZXR0UmV2ZXJ0O1xuQmFycmV0dC5wcm90b3R5cGUucmVkdWNlID0gYmFycmV0dFJlZHVjZTtcbkJhcnJldHQucHJvdG90eXBlLm11bFRvID0gYmFycmV0dE11bFRvO1xuQmFycmV0dC5wcm90b3R5cGUuc3FyVG8gPSBiYXJyZXR0U3FyVG87XG5cbi8vIChwdWJsaWMpIHRoaXNeZSAlIG0gKEhBQyAxNC44NSlcblxuZnVuY3Rpb24gYm5Nb2RQb3coZSwgbSkge1xuICB2YXIgaSA9IGUuYml0TGVuZ3RoKCksXG4gICAgaywgciA9IG5idigxKSxcbiAgICB6O1xuICBpZiAoaSA8PSAwKSByZXR1cm4gcjtcbiAgZWxzZSBpZiAoaSA8IDE4KSBrID0gMTtcbiAgZWxzZSBpZiAoaSA8IDQ4KSBrID0gMztcbiAgZWxzZSBpZiAoaSA8IDE0NCkgayA9IDQ7XG4gIGVsc2UgaWYgKGkgPCA3NjgpIGsgPSA1O1xuICBlbHNlIGsgPSA2O1xuICBpZiAoaSA8IDgpXG4gICAgeiA9IG5ldyBDbGFzc2ljKG0pO1xuICBlbHNlIGlmIChtLmlzRXZlbigpKVxuICAgIHogPSBuZXcgQmFycmV0dChtKTtcbiAgZWxzZVxuICAgIHogPSBuZXcgTW9udGdvbWVyeShtKTtcblxuICAvLyBwcmVjb21wdXRhdGlvblxuICB2YXIgZyA9IG5ldyBBcnJheSgpLFxuICAgIG4gPSAzLFxuICAgIGsxID0gayAtIDEsXG4gICAga20gPSAoMSA8PCBrKSAtIDE7XG4gIGdbMV0gPSB6LmNvbnZlcnQodGhpcyk7XG4gIGlmIChrID4gMSkge1xuICAgIHZhciBnMiA9IG5iaSgpO1xuICAgIHouc3FyVG8oZ1sxXSwgZzIpO1xuICAgIHdoaWxlIChuIDw9IGttKSB7XG4gICAgICBnW25dID0gbmJpKCk7XG4gICAgICB6Lm11bFRvKGcyLCBnW24gLSAyXSwgZ1tuXSk7XG4gICAgICBuICs9IDI7XG4gICAgfVxuICB9XG5cbiAgdmFyIGogPSBlLnQgLSAxLFxuICAgIHcsIGlzMSA9IHRydWUsXG4gICAgcjIgPSBuYmkoKSxcbiAgICB0O1xuICBpID0gbmJpdHMoZVtqXSkgLSAxO1xuICB3aGlsZSAoaiA+PSAwKSB7XG4gICAgaWYgKGkgPj0gazEpIHcgPSAoZVtqXSA+PiAoaSAtIGsxKSkgJiBrbTtcbiAgICBlbHNlIHtcbiAgICAgIHcgPSAoZVtqXSAmICgoMSA8PCAoaSArIDEpKSAtIDEpKSA8PCAoazEgLSBpKTtcbiAgICAgIGlmIChqID4gMCkgdyB8PSBlW2ogLSAxXSA+PiAodGhpcy5EQiArIGkgLSBrMSk7XG4gICAgfVxuXG4gICAgbiA9IGs7XG4gICAgd2hpbGUgKCh3ICYgMSkgPT0gMCkge1xuICAgICAgdyA+Pj0gMTtcbiAgICAgIC0tbjtcbiAgICB9XG4gICAgaWYgKChpIC09IG4pIDwgMCkge1xuICAgICAgaSArPSB0aGlzLkRCO1xuICAgICAgLS1qO1xuICAgIH1cbiAgICBpZiAoaXMxKSB7IC8vIHJldCA9PSAxLCBkb24ndCBib3RoZXIgc3F1YXJpbmcgb3IgbXVsdGlwbHlpbmcgaXRcbiAgICAgIGdbd10uY29weVRvKHIpO1xuICAgICAgaXMxID0gZmFsc2U7XG4gICAgfSBlbHNlIHtcbiAgICAgIHdoaWxlIChuID4gMSkge1xuICAgICAgICB6LnNxclRvKHIsIHIyKTtcbiAgICAgICAgei5zcXJUbyhyMiwgcik7XG4gICAgICAgIG4gLT0gMjtcbiAgICAgIH1cbiAgICAgIGlmIChuID4gMCkgei5zcXJUbyhyLCByMik7XG4gICAgICBlbHNlIHtcbiAgICAgICAgdCA9IHI7XG4gICAgICAgIHIgPSByMjtcbiAgICAgICAgcjIgPSB0O1xuICAgICAgfVxuICAgICAgei5tdWxUbyhyMiwgZ1t3XSwgcik7XG4gICAgfVxuXG4gICAgd2hpbGUgKGogPj0gMCAmJiAoZVtqXSAmICgxIDw8IGkpKSA9PSAwKSB7XG4gICAgICB6LnNxclRvKHIsIHIyKTtcbiAgICAgIHQgPSByO1xuICAgICAgciA9IHIyO1xuICAgICAgcjIgPSB0O1xuICAgICAgaWYgKC0taSA8IDApIHtcbiAgICAgICAgaSA9IHRoaXMuREIgLSAxO1xuICAgICAgICAtLWo7XG4gICAgICB9XG4gICAgfVxuICB9XG4gIHJldHVybiB6LnJldmVydChyKTtcbn1cblxuLy8gKHB1YmxpYykgZ2NkKHRoaXMsYSkgKEhBQyAxNC41NClcblxuZnVuY3Rpb24gYm5HQ0QoYSkge1xuICB2YXIgeCA9ICh0aGlzLnMgPCAwKSA/IHRoaXMubmVnYXRlKCkgOiB0aGlzLmNsb25lKCk7XG4gIHZhciB5ID0gKGEucyA8IDApID8gYS5uZWdhdGUoKSA6IGEuY2xvbmUoKTtcbiAgaWYgKHguY29tcGFyZVRvKHkpIDwgMCkge1xuICAgIHZhciB0ID0geDtcbiAgICB4ID0geTtcbiAgICB5ID0gdDtcbiAgfVxuICB2YXIgaSA9IHguZ2V0TG93ZXN0U2V0Qml0KCksXG4gICAgZyA9IHkuZ2V0TG93ZXN0U2V0Qml0KCk7XG4gIGlmIChnIDwgMCkgcmV0dXJuIHg7XG4gIGlmIChpIDwgZykgZyA9IGk7XG4gIGlmIChnID4gMCkge1xuICAgIHguclNoaWZ0VG8oZywgeCk7XG4gICAgeS5yU2hpZnRUbyhnLCB5KTtcbiAgfVxuICB3aGlsZSAoeC5zaWdudW0oKSA+IDApIHtcbiAgICBpZiAoKGkgPSB4LmdldExvd2VzdFNldEJpdCgpKSA+IDApIHguclNoaWZ0VG8oaSwgeCk7XG4gICAgaWYgKChpID0geS5nZXRMb3dlc3RTZXRCaXQoKSkgPiAwKSB5LnJTaGlmdFRvKGksIHkpO1xuICAgIGlmICh4LmNvbXBhcmVUbyh5KSA+PSAwKSB7XG4gICAgICB4LnN1YlRvKHksIHgpO1xuICAgICAgeC5yU2hpZnRUbygxLCB4KTtcbiAgICB9IGVsc2Uge1xuICAgICAgeS5zdWJUbyh4LCB5KTtcbiAgICAgIHkuclNoaWZ0VG8oMSwgeSk7XG4gICAgfVxuICB9XG4gIGlmIChnID4gMCkgeS5sU2hpZnRUbyhnLCB5KTtcbiAgcmV0dXJuIHk7XG59XG5cbi8vIChwcm90ZWN0ZWQpIHRoaXMgJSBuLCBuIDwgMl4yNlxuXG5mdW5jdGlvbiBibnBNb2RJbnQobikge1xuICBpZiAobiA8PSAwKSByZXR1cm4gMDtcbiAgdmFyIGQgPSB0aGlzLkRWICUgbixcbiAgICByID0gKHRoaXMucyA8IDApID8gbiAtIDEgOiAwO1xuICBpZiAodGhpcy50ID4gMClcbiAgICBpZiAoZCA9PSAwKSByID0gdGhpc1swXSAlIG47XG4gICAgZWxzZSBmb3IgKHZhciBpID0gdGhpcy50IC0gMTsgaSA+PSAwOyAtLWkpIHIgPSAoZCAqIHIgKyB0aGlzW2ldKSAlIG47XG4gIHJldHVybiByO1xufVxuXG4vLyAocHVibGljKSAxL3RoaXMgJSBtIChIQUMgMTQuNjEpXG5cbmZ1bmN0aW9uIGJuTW9kSW52ZXJzZShtKSB7XG4gIHZhciBhYyA9IG0uaXNFdmVuKCk7XG4gIGlmICgodGhpcy5pc0V2ZW4oKSAmJiBhYykgfHwgbS5zaWdudW0oKSA9PSAwKSByZXR1cm4gQmlnSW50ZWdlci5aRVJPO1xuICB2YXIgdSA9IG0uY2xvbmUoKSxcbiAgICB2ID0gdGhpcy5jbG9uZSgpO1xuICB2YXIgYSA9IG5idigxKSxcbiAgICBiID0gbmJ2KDApLFxuICAgIGMgPSBuYnYoMCksXG4gICAgZCA9IG5idigxKTtcbiAgd2hpbGUgKHUuc2lnbnVtKCkgIT0gMCkge1xuICAgIHdoaWxlICh1LmlzRXZlbigpKSB7XG4gICAgICB1LnJTaGlmdFRvKDEsIHUpO1xuICAgICAgaWYgKGFjKSB7XG4gICAgICAgIGlmICghYS5pc0V2ZW4oKSB8fCAhYi5pc0V2ZW4oKSkge1xuICAgICAgICAgIGEuYWRkVG8odGhpcywgYSk7XG4gICAgICAgICAgYi5zdWJUbyhtLCBiKTtcbiAgICAgICAgfVxuICAgICAgICBhLnJTaGlmdFRvKDEsIGEpO1xuICAgICAgfSBlbHNlIGlmICghYi5pc0V2ZW4oKSkgYi5zdWJUbyhtLCBiKTtcbiAgICAgIGIuclNoaWZ0VG8oMSwgYik7XG4gICAgfVxuICAgIHdoaWxlICh2LmlzRXZlbigpKSB7XG4gICAgICB2LnJTaGlmdFRvKDEsIHYpO1xuICAgICAgaWYgKGFjKSB7XG4gICAgICAgIGlmICghYy5pc0V2ZW4oKSB8fCAhZC5pc0V2ZW4oKSkge1xuICAgICAgICAgIGMuYWRkVG8odGhpcywgYyk7XG4gICAgICAgICAgZC5zdWJUbyhtLCBkKTtcbiAgICAgICAgfVxuICAgICAgICBjLnJTaGlmdFRvKDEsIGMpO1xuICAgICAgfSBlbHNlIGlmICghZC5pc0V2ZW4oKSkgZC5zdWJUbyhtLCBkKTtcbiAgICAgIGQuclNoaWZ0VG8oMSwgZCk7XG4gICAgfVxuICAgIGlmICh1LmNvbXBhcmVUbyh2KSA+PSAwKSB7XG4gICAgICB1LnN1YlRvKHYsIHUpO1xuICAgICAgaWYgKGFjKSBhLnN1YlRvKGMsIGEpO1xuICAgICAgYi5zdWJUbyhkLCBiKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdi5zdWJUbyh1LCB2KTtcbiAgICAgIGlmIChhYykgYy5zdWJUbyhhLCBjKTtcbiAgICAgIGQuc3ViVG8oYiwgZCk7XG4gICAgfVxuICB9XG4gIGlmICh2LmNvbXBhcmVUbyhCaWdJbnRlZ2VyLk9ORSkgIT0gMCkgcmV0dXJuIEJpZ0ludGVnZXIuWkVSTztcbiAgaWYgKGQuY29tcGFyZVRvKG0pID49IDApIHJldHVybiBkLnN1YnRyYWN0KG0pO1xuICBpZiAoZC5zaWdudW0oKSA8IDApIGQuYWRkVG8obSwgZCk7XG4gIGVsc2UgcmV0dXJuIGQ7XG4gIGlmIChkLnNpZ251bSgpIDwgMCkgcmV0dXJuIGQuYWRkKG0pO1xuICBlbHNlIHJldHVybiBkO1xufVxuXG52YXIgbG93cHJpbWVzID0gWzIsIDMsIDUsIDcsIDExLCAxMywgMTcsIDE5LCAyMywgMjksIDMxLCAzNywgNDEsIDQzLCA0NywgNTMsIDU5LCA2MSwgNjcsIDcxLCA3MywgNzksIDgzLCA4OSwgOTcsIDEwMSxcbiAgICAxMDMsIDEwNywgMTA5LCAxMTMsIDEyNywgMTMxLCAxMzcsIDEzOSwgMTQ5LCAxNTEsIDE1NywgMTYzLCAxNjcsIDE3MywgMTc5LCAxODEsIDE5MSwgMTkzLCAxOTcsIDE5OSwgMjExLCAyMjMsIDIyNyxcbiAgICAyMjksIDIzMywgMjM5LCAyNDEsIDI1MSwgMjU3LCAyNjMsIDI2OSwgMjcxLCAyNzcsIDI4MSwgMjgzLCAyOTMsIDMwNywgMzExLCAzMTMsIDMxNywgMzMxLCAzMzcsIDM0NywgMzQ5LCAzNTMsIDM1OSxcbiAgICAzNjcsIDM3MywgMzc5LCAzODMsIDM4OSwgMzk3LCA0MDEsIDQwOSwgNDE5LCA0MjEsIDQzMSwgNDMzLCA0MzksIDQ0MywgNDQ5LCA0NTcsIDQ2MSwgNDYzLCA0NjcsIDQ3OSwgNDg3LCA0OTEsIDQ5OSxcbiAgICA1MDMsIDUwOSwgNTIxLCA1MjMsIDU0MSwgNTQ3LCA1NTcsIDU2MywgNTY5LCA1NzEsIDU3NywgNTg3LCA1OTMsIDU5OSwgNjAxLCA2MDcsIDYxMywgNjE3LCA2MTksIDYzMSwgNjQxLCA2NDMsIDY0NyxcbiAgICA2NTMsIDY1OSwgNjYxLCA2NzMsIDY3NywgNjgzLCA2OTEsIDcwMSwgNzA5LCA3MTksIDcyNywgNzMzLCA3MzksIDc0MywgNzUxLCA3NTcsIDc2MSwgNzY5LCA3NzMsIDc4NywgNzk3LCA4MDksIDgxMSxcbiAgICA4MjEsIDgyMywgODI3LCA4MjksIDgzOSwgODUzLCA4NTcsIDg1OSwgODYzLCA4NzcsIDg4MSwgODgzLCA4ODcsIDkwNywgOTExLCA5MTksIDkyOSwgOTM3LCA5NDEsIDk0NywgOTUzLCA5NjcsIDk3MSxcbiAgICA5NzcsIDk4MywgOTkxLCA5OTdcbl07XG52YXIgbHBsaW0gPSAoMSA8PCAyNikgLyBsb3dwcmltZXNbbG93cHJpbWVzLmxlbmd0aCAtIDFdO1xuXG4vLyAocHVibGljKSB0ZXN0IHByaW1hbGl0eSB3aXRoIGNlcnRhaW50eSA+PSAxLS41XnRcblxuZnVuY3Rpb24gYm5Jc1Byb2JhYmxlUHJpbWUodCkge1xuICB2YXIgaSwgeCA9IHRoaXMuYWJzKCk7XG4gIGlmICh4LnQgPT0gMSAmJiB4WzBdIDw9IGxvd3ByaW1lc1tsb3dwcmltZXMubGVuZ3RoIC0gMV0pIHtcbiAgICBmb3IgKGkgPSAwOyBpIDwgbG93cHJpbWVzLmxlbmd0aDsgKytpKVxuICAgICAgaWYgKHhbMF0gPT0gbG93cHJpbWVzW2ldKSByZXR1cm4gdHJ1ZTtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbiAgaWYgKHguaXNFdmVuKCkpIHJldHVybiBmYWxzZTtcbiAgaSA9IDE7XG4gIHdoaWxlIChpIDwgbG93cHJpbWVzLmxlbmd0aCkge1xuICAgIHZhciBtID0gbG93cHJpbWVzW2ldLFxuICAgICAgaiA9IGkgKyAxO1xuICAgIHdoaWxlIChqIDwgbG93cHJpbWVzLmxlbmd0aCAmJiBtIDwgbHBsaW0pIG0gKj0gbG93cHJpbWVzW2orK107XG4gICAgbSA9IHgubW9kSW50KG0pO1xuICAgIHdoaWxlIChpIDwgaikgaWYgKG0gJSBsb3dwcmltZXNbaSsrXSA9PSAwKSByZXR1cm4gZmFsc2U7XG4gIH1cbiAgcmV0dXJuIHgubWlsbGVyUmFiaW4odCk7XG59XG5cbi8qIGFkZGVkIGJ5IFJlY3VyaXR5IExhYnMgKi9cblxuZnVuY3Rpb24gbmJpdHMoeCkge1xuICB2YXIgbiA9IDEsXG4gICAgdDtcbiAgaWYgKCh0ID0geCA+Pj4gMTYpICE9IDApIHtcbiAgICB4ID0gdDtcbiAgICBuICs9IDE2O1xuICB9XG4gIGlmICgodCA9IHggPj4gOCkgIT0gMCkge1xuICAgIHggPSB0O1xuICAgIG4gKz0gODtcbiAgfVxuICBpZiAoKHQgPSB4ID4+IDQpICE9IDApIHtcbiAgICB4ID0gdDtcbiAgICBuICs9IDQ7XG4gIH1cbiAgaWYgKCh0ID0geCA+PiAyKSAhPSAwKSB7XG4gICAgeCA9IHQ7XG4gICAgbiArPSAyO1xuICB9XG4gIGlmICgodCA9IHggPj4gMSkgIT0gMCkge1xuICAgIHggPSB0O1xuICAgIG4gKz0gMTtcbiAgfVxuICByZXR1cm4gbjtcbn1cblxuZnVuY3Rpb24gYm5Ub01QSSgpIHtcbiAgdmFyIGJhID0gdGhpcy50b0J5dGVBcnJheSgpO1xuICB2YXIgc2l6ZSA9IChiYS5sZW5ndGggLSAxKSAqIDggKyBuYml0cyhiYVswXSk7XG4gIHZhciByZXN1bHQgPSBcIlwiO1xuICByZXN1bHQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSgoc2l6ZSAmIDB4RkYwMCkgPj4gOCk7XG4gIHJlc3VsdCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKHNpemUgJiAweEZGKTtcbiAgcmVzdWx0ICs9IHV0aWwuYmluMnN0cihiYSk7XG4gIHJldHVybiByZXN1bHQ7XG59XG4vKiBFTkQgb2YgYWRkaXRpb24gKi9cblxuLy8gKHByb3RlY3RlZCkgdHJ1ZSBpZiBwcm9iYWJseSBwcmltZSAoSEFDIDQuMjQsIE1pbGxlci1SYWJpbilcbmZ1bmN0aW9uIGJucE1pbGxlclJhYmluKHQpIHtcbiAgdmFyIG4xID0gdGhpcy5zdWJ0cmFjdChCaWdJbnRlZ2VyLk9ORSk7XG4gIHZhciBrID0gbjEuZ2V0TG93ZXN0U2V0Qml0KCk7XG4gIGlmIChrIDw9IDApIHJldHVybiBmYWxzZTtcbiAgdmFyIHIgPSBuMS5zaGlmdFJpZ2h0KGspO1xuICB0ID0gKHQgKyAxKSA+PiAxO1xuICBpZiAodCA+IGxvd3ByaW1lcy5sZW5ndGgpIHQgPSBsb3dwcmltZXMubGVuZ3RoO1xuICB2YXIgYSA9IG5iaSgpO1xuICB2YXIgaiwgYmFzZXMgPSBbXTtcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCB0OyArK2kpIHtcbiAgICAvL1BpY2sgYmFzZXMgYXQgcmFuZG9tLCBpbnN0ZWFkIG9mIHN0YXJ0aW5nIGF0IDJcbiAgICBmb3IgKDs7KSB7XG4gICAgICBqID0gbG93cHJpbWVzW01hdGguZmxvb3IoTWF0aC5yYW5kb20oKSAqIGxvd3ByaW1lcy5sZW5ndGgpXTtcbiAgICAgIGlmIChiYXNlcy5pbmRleE9mKGopID09IC0xKSBicmVhaztcbiAgICB9XG4gICAgYmFzZXMucHVzaChqKTtcbiAgICBhLmZyb21JbnQoaik7XG4gICAgdmFyIHkgPSBhLm1vZFBvdyhyLCB0aGlzKTtcbiAgICBpZiAoeS5jb21wYXJlVG8oQmlnSW50ZWdlci5PTkUpICE9IDAgJiYgeS5jb21wYXJlVG8objEpICE9IDApIHtcbiAgICAgIHZhciBqID0gMTtcbiAgICAgIHdoaWxlIChqKysgPCBrICYmIHkuY29tcGFyZVRvKG4xKSAhPSAwKSB7XG4gICAgICAgIHkgPSB5Lm1vZFBvd0ludCgyLCB0aGlzKTtcbiAgICAgICAgaWYgKHkuY29tcGFyZVRvKEJpZ0ludGVnZXIuT05FKSA9PSAwKSByZXR1cm4gZmFsc2U7XG4gICAgICB9XG4gICAgICBpZiAoeS5jb21wYXJlVG8objEpICE9IDApIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHRydWU7XG59XG5cbnZhciBCaWdJbnRlZ2VyID0gcmVxdWlyZSgnLi9qc2JuLmpzJyk7XG5cbi8vIHByb3RlY3RlZFxuQmlnSW50ZWdlci5wcm90b3R5cGUuY2h1bmtTaXplID0gYm5wQ2h1bmtTaXplO1xuQmlnSW50ZWdlci5wcm90b3R5cGUudG9SYWRpeCA9IGJucFRvUmFkaXg7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5mcm9tUmFkaXggPSBibnBGcm9tUmFkaXg7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5mcm9tTnVtYmVyID0gYm5wRnJvbU51bWJlcjtcbkJpZ0ludGVnZXIucHJvdG90eXBlLmJpdHdpc2VUbyA9IGJucEJpdHdpc2VUbztcbkJpZ0ludGVnZXIucHJvdG90eXBlLmNoYW5nZUJpdCA9IGJucENoYW5nZUJpdDtcbkJpZ0ludGVnZXIucHJvdG90eXBlLmFkZFRvID0gYm5wQWRkVG87XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5kTXVsdGlwbHkgPSBibnBETXVsdGlwbHk7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5kQWRkT2Zmc2V0ID0gYm5wREFkZE9mZnNldDtcbkJpZ0ludGVnZXIucHJvdG90eXBlLm11bHRpcGx5TG93ZXJUbyA9IGJucE11bHRpcGx5TG93ZXJUbztcbkJpZ0ludGVnZXIucHJvdG90eXBlLm11bHRpcGx5VXBwZXJUbyA9IGJucE11bHRpcGx5VXBwZXJUbztcbkJpZ0ludGVnZXIucHJvdG90eXBlLm1vZEludCA9IGJucE1vZEludDtcbkJpZ0ludGVnZXIucHJvdG90eXBlLm1pbGxlclJhYmluID0gYm5wTWlsbGVyUmFiaW47XG5cbi8vIHB1YmxpY1xuQmlnSW50ZWdlci5wcm90b3R5cGUuY2xvbmUgPSBibkNsb25lO1xuQmlnSW50ZWdlci5wcm90b3R5cGUuaW50VmFsdWUgPSBibkludFZhbHVlO1xuQmlnSW50ZWdlci5wcm90b3R5cGUuYnl0ZVZhbHVlID0gYm5CeXRlVmFsdWU7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5zaG9ydFZhbHVlID0gYm5TaG9ydFZhbHVlO1xuQmlnSW50ZWdlci5wcm90b3R5cGUuc2lnbnVtID0gYm5TaWdOdW07XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS50b0J5dGVBcnJheSA9IGJuVG9CeXRlQXJyYXk7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5lcXVhbHMgPSBibkVxdWFscztcbkJpZ0ludGVnZXIucHJvdG90eXBlLm1pbiA9IGJuTWluO1xuQmlnSW50ZWdlci5wcm90b3R5cGUubWF4ID0gYm5NYXg7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5hbmQgPSBibkFuZDtcbkJpZ0ludGVnZXIucHJvdG90eXBlLm9yID0gYm5PcjtcbkJpZ0ludGVnZXIucHJvdG90eXBlLnhvciA9IGJuWG9yO1xuQmlnSW50ZWdlci5wcm90b3R5cGUuYW5kTm90ID0gYm5BbmROb3Q7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5ub3QgPSBibk5vdDtcbkJpZ0ludGVnZXIucHJvdG90eXBlLnNoaWZ0TGVmdCA9IGJuU2hpZnRMZWZ0O1xuQmlnSW50ZWdlci5wcm90b3R5cGUuc2hpZnRSaWdodCA9IGJuU2hpZnRSaWdodDtcbkJpZ0ludGVnZXIucHJvdG90eXBlLmdldExvd2VzdFNldEJpdCA9IGJuR2V0TG93ZXN0U2V0Qml0O1xuQmlnSW50ZWdlci5wcm90b3R5cGUuYml0Q291bnQgPSBibkJpdENvdW50O1xuQmlnSW50ZWdlci5wcm90b3R5cGUudGVzdEJpdCA9IGJuVGVzdEJpdDtcbkJpZ0ludGVnZXIucHJvdG90eXBlLnNldEJpdCA9IGJuU2V0Qml0O1xuQmlnSW50ZWdlci5wcm90b3R5cGUuY2xlYXJCaXQgPSBibkNsZWFyQml0O1xuQmlnSW50ZWdlci5wcm90b3R5cGUuZmxpcEJpdCA9IGJuRmxpcEJpdDtcbkJpZ0ludGVnZXIucHJvdG90eXBlLmFkZCA9IGJuQWRkO1xuQmlnSW50ZWdlci5wcm90b3R5cGUuc3VidHJhY3QgPSBiblN1YnRyYWN0O1xuQmlnSW50ZWdlci5wcm90b3R5cGUubXVsdGlwbHkgPSBibk11bHRpcGx5O1xuQmlnSW50ZWdlci5wcm90b3R5cGUuZGl2aWRlID0gYm5EaXZpZGU7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5yZW1haW5kZXIgPSBiblJlbWFpbmRlcjtcbkJpZ0ludGVnZXIucHJvdG90eXBlLmRpdmlkZUFuZFJlbWFpbmRlciA9IGJuRGl2aWRlQW5kUmVtYWluZGVyO1xuQmlnSW50ZWdlci5wcm90b3R5cGUubW9kUG93ID0gYm5Nb2RQb3c7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5tb2RJbnZlcnNlID0gYm5Nb2RJbnZlcnNlO1xuQmlnSW50ZWdlci5wcm90b3R5cGUucG93ID0gYm5Qb3c7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5nY2QgPSBibkdDRDtcbkJpZ0ludGVnZXIucHJvdG90eXBlLmlzUHJvYmFibGVQcmltZSA9IGJuSXNQcm9iYWJsZVByaW1lO1xuQmlnSW50ZWdlci5wcm90b3R5cGUudG9NUEkgPSBiblRvTVBJO1xuXG4vLyBKU0JOLXNwZWNpZmljIGV4dGVuc2lvblxuQmlnSW50ZWdlci5wcm90b3R5cGUuc3F1YXJlID0gYm5TcXVhcmU7XG4iLCIvLyBHUEc0QnJvd3NlcnMgLSBBbiBPcGVuUEdQIGltcGxlbWVudGF0aW9uIGluIGphdmFzY3JpcHRcbi8vIENvcHlyaWdodCAoQykgMjAxMSBSZWN1cml0eSBMYWJzIEdtYkhcbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vclxuLy8gbW9kaWZ5IGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyXG4vLyB2ZXJzaW9uIDIuMSBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4vLyBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuLy8gTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZSBHTlVcbi8vIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG4vLyBcbi8vIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYWxvbmcgd2l0aCB0aGlzIGxpYnJhcnk7IGlmIG5vdCwgd3JpdGUgdG8gdGhlIEZyZWUgU29mdHdhcmVcbi8vIEZvdW5kYXRpb24sIEluYy4sIDUxIEZyYW5rbGluIFN0cmVldCwgRmlmdGggRmxvb3IsIEJvc3RvbiwgTUEgIDAyMTEwLTEzMDEgIFVTQVxuLy9cbi8vIFJTQSBpbXBsZW1lbnRhdGlvblxuXG52YXIgQmlnSW50ZWdlciA9IHJlcXVpcmUoJy4vanNibi5qcycpLFxuICB1dGlsID0gcmVxdWlyZSgnLi4vLi4vdXRpbCcpLFxuICByYW5kb20gPSByZXF1aXJlKCcuLi9yYW5kb20uanMnKTtcblxuZnVuY3Rpb24gU2VjdXJlUmFuZG9tKCkge1xuICBmdW5jdGlvbiBuZXh0Qnl0ZXMoYnl0ZUFycmF5KSB7XG4gICAgZm9yICh2YXIgbiA9IDA7IG4gPCBieXRlQXJyYXkubGVuZ3RoOyBuKyspIHtcbiAgICAgIGJ5dGVBcnJheVtuXSA9IHJhbmRvbS5nZXRTZWN1cmVSYW5kb21PY3RldCgpO1xuICAgIH1cbiAgfVxuICB0aGlzLm5leHRCeXRlcyA9IG5leHRCeXRlcztcbn1cblxuZnVuY3Rpb24gUlNBKCkge1xuICAvKipcbiAgICogVGhpcyBmdW5jdGlvbiB1c2VzIGpzYm4gQmlnIE51bSBsaWJyYXJ5IHRvIGRlY3J5cHQgUlNBXG4gICAqIEBwYXJhbSBtXG4gICAqICAgICAgICAgICAgbWVzc2FnZVxuICAgKiBAcGFyYW0gZFxuICAgKiAgICAgICAgICAgIFJTQSBkIGFzIEJpZ0ludGVnZXJcbiAgICogQHBhcmFtIHBcbiAgICogICAgICAgICAgICBSU0EgcCBhcyBCaWdJbnRlZ2VyXG4gICAqIEBwYXJhbSBxXG4gICAqICAgICAgICAgICAgUlNBIHEgYXMgQmlnSW50ZWdlclxuICAgKiBAcGFyYW0gdVxuICAgKiAgICAgICAgICAgIFJTQSB1IGFzIEJpZ0ludGVnZXJcbiAgICogQHJldHVybiB7QmlnSW50ZWdlcn0gVGhlIGRlY3J5cHRlZCB2YWx1ZSBvZiB0aGUgbWVzc2FnZVxuICAgKi9cbiAgZnVuY3Rpb24gZGVjcnlwdChtLCBkLCBwLCBxLCB1KSB7XG4gICAgdmFyIHhwID0gbS5tb2QocCkubW9kUG93KGQubW9kKHAuc3VidHJhY3QoQmlnSW50ZWdlci5PTkUpKSwgcCk7XG4gICAgdmFyIHhxID0gbS5tb2QocSkubW9kUG93KGQubW9kKHEuc3VidHJhY3QoQmlnSW50ZWdlci5PTkUpKSwgcSk7XG4gICAgdXRpbC5wcmludF9kZWJ1ZyhcInJzYS5qcyBkZWNyeXB0XFxueHBuOlwiICsgdXRpbC5oZXhzdHJkdW1wKHhwLnRvTVBJKCkpICsgXCJcXG54cW46XCIgKyB1dGlsLmhleHN0cmR1bXAoeHEudG9NUEkoKSkpO1xuXG4gICAgdmFyIHQgPSB4cS5zdWJ0cmFjdCh4cCk7XG4gICAgaWYgKHRbMF0gPT0gMCkge1xuICAgICAgdCA9IHhwLnN1YnRyYWN0KHhxKTtcbiAgICAgIHQgPSB0Lm11bHRpcGx5KHUpLm1vZChxKTtcbiAgICAgIHQgPSBxLnN1YnRyYWN0KHQpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0ID0gdC5tdWx0aXBseSh1KS5tb2QocSk7XG4gICAgfVxuICAgIHJldHVybiB0Lm11bHRpcGx5KHApLmFkZCh4cCk7XG4gIH1cblxuICAvKipcbiAgICogZW5jcnlwdCBtZXNzYWdlXG4gICAqIEBwYXJhbSBtIG1lc3NhZ2UgYXMgQmlnSW50ZWdlclxuICAgKiBAcGFyYW0gZSBwdWJsaWMgTVBJIHBhcnQgYXMgQmlnSW50ZWdlclxuICAgKiBAcGFyYW0gbiBwdWJsaWMgTVBJIHBhcnQgYXMgQmlnSW50ZWdlclxuICAgKiBAcmV0dXJuIEJpZ0ludGVnZXJcbiAgICovXG4gIGZ1bmN0aW9uIGVuY3J5cHQobSwgZSwgbikge1xuICAgIHJldHVybiBtLm1vZFBvd0ludChlLCBuKTtcbiAgfVxuXG4gIC8qIFNpZ24gYW5kIFZlcmlmeSAqL1xuICBmdW5jdGlvbiBzaWduKG0sIGQsIG4pIHtcbiAgICByZXR1cm4gbS5tb2RQb3coZCwgbik7XG4gIH1cblxuICBmdW5jdGlvbiB2ZXJpZnkoeCwgZSwgbikge1xuICAgIHJldHVybiB4Lm1vZFBvd0ludChlLCBuKTtcbiAgfVxuXG4gIC8vIFwiZW1wdHlcIiBSU0Ega2V5IGNvbnN0cnVjdG9yXG5cbiAgZnVuY3Rpb24ga2V5T2JqZWN0KCkge1xuICAgIHRoaXMubiA9IG51bGw7XG4gICAgdGhpcy5lID0gMDtcbiAgICB0aGlzLmVlID0gbnVsbDtcbiAgICB0aGlzLmQgPSBudWxsO1xuICAgIHRoaXMucCA9IG51bGw7XG4gICAgdGhpcy5xID0gbnVsbDtcbiAgICB0aGlzLmRtcDEgPSBudWxsO1xuICAgIHRoaXMuZG1xMSA9IG51bGw7XG4gICAgdGhpcy51ID0gbnVsbDtcbiAgfVxuXG4gIC8vIEdlbmVyYXRlIGEgbmV3IHJhbmRvbSBwcml2YXRlIGtleSBCIGJpdHMgbG9uZywgdXNpbmcgcHVibGljIGV4cHQgRVxuXG4gIGZ1bmN0aW9uIGdlbmVyYXRlKEIsIEUpIHtcbiAgICB2YXIga2V5ID0gbmV3IGtleU9iamVjdCgpO1xuICAgIHZhciBybmcgPSBuZXcgU2VjdXJlUmFuZG9tKCk7XG4gICAgdmFyIHFzID0gQiA+PiAxO1xuICAgIGtleS5lID0gcGFyc2VJbnQoRSwgMTYpO1xuICAgIGtleS5lZSA9IG5ldyBCaWdJbnRlZ2VyKEUsIDE2KTtcbiAgICBmb3IgKDs7KSB7XG4gICAgICBmb3IgKDs7KSB7XG4gICAgICAgIGtleS5wID0gbmV3IEJpZ0ludGVnZXIoQiAtIHFzLCAxLCBybmcpO1xuICAgICAgICBpZiAoa2V5LnAuc3VidHJhY3QoQmlnSW50ZWdlci5PTkUpLmdjZChrZXkuZWUpLmNvbXBhcmVUbyhCaWdJbnRlZ2VyLk9ORSkgPT0gMCAmJiBrZXkucC5pc1Byb2JhYmxlUHJpbWUoMTApKVxuICAgICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgICAgZm9yICg7Oykge1xuICAgICAgICBrZXkucSA9IG5ldyBCaWdJbnRlZ2VyKHFzLCAxLCBybmcpO1xuICAgICAgICBpZiAoa2V5LnEuc3VidHJhY3QoQmlnSW50ZWdlci5PTkUpLmdjZChrZXkuZWUpLmNvbXBhcmVUbyhCaWdJbnRlZ2VyLk9ORSkgPT0gMCAmJiBrZXkucS5pc1Byb2JhYmxlUHJpbWUoMTApKVxuICAgICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgICAgaWYgKGtleS5wLmNvbXBhcmVUbyhrZXkucSkgPD0gMCkge1xuICAgICAgICB2YXIgdCA9IGtleS5wO1xuICAgICAgICBrZXkucCA9IGtleS5xO1xuICAgICAgICBrZXkucSA9IHQ7XG4gICAgICB9XG4gICAgICB2YXIgcDEgPSBrZXkucC5zdWJ0cmFjdChCaWdJbnRlZ2VyLk9ORSk7XG4gICAgICB2YXIgcTEgPSBrZXkucS5zdWJ0cmFjdChCaWdJbnRlZ2VyLk9ORSk7XG4gICAgICB2YXIgcGhpID0gcDEubXVsdGlwbHkocTEpO1xuICAgICAgaWYgKHBoaS5nY2Qoa2V5LmVlKS5jb21wYXJlVG8oQmlnSW50ZWdlci5PTkUpID09IDApIHtcbiAgICAgICAga2V5Lm4gPSBrZXkucC5tdWx0aXBseShrZXkucSk7XG4gICAgICAgIGtleS5kID0ga2V5LmVlLm1vZEludmVyc2UocGhpKTtcbiAgICAgICAga2V5LmRtcDEgPSBrZXkuZC5tb2QocDEpO1xuICAgICAgICBrZXkuZG1xMSA9IGtleS5kLm1vZChxMSk7XG4gICAgICAgIGtleS51ID0ga2V5LnAubW9kSW52ZXJzZShrZXkucSk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4ga2V5O1xuICB9XG5cbiAgdGhpcy5lbmNyeXB0ID0gZW5jcnlwdDtcbiAgdGhpcy5kZWNyeXB0ID0gZGVjcnlwdDtcbiAgdGhpcy52ZXJpZnkgPSB2ZXJpZnk7XG4gIHRoaXMuc2lnbiA9IHNpZ247XG4gIHRoaXMuZ2VuZXJhdGUgPSBnZW5lcmF0ZTtcbiAgdGhpcy5rZXlPYmplY3QgPSBrZXlPYmplY3Q7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gUlNBO1xuIiwiLy8gR1BHNEJyb3dzZXJzIC0gQW4gT3BlblBHUCBpbXBsZW1lbnRhdGlvbiBpbiBqYXZhc2NyaXB0XG4vLyBDb3B5cmlnaHQgKEMpIDIwMTEgUmVjdXJpdHkgTGFicyBHbWJIXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3Jcbi8vIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlclxuLy8gdmVyc2lvbiAyLjEgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuLy8gYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2Zcbi8vIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUgR05VXG4vLyBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuLy8gXG4vLyBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFsb25nIHdpdGggdGhpcyBsaWJyYXJ5OyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlXG4vLyBGb3VuZGF0aW9uLCBJbmMuLCA1MSBGcmFua2xpbiBTdHJlZXQsIEZpZnRoIEZsb29yLCBCb3N0b24sIE1BICAwMjExMC0xMzAxICBVU0EgXG5cbi8vIFRoZSBHUEc0QnJvd3NlcnMgY3J5cHRvIGludGVyZmFjZVxuXG52YXIgdHlwZV9tcGkgPSByZXF1aXJlKCcuLi90eXBlL21waS5qcycpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgLyoqXG4gICAqIFJldHJpZXZlIHNlY3VyZSByYW5kb20gYnl0ZSBzdHJpbmcgb2YgdGhlIHNwZWNpZmllZCBsZW5ndGhcbiAgICogQHBhcmFtIHtJbnRlZ2VyfSBsZW5ndGggTGVuZ3RoIGluIGJ5dGVzIHRvIGdlbmVyYXRlXG4gICAqIEByZXR1cm4ge1N0cmluZ30gUmFuZG9tIGJ5dGUgc3RyaW5nXG4gICAqL1xuICBnZXRSYW5kb21CeXRlczogZnVuY3Rpb24obGVuZ3RoKSB7XG4gICAgdmFyIHJlc3VsdCA9ICcnO1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpKyspIHtcbiAgICAgIHJlc3VsdCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKHRoaXMuZ2V0U2VjdXJlUmFuZG9tT2N0ZXQoKSk7XG4gICAgfVxuICAgIHJldHVybiByZXN1bHQ7XG4gIH0sXG5cbiAgLyoqXG4gICAqIFJldHVybiBhIHBzZXVkby1yYW5kb20gbnVtYmVyIGluIHRoZSBzcGVjaWZpZWQgcmFuZ2VcbiAgICogQHBhcmFtIHtJbnRlZ2VyfSBmcm9tIE1pbiBvZiB0aGUgcmFuZG9tIG51bWJlclxuICAgKiBAcGFyYW0ge0ludGVnZXJ9IHRvIE1heCBvZiB0aGUgcmFuZG9tIG51bWJlciAobWF4IDMyYml0KVxuICAgKiBAcmV0dXJuIHtJbnRlZ2VyfSBBIHBzZXVkbyByYW5kb20gbnVtYmVyXG4gICAqL1xuICBnZXRQc2V1ZG9SYW5kb206IGZ1bmN0aW9uKGZyb20sIHRvKSB7XG4gICAgcmV0dXJuIE1hdGgucm91bmQoTWF0aC5yYW5kb20oKSAqICh0byAtIGZyb20pKSArIGZyb207XG4gIH0sXG5cbiAgLyoqXG4gICAqIFJldHVybiBhIHNlY3VyZSByYW5kb20gbnVtYmVyIGluIHRoZSBzcGVjaWZpZWQgcmFuZ2VcbiAgICogQHBhcmFtIHtJbnRlZ2VyfSBmcm9tIE1pbiBvZiB0aGUgcmFuZG9tIG51bWJlclxuICAgKiBAcGFyYW0ge0ludGVnZXJ9IHRvIE1heCBvZiB0aGUgcmFuZG9tIG51bWJlciAobWF4IDMyYml0KVxuICAgKiBAcmV0dXJuIHtJbnRlZ2VyfSBBIHNlY3VyZSByYW5kb20gbnVtYmVyXG4gICAqL1xuICBnZXRTZWN1cmVSYW5kb206IGZ1bmN0aW9uKGZyb20sIHRvKSB7XG4gICAgdmFyIGJ1ZiA9IG5ldyBVaW50MzJBcnJheSgxKTtcbiAgICB3aW5kb3cuY3J5cHRvLmdldFJhbmRvbVZhbHVlcyhidWYpO1xuICAgIHZhciBiaXRzID0gKCh0byAtIGZyb20pKS50b1N0cmluZygyKS5sZW5ndGg7XG4gICAgd2hpbGUgKChidWZbMF0gJiAoTWF0aC5wb3coMiwgYml0cykgLSAxKSkgPiAodG8gLSBmcm9tKSlcbiAgICAgIHdpbmRvdy5jcnlwdG8uZ2V0UmFuZG9tVmFsdWVzKGJ1Zik7XG4gICAgcmV0dXJuIGZyb20gKyAoTWF0aC5hYnMoYnVmWzBdICYgKE1hdGgucG93KDIsIGJpdHMpIC0gMSkpKTtcbiAgfSxcblxuICBnZXRTZWN1cmVSYW5kb21PY3RldDogZnVuY3Rpb24oKSB7XG4gICAgdmFyIGJ1ZiA9IG5ldyBVaW50MzJBcnJheSgxKTtcbiAgICB3aW5kb3cuY3J5cHRvLmdldFJhbmRvbVZhbHVlcyhidWYpO1xuICAgIHJldHVybiBidWZbMF0gJiAweEZGO1xuICB9LFxuXG4gIC8qKlxuICAgKiBDcmVhdGUgYSBzZWN1cmUgcmFuZG9tIGJpZyBpbnRlZ2VyIG9mIGJpdHMgbGVuZ3RoXG4gICAqIEBwYXJhbSB7SW50ZWdlcn0gYml0cyBCaXQgbGVuZ3RoIG9mIHRoZSBNUEkgdG8gY3JlYXRlXG4gICAqIEByZXR1cm4ge0JpZ0ludGVnZXJ9IFJlc3VsdGluZyBiaWcgaW50ZWdlclxuICAgKi9cbiAgZ2V0UmFuZG9tQmlnSW50ZWdlcjogZnVuY3Rpb24oYml0cykge1xuICAgIGlmIChiaXRzIDwgMCkge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICAgIHZhciBudW1CeXRlcyA9IE1hdGguZmxvb3IoKGJpdHMgKyA3KSAvIDgpO1xuXG4gICAgdmFyIHJhbmRvbUJpdHMgPSB0aGlzLmdldFJhbmRvbUJ5dGVzKG51bUJ5dGVzKTtcbiAgICBpZiAoYml0cyAlIDggPiAwKSB7XG5cbiAgICAgIHJhbmRvbUJpdHMgPSBTdHJpbmcuZnJvbUNoYXJDb2RlKFxuICAgICAgKE1hdGgucG93KDIsIGJpdHMgJSA4KSAtIDEpICZcbiAgICAgICAgcmFuZG9tQml0cy5jaGFyQ29kZUF0KDApKSArXG4gICAgICAgIHJhbmRvbUJpdHMuc3Vic3RyaW5nKDEpO1xuICAgIH1cbiAgICB2YXIgbXBpID0gbmV3IHR5cGVfbXBpKCk7XG4gICAgbXBpLmZyb21CeXRlcyhyYW5kb21CaXRzKTtcbiAgICByZXR1cm4gbXBpLnRvQmlnSW50ZWdlcigpO1xuICB9LFxuXG4gIGdldFJhbmRvbUJpZ0ludGVnZXJJblJhbmdlOiBmdW5jdGlvbihtaW4sIG1heCkge1xuICAgIGlmIChtYXguY29tcGFyZVRvKG1pbikgPD0gMCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHZhciByYW5nZSA9IG1heC5zdWJ0cmFjdChtaW4pO1xuICAgIHZhciByID0gdGhpcy5nZXRSYW5kb21CaWdJbnRlZ2VyKHJhbmdlLmJpdExlbmd0aCgpKTtcbiAgICB3aGlsZSAociA+IHJhbmdlKSB7XG4gICAgICByID0gdGhpcy5nZXRSYW5kb21CaWdJbnRlZ2VyKHJhbmdlLmJpdExlbmd0aCgpKTtcbiAgICB9XG4gICAgcmV0dXJuIG1pbi5hZGQocik7XG4gIH1cblxufTtcbiIsInZhciBwdWJsaWNLZXkgPSByZXF1aXJlKCcuL3B1YmxpY19rZXknKSxcbiAgcGtjczEgPSByZXF1aXJlKCcuL3BrY3MxLmpzJyksXG4gIGhhc2hNb2R1bGUgPSByZXF1aXJlKCcuL2hhc2gnKTtcblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gIC8qKlxuICAgKiBcbiAgICogQHBhcmFtIHtJbnRlZ2VyfSBhbGdvIHB1YmxpYyBLZXkgYWxnb3JpdGhtXG4gICAqIEBwYXJhbSB7SW50ZWdlcn0gaGFzaF9hbGdvIEhhc2ggYWxnb3JpdGhtXG4gICAqIEBwYXJhbSB7b3BlbnBncF90eXBlX21waVtdfSBtc2dfTVBJcyBTaWduYXR1cmUgbXVsdGlwcmVjaXNpb24gaW50ZWdlcnNcbiAgICogQHBhcmFtIHtvcGVucGdwX3R5cGVfbXBpW119IHB1YmxpY2tleV9NUElzIFB1YmxpYyBrZXkgbXVsdGlwcmVjaXNpb24gaW50ZWdlcnMgXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBkYXRhIERhdGEgb24gd2hlcmUgdGhlIHNpZ25hdHVyZSB3YXMgY29tcHV0ZWQgb24uXG4gICAqIEByZXR1cm4ge0Jvb2xlYW59IHRydWUgaWYgc2lnbmF0dXJlIChzaWdfZGF0YSB3YXMgZXF1YWwgdG8gZGF0YSBvdmVyIGhhc2gpXG4gICAqL1xuICB2ZXJpZnk6IGZ1bmN0aW9uKGFsZ28sIGhhc2hfYWxnbywgbXNnX01QSXMsIHB1YmxpY2tleV9NUElzLCBkYXRhKSB7XG4gICAgdmFyIGNhbGNfaGFzaCA9IGhhc2hNb2R1bGUuZGlnZXN0KGhhc2hfYWxnbywgZGF0YSk7XG5cbiAgICBzd2l0Y2ggKGFsZ28pIHtcbiAgICAgIGNhc2UgMTpcbiAgICAgICAgLy8gUlNBIChFbmNyeXB0IG9yIFNpZ24pIFtIQUNdICBcbiAgICAgIGNhc2UgMjpcbiAgICAgICAgLy8gUlNBIEVuY3J5cHQtT25seSBbSEFDXVxuICAgICAgY2FzZSAzOlxuICAgICAgICAvLyBSU0EgU2lnbi1Pbmx5IFtIQUNdXG4gICAgICAgIHZhciByc2EgPSBuZXcgcHVibGljS2V5LnJzYSgpO1xuICAgICAgICB2YXIgbiA9IHB1YmxpY2tleV9NUElzWzBdLnRvQmlnSW50ZWdlcigpO1xuICAgICAgICB2YXIgZSA9IHB1YmxpY2tleV9NUElzWzFdLnRvQmlnSW50ZWdlcigpO1xuICAgICAgICB2YXIgeCA9IG1zZ19NUElzWzBdLnRvQmlnSW50ZWdlcigpO1xuICAgICAgICB2YXIgZG9wdWJsaWMgPSByc2EudmVyaWZ5KHgsIGUsIG4pO1xuICAgICAgICB2YXIgaGFzaCA9IHBrY3MxLmVtc2EuZGVjb2RlKGhhc2hfYWxnbywgZG9wdWJsaWMudG9NUEkoKS5zdWJzdHJpbmcoMikpO1xuICAgICAgICBpZiAoaGFzaCA9PSAtMSkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcignUEtDUzEgcGFkZGluZyBpbiBtZXNzYWdlIG9yIGtleSBpbmNvcnJlY3QuIEFib3J0aW5nLi4uJyk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGhhc2ggPT0gY2FsY19oYXNoO1xuXG4gICAgICBjYXNlIDE2OlxuICAgICAgICAvLyBFbGdhbWFsIChFbmNyeXB0LU9ubHkpIFtFTEdBTUFMXSBbSEFDXVxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJzaWduaW5nIHdpdGggRWxnYW1hbCBpcyBub3QgZGVmaW5lZCBpbiB0aGUgT3BlblBHUCBzdGFuZGFyZC5cIik7XG4gICAgICBjYXNlIDE3OlxuICAgICAgICAvLyBEU0EgKERpZ2l0YWwgU2lnbmF0dXJlIEFsZ29yaXRobSkgW0ZJUFMxODZdIFtIQUNdXG4gICAgICAgIHZhciBkc2EgPSBuZXcgcHVibGljS2V5LmRzYSgpO1xuICAgICAgICB2YXIgczEgPSBtc2dfTVBJc1swXS50b0JpZ0ludGVnZXIoKTtcbiAgICAgICAgdmFyIHMyID0gbXNnX01QSXNbMV0udG9CaWdJbnRlZ2VyKCk7XG4gICAgICAgIHZhciBwID0gcHVibGlja2V5X01QSXNbMF0udG9CaWdJbnRlZ2VyKCk7XG4gICAgICAgIHZhciBxID0gcHVibGlja2V5X01QSXNbMV0udG9CaWdJbnRlZ2VyKCk7XG4gICAgICAgIHZhciBnID0gcHVibGlja2V5X01QSXNbMl0udG9CaWdJbnRlZ2VyKCk7XG4gICAgICAgIHZhciB5ID0gcHVibGlja2V5X01QSXNbM10udG9CaWdJbnRlZ2VyKCk7XG4gICAgICAgIHZhciBtID0gZGF0YTtcbiAgICAgICAgdmFyIGRvcHVibGljID0gZHNhLnZlcmlmeShoYXNoX2FsZ28sIHMxLCBzMiwgbSwgcCwgcSwgZywgeSk7XG4gICAgICAgIHJldHVybiBkb3B1YmxpYy5jb21wYXJlVG8oczEpID09IDA7XG4gICAgICBkZWZhdWx0OlxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgc2lnbmF0dXJlIGFsZ29yaXRobS4nKTtcbiAgICB9XG5cbiAgfSxcblxuICAvKipcbiAgICogQ3JlYXRlIGEgc2lnbmF0dXJlIG9uIGRhdGEgdXNpbmcgdGhlIHNwZWNpZmllZCBhbGdvcml0aG1cbiAgICogQHBhcmFtIHtJbnRlZ2VyfSBoYXNoX2FsZ28gaGFzaCBBbGdvcml0aG0gdG8gdXNlIChTZWUgUkZDNDg4MCA5LjQpXG4gICAqIEBwYXJhbSB7SW50ZWdlcn0gYWxnbyBBc3ltbWV0cmljIGNpcGhlciBhbGdvcml0aG0gdG8gdXNlIChTZWUgUkZDNDg4MCA5LjEpXG4gICAqIEBwYXJhbSB7b3BlbnBncF90eXBlX21waVtdfSBwdWJsaWNNUElzIFB1YmxpYyBrZXkgbXVsdGlwcmVjaXNpb24gaW50ZWdlcnMgXG4gICAqIG9mIHRoZSBwcml2YXRlIGtleSBcbiAgICogQHBhcmFtIHtvcGVucGdwX3R5cGVfbXBpW119IHNlY3JldE1QSXMgUHJpdmF0ZSBrZXkgbXVsdGlwcmVjaXNpb24gXG4gICAqIGludGVnZXJzIHdoaWNoIGlzIHVzZWQgdG8gc2lnbiB0aGUgZGF0YVxuICAgKiBAcGFyYW0ge1N0cmluZ30gZGF0YSBEYXRhIHRvIGJlIHNpZ25lZFxuICAgKiBAcmV0dXJuIHtvcGVucGdwX3R5cGVfbXBpW119XG4gICAqL1xuICBzaWduOiBmdW5jdGlvbihoYXNoX2FsZ28sIGFsZ28sIGtleUludGVnZXJzLCBkYXRhKSB7XG5cbiAgICBzd2l0Y2ggKGFsZ28pIHtcbiAgICAgIGNhc2UgMTpcbiAgICAgICAgLy8gUlNBIChFbmNyeXB0IG9yIFNpZ24pIFtIQUNdICBcbiAgICAgIGNhc2UgMjpcbiAgICAgICAgLy8gUlNBIEVuY3J5cHQtT25seSBbSEFDXVxuICAgICAgY2FzZSAzOlxuICAgICAgICAvLyBSU0EgU2lnbi1Pbmx5IFtIQUNdXG4gICAgICAgIHZhciByc2EgPSBuZXcgcHVibGljS2V5LnJzYSgpO1xuICAgICAgICB2YXIgZCA9IGtleUludGVnZXJzWzJdLnRvQmlnSW50ZWdlcigpO1xuICAgICAgICB2YXIgbiA9IGtleUludGVnZXJzWzBdLnRvQmlnSW50ZWdlcigpO1xuICAgICAgICB2YXIgbSA9IHBrY3MxLmVtc2EuZW5jb2RlKGhhc2hfYWxnbyxcbiAgICAgICAgICBkYXRhLCBrZXlJbnRlZ2Vyc1swXS5ieXRlTGVuZ3RoKCkpO1xuXG4gICAgICAgIHJldHVybiByc2Euc2lnbihtLCBkLCBuKS50b01QSSgpO1xuXG4gICAgICBjYXNlIDE3OlxuICAgICAgICAvLyBEU0EgKERpZ2l0YWwgU2lnbmF0dXJlIEFsZ29yaXRobSkgW0ZJUFMxODZdIFtIQUNdXG4gICAgICAgIHZhciBkc2EgPSBuZXcgcHVibGljS2V5LmRzYSgpO1xuXG4gICAgICAgIHZhciBwID0ga2V5SW50ZWdlcnNbMF0udG9CaWdJbnRlZ2VyKCk7XG4gICAgICAgIHZhciBxID0ga2V5SW50ZWdlcnNbMV0udG9CaWdJbnRlZ2VyKCk7XG4gICAgICAgIHZhciBnID0ga2V5SW50ZWdlcnNbMl0udG9CaWdJbnRlZ2VyKCk7XG4gICAgICAgIHZhciB5ID0ga2V5SW50ZWdlcnNbM10udG9CaWdJbnRlZ2VyKCk7XG4gICAgICAgIHZhciB4ID0ga2V5SW50ZWdlcnNbNF0udG9CaWdJbnRlZ2VyKCk7XG4gICAgICAgIHZhciBtID0gZGF0YTtcbiAgICAgICAgdmFyIHJlc3VsdCA9IGRzYS5zaWduKGhhc2hfYWxnbywgbSwgZywgcCwgcSwgeCk7XG5cbiAgICAgICAgcmV0dXJuIHJlc3VsdFswXS50b1N0cmluZygpICsgcmVzdWx0WzFdLnRvU3RyaW5nKCk7XG4gICAgICBjYXNlIDE2OlxuICAgICAgICAvLyBFbGdhbWFsIChFbmNyeXB0LU9ubHkpIFtFTEdBTUFMXSBbSEFDXVxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1NpZ25pbmcgd2l0aCBFbGdhbWFsIGlzIG5vdCBkZWZpbmVkIGluIHRoZSBPcGVuUEdQIHN0YW5kYXJkLicpO1xuICAgICAgZGVmYXVsdDpcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIHNpZ25hdHVyZSBhbGdvcml0aG0uJyk7XG4gICAgfVxuICB9XG59XG4iLCIvLyBHUEc0QnJvd3NlcnMgLSBBbiBPcGVuUEdQIGltcGxlbWVudGF0aW9uIGluIGphdmFzY3JpcHRcbi8vIENvcHlyaWdodCAoQykgMjAxMSBSZWN1cml0eSBMYWJzIEdtYkhcbi8vXG4vLyBUaGlzIGxpYnJhcnkgaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yXG4vLyBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uOyBlaXRoZXJcbi8vIHZlcnNpb24gMi4xIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuLy9cbi8vIFRoaXMgbGlicmFyeSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuLy8gYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2Zcbi8vIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUgR05VXG4vLyBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuLy9cbi8vIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYWxvbmcgd2l0aCB0aGlzIGxpYnJhcnk7IGlmIG5vdCwgd3JpdGUgdG8gdGhlIEZyZWUgU29mdHdhcmVcbi8vIEZvdW5kYXRpb24sIEluYy4sIDUxIEZyYW5rbGluIFN0cmVldCwgRmlmdGggRmxvb3IsIEJvc3RvbiwgTUEgIDAyMTEwLTEzMDEgIFVTQVxuXG52YXIgYmFzZTY0ID0gcmVxdWlyZSgnLi9iYXNlNjQuanMnKTtcbnZhciBlbnVtcyA9IHJlcXVpcmUoJy4uL2VudW1zLmpzJyk7XG52YXIgY29uZmlnID0gcmVxdWlyZSgnLi4vY29uZmlnJyk7XG5cbi8qKlxuICogRmluZHMgb3V0IHdoaWNoIEFzY2lpIEFybW9yaW5nIHR5cGUgaXMgdXNlZC4gVGhpcyBpcyBhbiBpbnRlcm5hbCBmdW5jdGlvblxuICogQHBhcmFtIHtTdHJpbmd9IHRleHQgW1N0cmluZ10gYXNjaWkgYXJtb3JlZCB0ZXh0XG4gKiBAcmV0dXJucyB7SW50ZWdlcn0gMCA9IE1FU1NBR0UgUEFSVCBuIG9mIG1cbiAqICAgICAgICAgMSA9IE1FU1NBR0UgUEFSVCBuXG4gKiAgICAgICAgIDIgPSBTSUdORUQgTUVTU0FHRVxuICogICAgICAgICAzID0gUEdQIE1FU1NBR0VcbiAqICAgICAgICAgNCA9IFBVQkxJQyBLRVkgQkxPQ0tcbiAqICAgICAgICAgNSA9IFBSSVZBVEUgS0VZIEJMT0NLXG4gKiAgICAgICAgIG51bGwgPSB1bmtub3duXG4gKi9cbmZ1bmN0aW9uIGdldF90eXBlKHRleHQpIHtcbiAgdmFyIHJlSGVhZGVyID0gL14tLS0tLShbXi1dKyktLS0tLSRcXG4vbTtcblxuICB2YXIgaGVhZGVyID0gdGV4dC5tYXRjaChyZUhlYWRlcik7XG5cbiAgLy8gQkVHSU4gUEdQIE1FU1NBR0UsIFBBUlQgWC9ZXG4gIC8vIFVzZWQgZm9yIG11bHRpLXBhcnQgbWVzc2FnZXMsIHdoZXJlIHRoZSBhcm1vciBpcyBzcGxpdCBhbW9uZ3N0IFlcbiAgLy8gcGFydHMsIGFuZCB0aGlzIGlzIHRoZSBYdGggcGFydCBvdXQgb2YgWS5cbiAgaWYgKGhlYWRlclsxXS5tYXRjaCgvQkVHSU4gUEdQIE1FU1NBR0UsIFBBUlQgXFxkK1xcL1xcZCsvKSkge1xuICAgIHJldHVybiBlbnVtcy5hcm1vci5tdWx0aXBhcnRfc2VjdGlvbjtcbiAgfSBlbHNlXG4gIC8vIEJFR0lOIFBHUCBNRVNTQUdFLCBQQVJUIFhcbiAgLy8gVXNlZCBmb3IgbXVsdGktcGFydCBtZXNzYWdlcywgd2hlcmUgdGhpcyBpcyB0aGUgWHRoIHBhcnQgb2YgYW5cbiAgLy8gdW5zcGVjaWZpZWQgbnVtYmVyIG9mIHBhcnRzLiBSZXF1aXJlcyB0aGUgTUVTU0FHRS1JRCBBcm1vclxuICAvLyBIZWFkZXIgdG8gYmUgdXNlZC5cbiAgaWYgKGhlYWRlclsxXS5tYXRjaCgvQkVHSU4gUEdQIE1FU1NBR0UsIFBBUlQgXFxkKy8pKSB7XG4gICAgcmV0dXJuIGVudW1zLmFybW9yLm11bHRpcGFydF9sYXN0O1xuXG4gIH0gZWxzZVxuICAvLyBCRUdJTiBQR1AgU0lHTkFUVVJFXG4gIC8vIFVzZWQgZm9yIGRldGFjaGVkIHNpZ25hdHVyZXMsIE9wZW5QR1AvTUlNRSBzaWduYXR1cmVzLCBhbmRcbiAgLy8gY2xlYXJ0ZXh0IHNpZ25hdHVyZXMuIE5vdGUgdGhhdCBQR1AgMi54IHVzZXMgQkVHSU4gUEdQIE1FU1NBR0VcbiAgLy8gZm9yIGRldGFjaGVkIHNpZ25hdHVyZXMuXG4gIGlmIChoZWFkZXJbMV0ubWF0Y2goL0JFR0lOIFBHUCBTSUdORUQgTUVTU0FHRS8pKSB7XG4gICAgcmV0dXJuIGVudW1zLmFybW9yLnNpZ25lZDtcblxuICB9IGVsc2VcbiAgLy8gQkVHSU4gUEdQIE1FU1NBR0VcbiAgLy8gVXNlZCBmb3Igc2lnbmVkLCBlbmNyeXB0ZWQsIG9yIGNvbXByZXNzZWQgZmlsZXMuXG4gIGlmIChoZWFkZXJbMV0ubWF0Y2goL0JFR0lOIFBHUCBNRVNTQUdFLykpIHtcbiAgICByZXR1cm4gZW51bXMuYXJtb3IubWVzc2FnZTtcblxuICB9IGVsc2VcbiAgLy8gQkVHSU4gUEdQIFBVQkxJQyBLRVkgQkxPQ0tcbiAgLy8gVXNlZCBmb3IgYXJtb3JpbmcgcHVibGljIGtleXMuXG4gIGlmIChoZWFkZXJbMV0ubWF0Y2goL0JFR0lOIFBHUCBQVUJMSUMgS0VZIEJMT0NLLykpIHtcbiAgICByZXR1cm4gZW51bXMuYXJtb3IucHVibGljX2tleTtcblxuICB9IGVsc2VcbiAgLy8gQkVHSU4gUEdQIFBSSVZBVEUgS0VZIEJMT0NLXG4gIC8vIFVzZWQgZm9yIGFybW9yaW5nIHByaXZhdGUga2V5cy5cbiAgaWYgKGhlYWRlclsxXS5tYXRjaCgvQkVHSU4gUEdQIFBSSVZBVEUgS0VZIEJMT0NLLykpIHtcbiAgICByZXR1cm4gZW51bXMuYXJtb3IucHJpdmF0ZV9rZXk7XG4gIH1cbn1cblxuLyoqXG4gKiBBZGQgYWRkaXRpb25hbCBpbmZvcm1hdGlvbiB0byB0aGUgYXJtb3IgdmVyc2lvbiBvZiBhbiBPcGVuUEdQIGJpbmFyeVxuICogcGFja2V0IGJsb2NrLlxuICogQGF1dGhvciAgQWxleFxuICogQHZlcnNpb24gMjAxMS0xMi0xNlxuICogQHJldHVybnMge1N0cmluZ30gVGhlIGhlYWRlciBpbmZvcm1hdGlvblxuICovXG5mdW5jdGlvbiBhcm1vcl9hZGRoZWFkZXIoKSB7XG4gIHZhciByZXN1bHQgPSBcIlwiO1xuICBpZiAoY29uZmlnLnNob3dfdmVyc2lvbikge1xuICAgIHJlc3VsdCArPSBcIlZlcnNpb246IFwiICsgY29uZmlnLnZlcnNpb25zdHJpbmcgKyAnXFxyXFxuJztcbiAgfVxuICBpZiAoY29uZmlnLnNob3dfY29tbWVudCkge1xuICAgIHJlc3VsdCArPSBcIkNvbW1lbnQ6IFwiICsgY29uZmlnLmNvbW1lbnRzdHJpbmcgKyAnXFxyXFxuJztcbiAgfVxuICByZXN1bHQgKz0gJ1xcclxcbic7XG4gIHJldHVybiByZXN1bHQ7XG59XG5cblxuXG4vKipcbiAqIENhbGN1bGF0ZXMgYSBjaGVja3N1bSBvdmVyIHRoZSBnaXZlbiBkYXRhIGFuZCByZXR1cm5zIGl0IGJhc2U2NCBlbmNvZGVkXG4gKiBAcGFyYW0ge1N0cmluZ30gZGF0YSBEYXRhIHRvIGNyZWF0ZSBhIENSQy0yNCBjaGVja3N1bSBmb3JcbiAqIEByZXR1cm4ge1N0cmluZ30gQmFzZTY0IGVuY29kZWQgY2hlY2tzdW1cbiAqL1xuZnVuY3Rpb24gZ2V0Q2hlY2tTdW0oZGF0YSkge1xuICB2YXIgYyA9IGNyZWF0ZWNyYzI0KGRhdGEpO1xuICB2YXIgc3RyID0gXCJcIiArIFN0cmluZy5mcm9tQ2hhckNvZGUoYyA+PiAxNikgK1xuICAgIFN0cmluZy5mcm9tQ2hhckNvZGUoKGMgPj4gOCkgJiAweEZGKSArXG4gICAgU3RyaW5nLmZyb21DaGFyQ29kZShjICYgMHhGRik7XG4gIHJldHVybiBiYXNlNjQuZW5jb2RlKHN0cik7XG59XG5cbi8qKlxuICogQ2FsY3VsYXRlcyB0aGUgY2hlY2tzdW0gb3ZlciB0aGUgZ2l2ZW4gZGF0YSBhbmQgY29tcGFyZXMgaXQgd2l0aCB0aGVcbiAqIGdpdmVuIGJhc2U2NCBlbmNvZGVkIGNoZWNrc3VtXG4gKiBAcGFyYW0ge1N0cmluZ30gZGF0YSBEYXRhIHRvIGNyZWF0ZSBhIENSQy0yNCBjaGVja3N1bSBmb3JcbiAqIEBwYXJhbSB7U3RyaW5nfSBjaGVja3N1bSBCYXNlNjQgZW5jb2RlZCBjaGVja3N1bVxuICogQHJldHVybiB7Qm9vbGVhbn0gVHJ1ZSBpZiB0aGUgZ2l2ZW4gY2hlY2tzdW0gaXMgY29ycmVjdDsgb3RoZXJ3aXNlIGZhbHNlXG4gKi9cbmZ1bmN0aW9uIHZlcmlmeUNoZWNrU3VtKGRhdGEsIGNoZWNrc3VtKSB7XG4gIHZhciBjID0gZ2V0Q2hlY2tTdW0oZGF0YSk7XG4gIHZhciBkID0gY2hlY2tzdW07XG4gIHJldHVybiBjWzBdID09IGRbMF0gJiYgY1sxXSA9PSBkWzFdICYmIGNbMl0gPT0gZFsyXTtcbn1cbi8qKlxuICogSW50ZXJuYWwgZnVuY3Rpb24gdG8gY2FsY3VsYXRlIGEgQ1JDLTI0IGNoZWNrc3VtIG92ZXIgYSBnaXZlbiBzdHJpbmcgKGRhdGEpXG4gKiBAcGFyYW0ge1N0cmluZ30gZGF0YSBEYXRhIHRvIGNyZWF0ZSBhIENSQy0yNCBjaGVja3N1bSBmb3JcbiAqIEByZXR1cm4ge0ludGVnZXJ9IFRoZSBDUkMtMjQgY2hlY2tzdW0gYXMgbnVtYmVyXG4gKi9cbnZhciBjcmNfdGFibGUgPSBbXG4gICAgMHgwMDAwMDAwMCwgMHgwMDg2NGNmYiwgMHgwMThhZDUwZCwgMHgwMTBjOTlmNiwgMHgwMzkzZTZlMSwgMHgwMzE1YWExYSwgMHgwMjE5MzNlYywgMHgwMjlmN2YxNywgMHgwN2ExODEzOSxcbiAgICAweDA3MjdjZGMyLCAweDA2MmI1NDM0LCAweDA2YWQxOGNmLCAweDA0MzI2N2Q4LCAweDA0YjQyYjIzLCAweDA1YjhiMmQ1LCAweDA1M2VmZTJlLCAweDBmYzU0ZTg5LCAweDBmNDMwMjcyLFxuICAgIDB4MGU0ZjliODQsIDB4MGVjOWQ3N2YsIDB4MGM1NmE4NjgsIDB4MGNkMGU0OTMsIDB4MGRkYzdkNjUsIDB4MGQ1YTMxOWUsIDB4MDg2NGNmYjAsIDB4MDhlMjgzNGIsIDB4MDllZTFhYmQsXG4gICAgMHgwOTY4NTY0NiwgMHgwYmY3Mjk1MSwgMHgwYjcxNjVhYSwgMHgwYTdkZmM1YywgMHgwYWZiYjBhNywgMHgxZjBjZDFlOSwgMHgxZjhhOWQxMiwgMHgxZTg2MDRlNCwgMHgxZTAwNDgxZixcbiAgICAweDFjOWYzNzA4LCAweDFjMTk3YmYzLCAweDFkMTVlMjA1LCAweDFkOTNhZWZlLCAweDE4YWQ1MGQwLCAweDE4MmIxYzJiLCAweDE5Mjc4NWRkLCAweDE5YTFjOTI2LCAweDFiM2ViNjMxLFxuICAgIDB4MWJiOGZhY2EsIDB4MWFiNDYzM2MsIDB4MWEzMjJmYzcsIDB4MTBjOTlmNjAsIDB4MTA0ZmQzOWIsIDB4MTE0MzRhNmQsIDB4MTFjNTA2OTYsIDB4MTM1YTc5ODEsIDB4MTNkYzM1N2EsXG4gICAgMHgxMmQwYWM4YywgMHgxMjU2ZTA3NywgMHgxNzY4MWU1OSwgMHgxN2VlNTJhMiwgMHgxNmUyY2I1NCwgMHgxNjY0ODdhZiwgMHgxNGZiZjhiOCwgMHgxNDdkYjQ0MywgMHgxNTcxMmRiNSxcbiAgICAweDE1Zjc2MTRlLCAweDNlMTlhM2QyLCAweDNlOWZlZjI5LCAweDNmOTM3NmRmLCAweDNmMTUzYTI0LCAweDNkOGE0NTMzLCAweDNkMGMwOWM4LCAweDNjMDA5MDNlLCAweDNjODZkY2M1LFxuICAgIDB4MzliODIyZWIsIDB4MzkzZTZlMTAsIDB4MzgzMmY3ZTYsIDB4MzhiNGJiMWQsIDB4M2EyYmM0MGEsIDB4M2FhZDg4ZjEsIDB4M2JhMTExMDcsIDB4M2IyNzVkZmMsIDB4MzFkY2VkNWIsXG4gICAgMHgzMTVhYTFhMCxcbiAgICAweDMwNTYzODU2LCAweDMwZDA3NGFkLCAweDMyNGYwYmJhLCAweDMyYzk0NzQxLCAweDMzYzVkZWI3LCAweDMzNDM5MjRjLCAweDM2N2Q2YzYyLCAweDM2ZmIyMDk5LCAweDM3ZjdiOTZmLFxuICAgIDB4Mzc3MWY1OTQsIDB4MzVlZThhODMsIDB4MzU2OGM2NzgsIDB4MzQ2NDVmOGUsIDB4MzRlMjEzNzUsIDB4MjExNTcyM2IsIDB4MjE5MzNlYzAsIDB4MjA5ZmE3MzYsIDB4MjAxOWViY2QsXG4gICAgMHgyMjg2OTRkYSwgMHgyMjAwZDgyMSwgMHgyMzBjNDFkNywgMHgyMzhhMGQyYywgMHgyNmI0ZjMwMiwgMHgyNjMyYmZmOSwgMHgyNzNlMjYwZiwgMHgyN2I4NmFmNCwgMHgyNTI3MTVlMyxcbiAgICAweDI1YTE1OTE4LCAweDI0YWRjMGVlLCAweDI0MmI4YzE1LCAweDJlZDAzY2IyLCAweDJlNTY3MDQ5LCAweDJmNWFlOWJmLCAweDJmZGNhNTQ0LCAweDJkNDNkYTUzLCAweDJkYzU5NmE4LFxuICAgIDB4MmNjOTBmNWUsIDB4MmM0ZjQzYTUsIDB4Mjk3MWJkOGIsIDB4MjlmN2YxNzAsIDB4MjhmYjY4ODYsIDB4Mjg3ZDI0N2QsIDB4MmFlMjViNmEsIDB4MmE2NDE3OTEsIDB4MmI2ODhlNjcsXG4gICAgMHgyYmVlYzI5YywgMHg3YzMzNDdhNCwgMHg3Y2I1MGI1ZiwgMHg3ZGI5OTJhOSwgMHg3ZDNmZGU1MiwgMHg3ZmEwYTE0NSwgMHg3ZjI2ZWRiZSwgMHg3ZTJhNzQ0OCwgMHg3ZWFjMzhiMyxcbiAgICAweDdiOTJjNjlkLCAweDdiMTQ4YTY2LCAweDdhMTgxMzkwLCAweDdhOWU1ZjZiLCAweDc4MDEyMDdjLCAweDc4ODc2Yzg3LCAweDc5OGJmNTcxLCAweDc5MGRiOThhLCAweDczZjYwOTJkLFxuICAgIDB4NzM3MDQ1ZDYsIDB4NzI3Y2RjMjAsIDB4NzJmYTkwZGIsIDB4NzA2NWVmY2MsIDB4NzBlM2EzMzcsIDB4NzFlZjNhYzEsIDB4NzE2OTc2M2EsIDB4NzQ1Nzg4MTQsIDB4NzRkMWM0ZWYsXG4gICAgMHg3NWRkNWQxOSwgMHg3NTViMTFlMiwgMHg3N2M0NmVmNSwgMHg3NzQyMjIwZSwgMHg3NjRlYmJmOCwgMHg3NmM4ZjcwMywgMHg2MzNmOTY0ZCwgMHg2M2I5ZGFiNiwgMHg2MmI1NDM0MCxcbiAgICAweDYyMzMwZmJiLFxuICAgIDB4NjBhYzcwYWMsIDB4NjAyYTNjNTcsIDB4NjEyNmE1YTEsIDB4NjFhMGU5NWEsIDB4NjQ5ZTE3NzQsIDB4NjQxODViOGYsIDB4NjUxNGMyNzksIDB4NjU5MjhlODIsIDB4NjcwZGYxOTUsXG4gICAgMHg2NzhiYmQ2ZSwgMHg2Njg3MjQ5OCwgMHg2NjAxNjg2MywgMHg2Y2ZhZDhjNCwgMHg2YzdjOTQzZiwgMHg2ZDcwMGRjOSwgMHg2ZGY2NDEzMiwgMHg2ZjY5M2UyNSwgMHg2ZmVmNzJkZSxcbiAgICAweDZlZTNlYjI4LCAweDZlNjVhN2QzLCAweDZiNWI1OWZkLCAweDZiZGQxNTA2LCAweDZhZDE4Y2YwLCAweDZhNTdjMDBiLCAweDY4YzhiZjFjLCAweDY4NGVmM2U3LCAweDY5NDI2YTExLFxuICAgIDB4NjljNDI2ZWEsIDB4NDIyYWU0NzYsIDB4NDJhY2E4OGQsIDB4NDNhMDMxN2IsIDB4NDMyNjdkODAsIDB4NDFiOTAyOTcsIDB4NDEzZjRlNmMsIDB4NDAzM2Q3OWEsIDB4NDBiNTliNjEsXG4gICAgMHg0NThiNjU0ZiwgMHg0NTBkMjliNCwgMHg0NDAxYjA0MiwgMHg0NDg3ZmNiOSwgMHg0NjE4ODNhZSwgMHg0NjllY2Y1NSwgMHg0NzkyNTZhMywgMHg0NzE0MWE1OCwgMHg0ZGVmYWFmZixcbiAgICAweDRkNjllNjA0LCAweDRjNjU3ZmYyLCAweDRjZTMzMzA5LCAweDRlN2M0YzFlLCAweDRlZmEwMGU1LCAweDRmZjY5OTEzLCAweDRmNzBkNWU4LCAweDRhNGUyYmM2LCAweDRhYzg2NzNkLFxuICAgIDB4NGJjNGZlY2IsIDB4NGI0MmIyMzAsIDB4NDlkZGNkMjcsIDB4NDk1YjgxZGMsIDB4NDg1NzE4MmEsIDB4NDhkMTU0ZDEsIDB4NWQyNjM1OWYsIDB4NWRhMDc5NjQsIDB4NWNhY2UwOTIsXG4gICAgMHg1YzJhYWM2OSwgMHg1ZWI1ZDM3ZSwgMHg1ZTMzOWY4NSwgMHg1ZjNmMDY3MywgMHg1ZmI5NGE4OCwgMHg1YTg3YjRhNiwgMHg1YTAxZjg1ZCwgMHg1YjBkNjFhYiwgMHg1YjhiMmQ1MCxcbiAgICAweDU5MTQ1MjQ3LCAweDU5OTIxZWJjLCAweDU4OWU4NzRhLCAweDU4MThjYmIxLCAweDUyZTM3YjE2LCAweDUyNjUzN2VkLCAweDUzNjlhZTFiLCAweDUzZWZlMmUwLCAweDUxNzA5ZGY3LFxuICAgIDB4NTFmNmQxMGMsXG4gICAgMHg1MGZhNDhmYSwgMHg1MDdjMDQwMSwgMHg1NTQyZmEyZiwgMHg1NWM0YjZkNCwgMHg1NGM4MmYyMiwgMHg1NDRlNjNkOSwgMHg1NmQxMWNjZSwgMHg1NjU3NTAzNSwgMHg1NzViYzljMyxcbiAgICAweDU3ZGQ4NTM4XG5dO1xuXG5mdW5jdGlvbiBjcmVhdGVjcmMyNChpbnB1dCkge1xuICB2YXIgY3JjID0gMHhCNzA0Q0U7XG4gIHZhciBpbmRleCA9IDA7XG5cbiAgd2hpbGUgKChpbnB1dC5sZW5ndGggLSBpbmRleCkgPiAxNikge1xuICAgIGNyYyA9IChjcmMgPDwgOCkgXiBjcmNfdGFibGVbKChjcmMgPj4gMTYpIF4gaW5wdXQuY2hhckNvZGVBdChpbmRleCkpICYgMHhmZl07XG4gICAgY3JjID0gKGNyYyA8PCA4KSBeIGNyY190YWJsZVsoKGNyYyA+PiAxNikgXiBpbnB1dC5jaGFyQ29kZUF0KGluZGV4ICsgMSkpICYgMHhmZl07XG4gICAgY3JjID0gKGNyYyA8PCA4KSBeIGNyY190YWJsZVsoKGNyYyA+PiAxNikgXiBpbnB1dC5jaGFyQ29kZUF0KGluZGV4ICsgMikpICYgMHhmZl07XG4gICAgY3JjID0gKGNyYyA8PCA4KSBeIGNyY190YWJsZVsoKGNyYyA+PiAxNikgXiBpbnB1dC5jaGFyQ29kZUF0KGluZGV4ICsgMykpICYgMHhmZl07XG4gICAgY3JjID0gKGNyYyA8PCA4KSBeIGNyY190YWJsZVsoKGNyYyA+PiAxNikgXiBpbnB1dC5jaGFyQ29kZUF0KGluZGV4ICsgNCkpICYgMHhmZl07XG4gICAgY3JjID0gKGNyYyA8PCA4KSBeIGNyY190YWJsZVsoKGNyYyA+PiAxNikgXiBpbnB1dC5jaGFyQ29kZUF0KGluZGV4ICsgNSkpICYgMHhmZl07XG4gICAgY3JjID0gKGNyYyA8PCA4KSBeIGNyY190YWJsZVsoKGNyYyA+PiAxNikgXiBpbnB1dC5jaGFyQ29kZUF0KGluZGV4ICsgNikpICYgMHhmZl07XG4gICAgY3JjID0gKGNyYyA8PCA4KSBeIGNyY190YWJsZVsoKGNyYyA+PiAxNikgXiBpbnB1dC5jaGFyQ29kZUF0KGluZGV4ICsgNykpICYgMHhmZl07XG4gICAgY3JjID0gKGNyYyA8PCA4KSBeIGNyY190YWJsZVsoKGNyYyA+PiAxNikgXiBpbnB1dC5jaGFyQ29kZUF0KGluZGV4ICsgOCkpICYgMHhmZl07XG4gICAgY3JjID0gKGNyYyA8PCA4KSBeIGNyY190YWJsZVsoKGNyYyA+PiAxNikgXiBpbnB1dC5jaGFyQ29kZUF0KGluZGV4ICsgOSkpICYgMHhmZl07XG4gICAgY3JjID0gKGNyYyA8PCA4KSBeIGNyY190YWJsZVsoKGNyYyA+PiAxNikgXiBpbnB1dC5jaGFyQ29kZUF0KGluZGV4ICsgMTApKSAmIDB4ZmZdO1xuICAgIGNyYyA9IChjcmMgPDwgOCkgXiBjcmNfdGFibGVbKChjcmMgPj4gMTYpIF4gaW5wdXQuY2hhckNvZGVBdChpbmRleCArIDExKSkgJiAweGZmXTtcbiAgICBjcmMgPSAoY3JjIDw8IDgpIF4gY3JjX3RhYmxlWygoY3JjID4+IDE2KSBeIGlucHV0LmNoYXJDb2RlQXQoaW5kZXggKyAxMikpICYgMHhmZl07XG4gICAgY3JjID0gKGNyYyA8PCA4KSBeIGNyY190YWJsZVsoKGNyYyA+PiAxNikgXiBpbnB1dC5jaGFyQ29kZUF0KGluZGV4ICsgMTMpKSAmIDB4ZmZdO1xuICAgIGNyYyA9IChjcmMgPDwgOCkgXiBjcmNfdGFibGVbKChjcmMgPj4gMTYpIF4gaW5wdXQuY2hhckNvZGVBdChpbmRleCArIDE0KSkgJiAweGZmXTtcbiAgICBjcmMgPSAoY3JjIDw8IDgpIF4gY3JjX3RhYmxlWygoY3JjID4+IDE2KSBeIGlucHV0LmNoYXJDb2RlQXQoaW5kZXggKyAxNSkpICYgMHhmZl07XG4gICAgaW5kZXggKz0gMTY7XG4gIH1cblxuICBmb3IgKHZhciBqID0gaW5kZXg7IGogPCBpbnB1dC5sZW5ndGg7IGorKykge1xuICAgIGNyYyA9IChjcmMgPDwgOCkgXiBjcmNfdGFibGVbKChjcmMgPj4gMTYpIF4gaW5wdXQuY2hhckNvZGVBdChpbmRleCsrKSkgJiAweGZmXTtcbiAgfVxuICByZXR1cm4gY3JjICYgMHhmZmZmZmY7XG59XG5cbi8qKlxuICogU3BsaXRzIGEgbWVzc2FnZSBpbnRvIHR3byBwYXJ0cywgdGhlIGhlYWRlcnMgYW5kIHRoZSBib2R5LiBUaGlzIGlzIGFuIGludGVybmFsIGZ1bmN0aW9uXG4gKiBAcGFyYW0ge1N0cmluZ30gdGV4dCBPcGVuUEdQIGFybW9yZWQgbWVzc2FnZSBwYXJ0XG4gKiBAcmV0dXJucyB7KEJvb2xlYW58T2JqZWN0KX0gRWl0aGVyIGZhbHNlIGluIGNhc2Ugb2YgYW4gZXJyb3JcbiAqIG9yIGFuIG9iamVjdCB3aXRoIGF0dHJpYnV0ZSBcImhlYWRlcnNcIiBjb250YWluaW5nIHRoZSBoZWFkZXJzIGFuZFxuICogYW5kIGFuIGF0dHJpYnV0ZSBcImJvZHlcIiBjb250YWluaW5nIHRoZSBib2R5LlxuICovXG5mdW5jdGlvbiBzcGxpdF9oZWFkZXJzKHRleHQpIHtcbiAgdmFyIHJlRW1wdHlMaW5lID0gL15bXFx0IF0qXFxuL207XG4gIHZhciBoZWFkZXJzID0gXCJcIjtcbiAgdmFyIGJvZHkgPSB0ZXh0O1xuXG4gIHZhciBtYXRjaFJlc3VsdCA9IHJlRW1wdHlMaW5lLmV4ZWModGV4dCk7XG5cbiAgaWYgKG1hdGNoUmVzdWx0ICE9IG51bGwpIHtcbiAgICBoZWFkZXJzID0gdGV4dC5zbGljZSgwLCBtYXRjaFJlc3VsdC5pbmRleCk7XG4gICAgYm9keSA9IHRleHQuc2xpY2UobWF0Y2hSZXN1bHQuaW5kZXggKyBtYXRjaFJlc3VsdFswXS5sZW5ndGgpO1xuICB9XG5cbiAgcmV0dXJuIHsgaGVhZGVyczogaGVhZGVycywgYm9keTogYm9keSB9O1xufVxuXG4vKipcbiAqIFNwbGl0cyBhIG1lc3NhZ2UgaW50byB0d28gcGFydHMsIHRoZSBib2R5IGFuZCB0aGUgY2hlY2tzdW0uIFRoaXMgaXMgYW4gaW50ZXJuYWwgZnVuY3Rpb25cbiAqIEBwYXJhbSB7U3RyaW5nfSB0ZXh0IE9wZW5QR1AgYXJtb3JlZCBtZXNzYWdlIHBhcnRcbiAqIEByZXR1cm5zIHsoQm9vbGVhbnxPYmplY3QpfSBFaXRoZXIgZmFsc2UgaW4gY2FzZSBvZiBhbiBlcnJvclxuICogb3IgYW4gb2JqZWN0IHdpdGggYXR0cmlidXRlIFwiYm9keVwiIGNvbnRhaW5pbmcgdGhlIGJvZHlcbiAqIGFuZCBhbiBhdHRyaWJ1dGUgXCJjaGVja3N1bVwiIGNvbnRhaW5pbmcgdGhlIGNoZWNrc3VtLlxuICovXG5mdW5jdGlvbiBzcGxpdF9jaGVja3N1bSh0ZXh0KSB7XG4gIHZhciByZUNoZWNrc3VtU3RhcnQgPSAvXj0vbTtcbiAgdmFyIGJvZHkgPSB0ZXh0O1xuICB2YXIgY2hlY2tzdW0gPSBcIlwiO1xuXG4gIHZhciBtYXRjaFJlc3VsdCA9IHJlQ2hlY2tzdW1TdGFydC5leGVjKHRleHQpO1xuXG4gIGlmIChtYXRjaFJlc3VsdCAhPSBudWxsKSB7XG4gICAgYm9keSA9IHRleHQuc2xpY2UoMCwgbWF0Y2hSZXN1bHQuaW5kZXgpO1xuICAgIGNoZWNrc3VtID0gdGV4dC5zbGljZShtYXRjaFJlc3VsdC5pbmRleCArIDEpO1xuICB9XG5cbiAgcmV0dXJuIHsgYm9keTogYm9keSwgY2hlY2tzdW06IGNoZWNrc3VtIH07XG59XG5cbi8qKlxuICogRGVBcm1vciBhbiBPcGVuUEdQIGFybW9yZWQgbWVzc2FnZTsgdmVyaWZ5IHRoZSBjaGVja3N1bSBhbmQgcmV0dXJuXG4gKiB0aGUgZW5jb2RlZCBieXRlc1xuICogQHBhcmFtIHtTdHJpbmd9IHRleHQgT3BlblBHUCBhcm1vcmVkIG1lc3NhZ2VcbiAqIEByZXR1cm5zIHsoQm9vbGVhbnxPYmplY3QpfSBFaXRoZXIgZmFsc2UgaW4gY2FzZSBvZiBhbiBlcnJvclxuICogb3IgYW4gb2JqZWN0IHdpdGggYXR0cmlidXRlIFwidGV4dFwiIGNvbnRhaW5pbmcgdGhlIG1lc3NhZ2UgdGV4dFxuICogYW5kIGFuIGF0dHJpYnV0ZSBcImRhdGFcIiBjb250YWluaW5nIHRoZSBieXRlcy5cbiAqL1xuZnVuY3Rpb24gZGVhcm1vcih0ZXh0KSB7XG4gIHZhciByZVNwbGl0ID0gL14tLS0tLVteLV0rLS0tLS0kXFxuL207XG5cbiAgdGV4dCA9IHRleHQucmVwbGFjZSgvXFxyL2csICcnKTtcblxuICB2YXIgdHlwZSA9IGdldF90eXBlKHRleHQpO1xuXG4gIHZhciBzcGxpdHRleHQgPSB0ZXh0LnNwbGl0KHJlU3BsaXQpO1xuXG4gIC8vIElFIGhhcyBhIGJ1ZyBpbiBzcGxpdCB3aXRoIGEgcmUuIElmIHRoZSBwYXR0ZXJuIG1hdGNoZXMgdGhlIGJlZ2lubmluZyBvZiB0aGVcbiAgLy8gc3RyaW5nIGl0IGRvZXNuJ3QgY3JlYXRlIGFuIGVtcHR5IGFycmF5IGVsZW1lbnQgMC4gU28gd2UgbmVlZCB0byBkZXRlY3QgdGhpc1xuICAvLyBzbyB3ZSBrbm93IHRoZSBpbmRleCBvZiB0aGUgZGF0YSB3ZSBhcmUgaW50ZXJlc3RlZCBpbi5cbiAgdmFyIGluZGV4QmFzZSA9IDE7XG5cbiAgdmFyIHJlc3VsdCwgY2hlY2tzdW07XG5cbiAgaWYgKHRleHQuc2VhcmNoKHJlU3BsaXQpICE9IHNwbGl0dGV4dFswXS5sZW5ndGgpIHtcbiAgICBpbmRleEJhc2UgPSAwO1xuICB9XG5cbiAgaWYgKHR5cGUgIT0gMikge1xuICAgIHZhciBtc2cgPSBzcGxpdF9oZWFkZXJzKHNwbGl0dGV4dFtpbmRleEJhc2VdKTtcbiAgICB2YXIgbXNnX3N1bSA9IHNwbGl0X2NoZWNrc3VtKG1zZy5ib2R5KTtcblxuICAgIHJlc3VsdCA9IHtcbiAgICAgIGRhdGE6IGJhc2U2NC5kZWNvZGUobXNnX3N1bS5ib2R5KSxcbiAgICAgIHR5cGU6IHR5cGVcbiAgICB9O1xuXG4gICAgY2hlY2tzdW0gPSBtc2dfc3VtLmNoZWNrc3VtO1xuICB9IGVsc2Uge1xuICAgIC8vIFJldmVyc2UgZGFzaC1lc2NhcGluZyBmb3IgbXNnIGFuZCByZW1vdmUgdHJhaWxpbmcgd2hpdGVzcGFjZSBhdCBlbmQgb2YgbGluZVxuICAgIHZhciBtc2cgPSBzcGxpdF9oZWFkZXJzKHNwbGl0dGV4dFtpbmRleEJhc2VdLnJlcGxhY2UoL14tIC9tZywgJycpLnJlcGxhY2UoL1tcXHQgXStcXG4vZywgXCJcXG5cIikpO1xuICAgIHZhciBzaWcgPSBzcGxpdF9oZWFkZXJzKHNwbGl0dGV4dFtpbmRleEJhc2UgKyAxXS5yZXBsYWNlKC9eLSAvbWcsICcnKSk7XG4gICAgdmFyIHNpZ19zdW0gPSBzcGxpdF9jaGVja3N1bShzaWcuYm9keSk7XG5cbiAgICByZXN1bHQgPSB7XG4gICAgICB0ZXh0OiAgbXNnLmJvZHkucmVwbGFjZSgvXFxuJC8sICcnKS5yZXBsYWNlKC9cXG4vZywgXCJcXHJcXG5cIiksXG4gICAgICBkYXRhOiBiYXNlNjQuZGVjb2RlKHNpZ19zdW0uYm9keSksXG4gICAgICB0eXBlOiB0eXBlXG4gICAgfTtcblxuICAgIGNoZWNrc3VtID0gc2lnX3N1bS5jaGVja3N1bTtcbiAgfVxuXG4gIGlmICghdmVyaWZ5Q2hlY2tTdW0ocmVzdWx0LmRhdGEsIGNoZWNrc3VtKSkge1xuICAgIHV0aWwucHJpbnRfZXJyb3IoXCJBc2NpaSBhcm1vciBpbnRlZ3JpdHkgY2hlY2sgb24gbWVzc2FnZSBmYWlsZWQ6ICdcIlxuICAgICAgKyBjaGVja3N1bVxuICAgICAgKyBcIicgc2hvdWxkIGJlICdcIlxuICAgICAgKyBnZXRDaGVja1N1bShyZXN1bHQpICsgXCInXCIpO1xuICAgIHJldHVybiBmYWxzZTtcbiAgfSBlbHNlIHtcbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG59XG5cblxuLyoqXG4gKiBBcm1vciBhbiBPcGVuUEdQIGJpbmFyeSBwYWNrZXQgYmxvY2tcbiAqIEBwYXJhbSB7SW50ZWdlcn0gbWVzc2FnZXR5cGUgdHlwZSBvZiB0aGUgbWVzc2FnZVxuICogQHBhcmFtIGJvZHlcbiAqIEBwYXJhbSB7SW50ZWdlcn0gcGFydGluZGV4XG4gKiBAcGFyYW0ge0ludGVnZXJ9IHBhcnR0b3RhbFxuICogQHJldHVybnMge1N0cmluZ30gQXJtb3JlZCB0ZXh0XG4gKi9cbmZ1bmN0aW9uIGFybW9yKG1lc3NhZ2V0eXBlLCBib2R5LCBwYXJ0aW5kZXgsIHBhcnR0b3RhbCkge1xuICB2YXIgcmVzdWx0ID0gXCJcIjtcbiAgc3dpdGNoIChtZXNzYWdldHlwZSkge1xuICAgIGNhc2UgZW51bXMuYXJtb3IubXVsdGlwYXJ0X3NlY3Rpb246XG4gICAgICByZXN1bHQgKz0gXCItLS0tLUJFR0lOIFBHUCBNRVNTQUdFLCBQQVJUIFwiICsgcGFydGluZGV4ICsgXCIvXCIgKyBwYXJ0dG90YWwgKyBcIi0tLS0tXFxyXFxuXCI7XG4gICAgICByZXN1bHQgKz0gYXJtb3JfYWRkaGVhZGVyKCk7XG4gICAgICByZXN1bHQgKz0gYmFzZTY0LmVuY29kZShib2R5KTtcbiAgICAgIHJlc3VsdCArPSBcIlxcclxcbj1cIiArIGdldENoZWNrU3VtKGJvZHkpICsgXCJcXHJcXG5cIjtcbiAgICAgIHJlc3VsdCArPSBcIi0tLS0tRU5EIFBHUCBNRVNTQUdFLCBQQVJUIFwiICsgcGFydGluZGV4ICsgXCIvXCIgKyBwYXJ0dG90YWwgKyBcIi0tLS0tXFxyXFxuXCI7XG4gICAgICBicmVhaztcbiAgICBjYXNlIGVudW1zLmFybW9yLm11dGxpcGFydF9sYXN0OlxuICAgICAgcmVzdWx0ICs9IFwiLS0tLS1CRUdJTiBQR1AgTUVTU0FHRSwgUEFSVCBcIiArIHBhcnRpbmRleCArIFwiLS0tLS1cXHJcXG5cIjtcbiAgICAgIHJlc3VsdCArPSBhcm1vcl9hZGRoZWFkZXIoKTtcbiAgICAgIHJlc3VsdCArPSBiYXNlNjQuZW5jb2RlKGJvZHkpO1xuICAgICAgcmVzdWx0ICs9IFwiXFxyXFxuPVwiICsgZ2V0Q2hlY2tTdW0oYm9keSkgKyBcIlxcclxcblwiO1xuICAgICAgcmVzdWx0ICs9IFwiLS0tLS1FTkQgUEdQIE1FU1NBR0UsIFBBUlQgXCIgKyBwYXJ0aW5kZXggKyBcIi0tLS0tXFxyXFxuXCI7XG4gICAgICBicmVhaztcbiAgICBjYXNlIGVudW1zLmFybW9yLnNpZ25lZDpcbiAgICAgIHJlc3VsdCArPSBcIlxcclxcbi0tLS0tQkVHSU4gUEdQIFNJR05FRCBNRVNTQUdFLS0tLS1cXHJcXG5cIjtcbiAgICAgIHJlc3VsdCArPSBcIkhhc2g6IFwiICsgYm9keS5oYXNoICsgXCJcXHJcXG5cXHJcXG5cIjtcbiAgICAgIHJlc3VsdCArPSBib2R5LnRleHQucmVwbGFjZSgvXFxuLS9nLCBcIlxcbi0gLVwiKTtcbiAgICAgIHJlc3VsdCArPSBcIlxcclxcbi0tLS0tQkVHSU4gUEdQIFNJR05BVFVSRS0tLS0tXFxyXFxuXCI7XG4gICAgICByZXN1bHQgKz0gYXJtb3JfYWRkaGVhZGVyKCk7XG4gICAgICByZXN1bHQgKz0gYmFzZTY0LmVuY29kZShib2R5LmRhdGEpO1xuICAgICAgcmVzdWx0ICs9IFwiXFxyXFxuPVwiICsgZ2V0Q2hlY2tTdW0oYm9keS5kYXRhKSArIFwiXFxyXFxuXCI7XG4gICAgICByZXN1bHQgKz0gXCItLS0tLUVORCBQR1AgU0lHTkFUVVJFLS0tLS1cXHJcXG5cIjtcbiAgICAgIGJyZWFrO1xuICAgIGNhc2UgZW51bXMuYXJtb3IubWVzc2FnZTpcbiAgICAgIHJlc3VsdCArPSBcIi0tLS0tQkVHSU4gUEdQIE1FU1NBR0UtLS0tLVxcclxcblwiO1xuICAgICAgcmVzdWx0ICs9IGFybW9yX2FkZGhlYWRlcigpO1xuICAgICAgcmVzdWx0ICs9IGJhc2U2NC5lbmNvZGUoYm9keSk7XG4gICAgICByZXN1bHQgKz0gXCJcXHJcXG49XCIgKyBnZXRDaGVja1N1bShib2R5KSArIFwiXFxyXFxuXCI7XG4gICAgICByZXN1bHQgKz0gXCItLS0tLUVORCBQR1AgTUVTU0FHRS0tLS0tXFxyXFxuXCI7XG4gICAgICBicmVhaztcbiAgICBjYXNlIGVudW1zLmFybW9yLnB1YmxpY19rZXk6XG4gICAgICByZXN1bHQgKz0gXCItLS0tLUJFR0lOIFBHUCBQVUJMSUMgS0VZIEJMT0NLLS0tLS1cXHJcXG5cIjtcbiAgICAgIHJlc3VsdCArPSBhcm1vcl9hZGRoZWFkZXIoKTtcbiAgICAgIHJlc3VsdCArPSBiYXNlNjQuZW5jb2RlKGJvZHkpO1xuICAgICAgcmVzdWx0ICs9IFwiXFxyXFxuPVwiICsgZ2V0Q2hlY2tTdW0oYm9keSkgKyBcIlxcclxcblwiO1xuICAgICAgcmVzdWx0ICs9IFwiLS0tLS1FTkQgUEdQIFBVQkxJQyBLRVkgQkxPQ0stLS0tLVxcclxcblxcclxcblwiO1xuICAgICAgYnJlYWs7XG4gICAgY2FzZSBlbnVtcy5hcm1vci5wcml2YXRlX2tleTpcbiAgICAgIHJlc3VsdCArPSBcIi0tLS0tQkVHSU4gUEdQIFBSSVZBVEUgS0VZIEJMT0NLLS0tLS1cXHJcXG5cIjtcbiAgICAgIHJlc3VsdCArPSBhcm1vcl9hZGRoZWFkZXIoKTtcbiAgICAgIHJlc3VsdCArPSBiYXNlNjQuZW5jb2RlKGJvZHkpO1xuICAgICAgcmVzdWx0ICs9IFwiXFxyXFxuPVwiICsgZ2V0Q2hlY2tTdW0oYm9keSkgKyBcIlxcclxcblwiO1xuICAgICAgcmVzdWx0ICs9IFwiLS0tLS1FTkQgUEdQIFBSSVZBVEUgS0VZIEJMT0NLLS0tLS1cXHJcXG5cIjtcbiAgICAgIGJyZWFrO1xuICB9XG5cbiAgcmV0dXJuIHJlc3VsdDtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gIGVuY29kZTogYXJtb3IsXG4gIGRlY29kZTogZGVhcm1vclxufTtcbiIsIi8qIE9wZW5QR1AgcmFkaXgtNjQvYmFzZTY0IHN0cmluZyBlbmNvZGluZy9kZWNvZGluZ1xuICogQ29weXJpZ2h0IDIwMDUgSGVyYmVydCBIYW5ld2lua2VsLCB3d3cuaGFuZVdJTi5kZVxuICogdmVyc2lvbiAxLjAsIGNoZWNrIHd3dy5oYW5lV0lOLmRlIGZvciB0aGUgbGF0ZXN0IHZlcnNpb25cbiAqXG4gKiBUaGlzIHNvZnR3YXJlIGlzIHByb3ZpZGVkIGFzLWlzLCB3aXRob3V0IGV4cHJlc3Mgb3IgaW1wbGllZCB3YXJyYW50eS4gIFxuICogUGVybWlzc2lvbiB0byB1c2UsIGNvcHksIG1vZGlmeSwgZGlzdHJpYnV0ZSBvciBzZWxsIHRoaXMgc29mdHdhcmUsIHdpdGggb3JcbiAqIHdpdGhvdXQgZmVlLCBmb3IgYW55IHB1cnBvc2UgYW5kIGJ5IGFueSBpbmRpdmlkdWFsIG9yIG9yZ2FuaXphdGlvbiwgaXMgaGVyZWJ5XG4gKiBncmFudGVkLCBwcm92aWRlZCB0aGF0IHRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBhcmFncmFwaCBhcHBlYXIgXG4gKiBpbiBhbGwgY29waWVzLiBEaXN0cmlidXRpb24gYXMgYSBwYXJ0IG9mIGFuIGFwcGxpY2F0aW9uIG9yIGJpbmFyeSBtdXN0XG4gKiBpbmNsdWRlIHRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGluIHRoZSBkb2N1bWVudGF0aW9uIGFuZC9vciBvdGhlciBtYXRlcmlhbHNcbiAqIHByb3ZpZGVkIHdpdGggdGhlIGFwcGxpY2F0aW9uIG9yIGRpc3RyaWJ1dGlvbi5cbiAqL1xuXG52YXIgYjY0cyA9ICdBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWmFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6MDEyMzQ1Njc4OSsvJztcblxuZnVuY3Rpb24gczJyKHQpIHtcbiAgdmFyIGEsIGMsIG47XG4gIHZhciByID0gJycsXG4gICAgbCA9IDAsXG4gICAgcyA9IDA7XG4gIHZhciB0bCA9IHQubGVuZ3RoO1xuXG4gIGZvciAobiA9IDA7IG4gPCB0bDsgbisrKSB7XG4gICAgYyA9IHQuY2hhckNvZGVBdChuKTtcbiAgICBpZiAocyA9PSAwKSB7XG4gICAgICByICs9IGI2NHMuY2hhckF0KChjID4+IDIpICYgNjMpO1xuICAgICAgYSA9IChjICYgMykgPDwgNDtcbiAgICB9IGVsc2UgaWYgKHMgPT0gMSkge1xuICAgICAgciArPSBiNjRzLmNoYXJBdCgoYSB8IChjID4+IDQpICYgMTUpKTtcbiAgICAgIGEgPSAoYyAmIDE1KSA8PCAyO1xuICAgIH0gZWxzZSBpZiAocyA9PSAyKSB7XG4gICAgICByICs9IGI2NHMuY2hhckF0KGEgfCAoKGMgPj4gNikgJiAzKSk7XG4gICAgICBsICs9IDE7XG4gICAgICBpZiAoKGwgJSA2MCkgPT0gMClcbiAgICAgICAgciArPSBcIlxcblwiO1xuICAgICAgciArPSBiNjRzLmNoYXJBdChjICYgNjMpO1xuICAgIH1cbiAgICBsICs9IDE7XG4gICAgaWYgKChsICUgNjApID09IDApXG4gICAgICByICs9IFwiXFxuXCI7XG5cbiAgICBzICs9IDE7XG4gICAgaWYgKHMgPT0gMylcbiAgICAgIHMgPSAwO1xuICB9XG4gIGlmIChzID4gMCkge1xuICAgIHIgKz0gYjY0cy5jaGFyQXQoYSk7XG4gICAgbCArPSAxO1xuICAgIGlmICgobCAlIDYwKSA9PSAwKVxuICAgICAgciArPSBcIlxcblwiO1xuICAgIHIgKz0gJz0nO1xuICAgIGwgKz0gMTtcbiAgfVxuICBpZiAocyA9PSAxKSB7XG4gICAgaWYgKChsICUgNjApID09IDApXG4gICAgICByICs9IFwiXFxuXCI7XG4gICAgciArPSAnPSc7XG4gIH1cblxuICByZXR1cm4gcjtcbn1cblxuZnVuY3Rpb24gcjJzKHQpIHtcbiAgdmFyIGMsIG47XG4gIHZhciByID0gJycsXG4gICAgcyA9IDAsXG4gICAgYSA9IDA7XG4gIHZhciB0bCA9IHQubGVuZ3RoO1xuXG4gIGZvciAobiA9IDA7IG4gPCB0bDsgbisrKSB7XG4gICAgYyA9IGI2NHMuaW5kZXhPZih0LmNoYXJBdChuKSk7XG4gICAgaWYgKGMgPj0gMCkge1xuICAgICAgaWYgKHMpXG4gICAgICAgIHIgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShhIHwgKGMgPj4gKDYgLSBzKSkgJiAyNTUpO1xuICAgICAgcyA9IChzICsgMikgJiA3O1xuICAgICAgYSA9IChjIDw8IHMpICYgMjU1O1xuICAgIH1cbiAgfVxuICByZXR1cm4gcjtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gIGVuY29kZTogczJyLFxuICBkZWNvZGU6IHIyc1xufVxuIiwidmFyIGVudW1zID0ge1xuXG4gIC8qKiBBIHN0cmluZyB0byBrZXkgc3BlY2lmaWVyIHR5cGVcbiAgICogQGVudW0ge0ludGVnZXJ9XG4gICAqL1xuICBzMms6IHtcbiAgICBzaW1wbGU6IDAsXG4gICAgc2FsdGVkOiAxLFxuICAgIGl0ZXJhdGVkOiAzLFxuICAgIGdudTogMTAxXG4gIH0sXG5cbiAgLyoqIFJGQzQ4ODAsIHNlY3Rpb24gOS4xIFxuICAgKiBAZW51bSB7U3RyaW5nfVxuICAgKi9cbiAgcHVibGljS2V5OiB7XG4gICAgcnNhX2VuY3J5cHRfc2lnbjogMSxcbiAgICByc2FfZW5jcnlwdDogMixcbiAgICByc2Ffc2lnbjogMyxcbiAgICBlbGdhbWFsOiAxNixcbiAgICBkc2E6IDE3XG4gIH0sXG5cbiAgLyoqIFJGQzQ4ODAsIHNlY3Rpb24gOS4yIFxuICAgKiBAZW51bSB7U3RyaW5nfVxuICAgKi9cbiAgc3ltbWV0cmljOiB7XG4gICAgcGxhaW50ZXh0OiAwLFxuICAgIC8qKiBOb3QgaW1wbGVtZW50ZWQhICovXG4gICAgaWRlYTogMSxcbiAgICB0cmlwbGVkZXM6IDIsXG4gICAgY2FzdDU6IDMsXG4gICAgYmxvd2Zpc2g6IDQsXG4gICAgYWVzMTI4OiA3LFxuICAgIGFlczE5MjogOCxcbiAgICBhZXMyNTY6IDksXG4gICAgdHdvZmlzaDogMTBcbiAgfSxcblxuICAvKiogUkZDNDg4MCwgc2VjdGlvbiA5LjNcbiAgICogQGVudW0ge1N0cmluZ31cbiAgICovXG4gIGNvbXByZXNzaW9uOiB7XG4gICAgdW5jb21wcmVzc2VkOiAwLFxuICAgIC8qKiBSRkMxOTUxICovXG4gICAgemlwOiAxLFxuICAgIC8qKiBSRkMxOTUwICovXG4gICAgemxpYjogMixcbiAgICBiemlwMjogM1xuICB9LFxuXG4gIC8qKiBSRkM0ODgwLCBzZWN0aW9uIDkuNFxuICAgKiBAZW51bSB7U3RyaW5nfVxuICAgKi9cbiAgaGFzaDoge1xuICAgIG1kNTogMSxcbiAgICBzaGExOiAyLFxuICAgIHJpcGVtZDogMyxcbiAgICBzaGEyNTY6IDgsXG4gICAgc2hhMzg0OiA5LFxuICAgIHNoYTUxMjogMTAsXG4gICAgc2hhMjI0OiAxMVxuICB9LFxuXG5cbiAgLyoqXG4gICAqIEBlbnVtIHtTdHJpbmd9XG4gICAqIEEgbGlzdCBvZiBwYWNrZXQgdHlwZXMgYW5kIG51bWVyaWMgdGFncyBhc3NvY2lhdGVkIHdpdGggdGhlbS5cbiAgICovXG4gIHBhY2tldDoge1xuICAgIHB1YmxpY19rZXlfZW5jcnlwdGVkX3Nlc3Npb25fa2V5OiAxLFxuICAgIHNpZ25hdHVyZTogMixcbiAgICBzeW1fZW5jcnlwdGVkX3Nlc3Npb25fa2V5OiAzLFxuICAgIG9uZV9wYXNzX3NpZ25hdHVyZTogNCxcbiAgICBzZWNyZXRfa2V5OiA1LFxuICAgIHB1YmxpY19rZXk6IDYsXG4gICAgc2VjcmV0X3N1YmtleTogNyxcbiAgICBjb21wcmVzc2VkOiA4LFxuICAgIHN5bW1ldHJpY2FsbHlfZW5jcnlwdGVkOiA5LFxuICAgIG1hcmtlcjogMTAsXG4gICAgbGl0ZXJhbDogMTEsXG4gICAgdHJ1c3Q6IDEyLFxuICAgIHVzZXJpZDogMTMsXG4gICAgcHVibGljX3N1YmtleTogMTQsXG4gICAgdXNlcl9hdHRyaWJ1dGU6IDE3LFxuICAgIHN5bV9lbmNyeXB0ZWRfaW50ZWdyaXR5X3Byb3RlY3RlZDogMTgsXG4gICAgbW9kaWZpY2F0aW9uX2RldGVjdGlvbl9jb2RlOiAxOVxuICB9LFxuXG5cbiAgLyoqXG4gICAqIERhdGEgdHlwZXMgaW4gdGhlIGxpdGVyYWwgcGFja2V0XG4gICAqIEByZWFkb25seVxuICAgKiBAZW51bSB7U3RyaW5nfVxuICAgKi9cbiAgbGl0ZXJhbDoge1xuICAgIC8qKiBCaW5hcnkgZGF0YSAqL1xuICAgIGJpbmFyeTogJ2InLmNoYXJDb2RlQXQoKSxcbiAgICAvKiogVGV4dCBkYXRhICovXG4gICAgdGV4dDogJ3QnLmNoYXJDb2RlQXQoKSxcbiAgICAvKiogVXRmOCBkYXRhICovXG4gICAgdXRmODogJ3UnLmNoYXJDb2RlQXQoKVxuICB9LFxuXG5cbiAgLyoqIE9uZSBwYXNzIHNpZ25hdHVyZSBwYWNrZXQgdHlwZVxuICAgKiBAZW51bSB7U3RyaW5nfSAqL1xuICBzaWduYXR1cmU6IHtcbiAgICAvKiogMHgwMDogU2lnbmF0dXJlIG9mIGEgYmluYXJ5IGRvY3VtZW50LiAqL1xuICAgIGJpbmFyeTogMCxcbiAgICAvKiogMHgwMTogU2lnbmF0dXJlIG9mIGEgY2Fub25pY2FsIHRleHQgZG9jdW1lbnQuXG4gICAgICogQ2Fub25pY2FseXppbmcgdGhlIGRvY3VtZW50IGJ5IGNvbnZlcnRpbmcgbGluZSBlbmRpbmdzLiAqL1xuICAgIHRleHQ6IDEsXG4gICAgLyoqIDB4MDI6IFN0YW5kYWxvbmUgc2lnbmF0dXJlLlxuICAgICAqIFRoaXMgc2lnbmF0dXJlIGlzIGEgc2lnbmF0dXJlIG9mIG9ubHkgaXRzIG93biBzdWJwYWNrZXQgY29udGVudHMuXG4gICAgICogSXQgaXMgY2FsY3VsYXRlZCBpZGVudGljYWxseSB0byBhIHNpZ25hdHVyZSBvdmVyIGEgemVyby1sZW5naFxuICAgICAqIGJpbmFyeSBkb2N1bWVudC4gIE5vdGUgdGhhdCBpdCBkb2Vzbid0IG1ha2Ugc2Vuc2UgdG8gaGF2ZSBhIFYzXG4gICAgICogc3RhbmRhbG9uZSBzaWduYXR1cmUuICovXG4gICAgc3RhbmRhbG9uZTogMixcbiAgICAvKiogMHgxMDogR2VuZXJpYyBjZXJ0aWZpY2F0aW9uIG9mIGEgVXNlciBJRCBhbmQgUHVibGljLUtleSBwYWNrZXQuXG4gICAgICogVGhlIGlzc3VlciBvZiB0aGlzIGNlcnRpZmljYXRpb24gZG9lcyBub3QgbWFrZSBhbnkgcGFydGljdWxhclxuICAgICAqIGFzc2VydGlvbiBhcyB0byBob3cgd2VsbCB0aGUgY2VydGlmaWVyIGhhcyBjaGVja2VkIHRoYXQgdGhlIG93bmVyXG4gICAgICogb2YgdGhlIGtleSBpcyBpbiBmYWN0IHRoZSBwZXJzb24gZGVzY3JpYmVkIGJ5IHRoZSBVc2VyIElELiAqL1xuICAgIGNlcnRfZ2VuZXJpYzogMTYsXG4gICAgLyoqIDB4MTE6IFBlcnNvbmEgY2VydGlmaWNhdGlvbiBvZiBhIFVzZXIgSUQgYW5kIFB1YmxpYy1LZXkgcGFja2V0LlxuICAgICAqIFRoZSBpc3N1ZXIgb2YgdGhpcyBjZXJ0aWZpY2F0aW9uIGhhcyBub3QgZG9uZSBhbnkgdmVyaWZpY2F0aW9uIG9mXG4gICAgICogdGhlIGNsYWltIHRoYXQgdGhlIG93bmVyIG9mIHRoaXMga2V5IGlzIHRoZSBVc2VyIElEIHNwZWNpZmllZC4gKi9cbiAgICBjZXJ0X3BlcnNvbmE6IDE3LFxuICAgIC8qKiAweDEyOiBDYXN1YWwgY2VydGlmaWNhdGlvbiBvZiBhIFVzZXIgSUQgYW5kIFB1YmxpYy1LZXkgcGFja2V0LlxuICAgICAqIFRoZSBpc3N1ZXIgb2YgdGhpcyBjZXJ0aWZpY2F0aW9uIGhhcyBkb25lIHNvbWUgY2FzdWFsXG4gICAgICogdmVyaWZpY2F0aW9uIG9mIHRoZSBjbGFpbSBvZiBpZGVudGl0eS4gKi9cbiAgICBjZXJ0X2Nhc3VhbDogMTgsXG4gICAgLyoqIDB4MTM6IFBvc2l0aXZlIGNlcnRpZmljYXRpb24gb2YgYSBVc2VyIElEIGFuZCBQdWJsaWMtS2V5IHBhY2tldC5cbiAgICAgKiBUaGUgaXNzdWVyIG9mIHRoaXMgY2VydGlmaWNhdGlvbiBoYXMgZG9uZSBzdWJzdGFudGlhbFxuICAgICAqIHZlcmlmaWNhdGlvbiBvZiB0aGUgY2xhaW0gb2YgaWRlbnRpdHkuXG4gICAgICogXG4gICAgICogTW9zdCBPcGVuUEdQIGltcGxlbWVudGF0aW9ucyBtYWtlIHRoZWlyIFwia2V5IHNpZ25hdHVyZXNcIiBhcyAweDEwXG4gICAgICogY2VydGlmaWNhdGlvbnMuICBTb21lIGltcGxlbWVudGF0aW9ucyBjYW4gaXNzdWUgMHgxMS0weDEzXG4gICAgICogY2VydGlmaWNhdGlvbnMsIGJ1dCBmZXcgZGlmZmVyZW50aWF0ZSBiZXR3ZWVuIHRoZSB0eXBlcy4gKi9cbiAgICBjZXJ0X3Bvc2l0aXZlOiAxOSxcbiAgICAvKiogMHgzMDogQ2VydGlmaWNhdGlvbiByZXZvY2F0aW9uIHNpZ25hdHVyZVxuICAgICAqIFRoaXMgc2lnbmF0dXJlIHJldm9rZXMgYW4gZWFybGllciBVc2VyIElEIGNlcnRpZmljYXRpb24gc2lnbmF0dXJlXG4gICAgICogKHNpZ25hdHVyZSBjbGFzcyAweDEwIHRocm91Z2ggMHgxMykgb3IgZGlyZWN0LWtleSBzaWduYXR1cmVcbiAgICAgKiAoMHgxRikuICBJdCBzaG91bGQgYmUgaXNzdWVkIGJ5IHRoZSBzYW1lIGtleSB0aGF0IGlzc3VlZCB0aGVcbiAgICAgKiByZXZva2VkIHNpZ25hdHVyZSBvciBhbiBhdXRob3JpemVkIHJldm9jYXRpb24ga2V5LiAgVGhlIHNpZ25hdHVyZVxuICAgICAqIGlzIGNvbXB1dGVkIG92ZXIgdGhlIHNhbWUgZGF0YSBhcyB0aGUgY2VydGlmaWNhdGUgdGhhdCBpdFxuICAgICAqIHJldm9rZXMsIGFuZCBzaG91bGQgaGF2ZSBhIGxhdGVyIGNyZWF0aW9uIGRhdGUgdGhhbiB0aGF0XG4gICAgICogY2VydGlmaWNhdGUuICovXG4gICAgY2VydF9yZXZvY2F0aW9uOiA0OCxcbiAgICAvKiogMHgxODogU3Via2V5IEJpbmRpbmcgU2lnbmF0dXJlXG4gICAgICogVGhpcyBzaWduYXR1cmUgaXMgYSBzdGF0ZW1lbnQgYnkgdGhlIHRvcC1sZXZlbCBzaWduaW5nIGtleSB0aGF0XG4gICAgICogaW5kaWNhdGVzIHRoYXQgaXQgb3ducyB0aGUgc3Via2V5LiAgVGhpcyBzaWduYXR1cmUgaXMgY2FsY3VsYXRlZFxuICAgICAqIGRpcmVjdGx5IG9uIHRoZSBwcmltYXJ5IGtleSBhbmQgc3Via2V5LCBhbmQgbm90IG9uIGFueSBVc2VyIElEIG9yXG4gICAgICogb3RoZXIgcGFja2V0cy4gIEEgc2lnbmF0dXJlIHRoYXQgYmluZHMgYSBzaWduaW5nIHN1YmtleSBNVVNUIGhhdmVcbiAgICAgKiBhbiBFbWJlZGRlZCBTaWduYXR1cmUgc3VicGFja2V0IGluIHRoaXMgYmluZGluZyBzaWduYXR1cmUgdGhhdFxuICAgICAqIGNvbnRhaW5zIGEgMHgxOSBzaWduYXR1cmUgbWFkZSBieSB0aGUgc2lnbmluZyBzdWJrZXkgb24gdGhlXG4gICAgICogcHJpbWFyeSBrZXkgYW5kIHN1YmtleS4gKi9cbiAgICBzdWJrZXlfYmluZGluZzogMjQsXG4gICAgLyoqIDB4MTk6IFByaW1hcnkgS2V5IEJpbmRpbmcgU2lnbmF0dXJlXG5cdFx0KiBUaGlzIHNpZ25hdHVyZSBpcyBhIHN0YXRlbWVudCBieSBhIHNpZ25pbmcgc3Via2V5LCBpbmRpY2F0aW5nXG5cdFx0KiB0aGF0IGl0IGlzIG93bmVkIGJ5IHRoZSBwcmltYXJ5IGtleSBhbmQgc3Via2V5LiAgVGhpcyBzaWduYXR1cmVcblx0XHQqIGlzIGNhbGN1bGF0ZWQgdGhlIHNhbWUgd2F5IGFzIGEgMHgxOCBzaWduYXR1cmU6IGRpcmVjdGx5IG9uIHRoZVxuXHRcdCogcHJpbWFyeSBrZXkgYW5kIHN1YmtleSwgYW5kIG5vdCBvbiBhbnkgVXNlciBJRCBvciBvdGhlciBwYWNrZXRzLlxuXHRcdFxuXHRcdCogV2hlbiBhIHNpZ25hdHVyZSBpcyBtYWRlIG92ZXIgYSBrZXksIHRoZSBoYXNoIGRhdGEgc3RhcnRzIHdpdGggdGhlXG5cdFx0KiBvY3RldCAweDk5LCBmb2xsb3dlZCBieSBhIHR3by1vY3RldCBsZW5ndGggb2YgdGhlIGtleSwgYW5kIHRoZW4gYm9keVxuXHRcdCogb2YgdGhlIGtleSBwYWNrZXQuICAoTm90ZSB0aGF0IHRoaXMgaXMgYW4gb2xkLXN0eWxlIHBhY2tldCBoZWFkZXIgZm9yXG5cdFx0KiBhIGtleSBwYWNrZXQgd2l0aCB0d28tb2N0ZXQgbGVuZ3RoLikgIEEgc3Via2V5IGJpbmRpbmcgc2lnbmF0dXJlXG5cdFx0KiAodHlwZSAweDE4KSBvciBwcmltYXJ5IGtleSBiaW5kaW5nIHNpZ25hdHVyZSAodHlwZSAweDE5KSB0aGVuIGhhc2hlc1xuXHRcdCogdGhlIHN1YmtleSB1c2luZyB0aGUgc2FtZSBmb3JtYXQgYXMgdGhlIG1haW4ga2V5IChhbHNvIHVzaW5nIDB4OTkgYXNcblx0XHQqIHRoZSBmaXJzdCBvY3RldCkuICovXG4gICAga2V5X2JpbmRpbmc6IDI1LFxuICAgIC8qKiAweDFGOiBTaWduYXR1cmUgZGlyZWN0bHkgb24gYSBrZXlcbiAgICAgKiBUaGlzIHNpZ25hdHVyZSBpcyBjYWxjdWxhdGVkIGRpcmVjdGx5IG9uIGEga2V5LiAgSXQgYmluZHMgdGhlXG4gICAgICogaW5mb3JtYXRpb24gaW4gdGhlIFNpZ25hdHVyZSBzdWJwYWNrZXRzIHRvIHRoZSBrZXksIGFuZCBpc1xuICAgICAqIGFwcHJvcHJpYXRlIHRvIGJlIHVzZWQgZm9yIHN1YnBhY2tldHMgdGhhdCBwcm92aWRlIGluZm9ybWF0aW9uXG4gICAgICogYWJvdXQgdGhlIGtleSwgc3VjaCBhcyB0aGUgUmV2b2NhdGlvbiBLZXkgc3VicGFja2V0LiAgSXQgaXMgYWxzb1xuICAgICAqIGFwcHJvcHJpYXRlIGZvciBzdGF0ZW1lbnRzIHRoYXQgbm9uLXNlbGYgY2VydGlmaWVycyB3YW50IHRvIG1ha2VcbiAgICAgKiBhYm91dCB0aGUga2V5IGl0c2VsZiwgcmF0aGVyIHRoYW4gdGhlIGJpbmRpbmcgYmV0d2VlbiBhIGtleSBhbmQgYVxuICAgICAqIG5hbWUuICovXG4gICAga2V5OiAzMSxcbiAgICAvKiogMHgyMDogS2V5IHJldm9jYXRpb24gc2lnbmF0dXJlXG4gICAgICogVGhlIHNpZ25hdHVyZSBpcyBjYWxjdWxhdGVkIGRpcmVjdGx5IG9uIHRoZSBrZXkgYmVpbmcgcmV2b2tlZC4gIEFcbiAgICAgKiByZXZva2VkIGtleSBpcyBub3QgdG8gYmUgdXNlZC4gIE9ubHkgcmV2b2NhdGlvbiBzaWduYXR1cmVzIGJ5IHRoZVxuICAgICAqIGtleSBiZWluZyByZXZva2VkLCBvciBieSBhbiBhdXRob3JpemVkIHJldm9jYXRpb24ga2V5LCBzaG91bGQgYmVcbiAgICAgKiBjb25zaWRlcmVkIHZhbGlkIHJldm9jYXRpb24gc2lnbmF0dXJlcy5hICovXG4gICAga2V5X3Jldm9jYXRpb246IDMyLFxuICAgIC8qKiAweDI4OiBTdWJrZXkgcmV2b2NhdGlvbiBzaWduYXR1cmVcbiAgICAgKiBUaGUgc2lnbmF0dXJlIGlzIGNhbGN1bGF0ZWQgZGlyZWN0bHkgb24gdGhlIHN1YmtleSBiZWluZyByZXZva2VkLlxuICAgICAqIEEgcmV2b2tlZCBzdWJrZXkgaXMgbm90IHRvIGJlIHVzZWQuICBPbmx5IHJldm9jYXRpb24gc2lnbmF0dXJlc1xuICAgICAqIGJ5IHRoZSB0b3AtbGV2ZWwgc2lnbmF0dXJlIGtleSB0aGF0IGlzIGJvdW5kIHRvIHRoaXMgc3Via2V5LCBvclxuICAgICAqIGJ5IGFuIGF1dGhvcml6ZWQgcmV2b2NhdGlvbiBrZXksIHNob3VsZCBiZSBjb25zaWRlcmVkIHZhbGlkXG4gICAgICogcmV2b2NhdGlvbiBzaWduYXR1cmVzLlxuICAgICAqIEtleSByZXZvY2F0aW9uIHNpZ25hdHVyZXMgKHR5cGVzIDB4MjAgYW5kIDB4MjgpXG4gICAgICogaGFzaCBvbmx5IHRoZSBrZXkgYmVpbmcgcmV2b2tlZC4gKi9cbiAgICBzdWJrZXlfcmV2b2NhdGlvbjogNDAsXG4gICAgLyoqIDB4NDA6IFRpbWVzdGFtcCBzaWduYXR1cmUuXG4gICAgICogVGhpcyBzaWduYXR1cmUgaXMgb25seSBtZWFuaW5nZnVsIGZvciB0aGUgdGltZXN0YW1wIGNvbnRhaW5lZCBpblxuICAgICAqIGl0LiAqL1xuICAgIHRpbWVzdGFtcDogNjQsXG4gICAgLyoqICAgIDB4NTA6IFRoaXJkLVBhcnR5IENvbmZpcm1hdGlvbiBzaWduYXR1cmUuXG4gICAgICogVGhpcyBzaWduYXR1cmUgaXMgYSBzaWduYXR1cmUgb3ZlciBzb21lIG90aGVyIE9wZW5QR1AgU2lnbmF0dXJlXG4gICAgICogcGFja2V0KHMpLiAgSXQgaXMgYW5hbG9nb3VzIHRvIGEgbm90YXJ5IHNlYWwgb24gdGhlIHNpZ25lZCBkYXRhLlxuICAgICAqIEEgdGhpcmQtcGFydHkgc2lnbmF0dXJlIFNIT1VMRCBpbmNsdWRlIFNpZ25hdHVyZSBUYXJnZXRcbiAgICAgKiBzdWJwYWNrZXQocykgdG8gZ2l2ZSBlYXN5IGlkZW50aWZpY2F0aW9uLiAgTm90ZSB0aGF0IHdlIHJlYWxseSBkb1xuICAgICAqIG1lYW4gU0hPVUxELiAgVGhlcmUgYXJlIHBsYXVzaWJsZSB1c2VzIGZvciB0aGlzIChzdWNoIGFzIGEgYmxpbmRcbiAgICAgKiBwYXJ0eSB0aGF0IG9ubHkgc2VlcyB0aGUgc2lnbmF0dXJlLCBub3QgdGhlIGtleSBvciBzb3VyY2VcbiAgICAgKiBkb2N1bWVudCkgdGhhdCBjYW5ub3QgaW5jbHVkZSBhIHRhcmdldCBzdWJwYWNrZXQuICovXG4gICAgdGhpcmRfcGFydHk6IDgwXG4gIH0sXG5cbiAgc2lnbmF0dXJlU3VicGFja2V0OiB7XG4gICAgc2lnbmF0dXJlX2NyZWF0aW9uX3RpbWU6IDIsXG4gICAgc2lnbmF0dXJlX2V4cGlyYXRpb25fdGltZTogMyxcbiAgICBleHBvcnRhYmxlX2NlcnRpZmljYXRpb246IDQsXG4gICAgdHJ1c3Rfc2lnbmF0dXJlOiA1LFxuICAgIHJlZ3VsYXJfZXhwcmVzc2lvbjogNixcbiAgICByZXZvY2FibGU6IDcsXG4gICAga2V5X2V4cGlyYXRpb25fdGltZTogOSxcbiAgICBwbGFjZWhvbGRlcl9iYWNrd2FyZHNfY29tcGF0aWJpbGl0eTogMTAsXG4gICAgcHJlZmVycmVkX3N5bW1ldHJpY19hbGdvcml0aG1zOiAxMSxcbiAgICByZXZvY2F0aW9uX2tleTogMTIsXG4gICAgaXNzdWVyOiAxNixcbiAgICBub3RhdGlvbl9kYXRhOiAyMCxcbiAgICBwcmVmZXJyZWRfaGFzaF9hbGdvcml0aG1zOiAyMSxcbiAgICBwcmVmZXJyZWRfY29tcHJlc3Npb25fYWxnb3JpdGhtczogMjIsXG4gICAga2V5X3NlcnZlcl9wcmVmZXJlbmNlczogMjMsXG4gICAgcHJlZmVycmVkX2tleV9zZXJ2ZXI6IDI0LFxuICAgIHByaW1hcnlfdXNlcl9pZDogMjUsXG4gICAgcG9saWN5X3VyaTogMjYsXG4gICAga2V5X2ZsYWdzOiAyNyxcbiAgICBzaWduZXJzX3VzZXJfaWQ6IDI4LFxuICAgIHJlYXNvbl9mb3JfcmV2b2NhdGlvbjogMjksXG4gICAgZmVhdHVyZXM6IDMwLFxuICAgIHNpZ25hdHVyZV90YXJnZXQ6IDMxLFxuICAgIGVtYmVkZGVkX3NpZ25hdHVyZTogMzJcbiAgfSxcblxuICBrZXlGbGFnczoge1xuICAgIC8vIDB4MDEgLSBUaGlzIGtleSBtYXkgYmUgdXNlZCB0byBjZXJ0aWZ5IG90aGVyIGtleXMuXG4gICAgY2VydGlmeV9rZXlzOiAxLFxuICAgIC8vIDB4MDIgLSBUaGlzIGtleSBtYXkgYmUgdXNlZCB0byBzaWduIGRhdGEuXG4gICAgc2lnbl9kYXRhOiAyLFxuICAgIC8vIDB4MDQgLSBUaGlzIGtleSBtYXkgYmUgdXNlZCB0byBlbmNyeXB0IGNvbW11bmljYXRpb25zLlxuICAgIGVuY3J5cHRfY29tbXVuaWNhdGlvbjogNCxcbiAgICAvLyAweDA4IC0gVGhpcyBrZXkgbWF5IGJlIHVzZWQgdG8gZW5jcnlwdCBzdG9yYWdlLlxuICAgIGVuY3J5cHRfc3RvcmFnZTogOCxcbiAgICAvLyAweDEwIC0gVGhlIHByaXZhdGUgY29tcG9uZW50IG9mIHRoaXMga2V5IG1heSBoYXZlIGJlZW4gc3BsaXRcbiAgICAvLyAgICAgICAgYnkgYSBzZWNyZXQtc2hhcmluZyBtZWNoYW5pc20uXG4gICAgc3BsaXRfcHJpdmF0ZV9rZXk6IDE2LFxuICAgIC8vIDB4MjAgLSBUaGlzIGtleSBtYXkgYmUgdXNlZCBmb3IgYXV0aGVudGljYXRpb24uXG4gICAgYXV0aGVudGljYXRpb246IDMyLFxuICAgIC8vIDB4ODAgLSBUaGUgcHJpdmF0ZSBjb21wb25lbnQgb2YgdGhpcyBrZXkgbWF5IGJlIGluIHRoZVxuICAgIC8vICAgICAgICBwb3NzZXNzaW9uIG9mIG1vcmUgdGhhbiBvbmUgcGVyc29uLlxuICAgIHNoYXJlZF9wcml2YXRlX2tleTogMTI4XG4gIH0sXG5cbiAgYXJtb3I6IHtcbiAgICBtdWx0aXBhcnRfc2VjdGlvbjogMCxcbiAgICBtdWx0aXBhcnRfbGFzdDogMSxcbiAgICBzaWduZWQ6IDIsXG4gICAgbWVzc2FnZTogMyxcbiAgICBwdWJsaWNfa2V5OiA0LFxuICAgIHByaXZhdGVfa2V5OiA1XG4gIH0sXG5cbiAgLy8gQXNzZXJ0cyB2YWxpZGl0eSBhbmQgY29udmVydHMgZnJvbSBzdHJpbmcvaW50ZWdlciB0byBpbnRlZ2VyLlxuICB3cml0ZTogZnVuY3Rpb24odHlwZSwgZSkge1xuICAgIGlmICh0eXBlb2YgZSA9PSAnbnVtYmVyJykge1xuICAgICAgZSA9IHRoaXMucmVhZCh0eXBlLCBlKTtcbiAgICB9XG5cbiAgICBpZiAodHlwZVtlXSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICByZXR1cm4gdHlwZVtlXTtcbiAgICB9IGVsc2UgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIGVudW0gdmFsdWUuJyk7XG4gIH0sXG4gIC8vIENvbnZlcnRzIGZyb20gYW4gaW50ZWdlciB0byBzdHJpbmcuXG4gIHJlYWQ6IGZ1bmN0aW9uKHR5cGUsIGUpIHtcbiAgICBmb3IgKHZhciBpIGluIHR5cGUpXG4gICAgICBpZiAodHlwZVtpXSA9PSBlKSByZXR1cm4gaTtcblxuICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBlbnVtIHZhbHVlLicpO1xuICB9XG59XG5cbm1vZHVsZS5leHBvcnRzID0gZW51bXM7XG4iLCJcbm1vZHVsZS5leHBvcnRzID0gcmVxdWlyZSgnLi9vcGVucGdwLmpzJyk7XG5tb2R1bGUuZXhwb3J0cy5rZXkgPSByZXF1aXJlKCcuL2tleS5qcycpO1xubW9kdWxlLmV4cG9ydHMubWVzc2FnZSA9IHJlcXVpcmUoJy4vbWVzc2FnZS5qcycpO1xubW9kdWxlLmV4cG9ydHMuY2xlYXJ0ZXh0ID0gcmVxdWlyZSgnLi9jbGVhcnRleHQuanMnKTtcbm1vZHVsZS5leHBvcnRzLnV0aWwgPSByZXF1aXJlKCcuL3V0aWwnKTtcbm1vZHVsZS5leHBvcnRzLnBhY2tldCA9IHJlcXVpcmUoJy4vcGFja2V0Jyk7XG5tb2R1bGUuZXhwb3J0cy5tcGkgPSByZXF1aXJlKCcuL3R5cGUvbXBpLmpzJyk7XG5tb2R1bGUuZXhwb3J0cy5zMmsgPSByZXF1aXJlKCcuL3R5cGUvczJrLmpzJyk7XG5tb2R1bGUuZXhwb3J0cy5rZXlpZCA9IHJlcXVpcmUoJy4vdHlwZS9rZXlpZC5qcycpO1xubW9kdWxlLmV4cG9ydHMuYXJtb3IgPSByZXF1aXJlKCcuL2VuY29kaW5nL2FybW9yLmpzJyk7XG5tb2R1bGUuZXhwb3J0cy5lbnVtcyA9IHJlcXVpcmUoJy4vZW51bXMuanMnKTtcbm1vZHVsZS5leHBvcnRzLmNvbmZpZyA9IHJlcXVpcmUoJy4vY29uZmlnJyk7XG5tb2R1bGUuZXhwb3J0cy5jcnlwdG8gPSByZXF1aXJlKCcuL2NyeXB0bycpO1xuIiwiLy8gR1BHNEJyb3dzZXJzIC0gQW4gT3BlblBHUCBpbXBsZW1lbnRhdGlvbiBpbiBqYXZhc2NyaXB0XG4vLyBDb3B5cmlnaHQgKEMpIDIwMTEgUmVjdXJpdHkgTGFicyBHbWJIXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3Jcbi8vIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlclxuLy8gdmVyc2lvbiAyLjEgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuLy8gYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2Zcbi8vIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUgR05VXG4vLyBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuLy8gXG4vLyBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFsb25nIHdpdGggdGhpcyBsaWJyYXJ5OyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlXG4vLyBGb3VuZGF0aW9uLCBJbmMuLCA1MSBGcmFua2xpbiBTdHJlZXQsIEZpZnRoIEZsb29yLCBCb3N0b24sIE1BICAwMjExMC0xMzAxICBVU0FcblxudmFyIHBhY2tldCA9IHJlcXVpcmUoJy4vcGFja2V0Jyk7XG52YXIgZW51bXMgPSByZXF1aXJlKCcuL2VudW1zLmpzJyk7XG52YXIgYXJtb3IgPSByZXF1aXJlKCcuL2VuY29kaW5nL2FybW9yLmpzJyk7XG52YXIgY29uZmlnID0gcmVxdWlyZSgnLi9jb25maWcnKTtcblxuLyoqXG4gKiBAY2xhc3NcbiAqIEBjbGFzc2Rlc2MgQ2xhc3MgdGhhdCByZXByZXNlbnRzIGFuIE9wZW5QR1Aga2V5LiBNdXN0IGNvbnRhaW4gYSBwcmltYXJ5IGtleS5cbiAqIENhbiBjb250YWluIGFkZGl0aW9uYWwgc3Via2V5cywgc2lnbmF0dXJlcywgdXNlciBpZHMsIHVzZXIgYXR0cmlidXRlcy5cbiAqIEBwYXJhbSAge3BhY2tldGxpc3R9IHBhY2tldGxpc3QgVGhlIHBhY2tldHMgdGhhdCBmb3JtIHRoaXMga2V5XG4gKi9cblxuZnVuY3Rpb24gS2V5KHBhY2tldGxpc3QpIHtcbiAgaWYgKCEodGhpcyBpbnN0YW5jZW9mIEtleSkpIHtcbiAgICByZXR1cm4gbmV3IEtleShwYWNrZXRsaXN0KTtcbiAgfVxuICB0aGlzLnBhY2tldHMgPSBwYWNrZXRsaXN0IHx8IG5ldyBwYWNrZXQubGlzdCgpO1xufVxuXG4vKiogXG4gKiBSZXR1cm5zIHRoZSBwcmltYXJ5IGtleSBwYWNrZXQgKHNlY3JldCBvciBwdWJsaWMpXG4gKiBAcmV0dXJucyB7cGFja2V0X3NlY3JldF9rZXl8cGFja2V0X3B1YmxpY19rZXl8bnVsbH0gXG4gKi9cbktleS5wcm90b3R5cGUuZ2V0S2V5UGFja2V0ID0gZnVuY3Rpb24oKSB7XG4gIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5wYWNrZXRzLmxlbmd0aDsgaSsrKSB7XG4gICAgaWYgKHRoaXMucGFja2V0c1tpXS50YWcgPT0gZW51bXMucGFja2V0LnB1YmxpY19rZXkgfHxcbiAgICAgIHRoaXMucGFja2V0c1tpXS50YWcgPT0gZW51bXMucGFja2V0LnNlY3JldF9rZXkpIHtcbiAgICAgIHJldHVybiB0aGlzLnBhY2tldHNbaV07XG4gICAgfVxuICB9XG4gIHJldHVybiBudWxsO1xufTtcblxuLyoqIFxuICogUmV0dXJucyBhbGwgdGhlIHByaXZhdGUgYW5kIHB1YmxpYyBzdWJrZXkgcGFja2V0c1xuICogQHJldHVybnMge1twdWJsaWNfc3Via2V5fHNlY3JldF9zdWJrZXldfSBcbiAqL1xuS2V5LnByb3RvdHlwZS5nZXRTdWJrZXlQYWNrZXRzID0gZnVuY3Rpb24oKSB7XG5cbiAgdmFyIHN1YmtleXMgPSBbXTtcblxuICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMucGFja2V0cy5sZW5ndGg7IGkrKykge1xuICAgIGlmICh0aGlzLnBhY2tldHNbaV0udGFnID09IGVudW1zLnBhY2tldC5wdWJsaWNfc3Via2V5IHx8XG4gICAgICB0aGlzLnBhY2tldHNbaV0udGFnID09IGVudW1zLnBhY2tldC5zZWNyZXRfc3Via2V5KSB7XG4gICAgICBzdWJrZXlzLnB1c2godGhpcy5wYWNrZXRzW2ldKTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gc3Via2V5cztcbn07XG5cbi8qKiBcbiAqIFJldHVybnMgYWxsIHRoZSBwcml2YXRlIGFuZCBwdWJsaWMga2V5IGFuZCBzdWJrZXkgcGFja2V0c1xuICogQHJldHVybnMge1twdWJsaWNfc3Via2V5fHNlY3JldF9zdWJrZXl8cGFja2V0X3NlY3JldF9rZXl8cGFja2V0X3B1YmxpY19rZXldfSBcbiAqL1xuS2V5LnByb3RvdHlwZS5nZXRBbGxLZXlQYWNrZXRzID0gZnVuY3Rpb24oKSB7XG4gIHJldHVybiBbdGhpcy5nZXRLZXlQYWNrZXQoKV0uY29uY2F0KHRoaXMuZ2V0U3Via2V5UGFja2V0cygpKTtcbn07XG5cbi8qKiBcbiAqIFJldHVybnMga2V5IElEcyBvZiBhbGwga2V5IHBhY2tldHNcbiAqIEByZXR1cm5zIHtba2V5aWRdfSBcbiAqL1xuS2V5LnByb3RvdHlwZS5nZXRLZXlJZHMgPSBmdW5jdGlvbigpIHtcbiAgdmFyIGtleUlkcyA9IFtdO1xuICB2YXIga2V5cyA9IHRoaXMuZ2V0QWxsS2V5UGFja2V0cygpO1xuICBmb3IgKHZhciBpID0gMDsgaSA8IGtleXMubGVuZ3RoOyBpKyspIHtcbiAgICBrZXlJZHMucHVzaChrZXlzW2ldLmdldEtleUlkKCkpO1xuICB9XG4gIHJldHVybiBrZXlJZHM7XG59O1xuXG5mdW5jdGlvbiBmaW5kS2V5KGtleXMsIGtleUlkcykge1xuICBmb3IgKHZhciBpID0gMDsgaSA8IGtleXMubGVuZ3RoOyBpKyspIHtcbiAgICB2YXIga2V5SWQgPSBrZXlzW2ldLmdldEtleUlkKCk7IFxuICAgIGZvciAodmFyIGogPSAwOyBqIDwga2V5SWRzLmxlbmd0aDsgaisrKSB7XG4gICAgICBpZiAoa2V5SWQuZXF1YWxzKGtleUlkc1tqXSkpIHtcbiAgICAgICAgcmV0dXJuIGtleXNbaV07XG4gICAgICB9XG4gICAgfVxuICB9XG4gIHJldHVybiBudWxsO1xufVxuXG4vKipcbiAqIFJldHVybnMgZmlyc3QgcHVibGljIGtleSBwYWNrZXQgZm9yIGdpdmVuIGFycmF5IG9mIGtleSBJRHNcbiAqIEBwYXJhbSAge1trZXlpZF19IGtleUlkcyBcbiAqIEByZXR1cm4ge3B1YmxpY19zdWJrZXl8cGFja2V0X3B1YmxpY19rZXl8bnVsbH0gICAgICAgXG4gKi9cbktleS5wcm90b3R5cGUuZ2V0UHVibGljS2V5UGFja2V0ID0gZnVuY3Rpb24oa2V5SWRzKSB7XG4gIHZhciBrZXlzID0gdGhpcy5wYWNrZXRzLmZpbHRlckJ5VGFnKGVudW1zLnBhY2tldC5wdWJsaWNfa2V5LCBlbnVtcy5wYWNrZXQucHVibGljX3N1YmtleSk7XG4gIHJldHVybiBmaW5kS2V5KGtleXMsIGtleUlkcyk7XG59O1xuXG4vKipcbiAqIFJldHVybnMgZmlyc3QgcHJpdmF0ZSBrZXkgcGFja2V0IGZvciBnaXZlbiBhcnJheSBvZiBrZXkgSURzXG4gKiBAcGFyYW0gIHtba2V5aWRdfSBrZXlJZHNcbiAqIEByZXR1cm4ge3NlY3JldF9zdWJrZXl8cGFja2V0X3NlY3JldF9rZXl8bnVsbH0gICAgICAgXG4gKi9cbktleS5wcm90b3R5cGUuZ2V0UHJpdmF0ZUtleVBhY2tldCA9IGZ1bmN0aW9uKGtleUlkcykge1xuICB2YXIga2V5cyA9IHRoaXMucGFja2V0cy5maWx0ZXJCeVRhZyhlbnVtcy5wYWNrZXQuc2VjcmV0X2tleSwgZW51bXMucGFja2V0LnNlY3JldF9zdWJrZXkpO1xuICByZXR1cm4gZmluZEtleShrZXlzLCBrZXlJZHMpO1xufTtcblxuLyoqXG4gKiBSZXR1cm5zIHVzZXJpZHNcbiAqIEByZXR1cm4ge3N0cmluZ30gdXNlcmlkW11cbiAqL1xuS2V5LnByb3RvdHlwZS5nZXRVc2VySWRzID0gZnVuY3Rpb24oKSB7XG4gIHZhciB1c2VyaWRzID0gW107XG4gIHZhciB1c2VyaWRQYWNrZXRzID0gdGhpcy5wYWNrZXRzLmZpbHRlckJ5VGFnKGVudW1zLnBhY2tldC51c2VyaWQpO1xuICBmb3IgKHZhciBpID0gMDsgaSA8IHVzZXJpZFBhY2tldHMubGVuZ3RoOyBpKyspIHtcbiAgICB1c2VyaWRzLnB1c2godXNlcmlkUGFja2V0c1tpXS53cml0ZSgpKTtcbiAgfVxuICByZXR1cm4gdXNlcmlkcztcbn07XG5cbi8qKlxuICogUmV0dXJucyB0cnVlIGlmIHRoaXMgaXMgYSBwdWJsaWMga2V5XG4gKiBAcmV0dXJuIHtCb29sZWFufVxuICovXG5LZXkucHJvdG90eXBlLmlzUHVibGljID0gZnVuY3Rpb24oKSB7XG4gIHZhciBwdWJsaWNLZXlQYWNrZXRzID0gdGhpcy5wYWNrZXRzLmZpbHRlckJ5VGFnKGVudW1zLnBhY2tldC5wdWJsaWNfa2V5KTtcbiAgcmV0dXJuIHB1YmxpY0tleVBhY2tldHMubGVuZ3RoID8gdHJ1ZSA6IGZhbHNlO1xufTtcblxuLyoqXG4gKiBSZXR1cm5zIHRydWUgaWYgdGhpcyBpcyBhIHByaXZhdGUga2V5XG4gKiBAcmV0dXJuIHtCb29sZWFufVxuICovXG5LZXkucHJvdG90eXBlLmlzUHJpdmF0ZSA9IGZ1bmN0aW9uKCkge1xuICB2YXIgcHJpdmF0ZUtleVBhY2tldHMgPSB0aGlzLnBhY2tldHMuZmlsdGVyQnlUYWcoZW51bXMucGFja2V0LnByaXZhdGVfa2V5KTtcbiAgcmV0dXJuIHByaXZhdGVLZXlQYWNrZXRzLmxlbmd0aCA/IHRydWUgOiBmYWxzZTtcbn07XG5cbi8qKlxuICogUmV0dXJucyBrZXkgYXMgcHVibGljIGtleVxuICogQHJldHVybiB7a2V5fSBwdWJsaWMga2V5XG4gKi9cbktleS5wcm90b3R5cGUudG9QdWJsaWMgPSBmdW5jdGlvbigpIHtcbiAgdmFyIHBhY2tldGxpc3QgPSBuZXcgcGFja2V0Lmxpc3QoKTtcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLnBhY2tldHMubGVuZ3RoOyBpKyspIHtcbiAgICBzd2l0Y2ggKHRoaXMucGFja2V0c1tpXS50YWcpIHtcbiAgICAgIGNhc2UgZW51bXMucGFja2V0LnNlY3JldF9rZXk6XG4gICAgICAgIHZhciBieXRlcyA9IHRoaXMucGFja2V0c1tpXS53cml0ZVB1YmxpY0tleSgpO1xuICAgICAgICB2YXIgcHViS2V5UGFja2V0ID0gbmV3IHBhY2tldC5wdWJsaWNfa2V5KCk7XG4gICAgICAgIHB1YktleVBhY2tldC5yZWFkKGJ5dGVzKTtcbiAgICAgICAgcGFja2V0bGlzdC5wdXNoKHB1YktleVBhY2tldCk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSBlbnVtcy5wYWNrZXQuc2VjcmV0X3N1YmtleTpcbiAgICAgICAgdmFyIGJ5dGVzID0gdGhpcy5wYWNrZXRzW2ldLndyaXRlUHVibGljS2V5KCk7XG4gICAgICAgIHZhciBwdWJTdWJrZXlQYWNrZXQgPSBuZXcgcGFja2V0LnB1YmxpY19zdWJrZXkoKTtcbiAgICAgICAgcHViU3Via2V5UGFja2V0LnJlYWQoYnl0ZXMpO1xuICAgICAgICBwYWNrZXRsaXN0LnB1c2gocHViU3Via2V5UGFja2V0KTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBkZWZhdWx0OlxuICAgICAgICBwYWNrZXRsaXN0LnB1c2godGhpcy5wYWNrZXRzW2ldKTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIG5ldyBLZXkocGFja2V0bGlzdCk7XG59O1xuXG4vKipcbiAqIFJldHVybnMgQVNDSUkgYXJtb3JlZCB0ZXh0IG9mIGtleVxuICogQHJldHVybiB7U3RyaW5nfSBBU0NJSSBhcm1vclxuICovXG5LZXkucHJvdG90eXBlLmFybW9yID0gZnVuY3Rpb24oKSB7XG4gIHZhciB0eXBlID0gdGhpcy5pc1B1YmxpYygpID8gZW51bXMuYXJtb3IucHVibGljX2tleSA6IGVudW1zLmFybW9yLnByaXZhdGVfa2V5O1xuICByZXR1cm4gYXJtb3IuZW5jb2RlKHR5cGUsIHRoaXMucGFja2V0cy53cml0ZSgpKTtcbn07XG5cbi8qKlxuICogUmV0dXJucyBmaXJzdCBrZXkgcGFja2V0IHRoYXQgaXMgYXZhaWxhYmxlIGZvciBzaWduaW5nXG4gKiBAcmV0dXJuIHtwdWJsaWNfc3Via2V5fHNlY3JldF9zdWJrZXl8cGFja2V0X3NlY3JldF9rZXl8cGFja2V0X3B1YmxpY19rZXl8bnVsbH1cbiAqL1xuS2V5LnByb3RvdHlwZS5nZXRTaWduaW5nS2V5UGFja2V0ID0gZnVuY3Rpb24oKSB7XG5cbiAgdmFyIHNpZ25pbmcgPSBbIGVudW1zLnB1YmxpY0tleS5yc2FfZW5jcnlwdF9zaWduLCBlbnVtcy5wdWJsaWNLZXkucnNhX3NpZ24sIGVudW1zLnB1YmxpY0tleS5kc2FdO1xuXG4gIHNpZ25pbmcgPSBzaWduaW5nLm1hcChmdW5jdGlvbihzKSB7XG4gICAgcmV0dXJuIGVudW1zLnJlYWQoZW51bXMucHVibGljS2V5LCBzKTtcbiAgfSk7XG5cbiAgdmFyIGtleXMgPSB0aGlzLmdldEFsbEtleVBhY2tldHMoKTtcblxuICBmb3IgKHZhciBpID0gMDsgaSA8IGtleXMubGVuZ3RoOyBpKyspIHtcbiAgICBpZiAoc2lnbmluZy5pbmRleE9mKGtleXNbaV0uYWxnb3JpdGhtKSAhPT0gLTEpIHtcbiAgICAgIHJldHVybiBrZXlzW2ldO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiBudWxsO1xufTtcblxuLyoqXG4gKiBSZXR1cm5zIHByZWZlcnJlZCBzaWduYXR1cmUgaGFzaCBhbGdvcml0aG0gb2YgdGhpcyBrZXlcbiAqIEByZXR1cm4ge1N0cmluZ31cbiAqL1xuS2V5LnByb3RvdHlwZS5nZXRQcmVmZXJyZWRTaWduYXR1cmVIYXNoQWxnb3JpdGhtID0gZnVuY3Rpb24oKSB7XG4gIC8vVE9ETyBpbXBsZW1lbnQ6IGh0dHBzOi8vdG9vbHMuaWV0Zi5vcmcvaHRtbC9yZmM0ODgwI3NlY3Rpb24tNS4yLjMuOFxuICAvL3NlcGFyYXRlIHByaXZhdGUga2V5IHByZWZlcmVuY2UgZnJvbSBkaWdlc3QgcHJlZmVyZW5jZXNcbiAgcmV0dXJuIGNvbmZpZy5wcmVmZXJfaGFzaF9hbGdvcml0aG07XG59O1xuXG4vKipcbiAqIFJldHVybnMgdGhlIGZpcnN0IHZhbGlkIGVuY3J5cHRpb24ga2V5IHBhY2tldCBmb3IgdGhpcyBrZXlcbiAqIEByZXR1cm5zIHtwdWJsaWNfc3Via2V5fHNlY3JldF9zdWJrZXl8cGFja2V0X3NlY3JldF9rZXl8cGFja2V0X3B1YmxpY19rZXl8bnVsbH0ga2V5IHBhY2tldCBvciBudWxsIGlmIG5vIGVuY3J5cHRpb24ga2V5IGhhcyBiZWVuIGZvdW5kXG4gKi9cbktleS5wcm90b3R5cGUuZ2V0RW5jcnlwdGlvbktleVBhY2tldCA9IGZ1bmN0aW9uKCkge1xuICAvLyBWNDogYnkgY29udmVudGlvbiBzdWJrZXlzIGFyZSBwcmVmZXJlZCBmb3IgZW5jcnlwdGlvbiBzZXJ2aWNlXG4gIC8vIFYzOiBrZXlzIE1VU1QgTk9UIGhhdmUgc3Via2V5c1xuICB2YXIgaXNWYWxpZEVuY3J5cHRpb25LZXkgPSBmdW5jdGlvbihrZXkpIHtcbiAgICAvL1RPRE8gZXZhbHVhdGUga2V5IGZsYWdzOiBodHRwOi8vdG9vbHMuaWV0Zi5vcmcvaHRtbC9yZmM0ODgwI3NlY3Rpb24tNS4yLjMuMjFcbiAgICByZXR1cm4ga2V5LmFsZ29yaXRobSAhPSBlbnVtcy5yZWFkKGVudW1zLnB1YmxpY0tleSwgZW51bXMucHVibGljS2V5LmRzYSkgJiYga2V5LmFsZ29yaXRobSAhPSBlbnVtcy5yZWFkKGVudW1zLnB1YmxpY0tleSxcbiAgICAgIGVudW1zLnB1YmxpY0tleS5yc2Ffc2lnbik7XG4gICAgLy9UT0RPIHZlcmlmeSBrZXlcbiAgICAvLyYmIGtleXMudmVyaWZ5S2V5KClcbiAgfTtcblxuICB2YXIgc3Via2V5cyA9IHRoaXMuZ2V0U3Via2V5UGFja2V0cygpO1xuXG4gIGZvciAodmFyIGogPSAwOyBqIDwgc3Via2V5cy5sZW5ndGg7IGorKykge1xuICAgIGlmIChpc1ZhbGlkRW5jcnlwdGlvbktleShzdWJrZXlzW2pdKSkge1xuICAgICAgcmV0dXJuIHN1YmtleXNbal07XG4gICAgfVxuICB9XG4gIC8vIGlmIG5vIHZhbGlkIHN1YmtleSBmb3IgZW5jcnlwdGlvbiwgdXNlIHByaW1hcnkga2V5XG4gIHZhciBwcmltYXJ5S2V5ID0gdGhpcy5nZXRLZXlQYWNrZXQoKTtcbiAgaWYgKGlzVmFsaWRFbmNyeXB0aW9uS2V5KHByaW1hcnlLZXkpKSB7XG4gICAgcmV0dXJuIHByaW1hcnlLZXk7XG4gIH1cbiAgcmV0dXJuIG51bGw7XG59O1xuXG4vKipcbiAqIERlY3J5cHRzIGFsbCBzZWNyZXQga2V5IGFuZCBzdWJrZXkgcGFja2V0c1xuICogQHBhcmFtICB7U3RyaW5nfSBwYXNzcGhyYXNlIFxuICogQHJldHVybiB7Qm9vbGVhbn0gdHJ1ZSBpZiBhbGwga2V5IGFuZCBzdWJrZXkgcGFja2V0cyBkZWNyeXB0ZWQgc3VjY2Vzc2Z1bGx5XG4gKi9cbktleS5wcm90b3R5cGUuZGVjcnlwdCA9IGZ1bmN0aW9uKHBhc3NwaHJhc2UpIHtcbiAgdmFyIGtleXMgPSB0aGlzLnBhY2tldHMuZmlsdGVyQnlUYWcoZW51bXMucGFja2V0LnNlY3JldF9rZXksIGVudW1zLnBhY2tldC5zZWNyZXRfc3Via2V5KTtcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBrZXlzLmxlbmd0aDsgaSsrKSB7XG4gICAgdmFyIHN1Y2Nlc3MgPSBrZXlzW2ldLmRlY3J5cHQocGFzc3BocmFzZSk7XG4gICAgaWYgKCFzdWNjZXNzKSByZXR1cm4gZmFsc2U7XG4gIH1cbiAgcmV0dXJuIHRydWU7XG59O1xuXG4vKipcbiAqIERlY3J5cHRzIHNwZWNpZmljIGtleSBwYWNrZXRzIGJ5IGtleSBJRFxuICogQHBhcmFtICB7W2tleWlkXX0ga2V5SWRzXG4gKiBAcGFyYW0gIHtTdHJpbmd9IHBhc3NwaHJhc2UgXG4gKiBAcmV0dXJuIHtCb29sZWFufSB0cnVlIGlmIGFsbCBrZXkgcGFja2V0cyBkZWNyeXB0ZWQgc3VjY2Vzc2Z1bGx5XG4gKi9cbktleS5wcm90b3R5cGUuZGVjcnlwdEtleVBhY2tldCA9IGZ1bmN0aW9uKGtleUlkcywgcGFzc3BocmFzZSkge1xuICAvL1RPRE8gcmV0dXJuIHZhbHVlXG4gIHZhciBrZXlzID0gdGhpcy5wYWNrZXRzLmZpbHRlckJ5VGFnKGVudW1zLnBhY2tldC5zZWNyZXRfa2V5LCBlbnVtcy5wYWNrZXQuc2VjcmV0X3N1YmtleSk7XG4gIGZvciAodmFyIGkgPSAwOyBpIDwga2V5cy5sZW5ndGg7IGkrKykge1xuICAgIHZhciBrZXlJZCA9IGtleXNbaV0uZ2V0S2V5SWQoKTsgXG4gICAgZm9yICh2YXIgaiA9IDA7IGogPCBrZXlJZHMubGVuZ3RoOyBqKyspIHtcbiAgICAgIGlmIChrZXlJZC5lcXVhbHMoa2V5SWRzW2pdKSkge1xuICAgICAgICB2YXIgc3VjY2VzcyA9IGtleXNbaV0uZGVjcnlwdChwYXNzcGhyYXNlKTtcbiAgICAgICAgaWYgKCFzdWNjZXNzKSByZXR1cm4gZmFsc2U7XG4gICAgICB9XG4gICAgfVxuICB9XG4gIHJldHVybiB0cnVlO1xufTtcblxuLy8gVE9ET1xuS2V5LnByb3RvdHlwZS52ZXJpZnkgPSBmdW5jdGlvbigpIHtcblxufTtcbi8vIFRPRE9cbktleS5wcm90b3R5cGUucmV2b2tlID0gZnVuY3Rpb24oKSB7XG5cbn07XG5cbi8qKlxuICogUmVhZHMgYW4gT3BlblBHUCBhcm1vcmVkIHRleHQgYW5kIHJldHVybnMgYSBrZXkgb2JqZWN0XG4gKiBAcGFyYW0ge1N0cmluZ30gYXJtb3JlZFRleHQgdGV4dCB0byBiZSBwYXJzZWRcbiAqIEByZXR1cm4ge2tleX0gbmV3IGtleSBvYmplY3RcbiAqL1xuZnVuY3Rpb24gcmVhZEFybW9yZWQoYXJtb3JlZFRleHQpIHtcbiAgdmFyIGlucHV0ID0gYXJtb3IuZGVjb2RlKGFybW9yZWRUZXh0KTtcbiAgaWYgKCEoaW5wdXQudHlwZSA9PSBlbnVtcy5hcm1vci5wdWJsaWNfa2V5IHx8IGlucHV0LnR5cGUgPT0gZW51bXMuYXJtb3IucHJpdmF0ZV9rZXkpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdBcm1vcmVkIHRleHQgbm90IG9mIHR5cGUga2V5Jyk7XG4gIH1cbiAgdmFyIHBhY2tldGxpc3QgPSBuZXcgcGFja2V0Lmxpc3QoKTtcbiAgcGFja2V0bGlzdC5yZWFkKGlucHV0LmRhdGEpO1xuICB2YXIgbmV3S2V5ID0gbmV3IEtleShwYWNrZXRsaXN0KTtcbiAgcmV0dXJuIG5ld0tleTtcbn1cblxuLyoqXG4gKiBHZW5lcmF0ZXMgYSBuZXcgT3BlblBHUCBrZXkuIEN1cnJlbnRseSBvbmx5IHN1cHBvcnRzIFJTQSBrZXlzLlxuICogUHJpbWFyeSBhbmQgc3Via2V5IHdpbGwgYmUgb2Ygc2FtZSB0eXBlLlxuICogQHBhcmFtIHtJbnRlZ2VyfSBrZXlUeXBlICAgIHRvIGluZGljYXRlIHdoYXQgdHlwZSBvZiBrZXkgdG8gbWFrZS4gXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUlNBIGlzIDEuIFNlZSBodHRwOi8vdG9vbHMuaWV0Zi5vcmcvaHRtbC9yZmM0ODgwI3NlY3Rpb24tOS4xXG4gKiBAcGFyYW0ge0ludGVnZXJ9IG51bUJpdHMgICAgbnVtYmVyIG9mIGJpdHMgZm9yIHRoZSBrZXkgY3JlYXRpb24uXG4gKiBAcGFyYW0ge1N0cmluZ30gIHVzZXJJZCAgICAgYXNzdW1lcyBhbHJlYWR5IGluIGZvcm0gb2YgXCJVc2VyIE5hbWUgPHVzZXJuYW1lQGVtYWlsLmNvbT5cIlxuICogQHBhcmFtIHtTdHJpbmd9ICBwYXNzcGhyYXNlIFRoZSBwYXNzcGhyYXNlIHVzZWQgdG8gZW5jcnlwdCB0aGUgcmVzdWx0aW5nIHByaXZhdGUga2V5XG4gKiBAcmV0dXJuIHtLZXl9XG4gKi9cbmZ1bmN0aW9uIGdlbmVyYXRlKGtleVR5cGUsIG51bUJpdHMsIHVzZXJJZCwgcGFzc3BocmFzZSkge1xuICB2YXIgcGFja2V0bGlzdCA9IG5ldyBwYWNrZXQubGlzdCgpO1xuXG4gIHZhciBzZWNyZXRLZXlQYWNrZXQgPSBuZXcgcGFja2V0LnNlY3JldF9rZXkoKTtcbiAgc2VjcmV0S2V5UGFja2V0LmFsZ29yaXRobSA9IGVudW1zLnJlYWQoZW51bXMucHVibGljS2V5LCBrZXlUeXBlKTtcbiAgc2VjcmV0S2V5UGFja2V0LmdlbmVyYXRlKG51bUJpdHMpO1xuICBzZWNyZXRLZXlQYWNrZXQuZW5jcnlwdChwYXNzcGhyYXNlKTtcblxuICB2YXIgdXNlcklkUGFja2V0ID0gbmV3IHBhY2tldC51c2VyaWQoKTtcbiAgdXNlcklkUGFja2V0LnJlYWQodXNlcklkKTtcblxuICB2YXIgZGF0YVRvU2lnbiA9IHt9O1xuICBkYXRhVG9TaWduLnVzZXJpZCA9IHVzZXJJZFBhY2tldDtcbiAgZGF0YVRvU2lnbi5rZXkgPSBzZWNyZXRLZXlQYWNrZXQ7XG4gIHZhciBzaWduYXR1cmVQYWNrZXQgPSBuZXcgcGFja2V0LnNpZ25hdHVyZSgpO1xuICBzaWduYXR1cmVQYWNrZXQuc2lnbmF0dXJlVHlwZSA9IGVudW1zLnNpZ25hdHVyZS5jZXJ0X2dlbmVyaWM7XG4gIHNpZ25hdHVyZVBhY2tldC5wdWJsaWNLZXlBbGdvcml0aG0gPSBrZXlUeXBlO1xuICAvL1RPRE8gd2Ugc2hvdWxkIGxvYWQgcHJlZmVycmVkIGhhc2ggZnJvbSBjb25maWcsIG9yIGFzIGlucHV0IHRvIHRoaXMgZnVuY3Rpb25cbiAgc2lnbmF0dXJlUGFja2V0Lmhhc2hBbGdvcml0aG0gPSBlbnVtcy5oYXNoLnNoYTI1NjtcbiAgc2lnbmF0dXJlUGFja2V0LmtleUZsYWdzID0gW2VudW1zLmtleUZsYWdzLmNlcnRpZnlfa2V5cyB8IGVudW1zLmtleUZsYWdzLnNpZ25fZGF0YV07XG4gIHNpZ25hdHVyZVBhY2tldC5zaWduKHNlY3JldEtleVBhY2tldCwgZGF0YVRvU2lnbik7XG5cbiAgdmFyIHNlY3JldFN1YmtleVBhY2tldCA9IG5ldyBwYWNrZXQuc2VjcmV0X3N1YmtleSgpO1xuICBzZWNyZXRTdWJrZXlQYWNrZXQuYWxnb3JpdGhtID0gZW51bXMucmVhZChlbnVtcy5wdWJsaWNLZXksIGtleVR5cGUpO1xuICBzZWNyZXRTdWJrZXlQYWNrZXQuZ2VuZXJhdGUobnVtQml0cyk7XG4gIHNlY3JldFN1YmtleVBhY2tldC5lbmNyeXB0KHBhc3NwaHJhc2UpO1xuXG4gIGRhdGFUb1NpZ24gPSB7fTtcbiAgZGF0YVRvU2lnbi5rZXkgPSBzZWNyZXRLZXlQYWNrZXQ7XG4gIGRhdGFUb1NpZ24uYmluZCA9IHNlY3JldFN1YmtleVBhY2tldDtcbiAgdmFyIHN1YmtleVNpZ25hdHVyZVBhY2tldCA9IG5ldyBwYWNrZXQuc2lnbmF0dXJlKCk7XG4gIHN1YmtleVNpZ25hdHVyZVBhY2tldC5zaWduYXR1cmVUeXBlID0gZW51bXMuc2lnbmF0dXJlLnN1YmtleV9iaW5kaW5nO1xuICBzdWJrZXlTaWduYXR1cmVQYWNrZXQucHVibGljS2V5QWxnb3JpdGhtID0ga2V5VHlwZTtcbiAgLy9UT0RPIHdlIHNob3VsZCBsb2FkIHByZWZlcnJlZCBoYXNoIGZyb20gY29uZmlnLCBvciBhcyBpbnB1dCB0byB0aGlzIGZ1bmN0aW9uXG4gIHN1YmtleVNpZ25hdHVyZVBhY2tldC5oYXNoQWxnb3JpdGhtID0gZW51bXMuaGFzaC5zaGEyNTY7XG4gIHN1YmtleVNpZ25hdHVyZVBhY2tldC5rZXlGbGFncyA9IFtlbnVtcy5rZXlGbGFncy5lbmNyeXB0X2NvbW11bmljYXRpb24gfCBlbnVtcy5rZXlGbGFncy5lbmNyeXB0X3N0b3JhZ2VdO1xuICBzdWJrZXlTaWduYXR1cmVQYWNrZXQuc2lnbihzZWNyZXRLZXlQYWNrZXQsIGRhdGFUb1NpZ24pO1xuXG4gIHBhY2tldGxpc3QucHVzaChzZWNyZXRLZXlQYWNrZXQpO1xuICBwYWNrZXRsaXN0LnB1c2godXNlcklkUGFja2V0KTtcbiAgcGFja2V0bGlzdC5wdXNoKHNpZ25hdHVyZVBhY2tldCk7XG4gIHBhY2tldGxpc3QucHVzaChzZWNyZXRTdWJrZXlQYWNrZXQpO1xuICBwYWNrZXRsaXN0LnB1c2goc3Via2V5U2lnbmF0dXJlUGFja2V0KTtcblxuICByZXR1cm4gbmV3IEtleShwYWNrZXRsaXN0KTtcbn1cblxuZXhwb3J0cy5LZXkgPSBLZXk7XG5leHBvcnRzLnJlYWRBcm1vcmVkID0gcmVhZEFybW9yZWQ7XG5leHBvcnRzLmdlbmVyYXRlID0gZ2VuZXJhdGU7XG4iLCIvLyBHUEc0QnJvd3NlcnMgLSBBbiBPcGVuUEdQIGltcGxlbWVudGF0aW9uIGluIGphdmFzY3JpcHRcbi8vIENvcHlyaWdodCAoQykgMjAxMSBSZWN1cml0eSBMYWJzIEdtYkhcbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vclxuLy8gbW9kaWZ5IGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyXG4vLyB2ZXJzaW9uIDIuMSBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4vLyBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuLy8gTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZSBHTlVcbi8vIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG4vLyBcbi8vIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYWxvbmcgd2l0aCB0aGlzIGxpYnJhcnk7IGlmIG5vdCwgd3JpdGUgdG8gdGhlIEZyZWUgU29mdHdhcmVcbi8vIEZvdW5kYXRpb24sIEluYy4sIDUxIEZyYW5rbGluIFN0cmVldCwgRmlmdGggRmxvb3IsIEJvc3RvbiwgTUEgIDAyMTEwLTEzMDEgIFVTQVxuXG52YXIgcGFja2V0ID0gcmVxdWlyZSgnLi9wYWNrZXQnKTtcbnZhciBlbnVtcyA9IHJlcXVpcmUoJy4vZW51bXMuanMnKTtcbnZhciBhcm1vciA9IHJlcXVpcmUoJy4vZW5jb2RpbmcvYXJtb3IuanMnKTtcbnZhciBjb25maWcgPSByZXF1aXJlKCcuL2NvbmZpZycpO1xudmFyIGNyeXB0byA9IHJlcXVpcmUoJy4vY3J5cHRvJyk7XG52YXIgdXRpbCA9IHJlcXVpcmUoJy4vdXRpbCcpO1xuXG4vKipcbiAqIEBjbGFzc1xuICogQGNsYXNzZGVzYyBDbGFzcyB0aGF0IHJlcHJlc2VudHMgYW4gT3BlblBHUCBtZXNzYWdlLlxuICogQ2FuIGJlIGFuIGVuY3J5cHRlZCBtZXNzYWdlLCBzaWduZWQgbWVzc2FnZSwgY29tcHJlc3NlZCBtZXNzYWdlIG9yIGxpdGVyYWwgbWVzc2FnZVxuICogQHBhcmFtICB7cGFja2V0bGlzdH0gcGFja2V0bGlzdCBUaGUgcGFja2V0cyB0aGF0IGZvcm0gdGhpcyBtZXNzYWdlXG4gKiBTZWUgaHR0cDovL3Rvb2xzLmlldGYub3JnL2h0bWwvcmZjNDg4MCNzZWN0aW9uLTExLjNcbiAqL1xuXG5mdW5jdGlvbiBNZXNzYWdlKHBhY2tldGxpc3QpIHtcbiAgaWYgKCEodGhpcyBpbnN0YW5jZW9mIE1lc3NhZ2UpKSB7XG4gICAgcmV0dXJuIG5ldyBNZXNzYWdlKHBhY2tldGxpc3QpO1xuICB9XG4gIHRoaXMucGFja2V0cyA9IHBhY2tldGxpc3QgfHwgbmV3IHBhY2tldC5saXN0KCk7XG59XG5cbi8qKlxuICogUmV0dXJucyB0aGUga2V5IElEcyBvZiB0aGUga2V5cyB0byB3aGljaCB0aGUgc2Vzc2lvbiBrZXkgaXMgZW5jcnlwdGVkXG4gKiBAcmV0dXJuIHtba2V5SWRdfSBhcnJheSBvZiBrZXlpZCBvYmplY3RzXG4gKi9cbk1lc3NhZ2UucHJvdG90eXBlLmdldEVuY3J5cHRpb25LZXlJZHMgPSBmdW5jdGlvbigpIHtcbiAgdmFyIGtleUlkcyA9IFtdO1xuICB2YXIgcGtFU0tleVBhY2tldGxpc3QgPSB0aGlzLnBhY2tldHMuZmlsdGVyQnlUYWcoZW51bXMucGFja2V0LnB1YmxpY19rZXlfZW5jcnlwdGVkX3Nlc3Npb25fa2V5KTtcbiAgcGtFU0tleVBhY2tldGxpc3QuZm9yRWFjaChmdW5jdGlvbihwYWNrZXQpIHtcbiAgICBrZXlJZHMucHVzaChwYWNrZXQucHVibGljS2V5SWQpO1xuICB9KTtcbiAgcmV0dXJuIGtleUlkcztcbn07XG5cbi8qKlxuICogUmV0dXJucyB0aGUga2V5IElEcyBvZiB0aGUga2V5cyB0aGF0IHNpZ25lZCB0aGUgbWVzc2FnZVxuICogQHJldHVybiB7W2tleUlkXX0gYXJyYXkgb2Yga2V5aWQgb2JqZWN0c1xuICovXG5NZXNzYWdlLnByb3RvdHlwZS5nZXRTaWduaW5nS2V5SWRzID0gZnVuY3Rpb24oKSB7XG4gIHZhciBrZXlJZHMgPSBbXTtcbiAgdmFyIG1zZyA9IHRoaXMudW53cmFwQ29tcHJlc3NlZCgpO1xuICAvLyBzZWFyY2ggZm9yIG9uZSBwYXNzIHNpZ25hdHVyZXNcbiAgdmFyIG9uZVBhc3NTaWdMaXN0ID0gbXNnLnBhY2tldHMuZmlsdGVyQnlUYWcoZW51bXMucGFja2V0Lm9uZV9wYXNzX3NpZ25hdHVyZSk7XG4gIG9uZVBhc3NTaWdMaXN0LmZvckVhY2goZnVuY3Rpb24ocGFja2V0KSB7XG4gICAga2V5SWRzLnB1c2gocGFja2V0LnNpZ25pbmdLZXlJZCk7XG4gIH0pO1xuICAvLyBpZiBub3RoaW5nIGZvdW5kIGxvb2sgZm9yIHNpZ25hdHVyZSBwYWNrZXRzXG4gIGlmICgha2V5SWRzLmxlbmd0aCkge1xuICAgIHZhciBzaWduYXR1cmVMaXN0ID0gbXNnLnBhY2tldHMuZmlsdGVyQnlUYWcoZW51bXMucGFja2V0LnNpZ25hdHVyZSk7XG4gICAgc2lnbmF0dXJlTGlzdC5mb3JFYWNoKGZ1bmN0aW9uKHBhY2tldCkge1xuICAgICAga2V5SWRzLnB1c2gocGFja2V0Lmlzc3VlcktleUlkKTtcbiAgICB9KTtcbiAgfVxuICByZXR1cm4ga2V5SWRzO1xufTtcblxuLyoqXG4gKiBEZWNyeXB0IHRoZSBtZXNzYWdlXG4gKiBAcGFyYW0ge2tleX0gcHJpdmF0ZUtleSBwcml2YXRlIGtleSB3aXRoIGRlY3J5cHRlZCBzZWNyZXQgZGF0YSAgICAgICAgICAgXG4gKiBAcmV0dXJuIHtbbWVzc2FnZV19IG5ldyBtZXNzYWdlIHdpdGggZGVjcnlwdGVkIGNvbnRlbnRcbiAqL1xuTWVzc2FnZS5wcm90b3R5cGUuZGVjcnlwdCA9IGZ1bmN0aW9uKHByaXZhdGVLZXkpIHtcbiAgdmFyIGVuY3J5cHRpb25LZXlJZHMgPSB0aGlzLmdldEVuY3J5cHRpb25LZXlJZHMoKTtcbiAgaWYgKCFlbmNyeXB0aW9uS2V5SWRzLmxlbmd0aCkge1xuICAgIC8vIG5vdGhpbmcgdG8gZGVjcnlwdCByZXR1cm4gdW5tb2RpZmllZCBtZXNzYWdlXG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbiAgdmFyIHByaXZhdGVLZXlQYWNrZXQgPSBwcml2YXRlS2V5LmdldFByaXZhdGVLZXlQYWNrZXQoZW5jcnlwdGlvbktleUlkcyk7XG4gIGlmICghcHJpdmF0ZUtleVBhY2tldC5pc0RlY3J5cHRlZCkgdGhyb3cgbmV3IEVycm9yKCdQcml2YXRlIGtleSBpcyBub3QgZGVjcnlwdGVkLicpO1xuICB2YXIgcGtFU0tleVBhY2tldGxpc3QgPSB0aGlzLnBhY2tldHMuZmlsdGVyQnlUYWcoZW51bXMucGFja2V0LnB1YmxpY19rZXlfZW5jcnlwdGVkX3Nlc3Npb25fa2V5KTtcbiAgdmFyIHBrRVNLZXlQYWNrZXQ7XG4gIGZvciAodmFyIGkgPSAwOyBpIDwgcGtFU0tleVBhY2tldGxpc3QubGVuZ3RoOyBpKyspIHtcbiAgICBpZiAocGtFU0tleVBhY2tldGxpc3RbaV0ucHVibGljS2V5SWQuZXF1YWxzKHByaXZhdGVLZXlQYWNrZXQuZ2V0S2V5SWQoKSkpIHtcbiAgICAgIHBrRVNLZXlQYWNrZXQgPSBwa0VTS2V5UGFja2V0bGlzdFtpXTtcbiAgICAgIHBrRVNLZXlQYWNrZXQuZGVjcnlwdChwcml2YXRlS2V5UGFja2V0KTtcbiAgICAgIGJyZWFrO1xuICAgIH1cbiAgfVxuICBpZiAocGtFU0tleVBhY2tldCkge1xuICAgIHZhciBzeW1FbmNyeXB0ZWRQYWNrZXRsaXN0ID0gdGhpcy5wYWNrZXRzLmZpbHRlckJ5VGFnKGVudW1zLnBhY2tldC5zeW1tZXRyaWNhbGx5X2VuY3J5cHRlZCwgZW51bXMucGFja2V0LnN5bV9lbmNyeXB0ZWRfaW50ZWdyaXR5X3Byb3RlY3RlZCk7XG4gICAgaWYgKHN5bUVuY3J5cHRlZFBhY2tldGxpc3QubGVuZ3RoICE9PSAwKSB7XG4gICAgICB2YXIgc3ltRW5jcnlwdGVkUGFja2V0ID0gc3ltRW5jcnlwdGVkUGFja2V0bGlzdFswXTtcbiAgICAgIHN5bUVuY3J5cHRlZFBhY2tldC5kZWNyeXB0KHBrRVNLZXlQYWNrZXQuc2Vzc2lvbktleUFsZ29yaXRobSwgcGtFU0tleVBhY2tldC5zZXNzaW9uS2V5KTtcbiAgICAgIHJldHVybiBuZXcgTWVzc2FnZShzeW1FbmNyeXB0ZWRQYWNrZXQucGFja2V0cyk7XG4gICAgfVxuICB9XG59O1xuXG4vKipcbiAqIEdldCBsaXRlcmFsIGRhdGEgdGhhdCBpcyB0aGUgYm9keSBvZiB0aGUgbWVzc2FnZVxuICogQHJldHVybiB7U3RyaW5nfG51bGx9IGxpdGVyYWwgYm9keSBvZiB0aGUgbWVzc2FnZSBhcyBzdHJpbmdcbiAqL1xuTWVzc2FnZS5wcm90b3R5cGUuZ2V0TGl0ZXJhbERhdGEgPSBmdW5jdGlvbigpIHtcbiAgdmFyIGxpdGVyYWwgPSB0aGlzLnBhY2tldHMuZmluZFBhY2tldChlbnVtcy5wYWNrZXQubGl0ZXJhbCk7XG4gIHJldHVybiBsaXRlcmFsICYmIGxpdGVyYWwuZGF0YSB8fCBudWxsO1xufTtcblxuLyoqXG4gKiBHZXQgbGl0ZXJhbCBkYXRhIGFzIHRleHRcbiAqIEByZXR1cm4ge1N0cmluZ3xudWxsfSBsaXRlcmFsIGJvZHkgb2YgdGhlIG1lc3NhZ2UgaW50ZXJwcmV0ZWQgYXMgdGV4dFxuICovXG5NZXNzYWdlLnByb3RvdHlwZS5nZXRUZXh0ID0gZnVuY3Rpb24oKSB7XG4gIHZhciBsaXRlcmFsID0gdGhpcy5wYWNrZXRzLmZpbmRQYWNrZXQoZW51bXMucGFja2V0LmxpdGVyYWwpO1xuICBpZiAobGl0ZXJhbCkge1xuICAgIHJldHVybiBsaXRlcmFsLmdldFRleHQoKTtcbiAgfSBlbHNlIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxufTtcblxuLyoqXG4gKiBFbmNyeXB0IHRoZSBtZXNzYWdlXG4gKiBAcGFyYW0gIHtba2V5XX0ga2V5cyBhcnJheSBvZiBrZXlzLCB1c2VkIHRvIGVuY3J5cHQgdGhlIG1lc3NhZ2VcbiAqIEByZXR1cm4ge1ttZXNzYWdlXX0gbmV3IG1lc3NhZ2Ugd2l0aCBlbmNyeXB0ZWQgY29udGVudFxuICovXG5NZXNzYWdlLnByb3RvdHlwZS5lbmNyeXB0ID0gZnVuY3Rpb24oa2V5cykge1xuICB2YXIgcGFja2V0bGlzdCA9IG5ldyBwYWNrZXQubGlzdCgpO1xuICAvL1RPRE8gZ2V0IHByZWZlcnJlZCBhbGdvIGZyb20gc2lnbmF0dXJlXG4gIHZhciBzZXNzaW9uS2V5ID0gY3J5cHRvLmdlbmVyYXRlU2Vzc2lvbktleShlbnVtcy5yZWFkKGVudW1zLnN5bW1ldHJpYywgY29uZmlnLmVuY3J5cHRpb25fY2lwaGVyKSk7XG4gIGtleXMuZm9yRWFjaChmdW5jdGlvbihrZXkpIHtcbiAgICB2YXIgZW5jcnlwdGlvbktleVBhY2tldCA9IGtleS5nZXRFbmNyeXB0aW9uS2V5UGFja2V0KCk7XG4gICAgaWYgKGVuY3J5cHRpb25LZXlQYWNrZXQpIHtcbiAgICAgIHZhciBwa0VTS2V5UGFja2V0ID0gbmV3IHBhY2tldC5wdWJsaWNfa2V5X2VuY3J5cHRlZF9zZXNzaW9uX2tleSgpO1xuICAgICAgcGtFU0tleVBhY2tldC5wdWJsaWNLZXlJZCA9IGVuY3J5cHRpb25LZXlQYWNrZXQuZ2V0S2V5SWQoKTtcbiAgICAgIHBrRVNLZXlQYWNrZXQucHVibGljS2V5QWxnb3JpdGhtID0gZW5jcnlwdGlvbktleVBhY2tldC5hbGdvcml0aG07XG4gICAgICBwa0VTS2V5UGFja2V0LnNlc3Npb25LZXkgPSBzZXNzaW9uS2V5O1xuICAgICAgLy9UT0RPIGdldCBwcmVmZXJyZWQgYWxnbyBmcm9tIHNpZ25hdHVyZVxuICAgICAgcGtFU0tleVBhY2tldC5zZXNzaW9uS2V5QWxnb3JpdGhtID0gZW51bXMucmVhZChlbnVtcy5zeW1tZXRyaWMsIGNvbmZpZy5lbmNyeXB0aW9uX2NpcGhlcik7XG4gICAgICBwa0VTS2V5UGFja2V0LmVuY3J5cHQoZW5jcnlwdGlvbktleVBhY2tldCk7XG4gICAgICBwYWNrZXRsaXN0LnB1c2gocGtFU0tleVBhY2tldCk7XG4gICAgfVxuICB9KTtcbiAgdmFyIHN5bUVuY3J5cHRlZFBhY2tldDtcbiAgaWYgKGNvbmZpZy5pbnRlZ3JpdHlfcHJvdGVjdCkge1xuICAgIHN5bUVuY3J5cHRlZFBhY2tldCA9IG5ldyBwYWNrZXQuc3ltX2VuY3J5cHRlZF9pbnRlZ3JpdHlfcHJvdGVjdGVkKCk7XG4gIH0gZWxzZSB7XG4gICAgc3ltRW5jcnlwdGVkUGFja2V0ID0gbmV3IHBhY2tldC5zeW1tZXRyaWNhbGx5X2VuY3J5cHRlZCgpO1xuICB9XG4gIHN5bUVuY3J5cHRlZFBhY2tldC5wYWNrZXRzID0gdGhpcy5wYWNrZXRzO1xuICAvL1RPRE8gZ2V0IHByZWZlcnJlZCBhbGdvIGZyb20gc2lnbmF0dXJlXG4gIHN5bUVuY3J5cHRlZFBhY2tldC5lbmNyeXB0KGVudW1zLnJlYWQoZW51bXMuc3ltbWV0cmljLCBjb25maWcuZW5jcnlwdGlvbl9jaXBoZXIpLCBzZXNzaW9uS2V5KTtcbiAgcGFja2V0bGlzdC5wdXNoKHN5bUVuY3J5cHRlZFBhY2tldCk7XG4gIHJldHVybiBuZXcgTWVzc2FnZShwYWNrZXRsaXN0KTtcbn07XG5cbi8qKlxuICogU2lnbiB0aGUgbWVzc2FnZSAodGhlIGxpdGVyYWwgZGF0YSBwYWNrZXQgb2YgdGhlIG1lc3NhZ2UpXG4gKiBAcGFyYW0gIHtba2V5XX0gcHJpdmF0ZUtleSBwcml2YXRlIGtleXMgd2l0aCBkZWNyeXB0ZWQgc2VjcmV0IGtleSBkYXRhIGZvciBzaWduaW5nXG4gKiBAcmV0dXJuIHttZXNzYWdlfSAgICAgIG5ldyBtZXNzYWdlIHdpdGggc2lnbmVkIGNvbnRlbnRcbiAqL1xuTWVzc2FnZS5wcm90b3R5cGUuc2lnbiA9IGZ1bmN0aW9uKHByaXZhdGVLZXlzKSB7XG5cbiAgdmFyIHBhY2tldGxpc3QgPSBuZXcgcGFja2V0Lmxpc3QoKTtcblxuICB2YXIgbGl0ZXJhbERhdGFQYWNrZXQgPSB0aGlzLnBhY2tldHMuZmluZFBhY2tldChlbnVtcy5wYWNrZXQubGl0ZXJhbCk7XG4gIGlmICghbGl0ZXJhbERhdGFQYWNrZXQpIHRocm93IG5ldyBFcnJvcignTm8gbGl0ZXJhbCBkYXRhIHBhY2tldCB0byBzaWduLicpO1xuICBcbiAgdmFyIGxpdGVyYWxGb3JtYXQgPSBlbnVtcy53cml0ZShlbnVtcy5saXRlcmFsLCBsaXRlcmFsRGF0YVBhY2tldC5mb3JtYXQpO1xuICB2YXIgc2lnbmF0dXJlVHlwZSA9IGxpdGVyYWxGb3JtYXQgPT0gZW51bXMubGl0ZXJhbC5iaW5hcnkgXG4gICAgICAgICAgICAgICAgICAgICAgPyBlbnVtcy5zaWduYXR1cmUuYmluYXJ5IDogZW51bXMuc2lnbmF0dXJlLnRleHQ7IFxuICBcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBwcml2YXRlS2V5cy5sZW5ndGg7IGkrKykge1xuICAgIHZhciBvbmVQYXNzU2lnID0gbmV3IHBhY2tldC5vbmVfcGFzc19zaWduYXR1cmUoKTtcbiAgICBvbmVQYXNzU2lnLnR5cGUgPSBzaWduYXR1cmVUeXBlO1xuICAgIC8vVE9ETyBnZXQgcHJlZmVycmVkIGhhc2hnIGFsZ28gZnJvbSBrZXkgc2lnbmF0dXJlXG4gICAgb25lUGFzc1NpZy5oYXNoQWxnb3JpdGhtID0gY29uZmlnLnByZWZlcl9oYXNoX2FsZ29yaXRobTtcbiAgICB2YXIgc2lnbmluZ0tleVBhY2tldCA9IHByaXZhdGVLZXlzW2ldLmdldFNpZ25pbmdLZXlQYWNrZXQoKTtcbiAgICBvbmVQYXNzU2lnLnB1YmxpY0tleUFsZ29yaXRobSA9IHNpZ25pbmdLZXlQYWNrZXQuYWxnb3JpdGhtO1xuICAgIG9uZVBhc3NTaWcuc2lnbmluZ0tleUlkID0gc2lnbmluZ0tleVBhY2tldC5nZXRLZXlJZCgpO1xuICAgIHBhY2tldGxpc3QucHVzaChvbmVQYXNzU2lnKTtcbiAgfVxuXG4gIHBhY2tldGxpc3QucHVzaChsaXRlcmFsRGF0YVBhY2tldCk7XG4gIFxuICBmb3IgKHZhciBpID0gcHJpdmF0ZUtleXMubGVuZ3RoIC0gMTsgaSA+PSAwOyBpLS0pIHtcbiAgICB2YXIgc2lnbmF0dXJlUGFja2V0ID0gbmV3IHBhY2tldC5zaWduYXR1cmUoKTtcbiAgICBzaWduYXR1cmVQYWNrZXQuc2lnbmF0dXJlVHlwZSA9IHNpZ25hdHVyZVR5cGU7XG4gICAgc2lnbmF0dXJlUGFja2V0Lmhhc2hBbGdvcml0aG0gPSBjb25maWcucHJlZmVyX2hhc2hfYWxnb3JpdGhtO1xuICAgIHNpZ25hdHVyZVBhY2tldC5wdWJsaWNLZXlBbGdvcml0aG0gPSBzaWduaW5nS2V5UGFja2V0LmFsZ29yaXRobTtcbiAgICBpZiAoIXNpZ25pbmdLZXlQYWNrZXQuaXNEZWNyeXB0ZWQpIHRocm93IG5ldyBFcnJvcignUHJpdmF0ZSBrZXkgaXMgbm90IGRlY3J5cHRlZC4nKTtcbiAgICBzaWduYXR1cmVQYWNrZXQuc2lnbihzaWduaW5nS2V5UGFja2V0LCBsaXRlcmFsRGF0YVBhY2tldCk7XG4gICAgcGFja2V0bGlzdC5wdXNoKHNpZ25hdHVyZVBhY2tldCk7XG4gIH1cblxuICByZXR1cm4gbmV3IE1lc3NhZ2UocGFja2V0bGlzdCk7XG59O1xuXG4vKipcbiAqIFZlcmlmeSBtZXNzYWdlIHNpZ25hdHVyZXNcbiAqIEBwYXJhbSB7W2tleV19IHB1YmxpY0tleXMgcHVibGljIGtleXMgdG8gdmVyaWZ5IHNpZ25hdHVyZXNcbiAqIEByZXR1cm4ge1t7J2tleWlkJzoga2V5aWQsICd2YWxpZCc6IEJvb2xlYW59XX0gbGlzdCBvZiBzaWduZXIncyBrZXlpZCBhbmQgdmFsaWRpdHkgb2Ygc2lnbmF0dXJlXG4gKi9cbk1lc3NhZ2UucHJvdG90eXBlLnZlcmlmeSA9IGZ1bmN0aW9uKHB1YmxpY0tleXMpIHtcbiAgdmFyIHJlc3VsdCA9IFtdO1xuICB2YXIgbXNnID0gdGhpcy51bndyYXBDb21wcmVzc2VkKCk7XG4gIHZhciBsaXRlcmFsRGF0YUxpc3QgPSBtc2cucGFja2V0cy5maWx0ZXJCeVRhZyhlbnVtcy5wYWNrZXQubGl0ZXJhbCk7XG4gIGlmIChsaXRlcmFsRGF0YUxpc3QubGVuZ3RoICE9PSAxKSB0aHJvdyBuZXcgRXJyb3IoJ0NhbiBvbmx5IHZlcmlmeSBtZXNzYWdlIHdpdGggb25lIGxpdGVyYWwgZGF0YSBwYWNrZXQuJyk7XG4gIHZhciBzaWduYXR1cmVMaXN0ID0gbXNnLnBhY2tldHMuZmlsdGVyQnlUYWcoZW51bXMucGFja2V0LnNpZ25hdHVyZSk7XG4gIHB1YmxpY0tleXMuZm9yRWFjaChmdW5jdGlvbihwdWJLZXkpIHtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHNpZ25hdHVyZUxpc3QubGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciBwdWJsaWNLZXlQYWNrZXQgPSBwdWJLZXkuZ2V0UHVibGljS2V5UGFja2V0KFtzaWduYXR1cmVMaXN0W2ldLmlzc3VlcktleUlkXSk7XG4gICAgICBpZiAocHVibGljS2V5UGFja2V0KSB7XG4gICAgICAgIHZhciB2ZXJpZmllZFNpZyA9IHt9O1xuICAgICAgICB2ZXJpZmllZFNpZy5rZXlpZCA9IHNpZ25hdHVyZUxpc3RbaV0uaXNzdWVyS2V5SWQ7XG4gICAgICAgIHZlcmlmaWVkU2lnLnN0YXR1cyA9IHNpZ25hdHVyZUxpc3RbaV0udmVyaWZ5KHB1YmxpY0tleVBhY2tldCwgbGl0ZXJhbERhdGFMaXN0WzBdKTtcbiAgICAgICAgcmVzdWx0LnB1c2godmVyaWZpZWRTaWcpO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9XG4gIH0pO1xuICByZXR1cm4gcmVzdWx0O1xufTtcblxuLyoqXG4gKiBVbndyYXAgY29tcHJlc3NlZCBtZXNzYWdlXG4gKiBAcmV0dXJuIHttZXNzYWdlfSBtZXNzYWdlIENvbnRlbnQgb2YgY29tcHJlc3NlZCBtZXNzYWdlXG4gKi9cbk1lc3NhZ2UucHJvdG90eXBlLnVud3JhcENvbXByZXNzZWQgPSBmdW5jdGlvbigpIHtcbiAgdmFyIGNvbXByZXNzZWQgPSB0aGlzLnBhY2tldHMuZmlsdGVyQnlUYWcoZW51bXMucGFja2V0LmNvbXByZXNzZWQpO1xuICBpZiAoY29tcHJlc3NlZC5sZW5ndGgpIHtcbiAgICByZXR1cm4gbmV3IE1lc3NhZ2UoY29tcHJlc3NlZFswXS5wYWNrZXRzKTtcbiAgfSBlbHNlIHtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxufTtcblxuLyoqXG4gKiBSZXR1cm5zIEFTQ0lJIGFybW9yZWQgdGV4dCBvZiBtZXNzYWdlXG4gKiBAcmV0dXJuIHtTdHJpbmd9IEFTQ0lJIGFybW9yXG4gKi9cbk1lc3NhZ2UucHJvdG90eXBlLmFybW9yID0gZnVuY3Rpb24oKSB7XG4gIHJldHVybiBhcm1vci5lbmNvZGUoZW51bXMuYXJtb3IubWVzc2FnZSwgdGhpcy5wYWNrZXRzLndyaXRlKCkpO1xufTtcblxuLyoqXG4gKiByZWFkcyBhbiBPcGVuUEdQIGFybW9yZWQgbWVzc2FnZSBhbmQgcmV0dXJucyBhIG1lc3NhZ2Ugb2JqZWN0XG4gKiBAcGFyYW0ge1N0cmluZ30gYXJtb3JlZFRleHQgdGV4dCB0byBiZSBwYXJzZWRcbiAqIEByZXR1cm4ge21lc3NhZ2V9IG5ldyBtZXNzYWdlIG9iamVjdFxuICovXG5mdW5jdGlvbiByZWFkQXJtb3JlZChhcm1vcmVkVGV4dCkge1xuICAvL1RPRE8gaG93IGRvIHdlIHdhbnQgdG8gaGFuZGxlIGJhZCB0ZXh0PyBFeGNlcHRpb24gdGhyb3dpbmdcbiAgLy9UT0RPIGRvbid0IGFjY2VwdCBub24tbWVzc2FnZSBhcm1vcmVkIHRleHRzXG4gIHZhciBpbnB1dCA9IGFybW9yLmRlY29kZShhcm1vcmVkVGV4dCkuZGF0YTtcbiAgdmFyIHBhY2tldGxpc3QgPSBuZXcgcGFja2V0Lmxpc3QoKTtcbiAgcGFja2V0bGlzdC5yZWFkKGlucHV0KTtcbiAgdmFyIG5ld01lc3NhZ2UgPSBuZXcgTWVzc2FnZShwYWNrZXRsaXN0KTtcbiAgcmV0dXJuIG5ld01lc3NhZ2U7XG59XG5cbi8qKlxuICogY3JlYXRlcyBuZXcgbWVzc2FnZSBvYmplY3QgZnJvbSB0ZXh0XG4gKiBAcGFyYW0ge1N0cmluZ30gdGV4dFxuICogQHJldHVybiB7bWVzc2FnZX0gbmV3IG1lc3NhZ2Ugb2JqZWN0XG4gKi9cbmZ1bmN0aW9uIGZyb21UZXh0KHRleHQpIHtcbiAgdmFyIGxpdGVyYWxEYXRhUGFja2V0ID0gbmV3IHBhY2tldC5saXRlcmFsKCk7XG4gIC8vIHRleHQgd2lsbCBiZSBjb252ZXJ0ZWQgdG8gVVRGOFxuICBsaXRlcmFsRGF0YVBhY2tldC5zZXRUZXh0KHRleHQpO1xuICB2YXIgbGl0ZXJhbERhdGFQYWNrZXRsaXN0ID0gbmV3IHBhY2tldC5saXN0KCk7XG4gIGxpdGVyYWxEYXRhUGFja2V0bGlzdC5wdXNoKGxpdGVyYWxEYXRhUGFja2V0KTtcbiAgdmFyIG5ld01lc3NhZ2UgPSBuZXcgTWVzc2FnZShsaXRlcmFsRGF0YVBhY2tldGxpc3QpO1xuICByZXR1cm4gbmV3TWVzc2FnZTtcbn1cblxuLyoqXG4gKiBjcmVhdGVzIG5ldyBtZXNzYWdlIG9iamVjdCBmcm9tIGJpbmFyeSBkYXRhXG4gKiBAcGFyYW0ge1N0cmluZ30gYnl0ZXNcbiAqIEByZXR1cm4ge21lc3NhZ2V9IG5ldyBtZXNzYWdlIG9iamVjdFxuICovXG5mdW5jdGlvbiBmcm9tQmluYXJ5KGJ5dGVzKSB7XG4gIHZhciBsaXRlcmFsRGF0YVBhY2tldCA9IG5ldyBwYWNrZXQubGl0ZXJhbCgpO1xuICBsaXRlcmFsRGF0YVBhY2tldC5zZXRCeXRlcyhieXRlcywgZW51bXMucmVhZChlbnVtcy5saXRlcmFsLCBlbnVtcy5saXRlcmFsLmJpbmFyeSkpO1xuICB2YXIgbGl0ZXJhbERhdGFQYWNrZXRsaXN0ID0gbmV3IHBhY2tldC5saXN0KCk7XG4gIGxpdGVyYWxEYXRhUGFja2V0bGlzdC5wdXNoKGxpdGVyYWxEYXRhUGFja2V0KTtcbiAgdmFyIG5ld01lc3NhZ2UgPSBuZXcgTWVzc2FnZShsaXRlcmFsRGF0YVBhY2tldGxpc3QpO1xuICByZXR1cm4gbmV3TWVzc2FnZTtcbn1cblxuZXhwb3J0cy5NZXNzYWdlID0gTWVzc2FnZTtcbmV4cG9ydHMucmVhZEFybW9yZWQgPSByZWFkQXJtb3JlZDtcbmV4cG9ydHMuZnJvbVRleHQgPSBmcm9tVGV4dDtcbiIsIi8vIEdQRzRCcm93c2VycyAtIEFuIE9wZW5QR1AgaW1wbGVtZW50YXRpb24gaW4gamF2YXNjcmlwdFxuLy8gQ29weXJpZ2h0IChDKSAyMDExIFJlY3VyaXR5IExhYnMgR21iSFxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yXG4vLyBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uOyBlaXRoZXJcbi8vIHZlcnNpb24gMi4xIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbi8vIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4vLyBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlIEdOVVxuLy8gTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cbi8vIFxuLy8gWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhbG9uZyB3aXRoIHRoaXMgbGlicmFyeTsgaWYgbm90LCB3cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZVxuLy8gRm91bmRhdGlvbiwgSW5jLiwgNTEgRnJhbmtsaW4gU3RyZWV0LCBGaWZ0aCBGbG9vciwgQm9zdG9uLCBNQSAgMDIxMTAtMTMwMSAgVVNBXG5cbi8qKlxuICogQGZpbGVvdmVydmlldyBUaGUgb3BlbnBncCBiYXNlIG1vZHVsZSBzaG91bGQgcHJvdmlkZSBhbGwgb2YgdGhlIGZ1bmN0aW9uYWxpdHkgXG4gKiB0byBjb25zdW1lIHRoZSBvcGVucGdwLmpzIGxpYnJhcnkuIEFsbCBhZGRpdGlvbmFsIGNsYXNzZXMgYXJlIGRvY3VtZW50ZWQgXG4gKiBmb3IgZXh0ZW5kaW5nIGFuZCBkZXZlbG9waW5nIG9uIHRvcCBvZiB0aGUgYmFzZSBsaWJyYXJ5LlxuICovXG5cbnZhciBhcm1vciA9IHJlcXVpcmUoJy4vZW5jb2RpbmcvYXJtb3IuanMnKTtcbnZhciBwYWNrZXQgPSByZXF1aXJlKCcuL3BhY2tldCcpO1xudmFyIGVudW1zID0gcmVxdWlyZSgnLi9lbnVtcy5qcycpO1xudmFyIGNvbmZpZyA9IHJlcXVpcmUoJy4vY29uZmlnJyk7XG52YXIgbWVzc2FnZSA9IHJlcXVpcmUoJy4vbWVzc2FnZS5qcycpO1xudmFyIGNsZWFydGV4dCA9IHJlcXVpcmUoJy4vY2xlYXJ0ZXh0LmpzJyk7XG52YXIga2V5ID0gcmVxdWlyZSgnLi9rZXkuanMnKTtcblxuXG4vKipcbiAqIEVuY3J5cHRzIG1lc3NhZ2UgdGV4dCB3aXRoIGtleXNcbiAqIEBwYXJhbSAge1trZXldfSAga2V5cyBhcnJheSBvZiBrZXlzLCB1c2VkIHRvIGVuY3J5cHQgdGhlIG1lc3NhZ2VcbiAqIEBwYXJhbSAge1N0cmluZ30gdGV4dCBtZXNzYWdlIGFzIG5hdGl2ZSBKYXZhU2NyaXB0IHN0cmluZ1xuICogQHJldHVybiB7U3RyaW5nfSAgICAgIGVuY3J5cHRlZCBBU0NJSSBhcm1vcmVkIG1lc3NhZ2VcbiAqL1xuZnVuY3Rpb24gZW5jcnlwdE1lc3NhZ2Uoa2V5cywgdGV4dCkge1xuICB2YXIgbXNnID0gbWVzc2FnZS5mcm9tVGV4dCh0ZXh0KTtcbiAgbXNnID0gbXNnLmVuY3J5cHQoa2V5cyk7XG4gIHZhciBhcm1vcmVkID0gYXJtb3IuZW5jb2RlKGVudW1zLmFybW9yLm1lc3NhZ2UsIG1zZy5wYWNrZXRzLndyaXRlKCkpO1xuICByZXR1cm4gYXJtb3JlZDtcbn1cblxuLyoqXG4gKiBTaWducyBtZXNzYWdlIHRleHQgYW5kIGVuY3J5cHRzIGl0XG4gKiBAcGFyYW0gIHtba2V5XX0gIHB1YmxpY0tleXMgYXJyYXkgb2Yga2V5cywgdXNlZCB0byBlbmNyeXB0IHRoZSBtZXNzYWdlXG4gKiBAcGFyYW0gIHtrZXl9ICAgIHByaXZhdGVLZXkgcHJpdmF0ZSBrZXkgd2l0aCBkZWNyeXB0ZWQgc2VjcmV0IGtleSBkYXRhIGZvciBzaWduaW5nXG4gKiBAcGFyYW0gIHtTdHJpbmd9IHRleHQgICAgICAgbWVzc2FnZSBhcyBuYXRpdmUgSmF2YVNjcmlwdCBzdHJpbmdcbiAqIEByZXR1cm4ge1N0cmluZ30gICAgICAgICAgICBlbmNyeXB0ZWQgQVNDSUkgYXJtb3JlZCBtZXNzYWdlXG4gKi9cbmZ1bmN0aW9uIHNpZ25BbmRFbmNyeXB0TWVzc2FnZShwdWJsaWNLZXlzLCBwcml2YXRlS2V5LCB0ZXh0KSB7XG4gIHZhciBtc2cgPSBtZXNzYWdlLmZyb21UZXh0KHRleHQpO1xuICBtc2cgPSBtc2cuc2lnbihbcHJpdmF0ZUtleV0pO1xuICBtc2cgPSBtc2cuZW5jcnlwdChwdWJsaWNLZXlzKTtcbiAgdmFyIGFybW9yZWQgPSBhcm1vci5lbmNvZGUoZW51bXMuYXJtb3IubWVzc2FnZSwgbXNnLnBhY2tldHMud3JpdGUoKSk7XG4gIHJldHVybiBhcm1vcmVkO1xufVxuXG4vKipcbiAqIERlY3J5cHRzIG1lc3NhZ2VcbiAqIEBwYXJhbSAge2tleX0gICAgIHByaXZhdGVLZXkgcHJpdmF0ZSBrZXkgd2l0aCBkZWNyeXB0ZWQgc2VjcmV0IGtleSBkYXRhXG4gKiBAcGFyYW0gIHttZXNzYWdlfSBtZXNzYWdlICAgIHRoZSBtZXNzYWdlIG9iamVjdCB3aXRoIHRoZSBlbmNyeXB0ZWQgZGF0YVxuICogQHJldHVybiB7U3RyaW5nfG51bGx9ICAgICAgICBkZWNyeXB0ZWQgbWVzc2FnZSBhcyBhcyBuYXRpdmUgSmF2YVNjcmlwdCBzdHJpbmdcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3IgbnVsbCBpZiBubyBsaXRlcmFsIGRhdGEgZm91bmRcbiAqL1xuZnVuY3Rpb24gZGVjcnlwdE1lc3NhZ2UocHJpdmF0ZUtleSwgbWVzc2FnZSkge1xuICBtZXNzYWdlID0gbWVzc2FnZS5kZWNyeXB0KHByaXZhdGVLZXkpO1xuICByZXR1cm4gbWVzc2FnZS5nZXRUZXh0KCk7XG59XG5cbi8qKlxuICogRGVjcnlwdHMgbWVzc2FnZSBhbmQgdmVyaWZpZXMgc2lnbmF0dXJlc1xuICogQHBhcmFtICB7a2V5fSAgICAgcHJpdmF0ZUtleSBwcml2YXRlIGtleSB3aXRoIGRlY3J5cHRlZCBzZWNyZXQga2V5IGRhdGFcbiAqIEBwYXJhbSAge1trZXldfSAgIHB1YmxpY0tleXMgcHVibGljIGtleXMgdG8gdmVyaWZ5IHNpZ25hdHVyZXNcbiAqIEBwYXJhbSAge21lc3NhZ2V9IG1lc3NhZ2UgICAgdGhlIG1lc3NhZ2Ugb2JqZWN0IHdpdGggc2lnbmVkIGFuZCBlbmNyeXB0ZWQgZGF0YVxuICogQHJldHVybiB7eyd0ZXh0JzogU3RyaW5nLCBzaWduYXR1cmVzOiBbeydrZXlpZCc6IGtleWlkLCAnc3RhdHVzJzogQm9vbGVhbn1dfX1cbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVjcnlwdGVkIG1lc3NhZ2UgYXMgYXMgbmF0aXZlIEphdmFTY3JpcHQgc3RyaW5nXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdpdGggdmVyaWZpZWQgc2lnbmF0dXJlcyBvciBudWxsIGlmIG5vIGxpdGVyYWwgZGF0YSBmb3VuZFxuICovXG5mdW5jdGlvbiBkZWNyeXB0QW5kVmVyaWZ5TWVzc2FnZShwcml2YXRlS2V5LCBwdWJsaWNLZXlzLCBtZXNzYWdlKSB7XG4gIHZhciByZXN1bHQgPSB7fTtcbiAgbWVzc2FnZSA9IG1lc3NhZ2UuZGVjcnlwdChwcml2YXRlS2V5KTtcbiAgcmVzdWx0LnRleHQgPSBtZXNzYWdlLmdldFRleHQoKTtcbiAgaWYgKHJlc3VsdC50ZXh0KSB7XG4gICAgcmVzdWx0LnNpZ25hdHVyZXMgPSBtZXNzYWdlLnZlcmlmeShwdWJsaWNLZXlzKTtcbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG4gIHJldHVybiBudWxsO1xufVxuXG4vKipcbiAqIFNpZ25zIGEgY2xlYXJ0ZXh0IG1lc3NhZ2VcbiAqIEBwYXJhbSAge1tLZXldfSAgcHJpdmF0ZUtleXMgcHJpdmF0ZSBrZXkgd2l0aCBkZWNyeXB0ZWQgc2VjcmV0IGtleSBkYXRhIHRvIHNpZ24gY2xlYXJ0ZXh0XG4gKiBAcGFyYW0gIHtTdHJpbmd9IHRleHQgICAgICAgIGNsZWFydGV4dFxuICogQHJldHVybiB7U3RyaW5nfSAgICAgICAgICAgICBBU0NJSSBhcm1vcmVkIG1lc3NhZ2VcbiAqL1xuZnVuY3Rpb24gc2lnbkNsZWFyTWVzc2FnZShwcml2YXRlS2V5cywgdGV4dCkge1xuICB2YXIgY2xlYXJ0ZXh0TWVzc2FnZSA9IG5ldyBjbGVhcnRleHQuQ2xlYXJ0ZXh0TWVzc2FnZSh0ZXh0KTtcbiAgY2xlYXJ0ZXh0TWVzc2FnZS5zaWduKHByaXZhdGVLZXlzKTtcbiAgcmV0dXJuIGNsZWFydGV4dE1lc3NhZ2UuYXJtb3IoKTtcbn1cblxuLyoqXG4gKiBWZXJpZmllcyBzaWduYXR1cmVzIG9mIGNsZWFydGV4dCBzaWduZWQgbWVzc2FnZVxuICogQHBhcmFtICB7W0tleV19ICAgICAgICAgICAgcHVibGljS2V5cyBwdWJsaWMga2V5cyB0byB2ZXJpZnkgc2lnbmF0dXJlc1xuICogQHBhcmFtICB7Q2xlYXJ0ZXh0TWVzc2FnZX0gbWVzc2FnZSAgICBjbGVhcnRleHQgbWVzc2FnZSBvYmplY3Qgd2l0aCBzaWduYXR1cmVzXG4gKiBAcmV0dXJuIHt7J3RleHQnOiBTdHJpbmcsIHNpZ25hdHVyZXM6IFt7J2tleWlkJzoga2V5aWQsICdzdGF0dXMnOiBCb29sZWFufV19fVxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbGVhcnRleHQgd2l0aCBzdGF0dXMgb2YgdmVyaWZpZWQgc2lnbmF0dXJlc1xuICovXG5mdW5jdGlvbiB2ZXJpZnlDbGVhclNpZ25lZE1lc3NhZ2UocHVibGljS2V5cywgbWVzc2FnZSkge1xuICB2YXIgcmVzdWx0ID0ge307XG4gIGlmICghKG1lc3NhZ2UgaW5zdGFuY2VvZiBjbGVhcnRleHQuQ2xlYXJ0ZXh0TWVzc2FnZSkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ1BhcmFtZXRlciBbbWVzc2FnZV0gbmVlZHMgdG8gYmUgb2YgdHlwZSBDbGVhcnRleHRNZXNzYWdlLicpO1xuICB9XG4gIHJlc3VsdC50ZXh0ID0gbWVzc2FnZS5nZXRUZXh0KCk7XG4gIHJlc3VsdC5zaWduYXR1cmVzID0gbWVzc2FnZS52ZXJpZnkocHVibGljS2V5cyk7XG4gIHJldHVybiByZXN1bHQ7XG59XG5cbi8qKlxuICogR2VuZXJhdGVzIGEgbmV3IE9wZW5QR1Aga2V5IHBhaXIuIEN1cnJlbnRseSBvbmx5IHN1cHBvcnRzIFJTQSBrZXlzLlxuICogUHJpbWFyeSBhbmQgc3Via2V5IHdpbGwgYmUgb2Ygc2FtZSB0eXBlLlxuICogQHBhcmFtIHtJbnRlZ2VyfSBrZXlUeXBlICAgIHRvIGluZGljYXRlIHdoYXQgdHlwZSBvZiBrZXkgdG8gbWFrZS4gXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUlNBIGlzIDEuIFNlZSBodHRwOi8vdG9vbHMuaWV0Zi5vcmcvaHRtbC9yZmM0ODgwI3NlY3Rpb24tOS4xXG4gKiBAcGFyYW0ge0ludGVnZXJ9IG51bUJpdHMgICAgbnVtYmVyIG9mIGJpdHMgZm9yIHRoZSBrZXkgY3JlYXRpb24uIChzaG91bGQgYmUgMTAyNCssIGdlbmVyYWxseSlcbiAqIEBwYXJhbSB7U3RyaW5nfSAgdXNlcklkICAgICBhc3N1bWVzIGFscmVhZHkgaW4gZm9ybSBvZiBcIlVzZXIgTmFtZSA8dXNlcm5hbWVAZW1haWwuY29tPlwiXG4gKiBAcGFyYW0ge1N0cmluZ30gIHBhc3NwaHJhc2UgVGhlIHBhc3NwaHJhc2UgdXNlZCB0byBlbmNyeXB0IHRoZSByZXN1bHRpbmcgcHJpdmF0ZSBrZXlcbiAqIEByZXR1cm4ge09iamVjdH0ge2tleTogW0tleV0sIHByaXZhdGVLZXlBcm1vcmVkOiBbU3RyaW5nXSwgcHVibGljS2V5QXJtb3JlZDogW1N0cmluZ119XG4gKi9cbmZ1bmN0aW9uIGdlbmVyYXRlS2V5UGFpcihrZXlUeXBlLCBudW1CaXRzLCB1c2VySWQsIHBhc3NwaHJhc2UpIHtcbiAgdmFyIHJlc3VsdCA9IHt9O1xuICB2YXIgbmV3S2V5ID0ga2V5LmdlbmVyYXRlKGtleVR5cGUsIG51bUJpdHMsIHVzZXJJZCwgcGFzc3BocmFzZSk7XG4gIHJlc3VsdC5rZXkgPSBuZXdLZXk7XG4gIHJlc3VsdC5wcml2YXRlS2V5QXJtb3JlZCA9IG5ld0tleS5hcm1vcigpO1xuICByZXN1bHQucHVibGljS2V5QXJtb3JlZCA9IG5ld0tleS50b1B1YmxpYygpLmFybW9yKCk7XG4gIHJldHVybiByZXN1bHQ7XG59XG5cbmV4cG9ydHMuZW5jcnlwdE1lc3NhZ2UgPSBlbmNyeXB0TWVzc2FnZTtcbmV4cG9ydHMuc2lnbkFuZEVuY3J5cHRNZXNzYWdlID0gc2lnbkFuZEVuY3J5cHRNZXNzYWdlO1xuZXhwb3J0cy5kZWNyeXB0TWVzc2FnZSA9IGRlY3J5cHRNZXNzYWdlO1xuZXhwb3J0cy5kZWNyeXB0QW5kVmVyaWZ5TWVzc2FnZSA9IGRlY3J5cHRBbmRWZXJpZnlNZXNzYWdlXG5leHBvcnRzLnNpZ25DbGVhck1lc3NhZ2UgPSBzaWduQ2xlYXJNZXNzYWdlO1xuZXhwb3J0cy52ZXJpZnlDbGVhclNpZ25lZE1lc3NhZ2UgPSB2ZXJpZnlDbGVhclNpZ25lZE1lc3NhZ2U7XG5leHBvcnRzLmdlbmVyYXRlS2V5UGFpciA9IGdlbmVyYXRlS2V5UGFpcjtcbiIsInZhciBlbnVtcyA9IHJlcXVpcmUoJy4uL2VudW1zLmpzJyk7XG5cbi8vIFRoaXMgaXMgcHJldHR5IHVnbHksIGJ1dCBicm93c2VyaWZ5IG5lZWRzIHRvIGhhdmUgdGhlIHJlcXVpcmVzIGV4cGxpY2l0bHkgd3JpdHRlbi5cbm1vZHVsZS5leHBvcnRzID0ge1xuICBjb21wcmVzc2VkOiByZXF1aXJlKCcuL2NvbXByZXNzZWQuanMnKSxcbiAgc3ltX2VuY3J5cHRlZF9pbnRlZ3JpdHlfcHJvdGVjdGVkOiByZXF1aXJlKCcuL3N5bV9lbmNyeXB0ZWRfaW50ZWdyaXR5X3Byb3RlY3RlZC5qcycpLFxuICBwdWJsaWNfa2V5X2VuY3J5cHRlZF9zZXNzaW9uX2tleTogcmVxdWlyZSgnLi9wdWJsaWNfa2V5X2VuY3J5cHRlZF9zZXNzaW9uX2tleS5qcycpLFxuICBzeW1fZW5jcnlwdGVkX3Nlc3Npb25fa2V5OiByZXF1aXJlKCcuL3N5bV9lbmNyeXB0ZWRfc2Vzc2lvbl9rZXkuanMnKSxcbiAgbGl0ZXJhbDogcmVxdWlyZSgnLi9saXRlcmFsLmpzJyksXG4gIHB1YmxpY19rZXk6IHJlcXVpcmUoJy4vcHVibGljX2tleS5qcycpLFxuICBzeW1tZXRyaWNhbGx5X2VuY3J5cHRlZDogcmVxdWlyZSgnLi9zeW1tZXRyaWNhbGx5X2VuY3J5cHRlZC5qcycpLFxuICBtYXJrZXI6IHJlcXVpcmUoJy4vbWFya2VyLmpzJyksXG4gIHB1YmxpY19zdWJrZXk6IHJlcXVpcmUoJy4vcHVibGljX3N1YmtleS5qcycpLFxuICB1c2VyX2F0dHJpYnV0ZTogcmVxdWlyZSgnLi91c2VyX2F0dHJpYnV0ZS5qcycpLFxuICBvbmVfcGFzc19zaWduYXR1cmU6IHJlcXVpcmUoJy4vb25lX3Bhc3Nfc2lnbmF0dXJlLmpzJyksXG4gIHNlY3JldF9rZXk6IHJlcXVpcmUoJy4vc2VjcmV0X2tleS5qcycpLFxuICB1c2VyaWQ6IHJlcXVpcmUoJy4vdXNlcmlkLmpzJyksXG4gIHNlY3JldF9zdWJrZXk6IHJlcXVpcmUoJy4vc2VjcmV0X3N1YmtleS5qcycpLFxuICBzaWduYXR1cmU6IHJlcXVpcmUoJy4vc2lnbmF0dXJlLmpzJyksXG4gIHRydXN0OiByZXF1aXJlKCcuL3RydXN0LmpzJylcbn1cblxuZm9yICh2YXIgaSBpbiBlbnVtcy5wYWNrZXQpIHtcbiAgdmFyIHBhY2tldENsYXNzID0gbW9kdWxlLmV4cG9ydHNbaV07XG5cbiAgaWYgKHBhY2tldENsYXNzICE9IHVuZGVmaW5lZClcbiAgICBwYWNrZXRDbGFzcy5wcm90b3R5cGUudGFnID0gZW51bXMucGFja2V0W2ldO1xufVxuIiwiLy8gR1BHNEJyb3dzZXJzIC0gQW4gT3BlblBHUCBpbXBsZW1lbnRhdGlvbiBpbiBqYXZhc2NyaXB0XG4vLyBDb3B5cmlnaHQgKEMpIDIwMTEgUmVjdXJpdHkgTGFicyBHbWJIXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3Jcbi8vIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlclxuLy8gdmVyc2lvbiAyLjEgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuLy8gYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2Zcbi8vIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUgR05VXG4vLyBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuLy8gXG4vLyBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFsb25nIHdpdGggdGhpcyBsaWJyYXJ5OyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlXG4vLyBGb3VuZGF0aW9uLCBJbmMuLCA1MSBGcmFua2xpbiBTdHJlZXQsIEZpZnRoIEZsb29yLCBCb3N0b24sIE1BICAwMjExMC0xMzAxICBVU0FcblxudmFyIGVudW1zID0gcmVxdWlyZSgnLi4vZW51bXMuanMnKSxcbiAgSlhHID0gcmVxdWlyZSgnLi4vY29tcHJlc3Npb24vanhnLmpzJyksXG4gIGJhc2U2NCA9IHJlcXVpcmUoJy4uL2VuY29kaW5nL2Jhc2U2NC5qcycpO1xuXG4vKipcbiAqIEBjbGFzc1xuICogQGNsYXNzZGVzYyBJbXBsZW1lbnRhdGlvbiBvZiB0aGUgQ29tcHJlc3NlZCBEYXRhIFBhY2tldCAoVGFnIDgpXG4gKiBcbiAqIFJGQzQ4ODAgNS42OlxuICogVGhlIENvbXByZXNzZWQgRGF0YSBwYWNrZXQgY29udGFpbnMgY29tcHJlc3NlZCBkYXRhLiAgVHlwaWNhbGx5LCB0aGlzXG4gKiBwYWNrZXQgaXMgZm91bmQgYXMgdGhlIGNvbnRlbnRzIG9mIGFuIGVuY3J5cHRlZCBwYWNrZXQsIG9yIGZvbGxvd2luZ1xuICogYSBTaWduYXR1cmUgb3IgT25lLVBhc3MgU2lnbmF0dXJlIHBhY2tldCwgYW5kIGNvbnRhaW5zIGEgbGl0ZXJhbCBkYXRhXG4gKiBwYWNrZXQuXG4gKi9cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gcGFja2V0X2NvbXByZXNzZWQoKSB7XG4gIC8qKiBAdHlwZSB7cGFja2V0bGlzdH0gKi9cbiAgdGhpcy5wYWNrZXRzO1xuICAvKiogQHR5cGUge2NvbXByZXNzaW9ufSAqL1xuICB0aGlzLmFsZ29yaXRobSA9ICd1bmNvbXByZXNzZWQnO1xuXG4gIHRoaXMuY29tcHJlc3NlZCA9IG51bGw7XG5cblxuICAvKipcbiAgICogUGFyc2luZyBmdW5jdGlvbiBmb3IgdGhlIHBhY2tldC5cbiAgICogQHBhcmFtIHtTdHJpbmd9IGlucHV0IFBheWxvYWQgb2YgYSB0YWcgOCBwYWNrZXRcbiAgICogQHBhcmFtIHtJbnRlZ2VyfSBwb3NpdGlvbiBQb3NpdGlvbiB0byBzdGFydCByZWFkaW5nIGZyb20gdGhlIGlucHV0IHN0cmluZ1xuICAgKiBAcGFyQU0ge2lOVEVHRVJ9IExFTiBsRU5HVEggT0YgdGhlIHBhY2tldCBvciB0aGUgcmVtYWluaW5nIGxlbmd0aCBvZiBcbiAgICogaW5wdXQgYXQgcG9zaXRpb25cbiAgICogQHJldHVybiB7b3BlbnBncF9wYWNrZXRfY29tcHJlc3NlZH0gT2JqZWN0IHJlcHJlc2VudGF0aW9uXG4gICAqL1xuICB0aGlzLnJlYWQgPSBmdW5jdGlvbihieXRlcykge1xuICAgIC8vIE9uZSBvY3RldCB0aGF0IGdpdmVzIHRoZSBhbGdvcml0aG0gdXNlZCB0byBjb21wcmVzcyB0aGUgcGFja2V0LlxuICAgIHRoaXMuYWxnb3JpdGhtID0gZW51bXMucmVhZChlbnVtcy5jb21wcmVzc2lvbiwgYnl0ZXMuY2hhckNvZGVBdCgwKSk7XG5cbiAgICAvLyBDb21wcmVzc2VkIGRhdGEsIHdoaWNoIG1ha2VzIHVwIHRoZSByZW1haW5kZXIgb2YgdGhlIHBhY2tldC5cbiAgICB0aGlzLmNvbXByZXNzZWQgPSBieXRlcy5zdWJzdHIoMSk7XG5cbiAgICB0aGlzLmRlY29tcHJlc3MoKTtcbiAgfVxuXG5cblxuICB0aGlzLndyaXRlID0gZnVuY3Rpb24oKSB7XG4gICAgaWYgKHRoaXMuY29tcHJlc3NlZCA9PSBudWxsKVxuICAgICAgdGhpcy5jb21wcmVzcygpO1xuXG4gICAgcmV0dXJuIFN0cmluZy5mcm9tQ2hhckNvZGUoZW51bXMud3JpdGUoZW51bXMuY29tcHJlc3Npb24sIHRoaXMuYWxnb3JpdGhtKSkgKyB0aGlzLmNvbXByZXNzZWQ7XG4gIH1cblxuXG4gIC8qKlxuICAgKiBEZWNvbXByZXNzaW9uIG1ldGhvZCBmb3IgZGVjb21wcmVzc2luZyB0aGUgY29tcHJlc3NlZCBkYXRhXG4gICAqIHJlYWQgYnkgcmVhZF9wYWNrZXRcbiAgICogQHJldHVybiB7U3RyaW5nfSBUaGUgZGVjb21wcmVzc2VkIGRhdGFcbiAgICovXG4gIHRoaXMuZGVjb21wcmVzcyA9IGZ1bmN0aW9uKCkge1xuICAgIHZhciBkZWNvbXByZXNzZWQ7XG5cbiAgICBzd2l0Y2ggKHRoaXMuYWxnb3JpdGhtKSB7XG4gICAgICBjYXNlICd1bmNvbXByZXNzZWQnOlxuICAgICAgICBkZWNvbXByZXNzZWQgPSB0aGlzLmNvbXByZXNzZWQ7XG4gICAgICAgIGJyZWFrO1xuXG4gICAgICBjYXNlICd6aXAnOlxuICAgICAgICB2YXIgY29tcERhdGEgPSB0aGlzLmNvbXByZXNzZWQ7XG5cbiAgICAgICAgdmFyIHJhZGl4ID0gYmFzZTY0LmVuY29kZShjb21wRGF0YSkucmVwbGFjZSgvXFxuL2csIFwiXCIpO1xuICAgICAgICAvLyBubyBoZWFkZXIgaW4gdGhpcyBjYXNlLCBkaXJlY3RseSBjYWxsIGRlZmxhdGVcbiAgICAgICAgdmFyIGp4Z19vYmogPSBuZXcgSlhHLlV0aWwuVW56aXAoSlhHLlV0aWwuQmFzZTY0LmRlY29kZUFzQXJyYXkocmFkaXgpKTtcblxuICAgICAgICBkZWNvbXByZXNzZWQgPSB1bmVzY2FwZShqeGdfb2JqLmRlZmxhdGUoKVswXVswXSk7XG4gICAgICAgIGJyZWFrO1xuXG4gICAgICBjYXNlICd6bGliJzpcbiAgICAgICAgLy9SRkMgMTk1MC4gQml0cyAwLTMgQ29tcHJlc3Npb24gTWV0aG9kXG4gICAgICAgIHZhciBjb21wcmVzc2lvbk1ldGhvZCA9IHRoaXMuY29tcHJlc3NlZC5jaGFyQ29kZUF0KDApICUgMHgxMDtcblxuICAgICAgICAvL0JpdHMgNC03IFJGQyAxOTUwIGFyZSBMWjc3IFdpbmRvdy4gR2VuZXJhbGx5IHRoaXMgdmFsdWUgaXMgNyA9PSAzMmsgd2luZG93IHNpemUuXG4gICAgICAgIC8vIDJuZCBCeXRlIGluIFJGQyAxOTUwIGlzIGZvciBcIkZMQUdzXCIgQWxsb3dzIGZvciBhIERpY3Rpb25hcnkgXG4gICAgICAgIC8vIChob3cgaXMgdGhpcyBkZWZpbmVkKS4gQmFzaWMgY2hlY2tzdW0sIGFuZCBjb21wcmVzc2lvbiBsZXZlbC5cblxuICAgICAgICBpZiAoY29tcHJlc3Npb25NZXRob2QgPT0gOCkgeyAvL0NNIDggaXMgZm9yIERFRkxBVEUsIFJGQyAxOTUxXG4gICAgICAgICAgLy8gcmVtb3ZlIDQgYnl0ZXMgQURMRVIzMiBjaGVja3N1bSBmcm9tIHRoZSBlbmRcbiAgICAgICAgICB2YXIgY29tcERhdGEgPSB0aGlzLmNvbXByZXNzZWQuc3Vic3RyaW5nKDAsIHRoaXMuY29tcHJlc3NlZC5sZW5ndGggLSA0KTtcbiAgICAgICAgICB2YXIgcmFkaXggPSBiYXNlNjQuZW5jb2RlKGNvbXBEYXRhKS5yZXBsYWNlKC9cXG4vZywgXCJcIik7XG4gICAgICAgICAgLy9UT0RPIGNoZWNrIEFETEVSMzIgY2hlY2tzdW1cbiAgICAgICAgICBkZWNvbXByZXNzZWQgPSBKWEcuZGVjb21wcmVzcyhyYWRpeCk7XG4gICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB1dGlsLnByaW50X2Vycm9yKFwiQ29tcHJlc3Npb24gYWxnb3JpdGhtIFpMSUIgb25seSBzdXBwb3J0cyBcIiArXG4gICAgICAgICAgICBcIkRFRkxBVEUgY29tcHJlc3Npb24gbWV0aG9kLlwiKTtcbiAgICAgICAgfVxuICAgICAgICBicmVhaztcblxuICAgICAgY2FzZSAnYnppcDInOlxuICAgICAgICAvLyBUT0RPOiBuZWVkIHRvIGltcGxlbWVudCB0aGlzXG4gICAgICAgIHRocm93IG5ldyBFcnJvcignQ29tcHJlc3Npb24gYWxnb3JpdGhtIEJaaXAyIFtCWjJdIGlzIG5vdCBpbXBsZW1lbnRlZC4nKTtcbiAgICAgICAgYnJlYWs7XG5cbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIkNvbXByZXNzaW9uIGFsZ29yaXRobSB1bmtub3duIDpcIiArIHRoaXMuYWxvZ3JpdGhtKTtcbiAgICAgICAgYnJlYWs7XG4gICAgfVxuXG4gICAgdGhpcy5wYWNrZXRzLnJlYWQoZGVjb21wcmVzc2VkKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDb21wcmVzcyB0aGUgcGFja2V0IGRhdGEgKG1lbWJlciBkZWNvbXByZXNzZWREYXRhKVxuICAgKiBAcGFyYW0ge0ludGVnZXJ9IHR5cGUgQWxnb3JpdGhtIHRvIGJlIHVzZWQgLy8gU2VlIFJGQyA0ODgwIDkuM1xuICAgKiBAcGFyYW0ge1N0cmluZ30gZGF0YSBEYXRhIHRvIGJlIGNvbXByZXNzZWRcbiAgICogQHJldHVybiB7U3RyaW5nfSBUaGUgY29tcHJlc3NlZCBkYXRhIHN0b3JlZCBpbiBhdHRyaWJ1dGUgY29tcHJlc3NlZERhdGFcbiAgICovXG4gIHRoaXMuY29tcHJlc3MgPSBmdW5jdGlvbigpIHtcbiAgICBzd2l0Y2ggKHRoaXMuYWxnb3JpdGhtKSB7XG5cbiAgICAgIGNhc2UgJ3VuY29tcHJlc3NlZCc6XG4gICAgICAgIC8vIC0gVW5jb21wcmVzc2VkXG4gICAgICAgIHRoaXMuY29tcHJlc3NlZCA9IHRoaXMucGFja2V0cy53cml0ZSgpO1xuICAgICAgICBicmVhaztcblxuICAgICAgY2FzZSAnemlwJzpcbiAgICAgICAgLy8gLSBaSVAgW1JGQzE5NTFdXG4gICAgICAgIHV0aWwucHJpbnRfZXJyb3IoXCJDb21wcmVzc2lvbiBhbGdvcml0aG0gWklQIFtSRkMxOTUxXSBpcyBub3QgaW1wbGVtZW50ZWQuXCIpO1xuICAgICAgICBicmVhaztcblxuICAgICAgY2FzZSAnemxpYic6XG4gICAgICAgIC8vIC0gWkxJQiBbUkZDMTk1MF1cbiAgICAgICAgLy8gVE9ETzogbmVlZCB0byBpbXBsZW1lbnQgdGhpc1xuICAgICAgICB1dGlsLnByaW50X2Vycm9yKFwiQ29tcHJlc3Npb24gYWxnb3JpdGhtIFpMSUIgW1JGQzE5NTBdIGlzIG5vdCBpbXBsZW1lbnRlZC5cIik7XG4gICAgICAgIGJyZWFrO1xuXG4gICAgICBjYXNlICdiemlwMic6XG4gICAgICAgIC8vICAtIEJaaXAyIFtCWjJdXG4gICAgICAgIC8vIFRPRE86IG5lZWQgdG8gaW1wbGVtZW50IHRoaXNcbiAgICAgICAgdXRpbC5wcmludF9lcnJvcihcIkNvbXByZXNzaW9uIGFsZ29yaXRobSBCWmlwMiBbQloyXSBpcyBub3QgaW1wbGVtZW50ZWQuXCIpO1xuICAgICAgICBicmVhaztcblxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgdXRpbC5wcmludF9lcnJvcihcIkNvbXByZXNzaW9uIGFsZ29yaXRobSB1bmtub3duIDpcIiArIHRoaXMudHlwZSk7XG4gICAgICAgIGJyZWFrO1xuICAgIH1cbiAgfVxufTtcbiIsInZhciBlbnVtcyA9IHJlcXVpcmUoJy4uL2VudW1zLmpzJyk7XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICBsaXN0OiByZXF1aXJlKCcuL3BhY2tldGxpc3QuanMnKSxcbn07XG5cbnZhciBwYWNrZXRzID0gcmVxdWlyZSgnLi9hbGxfcGFja2V0cy5qcycpO1xuXG5mb3IgKHZhciBpIGluIHBhY2tldHMpXG4gIG1vZHVsZS5leHBvcnRzW2ldID0gcGFja2V0c1tpXTtcbiIsIi8vIEdQRzRCcm93c2VycyAtIEFuIE9wZW5QR1AgaW1wbGVtZW50YXRpb24gaW4gamF2YXNjcmlwdFxuLy8gQ29weXJpZ2h0IChDKSAyMDExIFJlY3VyaXR5IExhYnMgR21iSFxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yXG4vLyBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uOyBlaXRoZXJcbi8vIHZlcnNpb24gMi4xIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbi8vIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4vLyBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlIEdOVVxuLy8gTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cbi8vIFxuLy8gWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhbG9uZyB3aXRoIHRoaXMgbGlicmFyeTsgaWYgbm90LCB3cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZVxuLy8gRm91bmRhdGlvbiwgSW5jLiwgNTEgRnJhbmtsaW4gU3RyZWV0LCBGaWZ0aCBGbG9vciwgQm9zdG9uLCBNQSAgMDIxMTAtMTMwMSAgVVNBXG5cbnZhciB1dGlsID0gcmVxdWlyZSgnLi4vdXRpbCcpLFxuICBlbnVtcyA9IHJlcXVpcmUoJy4uL2VudW1zLmpzJyk7XG5cbi8qKlxuICogQGNsYXNzXG4gKiBAY2xhc3NkZXNjIEltcGxlbWVudGF0aW9uIG9mIHRoZSBMaXRlcmFsIERhdGEgUGFja2V0IChUYWcgMTEpXG4gKiBcbiAqIFJGQzQ4ODAgNS45OiBBIExpdGVyYWwgRGF0YSBwYWNrZXQgY29udGFpbnMgdGhlIGJvZHkgb2YgYSBtZXNzYWdlOyBkYXRhIHRoYXRcbiAqIGlzIG5vdCB0byBiZSBmdXJ0aGVyIGludGVycHJldGVkLlxuICovXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIHBhY2tldF9saXRlcmFsKCkge1xuICB0aGlzLmZvcm1hdCA9ICd1dGY4JzsgLy8gZGVmYXVsdCBmb3JtYXQgZm9yIGxpdGVyYWwgZGF0YSBwYWNrZXRzXG4gIHRoaXMuZGF0YSA9ICcnOyAvLyBsaXRlcmFsIGRhdGEgcmVwcmVzZW50YXRpb24gYXMgbmF0aXZlIEphdmFTY3JpcHQgc3RyaW5nIG9yIGJ5dGVzXG4gIHRoaXMuZGF0ZSA9IG5ldyBEYXRlKCk7XG5cblxuICAvKipcbiAgICogU2V0IHRoZSBwYWNrZXQgZGF0YSB0byBhIGphdmFzY3JpcHQgbmF0aXZlIHN0cmluZywgZW5kIG9mIGxpbmUgXG4gICAqIHdpbGwgYmUgbm9ybWFsaXplZCB0byBcXHJcXG4gYW5kIGJ5IGRlZmF1bHQgdGV4dCBpcyBjb252ZXJ0ZWQgdG8gVVRGOFxuICAgKiBAcGFyYW0ge1N0cmluZ30gdGV4dCBBbnkgbmF0aXZlIGphdmFzY3JpcHQgc3RyaW5nXG4gICAqL1xuICB0aGlzLnNldFRleHQgPSBmdW5jdGlvbih0ZXh0KSB7XG4gICAgLy8gbm9ybWFsaXplIEVPTCB0byBcXHJcXG5cbiAgICB0ZXh0ID0gdGV4dC5yZXBsYWNlKC9cXHIvZywgJycpLnJlcGxhY2UoL1xcbi9nLCAnXFxyXFxuJyk7XG4gICAgLy8gZW5jb2RlIFVURjhcbiAgICB0aGlzLmRhdGEgPSB0aGlzLmZvcm1hdCA9PSAndXRmOCcgPyB1dGlsLmVuY29kZV91dGY4KHRleHQpIDogdGV4dDtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGxpdGVyYWwgZGF0YSBwYWNrZXRzIGFzIG5hdGl2ZSBKYXZhU2NyaXB0IHN0cmluZ1xuICAgKiB3aXRoIG5vcm1hbGl6ZWQgZW5kIG9mIGxpbmUgdG8gXFxuXG4gICAqIEByZXR1cm4ge1N0cmluZ30gbGl0ZXJhbCBkYXRhIGFzIHRleHRcbiAgICovXG4gIHRoaXMuZ2V0VGV4dCA9IGZ1bmN0aW9uKCkge1xuICAgIC8vIGRlY29kZSBVVEY4XG4gICAgdmFyIHRleHQgPSB1dGlsLmRlY29kZV91dGY4KHRoaXMuZGF0YSk7XG4gICAgLy8gbm9ybWFsaXplIEVPTCB0byBcXG5cbiAgICByZXR1cm4gdGV4dC5yZXBsYWNlKC9cXHJcXG4vZywgJ1xcbicpO1xuICB9XG5cbiAgLyoqXG4gICAqIFNldCB0aGUgcGFja2V0IGRhdGEgdG8gdmFsdWUgcmVwcmVzZW50ZWQgYnkgdGhlIHByb3ZpZGVkIHN0cmluZyBvZiBieXRlcy5cbiAgICogQHBhcmFtIHtTdHJpbmd9IGJ5dGVzIFRoZSBzdHJpbmcgb2YgYnl0ZXNcbiAgICogQHBhcmFtIHsndXRmOHwnYmluYXJ5J3wndGV4dCd9IGZvcm1hdCBUaGUgZm9ybWF0IG9mIHRoZSBzdHJpbmcgb2YgYnl0ZXNcbiAgICovXG4gIHRoaXMuc2V0Qnl0ZXMgPSBmdW5jdGlvbihieXRlcywgZm9ybWF0KSB7XG4gICAgdGhpcy5mb3JtYXQgPSBmb3JtYXQ7XG4gICAgdGhpcy5kYXRhID0gYnl0ZXM7XG4gIH1cblxuXG4gIC8qKlxuICAgKiBHZXQgdGhlIGJ5dGUgc2VxdWVuY2UgcmVwcmVzZW50aW5nIHRoZSBsaXRlcmFsIHBhY2tldCBkYXRhXG4gICAqIEByZXR1cm5zIHtTdHJpbmd9IEEgc2VxdWVuY2Ugb2YgYnl0ZXNcbiAgICovXG4gIHRoaXMuZ2V0Qnl0ZXMgPSBmdW5jdGlvbigpIHtcbiAgICByZXR1cm4gdGhpcy5kYXRhO1xuICB9XG5cblxuICAvKipcbiAgICogUGFyc2luZyBmdW5jdGlvbiBmb3IgYSBsaXRlcmFsIGRhdGEgcGFja2V0ICh0YWcgMTEpLlxuICAgKiBcbiAgICogQHBhcmFtIHtTdHJpbmd9IGlucHV0IFBheWxvYWQgb2YgYSB0YWcgMTEgcGFja2V0XG4gICAqIEBwYXJhbSB7SW50ZWdlcn0gcG9zaXRpb25cbiAgICogICAgICAgICAgICBQb3NpdGlvbiB0byBzdGFydCByZWFkaW5nIGZyb20gdGhlIGlucHV0IHN0cmluZ1xuICAgKiBAcGFyYW0ge0ludGVnZXJ9IGxlblxuICAgKiAgICAgICAgICAgIExlbmd0aCBvZiB0aGUgcGFja2V0IG9yIHRoZSByZW1haW5pbmcgbGVuZ3RoIG9mXG4gICAqICAgICAgICAgICAgaW5wdXQgYXQgcG9zaXRpb25cbiAgICogQHJldHVybiB7b3BlbnBncF9wYWNrZXRfZW5jcnlwdGVkZGF0YX0gb2JqZWN0IHJlcHJlc2VudGF0aW9uXG4gICAqL1xuICB0aGlzLnJlYWQgPSBmdW5jdGlvbihieXRlcykge1xuICAgIC8vIC0gQSBvbmUtb2N0ZXQgZmllbGQgdGhhdCBkZXNjcmliZXMgaG93IHRoZSBkYXRhIGlzIGZvcm1hdHRlZC5cblxuICAgIHZhciBmb3JtYXQgPSBlbnVtcy5yZWFkKGVudW1zLmxpdGVyYWwsIGJ5dGVzLmNoYXJDb2RlQXQoMCkpO1xuXG4gICAgdmFyIGZpbGVuYW1lX2xlbiA9IGJ5dGVzLmNoYXJDb2RlQXQoMSk7XG4gICAgdGhpcy5maWxlbmFtZSA9IHV0aWwuZGVjb2RlX3V0ZjgoYnl0ZXMuc3Vic3RyKDIsIGZpbGVuYW1lX2xlbikpO1xuXG4gICAgdGhpcy5kYXRlID0gdXRpbC5yZWFkRGF0ZShieXRlcy5zdWJzdHIoMiArIGZpbGVuYW1lX2xlbiwgNCkpO1xuXG4gICAgdmFyIGRhdGEgPSBieXRlcy5zdWJzdHJpbmcoNiArIGZpbGVuYW1lX2xlbik7XG5cbiAgICB0aGlzLnNldEJ5dGVzKGRhdGEsIGZvcm1hdCk7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlcyBhIHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiB0aGUgcGFja2V0XG4gICAqIFxuICAgKiBAcGFyYW0ge1N0cmluZ30gZGF0YSBUaGUgZGF0YSB0byBiZSBpbnNlcnRlZCBhcyBib2R5XG4gICAqIEByZXR1cm4ge1N0cmluZ30gc3RyaW5nLXJlcHJlc2VudGF0aW9uIG9mIHRoZSBwYWNrZXRcbiAgICovXG4gIHRoaXMud3JpdGUgPSBmdW5jdGlvbigpIHtcbiAgICB2YXIgZmlsZW5hbWUgPSB1dGlsLmVuY29kZV91dGY4KFwibXNnLnR4dFwiKTtcblxuICAgIHZhciBkYXRhID0gdGhpcy5nZXRCeXRlcygpO1xuXG4gICAgdmFyIHJlc3VsdCA9ICcnO1xuICAgIHJlc3VsdCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGVudW1zLndyaXRlKGVudW1zLmxpdGVyYWwsIHRoaXMuZm9ybWF0KSk7XG4gICAgcmVzdWx0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoZmlsZW5hbWUubGVuZ3RoKTtcbiAgICByZXN1bHQgKz0gZmlsZW5hbWU7XG4gICAgcmVzdWx0ICs9IHV0aWwud3JpdGVEYXRlKHRoaXMuZGF0ZSk7XG4gICAgcmVzdWx0ICs9IGRhdGE7XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxufVxuIiwiLy8gR1BHNEJyb3dzZXJzIC0gQW4gT3BlblBHUCBpbXBsZW1lbnRhdGlvbiBpbiBqYXZhc2NyaXB0XG4vLyBDb3B5cmlnaHQgKEMpIDIwMTEgUmVjdXJpdHkgTGFicyBHbWJIXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3Jcbi8vIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlclxuLy8gdmVyc2lvbiAyLjEgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuLy8gYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2Zcbi8vIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUgR05VXG4vLyBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuLy8gXG4vLyBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFsb25nIHdpdGggdGhpcyBsaWJyYXJ5OyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlXG4vLyBGb3VuZGF0aW9uLCBJbmMuLCA1MSBGcmFua2xpbiBTdHJlZXQsIEZpZnRoIEZsb29yLCBCb3N0b24sIE1BICAwMjExMC0xMzAxICBVU0FcblxuLyoqXG4gKiBAY2xhc3NcbiAqIEBjbGFzc2Rlc2MgSW1wbGVtZW50YXRpb24gb2YgdGhlIHN0cmFuZ2UgXCJNYXJrZXIgcGFja2V0XCIgKFRhZyAxMClcbiAqIFxuICogUkZDNDg4MCA1Ljg6IEFuIGV4cGVyaW1lbnRhbCB2ZXJzaW9uIG9mIFBHUCB1c2VkIHRoaXMgcGFja2V0IGFzIHRoZSBMaXRlcmFsXG4gKiBwYWNrZXQsIGJ1dCBubyByZWxlYXNlZCB2ZXJzaW9uIG9mIFBHUCBnZW5lcmF0ZWQgTGl0ZXJhbCBwYWNrZXRzIHdpdGggdGhpc1xuICogdGFnLiBXaXRoIFBHUCA1LngsIHRoaXMgcGFja2V0IGhhcyBiZWVuIHJlYXNzaWduZWQgYW5kIGlzIHJlc2VydmVkIGZvciB1c2UgYXNcbiAqIHRoZSBNYXJrZXIgcGFja2V0LlxuICogXG4gKiBTdWNoIGEgcGFja2V0IE1VU1QgYmUgaWdub3JlZCB3aGVuIHJlY2VpdmVkLlxuICovXG5mdW5jdGlvbiBwYWNrZXRfbWFya2VyKCkge1xuICAvKipcbiAgICogUGFyc2luZyBmdW5jdGlvbiBmb3IgYSBsaXRlcmFsIGRhdGEgcGFja2V0ICh0YWcgMTApLlxuICAgKiBcbiAgICogQHBhcmFtIHtTdHJpbmd9IGlucHV0IFBheWxvYWQgb2YgYSB0YWcgMTAgcGFja2V0XG4gICAqIEBwYXJhbSB7SW50ZWdlcn0gcG9zaXRpb25cbiAgICogICAgICAgICAgICBQb3NpdGlvbiB0byBzdGFydCByZWFkaW5nIGZyb20gdGhlIGlucHV0IHN0cmluZ1xuICAgKiBAcGFyYW0ge0ludGVnZXJ9IGxlblxuICAgKiAgICAgICAgICAgIExlbmd0aCBvZiB0aGUgcGFja2V0IG9yIHRoZSByZW1haW5pbmcgbGVuZ3RoIG9mXG4gICAqICAgICAgICAgICAgaW5wdXQgYXQgcG9zaXRpb25cbiAgICogQHJldHVybiB7b3BlbnBncF9wYWNrZXRfZW5jcnlwdGVkZGF0YX0gT2JqZWN0IHJlcHJlc2VudGF0aW9uXG4gICAqL1xuICB0aGlzLnJlYWQgPSBmdW5jdGlvbihieXRlcykge1xuICAgIGlmIChieXRlcy5jaGFyQ29kZUF0KDApID09IDB4NTAgJiYgLy8gUFxuICAgIGJ5dGVzLmNoYXJDb2RlQXQoMSkgPT0gMHg0NyAmJiAvLyBHXG4gICAgYnl0ZXMuY2hhckNvZGVBdCgyKSA9PSAweDUwKSAvLyBQXG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICAvLyBtYXJrZXIgcGFja2V0IGRvZXMgbm90IGNvbnRhaW4gXCJQR1BcIlxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHBhY2tldF9tYXJrZXI7XG4iLCIvLyBHUEc0QnJvd3NlcnMgLSBBbiBPcGVuUEdQIGltcGxlbWVudGF0aW9uIGluIGphdmFzY3JpcHRcbi8vIENvcHlyaWdodCAoQykgMjAxMSBSZWN1cml0eSBMYWJzIEdtYkhcbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vclxuLy8gbW9kaWZ5IGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyXG4vLyB2ZXJzaW9uIDIuMSBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4vLyBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuLy8gTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZSBHTlVcbi8vIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG4vLyBcbi8vIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYWxvbmcgd2l0aCB0aGlzIGxpYnJhcnk7IGlmIG5vdCwgd3JpdGUgdG8gdGhlIEZyZWUgU29mdHdhcmVcbi8vIEZvdW5kYXRpb24sIEluYy4sIDUxIEZyYW5rbGluIFN0cmVldCwgRmlmdGggRmxvb3IsIEJvc3RvbiwgTUEgIDAyMTEwLTEzMDEgIFVTQVxuXG4vKipcbiAqIEBjbGFzc1xuICogQGNsYXNzZGVzYyBJbXBsZW1lbnRhdGlvbiBvZiB0aGUgT25lLVBhc3MgU2lnbmF0dXJlIFBhY2tldHMgKFRhZyA0KVxuICogXG4gKiBSRkM0ODgwIDUuNDpcbiAqIFRoZSBPbmUtUGFzcyBTaWduYXR1cmUgcGFja2V0IHByZWNlZGVzIHRoZSBzaWduZWQgZGF0YSBhbmQgY29udGFpbnNcbiAqIGVub3VnaCBpbmZvcm1hdGlvbiB0byBhbGxvdyB0aGUgcmVjZWl2ZXIgdG8gYmVnaW4gY2FsY3VsYXRpbmcgYW55XG4gKiBoYXNoZXMgbmVlZGVkIHRvIHZlcmlmeSB0aGUgc2lnbmF0dXJlLiAgSXQgYWxsb3dzIHRoZSBTaWduYXR1cmVcbiAqIHBhY2tldCB0byBiZSBwbGFjZWQgYXQgdGhlIGVuZCBvZiB0aGUgbWVzc2FnZSwgc28gdGhhdCB0aGUgc2lnbmVyXG4gKiBjYW4gY29tcHV0ZSB0aGUgZW50aXJlIHNpZ25lZCBtZXNzYWdlIGluIG9uZSBwYXNzLlxuICovXG5cbnZhciBlbnVtcyA9IHJlcXVpcmUoJy4uL2VudW1zLmpzJyksXG4gIHR5cGVfa2V5aWQgPSByZXF1aXJlKCcuLi90eXBlL2tleWlkLmpzJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gcGFja2V0X29uZV9wYXNzX3NpZ25hdHVyZSgpIHtcbiAgdGhpcy52ZXJzaW9uID0gbnVsbDsgLy8gQSBvbmUtb2N0ZXQgdmVyc2lvbiBudW1iZXIuICBUaGUgY3VycmVudCB2ZXJzaW9uIGlzIDMuXG4gIHRoaXMudHlwZSA9IG51bGw7IC8vIEEgb25lLW9jdGV0IHNpZ25hdHVyZSB0eXBlLiAgU2lnbmF0dXJlIHR5cGVzIGFyZSBkZXNjcmliZWQgaW4gUkZDNDg4MCBTZWN0aW9uIDUuMi4xLlxuICB0aGlzLmhhc2hBbGdvcml0aG0gPSBudWxsOyAvLyBBIG9uZS1vY3RldCBudW1iZXIgZGVzY3JpYmluZyB0aGUgaGFzaCBhbGdvcml0aG0gdXNlZC4gKFNlZSBSRkM0ODgwIDkuNClcbiAgdGhpcy5wdWJsaWNLZXlBbGdvcml0aG0gPSBudWxsOyAvLyBBIG9uZS1vY3RldCBudW1iZXIgZGVzY3JpYmluZyB0aGUgcHVibGljLWtleSBhbGdvcml0aG0gdXNlZC4gKFNlZSBSRkM0ODgwIDkuMSlcbiAgdGhpcy5zaWduaW5nS2V5SWQgPSBudWxsOyAvLyBBbiBlaWdodC1vY3RldCBudW1iZXIgaG9sZGluZyB0aGUgS2V5IElEIG9mIHRoZSBzaWduaW5nIGtleS5cbiAgdGhpcy5mbGFncyA9IG51bGw7IC8vICBBIG9uZS1vY3RldCBudW1iZXIgaG9sZGluZyBhIGZsYWcgc2hvd2luZyB3aGV0aGVyIHRoZSBzaWduYXR1cmUgaXMgbmVzdGVkLiAgQSB6ZXJvIHZhbHVlIGluZGljYXRlcyB0aGF0IHRoZSBuZXh0IHBhY2tldCBpcyBhbm90aGVyIE9uZS1QYXNzIFNpZ25hdHVyZSBwYWNrZXQgdGhhdCBkZXNjcmliZXMgYW5vdGhlciBzaWduYXR1cmUgdG8gYmUgYXBwbGllZCB0byB0aGUgc2FtZSBtZXNzYWdlIGRhdGEuXG5cbiAgLyoqXG4gICAqIHBhcnNpbmcgZnVuY3Rpb24gZm9yIGEgb25lLXBhc3Mgc2lnbmF0dXJlIHBhY2tldCAodGFnIDQpLlxuICAgKiBAcGFyYW0ge1N0cmluZ30gYnl0ZXMgcGF5bG9hZCBvZiBhIHRhZyA0IHBhY2tldFxuICAgKiBAcmV0dXJuIHtwYWNrZXRfb25lX3Bhc3Nfc2lnbmF0dXJlfSBvYmplY3QgcmVwcmVzZW50YXRpb25cbiAgICovXG4gIHRoaXMucmVhZCA9IGZ1bmN0aW9uKGJ5dGVzKSB7XG4gICAgdmFyIG15cG9zID0gMDtcbiAgICAvLyBBIG9uZS1vY3RldCB2ZXJzaW9uIG51bWJlci4gIFRoZSBjdXJyZW50IHZlcnNpb24gaXMgMy5cbiAgICB0aGlzLnZlcnNpb24gPSBieXRlcy5jaGFyQ29kZUF0KG15cG9zKyspO1xuXG4gICAgLy8gQSBvbmUtb2N0ZXQgc2lnbmF0dXJlIHR5cGUuICBTaWduYXR1cmUgdHlwZXMgYXJlIGRlc2NyaWJlZCBpblxuICAgIC8vICAgU2VjdGlvbiA1LjIuMS5cbiAgICB0aGlzLnR5cGUgPSBlbnVtcy5yZWFkKGVudW1zLnNpZ25hdHVyZSwgYnl0ZXMuY2hhckNvZGVBdChteXBvcysrKSk7XG5cbiAgICAvLyBBIG9uZS1vY3RldCBudW1iZXIgZGVzY3JpYmluZyB0aGUgaGFzaCBhbGdvcml0aG0gdXNlZC5cbiAgICB0aGlzLmhhc2hBbGdvcml0aG0gPSBlbnVtcy5yZWFkKGVudW1zLmhhc2gsIGJ5dGVzLmNoYXJDb2RlQXQobXlwb3MrKykpO1xuXG4gICAgLy8gQSBvbmUtb2N0ZXQgbnVtYmVyIGRlc2NyaWJpbmcgdGhlIHB1YmxpYy1rZXkgYWxnb3JpdGhtIHVzZWQuXG4gICAgdGhpcy5wdWJsaWNLZXlBbGdvcml0aG0gPSBlbnVtcy5yZWFkKGVudW1zLnB1YmxpY0tleSwgYnl0ZXMuY2hhckNvZGVBdChteXBvcysrKSk7XG5cbiAgICAvLyBBbiBlaWdodC1vY3RldCBudW1iZXIgaG9sZGluZyB0aGUgS2V5IElEIG9mIHRoZSBzaWduaW5nIGtleS5cbiAgICB0aGlzLnNpZ25pbmdLZXlJZCA9IG5ldyB0eXBlX2tleWlkKCk7XG4gICAgdGhpcy5zaWduaW5nS2V5SWQucmVhZChieXRlcy5zdWJzdHIobXlwb3MpKTtcbiAgICBteXBvcyArPSA4O1xuXG4gICAgLy8gQSBvbmUtb2N0ZXQgbnVtYmVyIGhvbGRpbmcgYSBmbGFnIHNob3dpbmcgd2hldGhlciB0aGUgc2lnbmF0dXJlXG4gICAgLy8gICBpcyBuZXN0ZWQuICBBIHplcm8gdmFsdWUgaW5kaWNhdGVzIHRoYXQgdGhlIG5leHQgcGFja2V0IGlzXG4gICAgLy8gICBhbm90aGVyIE9uZS1QYXNzIFNpZ25hdHVyZSBwYWNrZXQgdGhhdCBkZXNjcmliZXMgYW5vdGhlclxuICAgIC8vICAgc2lnbmF0dXJlIHRvIGJlIGFwcGxpZWQgdG8gdGhlIHNhbWUgbWVzc2FnZSBkYXRhLlxuICAgIHRoaXMuZmxhZ3MgPSBieXRlcy5jaGFyQ29kZUF0KG15cG9zKyspO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLyoqXG4gICAqIGNyZWF0ZXMgYSBzdHJpbmcgcmVwcmVzZW50YXRpb24gb2YgYSBvbmUtcGFzcyBzaWduYXR1cmUgcGFja2V0XG4gICAqIEByZXR1cm4ge1N0cmluZ30gYSBzdHJpbmcgcmVwcmVzZW50YXRpb24gb2YgYSBvbmUtcGFzcyBzaWduYXR1cmUgcGFja2V0XG4gICAqL1xuICB0aGlzLndyaXRlID0gZnVuY3Rpb24oKSB7XG4gICAgdmFyIHJlc3VsdCA9IFwiXCI7XG5cbiAgICByZXN1bHQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSgzKTtcbiAgICByZXN1bHQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShlbnVtcy53cml0ZShlbnVtcy5zaWduYXR1cmUsIHRoaXMudHlwZSkpO1xuICAgIHJlc3VsdCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGVudW1zLndyaXRlKGVudW1zLmhhc2gsIHRoaXMuaGFzaEFsZ29yaXRobSkpO1xuICAgIHJlc3VsdCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGVudW1zLndyaXRlKGVudW1zLnB1YmxpY0tleSwgdGhpcy5wdWJsaWNLZXlBbGdvcml0aG0pKTtcbiAgICByZXN1bHQgKz0gdGhpcy5zaWduaW5nS2V5SWQud3JpdGUoKTtcbiAgICByZXN1bHQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSh0aGlzLmZsYWdzKTtcblxuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cbn07XG4iLCIvLyBHUEc0QnJvd3NlcnMgLSBBbiBPcGVuUEdQIGltcGxlbWVudGF0aW9uIGluIGphdmFzY3JpcHRcbi8vIENvcHlyaWdodCAoQykgMjAxMSBSZWN1cml0eSBMYWJzIEdtYkhcbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vclxuLy8gbW9kaWZ5IGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyXG4vLyB2ZXJzaW9uIDIuMSBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4vLyBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuLy8gTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZSBHTlVcbi8vIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG4vLyBcbi8vIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYWxvbmcgd2l0aCB0aGlzIGxpYnJhcnk7IGlmIG5vdCwgd3JpdGUgdG8gdGhlIEZyZWUgU29mdHdhcmVcbi8vIEZvdW5kYXRpb24sIEluYy4sIDUxIEZyYW5rbGluIFN0cmVldCwgRmlmdGggRmxvb3IsIEJvc3RvbiwgTUEgIDAyMTEwLTEzMDEgIFVTQVxuXG52YXIgZW51bXMgPSByZXF1aXJlKCcuLi9lbnVtcy5qcycpLFxuICB1dGlsID0gcmVxdWlyZSgnLi4vdXRpbCcpO1xuXG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICByZWFkU2ltcGxlTGVuZ3RoOiBmdW5jdGlvbihieXRlcykge1xuICAgIHZhciBsZW4gPSAwLFxuICAgICAgb2Zmc2V0LFxuICAgICAgdHlwZSA9IGJ5dGVzLmNoYXJDb2RlQXQoMCk7XG5cblxuICAgIGlmICh0eXBlIDwgMTkyKSB7XG4gICAgICBsZW4gPSBieXRlcy5jaGFyQ29kZUF0KDApO1xuICAgICAgb2Zmc2V0ID0gMTtcbiAgICB9IGVsc2UgaWYgKHR5cGUgPCAyNTUpIHtcbiAgICAgIGxlbiA9ICgoYnl0ZXMuY2hhckNvZGVBdCgwKSAtIDE5MikgPDwgOCkgKyAoYnl0ZXMuY2hhckNvZGVBdCgxKSkgKyAxOTI7XG4gICAgICBvZmZzZXQgPSAyO1xuICAgIH0gZWxzZSBpZiAodHlwZSA9PSAyNTUpIHtcbiAgICAgIGxlbiA9IHV0aWwucmVhZE51bWJlcihieXRlcy5zdWJzdHIoMSwgNCkpO1xuICAgICAgb2Zmc2V0ID0gNTtcbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgbGVuOiBsZW4sXG4gICAgICBvZmZzZXQ6IG9mZnNldFxuICAgIH07XG4gIH0sXG5cbiAgLyoqXG4gICAqIEVuY29kZXMgYSBnaXZlbiBpbnRlZ2VyIG9mIGxlbmd0aCB0byB0aGUgb3BlbnBncCBsZW5ndGggc3BlY2lmaWVyIHRvIGFcbiAgICogc3RyaW5nXG4gICAqIFxuICAgKiBAcGFyYW0ge0ludGVnZXJ9IGxlbmd0aCBUaGUgbGVuZ3RoIHRvIGVuY29kZVxuICAgKiBAcmV0dXJuIHtTdHJpbmd9IFN0cmluZyB3aXRoIG9wZW5wZ3AgbGVuZ3RoIHJlcHJlc2VudGF0aW9uXG4gICAqL1xuICB3cml0ZVNpbXBsZUxlbmd0aDogZnVuY3Rpb24obGVuZ3RoKSB7XG4gICAgdmFyIHJlc3VsdCA9IFwiXCI7XG4gICAgaWYgKGxlbmd0aCA8IDE5Mikge1xuICAgICAgcmVzdWx0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUobGVuZ3RoKTtcbiAgICB9IGVsc2UgaWYgKGxlbmd0aCA+IDE5MSAmJiBsZW5ndGggPCA4Mzg0KSB7XG4gICAgICAvKlxuICAgICAgICogbGV0IGEgPSAodG90YWwgZGF0YSBwYWNrZXQgbGVuZ3RoKSAtIDE5MiBsZXQgYmMgPSB0d28gb2N0ZXRcbiAgICAgICAqIHJlcHJlc2VudGF0aW9uIG9mIGEgbGV0IGQgPSBiICsgMTkyXG4gICAgICAgKi9cbiAgICAgIHJlc3VsdCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKCgobGVuZ3RoIC0gMTkyKSA+PiA4KSArIDE5Mik7XG4gICAgICByZXN1bHQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSgobGVuZ3RoIC0gMTkyKSAmIDB4RkYpO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXN1bHQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSgyNTUpO1xuICAgICAgcmVzdWx0ICs9IHV0aWwud3JpdGVOdW1iZXIobGVuZ3RoLCA0KTtcbiAgICB9XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfSxcblxuICAvKipcbiAgICogV3JpdGVzIGEgcGFja2V0IGhlYWRlciB2ZXJzaW9uIDQgd2l0aCB0aGUgZ2l2ZW4gdGFnX3R5cGUgYW5kIGxlbmd0aCB0byBhXG4gICAqIHN0cmluZ1xuICAgKiBcbiAgICogQHBhcmFtIHtJbnRlZ2VyfSB0YWdfdHlwZSBUYWcgdHlwZVxuICAgKiBAcGFyYW0ge0ludGVnZXJ9IGxlbmd0aCBMZW5ndGggb2YgdGhlIHBheWxvYWRcbiAgICogQHJldHVybiB7U3RyaW5nfSBTdHJpbmcgb2YgdGhlIGhlYWRlclxuICAgKi9cbiAgd3JpdGVIZWFkZXI6IGZ1bmN0aW9uKHRhZ190eXBlLCBsZW5ndGgpIHtcbiAgICAvKiB3ZSdyZSBvbmx5IGdlbmVyYXRpbmcgdjQgcGFja2V0IGhlYWRlcnMgaGVyZSAqL1xuICAgIHZhciByZXN1bHQgPSBcIlwiO1xuICAgIHJlc3VsdCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKDB4QzAgfCB0YWdfdHlwZSk7XG4gICAgcmVzdWx0ICs9IHRoaXMud3JpdGVTaW1wbGVMZW5ndGgobGVuZ3RoKTtcbiAgICByZXR1cm4gcmVzdWx0O1xuICB9LFxuXG4gIC8qKlxuICAgKiBXcml0ZXMgYSBwYWNrZXQgaGVhZGVyIFZlcnNpb24gMyB3aXRoIHRoZSBnaXZlbiB0YWdfdHlwZSBhbmQgbGVuZ3RoIHRvIGFcbiAgICogc3RyaW5nXG4gICAqIFxuICAgKiBAcGFyYW0ge0ludGVnZXJ9IHRhZ190eXBlIFRhZyB0eXBlXG4gICAqIEBwYXJhbSB7SW50ZWdlcn0gbGVuZ3RoIExlbmd0aCBvZiB0aGUgcGF5bG9hZFxuICAgKiBAcmV0dXJuIHtTdHJpbmd9IFN0cmluZyBvZiB0aGUgaGVhZGVyXG4gICAqL1xuICB3cml0ZU9sZEhlYWRlcjogZnVuY3Rpb24odGFnX3R5cGUsIGxlbmd0aCkge1xuICAgIHZhciByZXN1bHQgPSBcIlwiO1xuICAgIGlmIChsZW5ndGggPCAyNTYpIHtcbiAgICAgIHJlc3VsdCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKDB4ODAgfCAodGFnX3R5cGUgPDwgMikpO1xuICAgICAgcmVzdWx0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUobGVuZ3RoKTtcbiAgICB9IGVsc2UgaWYgKGxlbmd0aCA8IDY1NTM2KSB7XG4gICAgICByZXN1bHQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSgweDgwIHwgKHRhZ190eXBlIDw8IDIpIHwgMSk7XG4gICAgICByZXN1bHQgKz0gdXRpbC53cml0ZU51bWJlcihsZW5ndGgsIDIpO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXN1bHQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSgweDgwIHwgKHRhZ190eXBlIDw8IDIpIHwgMik7XG4gICAgICByZXN1bHQgKz0gdXRpbC53cml0ZU51bWJlcihsZW5ndGgsIDQpO1xuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9LFxuXG4gIC8qKlxuICAgKiBHZW5lcmljIHN0YXRpYyBQYWNrZXQgUGFyc2VyIGZ1bmN0aW9uXG4gICAqIFxuICAgKiBAcGFyYW0ge1N0cmluZ30gaW5wdXQgSW5wdXQgc3RyZWFtIGFzIHN0cmluZ1xuICAgKiBAcGFyYW0ge2ludGVnZXJ9IHBvc2l0aW9uIFBvc2l0aW9uIHRvIHN0YXJ0IHBhcnNpbmdcbiAgICogQHBhcmFtIHtpbnRlZ2VyfSBsZW4gTGVuZ3RoIG9mIHRoZSBpbnB1dCBmcm9tIHBvc2l0aW9uIG9uXG4gICAqIEByZXR1cm4ge09iamVjdH0gUmV0dXJucyBhIHBhcnNlZCBvcGVucGdwX3BhY2tldFxuICAgKi9cbiAgcmVhZDogZnVuY3Rpb24oaW5wdXQsIHBvc2l0aW9uLCBsZW4pIHtcbiAgICAvLyBzb21lIHNhbml0eSBjaGVja3NcbiAgICBpZiAoaW5wdXQgPT0gbnVsbCB8fCBpbnB1dC5sZW5ndGggPD0gcG9zaXRpb24gfHwgaW5wdXQuc3Vic3RyaW5nKHBvc2l0aW9uKS5sZW5ndGggPCAyIHx8IChpbnB1dC5jaGFyQ29kZUF0KHBvc2l0aW9uKSAmXG4gICAgICAweDgwKSA9PSAwKSB7XG4gICAgICB1dGlsXG4gICAgICAgIC5wcmludF9lcnJvcihcIkVycm9yIGR1cmluZyBwYXJzaW5nLiBUaGlzIG1lc3NhZ2UgLyBrZXkgaXMgcHJvYmFibHkgbm90IGNvbnRhaW5pbmcgYSB2YWxpZCBPcGVuUEdQIGZvcm1hdC5cIik7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG4gICAgdmFyIG15cG9zID0gcG9zaXRpb247XG4gICAgdmFyIHRhZyA9IC0xO1xuICAgIHZhciBmb3JtYXQgPSAtMTtcbiAgICB2YXIgcGFja2V0X2xlbmd0aDtcblxuICAgIGZvcm1hdCA9IDA7IC8vIDAgPSBvbGQgZm9ybWF0OyAxID0gbmV3IGZvcm1hdFxuICAgIGlmICgoaW5wdXQuY2hhckNvZGVBdChteXBvcykgJiAweDQwKSAhPSAwKSB7XG4gICAgICBmb3JtYXQgPSAxO1xuICAgIH1cblxuICAgIHZhciBwYWNrZXRfbGVuZ3RoX3R5cGU7XG4gICAgaWYgKGZvcm1hdCkge1xuICAgICAgLy8gbmV3IGZvcm1hdCBoZWFkZXJcbiAgICAgIHRhZyA9IGlucHV0LmNoYXJDb2RlQXQobXlwb3MpICYgMHgzRjsgLy8gYml0IDUtMFxuICAgIH0gZWxzZSB7XG4gICAgICAvLyBvbGQgZm9ybWF0IGhlYWRlclxuICAgICAgdGFnID0gKGlucHV0LmNoYXJDb2RlQXQobXlwb3MpICYgMHgzRikgPj4gMjsgLy8gYml0IDUtMlxuICAgICAgcGFja2V0X2xlbmd0aF90eXBlID0gaW5wdXQuY2hhckNvZGVBdChteXBvcykgJiAweDAzOyAvLyBiaXQgMS0wXG4gICAgfVxuXG4gICAgLy8gaGVhZGVyIG9jdGV0IHBhcnNpbmcgZG9uZVxuICAgIG15cG9zKys7XG5cbiAgICAvLyBwYXJzZWQgbGVuZ3RoIGZyb20gbGVuZ3RoIGZpZWxkXG4gICAgdmFyIGJvZHlkYXRhID0gbnVsbDtcblxuICAgIC8vIHVzZWQgZm9yIHBhcnRpYWwgYm9keSBsZW5ndGhzXG4gICAgdmFyIHJlYWxfcGFja2V0X2xlbmd0aCA9IC0xO1xuICAgIGlmICghZm9ybWF0KSB7XG4gICAgICAvLyA0LjIuMS4gT2xkIEZvcm1hdCBQYWNrZXQgTGVuZ3Roc1xuICAgICAgc3dpdGNoIChwYWNrZXRfbGVuZ3RoX3R5cGUpIHtcbiAgICAgICAgY2FzZSAwOlxuICAgICAgICAgIC8vIFRoZSBwYWNrZXQgaGFzIGEgb25lLW9jdGV0IGxlbmd0aC4gVGhlIGhlYWRlciBpcyAyIG9jdGV0c1xuICAgICAgICAgIC8vIGxvbmcuXG4gICAgICAgICAgcGFja2V0X2xlbmd0aCA9IGlucHV0LmNoYXJDb2RlQXQobXlwb3MrKyk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgMTpcbiAgICAgICAgICAvLyBUaGUgcGFja2V0IGhhcyBhIHR3by1vY3RldCBsZW5ndGguIFRoZSBoZWFkZXIgaXMgMyBvY3RldHNcbiAgICAgICAgICAvLyBsb25nLlxuICAgICAgICAgIHBhY2tldF9sZW5ndGggPSAoaW5wdXQuY2hhckNvZGVBdChteXBvcysrKSA8PCA4KSB8IGlucHV0LmNoYXJDb2RlQXQobXlwb3MrKyk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgMjpcbiAgICAgICAgICAvLyBUaGUgcGFja2V0IGhhcyBhIGZvdXItb2N0ZXQgbGVuZ3RoLiBUaGUgaGVhZGVyIGlzIDVcbiAgICAgICAgICAvLyBvY3RldHMgbG9uZy5cbiAgICAgICAgICBwYWNrZXRfbGVuZ3RoID0gKGlucHV0LmNoYXJDb2RlQXQobXlwb3MrKykgPDwgMjQpIHwgKGlucHV0LmNoYXJDb2RlQXQobXlwb3MrKykgPDwgMTYpIHwgKGlucHV0LmNoYXJDb2RlQXQobXlwb3MrKykgPDxcbiAgICAgICAgICAgIDgpIHwgaW5wdXQuY2hhckNvZGVBdChteXBvcysrKTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAvLyAzIC0gVGhlIHBhY2tldCBpcyBvZiBpbmRldGVybWluYXRlIGxlbmd0aC4gVGhlIGhlYWRlciBpcyAxXG4gICAgICAgICAgLy8gb2N0ZXQgbG9uZywgYW5kIHRoZSBpbXBsZW1lbnRhdGlvbiBtdXN0IGRldGVybWluZSBob3cgbG9uZ1xuICAgICAgICAgIC8vIHRoZSBwYWNrZXQgaXMuIElmIHRoZSBwYWNrZXQgaXMgaW4gYSBmaWxlLCB0aGlzIG1lYW5zIHRoYXRcbiAgICAgICAgICAvLyB0aGUgcGFja2V0IGV4dGVuZHMgdW50aWwgdGhlIGVuZCBvZiB0aGUgZmlsZS4gSW4gZ2VuZXJhbCwgXG4gICAgICAgICAgLy8gYW4gaW1wbGVtZW50YXRpb24gU0hPVUxEIE5PVCB1c2UgaW5kZXRlcm1pbmF0ZS1sZW5ndGggXG4gICAgICAgICAgLy8gcGFja2V0cyBleGNlcHQgd2hlcmUgdGhlIGVuZCBvZiB0aGUgZGF0YSB3aWxsIGJlIGNsZWFyIFxuICAgICAgICAgIC8vIGZyb20gdGhlIGNvbnRleHQsIGFuZCBldmVuIHRoZW4gaXQgaXMgYmV0dGVyIHRvIHVzZSBhIFxuICAgICAgICAgIC8vIGRlZmluaXRlIGxlbmd0aCwgb3IgYSBuZXcgZm9ybWF0IGhlYWRlci4gVGhlIG5ldyBmb3JtYXQgXG4gICAgICAgICAgLy8gaGVhZGVycyBkZXNjcmliZWQgYmVsb3cgaGF2ZSBhIG1lY2hhbmlzbSBmb3IgcHJlY2lzZWx5XG4gICAgICAgICAgLy8gZW5jb2RpbmcgZGF0YSBvZiBpbmRldGVybWluYXRlIGxlbmd0aC5cbiAgICAgICAgICBwYWNrZXRfbGVuZ3RoID0gbGVuO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgfVxuXG4gICAgfSBlbHNlIC8vIDQuMi4yLiBOZXcgRm9ybWF0IFBhY2tldCBMZW5ndGhzXG4gICAge1xuXG4gICAgICAvLyA0LjIuMi4xLiBPbmUtT2N0ZXQgTGVuZ3Roc1xuICAgICAgaWYgKGlucHV0LmNoYXJDb2RlQXQobXlwb3MpIDwgMTkyKSB7XG4gICAgICAgIHBhY2tldF9sZW5ndGggPSBpbnB1dC5jaGFyQ29kZUF0KG15cG9zKyspO1xuICAgICAgICB1dGlsLnByaW50X2RlYnVnKFwiMSBieXRlIGxlbmd0aDpcIiArIHBhY2tldF9sZW5ndGgpO1xuICAgICAgICAvLyA0LjIuMi4yLiBUd28tT2N0ZXQgTGVuZ3Roc1xuICAgICAgfSBlbHNlIGlmIChpbnB1dC5jaGFyQ29kZUF0KG15cG9zKSA+PSAxOTIgJiYgaW5wdXQuY2hhckNvZGVBdChteXBvcykgPCAyMjQpIHtcbiAgICAgICAgcGFja2V0X2xlbmd0aCA9ICgoaW5wdXQuY2hhckNvZGVBdChteXBvcysrKSAtIDE5MikgPDwgOCkgKyAoaW5wdXQuY2hhckNvZGVBdChteXBvcysrKSkgKyAxOTI7XG4gICAgICAgIHV0aWwucHJpbnRfZGVidWcoXCIyIGJ5dGUgbGVuZ3RoOlwiICsgcGFja2V0X2xlbmd0aCk7XG4gICAgICAgIC8vIDQuMi4yLjQuIFBhcnRpYWwgQm9keSBMZW5ndGhzXG4gICAgICB9IGVsc2UgaWYgKGlucHV0LmNoYXJDb2RlQXQobXlwb3MpID4gMjIzICYmIGlucHV0LmNoYXJDb2RlQXQobXlwb3MpIDwgMjU1KSB7XG4gICAgICAgIHBhY2tldF9sZW5ndGggPSAxIDw8IChpbnB1dC5jaGFyQ29kZUF0KG15cG9zKyspICYgMHgxRik7XG4gICAgICAgIHV0aWwucHJpbnRfZGVidWcoXCI0IGJ5dGUgbGVuZ3RoOlwiICsgcGFja2V0X2xlbmd0aCk7XG4gICAgICAgIC8vIEVFRUssIHdlJ3JlIHJlYWRpbmcgdGhlIGZ1bGwgZGF0YSBoZXJlLi4uXG4gICAgICAgIHZhciBteXBvczIgPSBteXBvcyArIHBhY2tldF9sZW5ndGg7XG4gICAgICAgIGJvZHlkYXRhID0gaW5wdXQuc3Vic3RyaW5nKG15cG9zLCBteXBvcyArIHBhY2tldF9sZW5ndGgpO1xuICAgICAgICB3aGlsZSAodHJ1ZSkge1xuICAgICAgICAgIGlmIChpbnB1dC5jaGFyQ29kZUF0KG15cG9zMikgPCAxOTIpIHtcbiAgICAgICAgICAgIHZhciB0bXBsZW4gPSBpbnB1dC5jaGFyQ29kZUF0KG15cG9zMisrKTtcbiAgICAgICAgICAgIHBhY2tldF9sZW5ndGggKz0gdG1wbGVuO1xuICAgICAgICAgICAgYm9keWRhdGEgKz0gaW5wdXQuc3Vic3RyaW5nKG15cG9zMiwgbXlwb3MyICsgdG1wbGVuKTtcbiAgICAgICAgICAgIG15cG9zMiArPSB0bXBsZW47XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICB9IGVsc2UgaWYgKGlucHV0LmNoYXJDb2RlQXQobXlwb3MyKSA+PSAxOTIgJiYgaW5wdXQuY2hhckNvZGVBdChteXBvczIpIDwgMjI0KSB7XG4gICAgICAgICAgICB2YXIgdG1wbGVuID0gKChpbnB1dC5jaGFyQ29kZUF0KG15cG9zMisrKSAtIDE5MikgPDwgOCkgKyAoaW5wdXQuY2hhckNvZGVBdChteXBvczIrKykpICsgMTkyO1xuICAgICAgICAgICAgcGFja2V0X2xlbmd0aCArPSB0bXBsZW47XG4gICAgICAgICAgICBib2R5ZGF0YSArPSBpbnB1dC5zdWJzdHJpbmcobXlwb3MyLCBteXBvczIgKyB0bXBsZW4pO1xuICAgICAgICAgICAgbXlwb3MyICs9IHRtcGxlbjtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgIH0gZWxzZSBpZiAoaW5wdXQuY2hhckNvZGVBdChteXBvczIpID4gMjIzICYmIGlucHV0LmNoYXJDb2RlQXQobXlwb3MyKSA8IDI1NSkge1xuICAgICAgICAgICAgdmFyIHRtcGxlbiA9IDEgPDwgKGlucHV0LmNoYXJDb2RlQXQobXlwb3MyKyspICYgMHgxRik7XG4gICAgICAgICAgICBwYWNrZXRfbGVuZ3RoICs9IHRtcGxlbjtcbiAgICAgICAgICAgIGJvZHlkYXRhICs9IGlucHV0LnN1YnN0cmluZyhteXBvczIsIG15cG9zMiArIHRtcGxlbik7XG4gICAgICAgICAgICBteXBvczIgKz0gdG1wbGVuO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBteXBvczIrKztcbiAgICAgICAgICAgIHZhciB0bXBsZW4gPSAoaW5wdXQuY2hhckNvZGVBdChteXBvczIrKykgPDwgMjQpIHwgKGlucHV0LmNoYXJDb2RlQXQobXlwb3MyKyspIDw8IDE2KSB8IChpbnB1dFtteXBvczIrK11cbiAgICAgICAgICAgICAgLmNoYXJDb2RlQXQoKSA8PCA4KSB8IGlucHV0LmNoYXJDb2RlQXQobXlwb3MyKyspO1xuICAgICAgICAgICAgYm9keWRhdGEgKz0gaW5wdXQuc3Vic3RyaW5nKG15cG9zMiwgbXlwb3MyICsgdG1wbGVuKTtcbiAgICAgICAgICAgIHBhY2tldF9sZW5ndGggKz0gdG1wbGVuO1xuICAgICAgICAgICAgbXlwb3MyICs9IHRtcGxlbjtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZWFsX3BhY2tldF9sZW5ndGggPSBteXBvczI7XG4gICAgICAgIC8vIDQuMi4yLjMuIEZpdmUtT2N0ZXQgTGVuZ3Roc1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgbXlwb3MrKztcbiAgICAgICAgcGFja2V0X2xlbmd0aCA9IChpbnB1dC5jaGFyQ29kZUF0KG15cG9zKyspIDw8IDI0KSB8IChpbnB1dC5jaGFyQ29kZUF0KG15cG9zKyspIDw8IDE2KSB8IChpbnB1dC5jaGFyQ29kZUF0KG15cG9zKyspIDw8XG4gICAgICAgICAgOCkgfCBpbnB1dC5jaGFyQ29kZUF0KG15cG9zKyspO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIGlmIHRoZXJlIHdhcydudCBhIHBhcnRpYWwgYm9keSBsZW5ndGg6IHVzZSB0aGUgc3BlY2lmaWVkXG4gICAgLy8gcGFja2V0X2xlbmd0aFxuICAgIGlmIChyZWFsX3BhY2tldF9sZW5ndGggPT0gLTEpIHtcbiAgICAgIHJlYWxfcGFja2V0X2xlbmd0aCA9IHBhY2tldF9sZW5ndGg7XG4gICAgfVxuXG4gICAgaWYgKGJvZHlkYXRhID09IG51bGwpIHtcbiAgICAgIGJvZHlkYXRhID0gaW5wdXQuc3Vic3RyaW5nKG15cG9zLCBteXBvcyArIHJlYWxfcGFja2V0X2xlbmd0aCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIHRhZzogdGFnLFxuICAgICAgcGFja2V0OiBib2R5ZGF0YSxcbiAgICAgIG9mZnNldDogbXlwb3MgKyByZWFsX3BhY2tldF9sZW5ndGhcbiAgICB9O1xuICB9XG59XG4iLCJ2YXIgcGFja2V0UGFyc2VyID0gcmVxdWlyZSgnLi9wYWNrZXQuanMnKSxcbiAgcGFja2V0cyA9IHJlcXVpcmUoJy4vYWxsX3BhY2tldHMuanMnKSxcbiAgZW51bXMgPSByZXF1aXJlKCcuLi9lbnVtcy5qcycpO1xuXG4vKipcbiAqIEBjbGFzc1xuICogQGNsYXNzZGVzYyBUaGlzIGNsYXNzIHJlcHJlc2VudHMgYSBsaXN0IG9mIG9wZW5wZ3AgcGFja2V0cy5cbiAqIFRha2UgY2FyZSB3aGVuIGl0ZXJhdGluZyBvdmVyIGl0IC0gdGhlIHBhY2tldHMgdGhlbXNlbHZlc1xuICogYXJlIHN0b3JlZCBhcyBudW1lcmljYWwgaW5kaWNlcy5cbiAqL1xubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiBwYWNrZXRsaXN0KCkge1xuICAvKiogVGhlIG51bWJlciBvZiBwYWNrZXRzIGNvbnRhaW5lZCB3aXRoaW4gdGhlIGxpc3QuXG4gICAqIEByZWFkb25seVxuICAgKiBAdHlwZSB7SW50ZWdlcn0gKi9cbiAgdGhpcy5sZW5ndGggPSAwO1xuXG4gIC8qKlxuICAgKiBSZWFkcyBhIHN0cmVhbSBvZiBiaW5hcnkgZGF0YSBhbmQgaW50ZXJwcmVudHMgaXQgYXMgYSBsaXN0IG9mIHBhY2tldHMuXG4gICAqIEBwYXJhbSB7b3BlbnBncF9ieXRlYXJyYXl9IEFuIGFycmF5IG9mIGJ5dGVzLlxuICAgKi9cbiAgdGhpcy5yZWFkID0gZnVuY3Rpb24oYnl0ZXMpIHtcbiAgICB2YXIgaSA9IDA7XG5cbiAgICB3aGlsZSAoaSA8IGJ5dGVzLmxlbmd0aCkge1xuICAgICAgdmFyIHBhcnNlZCA9IHBhY2tldFBhcnNlci5yZWFkKGJ5dGVzLCBpLCBieXRlcy5sZW5ndGggLSBpKTtcbiAgICAgIGkgPSBwYXJzZWQub2Zmc2V0O1xuXG4gICAgICB2YXIgdGFnID0gZW51bXMucmVhZChlbnVtcy5wYWNrZXQsIHBhcnNlZC50YWcpO1xuICAgICAgdmFyIHBhY2tldCA9IG5ldyBwYWNrZXRzW3RhZ10oKTtcblxuICAgICAgdGhpcy5wdXNoKHBhY2tldCk7XG5cbiAgICAgIHBhY2tldC5yZWFkKHBhcnNlZC5wYWNrZXQpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGVzIGEgYmluYXJ5IHJlcHJlc2VudGF0aW9uIG9mIG9wZW5wZ3Agb2JqZWN0cyBjb250YWluZWQgd2l0aGluIHRoZVxuICAgKiBjbGFzcyBpbnN0YW5jZS5cbiAgICogQHJldHVybnMge29wZW5wZ3BfYnl0ZWFycmF5fSBBbiBhcnJheSBvZiBieXRlcyBjb250YWluaW5nIHZhbGlkIG9wZW5wZ3AgcGFja2V0cy5cbiAgICovXG4gIHRoaXMud3JpdGUgPSBmdW5jdGlvbigpIHtcbiAgICB2YXIgYnl0ZXMgPSAnJztcblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5sZW5ndGg7IGkrKykge1xuICAgICAgdmFyIHBhY2tldGJ5dGVzID0gdGhpc1tpXS53cml0ZSgpO1xuICAgICAgYnl0ZXMgKz0gcGFja2V0UGFyc2VyLndyaXRlSGVhZGVyKHRoaXNbaV0udGFnLCBwYWNrZXRieXRlcy5sZW5ndGgpO1xuICAgICAgYnl0ZXMgKz0gcGFja2V0Ynl0ZXM7XG4gICAgfVxuXG4gICAgcmV0dXJuIGJ5dGVzO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZHMgYSBwYWNrZXQgdG8gdGhlIGxpc3QuIFRoaXMgaXMgdGhlIG9ubHkgc3VwcG9ydGVkIG1ldGhvZCBvZiBkb2luZyBzbztcbiAgICogd3JpdGluZyB0byBwYWNrZXRsaXN0W2ldIGRpcmVjdGx5IHdpbGwgcmVzdWx0IGluIGFuIGVycm9yLlxuICAgKi9cbiAgdGhpcy5wdXNoID0gZnVuY3Rpb24ocGFja2V0KSB7XG4gICAgcGFja2V0LnBhY2tldHMgPSBwYWNrZXQucGFja2V0cyB8fCBuZXcgcGFja2V0bGlzdCgpO1xuXG4gICAgdGhpc1t0aGlzLmxlbmd0aF0gPSBwYWNrZXQ7XG4gICAgdGhpcy5sZW5ndGgrKztcbiAgfVxuXG4gIC8qKlxuICAqIENyZWF0ZXMgYSBuZXcgcGFja2V0TGlzdCB3aXRoIGFsbCBwYWNrZXRzIHRoYXQgcGFzcyB0aGUgdGVzdCBpbXBsZW1lbnRlZCBieSB0aGUgcHJvdmlkZWQgZnVuY3Rpb24uXG4gICovXG4gIHRoaXMuZmlsdGVyID0gZnVuY3Rpb24oY2FsbGJhY2spIHtcblxuICAgIHZhciBmaWx0ZXJlZCA9IG5ldyBwYWNrZXRsaXN0KCk7XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGlmIChjYWxsYmFjayh0aGlzW2ldLCBpLCB0aGlzKSkge1xuICAgICAgICBmaWx0ZXJlZC5wdXNoKHRoaXNbaV0pO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBmaWx0ZXJlZDtcbiAgfVxuXG4gIC8qKlxuICAqIENyZWF0ZXMgYSBuZXcgcGFja2V0TGlzdCB3aXRoIGFsbCBwYWNrZXRzIGZyb20gdGhlIGdpdmVuIHR5cGVzXG4gICovXG4gIHRoaXMuZmlsdGVyQnlUYWcgPSBmdW5jdGlvbigpIHtcbiAgICB2YXIgYXJncyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cyk7XG4gICAgdmFyIGZpbHRlcmVkID0gbmV3IHBhY2tldGxpc3QoKTtcbiAgICB2YXIgdGhhdCA9IHRoaXM7XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGlmIChhcmdzLnNvbWUoZnVuY3Rpb24ocGFja2V0VHlwZSkge3JldHVybiB0aGF0W2ldLnRhZyA9PSBwYWNrZXRUeXBlfSkpIHtcbiAgICAgICAgZmlsdGVyZWQucHVzaCh0aGlzW2ldKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gZmlsdGVyZWQ7XG4gIH0gXG5cbiAgLyoqXG4gICogRXhlY3V0ZXMgdGhlIHByb3ZpZGVkIGNhbGxiYWNrIG9uY2UgZm9yIGVhY2ggZWxlbWVudFxuICAqL1xuICB0aGlzLmZvckVhY2ggPSBmdW5jdGlvbihjYWxsYmFjaykge1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5sZW5ndGg7IGkrKykge1xuICAgICAgY2FsbGJhY2sodGhpc1tpXSk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFRyYXZlcnNlcyBwYWNrZXQgdHJlZSBhbmQgcmV0dXJucyBmaXJzdCBtYXRjaGluZyBwYWNrZXRcbiAgICogQHBhcmFtICB7ZW51bXMucGFja2V0fSB0eXBlIFRoZSBwYWNrZXQgdHlwZVxuICAgKiBAcmV0dXJuIHtwYWNrZXR8bnVsbH0gICAgICBcbiAgICovXG4gIHRoaXMuZmluZFBhY2tldCA9IGZ1bmN0aW9uKHR5cGUpIHtcbiAgICB2YXIgcGFja2V0bGlzdCA9IHRoaXMuZmlsdGVyQnlUYWcodHlwZSk7XG4gICAgaWYgKHBhY2tldGxpc3QubGVuZ3RoKSB7XG4gICAgICByZXR1cm4gcGFja2V0bGlzdFswXTtcbiAgICB9IGVsc2Uge1xuICAgICAgdmFyIGZvdW5kID0gbnVsbDtcbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5sZW5ndGg7IGkrKykge1xuICAgICAgICBpZiAodGhpc1tpXS5wYWNrZXRzLmxlbmd0aCkge1xuICAgICAgICAgIGZvdW5kID0gdGhpc1tpXS5wYWNrZXRzLmZpbmRQYWNrZXQodHlwZSk7XG4gICAgICAgICAgaWYgKGZvdW5kKSByZXR1cm4gZm91bmQ7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxufVxuIiwiLy8gR1BHNEJyb3dzZXJzIC0gQW4gT3BlblBHUCBpbXBsZW1lbnRhdGlvbiBpbiBqYXZhc2NyaXB0XG4vLyBDb3B5cmlnaHQgKEMpIDIwMTEgUmVjdXJpdHkgTGFicyBHbWJIXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3Jcbi8vIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlclxuLy8gdmVyc2lvbiAyLjEgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuLy8gYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2Zcbi8vIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUgR05VXG4vLyBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuLy8gXG4vLyBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFsb25nIHdpdGggdGhpcyBsaWJyYXJ5OyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlXG4vLyBGb3VuZGF0aW9uLCBJbmMuLCA1MSBGcmFua2xpbiBTdHJlZXQsIEZpZnRoIEZsb29yLCBCb3N0b24sIE1BICAwMjExMC0xMzAxICBVU0FcblxudmFyIHV0aWwgPSByZXF1aXJlKCcuLi91dGlsJyksXG4gIHR5cGVfbXBpID0gcmVxdWlyZSgnLi4vdHlwZS9tcGkuanMnKSxcbiAgdHlwZV9rZXlpZCA9IHJlcXVpcmUoJy4uL3R5cGUva2V5aWQuanMnKSxcbiAgZW51bXMgPSByZXF1aXJlKCcuLi9lbnVtcy5qcycpLFxuICBjcnlwdG8gPSByZXF1aXJlKCcuLi9jcnlwdG8nKTtcblxuLyoqXG4gKiBAY2xhc3NcbiAqIEBjbGFzc2Rlc2MgSW1wbGVtZW50YXRpb24gb2YgdGhlIEtleSBNYXRlcmlhbCBQYWNrZXQgKFRhZyA1LDYsNywxNClcbiAqICAgXG4gKiBSRkM0NDgwIDUuNTpcbiAqIEEga2V5IG1hdGVyaWFsIHBhY2tldCBjb250YWlucyBhbGwgdGhlIGluZm9ybWF0aW9uIGFib3V0IGEgcHVibGljIG9yXG4gKiBwcml2YXRlIGtleS4gIFRoZXJlIGFyZSBmb3VyIHZhcmlhbnRzIG9mIHRoaXMgcGFja2V0IHR5cGUsIGFuZCB0d29cbiAqIG1ham9yIHZlcnNpb25zLiAgQ29uc2VxdWVudGx5LCB0aGlzIHNlY3Rpb24gaXMgY29tcGxleC5cbiAqL1xubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiBwYWNrZXRfcHVibGljX2tleSgpIHtcbiAgLyoqIEtleSBjcmVhdGlvbiBkYXRlLlxuICAgKiBAdHlwZSB7RGF0ZX0gKi9cbiAgdGhpcy5jcmVhdGVkID0gbmV3IERhdGUoKTtcbiAgLyoqIEEgbGlzdCBvZiBtdWx0aXByZWNpc2lvbiBpbnRlZ2Vyc1xuICAgKiBAdHlwZSB7b3BlbnBncF90eXBlX21waX0gKi9cbiAgdGhpcy5tcGkgPSBbXTtcbiAgLyoqIFB1YmxpYyBrZXkgYWxnb3JpdGhtXG4gICAqIEB0eXBlIHtvcGVucGdwLnB1YmxpY2tleX0gKi9cbiAgdGhpcy5hbGdvcml0aG0gPSAncnNhX3NpZ24nO1xuXG5cbiAgLyoqXG4gICAqIEludGVybmFsIFBhcnNlciBmb3IgcHVibGljIGtleXMgYXMgc3BlY2lmaWVkIGluIFJGQyA0ODgwIHNlY3Rpb24gXG4gICAqIDUuNS4yIFB1YmxpYy1LZXkgUGFja2V0IEZvcm1hdHNcbiAgICogY2FsbGVkIGJ5IHJlYWRfdGFnJmx0O251bSZndDtcbiAgICogQHBhcmFtIHtTdHJpbmd9IGlucHV0IElucHV0IHN0cmluZyB0byByZWFkIHRoZSBwYWNrZXQgZnJvbVxuICAgKiBAcGFyYW0ge0ludGVnZXJ9IHBvc2l0aW9uIFN0YXJ0IHBvc2l0aW9uIGZvciB0aGUgcGFyc2VyXG4gICAqIEBwYXJhbSB7SW50ZWdlcn0gbGVuIExlbmd0aCBvZiB0aGUgcGFja2V0IG9yIHJlbWFpbmluZyBsZW5ndGggb2YgaW5wdXRcbiAgICogQHJldHVybiB7T2JqZWN0fSBUaGlzIG9iamVjdCB3aXRoIGF0dHJpYnV0ZXMgc2V0IGJ5IHRoZSBwYXJzZXJcbiAgICovXG4gIHRoaXMucmVhZFB1YmxpY0tleSA9IHRoaXMucmVhZCA9IGZ1bmN0aW9uKGJ5dGVzKSB7XG4gICAgLy8gQSBvbmUtb2N0ZXQgdmVyc2lvbiBudW1iZXIgKDMgb3IgNCkuXG4gICAgdmFyIHZlcnNpb24gPSBieXRlcy5jaGFyQ29kZUF0KDApO1xuXG4gICAgaWYgKHZlcnNpb24gPT0gNCkge1xuICAgICAgLy8gLSBBIGZvdXItb2N0ZXQgbnVtYmVyIGRlbm90aW5nIHRoZSB0aW1lIHRoYXQgdGhlIGtleSB3YXMgY3JlYXRlZC5cbiAgICAgIHRoaXMuY3JlYXRlZCA9IHV0aWwucmVhZERhdGUoYnl0ZXMuc3Vic3RyKDEsIDQpKTtcblxuICAgICAgLy8gLSBBIG9uZS1vY3RldCBudW1iZXIgZGVub3RpbmcgdGhlIHB1YmxpYy1rZXkgYWxnb3JpdGhtIG9mIHRoaXMga2V5LlxuICAgICAgdGhpcy5hbGdvcml0aG0gPSBlbnVtcy5yZWFkKGVudW1zLnB1YmxpY0tleSwgYnl0ZXMuY2hhckNvZGVBdCg1KSk7XG5cbiAgICAgIHZhciBtcGljb3VudCA9IGNyeXB0by5nZXRQdWJsaWNNcGlDb3VudCh0aGlzLmFsZ29yaXRobSk7XG4gICAgICB0aGlzLm1waSA9IFtdO1xuXG4gICAgICB2YXIgYm1waSA9IGJ5dGVzLnN1YnN0cig2KTtcbiAgICAgIHZhciBwID0gMDtcblxuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBtcGljb3VudCAmJiBwIDwgYm1waS5sZW5ndGg7IGkrKykge1xuXG4gICAgICAgIHRoaXMubXBpW2ldID0gbmV3IHR5cGVfbXBpKCk7XG5cbiAgICAgICAgcCArPSB0aGlzLm1waVtpXS5yZWFkKGJtcGkuc3Vic3RyKHApKVxuXG4gICAgICAgIGlmIChwID4gYm1waS5sZW5ndGgpXG4gICAgICAgICAgdXRpbC5wcmludF9lcnJvcihcIm9wZW5wZ3AucGFja2V0LmtleW1hdGVyaWFsLmpzXFxuXCIgKyAnZXJyb3IgcmVhZGluZyBNUEkgQDonICsgcCk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBwICsgNjtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdWZXJzaW9uICcgKyB2ZXJzaW9uICsgJyBvZiB0aGUga2V5IHBhY2tldCBpcyB1bnN1cHBvcnRlZC4nKTtcbiAgICB9XG4gIH1cblxuICAvKlxuICAgKiBTYW1lIGFzIHdyaXRlX3ByaXZhdGVfa2V5LCBidXQgaGFzIGxlc3MgaW5mb3JtYXRpb24gYmVjYXVzZSBvZiBcbiAgICogcHVibGljIGtleS5cbiAgICogQHBhcmFtIHtJbnRlZ2VyfSBrZXlUeXBlIEZvbGxvd3MgdGhlIE9wZW5QR1AgYWxnb3JpdGhtIHN0YW5kYXJkLCBcbiAgICogSUUgMSBjb3JyZXNwb25kcyB0byBSU0EuXG4gICAqIEBwYXJhbSB7UlNBLmtleU9iamVjdH0ga2V5XG4gICAqIEBwYXJhbSB0aW1lUGFja2V0XG4gICAqIEByZXR1cm4ge09iamVjdH0ge2JvZHk6IFtzdHJpbmddT3BlblBHUCBwYWNrZXQgYm9keSBjb250ZW50cywgXG4gICAqIGhlYWRlcjogW3N0cmluZ10gT3BlblBHUCBwYWNrZXQgaGVhZGVyLCBzdHJpbmc6IFtzdHJpbmddIGhlYWRlcitib2R5fVxuICAgKi9cbiAgdGhpcy53cml0ZVB1YmxpY0tleSA9IHRoaXMud3JpdGUgPSBmdW5jdGlvbigpIHtcbiAgICAvLyBWZXJzaW9uXG4gICAgdmFyIHJlc3VsdCA9IFN0cmluZy5mcm9tQ2hhckNvZGUoNCk7XG4gICAgcmVzdWx0ICs9IHV0aWwud3JpdGVEYXRlKHRoaXMuY3JlYXRlZCk7XG4gICAgcmVzdWx0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoZW51bXMud3JpdGUoZW51bXMucHVibGljS2V5LCB0aGlzLmFsZ29yaXRobSkpO1xuXG4gICAgdmFyIG1waWNvdW50ID0gY3J5cHRvLmdldFB1YmxpY01waUNvdW50KHRoaXMuYWxnb3JpdGhtKTtcblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbXBpY291bnQ7IGkrKykge1xuICAgICAgcmVzdWx0ICs9IHRoaXMubXBpW2ldLndyaXRlKCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIC8vIFdyaXRlIGFuIG9sZCB2ZXJzaW9uIHBhY2tldCAtIGl0J3MgdXNlZCBieSBzb21lIG9mIHRoZSBpbnRlcm5hbCByb3V0aW5lcy5cbiAgdGhpcy53cml0ZU9sZCA9IGZ1bmN0aW9uKCkge1xuICAgIHZhciBieXRlcyA9IHRoaXMud3JpdGVQdWJsaWNLZXkoKTtcblxuICAgIHJldHVybiBTdHJpbmcuZnJvbUNoYXJDb2RlKDB4OTkpICtcbiAgICAgIHV0aWwud3JpdGVOdW1iZXIoYnl0ZXMubGVuZ3RoLCAyKSArXG4gICAgICBieXRlcztcbiAgfVxuXG4gIC8qKlxuICAgKiBDYWxjdWxhdGVzIHRoZSBrZXkgaWQgb2YgdGhlIGtleSBcbiAgICogQHJldHVybiB7U3RyaW5nfSBBIDggYnl0ZSBrZXkgaWRcbiAgICovXG4gIHRoaXMuZ2V0S2V5SWQgPSBmdW5jdGlvbigpIHtcbiAgICB2YXIga2V5aWQgPSBuZXcgdHlwZV9rZXlpZCgpO1xuICAgIGtleWlkLnJlYWQodGhpcy5nZXRGaW5nZXJwcmludCgpLnN1YnN0cigxMiwgOCkpO1xuICAgIHJldHVybiBrZXlpZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBDYWxjdWxhdGVzIHRoZSBmaW5nZXJwcmludCBvZiB0aGUga2V5XG4gICAqIEByZXR1cm4ge1N0cmluZ30gQSBzdHJpbmcgY29udGFpbmluZyB0aGUgZmluZ2VycHJpbnRcbiAgICovXG4gIHRoaXMuZ2V0RmluZ2VycHJpbnQgPSBmdW5jdGlvbigpIHtcbiAgICB2YXIgdG9IYXNoID0gdGhpcy53cml0ZU9sZCgpO1xuICAgIHJldHVybiBjcnlwdG8uaGFzaC5zaGExKHRvSGFzaCwgdG9IYXNoLmxlbmd0aCk7XG4gIH1cblxufVxuIiwiLy8gR1BHNEJyb3dzZXJzIC0gQW4gT3BlblBHUCBpbXBsZW1lbnRhdGlvbiBpbiBqYXZhc2NyaXB0XG4vLyBDb3B5cmlnaHQgKEMpIDIwMTEgUmVjdXJpdHkgTGFicyBHbWJIXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3Jcbi8vIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlclxuLy8gdmVyc2lvbiAyLjEgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuLy8gYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2Zcbi8vIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUgR05VXG4vLyBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuLy8gXG4vLyBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFsb25nIHdpdGggdGhpcyBsaWJyYXJ5OyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlXG4vLyBGb3VuZGF0aW9uLCBJbmMuLCA1MSBGcmFua2xpbiBTdHJlZXQsIEZpZnRoIEZsb29yLCBCb3N0b24sIE1BICAwMjExMC0xMzAxICBVU0FcblxudmFyIHR5cGVfa2V5aWQgPSByZXF1aXJlKCcuLi90eXBlL2tleWlkLmpzJyksXG4gIHV0aWwgPSByZXF1aXJlKCcuLi91dGlsJyksXG4gIHR5cGVfbXBpID0gcmVxdWlyZSgnLi4vdHlwZS9tcGkuanMnKSxcbiAgZW51bXMgPSByZXF1aXJlKCcuLi9lbnVtcy5qcycpLFxuICBjcnlwdG8gPSByZXF1aXJlKCcuLi9jcnlwdG8nKTtcblxuXG4vKipcbiAqIEBjbGFzc1xuICogQGNsYXNzZGVzYyBQdWJsaWMtS2V5IEVuY3J5cHRlZCBTZXNzaW9uIEtleSBQYWNrZXRzIChUYWcgMSlcbiAqIFxuICogUkZDNDg4MCA1LjE6IEEgUHVibGljLUtleSBFbmNyeXB0ZWQgU2Vzc2lvbiBLZXkgcGFja2V0IGhvbGRzIHRoZSBzZXNzaW9uIGtleVxuICogdXNlZCB0byBlbmNyeXB0IGEgbWVzc2FnZS4gWmVybyBvciBtb3JlIFB1YmxpYy1LZXkgRW5jcnlwdGVkIFNlc3Npb24gS2V5XG4gKiBwYWNrZXRzIGFuZC9vciBTeW1tZXRyaWMtS2V5IEVuY3J5cHRlZCBTZXNzaW9uIEtleSBwYWNrZXRzIG1heSBwcmVjZWRlIGFcbiAqIFN5bW1ldHJpY2FsbHkgRW5jcnlwdGVkIERhdGEgUGFja2V0LCB3aGljaCBob2xkcyBhbiBlbmNyeXB0ZWQgbWVzc2FnZS4gVGhlXG4gKiBtZXNzYWdlIGlzIGVuY3J5cHRlZCB3aXRoIHRoZSBzZXNzaW9uIGtleSwgYW5kIHRoZSBzZXNzaW9uIGtleSBpcyBpdHNlbGZcbiAqIGVuY3J5cHRlZCBhbmQgc3RvcmVkIGluIHRoZSBFbmNyeXB0ZWQgU2Vzc2lvbiBLZXkgcGFja2V0KHMpLiBUaGVcbiAqIFN5bW1ldHJpY2FsbHkgRW5jcnlwdGVkIERhdGEgUGFja2V0IGlzIHByZWNlZGVkIGJ5IG9uZSBQdWJsaWMtS2V5IEVuY3J5cHRlZFxuICogU2Vzc2lvbiBLZXkgcGFja2V0IGZvciBlYWNoIE9wZW5QR1Aga2V5IHRvIHdoaWNoIHRoZSBtZXNzYWdlIGlzIGVuY3J5cHRlZC5cbiAqIFRoZSByZWNpcGllbnQgb2YgdGhlIG1lc3NhZ2UgZmluZHMgYSBzZXNzaW9uIGtleSB0aGF0IGlzIGVuY3J5cHRlZCB0byB0aGVpclxuICogcHVibGljIGtleSwgZGVjcnlwdHMgdGhlIHNlc3Npb24ga2V5LCBhbmQgdGhlbiB1c2VzIHRoZSBzZXNzaW9uIGtleSB0b1xuICogZGVjcnlwdCB0aGUgbWVzc2FnZS5cbiAqL1xubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiBwYWNrZXRfcHVibGljX2tleV9lbmNyeXB0ZWRfc2Vzc2lvbl9rZXkoKSB7XG4gIHRoaXMudmVyc2lvbiA9IDM7XG5cbiAgdGhpcy5wdWJsaWNLZXlJZCA9IG5ldyB0eXBlX2tleWlkKCk7XG4gIHRoaXMucHVibGljS2V5QWxnb3JpdGhtID0gJ3JzYV9lbmNyeXB0JztcblxuICB0aGlzLnNlc3Npb25LZXkgPSBudWxsO1xuICB0aGlzLnNlc3Npb25LZXlBbGdvcml0aG0gPSAnYWVzMjU2JztcblxuICAvKiogQHR5cGUge29wZW5wZ3BfdHlwZV9tcGlbXX0gKi9cbiAgdGhpcy5lbmNyeXB0ZWQgPSBbXTtcblxuICAvKipcbiAgICogUGFyc2luZyBmdW5jdGlvbiBmb3IgYSBwdWJsaWNrZXkgZW5jcnlwdGVkIHNlc3Npb24ga2V5IHBhY2tldCAodGFnIDEpLlxuICAgKiBcbiAgICogQHBhcmFtIHtTdHJpbmd9IGlucHV0IFBheWxvYWQgb2YgYSB0YWcgMSBwYWNrZXRcbiAgICogQHBhcmFtIHtJbnRlZ2VyfSBwb3NpdGlvbiBQb3NpdGlvbiB0byBzdGFydCByZWFkaW5nIGZyb20gdGhlIGlucHV0IHN0cmluZ1xuICAgKiBAcGFyYW0ge0ludGVnZXJ9IGxlbiBMZW5ndGggb2YgdGhlIHBhY2tldCBvciB0aGUgcmVtYWluaW5nIGxlbmd0aCBvZlxuICAgKiAgICAgICAgICAgIGlucHV0IGF0IHBvc2l0aW9uXG4gICAqIEByZXR1cm4ge29wZW5wZ3BfcGFja2V0X2VuY3J5cHRlZGRhdGF9IE9iamVjdCByZXByZXNlbnRhdGlvblxuICAgKi9cbiAgdGhpcy5yZWFkID0gZnVuY3Rpb24oYnl0ZXMpIHtcblxuICAgIHRoaXMudmVyc2lvbiA9IGJ5dGVzLmNoYXJDb2RlQXQoMCk7XG4gICAgdGhpcy5wdWJsaWNLZXlJZC5yZWFkKGJ5dGVzLnN1YnN0cigxKSk7XG4gICAgdGhpcy5wdWJsaWNLZXlBbGdvcml0aG0gPSBlbnVtcy5yZWFkKGVudW1zLnB1YmxpY0tleSwgYnl0ZXMuY2hhckNvZGVBdCg5KSk7XG5cbiAgICB2YXIgaSA9IDEwO1xuXG4gICAgdmFyIGludGVnZXJDb3VudCA9IChmdW5jdGlvbihhbGdvKSB7XG4gICAgICBzd2l0Y2ggKGFsZ28pIHtcbiAgICAgICAgY2FzZSAncnNhX2VuY3J5cHQnOlxuICAgICAgICBjYXNlICdyc2FfZW5jcnlwdF9zaWduJzpcbiAgICAgICAgICByZXR1cm4gMTtcblxuICAgICAgICBjYXNlICdlbGdhbWFsJzpcbiAgICAgICAgICByZXR1cm4gMjtcblxuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgYWxnb3JpdGhtLlwiKTtcbiAgICAgIH1cbiAgICB9KSh0aGlzLnB1YmxpY0tleUFsZ29yaXRobSk7XG5cbiAgICB0aGlzLmVuY3J5cHRlZCA9IFtdO1xuXG4gICAgZm9yICh2YXIgaiA9IDA7IGogPCBpbnRlZ2VyQ291bnQ7IGorKykge1xuICAgICAgdmFyIG1waSA9IG5ldyB0eXBlX21waSgpO1xuICAgICAgaSArPSBtcGkucmVhZChieXRlcy5zdWJzdHIoaSkpO1xuICAgICAgdGhpcy5lbmNyeXB0ZWQucHVzaChtcGkpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGUgYSBzdHJpbmcgcmVwcmVzZW50YXRpb24gb2YgYSB0YWcgMSBwYWNrZXRcbiAgICogXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBwdWJsaWNLZXlJZFxuICAgKiAgICAgICAgICAgICBUaGUgcHVibGljIGtleSBpZCBjb3JyZXNwb25kaW5nIHRvIHB1YmxpY01QSXMga2V5IGFzIHN0cmluZ1xuICAgKiBAcGFyYW0ge29wZW5wZ3BfdHlwZV9tcGlbXX0gcHVibGljTVBJc1xuICAgKiAgICAgICAgICAgIE11bHRpcHJlY2lzaW9uIGludGVnZXIgb2JqZWN0cyBkZXNjcmliaW5nIHRoZSBwdWJsaWMga2V5XG4gICAqIEBwYXJhbSB7SW50ZWdlcn0gcHViYWxnb1xuICAgKiAgICAgICAgICAgIFRoZSBjb3JyZXNwb25kaW5nIHB1YmxpYyBrZXkgYWxnb3JpdGhtIC8vIFNlZSBSRkM0ODgwIDkuMVxuICAgKiBAcGFyYW0ge0ludGVnZXJ9IHN5bW1hbGdvXG4gICAqICAgICAgICAgICAgVGhlIHN5bW1ldHJpYyBjaXBoZXIgYWxnb3JpdGhtIHVzZWQgdG8gZW5jcnlwdCB0aGUgZGF0YSBcbiAgICogICAgICAgICAgICB3aXRoaW4gYW4gZW5jcnlwdGVkZGF0YXBhY2tldCBvciBlbmNyeXB0ZWRpbnRlZ3JpdHktXG4gICAqICAgICAgICAgICAgcHJvdGVjdGVkZGF0YXBhY2tldCBcbiAgICogICAgICAgICAgICBmb2xsb3dpbmcgdGhpcyBwYWNrZXQgLy9TZWUgUkZDNDg4MCA5LjJcbiAgICogQHBhcmFtIHtTdHJpbmd9IHNlc3Npb25rZXlcbiAgICogICAgICAgICAgICBBIHN0cmluZyBvZiByYW5kb21ieXRlcyByZXByZXNlbnRpbmcgdGhlIHNlc3Npb24ga2V5XG4gICAqIEByZXR1cm4ge1N0cmluZ30gVGhlIHN0cmluZyByZXByZXNlbnRhdGlvblxuICAgKi9cbiAgdGhpcy53cml0ZSA9IGZ1bmN0aW9uKCkge1xuXG4gICAgdmFyIHJlc3VsdCA9IFN0cmluZy5mcm9tQ2hhckNvZGUodGhpcy52ZXJzaW9uKTtcbiAgICByZXN1bHQgKz0gdGhpcy5wdWJsaWNLZXlJZC53cml0ZSgpO1xuICAgIHJlc3VsdCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKFxuICAgICAgZW51bXMud3JpdGUoZW51bXMucHVibGljS2V5LCB0aGlzLnB1YmxpY0tleUFsZ29yaXRobSkpO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLmVuY3J5cHRlZC5sZW5ndGg7IGkrKykge1xuICAgICAgcmVzdWx0ICs9IHRoaXMuZW5jcnlwdGVkW2ldLndyaXRlKClcbiAgICB9XG5cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG5cbiAgdGhpcy5lbmNyeXB0ID0gZnVuY3Rpb24oa2V5KSB7XG4gICAgdmFyIGRhdGEgPSBTdHJpbmcuZnJvbUNoYXJDb2RlKFxuICAgICAgZW51bXMud3JpdGUoZW51bXMuc3ltbWV0cmljLCB0aGlzLnNlc3Npb25LZXlBbGdvcml0aG0pKTtcblxuICAgIGRhdGEgKz0gdGhpcy5zZXNzaW9uS2V5O1xuICAgIHZhciBjaGVja3N1bSA9IHV0aWwuY2FsY19jaGVja3N1bSh0aGlzLnNlc3Npb25LZXkpO1xuICAgIGRhdGEgKz0gdXRpbC53cml0ZU51bWJlcihjaGVja3N1bSwgMik7XG5cbiAgICB2YXIgbXBpID0gbmV3IHR5cGVfbXBpKCk7XG4gICAgbXBpLmZyb21CeXRlcyhjcnlwdG8ucGtjczEuZW1lLmVuY29kZShcbiAgICAgIGRhdGEsXG4gICAgICBrZXkubXBpWzBdLmJ5dGVMZW5ndGgoKSkpO1xuXG4gICAgdGhpcy5lbmNyeXB0ZWQgPSBjcnlwdG8ucHVibGljS2V5RW5jcnlwdChcbiAgICAgIHRoaXMucHVibGljS2V5QWxnb3JpdGhtLFxuICAgICAga2V5Lm1waSxcbiAgICAgIG1waSk7XG4gIH1cblxuICAvKipcbiAgICogRGVjcnlwdHMgdGhlIHNlc3Npb24ga2V5IChvbmx5IGZvciBwdWJsaWMga2V5IGVuY3J5cHRlZCBzZXNzaW9uIGtleVxuICAgKiBwYWNrZXRzICh0YWcgMSlcbiAgICogXG4gICAqIEBwYXJhbSB7b3BlbnBncF9tc2dfbWVzc2FnZX0gbXNnXG4gICAqICAgICAgICAgICAgVGhlIG1lc3NhZ2Ugb2JqZWN0ICh3aXRoIG1lbWJlciBlbmNyeXB0ZWREYXRhXG4gICAqIEBwYXJhbSB7b3BlbnBncF9tc2dfcHJpdmF0ZWtleX0ga2V5XG4gICAqICAgICAgICAgICAgUHJpdmF0ZSBrZXkgd2l0aCBzZWNNUElzIHVubG9ja2VkXG4gICAqIEByZXR1cm4ge1N0cmluZ30gVGhlIHVuZW5jcnlwdGVkIHNlc3Npb24ga2V5XG4gICAqL1xuICB0aGlzLmRlY3J5cHQgPSBmdW5jdGlvbihrZXkpIHtcbiAgICB2YXIgcmVzdWx0ID0gY3J5cHRvLnB1YmxpY0tleURlY3J5cHQoXG4gICAgICB0aGlzLnB1YmxpY0tleUFsZ29yaXRobSxcbiAgICAgIGtleS5tcGksXG4gICAgICB0aGlzLmVuY3J5cHRlZCkudG9CeXRlcygpO1xuXG4gICAgdmFyIGNoZWNrc3VtID0gdXRpbC5yZWFkTnVtYmVyKHJlc3VsdC5zdWJzdHIocmVzdWx0Lmxlbmd0aCAtIDIpKTtcblxuICAgIHZhciBkZWNvZGVkID0gY3J5cHRvLnBrY3MxLmVtZS5kZWNvZGUoXG4gICAgICByZXN1bHQsXG4gICAgICBrZXkubXBpWzBdLmJ5dGVMZW5ndGgoKSk7XG5cbiAgICB2YXIga2V5ID0gZGVjb2RlZC5zdWJzdHJpbmcoMSwgZGVjb2RlZC5sZW5ndGggLSAyKTtcblxuICAgIGlmIChjaGVja3N1bSAhPSB1dGlsLmNhbGNfY2hlY2tzdW0oa2V5KSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdDaGVja3N1bSBtaXNtYXRjaCcpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLnNlc3Npb25LZXkgPSBrZXk7XG4gICAgICB0aGlzLnNlc3Npb25LZXlBbGdvcml0aG0gPVxuICAgICAgICBlbnVtcy5yZWFkKGVudW1zLnN5bW1ldHJpYywgZGVjb2RlZC5jaGFyQ29kZUF0KDApKTtcbiAgICB9XG4gIH1cbn07XG4iLCIvLyBHUEc0QnJvd3NlcnMgLSBBbiBPcGVuUEdQIGltcGxlbWVudGF0aW9uIGluIGphdmFzY3JpcHRcbi8vIENvcHlyaWdodCAoQykgMjAxMSBSZWN1cml0eSBMYWJzIEdtYkhcbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vclxuLy8gbW9kaWZ5IGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyXG4vLyB2ZXJzaW9uIDIuMSBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4vLyBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuLy8gTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZSBHTlVcbi8vIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG4vLyBcbi8vIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYWxvbmcgd2l0aCB0aGlzIGxpYnJhcnk7IGlmIG5vdCwgd3JpdGUgdG8gdGhlIEZyZWUgU29mdHdhcmVcbi8vIEZvdW5kYXRpb24sIEluYy4sIDUxIEZyYW5rbGluIFN0cmVldCwgRmlmdGggRmxvb3IsIEJvc3RvbiwgTUEgIDAyMTEwLTEzMDEgIFVTQVxuXG52YXIgcHVibGljX2tleSA9IHJlcXVpcmUoJy4vcHVibGljX2tleS5qcycpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIHB1YmxpY19zdWJrZXkoKSB7XG4gIHB1YmxpY19rZXkuY2FsbCh0aGlzKTtcbn1cbiIsIi8vIEdQRzRCcm93c2VycyAtIEFuIE9wZW5QR1AgaW1wbGVtZW50YXRpb24gaW4gamF2YXNjcmlwdFxuLy8gQ29weXJpZ2h0IChDKSAyMDExIFJlY3VyaXR5IExhYnMgR21iSFxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yXG4vLyBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uOyBlaXRoZXJcbi8vIHZlcnNpb24gMi4xIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbi8vIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4vLyBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlIEdOVVxuLy8gTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cbi8vIFxuLy8gWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhbG9uZyB3aXRoIHRoaXMgbGlicmFyeTsgaWYgbm90LCB3cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZVxuLy8gRm91bmRhdGlvbiwgSW5jLiwgNTEgRnJhbmtsaW4gU3RyZWV0LCBGaWZ0aCBGbG9vciwgQm9zdG9uLCBNQSAgMDIxMTAtMTMwMSAgVVNBXG5cbnZhciBwdWJsaWNLZXkgPSByZXF1aXJlKCcuL3B1YmxpY19rZXkuanMnKSxcbiAgZW51bXMgPSByZXF1aXJlKCcuLi9lbnVtcy5qcycpLFxuICB1dGlsID0gcmVxdWlyZSgnLi4vdXRpbCcpLFxuICBjcnlwdG8gPSByZXF1aXJlKCcuLi9jcnlwdG8nKSxcbiAgdHlwZV9tcGkgPSByZXF1aXJlKCcuLi90eXBlL21waS5qcycpLFxuICB0eXBlX3MyayA9IHJlcXVpcmUoJy4uL3R5cGUvczJrLmpzJyk7XG5cbi8qKlxuICogQGNsYXNzXG4gKiBAY2xhc3NkZXNjIEltcGxlbWVudGF0aW9uIG9mIHRoZSBLZXkgTWF0ZXJpYWwgUGFja2V0IChUYWcgNSw2LDcsMTQpXG4gKiAgIFxuICogUkZDNDQ4MCA1LjU6XG4gKiBBIGtleSBtYXRlcmlhbCBwYWNrZXQgY29udGFpbnMgYWxsIHRoZSBpbmZvcm1hdGlvbiBhYm91dCBhIHB1YmxpYyBvclxuICogcHJpdmF0ZSBrZXkuICBUaGVyZSBhcmUgZm91ciB2YXJpYW50cyBvZiB0aGlzIHBhY2tldCB0eXBlLCBhbmQgdHdvXG4gKiBtYWpvciB2ZXJzaW9ucy4gIENvbnNlcXVlbnRseSwgdGhpcyBzZWN0aW9uIGlzIGNvbXBsZXguXG4gKi9cbmZ1bmN0aW9uIHBhY2tldF9zZWNyZXRfa2V5KCkge1xuICBwdWJsaWNLZXkuY2FsbCh0aGlzKTtcbiAgLy8gZW5jcnlwdGVkIHNlY3JldC1rZXkgZGF0YVxuICB0aGlzLmVuY3J5cHRlZCA9IG51bGw7XG4gIC8vIGluZGljYXRvciBpZiBzZWNyZXQta2V5IGRhdGEgaXMgYXZhaWxhYmxlIGluIGRlY3J5cHRlZCBmb3JtXG4gIHRoaXMuaXNEZWNyeXB0ZWQgPSBmYWxzZTtcblxuXG4gIGZ1bmN0aW9uIGdldF9oYXNoX2xlbihoYXNoKSB7XG4gICAgaWYgKGhhc2ggPT0gJ3NoYTEnKVxuICAgICAgcmV0dXJuIDIwO1xuICAgIGVsc2VcbiAgICAgIHJldHVybiAyO1xuICB9XG5cbiAgZnVuY3Rpb24gZ2V0X2hhc2hfZm4oaGFzaCkge1xuICAgIGlmIChoYXNoID09ICdzaGExJylcbiAgICAgIHJldHVybiBjcnlwdG8uaGFzaC5zaGExO1xuICAgIGVsc2VcbiAgICAgIHJldHVybiBmdW5jdGlvbihjKSB7XG4gICAgICAgIHJldHVybiB1dGlsLndyaXRlTnVtYmVyKHV0aWwuY2FsY19jaGVja3N1bShjKSwgMik7XG4gICAgfTtcbiAgfVxuXG4gIC8vIEhlbHBlciBmdW5jdGlvblxuXG4gIGZ1bmN0aW9uIHBhcnNlX2NsZWFydGV4dF9tcGkoaGFzaF9hbGdvcml0aG0sIGNsZWFydGV4dCwgYWxnb3JpdGhtKSB7XG4gICAgdmFyIGhhc2hsZW4gPSBnZXRfaGFzaF9sZW4oaGFzaF9hbGdvcml0aG0pLFxuICAgICAgaGFzaGZuID0gZ2V0X2hhc2hfZm4oaGFzaF9hbGdvcml0aG0pO1xuXG4gICAgdmFyIGhhc2h0ZXh0ID0gY2xlYXJ0ZXh0LnN1YnN0cihjbGVhcnRleHQubGVuZ3RoIC0gaGFzaGxlbik7XG4gICAgY2xlYXJ0ZXh0ID0gY2xlYXJ0ZXh0LnN1YnN0cigwLCBjbGVhcnRleHQubGVuZ3RoIC0gaGFzaGxlbik7XG5cbiAgICB2YXIgaGFzaCA9IGhhc2hmbihjbGVhcnRleHQpO1xuXG4gICAgaWYgKGhhc2ggIT0gaGFzaHRleHQpXG4gICAgICByZXR1cm4gbmV3IEVycm9yKFwiSGFzaCBtaXNtYXRjaC5cIik7XG5cbiAgICB2YXIgbXBpcyA9IGNyeXB0by5nZXRQcml2YXRlTXBpQ291bnQoYWxnb3JpdGhtKTtcblxuICAgIHZhciBqID0gMDtcbiAgICB2YXIgbXBpID0gW107XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IG1waXMgJiYgaiA8IGNsZWFydGV4dC5sZW5ndGg7IGkrKykge1xuICAgICAgbXBpW2ldID0gbmV3IHR5cGVfbXBpKCk7XG4gICAgICBqICs9IG1waVtpXS5yZWFkKGNsZWFydGV4dC5zdWJzdHIoaikpO1xuICAgIH1cblxuICAgIHJldHVybiBtcGk7XG4gIH1cblxuICBmdW5jdGlvbiB3cml0ZV9jbGVhcnRleHRfbXBpKGhhc2hfYWxnb3JpdGhtLCBhbGdvcml0aG0sIG1waSkge1xuICAgIHZhciBieXRlcyA9ICcnO1xuICAgIHZhciBkaXNjYXJkID0gY3J5cHRvLmdldFB1YmxpY01waUNvdW50KGFsZ29yaXRobSk7XG5cbiAgICBmb3IgKHZhciBpID0gZGlzY2FyZDsgaSA8IG1waS5sZW5ndGg7IGkrKykge1xuICAgICAgYnl0ZXMgKz0gbXBpW2ldLndyaXRlKCk7XG4gICAgfVxuXG5cbiAgICBieXRlcyArPSBnZXRfaGFzaF9mbihoYXNoX2FsZ29yaXRobSkoYnl0ZXMpO1xuXG4gICAgcmV0dXJuIGJ5dGVzO1xuICB9XG5cblxuICAvLyA1LjUuMy4gIFNlY3JldC1LZXkgUGFja2V0IEZvcm1hdHNcblxuICAvKipcbiAgICogSW50ZXJuYWwgcGFyc2VyIGZvciBwcml2YXRlIGtleXMgYXMgc3BlY2lmaWVkIGluIFJGQyA0ODgwIHNlY3Rpb24gNS41LjNcbiAgICogQHBhcmFtIHtTdHJpbmd9IGJ5dGVzIElucHV0IHN0cmluZyB0byByZWFkIHRoZSBwYWNrZXQgZnJvbVxuICAgKi9cbiAgdGhpcy5yZWFkID0gZnVuY3Rpb24oYnl0ZXMpIHtcbiAgICAvLyAtIEEgUHVibGljLUtleSBvciBQdWJsaWMtU3Via2V5IHBhY2tldCwgYXMgZGVzY3JpYmVkIGFib3ZlLlxuICAgIHZhciBsZW4gPSB0aGlzLnJlYWRQdWJsaWNLZXkoYnl0ZXMpO1xuXG4gICAgYnl0ZXMgPSBieXRlcy5zdWJzdHIobGVuKTtcblxuXG4gICAgLy8gLSBPbmUgb2N0ZXQgaW5kaWNhdGluZyBzdHJpbmctdG8ta2V5IHVzYWdlIGNvbnZlbnRpb25zLiAgWmVyb1xuICAgIC8vICAgaW5kaWNhdGVzIHRoYXQgdGhlIHNlY3JldC1rZXkgZGF0YSBpcyBub3QgZW5jcnlwdGVkLiAgMjU1IG9yIDI1NFxuICAgIC8vICAgaW5kaWNhdGVzIHRoYXQgYSBzdHJpbmctdG8ta2V5IHNwZWNpZmllciBpcyBiZWluZyBnaXZlbi4gIEFueVxuICAgIC8vICAgb3RoZXIgdmFsdWUgaXMgYSBzeW1tZXRyaWMta2V5IGVuY3J5cHRpb24gYWxnb3JpdGhtIGlkZW50aWZpZXIuXG4gICAgdmFyIGlzRW5jcnlwdGVkID0gYnl0ZXMuY2hhckNvZGVBdCgwKTtcblxuICAgIGlmIChpc0VuY3J5cHRlZCkge1xuICAgICAgdGhpcy5lbmNyeXB0ZWQgPSBieXRlcztcbiAgICB9IGVsc2Uge1xuXG4gICAgICAvLyAtIFBsYWluIG9yIGVuY3J5cHRlZCBtdWx0aXByZWNpc2lvbiBpbnRlZ2VycyBjb21wcmlzaW5nIHRoZSBzZWNyZXRcbiAgICAgIC8vICAga2V5IGRhdGEuICBUaGVzZSBhbGdvcml0aG0tc3BlY2lmaWMgZmllbGRzIGFyZSBhcyBkZXNjcmliZWRcbiAgICAgIC8vICAgYmVsb3cuXG4gICAgICB2YXIgcGFyc2VkTVBJID0gcGFyc2VfY2xlYXJ0ZXh0X21waSgnbW9kJywgYnl0ZXMuc3Vic3RyKDEpLCB0aGlzLmFsZ29yaXRobSk7XG4gICAgICBpZiAocGFyc2VkTVBJIGluc3RhbmNlb2YgRXJyb3IpXG4gICAgICAgIHRocm93IHBhcnNlZE1QSTtcbiAgICAgIHRoaXMubXBpID0gdGhpcy5tcGkuY29uY2F0KHBhcnNlZE1QSSk7XG4gICAgICB0aGlzLmlzRGVjcnlwdGVkID0gdHJ1ZTtcbiAgICB9XG5cbiAgfTtcblxuICAvKiogQ3JlYXRlcyBhbiBPcGVuUEdQIGtleSBwYWNrZXQgZm9yIHRoZSBnaXZlbiBrZXkuXG4gICAgKiBAcmV0dXJuIHtTdHJpbmd9IEEgc3RyaW5nIG9mIGJ5dGVzIGNvbnRhaW5pbmcgdGhlIHNlY3JldCBrZXkgT3BlblBHUCBwYWNrZXRcbiAgICAqL1xuICB0aGlzLndyaXRlID0gZnVuY3Rpb24oKSB7XG4gICAgdmFyIGJ5dGVzID0gdGhpcy53cml0ZVB1YmxpY0tleSgpO1xuXG4gICAgaWYgKCF0aGlzLmVuY3J5cHRlZCkge1xuICAgICAgYnl0ZXMgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSgwKTtcblxuICAgICAgYnl0ZXMgKz0gd3JpdGVfY2xlYXJ0ZXh0X21waSgnbW9kJywgdGhpcy5hbGdvcml0aG0sIHRoaXMubXBpKTtcbiAgICB9IGVsc2Uge1xuICAgICAgYnl0ZXMgKz0gdGhpcy5lbmNyeXB0ZWQ7XG4gICAgfVxuXG4gICAgcmV0dXJuIGJ5dGVzO1xuICB9O1xuXG5cblxuXG4gIC8qKiBFbmNyeXB0IHRoZSBwYXlsb2FkLiBCeSBkZWZhdWx0LCB3ZSB1c2UgYWVzMjU2IGFuZCBpdGVyYXRlZCwgc2FsdGVkIHN0cmluZ1xuICAgKiB0byBrZXkgc3BlY2lmaWVyXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBwYXNzcGhyYXNlXG4gICAqL1xuICB0aGlzLmVuY3J5cHQgPSBmdW5jdGlvbihwYXNzcGhyYXNlKSB7XG5cbiAgICB2YXIgczJrID0gbmV3IHR5cGVfczJrKCksXG4gICAgICBzeW1tZXRyaWMgPSAnYWVzMjU2JyxcbiAgICAgIGNsZWFydGV4dCA9IHdyaXRlX2NsZWFydGV4dF9tcGkoJ3NoYTEnLCB0aGlzLmFsZ29yaXRobSwgdGhpcy5tcGkpLFxuICAgICAga2V5ID0gcHJvZHVjZUVuY3J5cHRpb25LZXkoczJrLCBwYXNzcGhyYXNlLCBzeW1tZXRyaWMpLFxuICAgICAgYmxvY2tMZW4gPSBjcnlwdG8uY2lwaGVyW3N5bW1ldHJpY10uYmxvY2tTaXplLFxuICAgICAgaXYgPSBjcnlwdG8ucmFuZG9tLmdldFJhbmRvbUJ5dGVzKGJsb2NrTGVuKTtcblxuXG4gICAgdGhpcy5lbmNyeXB0ZWQgPSAnJztcbiAgICB0aGlzLmVuY3J5cHRlZCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKDI1NCk7XG4gICAgdGhpcy5lbmNyeXB0ZWQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShlbnVtcy53cml0ZShlbnVtcy5zeW1tZXRyaWMsIHN5bW1ldHJpYykpO1xuICAgIHRoaXMuZW5jcnlwdGVkICs9IHMyay53cml0ZSgpO1xuICAgIHRoaXMuZW5jcnlwdGVkICs9IGl2O1xuXG4gICAgdGhpcy5lbmNyeXB0ZWQgKz0gY3J5cHRvLmNmYi5ub3JtYWxFbmNyeXB0KHN5bW1ldHJpYywga2V5LCBjbGVhcnRleHQsIGl2KTtcbiAgfTtcblxuICBmdW5jdGlvbiBwcm9kdWNlRW5jcnlwdGlvbktleShzMmssIHBhc3NwaHJhc2UsIGFsZ29yaXRobSkge1xuICAgIHJldHVybiBzMmsucHJvZHVjZV9rZXkocGFzc3BocmFzZSxcbiAgICAgIGNyeXB0by5jaXBoZXJbYWxnb3JpdGhtXS5rZXlTaXplKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZWNyeXB0cyB0aGUgcHJpdmF0ZSBrZXkgTVBJcyB3aGljaCBhcmUgbmVlZGVkIHRvIHVzZSB0aGUga2V5LlxuICAgKiBvcGVucGdwX3BhY2tldF9rZXltYXRlcmlhbC5oYXNVbmVuY3J5cHRlZFNlY3JldEtleURhdGEgc2hvdWxkIGJlIFxuICAgKiBmYWxzZSBvdGhlcndpc2VcbiAgICogYSBjYWxsIHRvIHRoaXMgZnVuY3Rpb24gaXMgbm90IG5lZWRlZFxuICAgKiBcbiAgICogQHBhcmFtIHtTdHJpbmd9IHN0cl9wYXNzcGhyYXNlIFRoZSBwYXNzcGhyYXNlIGZvciB0aGlzIHByaXZhdGUga2V5IFxuICAgKiBhcyBzdHJpbmdcbiAgICogQHJldHVybiB7Qm9vbGVhbn0gVHJ1ZSBpZiB0aGUgcGFzc3BocmFzZSB3YXMgY29ycmVjdCBvciBNUEkgYWxyZWFkeVxuICAgKiAgICAgICAgICAgICAgICAgICBkZWNyeXB0ZWQ7IGZhbHNlIGlmIG5vdFxuICAgKi9cbiAgdGhpcy5kZWNyeXB0ID0gZnVuY3Rpb24ocGFzc3BocmFzZSkge1xuICAgIGlmICh0aGlzLmlzRGVjcnlwdGVkKVxuICAgICAgcmV0dXJuIHRydWU7XG5cbiAgICB2YXIgaSA9IDAsXG4gICAgICBzeW1tZXRyaWMsXG4gICAgICBrZXk7XG5cbiAgICB2YXIgczJrX3VzYWdlID0gdGhpcy5lbmNyeXB0ZWQuY2hhckNvZGVBdChpKyspO1xuXG4gICAgLy8gLSBbT3B0aW9uYWxdIElmIHN0cmluZy10by1rZXkgdXNhZ2Ugb2N0ZXQgd2FzIDI1NSBvciAyNTQsIGEgb25lLVxuICAgIC8vICAgb2N0ZXQgc3ltbWV0cmljIGVuY3J5cHRpb24gYWxnb3JpdGhtLlxuICAgIGlmIChzMmtfdXNhZ2UgPT0gMjU1IHx8IHMya191c2FnZSA9PSAyNTQpIHtcbiAgICAgIHN5bW1ldHJpYyA9IHRoaXMuZW5jcnlwdGVkLmNoYXJDb2RlQXQoaSsrKTtcbiAgICAgIHN5bW1ldHJpYyA9IGVudW1zLnJlYWQoZW51bXMuc3ltbWV0cmljLCBzeW1tZXRyaWMpO1xuXG4gICAgICAvLyAtIFtPcHRpb25hbF0gSWYgc3RyaW5nLXRvLWtleSB1c2FnZSBvY3RldCB3YXMgMjU1IG9yIDI1NCwgYVxuICAgICAgLy8gICBzdHJpbmctdG8ta2V5IHNwZWNpZmllci4gIFRoZSBsZW5ndGggb2YgdGhlIHN0cmluZy10by1rZXlcbiAgICAgIC8vICAgc3BlY2lmaWVyIGlzIGltcGxpZWQgYnkgaXRzIHR5cGUsIGFzIGRlc2NyaWJlZCBhYm92ZS5cbiAgICAgIHZhciBzMmsgPSBuZXcgdHlwZV9zMmsoKTtcbiAgICAgIGkgKz0gczJrLnJlYWQodGhpcy5lbmNyeXB0ZWQuc3Vic3RyKGkpKTtcblxuICAgICAga2V5ID0gcHJvZHVjZUVuY3J5cHRpb25LZXkoczJrLCBwYXNzcGhyYXNlLCBzeW1tZXRyaWMpO1xuICAgIH0gZWxzZSB7XG4gICAgICBzeW1tZXRyaWMgPSBzMmtfdXNhZ2U7XG4gICAgICBzeW1tZXRyaWMgPSBlbnVtcy5yZWFkKGVudW1zLnN5bW1ldHJpYywgc3ltbWV0cmljKTtcbiAgICAgIGtleSA9IGNyeXB0by5oYXNoLm1kNShwYXNzcGhyYXNlKTtcbiAgICB9XG5cblxuICAgIC8vIC0gW09wdGlvbmFsXSBJZiBzZWNyZXQgZGF0YSBpcyBlbmNyeXB0ZWQgKHN0cmluZy10by1rZXkgdXNhZ2Ugb2N0ZXRcbiAgICAvLyAgIG5vdCB6ZXJvKSwgYW4gSW5pdGlhbCBWZWN0b3IgKElWKSBvZiB0aGUgc2FtZSBsZW5ndGggYXMgdGhlXG4gICAgLy8gICBjaXBoZXIncyBibG9jayBzaXplLlxuICAgIHZhciBpdiA9IHRoaXMuZW5jcnlwdGVkLnN1YnN0cihpLFxuICAgICAgY3J5cHRvLmNpcGhlcltzeW1tZXRyaWNdLmJsb2NrU2l6ZSk7XG5cbiAgICBpICs9IGl2Lmxlbmd0aDtcblxuICAgIHZhciBjbGVhcnRleHQsXG4gICAgICBjaXBoZXJ0ZXh0ID0gdGhpcy5lbmNyeXB0ZWQuc3Vic3RyKGkpO1xuXG4gICAgY2xlYXJ0ZXh0ID0gY3J5cHRvLmNmYi5ub3JtYWxEZWNyeXB0KHN5bW1ldHJpYywga2V5LCBjaXBoZXJ0ZXh0LCBpdik7XG5cbiAgICB2YXIgaGFzaCA9IHMya191c2FnZSA9PSAyNTQgP1xuICAgICAgJ3NoYTEnIDpcbiAgICAgICdtb2QnO1xuXG4gICAgdmFyIHBhcnNlZE1QSSA9IHBhcnNlX2NsZWFydGV4dF9tcGkoaGFzaCwgY2xlYXJ0ZXh0LCB0aGlzLmFsZ29yaXRobSk7XG4gICAgaWYgKHBhcnNlZE1QSSBpbnN0YW5jZW9mIEVycm9yKVxuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIHRoaXMubXBpID0gdGhpcy5tcGkuY29uY2F0KHBhcnNlZE1QSSk7XG4gICAgdGhpcy5pc0RlY3J5cHRlZCA9IHRydWU7XG4gICAgcmV0dXJuIHRydWU7XG4gIH07XG5cbiAgdGhpcy5nZW5lcmF0ZSA9IGZ1bmN0aW9uKGJpdHMpIHtcbiAgICB0aGlzLm1waSA9IGNyeXB0by5nZW5lcmF0ZU1waSh0aGlzLmFsZ29yaXRobSwgYml0cyk7XG4gICAgdGhpcy5pc0RlY3J5cHRlZCA9IHRydWU7XG4gIH07XG5cbn1cblxucGFja2V0X3NlY3JldF9rZXkucHJvdG90eXBlID0gbmV3IHB1YmxpY0tleTtcblxubW9kdWxlLmV4cG9ydHMgPSBwYWNrZXRfc2VjcmV0X2tleTtcbiIsIi8vIEdQRzRCcm93c2VycyAtIEFuIE9wZW5QR1AgaW1wbGVtZW50YXRpb24gaW4gamF2YXNjcmlwdFxuLy8gQ29weXJpZ2h0IChDKSAyMDExIFJlY3VyaXR5IExhYnMgR21iSFxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yXG4vLyBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uOyBlaXRoZXJcbi8vIHZlcnNpb24gMi4xIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbi8vIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4vLyBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlIEdOVVxuLy8gTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cbi8vIFxuLy8gWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhbG9uZyB3aXRoIHRoaXMgbGlicmFyeTsgaWYgbm90LCB3cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZVxuLy8gRm91bmRhdGlvbiwgSW5jLiwgNTEgRnJhbmtsaW4gU3RyZWV0LCBGaWZ0aCBGbG9vciwgQm9zdG9uLCBNQSAgMDIxMTAtMTMwMSAgVVNBXG5cbnZhciBzZWNyZXRfa2V5ID0gcmVxdWlyZSgnLi9zZWNyZXRfa2V5LmpzJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gc2VjcmV0X3N1YmtleSgpIHtcbiAgc2VjcmV0X2tleS5jYWxsKHRoaXMpO1xufVxuIiwiLy8gR1BHNEJyb3dzZXJzIC0gQW4gT3BlblBHUCBpbXBsZW1lbnRhdGlvbiBpbiBqYXZhc2NyaXB0XG4vLyBDb3B5cmlnaHQgKEMpIDIwMTEgUmVjdXJpdHkgTGFicyBHbWJIXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3Jcbi8vIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlclxuLy8gdmVyc2lvbiAyLjEgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuLy8gYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2Zcbi8vIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUgR05VXG4vLyBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuLy8gXG4vLyBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFsb25nIHdpdGggdGhpcyBsaWJyYXJ5OyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlXG4vLyBGb3VuZGF0aW9uLCBJbmMuLCA1MSBGcmFua2xpbiBTdHJlZXQsIEZpZnRoIEZsb29yLCBCb3N0b24sIE1BICAwMjExMC0xMzAxICBVU0FcblxudmFyIHV0aWwgPSByZXF1aXJlKCcuLi91dGlsJyksXG4gIHBhY2tldCA9IHJlcXVpcmUoJy4vcGFja2V0LmpzJyksXG4gIGVudW1zID0gcmVxdWlyZSgnLi4vZW51bXMuanMnKSxcbiAgY3J5cHRvID0gcmVxdWlyZSgnLi4vY3J5cHRvJyksXG4gIHR5cGVfbXBpID0gcmVxdWlyZSgnLi4vdHlwZS9tcGkuanMnKSxcbiAgdHlwZV9rZXlpZCA9IHJlcXVpcmUoJy4uL3R5cGUva2V5aWQuanMnKTtcblxuLyoqXG4gKiBAY2xhc3NcbiAqIEBjbGFzc2Rlc2MgSW1wbGVtZW50YXRpb24gb2YgdGhlIFNpZ25hdHVyZSBQYWNrZXQgKFRhZyAyKVxuICogXG4gKiBSRkM0NDgwIDUuMjpcbiAqIEEgU2lnbmF0dXJlIHBhY2tldCBkZXNjcmliZXMgYSBiaW5kaW5nIGJldHdlZW4gc29tZSBwdWJsaWMga2V5IGFuZFxuICogc29tZSBkYXRhLiAgVGhlIG1vc3QgY29tbW9uIHNpZ25hdHVyZXMgYXJlIGEgc2lnbmF0dXJlIG9mIGEgZmlsZSBvciBhXG4gKiBibG9jayBvZiB0ZXh0LCBhbmQgYSBzaWduYXR1cmUgdGhhdCBpcyBhIGNlcnRpZmljYXRpb24gb2YgYSBVc2VyIElELlxuICovXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIHBhY2tldF9zaWduYXR1cmUoKSB7XG5cbiAgdGhpcy52ZXJzaW9uID0gbnVsbDtcbiAgdGhpcy5zaWduYXR1cmVUeXBlID0gbnVsbDtcbiAgdGhpcy5oYXNoQWxnb3JpdGhtID0gbnVsbDtcbiAgdGhpcy5wdWJsaWNLZXlBbGdvcml0aG0gPSBudWxsO1xuXG4gIHRoaXMuc2lnbmF0dXJlRGF0YSA9IG51bGw7XG4gIHRoaXMuc2lnbmVkSGFzaFZhbHVlID0gbnVsbDtcbiAgdGhpcy5tcGkgPSBudWxsO1xuXG4gIHRoaXMuY3JlYXRlZCA9IG5ldyBEYXRlKCk7XG4gIHRoaXMuc2lnbmF0dXJlRXhwaXJhdGlvblRpbWUgPSBudWxsO1xuICB0aGlzLnNpZ25hdHVyZU5ldmVyRXhwaXJlcyA9IG51bGw7XG4gIHRoaXMuZXhwb3J0YWJsZSA9IG51bGw7XG4gIHRoaXMudHJ1c3RMZXZlbCA9IG51bGw7XG4gIHRoaXMudHJ1c3RBbW91bnQgPSBudWxsO1xuICB0aGlzLnJlZ3VsYXJFeHByZXNzaW9uID0gbnVsbDtcbiAgdGhpcy5yZXZvY2FibGUgPSBudWxsO1xuICB0aGlzLmtleUV4cGlyYXRpb25UaW1lID0gbnVsbDtcbiAgdGhpcy5rZXlOZXZlckV4cGlyZXMgPSBudWxsO1xuICB0aGlzLnByZWZlcnJlZFN5bW1ldHJpY0FsZ29yaXRobXMgPSBudWxsO1xuICB0aGlzLnJldm9jYXRpb25LZXlDbGFzcyA9IG51bGw7XG4gIHRoaXMucmV2b2NhdGlvbktleUFsZ29yaXRobSA9IG51bGw7XG4gIHRoaXMucmV2b2NhdGlvbktleUZpbmdlcnByaW50ID0gbnVsbDtcbiAgdGhpcy5pc3N1ZXJLZXlJZCA9IG5ldyB0eXBlX2tleWlkKCk7XG4gIHRoaXMubm90YXRpb24gPSBudWxsO1xuICB0aGlzLnByZWZlcnJlZEhhc2hBbGdvcml0aG1zID0gbnVsbDtcbiAgdGhpcy5wcmVmZXJyZWRDb21wcmVzc2lvbkFsZ29yaXRobXMgPSBudWxsO1xuICB0aGlzLmtleVNlcnZlclByZWZlcmVuY2VzID0gbnVsbDtcbiAgdGhpcy5wcmVmZXJyZWRLZXlTZXJ2ZXIgPSBudWxsO1xuICB0aGlzLmlzUHJpbWFyeVVzZXJJRCA9IG51bGw7XG4gIHRoaXMucG9saWN5VVJJID0gbnVsbDtcbiAgdGhpcy5rZXlGbGFncyA9IG51bGw7XG4gIHRoaXMuc2lnbmVyc1VzZXJJZCA9IG51bGw7XG4gIHRoaXMucmVhc29uRm9yUmV2b2NhdGlvbkZsYWcgPSBudWxsO1xuICB0aGlzLnJlYXNvbkZvclJldm9jYXRpb25TdHJpbmcgPSBudWxsO1xuICB0aGlzLmZlYXR1cmVzID0gbnVsbDtcbiAgdGhpcy5zaWduYXR1cmVUYXJnZXRQdWJsaWNLZXlBbGdvcml0aG0gPSBudWxsO1xuICB0aGlzLnNpZ25hdHVyZVRhcmdldEhhc2hBbGdvcml0aG0gPSBudWxsO1xuICB0aGlzLnNpZ25hdHVyZVRhcmdldEhhc2ggPSBudWxsO1xuICB0aGlzLmVtYmVkZGVkU2lnbmF0dXJlID0gbnVsbDtcblxuICB0aGlzLnZlcmlmaWVkID0gZmFsc2U7XG5cbiAgLyoqXG4gICAqIHBhcnNpbmcgZnVuY3Rpb24gZm9yIGEgc2lnbmF0dXJlIHBhY2tldCAodGFnIDIpLlxuICAgKiBAcGFyYW0ge1N0cmluZ30gYnl0ZXMgcGF5bG9hZCBvZiBhIHRhZyAyIHBhY2tldFxuICAgKiBAcGFyYW0ge0ludGVnZXJ9IHBvc2l0aW9uIHBvc2l0aW9uIHRvIHN0YXJ0IHJlYWRpbmcgZnJvbSB0aGUgYnl0ZXMgc3RyaW5nXG4gICAqIEBwYXJhbSB7SW50ZWdlcn0gbGVuIGxlbmd0aCBvZiB0aGUgcGFja2V0IG9yIHRoZSByZW1haW5pbmcgbGVuZ3RoIG9mIGJ5dGVzIGF0IHBvc2l0aW9uXG4gICAqIEByZXR1cm4ge29wZW5wZ3BfcGFja2V0X2VuY3J5cHRlZGRhdGF9IG9iamVjdCByZXByZXNlbnRhdGlvblxuICAgKi9cbiAgdGhpcy5yZWFkID0gZnVuY3Rpb24oYnl0ZXMpIHtcbiAgICB2YXIgaSA9IDA7XG5cbiAgICB0aGlzLnZlcnNpb24gPSBieXRlcy5jaGFyQ29kZUF0KGkrKyk7XG4gICAgLy8gc3dpdGNoIG9uIHZlcnNpb24gKDMgYW5kIDQpXG4gICAgc3dpdGNoICh0aGlzLnZlcnNpb24pIHtcbiAgICAgIGNhc2UgMzpcbiAgICAgICAgLy8gT25lLW9jdGV0IGxlbmd0aCBvZiBmb2xsb3dpbmcgaGFzaGVkIG1hdGVyaWFsLiBNVVNUIGJlIDUuXG4gICAgICAgIGlmIChieXRlcy5jaGFyQ29kZUF0KGkrKykgIT0gNSlcbiAgICAgICAgICB1dGlsLnByaW50X2RlYnVnKFwib3BlbnBncC5wYWNrZXQuc2lnbmF0dXJlLmpzXFxuXCIgK1xuICAgICAgICAgICAgJ2ludmFsaWQgT25lLW9jdGV0IGxlbmd0aCBvZiBmb2xsb3dpbmcgaGFzaGVkIG1hdGVyaWFsLicgK1xuICAgICAgICAgICAgJ01VU1QgYmUgNS4gQDonICsgKGkgLSAxKSk7XG5cbiAgICAgICAgdmFyIHNpZ3BvcyA9IGk7XG4gICAgICAgIC8vIE9uZS1vY3RldCBzaWduYXR1cmUgdHlwZS5cbiAgICAgICAgdGhpcy5zaWduYXR1cmVUeXBlID0gYnl0ZXMuY2hhckNvZGVBdChpKyspO1xuXG4gICAgICAgIC8vIEZvdXItb2N0ZXQgY3JlYXRpb24gdGltZS5cbiAgICAgICAgdGhpcy5jcmVhdGVkID0gdXRpbC5yZWFkRGF0ZShieXRlcy5zdWJzdHIoaSwgNCkpO1xuICAgICAgICBpICs9IDQ7XG5cbiAgICAgICAgLy8gc3RvcmluZyBkYXRhIGFwcGVuZGVkIHRvIGRhdGEgd2hpY2ggZ2V0cyB2ZXJpZmllZFxuICAgICAgICB0aGlzLnNpZ25hdHVyZURhdGEgPSBieXRlcy5zdWJzdHJpbmcoc2lncG9zLCBpKTtcblxuICAgICAgICAvLyBFaWdodC1vY3RldCBLZXkgSUQgb2Ygc2lnbmVyLlxuICAgICAgICB0aGlzLmlzc3VlcktleUlkLnJlYWQoYnl0ZXMuc3Vic3RyaW5nKGksIGkgKyA4KSk7XG4gICAgICAgIGkgKz0gODtcblxuICAgICAgICAvLyBPbmUtb2N0ZXQgcHVibGljLWtleSBhbGdvcml0aG0uXG4gICAgICAgIHRoaXMucHVibGljS2V5QWxnb3JpdGhtID0gYnl0ZXMuY2hhckNvZGVBdChpKyspO1xuXG4gICAgICAgIC8vIE9uZS1vY3RldCBoYXNoIGFsZ29yaXRobS5cbiAgICAgICAgdGhpcy5oYXNoQWxnb3JpdGhtID0gYnl0ZXMuY2hhckNvZGVBdChpKyspO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgNDpcbiAgICAgICAgdGhpcy5zaWduYXR1cmVUeXBlID0gYnl0ZXMuY2hhckNvZGVBdChpKyspO1xuICAgICAgICB0aGlzLnB1YmxpY0tleUFsZ29yaXRobSA9IGJ5dGVzLmNoYXJDb2RlQXQoaSsrKTtcbiAgICAgICAgdGhpcy5oYXNoQWxnb3JpdGhtID0gYnl0ZXMuY2hhckNvZGVBdChpKyspO1xuXG4gICAgICAgIGZ1bmN0aW9uIHN1YnBhY2tldHMoYnl0ZXMpIHtcbiAgICAgICAgICAvLyBUd28tb2N0ZXQgc2NhbGFyIG9jdGV0IGNvdW50IGZvciBmb2xsb3dpbmcgc3VicGFja2V0IGRhdGEuXG4gICAgICAgICAgdmFyIHN1YnBhY2tldF9sZW5ndGggPSB1dGlsLnJlYWROdW1iZXIoXG4gICAgICAgICAgICBieXRlcy5zdWJzdHIoMCwgMikpO1xuXG4gICAgICAgICAgdmFyIGkgPSAyO1xuXG4gICAgICAgICAgLy8gc3VicGFja2V0IGRhdGEgc2V0ICh6ZXJvIG9yIG1vcmUgc3VicGFja2V0cylcbiAgICAgICAgICB2YXIgc3VicGFja2VkX3JlYWQgPSAwO1xuICAgICAgICAgIHdoaWxlIChpIDwgMiArIHN1YnBhY2tldF9sZW5ndGgpIHtcblxuICAgICAgICAgICAgdmFyIGxlbiA9IHBhY2tldC5yZWFkU2ltcGxlTGVuZ3RoKGJ5dGVzLnN1YnN0cihpKSk7XG4gICAgICAgICAgICBpICs9IGxlbi5vZmZzZXQ7XG5cbiAgICAgICAgICAgIHRoaXMucmVhZF9zdWJfcGFja2V0KGJ5dGVzLnN1YnN0cihpLCBsZW4ubGVuKSk7XG5cbiAgICAgICAgICAgIGkgKz0gbGVuLmxlbjtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZXR1cm4gaTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIGhhc2hlZCBzdWJwYWNrZXRzXG4gICAgICAgIGkgKz0gc3VicGFja2V0cy5jYWxsKHRoaXMsIGJ5dGVzLnN1YnN0cihpKSwgdHJ1ZSk7XG5cbiAgICAgICAgLy8gQSBWNCBzaWduYXR1cmUgaGFzaGVzIHRoZSBwYWNrZXQgYm9keVxuICAgICAgICAvLyBzdGFydGluZyBmcm9tIGl0cyBmaXJzdCBmaWVsZCwgdGhlIHZlcnNpb24gbnVtYmVyLCB0aHJvdWdoIHRoZSBlbmRcbiAgICAgICAgLy8gb2YgdGhlIGhhc2hlZCBzdWJwYWNrZXQgZGF0YS4gIFRodXMsIHRoZSBmaWVsZHMgaGFzaGVkIGFyZSB0aGVcbiAgICAgICAgLy8gc2lnbmF0dXJlIHZlcnNpb24sIHRoZSBzaWduYXR1cmUgdHlwZSwgdGhlIHB1YmxpYy1rZXkgYWxnb3JpdGhtLCB0aGVcbiAgICAgICAgLy8gaGFzaCBhbGdvcml0aG0sIHRoZSBoYXNoZWQgc3VicGFja2V0IGxlbmd0aCwgYW5kIHRoZSBoYXNoZWRcbiAgICAgICAgLy8gc3VicGFja2V0IGJvZHkuXG4gICAgICAgIHRoaXMuc2lnbmF0dXJlRGF0YSA9IGJ5dGVzLnN1YnN0cigwLCBpKTtcblxuICAgICAgICAvLyB1bmhhc2hlZCBzdWJwYWNrZXRzXG4gICAgICAgIGkgKz0gc3VicGFja2V0cy5jYWxsKHRoaXMsIGJ5dGVzLnN1YnN0cihpKSwgZmFsc2UpO1xuXG4gICAgICAgIGJyZWFrO1xuICAgICAgZGVmYXVsdDpcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdWZXJzaW9uICcgKyB2ZXJzaW9uICsgJyBvZiB0aGUgc2lnbmF0dXJlIGlzIHVuc3VwcG9ydGVkLicpO1xuICAgICAgICBicmVhaztcbiAgICB9XG5cbiAgICAvLyBUd28tb2N0ZXQgZmllbGQgaG9sZGluZyBsZWZ0IDE2IGJpdHMgb2Ygc2lnbmVkIGhhc2ggdmFsdWUuXG4gICAgdGhpcy5zaWduZWRIYXNoVmFsdWUgPSBieXRlcy5zdWJzdHIoaSwgMik7XG4gICAgaSArPSAyO1xuXG4gICAgdGhpcy5zaWduYXR1cmUgPSBieXRlcy5zdWJzdHIoaSk7XG4gIH07XG5cbiAgdGhpcy53cml0ZSA9IGZ1bmN0aW9uKCkge1xuICAgIHJldHVybiB0aGlzLnNpZ25hdHVyZURhdGEgK1xuICAgICAgdXRpbC53cml0ZU51bWJlcigwLCAyKSArIC8vIE51bWJlciBvZiB1bnNpZ25lZCBzdWJwYWNrZXRzLlxuICAgIHRoaXMuc2lnbmVkSGFzaFZhbHVlICtcbiAgICAgIHRoaXMuc2lnbmF0dXJlO1xuICB9O1xuXG4gIC8qKlxuICAgKiBTaWducyBwcm92aWRlZCBkYXRhLiBUaGlzIG5lZWRzIHRvIGJlIGRvbmUgcHJpb3IgdG8gc2VyaWFsaXphdGlvbi5cbiAgICogQHBhcmFtIHtPYmplY3R9IGRhdGEgQ29udGFpbnMgcGFja2V0cyB0byBiZSBzaWduZWQuXG4gICAqIEBwYXJhbSB7b3BlbnBncF9tc2dfcHJpdmF0ZWtleX0gcHJpdmF0ZWtleSBwcml2YXRlIGtleSB1c2VkIHRvIHNpZ24gdGhlIG1lc3NhZ2UuIFxuICAgKi9cbiAgdGhpcy5zaWduID0gZnVuY3Rpb24oa2V5LCBkYXRhKSB7XG4gICAgdmFyIHNpZ25hdHVyZVR5cGUgPSBlbnVtcy53cml0ZShlbnVtcy5zaWduYXR1cmUsIHRoaXMuc2lnbmF0dXJlVHlwZSksXG4gICAgICBwdWJsaWNLZXlBbGdvcml0aG0gPSBlbnVtcy53cml0ZShlbnVtcy5wdWJsaWNLZXksIHRoaXMucHVibGljS2V5QWxnb3JpdGhtKSxcbiAgICAgIGhhc2hBbGdvcml0aG0gPSBlbnVtcy53cml0ZShlbnVtcy5oYXNoLCB0aGlzLmhhc2hBbGdvcml0aG0pO1xuXG4gICAgdmFyIHJlc3VsdCA9IFN0cmluZy5mcm9tQ2hhckNvZGUoNCk7XG4gICAgcmVzdWx0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoc2lnbmF0dXJlVHlwZSk7XG4gICAgcmVzdWx0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUocHVibGljS2V5QWxnb3JpdGhtKTtcbiAgICByZXN1bHQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShoYXNoQWxnb3JpdGhtKTtcblxuICAgIHRoaXMuaXNzdWVyS2V5SWQgPSBrZXkuZ2V0S2V5SWQoKTtcblxuICAgIC8vIEFkZCBoYXNoZWQgc3VicGFja2V0c1xuICAgIHJlc3VsdCArPSB0aGlzLndyaXRlX2FsbF9zdWJfcGFja2V0cygpO1xuXG4gICAgdGhpcy5zaWduYXR1cmVEYXRhID0gcmVzdWx0O1xuXG4gICAgdmFyIHRyYWlsZXIgPSB0aGlzLmNhbGN1bGF0ZVRyYWlsZXIoKTtcblxuICAgIHZhciB0b0hhc2ggPSB0aGlzLnRvU2lnbihzaWduYXR1cmVUeXBlLCBkYXRhKSArXG4gICAgICB0aGlzLnNpZ25hdHVyZURhdGEgKyB0cmFpbGVyO1xuXG4gICAgdmFyIGhhc2ggPSBjcnlwdG8uaGFzaC5kaWdlc3QoaGFzaEFsZ29yaXRobSwgdG9IYXNoKTtcblxuICAgIHRoaXMuc2lnbmVkSGFzaFZhbHVlID0gaGFzaC5zdWJzdHIoMCwgMik7XG5cbiAgICB0aGlzLnNpZ25hdHVyZSA9IGNyeXB0by5zaWduYXR1cmUuc2lnbihoYXNoQWxnb3JpdGhtLFxuICAgICAgcHVibGljS2V5QWxnb3JpdGhtLCBrZXkubXBpLCB0b0hhc2gpO1xuICB9O1xuXG4gIC8qKlxuICAgKiBDcmVhdGVzIHN0cmluZyBvZiBieXRlcyB3aXRoIGFsbCBzdWJwYWNrZXQgZGF0YVxuICAgKiBAcmV0dXJuIHtTdHJpbmd9IGEgc3RyaW5nLXJlcHJlc2VudGF0aW9uIG9mIGEgYWxsIHN1YnBhY2tldCBkYXRhXG4gICAqL1xuICB0aGlzLndyaXRlX2FsbF9zdWJfcGFja2V0cyA9IGZ1bmN0aW9uKCkge1xuICAgIHZhciBzdWIgPSBlbnVtcy5zaWduYXR1cmVTdWJwYWNrZXQ7XG4gICAgdmFyIHJlc3VsdCA9ICcnO1xuICAgIHZhciBieXRlcyA9ICcnO1xuICAgIGlmICh0aGlzLmNyZWF0ZWQgIT09IG51bGwpIHtcbiAgICAgIHJlc3VsdCArPSB3cml0ZV9zdWJfcGFja2V0KHN1Yi5zaWduYXR1cmVfY3JlYXRpb25fdGltZSwgdXRpbC53cml0ZURhdGUodGhpcy5jcmVhdGVkKSk7XG4gICAgfVxuICAgIGlmICh0aGlzLnNpZ25hdHVyZUV4cGlyYXRpb25UaW1lICE9PSBudWxsKSB7XG4gICAgICByZXN1bHQgKz0gd3JpdGVfc3ViX3BhY2tldChzdWIuc2lnbmF0dXJlX2V4cGlyYXRpb25fdGltZSwgdXRpbC53cml0ZURhdGUodGhpcy5zaWduYXR1cmVFeHBpcmF0aW9uVGltZSkpO1xuICAgIH1cbiAgICBpZiAodGhpcy5leHBvcnRhYmxlICE9PSBudWxsKSB7XG4gICAgICByZXN1bHQgKz0gd3JpdGVfc3ViX3BhY2tldChzdWIuZXhwb3J0YWJsZV9jZXJ0aWZpY2F0aW9uLCBTdHJpbmcuZnJvbUNoYXJDb2RlKHRoaXMuZXhwb3J0YWJsZSA/IDEgOiAwKSk7XG4gICAgfVxuICAgIGlmICh0aGlzLnRydXN0TGV2ZWwgIT09IG51bGwpIHtcbiAgICAgIGJ5dGVzID0gU3RyaW5nLmZyb21DaGFyQ29kZSh0aGlzLnRydXN0TGV2ZWwpICsgU3RyaW5nLmZyb21DaGFyQ29kZSh0aGlzLnRydXN0QW1vdW50KTtcbiAgICAgIHJlc3VsdCArPSB3cml0ZV9zdWJfcGFja2V0KHN1Yi50cnVzdF9zaWduYXR1cmUsIGJ5dGVzKTtcbiAgICB9XG4gICAgaWYgKHRoaXMucmVndWxhckV4cHJlc3Npb24gIT09IG51bGwpIHtcbiAgICAgIHJlc3VsdCArPSB3cml0ZV9zdWJfcGFja2V0KHN1Yi5yZWd1bGFyX2V4cHJlc3Npb24sIHRoaXMucmVndWxhckV4cHJlc3Npb24pO1xuICAgIH1cbiAgICBpZiAodGhpcy5yZXZvY2FibGUgIT09IG51bGwpIHtcbiAgICAgIHJlc3VsdCArPSB3cml0ZV9zdWJfcGFja2V0KHN1Yi5yZXZvY2FibGUsIFN0cmluZy5mcm9tQ2hhckNvZGUodGhpcy5yZXZvY2FibGUgPyAxIDogMCkpO1xuICAgIH1cbiAgICBpZiAodGhpcy5rZXlFeHBpcmF0aW9uVGltZSAhPT0gbnVsbCkge1xuICAgICAgcmVzdWx0ICs9IHdyaXRlX3N1Yl9wYWNrZXQoc3ViLmtleV9leHBpcmF0aW9uX3RpbWUsIHV0aWwud3JpdGVEYXRlKHRoaXMua2V5RXhwaXJhdGlvblRpbWUpKTtcbiAgICB9XG4gICAgaWYgKHRoaXMucHJlZmVycmVkU3ltbWV0cmljQWxnb3JpdGhtcyAhPT0gbnVsbCkge1xuICAgICAgYnl0ZXMgPSB1dGlsLmJpbjJzdHIodGhpcy5wcmVmZXJyZWRTeW1tZXRyaWNBbGdvcml0aG1zKTtcbiAgICAgIHJlc3VsdCArPSB3cml0ZV9zdWJfcGFja2V0KHN1Yi5wcmVmZXJyZWRfc3ltbWV0cmljX2FsZ29yaXRobXMsIGJ5dGVzKTtcbiAgICB9XG4gICAgaWYgKHRoaXMucmV2b2NhdGlvbktleUNsYXNzICE9PSBudWxsKSB7XG4gICAgICBieXRlcyA9IFN0cmluZy5mcm9tQ2hhckNvZGUodGhpcy5yZXZvY2F0aW9uS2V5Q2xhc3MpO1xuICAgICAgYnl0ZXMgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSh0aGlzLnJldm9jYXRpb25LZXlBbGdvcml0aG0pO1xuICAgICAgYnl0ZXMgKz0gdGhpcy5yZXZvY2F0aW9uS2V5RmluZ2VycHJpbnQ7XG4gICAgICByZXN1bHQgKz0gd3JpdGVfc3ViX3BhY2tldChzdWIucmV2b2NhdGlvbl9rZXksIGJ5dGVzKTtcbiAgICB9XG4gICAgaWYgKCF0aGlzLmlzc3VlcktleUlkLmlzTnVsbCgpKSB7XG4gICAgICByZXN1bHQgKz0gd3JpdGVfc3ViX3BhY2tldChzdWIuaXNzdWVyLCB0aGlzLmlzc3VlcktleUlkLndyaXRlKCkpO1xuICAgIH1cbiAgICBpZiAodGhpcy5ub3RhdGlvbiAhPT0gbnVsbCkge1xuICAgICAgZm9yICh2YXIgbmFtZSBpbiB0aGlzLm5vdGF0aW9uKSB7XG4gICAgICAgIGlmICh0aGlzLm5vdGF0aW9uLmhhc093blByb3BlcnR5KG5hbWUpKSB7XG4gICAgICAgICAgdmFyIHZhbHVlID0gdGhpcy5ub3RhdGlvbltuYW1lXTtcbiAgICAgICAgICBieXRlcyA9IFN0cmluZy5mcm9tQ2hhckNvZGUoMHg4MCk7XG4gICAgICAgICAgYnl0ZXMgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSgwKTtcbiAgICAgICAgICBieXRlcyArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKDApO1xuICAgICAgICAgIGJ5dGVzICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoMCk7XG4gICAgICAgICAgLy8gMiBvY3RldHMgb2YgbmFtZSBsZW5ndGhcbiAgICAgICAgICBieXRlcyArPSB1dGlsLndyaXRlTnVtYmVyKG5hbWUubGVuZ3RoLCAyKTtcbiAgICAgICAgICAvLyAyIG9jdGV0cyBvZiB2YWx1ZSBsZW5ndGhcbiAgICAgICAgICBieXRlcyArPSB1dGlsLndyaXRlTnVtYmVyKHZhbHVlLmxlbmd0aCwgMik7XG4gICAgICAgICAgYnl0ZXMgKz0gbmFtZSArIHZhbHVlO1xuICAgICAgICAgIHJlc3VsdCArPSB3cml0ZV9zdWJfcGFja2V0KHN1Yi5ub3RhdGlvbl9kYXRhLCBieXRlcyk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IFxuICAgIGlmICh0aGlzLnByZWZlcnJlZEhhc2hBbGdvcml0aG1zICE9PSBudWxsKSB7XG4gICAgICBieXRlcyA9IHV0aWwuYmluMnN0cih0aGlzLnByZWZlcnJlZEhhc2hBbGdvcml0aG1zKTtcbiAgICAgIHJlc3VsdCArPSB3cml0ZV9zdWJfcGFja2V0KHN1Yi5wcmVmZXJyZWRfaGFzaF9hbGdvcml0aG1zLCBieXRlcyk7XG4gICAgfVxuICAgIGlmICh0aGlzLnByZWZlcnJlZENvbXByZXNzaW9uQWxnb3JpdGhtcyAhPT0gbnVsbCkge1xuICAgICAgYnl0ZXMgPSB1dGlsLmJpbjJzdHIodGhpcy5wcmVmZXJyZWRDb21wcmVzc2lvbkFsZ29yaXRobXMpO1xuICAgICAgcmVzdWx0ICs9IHdyaXRlX3N1Yl9wYWNrZXQoc3ViLnByZWZlcnJlZF9oYXNoX2FsZ29yaXRobXMsIGJ5dGVzKTtcbiAgICB9XG4gICAgaWYgKHRoaXMua2V5U2VydmVyUHJlZmVyZW5jZXMgIT09IG51bGwpIHtcbiAgICAgIGJ5dGVzID0gdXRpbC5iaW4yc3RyKHRoaXMua2V5U2VydmVyUHJlZmVyZW5jZXMpO1xuICAgICAgcmVzdWx0ICs9IHdyaXRlX3N1Yl9wYWNrZXQoc3ViLmtleV9zZXJ2ZXJfcHJlZmVyZW5jZXMsIGJ5dGVzKTtcbiAgICB9XG4gICAgaWYgKHRoaXMucHJlZmVycmVkS2V5U2VydmVyICE9PSBudWxsKSB7XG4gICAgICByZXN1bHQgKz0gd3JpdGVfc3ViX3BhY2tldChzdWIucHJlZmVycmVkX2tleV9zZXJ2ZXIsIHRoaXMucHJlZmVycmVkS2V5U2VydmVyKTtcbiAgICB9XG4gICAgaWYgKHRoaXMuaXNQcmltYXJ5VXNlcklEICE9PSBudWxsKSB7XG4gICAgICByZXN1bHQgKz0gd3JpdGVfc3ViX3BhY2tldChzdWIucHJpbWFyeV91c2VyX2lkLCBTdHJpbmcuZnJvbUNoYXJDb2RlKHRoaXMuaXNQcmltYXJ5VXNlcklEID8gMSA6IDApKTtcbiAgICB9XG4gICAgaWYgKHRoaXMucG9saWN5VVJJICE9PSBudWxsKSB7XG4gICAgICByZXN1bHQgKz0gd3JpdGVfc3ViX3BhY2tldChzdWIucG9saWN5X3VyaSwgdGhpcy5wb2xpY3lVUkkpOyBcbiAgICB9XG4gICAgaWYgKHRoaXMua2V5RmxhZ3MgIT09IG51bGwpIHtcbiAgICAgIGJ5dGVzID0gdXRpbC5iaW4yc3RyKHRoaXMua2V5RmxhZ3MpO1xuICAgICAgcmVzdWx0ICs9IHdyaXRlX3N1Yl9wYWNrZXQoc3ViLmtleV9mbGFncywgYnl0ZXMpO1xuICAgIH1cbiAgICBpZiAodGhpcy5zaWduZXJzVXNlcklkICE9PSBudWxsKSB7XG4gICAgICByZXN1bHQgKz0gd3JpdGVfc3ViX3BhY2tldChzdWIuc2lnbmVyc191c2VyX2lkLCB0aGlzLnNpZ25lcnNVc2VySWQpOyBcbiAgICB9XG4gICAgaWYgKHRoaXMucmVhc29uRm9yUmV2b2NhdGlvbkZsYWcgIT09IG51bGwpIHtcbiAgICAgIGJ5dGVzID0gU3RyaW5nLmZyb21DaGFyQ29kZSh0aGlzLnJlYXNvbkZvclJldm9jYXRpb25GbGFnKTtcbiAgICAgIGJ5dGVzICs9IHRoaXMucmVhc29uRm9yUmV2b2NhdGlvblN0cmluZztcbiAgICAgIHJlc3VsdCArPSB3cml0ZV9zdWJfcGFja2V0KHN1Yi5yZWFzb25fZm9yX3Jldm9jYXRpb24sIGJ5dGVzKTtcbiAgICB9XG4gICAgaWYgKHRoaXMuZmVhdHVyZXMgIT09IG51bGwpIHtcbiAgICAgIGJ5dGVzID0gdXRpbC5iaW4yc3RyKHRoaXMuZmVhdHVyZXMpO1xuICAgICAgcmVzdWx0ICs9IHdyaXRlX3N1Yl9wYWNrZXQoc3ViLmZlYXR1cmVzLCBieXRlcyk7XG4gICAgfVxuICAgIGlmICh0aGlzLnNpZ25hdHVyZVRhcmdldFB1YmxpY0tleUFsZ29yaXRobSAhPT0gbnVsbCkge1xuICAgICAgYnl0ZXMgPSBTdHJpbmcuZnJvbUNoYXJDb2RlKHRoaXMuc2lnbmF0dXJlVGFyZ2V0UHVibGljS2V5QWxnb3JpdGhtKTtcbiAgICAgIGJ5dGVzICs9IFN0cmluZy5mcm9tQ2hhckNvZGUodGhpcy5zaWduYXR1cmVUYXJnZXRIYXNoQWxnb3JpdGhtKTtcbiAgICAgIGJ5dGVzICs9IHRoaXMuc2lnbmF0dXJlVGFyZ2V0SGFzaDtcbiAgICAgIHJlc3VsdCArPSB3cml0ZV9zdWJfcGFja2V0KHN1Yi5zaWduYXR1cmVfdGFyZ2V0LCBieXRlcyk7XG4gICAgfVxuICAgIGlmICh0aGlzLmVtYmVkZGVkU2lnbmF0dXJlICE9PSBudWxsKSB7XG4gICAgICByZXN1bHQgKz0gd3JpdGVfc3ViX3BhY2tldChzdWIuZW1iZWRkZWRfc2lnbmF0dXJlLCB0aGlzLmVtYmVkZGVkU2lnbmF0dXJlLndyaXRlKCkpO1xuICAgIH1cbiAgICByZXN1bHQgPSB1dGlsLndyaXRlTnVtYmVyKHJlc3VsdC5sZW5ndGgsIDIpICsgcmVzdWx0O1xuICAgIHJldHVybiByZXN1bHQ7XG4gIH07XG5cbiAgLyoqXG4gICAqIGNyZWF0ZXMgYSBzdHJpbmcgcmVwcmVzZW50YXRpb24gb2YgYSBzdWIgc2lnbmF0dXJlIHBhY2tldCAoU2VlIFJGQyA0ODgwIDUuMi4zLjEpXG4gICAqIEBwYXJhbSB7SW50ZWdlcn0gdHlwZSBzdWJwYWNrZXQgc2lnbmF0dXJlIHR5cGUuIFNpZ25hdHVyZSB0eXBlcyBhcyBkZXNjcmliZWQgXG4gICAqIGluIFJGQzQ4ODAgU2VjdGlvbiA1LjIuMy4yXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBkYXRhIGRhdGEgdG8gYmUgaW5jbHVkZWRcbiAgICogQHJldHVybiB7U3RyaW5nfSBhIHN0cmluZy1yZXByZXNlbnRhdGlvbiBvZiBhIHN1YiBzaWduYXR1cmUgcGFja2V0IChTZWUgUkZDIDQ4ODAgNS4yLjMuMSlcbiAgICovXG4gIGZ1bmN0aW9uIHdyaXRlX3N1Yl9wYWNrZXQodHlwZSwgZGF0YSkge1xuICAgIHZhciByZXN1bHQgPSBcIlwiO1xuICAgIHJlc3VsdCArPSBwYWNrZXQud3JpdGVTaW1wbGVMZW5ndGgoZGF0YS5sZW5ndGggKyAxKTtcbiAgICByZXN1bHQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSh0eXBlKTtcbiAgICByZXN1bHQgKz0gZGF0YTtcbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG5cbiAgLy8gVjQgc2lnbmF0dXJlIHN1YiBwYWNrZXRzXG5cbiAgdGhpcy5yZWFkX3N1Yl9wYWNrZXQgPSBmdW5jdGlvbihieXRlcykge1xuICAgIHZhciBteXBvcyA9IDA7XG5cbiAgICBmdW5jdGlvbiByZWFkX2FycmF5KHByb3AsIGJ5dGVzKSB7XG4gICAgICB0aGlzW3Byb3BdID0gW107XG5cbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgYnl0ZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdGhpc1twcm9wXS5wdXNoKGJ5dGVzLmNoYXJDb2RlQXQoaSkpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIFRoZSBsZWZ0d29zdCBiaXQgZGVub3RlcyBhIFwiY3JpdGljYWxcIiBwYWNrZXQsIGJ1dCB3ZSBpZ25vcmUgaXQuXG4gICAgdmFyIHR5cGUgPSBieXRlcy5jaGFyQ29kZUF0KG15cG9zKyspICYgMHg3RjtcblxuICAgIC8vIHN1YnBhY2tldCB0eXBlXG4gICAgc3dpdGNoICh0eXBlKSB7XG4gICAgICBjYXNlIDI6XG4gICAgICAgIC8vIFNpZ25hdHVyZSBDcmVhdGlvbiBUaW1lXG4gICAgICAgIHRoaXMuY3JlYXRlZCA9IHV0aWwucmVhZERhdGUoYnl0ZXMuc3Vic3RyKG15cG9zKSk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAzOlxuICAgICAgICAvLyBTaWduYXR1cmUgRXhwaXJhdGlvbiBUaW1lXG4gICAgICAgIHZhciB0aW1lID0gdXRpbC5yZWFkRGF0ZShieXRlcy5zdWJzdHIobXlwb3MpKTtcblxuICAgICAgICB0aGlzLnNpZ25hdHVyZU5ldmVyRXhwaXJlcyA9IHRpbWUuZ2V0VGltZSgpID09IDA7XG4gICAgICAgIHRoaXMuc2lnbmF0dXJlRXhwaXJhdGlvblRpbWUgPSB0aW1lO1xuXG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSA0OlxuICAgICAgICAvLyBFeHBvcnRhYmxlIENlcnRpZmljYXRpb25cbiAgICAgICAgdGhpcy5leHBvcnRhYmxlID0gYnl0ZXMuY2hhckNvZGVBdChteXBvcysrKSA9PSAxO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgNTpcbiAgICAgICAgLy8gVHJ1c3QgU2lnbmF0dXJlXG4gICAgICAgIHRoaXMudHJ1c3RMZXZlbCA9IGJ5dGVzLmNoYXJDb2RlQXQobXlwb3MrKyk7XG4gICAgICAgIHRoaXMudHJ1c3RBbW91bnQgPSBieXRlcy5jaGFyQ29kZUF0KG15cG9zKyspO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgNjpcbiAgICAgICAgLy8gUmVndWxhciBFeHByZXNzaW9uXG4gICAgICAgIHRoaXMucmVndWxhckV4cHJlc3Npb24gPSBieXRlcy5zdWJzdHIobXlwb3MpO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgNzpcbiAgICAgICAgLy8gUmV2b2NhYmxlXG4gICAgICAgIHRoaXMucmV2b2NhYmxlID0gYnl0ZXMuY2hhckNvZGVBdChteXBvcysrKSA9PSAxO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgOTpcbiAgICAgICAgLy8gS2V5IEV4cGlyYXRpb24gVGltZVxuICAgICAgICB2YXIgdGltZSA9IHV0aWwucmVhZERhdGUoYnl0ZXMuc3Vic3RyKG15cG9zKSk7XG5cbiAgICAgICAgdGhpcy5rZXlFeHBpcmF0aW9uVGltZSA9IHRpbWU7XG4gICAgICAgIHRoaXMua2V5TmV2ZXJFeHBpcmVzID0gdGltZS5nZXRUaW1lKCkgPT0gMDtcblxuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgMTE6XG4gICAgICAgIC8vIFByZWZlcnJlZCBTeW1tZXRyaWMgQWxnb3JpdGhtc1xuICAgICAgICB0aGlzLnByZWZlcnJlZFN5bW1ldHJpY0FsZ29yaXRobXMgPSBbXTtcblxuICAgICAgICB3aGlsZSAobXlwb3MgIT0gYnl0ZXMubGVuZ3RoKSB7XG4gICAgICAgICAgdGhpcy5wcmVmZXJyZWRTeW1tZXRyaWNBbGdvcml0aG1zLnB1c2goYnl0ZXMuY2hhckNvZGVBdChteXBvcysrKSk7XG4gICAgICAgIH1cblxuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgMTI6XG4gICAgICAgIC8vIFJldm9jYXRpb24gS2V5XG4gICAgICAgIC8vICgxIG9jdGV0IG9mIGNsYXNzLCAxIG9jdGV0IG9mIHB1YmxpYy1rZXkgYWxnb3JpdGhtIElELCAyMFxuICAgICAgICAvLyBvY3RldHMgb2ZcbiAgICAgICAgLy8gZmluZ2VycHJpbnQpXG4gICAgICAgIHRoaXMucmV2b2NhdGlvbktleUNsYXNzID0gYnl0ZXMuY2hhckNvZGVBdChteXBvcysrKTtcbiAgICAgICAgdGhpcy5yZXZvY2F0aW9uS2V5QWxnb3JpdGhtID0gYnl0ZXMuY2hhckNvZGVBdChteXBvcysrKTtcbiAgICAgICAgdGhpcy5yZXZvY2F0aW9uS2V5RmluZ2VycHJpbnQgPSBieXRlcy5zdWJzdHIobXlwb3MsIDIwKTtcbiAgICAgICAgYnJlYWs7XG5cbiAgICAgIGNhc2UgMTY6XG4gICAgICAgIC8vIElzc3VlclxuICAgICAgICB0aGlzLmlzc3VlcktleUlkLnJlYWQoYnl0ZXMuc3Vic3RyKG15cG9zKSk7XG4gICAgICAgIGJyZWFrO1xuXG4gICAgICBjYXNlIDIwOlxuICAgICAgICAvLyBOb3RhdGlvbiBEYXRhXG4gICAgICAgIC8vIFdlIGRvbid0IGtub3cgaG93IHRvIGhhbmRsZSBhbnl0aGluZyBidXQgYSB0ZXh0IGZsYWdnZWQgZGF0YS5cbiAgICAgICAgaWYgKGJ5dGVzLmNoYXJDb2RlQXQobXlwb3MpID09IDB4ODApIHtcblxuICAgICAgICAgIC8vIFdlIGV4dHJhY3Qga2V5L3ZhbHVlIHR1cGxlIGZyb20gdGhlIGJ5dGUgc3RyZWFtLlxuICAgICAgICAgIG15cG9zICs9IDQ7XG4gICAgICAgICAgdmFyIG0gPSB1dGlsLnJlYWROdW1iZXIoYnl0ZXMuc3Vic3RyKG15cG9zLCAyKSk7XG4gICAgICAgICAgbXlwb3MgKz0gMlxuICAgICAgICAgIHZhciBuID0gdXRpbC5yZWFkTnVtYmVyKGJ5dGVzLnN1YnN0cihteXBvcywgMikpO1xuICAgICAgICAgIG15cG9zICs9IDJcblxuICAgICAgICAgIHZhciBuYW1lID0gYnl0ZXMuc3Vic3RyKG15cG9zLCBtKSxcbiAgICAgICAgICAgIHZhbHVlID0gYnl0ZXMuc3Vic3RyKG15cG9zICsgbSwgbik7XG5cbiAgICAgICAgICB0aGlzLm5vdGF0aW9uID0gdGhpcy5ub3RhdGlvbiB8fCB7fTtcbiAgICAgICAgICB0aGlzLm5vdGF0aW9uW25hbWVdID0gdmFsdWU7XG4gICAgICAgIH0gZWxzZSB0aHJvdyBuZXcgRXJyb3IoXCJVbnN1cHBvcnRlZCBub3RhdGlvbiBmbGFnLlwiKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIDIxOlxuICAgICAgICAvLyBQcmVmZXJyZWQgSGFzaCBBbGdvcml0aG1zXG4gICAgICAgIHJlYWRfYXJyYXkuY2FsbCh0aGlzLCAncHJlZmVycmVkSGFzaEFsZ29yaXRobXMnLCBieXRlcy5zdWJzdHIobXlwb3MpKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIDIyOlxuICAgICAgICAvLyBQcmVmZXJyZWQgQ29tcHJlc3Npb24gQWxnb3JpdGhtc1xuICAgICAgICByZWFkX2FycmF5LmNhbGwodGhpcywgJ3ByZWZlcnJlZENvbXByZXNzaW9uQWxnb3JpdGhtcyAnLCBieXRlcy5zdWJzdHIobXlwb3MpKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIDIzOlxuICAgICAgICAvLyBLZXkgU2VydmVyIFByZWZlcmVuY2VzXG4gICAgICAgIHJlYWRfYXJyYXkuY2FsbCh0aGlzLCAna2V5U2VydmVyUHJlZmVyZW5jZXNzJywgYnl0ZXMuc3Vic3RyKG15cG9zKSk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAyNDpcbiAgICAgICAgLy8gUHJlZmVycmVkIEtleSBTZXJ2ZXJcbiAgICAgICAgdGhpcy5wcmVmZXJyZWRLZXlTZXJ2ZXIgPSBieXRlcy5zdWJzdHIobXlwb3MpO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgMjU6XG4gICAgICAgIC8vIFByaW1hcnkgVXNlciBJRFxuICAgICAgICB0aGlzLmlzUHJpbWFyeVVzZXJJRCA9IGJ5dGVzW215cG9zKytdICE9IDA7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAyNjpcbiAgICAgICAgLy8gUG9saWN5IFVSSVxuICAgICAgICB0aGlzLnBvbGljeVVSSSA9IGJ5dGVzLnN1YnN0cihteXBvcyk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAyNzpcbiAgICAgICAgLy8gS2V5IEZsYWdzXG4gICAgICAgIHJlYWRfYXJyYXkuY2FsbCh0aGlzLCAna2V5RmxhZ3MnLCBieXRlcy5zdWJzdHIobXlwb3MpKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIDI4OlxuICAgICAgICAvLyBTaWduZXIncyBVc2VyIElEXG4gICAgICAgIHRoaXMuc2lnbmVyc1VzZXJJZCArPSBieXRlcy5zdWJzdHIobXlwb3MpO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgMjk6XG4gICAgICAgIC8vIFJlYXNvbiBmb3IgUmV2b2NhdGlvblxuICAgICAgICB0aGlzLnJlYXNvbkZvclJldm9jYXRpb25GbGFnID0gYnl0ZXMuY2hhckNvZGVBdChteXBvcysrKTtcbiAgICAgICAgdGhpcy5yZWFzb25Gb3JSZXZvY2F0aW9uU3RyaW5nID0gYnl0ZXMuc3Vic3RyKG15cG9zKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIDMwOlxuICAgICAgICAvLyBGZWF0dXJlc1xuICAgICAgICByZWFkX2FycmF5LmNhbGwodGhpcywgJ2ZlYXR1cmVzJywgYnl0ZXMuc3Vic3RyKG15cG9zKSk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAzMTpcbiAgICAgICAgLy8gU2lnbmF0dXJlIFRhcmdldFxuICAgICAgICAvLyAoMSBvY3RldCBwdWJsaWMta2V5IGFsZ29yaXRobSwgMSBvY3RldCBoYXNoIGFsZ29yaXRobSwgTiBvY3RldHMgaGFzaClcbiAgICAgICAgdGhpcy5zaWduYXR1cmVUYXJnZXRQdWJsaWNLZXlBbGdvcml0aG0gPSBieXRlcy5jaGFyQ29kZUF0KG15cG9zKyspO1xuICAgICAgICB0aGlzLnNpZ25hdHVyZVRhcmdldEhhc2hBbGdvcml0aG0gPSBieXRlcy5jaGFyQ29kZUF0KG15cG9zKyspO1xuXG4gICAgICAgIHZhciBsZW4gPSBjcnlwdG8uZ2V0SGFzaEJ5dGVMZW5ndGgodGhpcy5zaWduYXR1cmVUYXJnZXRIYXNoQWxnb3JpdGhtKTtcblxuICAgICAgICB0aGlzLnNpZ25hdHVyZVRhcmdldEhhc2ggPSBieXRlcy5zdWJzdHIobXlwb3MsIGxlbik7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAzMjpcbiAgICAgICAgLy8gRW1iZWRkZWQgU2lnbmF0dXJlXG4gICAgICAgIHRoaXMuZW1iZWRkZWRTaWduYXR1cmUgPSBuZXcgcGFja2V0X3NpZ25hdHVyZSgpO1xuICAgICAgICB0aGlzLmVtYmVkZGVkU2lnbmF0dXJlLnJlYWQoYnl0ZXMuc3Vic3RyKG15cG9zKSk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgZGVmYXVsdDpcbiAgICAgICAgdXRpbC5wcmludF9lcnJvcihcIm9wZW5wZ3AucGFja2V0LnNpZ25hdHVyZS5qc1xcblwiICtcbiAgICAgICAgICAndW5rbm93biBzaWduYXR1cmUgc3VicGFja2V0IHR5cGUgJyArIHR5cGUgKyBcIiBAOlwiICsgbXlwb3MgK1xuICAgICAgICAgIFwiIHN1YnBsZW46XCIgKyBzdWJwbGVuICsgXCIgbGVuOlwiICsgbGVuKTtcbiAgICAgICAgYnJlYWs7XG4gICAgfVxuICB9O1xuXG4gIC8vIFByb2R1Y2VzIGRhdGEgdG8gcHJvZHVjZSBzaWduYXR1cmUgb25cbiAgdGhpcy50b1NpZ24gPSBmdW5jdGlvbih0eXBlLCBkYXRhKSB7XG4gICAgdmFyIHQgPSBlbnVtcy5zaWduYXR1cmU7XG5cbiAgICBzd2l0Y2ggKHR5cGUpIHtcbiAgICAgIGNhc2UgdC5iaW5hcnk6XG4gICAgICBjYXNlIHQudGV4dDpcbiAgICAgICAgcmV0dXJuIGRhdGEuZ2V0Qnl0ZXMoKTtcblxuICAgICAgY2FzZSB0LnN0YW5kYWxvbmU6XG4gICAgICAgIHJldHVybiAnJztcblxuICAgICAgY2FzZSB0LmNlcnRfZ2VuZXJpYzpcbiAgICAgIGNhc2UgdC5jZXJ0X3BlcnNvbmE6XG4gICAgICBjYXNlIHQuY2VydF9jYXN1YWw6XG4gICAgICBjYXNlIHQuY2VydF9wb3NpdGl2ZTpcbiAgICAgIGNhc2UgdC5jZXJ0X3Jldm9jYXRpb246XG4gICAgICAgIHtcbiAgICAgICAgICB2YXIgcGFja2V0LCB0YWc7XG5cbiAgICAgICAgICBpZiAoZGF0YS51c2VyaWQgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgdGFnID0gMHhCNDtcbiAgICAgICAgICAgIHBhY2tldCA9IGRhdGEudXNlcmlkO1xuICAgICAgICAgIH0gZWxzZSBpZiAoZGF0YS51c2VyYXR0cmlidXRlICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIHRhZyA9IDB4RDE7XG4gICAgICAgICAgICBwYWNrZXQgPSBkYXRhLnVzZXJhdHRyaWJ1dGU7XG4gICAgICAgICAgfSBlbHNlIHRocm93IG5ldyBFcnJvcignRWl0aGVyIGEgdXNlcmlkIG9yIHVzZXJhdHRyaWJ1dGUgcGFja2V0IG5lZWRzIHRvIGJlICcgK1xuICAgICAgICAgICAgICAnc3VwcGxpZWQgZm9yIGNlcnRpZmljYXRpb24uJyk7XG5cbiAgICAgICAgICB2YXIgYnl0ZXMgPSBwYWNrZXQud3JpdGUoKTtcblxuICAgICAgICAgIHJldHVybiB0aGlzLnRvU2lnbih0LmtleSwgZGF0YSkgK1xuICAgICAgICAgICAgU3RyaW5nLmZyb21DaGFyQ29kZSh0YWcpICtcbiAgICAgICAgICAgIHV0aWwud3JpdGVOdW1iZXIoYnl0ZXMubGVuZ3RoLCA0KSArXG4gICAgICAgICAgICBieXRlcztcbiAgICAgICAgfVxuICAgICAgY2FzZSB0LnN1YmtleV9iaW5kaW5nOlxuICAgICAgY2FzZSB0LmtleV9iaW5kaW5nOlxuICAgICAgICB7XG4gICAgICAgICAgcmV0dXJuIHRoaXMudG9TaWduKHQua2V5LCBkYXRhKSArIHRoaXMudG9TaWduKHQua2V5LCB7XG4gICAgICAgICAgICBrZXk6IGRhdGEuYmluZFxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICBjYXNlIHQua2V5OlxuICAgICAgICB7XG4gICAgICAgICAgaWYgKGRhdGEua2V5ID09IHVuZGVmaW5lZClcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignS2V5IHBhY2tldCBpcyByZXF1aXJlZCBmb3IgdGhpcyBzaWd0YXR1cmUuJyk7XG5cbiAgICAgICAgICByZXR1cm4gZGF0YS5rZXkud3JpdGVPbGQoKTtcbiAgICAgICAgfVxuICAgICAgY2FzZSB0LmtleV9yZXZvY2F0aW9uOlxuICAgICAgY2FzZSB0LnN1YmtleV9yZXZvY2F0aW9uOlxuICAgICAgICByZXR1cm4gdGhpcy50b1NpZ24odC5rZXksIGRhdGEpO1xuICAgICAgY2FzZSB0LnRpbWVzdGFtcDpcbiAgICAgICAgcmV0dXJuICcnO1xuICAgICAgY2FzZSB0LnRoaXJkX3BhcnR5OlxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ05vdCBpbXBsZW1lbnRlZCcpO1xuICAgICAgICBicmVhaztcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignVW5rbm93biBzaWduYXR1cmUgdHlwZS4nKVxuICAgIH1cbiAgfVxuXG5cbiAgdGhpcy5jYWxjdWxhdGVUcmFpbGVyID0gZnVuY3Rpb24oKSB7XG4gICAgLy8gY2FsY3VsYXRpbmcgdGhlIHRyYWlsZXJcbiAgICB2YXIgdHJhaWxlciA9ICcnO1xuICAgIC8vIFYzIHNpZ25hdHVyZXMgZG9uJ3QgaGF2ZSBhIHRyYWlsZXJcbiAgICBpZiAodGhpcy52ZXJzaW9uID09IDMpIHJldHVybiB0cmFpbGVyO1xuICAgIHRyYWlsZXIgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSg0KTsgLy8gVmVyc2lvblxuICAgIHRyYWlsZXIgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSgweEZGKTtcbiAgICB0cmFpbGVyICs9IHV0aWwud3JpdGVOdW1iZXIodGhpcy5zaWduYXR1cmVEYXRhLmxlbmd0aCwgNCk7XG4gICAgcmV0dXJuIHRyYWlsZXJcbiAgfVxuXG5cbiAgLyoqXG4gICAqIHZlcmlmeXMgdGhlIHNpZ25hdHVyZSBwYWNrZXQuIE5vdGU6IG5vdCBzaWduYXR1cmUgdHlwZXMgYXJlIGltcGxlbWVudGVkXG4gICAqIEBwYXJhbSB7U3RyaW5nfE9iamVjdH0gZGF0YSBkYXRhIHdoaWNoIG9uIHRoZSBzaWduYXR1cmUgYXBwbGllc1xuICAgKiBAcGFyYW0ge3B1YmxpY19zdWJrZXl8cGFja2V0X3B1YmxpY19rZXl9IGtleSB0aGUgcHVibGljIGtleSB0byB2ZXJpZnkgdGhlIHNpZ25hdHVyZVxuICAgKiBAcmV0dXJuIHtib29sZWFufSBUcnVlIGlmIG1lc3NhZ2UgaXMgdmVyaWZpZWQsIGVsc2UgZmFsc2UuXG4gICAqL1xuICB0aGlzLnZlcmlmeSA9IGZ1bmN0aW9uKGtleSwgZGF0YSkge1xuICAgIHZhciBzaWduYXR1cmVUeXBlID0gZW51bXMud3JpdGUoZW51bXMuc2lnbmF0dXJlLCB0aGlzLnNpZ25hdHVyZVR5cGUpLFxuICAgICAgcHVibGljS2V5QWxnb3JpdGhtID0gZW51bXMud3JpdGUoZW51bXMucHVibGljS2V5LCB0aGlzLnB1YmxpY0tleUFsZ29yaXRobSksXG4gICAgICBoYXNoQWxnb3JpdGhtID0gZW51bXMud3JpdGUoZW51bXMuaGFzaCwgdGhpcy5oYXNoQWxnb3JpdGhtKTtcblxuICAgIHZhciBieXRlcyA9IHRoaXMudG9TaWduKHNpZ25hdHVyZVR5cGUsIGRhdGEpLFxuICAgICAgdHJhaWxlciA9IHRoaXMuY2FsY3VsYXRlVHJhaWxlcigpO1xuXG5cbiAgICB2YXIgbXBpY291bnQgPSAwO1xuICAgIC8vIEFsZ29yaXRobS1TcGVjaWZpYyBGaWVsZHMgZm9yIFJTQSBzaWduYXR1cmVzOlxuICAgIC8vIFx0ICAgIC0gbXVsdGlwcmVjaXNpb24gbnVtYmVyIChNUEkpIG9mIFJTQSBzaWduYXR1cmUgdmFsdWUgbSoqZCBtb2Qgbi5cbiAgICBpZiAocHVibGljS2V5QWxnb3JpdGhtID4gMCAmJiBwdWJsaWNLZXlBbGdvcml0aG0gPCA0KVxuICAgICAgbXBpY291bnQgPSAxO1xuICAgIC8vICAgIEFsZ29yaXRobS1TcGVjaWZpYyBGaWVsZHMgZm9yIERTQSBzaWduYXR1cmVzOlxuICAgIC8vICAgICAgLSBNUEkgb2YgRFNBIHZhbHVlIHIuXG4gICAgLy8gICAgICAtIE1QSSBvZiBEU0EgdmFsdWUgcy5cbiAgICBlbHNlIGlmIChwdWJsaWNLZXlBbGdvcml0aG0gPT0gMTcpXG4gICAgICBtcGljb3VudCA9IDI7XG5cbiAgICB2YXIgbXBpID0gW10sXG4gICAgICBpID0gMDtcbiAgICBmb3IgKHZhciBqID0gMDsgaiA8IG1waWNvdW50OyBqKyspIHtcbiAgICAgIG1waVtqXSA9IG5ldyB0eXBlX21waSgpO1xuICAgICAgaSArPSBtcGlbal0ucmVhZCh0aGlzLnNpZ25hdHVyZS5zdWJzdHIoaSkpO1xuICAgIH1cblxuICAgIHRoaXMudmVyaWZpZWQgPSBjcnlwdG8uc2lnbmF0dXJlLnZlcmlmeShwdWJsaWNLZXlBbGdvcml0aG0sXG4gICAgICBoYXNoQWxnb3JpdGhtLCBtcGksIGtleS5tcGksXG4gICAgICBieXRlcyArIHRoaXMuc2lnbmF0dXJlRGF0YSArIHRyYWlsZXIpO1xuXG4gICAgcmV0dXJuIHRoaXMudmVyaWZpZWQ7XG4gIH1cbn1cbiIsIi8vIEdQRzRCcm93c2VycyAtIEFuIE9wZW5QR1AgaW1wbGVtZW50YXRpb24gaW4gamF2YXNjcmlwdFxuLy8gQ29weXJpZ2h0IChDKSAyMDExIFJlY3VyaXR5IExhYnMgR21iSFxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yXG4vLyBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uOyBlaXRoZXJcbi8vIHZlcnNpb24gMi4xIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbi8vIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4vLyBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlIEdOVVxuLy8gTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cbi8vIFxuLy8gWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhbG9uZyB3aXRoIHRoaXMgbGlicmFyeTsgaWYgbm90LCB3cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZVxuLy8gRm91bmRhdGlvbiwgSW5jLiwgNTEgRnJhbmtsaW4gU3RyZWV0LCBGaWZ0aCBGbG9vciwgQm9zdG9uLCBNQSAgMDIxMTAtMTMwMSAgVVNBXG5cbnZhciB1dGlsID0gcmVxdWlyZSgnLi4vdXRpbCcpLFxuICBjcnlwdG8gPSByZXF1aXJlKCcuLi9jcnlwdG8nKTtcblxuLyoqXG4gKiBAY2xhc3NcbiAqIEBjbGFzc2Rlc2MgSW1wbGVtZW50YXRpb24gb2YgdGhlIFN5bS4gRW5jcnlwdGVkIEludGVncml0eSBQcm90ZWN0ZWQgRGF0YSBcbiAqIFBhY2tldCAoVGFnIDE4KVxuICogXG4gKiBSRkM0ODgwIDUuMTM6IFRoZSBTeW1tZXRyaWNhbGx5IEVuY3J5cHRlZCBJbnRlZ3JpdHkgUHJvdGVjdGVkIERhdGEgcGFja2V0IGlzXG4gKiBhIHZhcmlhbnQgb2YgdGhlIFN5bW1ldHJpY2FsbHkgRW5jcnlwdGVkIERhdGEgcGFja2V0LiBJdCBpcyBhIG5ldyBmZWF0dXJlXG4gKiBjcmVhdGVkIGZvciBPcGVuUEdQIHRoYXQgYWRkcmVzc2VzIHRoZSBwcm9ibGVtIG9mIGRldGVjdGluZyBhIG1vZGlmaWNhdGlvbiB0b1xuICogZW5jcnlwdGVkIGRhdGEuIEl0IGlzIHVzZWQgaW4gY29tYmluYXRpb24gd2l0aCBhIE1vZGlmaWNhdGlvbiBEZXRlY3Rpb24gQ29kZVxuICogcGFja2V0LlxuICovXG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gcGFja2V0X3N5bV9lbmNyeXB0ZWRfaW50ZWdyaXR5X3Byb3RlY3RlZCgpIHtcbiAgLyoqIFRoZSBlbmNyeXB0ZWQgcGF5bG9hZC4gKi9cbiAgdGhpcy5lbmNyeXB0ZWQgPSBudWxsOyAvLyBzdHJpbmdcbiAgLyoqIEB0eXBlIHtCb29sZWFufVxuICAgKiBJZiBhZnRlciBkZWNyeXB0aW5nIHRoZSBwYWNrZXQgdGhpcyBpcyBzZXQgdG8gdHJ1ZSxcbiAgICogYSBtb2RpZmljYXRpb24gaGFzIGJlZW4gZGV0ZWN0ZWQgYW5kIHRodXMgdGhlIGNvbnRlbnRzXG4gICAqIHNob3VsZCBiZSBkaXNjYXJkZWQuXG4gICAqL1xuICB0aGlzLm1vZGlmaWNhdGlvbiA9IGZhbHNlO1xuICB0aGlzLnBhY2tldHM7XG5cblxuICB0aGlzLnJlYWQgPSBmdW5jdGlvbihieXRlcykge1xuICAgIC8vIC0gQSBvbmUtb2N0ZXQgdmVyc2lvbiBudW1iZXIuIFRoZSBvbmx5IGN1cnJlbnRseSBkZWZpbmVkIHZhbHVlIGlzXG4gICAgLy8gMS5cbiAgICB2YXIgdmVyc2lvbiA9IGJ5dGVzLmNoYXJDb2RlQXQoMCk7XG5cbiAgICBpZiAodmVyc2lvbiAhPSAxKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgcGFja2V0IHZlcnNpb24uJyk7XG4gICAgfVxuXG4gICAgLy8gLSBFbmNyeXB0ZWQgZGF0YSwgdGhlIG91dHB1dCBvZiB0aGUgc2VsZWN0ZWQgc3ltbWV0cmljLWtleSBjaXBoZXJcbiAgICAvLyAgIG9wZXJhdGluZyBpbiBDaXBoZXIgRmVlZGJhY2sgbW9kZSB3aXRoIHNoaWZ0IGFtb3VudCBlcXVhbCB0byB0aGVcbiAgICAvLyAgIGJsb2NrIHNpemUgb2YgdGhlIGNpcGhlciAoQ0ZCLW4gd2hlcmUgbiBpcyB0aGUgYmxvY2sgc2l6ZSkuXG4gICAgdGhpcy5lbmNyeXB0ZWQgPSBieXRlcy5zdWJzdHIoMSk7XG4gIH1cblxuICB0aGlzLndyaXRlID0gZnVuY3Rpb24oKSB7XG5cbiAgICByZXR1cm4gU3RyaW5nLmZyb21DaGFyQ29kZSgxKSAvLyBWZXJzaW9uXG4gICAgKyB0aGlzLmVuY3J5cHRlZDtcbiAgfVxuXG4gIHRoaXMuZW5jcnlwdCA9IGZ1bmN0aW9uKHNlc3Npb25LZXlBbGdvcml0aG0sIGtleSkge1xuICAgIHZhciBieXRlcyA9IHRoaXMucGFja2V0cy53cml0ZSgpXG5cbiAgICB2YXIgcHJlZml4cmFuZG9tID0gY3J5cHRvLmdldFByZWZpeFJhbmRvbShzZXNzaW9uS2V5QWxnb3JpdGhtKTtcbiAgICB2YXIgcHJlZml4ID0gcHJlZml4cmFuZG9tICsgcHJlZml4cmFuZG9tLmNoYXJBdChwcmVmaXhyYW5kb20ubGVuZ3RoIC0gMikgKyBwcmVmaXhyYW5kb20uY2hhckF0KHByZWZpeHJhbmRvbS5sZW5ndGggLVxuICAgICAgMSlcblxuICAgIHZhciB0b2hhc2ggPSBieXRlcztcblxuXG4gICAgLy8gTW9kaWZpY2F0aW9uIGRldGVjdGlvbiBjb2RlIHBhY2tldC5cbiAgICB0b2hhc2ggKz0gU3RyaW5nLmZyb21DaGFyQ29kZSgweEQzKTtcbiAgICB0b2hhc2ggKz0gU3RyaW5nLmZyb21DaGFyQ29kZSgweDE0KTtcblxuXG4gICAgdG9oYXNoICs9IGNyeXB0by5oYXNoLnNoYTEocHJlZml4ICsgdG9oYXNoKTtcblxuXG4gICAgdGhpcy5lbmNyeXB0ZWQgPSBjcnlwdG8uY2ZiLmVuY3J5cHQocHJlZml4cmFuZG9tLFxuICAgICAgc2Vzc2lvbktleUFsZ29yaXRobSwgdG9oYXNoLCBrZXksIGZhbHNlKS5zdWJzdHJpbmcoMCxcbiAgICAgIHByZWZpeC5sZW5ndGggKyB0b2hhc2gubGVuZ3RoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZWNyeXB0cyB0aGUgZW5jcnlwdGVkIGRhdGEgY29udGFpbmVkIGluIHRoaXMgb2JqZWN0IHJlYWRfcGFja2V0IG11c3RcbiAgICogaGF2ZSBiZWVuIGNhbGxlZCBiZWZvcmVcbiAgICogXG4gICAqIEBwYXJhbSB7SW50ZWdlcn0gc2Vzc2lvbktleUFsZ29yaXRobVxuICAgKiAgICAgICAgICAgIFRoZSBzZWxlY3RlZCBzeW1tZXRyaWMgZW5jcnlwdGlvbiBhbGdvcml0aG0gdG8gYmUgdXNlZFxuICAgKiBAcGFyYW0ge1N0cmluZ30ga2V5IFRoZSBrZXkgb2YgY2lwaGVyIGJsb2Nrc2l6ZSBsZW5ndGggdG8gYmUgdXNlZFxuICAgKiBAcmV0dXJuIHtTdHJpbmd9IFRoZSBkZWNyeXB0ZWQgZGF0YSBvZiB0aGlzIHBhY2tldFxuICAgKi9cbiAgdGhpcy5kZWNyeXB0ID0gZnVuY3Rpb24oc2Vzc2lvbktleUFsZ29yaXRobSwga2V5KSB7XG4gICAgdmFyIGRlY3J5cHRlZCA9IGNyeXB0by5jZmIuZGVjcnlwdChcbiAgICAgIHNlc3Npb25LZXlBbGdvcml0aG0sIGtleSwgdGhpcy5lbmNyeXB0ZWQsIGZhbHNlKTtcblxuXG4gICAgLy8gdGhlcmUgbXVzdCBiZSBhIG1vZGlmaWNhdGlvbiBkZXRlY3Rpb24gY29kZSBwYWNrZXQgYXMgdGhlXG4gICAgLy8gbGFzdCBwYWNrZXQgYW5kIGV2ZXJ5dGhpbmcgZ2V0cyBoYXNoZWQgZXhjZXB0IHRoZSBoYXNoIGl0c2VsZlxuICAgIHRoaXMuaGFzaCA9IGNyeXB0by5oYXNoLnNoYTEoXG4gICAgICBjcnlwdG8uY2ZiLm1kYyhzZXNzaW9uS2V5QWxnb3JpdGhtLCBrZXksIHRoaXMuZW5jcnlwdGVkKSArIGRlY3J5cHRlZC5zdWJzdHJpbmcoMCwgZGVjcnlwdGVkLmxlbmd0aCAtIDIwKSk7XG5cblxuICAgIHZhciBtZGMgPSBkZWNyeXB0ZWQuc3Vic3RyKGRlY3J5cHRlZC5sZW5ndGggLSAyMCwgMjApO1xuXG4gICAgaWYgKHRoaXMuaGFzaCAhPSBtZGMpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignTW9kaWZpY2F0aW9uIGRldGVjdGVkLicpO1xuICAgIH0gZWxzZVxuICAgICAgdGhpcy5wYWNrZXRzLnJlYWQoZGVjcnlwdGVkLnN1YnN0cigwLCBkZWNyeXB0ZWQubGVuZ3RoIC0gMjIpKTtcbiAgfVxufTtcbiIsIi8vIEdQRzRCcm93c2VycyAtIEFuIE9wZW5QR1AgaW1wbGVtZW50YXRpb24gaW4gamF2YXNjcmlwdFxuLy8gQ29weXJpZ2h0IChDKSAyMDExIFJlY3VyaXR5IExhYnMgR21iSFxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yXG4vLyBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uOyBlaXRoZXJcbi8vIHZlcnNpb24gMi4xIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbi8vIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4vLyBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlIEdOVVxuLy8gTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cbi8vIFxuLy8gWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhbG9uZyB3aXRoIHRoaXMgbGlicmFyeTsgaWYgbm90LCB3cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZVxuLy8gRm91bmRhdGlvbiwgSW5jLiwgNTEgRnJhbmtsaW4gU3RyZWV0LCBGaWZ0aCBGbG9vciwgQm9zdG9uLCBNQSAgMDIxMTAtMTMwMSAgVVNBXG5cbnZhciB0eXBlX3MyayA9IHJlcXVpcmUoJy4uL3R5cGUvczJrLmpzJyksXG4gIGVudW1zID0gcmVxdWlyZSgnLi4vZW51bXMuanMnKSxcbiAgY3J5cHRvID0gcmVxdWlyZSgnLi4vY3J5cHRvJyk7XG5cbi8qKlxuICogQGNsYXNzXG4gKiBAY2xhc3NkZXNjIFB1YmxpYy1LZXkgRW5jcnlwdGVkIFNlc3Npb24gS2V5IFBhY2tldHMgKFRhZyAxKVxuICogXG4gKiBSRkM0ODgwIDUuMTogQSBQdWJsaWMtS2V5IEVuY3J5cHRlZCBTZXNzaW9uIEtleSBwYWNrZXQgaG9sZHMgdGhlIHNlc3Npb24ga2V5XG4gKiB1c2VkIHRvIGVuY3J5cHQgYSBtZXNzYWdlLiBaZXJvIG9yIG1vcmUgUHVibGljLUtleSBFbmNyeXB0ZWQgU2Vzc2lvbiBLZXlcbiAqIHBhY2tldHMgYW5kL29yIFN5bW1ldHJpYy1LZXkgRW5jcnlwdGVkIFNlc3Npb24gS2V5IHBhY2tldHMgbWF5IHByZWNlZGUgYVxuICogU3ltbWV0cmljYWxseSBFbmNyeXB0ZWQgRGF0YSBQYWNrZXQsIHdoaWNoIGhvbGRzIGFuIGVuY3J5cHRlZCBtZXNzYWdlLiBUaGVcbiAqIG1lc3NhZ2UgaXMgZW5jcnlwdGVkIHdpdGggdGhlIHNlc3Npb24ga2V5LCBhbmQgdGhlIHNlc3Npb24ga2V5IGlzIGl0c2VsZlxuICogZW5jcnlwdGVkIGFuZCBzdG9yZWQgaW4gdGhlIEVuY3J5cHRlZCBTZXNzaW9uIEtleSBwYWNrZXQocykuIFRoZVxuICogU3ltbWV0cmljYWxseSBFbmNyeXB0ZWQgRGF0YSBQYWNrZXQgaXMgcHJlY2VkZWQgYnkgb25lIFB1YmxpYy1LZXkgRW5jcnlwdGVkXG4gKiBTZXNzaW9uIEtleSBwYWNrZXQgZm9yIGVhY2ggT3BlblBHUCBrZXkgdG8gd2hpY2ggdGhlIG1lc3NhZ2UgaXMgZW5jcnlwdGVkLlxuICogVGhlIHJlY2lwaWVudCBvZiB0aGUgbWVzc2FnZSBmaW5kcyBhIHNlc3Npb24ga2V5IHRoYXQgaXMgZW5jcnlwdGVkIHRvIHRoZWlyXG4gKiBwdWJsaWMga2V5LCBkZWNyeXB0cyB0aGUgc2Vzc2lvbiBrZXksIGFuZCB0aGVuIHVzZXMgdGhlIHNlc3Npb24ga2V5IHRvXG4gKiBkZWNyeXB0IHRoZSBtZXNzYWdlLlxuICovXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIHBhY2tldF9zeW1fZW5jcnlwdGVkX3Nlc3Npb25fa2V5KCkge1xuICB0aGlzLnRhZyA9IDM7XG4gIHRoaXMuc2Vzc2lvbktleUVuY3J5cHRpb25BbGdvcml0aG0gPSBudWxsO1xuICB0aGlzLnNlc3Npb25LZXlBbGdvcml0aG0gPSAnYWVzMjU2JztcbiAgdGhpcy5lbmNyeXB0ZWQgPSBudWxsO1xuICB0aGlzLnMyayA9IG5ldyB0eXBlX3MyaygpO1xuXG4gIC8qKlxuICAgKiBQYXJzaW5nIGZ1bmN0aW9uIGZvciBhIHN5bW1ldHJpYyBlbmNyeXB0ZWQgc2Vzc2lvbiBrZXkgcGFja2V0ICh0YWcgMykuXG4gICAqIFxuICAgKiBAcGFyYW0ge1N0cmluZ30gaW5wdXQgUGF5bG9hZCBvZiBhIHRhZyAxIHBhY2tldFxuICAgKiBAcGFyYW0ge0ludGVnZXJ9IHBvc2l0aW9uIFBvc2l0aW9uIHRvIHN0YXJ0IHJlYWRpbmcgZnJvbSB0aGUgaW5wdXQgc3RyaW5nXG4gICAqIEBwYXJhbSB7SW50ZWdlcn0gbGVuXG4gICAqICAgICAgICAgICAgTGVuZ3RoIG9mIHRoZSBwYWNrZXQgb3IgdGhlIHJlbWFpbmluZyBsZW5ndGggb2ZcbiAgICogICAgICAgICAgICBpbnB1dCBhdCBwb3NpdGlvblxuICAgKiBAcmV0dXJuIHtvcGVucGdwX3BhY2tldF9lbmNyeXB0ZWRkYXRhfSBPYmplY3QgcmVwcmVzZW50YXRpb25cbiAgICovXG4gIHRoaXMucmVhZCA9IGZ1bmN0aW9uKGJ5dGVzKSB7XG4gICAgLy8gQSBvbmUtb2N0ZXQgdmVyc2lvbiBudW1iZXIuIFRoZSBvbmx5IGN1cnJlbnRseSBkZWZpbmVkIHZlcnNpb24gaXMgNC5cbiAgICB0aGlzLnZlcnNpb24gPSBieXRlcy5jaGFyQ29kZUF0KDApO1xuXG4gICAgLy8gQSBvbmUtb2N0ZXQgbnVtYmVyIGRlc2NyaWJpbmcgdGhlIHN5bW1ldHJpYyBhbGdvcml0aG0gdXNlZC5cbiAgICB2YXIgYWxnbyA9IGVudW1zLnJlYWQoZW51bXMuc3ltbWV0cmljLCBieXRlcy5jaGFyQ29kZUF0KDEpKTtcblxuICAgIC8vIEEgc3RyaW5nLXRvLWtleSAoUzJLKSBzcGVjaWZpZXIsIGxlbmd0aCBhcyBkZWZpbmVkIGFib3ZlLlxuICAgIHZhciBzMmtsZW5ndGggPSB0aGlzLnMyay5yZWFkKGJ5dGVzLnN1YnN0cigyKSk7XG5cbiAgICAvLyBPcHRpb25hbGx5LCB0aGUgZW5jcnlwdGVkIHNlc3Npb24ga2V5IGl0c2VsZiwgd2hpY2ggaXMgZGVjcnlwdGVkXG4gICAgLy8gd2l0aCB0aGUgc3RyaW5nLXRvLWtleSBvYmplY3QuXG4gICAgdmFyIGRvbmUgPSBzMmtsZW5ndGggKyAyO1xuXG4gICAgaWYgKGRvbmUgPCBieXRlcy5sZW5ndGgpIHtcbiAgICAgIHRoaXMuZW5jcnlwdGVkID0gYnl0ZXMuc3Vic3RyKGRvbmUpO1xuICAgICAgdGhpcy5zZXNzaW9uS2V5RW5jcnlwdGlvbkFsZ29yaXRobSA9IGFsZ29cbiAgICB9IGVsc2VcbiAgICAgIHRoaXMuc2Vzc2lvbktleUFsZ29yaXRobSA9IGFsZ287XG4gIH1cblxuICB0aGlzLndyaXRlID0gZnVuY3Rpb24oKSB7XG4gICAgdmFyIGFsZ28gPSB0aGlzLmVuY3J5cHRlZCA9PSBudWxsID9cbiAgICAgIHRoaXMuc2Vzc2lvbktleUFsZ29yaXRobSA6XG4gICAgICB0aGlzLnNlc3Npb25LZXlFbmNyeXB0aW9uQWxnb3JpdGhtO1xuXG4gICAgdmFyIGJ5dGVzID0gU3RyaW5nLmZyb21DaGFyQ29kZSh0aGlzLnZlcnNpb24pICtcbiAgICAgIFN0cmluZy5mcm9tQ2hhckNvZGUoZW51bXMud3JpdGUoZW51bXMuc3ltbWV0cmljLCBhbGdvKSkgK1xuICAgICAgdGhpcy5zMmsud3JpdGUoKTtcblxuICAgIGlmICh0aGlzLmVuY3J5cHRlZCAhPSBudWxsKVxuICAgICAgYnl0ZXMgKz0gdGhpcy5lbmNyeXB0ZWQ7XG4gICAgcmV0dXJuIGJ5dGVzO1xuICB9XG5cbiAgLyoqXG4gICAqIERlY3J5cHRzIHRoZSBzZXNzaW9uIGtleSAob25seSBmb3IgcHVibGljIGtleSBlbmNyeXB0ZWQgc2Vzc2lvbiBrZXlcbiAgICogcGFja2V0cyAodGFnIDEpXG4gICAqIFxuICAgKiBAcGFyYW0ge29wZW5wZ3BfbXNnX21lc3NhZ2V9IG1zZ1xuICAgKiAgICAgICAgICAgIFRoZSBtZXNzYWdlIG9iamVjdCAod2l0aCBtZW1iZXIgZW5jcnlwdGVkRGF0YVxuICAgKiBAcGFyYW0ge29wZW5wZ3BfbXNnX3ByaXZhdGVrZXl9IGtleVxuICAgKiAgICAgICAgICAgIFByaXZhdGUga2V5IHdpdGggc2VjTVBJcyB1bmxvY2tlZFxuICAgKiBAcmV0dXJuIHtTdHJpbmd9IFRoZSB1bmVuY3J5cHRlZCBzZXNzaW9uIGtleVxuICAgKi9cbiAgdGhpcy5kZWNyeXB0ID0gZnVuY3Rpb24ocGFzc3BocmFzZSkge1xuICAgIHZhciBhbGdvID0gdGhpcy5zZXNzaW9uS2V5RW5jcnlwdGlvbkFsZ29yaXRobSAhPSBudWxsID9cbiAgICAgIHRoaXMuc2Vzc2lvbktleUVuY3J5cHRpb25BbGdvcml0aG0gOlxuICAgICAgdGhpcy5zZXNzaW9uS2V5QWxnb3JpdGhtO1xuXG5cbiAgICB2YXIgbGVuZ3RoID0gY3J5cHRvLmNpcGhlclthbGdvXS5rZXlTaXplO1xuICAgIHZhciBrZXkgPSB0aGlzLnMyay5wcm9kdWNlX2tleShwYXNzcGhyYXNlLCBsZW5ndGgpO1xuXG4gICAgaWYgKHRoaXMuZW5jcnlwdGVkID09IG51bGwpIHtcbiAgICAgIHRoaXMuc2Vzc2lvbktleSA9IGtleTtcblxuICAgIH0gZWxzZSB7XG4gICAgICB2YXIgZGVjcnlwdGVkID0gY3J5cHRvLmNmYi5kZWNyeXB0KFxuICAgICAgICB0aGlzLnNlc3Npb25LZXlFbmNyeXB0aW9uQWxnb3JpdGhtLCBrZXksIHRoaXMuZW5jcnlwdGVkLCB0cnVlKTtcblxuICAgICAgdGhpcy5zZXNzaW9uS2V5QWxnb3JpdGhtID0gZW51bXMucmVhZChlbnVtcy5zeW1tZXRyaWMsXG4gICAgICAgIGRlY3J5cHRlZFswXS5rZXlDb2RlQXQoKSk7XG5cbiAgICAgIHRoaXMuc2Vzc2lvbktleSA9IGRlY3J5cHRlZC5zdWJzdHIoMSk7XG4gICAgfVxuICB9XG5cbiAgdGhpcy5lbmNyeXB0ID0gZnVuY3Rpb24ocGFzc3BocmFzZSkge1xuICAgIHZhciBsZW5ndGggPSBjcnlwdG8uZ2V0S2V5TGVuZ3RoKHRoaXMuc2Vzc2lvbktleUVuY3J5cHRpb25BbGdvcml0aG0pO1xuICAgIHZhciBrZXkgPSB0aGlzLnMyay5wcm9kdWNlX2tleShwYXNzcGhyYXNlLCBsZW5ndGgpO1xuXG4gICAgdmFyIHByaXZhdGVfa2V5ID0gU3RyaW5nLmZyb21DaGFyQ29kZShcbiAgICAgIGVudW1zLndyaXRlKGVudW1zLnN5bW1ldHJpYywgdGhpcy5zZXNzaW9uS2V5QWxnb3JpdGhtKSkgK1xuXG4gICAgY3J5cHRvLmdldFJhbmRvbUJ5dGVzKFxuICAgICAgY3J5cHRvLmdldEtleUxlbmd0aCh0aGlzLnNlc3Npb25LZXlBbGdvcml0aG0pKTtcblxuICAgIHRoaXMuZW5jcnlwdGVkID0gY3J5cHRvLmNmYi5lbmNyeXB0KFxuICAgICAgY3J5cHRvLmdldFByZWZpeFJhbmRvbSh0aGlzLnNlc3Npb25LZXlFbmNyeXB0aW9uQWxnb3JpdGhtKSxcbiAgICAgIHRoaXMuc2Vzc2lvbktleUVuY3J5cHRpb25BbGdvcml0aG0sIGtleSwgcHJpdmF0ZV9rZXksIHRydWUpO1xuICB9XG59O1xuIiwiLy8gR1BHNEJyb3dzZXJzIC0gQW4gT3BlblBHUCBpbXBsZW1lbnRhdGlvbiBpbiBqYXZhc2NyaXB0XG4vLyBDb3B5cmlnaHQgKEMpIDIwMTEgUmVjdXJpdHkgTGFicyBHbWJIXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3Jcbi8vIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlclxuLy8gdmVyc2lvbiAyLjEgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuLy8gYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2Zcbi8vIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUgR05VXG4vLyBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuLy8gXG4vLyBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFsb25nIHdpdGggdGhpcyBsaWJyYXJ5OyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlXG4vLyBGb3VuZGF0aW9uLCBJbmMuLCA1MSBGcmFua2xpbiBTdHJlZXQsIEZpZnRoIEZsb29yLCBCb3N0b24sIE1BICAwMjExMC0xMzAxICBVU0FcblxudmFyIGNyeXB0byA9IHJlcXVpcmUoJy4uL2NyeXB0bycpO1xuXG4vKipcbiAqIEBjbGFzc1xuICogQGNsYXNzZGVzYyBJbXBsZW1lbnRhdGlvbiBvZiB0aGUgU3ltbWV0cmljYWxseSBFbmNyeXB0ZWQgRGF0YSBQYWNrZXQgKFRhZyA5KVxuICogXG4gKiBSRkM0ODgwIDUuNzogVGhlIFN5bW1ldHJpY2FsbHkgRW5jcnlwdGVkIERhdGEgcGFja2V0IGNvbnRhaW5zIGRhdGEgZW5jcnlwdGVkXG4gKiB3aXRoIGEgc3ltbWV0cmljLWtleSBhbGdvcml0aG0uIFdoZW4gaXQgaGFzIGJlZW4gZGVjcnlwdGVkLCBpdCBjb250YWlucyBvdGhlclxuICogcGFja2V0cyAodXN1YWxseSBhIGxpdGVyYWwgZGF0YSBwYWNrZXQgb3IgY29tcHJlc3NlZCBkYXRhIHBhY2tldCwgYnV0IGluXG4gKiB0aGVvcnkgb3RoZXIgU3ltbWV0cmljYWxseSBFbmNyeXB0ZWQgRGF0YSBwYWNrZXRzIG9yIHNlcXVlbmNlcyBvZiBwYWNrZXRzXG4gKiB0aGF0IGZvcm0gd2hvbGUgT3BlblBHUCBtZXNzYWdlcykuXG4gKi9cblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiBwYWNrZXRfc3ltbWV0cmljYWxseV9lbmNyeXB0ZWQoKSB7XG4gIHRoaXMuZW5jcnlwdGVkID0gbnVsbDtcbiAgLyoqIERlY3J5cHRlZCBwYWNrZXRzIGNvbnRhaW5lZCB3aXRoaW4uIFxuICAgKiBAdHlwZSB7b3BlbnBncF9wYWNrZXRsaXN0fSAqL1xuICB0aGlzLnBhY2tldHM7XG5cbiAgdGhpcy5yZWFkID0gZnVuY3Rpb24oYnl0ZXMpIHtcbiAgICB0aGlzLmVuY3J5cHRlZCA9IGJ5dGVzO1xuICB9XG5cbiAgdGhpcy53cml0ZSA9IGZ1bmN0aW9uKCkge1xuICAgIHJldHVybiB0aGlzLmVuY3J5cHRlZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBTeW1tZXRyaWNhbGx5IGRlY3J5cHQgdGhlIHBhY2tldCBkYXRhXG4gICAqIFxuICAgKiBAcGFyYW0ge0ludGVnZXJ9IHNlc3Npb25LZXlBbGdvcml0aG1cbiAgICogICAgICAgICAgICAgU3ltbWV0cmljIGtleSBhbGdvcml0aG0gdG8gdXNlIC8vIFNlZSBSRkM0ODgwIDkuMlxuICAgKiBAcGFyYW0ge1N0cmluZ30ga2V5XG4gICAqICAgICAgICAgICAgIEtleSBhcyBzdHJpbmcgd2l0aCB0aGUgY29ycmVzcG9uZGluZyBsZW5ndGggdG8gdGhlXG4gICAqICAgICAgICAgICAgYWxnb3JpdGhtXG4gICAqIEByZXR1cm4gVGhlIGRlY3J5cHRlZCBkYXRhO1xuICAgKi9cbiAgdGhpcy5kZWNyeXB0ID0gZnVuY3Rpb24oc2Vzc2lvbktleUFsZ29yaXRobSwga2V5KSB7XG4gICAgdmFyIGRlY3J5cHRlZCA9IGNyeXB0by5jZmIuZGVjcnlwdChcbiAgICAgIHNlc3Npb25LZXlBbGdvcml0aG0sIGtleSwgdGhpcy5lbmNyeXB0ZWQsIHRydWUpO1xuXG4gICAgdGhpcy5wYWNrZXRzLnJlYWQoZGVjcnlwdGVkKTtcbiAgfVxuXG4gIHRoaXMuZW5jcnlwdCA9IGZ1bmN0aW9uKGFsZ28sIGtleSkge1xuICAgIHZhciBkYXRhID0gdGhpcy5wYWNrZXRzLndyaXRlKCk7XG5cbiAgICB0aGlzLmVuY3J5cHRlZCA9IGNyeXB0by5jZmIuZW5jcnlwdChcbiAgICAgIGNyeXB0by5nZXRQcmVmaXhSYW5kb20oYWxnbyksIGFsZ28sIGRhdGEsIGtleSwgdHJ1ZSk7XG4gIH1cbn07XG4iLCJtb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIHBhY2tldF90cnVzdCgpIHtcblxufTtcbiIsIi8vIEdQRzRCcm93c2VycyAtIEFuIE9wZW5QR1AgaW1wbGVtZW50YXRpb24gaW4gamF2YXNjcmlwdFxuLy8gQ29weXJpZ2h0IChDKSAyMDExIFJlY3VyaXR5IExhYnMgR21iSFxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yXG4vLyBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uOyBlaXRoZXJcbi8vIHZlcnNpb24gMi4xIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbi8vIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4vLyBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlIEdOVVxuLy8gTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cbi8vIFxuLy8gWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhbG9uZyB3aXRoIHRoaXMgbGlicmFyeTsgaWYgbm90LCB3cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZVxuLy8gRm91bmRhdGlvbiwgSW5jLiwgNTEgRnJhbmtsaW4gU3RyZWV0LCBGaWZ0aCBGbG9vciwgQm9zdG9uLCBNQSAgMDIxMTAtMTMwMSAgVVNBXG5cbi8qKiBcbiAqIEBjbGFzc1xuICogQGNsYXNzZGVzYyBJbXBsZW1lbnRhdGlvbiBvZiB0aGUgVXNlciBBdHRyaWJ1dGUgUGFja2V0IChUYWcgMTcpXG4gKiAgVGhlIFVzZXIgQXR0cmlidXRlIHBhY2tldCBpcyBhIHZhcmlhdGlvbiBvZiB0aGUgVXNlciBJRCBwYWNrZXQuICBJdFxuICogIGlzIGNhcGFibGUgb2Ygc3RvcmluZyBtb3JlIHR5cGVzIG9mIGRhdGEgdGhhbiB0aGUgVXNlciBJRCBwYWNrZXQsXG4gKiAgd2hpY2ggaXMgbGltaXRlZCB0byB0ZXh0LiAgTGlrZSB0aGUgVXNlciBJRCBwYWNrZXQsIGEgVXNlciBBdHRyaWJ1dGVcbiAqICBwYWNrZXQgbWF5IGJlIGNlcnRpZmllZCBieSB0aGUga2V5IG93bmVyIChcInNlbGYtc2lnbmVkXCIpIG9yIGFueSBvdGhlclxuICogIGtleSBvd25lciB3aG8gY2FyZXMgdG8gY2VydGlmeSBpdC4gIEV4Y2VwdCBhcyBub3RlZCwgYSBVc2VyIEF0dHJpYnV0ZVxuICogIHBhY2tldCBtYXkgYmUgdXNlZCBhbnl3aGVyZSB0aGF0IGEgVXNlciBJRCBwYWNrZXQgbWF5IGJlIHVzZWQuXG4gKlxuICogIFdoaWxlIFVzZXIgQXR0cmlidXRlIHBhY2tldHMgYXJlIG5vdCBhIHJlcXVpcmVkIHBhcnQgb2YgdGhlIE9wZW5QR1BcbiAqICBzdGFuZGFyZCwgaW1wbGVtZW50YXRpb25zIFNIT1VMRCBwcm92aWRlIGF0IGxlYXN0IGVub3VnaFxuICogIGNvbXBhdGliaWxpdHkgdG8gcHJvcGVybHkgaGFuZGxlIGEgY2VydGlmaWNhdGlvbiBzaWduYXR1cmUgb24gdGhlXG4gKiAgVXNlciBBdHRyaWJ1dGUgcGFja2V0LiAgQSBzaW1wbGUgd2F5IHRvIGRvIHRoaXMgaXMgYnkgdHJlYXRpbmcgdGhlXG4gKiAgVXNlciBBdHRyaWJ1dGUgcGFja2V0IGFzIGEgVXNlciBJRCBwYWNrZXQgd2l0aCBvcGFxdWUgY29udGVudHMsIGJ1dFxuICogIGFuIGltcGxlbWVudGF0aW9uIG1heSB1c2UgYW55IG1ldGhvZCBkZXNpcmVkLlxuICovXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIHBhY2tldF91c2VyX2F0dHJpYnV0ZSgpIHtcbiAgdGhpcy50YWcgPSAxNztcbiAgdGhpcy5hdHRyaWJ1dGVzID0gW107XG5cbiAgLyoqXG4gICAqIHBhcnNpbmcgZnVuY3Rpb24gZm9yIGEgdXNlciBhdHRyaWJ1dGUgcGFja2V0ICh0YWcgMTcpLlxuICAgKiBAcGFyYW0ge1N0cmluZ30gaW5wdXQgcGF5bG9hZCBvZiBhIHRhZyAxNyBwYWNrZXRcbiAgICogQHBhcmFtIHtJbnRlZ2VyfSBwb3NpdGlvbiBwb3NpdGlvbiB0byBzdGFydCByZWFkaW5nIGZyb20gdGhlIGlucHV0IHN0cmluZ1xuICAgKiBAcGFyYW0ge0ludGVnZXJ9IGxlbiBsZW5ndGggb2YgdGhlIHBhY2tldCBvciB0aGUgcmVtYWluaW5nIGxlbmd0aCBvZiBpbnB1dCBhdCBwb3NpdGlvblxuICAgKiBAcmV0dXJuIHtvcGVucGdwX3BhY2tldF9lbmNyeXB0ZWRkYXRhfSBvYmplY3QgcmVwcmVzZW50YXRpb25cbiAgICovXG4gIHRoaXMucmVhZCA9IGZ1bmN0aW9uKGJ5dGVzKSB7XG4gICAgdmFyIGkgPSAwO1xuICAgIHdoaWxlIChpIDwgYnl0ZXMubGVuZ3RoKSB7XG4gICAgICB2YXIgbGVuID0gb3BlbnBncF9wYWNrZXQucmVhZF9zaW1wbGVfbGVuZ3RoKGJ5dGVzKTtcblxuICAgICAgaSArPSBsZW4ub2Zmc2V0O1xuICAgICAgdGhpcy5hdHRyaWJ1dGVzLnB1c2goYnl0ZXMuc3Vic3RyKGksIGxlbi5sZW4pKTtcbiAgICAgIGkgKz0gbGVuLmxlbjtcbiAgICB9XG4gIH1cbn07XG4iLCIvLyBHUEc0QnJvd3NlcnMgLSBBbiBPcGVuUEdQIGltcGxlbWVudGF0aW9uIGluIGphdmFzY3JpcHRcbi8vIENvcHlyaWdodCAoQykgMjAxMSBSZWN1cml0eSBMYWJzIEdtYkhcbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vclxuLy8gbW9kaWZ5IGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyXG4vLyB2ZXJzaW9uIDIuMSBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4vLyBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuLy8gTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZSBHTlVcbi8vIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG4vLyBcbi8vIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYWxvbmcgd2l0aCB0aGlzIGxpYnJhcnk7IGlmIG5vdCwgd3JpdGUgdG8gdGhlIEZyZWUgU29mdHdhcmVcbi8vIEZvdW5kYXRpb24sIEluYy4sIDUxIEZyYW5rbGluIFN0cmVldCwgRmlmdGggRmxvb3IsIEJvc3RvbiwgTUEgIDAyMTEwLTEzMDEgIFVTQVxuXG52YXIgdXRpbCA9IHJlcXVpcmUoJy4uL3V0aWwnKTtcblxuLyoqXG4gKiBAY2xhc3NcbiAqIEBjbGFzc2Rlc2MgSW1wbGVtZW50YXRpb24gb2YgdGhlIFVzZXIgSUQgUGFja2V0IChUYWcgMTMpXG4gKiBBIFVzZXIgSUQgcGFja2V0IGNvbnNpc3RzIG9mIFVURi04IHRleHQgdGhhdCBpcyBpbnRlbmRlZCB0byByZXByZXNlbnRcbiAqIHRoZSBuYW1lIGFuZCBlbWFpbCBhZGRyZXNzIG9mIHRoZSBrZXkgaG9sZGVyLiAgQnkgY29udmVudGlvbiwgaXRcbiAqIGluY2x1ZGVzIGFuIFJGQyAyODIyIFtSRkMyODIyXSBtYWlsIG5hbWUtYWRkciwgYnV0IHRoZXJlIGFyZSBub1xuICogcmVzdHJpY3Rpb25zIG9uIGl0cyBjb250ZW50LiAgVGhlIHBhY2tldCBsZW5ndGggaW4gdGhlIGhlYWRlclxuICogc3BlY2lmaWVzIHRoZSBsZW5ndGggb2YgdGhlIFVzZXIgSUQuIFxuICovXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIHBhY2tldF91c2VyaWQoKSB7XG4gIC8qKiBAdHlwZSB7U3RyaW5nfSBBIHN0cmluZyBjb250YWluaW5nIHRoZSB1c2VyIGlkLiBVc3VhbGx5IGluIHRoZSBmb3JtXG4gICAqIEpvaG4gRG9lIDxqb2huQGV4YW1wbGUuY29tPiBcbiAgICovXG4gIHRoaXMudXNlcmlkID0gJyc7XG5cblxuICAvKipcbiAgICogUGFyc2luZyBmdW5jdGlvbiBmb3IgYSB1c2VyIGlkIHBhY2tldCAodGFnIDEzKS5cbiAgICogQHBhcmFtIHtTdHJpbmd9IGlucHV0IHBheWxvYWQgb2YgYSB0YWcgMTMgcGFja2V0XG4gICAqIEBwYXJhbSB7SW50ZWdlcn0gcG9zaXRpb24gcG9zaXRpb24gdG8gc3RhcnQgcmVhZGluZyBmcm9tIHRoZSBpbnB1dCBzdHJpbmdcbiAgICogQHBhcmFtIHtJbnRlZ2VyfSBsZW4gbGVuZ3RoIG9mIHRoZSBwYWNrZXQgb3IgdGhlIHJlbWFpbmluZyBsZW5ndGggb2YgaW5wdXQgXG4gICAqIGF0IHBvc2l0aW9uXG4gICAqIEByZXR1cm4ge29wZW5wZ3BfcGFja2V0X2VuY3J5cHRlZGRhdGF9IG9iamVjdCByZXByZXNlbnRhdGlvblxuICAgKi9cbiAgdGhpcy5yZWFkID0gZnVuY3Rpb24oYnl0ZXMpIHtcbiAgICB0aGlzLnVzZXJpZCA9IHV0aWwuZGVjb2RlX3V0ZjgoYnl0ZXMpO1xuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZXMgYSBzdHJpbmcgcmVwcmVzZW50YXRpb24gb2YgdGhlIHVzZXIgaWQgcGFja2V0XG4gICAqIEBwYXJhbSB7U3RyaW5nfSB1c2VyX2lkIHRoZSB1c2VyIGlkIGFzIHN0cmluZyAoXCJKb2huIERvZSA8am9obi5kb2VAbWFpbC51c1wiKVxuICAgKiBAcmV0dXJuIHtTdHJpbmd9IHN0cmluZyByZXByZXNlbnRhdGlvblxuICAgKi9cbiAgdGhpcy53cml0ZSA9IGZ1bmN0aW9uKCkge1xuICAgIHJldHVybiB1dGlsLmVuY29kZV91dGY4KHRoaXMudXNlcmlkKTtcbiAgfVxufVxuIiwiLy8gR1BHNEJyb3dzZXJzIC0gQW4gT3BlblBHUCBpbXBsZW1lbnRhdGlvbiBpbiBqYXZhc2NyaXB0XG4vLyBDb3B5cmlnaHQgKEMpIDIwMTEgUmVjdXJpdHkgTGFicyBHbWJIXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3Jcbi8vIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlclxuLy8gdmVyc2lvbiAyLjEgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuLy8gYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2Zcbi8vIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUgR05VXG4vLyBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuLy8gXG4vLyBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFsb25nIHdpdGggdGhpcyBsaWJyYXJ5OyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlXG4vLyBGb3VuZGF0aW9uLCBJbmMuLCA1MSBGcmFua2xpbiBTdHJlZXQsIEZpZnRoIEZsb29yLCBCb3N0b24sIE1BICAwMjExMC0xMzAxICBVU0FcblxudmFyIHV0aWwgPSByZXF1aXJlKCcuLi91dGlsJyk7XG5cbi8qKlxuICogQGNsYXNzXG4gKiBAY2xhc3NkZXNjIEltcGxlbWVudGF0aW9uIG9mIHR5cGUga2V5IGlkIChSRkM0ODgwIDMuMylcbiAqICBBIEtleSBJRCBpcyBhbiBlaWdodC1vY3RldCBzY2FsYXIgdGhhdCBpZGVudGlmaWVzIGEga2V5LlxuICAgSW1wbGVtZW50YXRpb25zIFNIT1VMRCBOT1QgYXNzdW1lIHRoYXQgS2V5IElEcyBhcmUgdW5pcXVlLiAgVGhlXG4gICBzZWN0aW9uIFwiRW5oYW5jZWQgS2V5IEZvcm1hdHNcIiBiZWxvdyBkZXNjcmliZXMgaG93IEtleSBJRHMgYXJlXG4gICBmb3JtZWQuXG4gKi9cbmZ1bmN0aW9uIGtleWlkKCkge1xuXG4gIHRoaXMuYnl0ZXMgPSAnJztcblxuXG4gIC8qKlxuICAgKiBQYXJzaW5nIG1ldGhvZCBmb3IgYSBrZXkgaWRcbiAgICogQHBhcmFtIHtTdHJpbmd9IGlucHV0IElucHV0IHRvIHJlYWQgdGhlIGtleSBpZCBmcm9tIFxuICAgKiBAcGFyYW0ge2ludGVnZXJ9IHBvc2l0aW9uIFBvc2l0aW9uIHdoZXJlIHRvIHN0YXJ0IHJlYWRpbmcgdGhlIGtleSBcbiAgICogaWQgZnJvbSBpbnB1dFxuICAgKiBAcmV0dXJuIHtvcGVucGdwX3R5cGVfa2V5aWR9IFRoaXMgb2JqZWN0XG4gICAqL1xuICB0aGlzLnJlYWQgPSBmdW5jdGlvbihieXRlcykge1xuICAgIHRoaXMuYnl0ZXMgPSBieXRlcy5zdWJzdHIoMCwgOCk7XG4gIH1cblxuICB0aGlzLndyaXRlID0gZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIHRoaXMuYnl0ZXM7XG4gIH1cblxuICB0aGlzLnRvSGV4ID0gZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIHV0aWwuaGV4c3RyZHVtcCh0aGlzLmJ5dGVzKTtcbiAgfVxuXG4gIHRoaXMuZXF1YWxzID0gZnVuY3Rpb24oa2V5aWQpIHtcbiAgICByZXR1cm4gdGhpcy5ieXRlcyA9PSBrZXlpZC5ieXRlcztcbiAgfVxuXG4gIHRoaXMuaXNOdWxsID0gZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIHRoaXMuYnl0ZXMgPT09ICcnO1xuICB9XG59XG5cbmtleWlkLm1hcFRvSGV4ID0gZnVuY3Rpb24oa2V5aWQpIHtcbiAgcmV0dXJuIGtleWlkLnRvSGV4KCk7XG59XG5cbm1vZHVsZS5leHBvcnRzID0ga2V5aWQ7XG4iLCIvLyBHUEc0QnJvd3NlcnMgLSBBbiBPcGVuUEdQIGltcGxlbWVudGF0aW9uIGluIGphdmFzY3JpcHRcbi8vIENvcHlyaWdodCAoQykgMjAxMSBSZWN1cml0eSBMYWJzIEdtYkhcbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vclxuLy8gbW9kaWZ5IGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyXG4vLyB2ZXJzaW9uIDIuMSBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4vLyBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuLy8gTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZSBHTlVcbi8vIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG4vLyBcbi8vIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYWxvbmcgd2l0aCB0aGlzIGxpYnJhcnk7IGlmIG5vdCwgd3JpdGUgdG8gdGhlIEZyZWUgU29mdHdhcmVcbi8vIEZvdW5kYXRpb24sIEluYy4sIDUxIEZyYW5rbGluIFN0cmVldCwgRmlmdGggRmxvb3IsIEJvc3RvbiwgTUEgIDAyMTEwLTEzMDEgIFVTQVxuXG4vLyBIaW50OiBXZSBob2xkIG91ciBNUElzIGFzIGFuIGFycmF5IG9mIG9jdGV0cyBpbiBiaWcgZW5kaWFuIGZvcm1hdCBwcmVjZWVkaW5nIGEgdHdvXG4vLyBvY3RldCBzY2FsYXI6IE1QSTogW2EsYixjLGQsZSxmXVxuLy8gLSBNUEkgc2l6ZTogKGEgPDwgOCkgfCBiIFxuLy8gLSBNUEkgPSBjIHwgZCA8PCA4IHwgZSA8PCAoKE1QSS5sZW5ndGggLTIpKjgpIHwgZiAoKE1QSS5sZW5ndGggLTIpKjgpXG5cbnZhciBCaWdJbnRlZ2VyID0gcmVxdWlyZSgnLi4vY3J5cHRvL3B1YmxpY19rZXkvanNibi5qcycpLFxuICB1dGlsID0gcmVxdWlyZSgnLi4vdXRpbCcpO1xuXG4vKipcbiAqIEBjbGFzc1xuICogQGNsYXNzZGVzY0ltcGxlbWVudGF0aW9uIG9mIHR5cGUgTVBJIChSRkM0ODgwIDMuMilcbiAqIE11bHRpcHJlY2lzaW9uIGludGVnZXJzIChhbHNvIGNhbGxlZCBNUElzKSBhcmUgdW5zaWduZWQgaW50ZWdlcnMgdXNlZFxuICogdG8gaG9sZCBsYXJnZSBpbnRlZ2VycyBzdWNoIGFzIHRoZSBvbmVzIHVzZWQgaW4gY3J5cHRvZ3JhcGhpY1xuICogY2FsY3VsYXRpb25zLlxuICogQW4gTVBJIGNvbnNpc3RzIG9mIHR3byBwaWVjZXM6IGEgdHdvLW9jdGV0IHNjYWxhciB0aGF0IGlzIHRoZSBsZW5ndGhcbiAqIG9mIHRoZSBNUEkgaW4gYml0cyBmb2xsb3dlZCBieSBhIHN0cmluZyBvZiBvY3RldHMgdGhhdCBjb250YWluIHRoZVxuICogYWN0dWFsIGludGVnZXIuXG4gKi9cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gbXBpKCkge1xuICAvKiogQW4gaW1wbGVtZW50YXRpb24gZGVwZW5kZW50IGludGVnZXIgKi9cbiAgdGhpcy5kYXRhID0gbnVsbDtcblxuICAvKipcbiAgICogUGFyc2luZyBmdW5jdGlvbiBmb3IgYSBtcGkgKFJGQyA0ODgwIDMuMikuXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBpbnB1dCBQYXlsb2FkIG9mIG1waSBkYXRhXG4gICAqIEBwYXJhbSB7SW50ZWdlcn0gcG9zaXRpb24gUG9zaXRpb24gdG8gc3RhcnQgcmVhZGluZyBmcm9tIHRoZSBpbnB1dCBcbiAgICogc3RyaW5nXG4gICAqIEBwYXJhbSB7SW50ZWdlcn0gbGVuIExlbmd0aCBvZiB0aGUgcGFja2V0IG9yIHRoZSByZW1haW5pbmcgbGVuZ3RoIG9mIFxuICAgKiBpbnB1dCBhdCBwb3NpdGlvblxuICAgKiBAcmV0dXJuIHtvcGVucGdwX3R5cGVfbXBpfSBPYmplY3QgcmVwcmVzZW50YXRpb25cbiAgICovXG4gIHRoaXMucmVhZCA9IGZ1bmN0aW9uKGJ5dGVzKSB7XG4gICAgdmFyIGJpdHMgPSAoYnl0ZXMuY2hhckNvZGVBdCgwKSA8PCA4KSB8IGJ5dGVzLmNoYXJDb2RlQXQoMSk7XG5cbiAgICAvLyBBZGRpdGlvbmFsIHJ1bGVzOlxuICAgIC8vXG4gICAgLy8gICAgVGhlIHNpemUgb2YgYW4gTVBJIGlzICgoTVBJLmxlbmd0aCArIDcpIC8gOCkgKyAyIG9jdGV0cy5cbiAgICAvL1xuICAgIC8vICAgIFRoZSBsZW5ndGggZmllbGQgb2YgYW4gTVBJIGRlc2NyaWJlcyB0aGUgbGVuZ3RoIHN0YXJ0aW5nIGZyb20gaXRzXG4gICAgLy9cdCAgbW9zdCBzaWduaWZpY2FudCBub24temVybyBiaXQuICBUaHVzLCB0aGUgTVBJIFswMCAwMiAwMV0gaXMgbm90XG4gICAgLy8gICAgZm9ybWVkIGNvcnJlY3RseS4gIEl0IHNob3VsZCBiZSBbMDAgMDEgMDFdLlxuXG4gICAgLy8gVE9ETzogVmVyaWZpY2F0aW9uIG9mIHRoaXMgc2l6ZSBtZXRob2QhIFRoaXMgc2l6ZSBjYWxjdWxhdGlvbiBhc1xuICAgIC8vIFx0XHQgc3BlY2lmaWVkIGFib3ZlIGlzIG5vdCBhcHBsaWNhYmxlIGluIEphdmFTY3JpcHRcbiAgICB2YXIgYnl0ZWxlbiA9IE1hdGguY2VpbChiaXRzIC8gOCk7XG5cbiAgICB2YXIgcmF3ID0gYnl0ZXMuc3Vic3RyKDIsIGJ5dGVsZW4pO1xuICAgIHRoaXMuZnJvbUJ5dGVzKHJhdyk7XG5cbiAgICByZXR1cm4gMiArIGJ5dGVsZW47XG4gIH1cblxuICB0aGlzLmZyb21CeXRlcyA9IGZ1bmN0aW9uKGJ5dGVzKSB7XG4gICAgdGhpcy5kYXRhID0gbmV3IEJpZ0ludGVnZXIodXRpbC5oZXhzdHJkdW1wKGJ5dGVzKSwgMTYpO1xuICB9XG5cbiAgdGhpcy50b0J5dGVzID0gZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIHRoaXMud3JpdGUoKS5zdWJzdHIoMik7XG4gIH1cblxuICB0aGlzLmJ5dGVMZW5ndGggPSBmdW5jdGlvbigpIHtcbiAgICByZXR1cm4gdGhpcy50b0J5dGVzKCkubGVuZ3RoO1xuICB9XG5cbiAgLyoqXG4gICAqIENvbnZlcnRzIHRoZSBtcGkgb2JqZWN0IHRvIGEgc3RyaW5nIGFzIHNwZWNpZmllZCBpbiBSRkM0ODgwIDMuMlxuICAgKiBAcmV0dXJuIHtTdHJpbmd9IG1waSBCeXRlIHJlcHJlc2VudGF0aW9uXG4gICAqL1xuICB0aGlzLndyaXRlID0gZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIHRoaXMuZGF0YS50b01QSSgpO1xuICB9XG5cbiAgdGhpcy50b0JpZ0ludGVnZXIgPSBmdW5jdGlvbigpIHtcbiAgICByZXR1cm4gdGhpcy5kYXRhLmNsb25lKCk7XG4gIH1cblxuICB0aGlzLmZyb21CaWdJbnRlZ2VyID0gZnVuY3Rpb24oYm4pIHtcbiAgICB0aGlzLmRhdGEgPSBibi5jbG9uZSgpO1xuICB9XG59XG4iLCIvLyBHUEc0QnJvd3NlcnMgLSBBbiBPcGVuUEdQIGltcGxlbWVudGF0aW9uIGluIGphdmFzY3JpcHRcbi8vIENvcHlyaWdodCAoQykgMjAxMSBSZWN1cml0eSBMYWJzIEdtYkhcbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vclxuLy8gbW9kaWZ5IGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyXG4vLyB2ZXJzaW9uIDIuMSBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4vLyBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuLy8gTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZSBHTlVcbi8vIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG4vLyBcbi8vIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYWxvbmcgd2l0aCB0aGlzIGxpYnJhcnk7IGlmIG5vdCwgd3JpdGUgdG8gdGhlIEZyZWUgU29mdHdhcmVcbi8vIEZvdW5kYXRpb24sIEluYy4sIDUxIEZyYW5rbGluIFN0cmVldCwgRmlmdGggRmxvb3IsIEJvc3RvbiwgTUEgIDAyMTEwLTEzMDEgIFVTQVxuXG52YXIgZW51bXMgPSByZXF1aXJlKCcuLi9lbnVtcy5qcycpLFxuICB1dGlsID0gcmVxdWlyZSgnLi4vdXRpbCcpLFxuICBjcnlwdG8gPSByZXF1aXJlKCcuLi9jcnlwdG8nKTtcblxuLyoqXG4gKiBAY2xhc3NcbiAqIEBjbGFzc2Rlc2MgSW1wbGVtZW50YXRpb24gb2YgdGhlIFN0cmluZy10by1rZXkgc3BlY2lmaWVyIChSRkM0ODgwIDMuNylcbiAqIFN0cmluZy10by1rZXkgKFMySykgc3BlY2lmaWVycyBhcmUgdXNlZCB0byBjb252ZXJ0IHBhc3NwaHJhc2Ugc3RyaW5nc1xuICAgaW50byBzeW1tZXRyaWMta2V5IGVuY3J5cHRpb24vZGVjcnlwdGlvbiBrZXlzLiAgVGhleSBhcmUgdXNlZCBpbiB0d29cbiAgIHBsYWNlcywgY3VycmVudGx5OiB0byBlbmNyeXB0IHRoZSBzZWNyZXQgcGFydCBvZiBwcml2YXRlIGtleXMgaW4gdGhlXG4gICBwcml2YXRlIGtleXJpbmcsIGFuZCB0byBjb252ZXJ0IHBhc3NwaHJhc2VzIHRvIGVuY3J5cHRpb24ga2V5cyBmb3JcbiAgIHN5bW1ldHJpY2FsbHkgZW5jcnlwdGVkIG1lc3NhZ2VzLlxuICovXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIHMyaygpIHtcbiAgLyoqIEB0eXBlIHtvcGVucGdwLmhhc2h9ICovXG4gIHRoaXMuYWxnb3JpdGhtID0gJ3NoYTI1Nic7XG4gIC8qKiBAdHlwZSB7b3BlbnBncF90eXBlX3Myay50eXBlfSAqL1xuICB0aGlzLnR5cGUgPSAnaXRlcmF0ZWQnO1xuICB0aGlzLmMgPSA5NjtcbiAgLyoqIEB0eXBlIHtvcGVucGdwX2J5dGVhcnJheX0gXG4gICAqIEVpZ2h0IGJ5dGVzIG9mIHNhbHQuICovXG4gIHRoaXMuc2FsdCA9IGNyeXB0by5yYW5kb20uZ2V0UmFuZG9tQnl0ZXMoOCk7XG5cblxuICAvLyBFeHBvbmVuIGJpYXMsIGRlZmluZWQgaW4gUkZDNDg4MFxuICB2YXIgZXhwYmlhcyA9IDY7XG5cbiAgdGhpcy5nZXRfY291bnQgPSBmdW5jdGlvbigpIHtcbiAgICByZXR1cm4gKDE2ICsgKHRoaXMuYyAmIDE1KSkgPDwgKCh0aGlzLmMgPj4gNCkgKyBleHBiaWFzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBQYXJzaW5nIGZ1bmN0aW9uIGZvciBhIHN0cmluZy10by1rZXkgc3BlY2lmaWVyIChSRkMgNDg4MCAzLjcpLlxuICAgKiBAcGFyYW0ge1N0cmluZ30gaW5wdXQgUGF5bG9hZCBvZiBzdHJpbmctdG8ta2V5IHNwZWNpZmllclxuICAgKiBAcmV0dXJuIHtJbnRlZ2VyfSBBY3R1YWwgbGVuZ3RoIG9mIHRoZSBvYmplY3RcbiAgICovXG4gIHRoaXMucmVhZCA9IGZ1bmN0aW9uKGJ5dGVzKSB7XG4gICAgdmFyIGkgPSAwO1xuICAgIHRoaXMudHlwZSA9IGVudW1zLnJlYWQoZW51bXMuczJrLCBieXRlcy5jaGFyQ29kZUF0KGkrKykpO1xuICAgIHRoaXMuYWxnb3JpdGhtID0gZW51bXMucmVhZChlbnVtcy5oYXNoLCBieXRlcy5jaGFyQ29kZUF0KGkrKykpO1xuXG4gICAgc3dpdGNoICh0aGlzLnR5cGUpIHtcbiAgICAgIGNhc2UgJ3NpbXBsZSc6XG4gICAgICAgIGJyZWFrO1xuXG4gICAgICBjYXNlICdzYWx0ZWQnOlxuICAgICAgICB0aGlzLnNhbHQgPSBieXRlcy5zdWJzdHIoaSwgOCk7XG4gICAgICAgIGkgKz0gODtcbiAgICAgICAgYnJlYWs7XG5cbiAgICAgIGNhc2UgJ2l0ZXJhdGVkJzpcbiAgICAgICAgdGhpcy5zYWx0ID0gYnl0ZXMuc3Vic3RyKGksIDgpO1xuICAgICAgICBpICs9IDg7XG5cbiAgICAgICAgLy8gT2N0ZXQgMTA6IGNvdW50LCBhIG9uZS1vY3RldCwgY29kZWQgdmFsdWVcbiAgICAgICAgdGhpcy5jID0gYnl0ZXMuY2hhckNvZGVBdChpKyspO1xuICAgICAgICBicmVhaztcblxuICAgICAgY2FzZSAnZ251JzpcbiAgICAgICAgaWYgKGJ5dGVzLnN1YnN0cihpLCAzKSA9PSBcIkdOVVwiKSB7XG4gICAgICAgICAgaSArPSAzOyAvLyBHTlVcbiAgICAgICAgICB2YXIgZ251RXh0VHlwZSA9IDEwMDAgKyBieXRlcy5jaGFyQ29kZUF0KGkrKyk7XG4gICAgICAgICAgaWYgKGdudUV4dFR5cGUgPT0gMTAwMSkge1xuICAgICAgICAgICAgdGhpcy50eXBlID0gZ251RXh0VHlwZTtcbiAgICAgICAgICAgIC8vIEdudVBHIGV4dGVuc2lvbiBtb2RlIDEwMDEgLS0gZG9uJ3Qgd3JpdGUgc2VjcmV0IGtleSBhdCBhbGxcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiVW5rbm93biBzMmsgZ251IHByb3RlY3Rpb24gbW9kZS5cIik7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIlVua25vd24gczJrIHR5cGUuXCIpO1xuICAgICAgICB9XG4gICAgICAgIGJyZWFrO1xuXG4gICAgICBkZWZhdWx0OlxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJVbmtub3duIHMyayB0eXBlLlwiKTtcbiAgICAgICAgYnJlYWs7XG4gICAgfVxuXG4gICAgcmV0dXJuIGk7XG4gIH1cblxuXG4gIC8qKlxuICAgKiB3cml0ZXMgYW4gczJrIGhhc2ggYmFzZWQgb24gdGhlIGlucHV0cy5cbiAgICogQHJldHVybiB7U3RyaW5nfSBQcm9kdWNlZCBrZXkgb2YgaGFzaEFsZ29yaXRobSBoYXNoIGxlbmd0aFxuICAgKi9cbiAgdGhpcy53cml0ZSA9IGZ1bmN0aW9uKCkge1xuICAgIHZhciBieXRlcyA9IFN0cmluZy5mcm9tQ2hhckNvZGUoZW51bXMud3JpdGUoZW51bXMuczJrLCB0aGlzLnR5cGUpKTtcbiAgICBieXRlcyArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGVudW1zLndyaXRlKGVudW1zLmhhc2gsIHRoaXMuYWxnb3JpdGhtKSk7XG5cbiAgICBzd2l0Y2ggKHRoaXMudHlwZSkge1xuICAgICAgY2FzZSAnc2ltcGxlJzpcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlICdzYWx0ZWQnOlxuICAgICAgICBieXRlcyArPSB0aGlzLnNhbHQ7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAnaXRlcmF0ZWQnOlxuICAgICAgICBieXRlcyArPSB0aGlzLnNhbHQ7XG4gICAgICAgIGJ5dGVzICs9IFN0cmluZy5mcm9tQ2hhckNvZGUodGhpcy5jKTtcbiAgICAgICAgYnJlYWs7XG4gICAgfTtcblxuICAgIHJldHVybiBieXRlcztcbiAgfVxuXG4gIC8qKlxuICAgKiBQcm9kdWNlcyBhIGtleSB1c2luZyB0aGUgc3BlY2lmaWVkIHBhc3NwaHJhc2UgYW5kIHRoZSBkZWZpbmVkIFxuICAgKiBoYXNoQWxnb3JpdGhtIFxuICAgKiBAcGFyYW0ge1N0cmluZ30gcGFzc3BocmFzZSBQYXNzcGhyYXNlIGNvbnRhaW5pbmcgdXNlciBpbnB1dFxuICAgKiBAcmV0dXJuIHtTdHJpbmd9IFByb2R1Y2VkIGtleSB3aXRoIGEgbGVuZ3RoIGNvcnJlc3BvbmRpbmcgdG8gXG4gICAqIGhhc2hBbGdvcml0aG0gaGFzaCBsZW5ndGhcbiAgICovXG4gIHRoaXMucHJvZHVjZV9rZXkgPSBmdW5jdGlvbihwYXNzcGhyYXNlLCBudW1CeXRlcykge1xuICAgIHBhc3NwaHJhc2UgPSB1dGlsLmVuY29kZV91dGY4KHBhc3NwaHJhc2UpO1xuXG4gICAgZnVuY3Rpb24gcm91bmQocHJlZml4LCBzMmspIHtcbiAgICAgIHZhciBhbGdvcml0aG0gPSBlbnVtcy53cml0ZShlbnVtcy5oYXNoLCBzMmsuYWxnb3JpdGhtKTtcblxuICAgICAgc3dpdGNoIChzMmsudHlwZSkge1xuICAgICAgICBjYXNlICdzaW1wbGUnOlxuICAgICAgICAgIHJldHVybiBjcnlwdG8uaGFzaC5kaWdlc3QoYWxnb3JpdGhtLCBwcmVmaXggKyBwYXNzcGhyYXNlKTtcblxuICAgICAgICBjYXNlICdzYWx0ZWQnOlxuICAgICAgICAgIHJldHVybiBjcnlwdG8uaGFzaC5kaWdlc3QoYWxnb3JpdGhtLFxuICAgICAgICAgICAgcHJlZml4ICsgczJrLnNhbHQgKyBwYXNzcGhyYXNlKTtcblxuICAgICAgICBjYXNlICdpdGVyYXRlZCc6XG4gICAgICAgICAgdmFyIGlzcCA9IFtdLFxuICAgICAgICAgICAgY291bnQgPSBzMmsuZ2V0X2NvdW50KCk7XG4gICAgICAgICAgZGF0YSA9IHMyay5zYWx0ICsgcGFzc3BocmFzZTtcblxuICAgICAgICAgIHdoaWxlIChpc3AubGVuZ3RoICogZGF0YS5sZW5ndGggPCBjb3VudClcbiAgICAgICAgICAgIGlzcC5wdXNoKGRhdGEpO1xuXG4gICAgICAgICAgaXNwID0gaXNwLmpvaW4oJycpO1xuXG4gICAgICAgICAgaWYgKGlzcC5sZW5ndGggPiBjb3VudClcbiAgICAgICAgICAgIGlzcCA9IGlzcC5zdWJzdHIoMCwgY291bnQpO1xuXG4gICAgICAgICAgcmV0dXJuIGNyeXB0by5oYXNoLmRpZ2VzdChhbGdvcml0aG0sIHByZWZpeCArIGlzcCk7XG4gICAgICB9O1xuICAgIH1cblxuICAgIHZhciByZXN1bHQgPSAnJyxcbiAgICAgIHByZWZpeCA9ICcnO1xuXG4gICAgd2hpbGUgKHJlc3VsdC5sZW5ndGggPD0gbnVtQnl0ZXMpIHtcbiAgICAgIHJlc3VsdCArPSByb3VuZChwcmVmaXgsIHRoaXMpO1xuICAgICAgcHJlZml4ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoMCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHJlc3VsdC5zdWJzdHIoMCwgbnVtQnl0ZXMpO1xuICB9XG59XG4iLCIvLyBHUEc0QnJvd3NlcnMgLSBBbiBPcGVuUEdQIGltcGxlbWVudGF0aW9uIGluIGphdmFzY3JpcHRcbi8vIENvcHlyaWdodCAoQykgMjAxMSBSZWN1cml0eSBMYWJzIEdtYkhcbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vclxuLy8gbW9kaWZ5IGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyXG4vLyB2ZXJzaW9uIDIuMSBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4vLyBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuLy8gTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZSBHTlVcbi8vIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG4vLyBcbi8vIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYWxvbmcgd2l0aCB0aGlzIGxpYnJhcnk7IGlmIG5vdCwgd3JpdGUgdG8gdGhlIEZyZWUgU29mdHdhcmVcbi8vIEZvdW5kYXRpb24sIEluYy4sIDUxIEZyYW5rbGluIFN0cmVldCwgRmlmdGggRmxvb3IsIEJvc3RvbiwgTUEgIDAyMTEwLTEzMDEgIFVTQVxuXG52YXIgY29uZmlnID0gcmVxdWlyZSgnLi4vY29uZmlnJyk7XG5cbnZhciBVdGlsID0gZnVuY3Rpb24oKSB7XG5cbiAgdGhpcy5yZWFkTnVtYmVyID0gZnVuY3Rpb24oYnl0ZXMpIHtcbiAgICB2YXIgbiA9IDA7XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGJ5dGVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBuIDw8PSA4O1xuICAgICAgbiArPSBieXRlcy5jaGFyQ29kZUF0KGkpO1xuICAgIH1cblxuICAgIHJldHVybiBuO1xuICB9O1xuXG4gIHRoaXMud3JpdGVOdW1iZXIgPSBmdW5jdGlvbihuLCBieXRlcykge1xuICAgIHZhciBiID0gJyc7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBieXRlczsgaSsrKSB7XG4gICAgICBiICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoKG4gPj4gKDggKiAoYnl0ZXMgLSBpIC0gMSkpKSAmIDB4RkYpO1xuICAgIH1cblxuICAgIHJldHVybiBiO1xuICB9O1xuXG5cblxuICB0aGlzLnJlYWREYXRlID0gZnVuY3Rpb24oYnl0ZXMpIHtcbiAgICB2YXIgbiA9IHRoaXMucmVhZE51bWJlcihieXRlcyk7XG4gICAgdmFyIGQgPSBuZXcgRGF0ZSgpO1xuICAgIGQuc2V0VGltZShuICogMTAwMCk7XG4gICAgcmV0dXJuIGQ7XG4gIH07XG5cbiAgdGhpcy53cml0ZURhdGUgPSBmdW5jdGlvbih0aW1lKSB7XG4gICAgdmFyIG51bWVyaWMgPSBNYXRoLnJvdW5kKHRpbWUuZ2V0VGltZSgpIC8gMTAwMCk7XG5cbiAgICByZXR1cm4gdGhpcy53cml0ZU51bWJlcihudW1lcmljLCA0KTtcbiAgfTtcblxuICB0aGlzLmVtYWlsUmVnRXggPSAvXlsrYS16QS1aMC05Xy4tXStAKFthLXpBLVowLTktXStcXC4pK1thLXpBLVowLTldezIsNn0kLztcblxuICB0aGlzLmRlYnVnID0gZmFsc2U7XG5cbiAgdGhpcy5oZXhkdW1wID0gZnVuY3Rpb24oc3RyKSB7XG4gICAgdmFyIHIgPSBbXTtcbiAgICB2YXIgZSA9IHN0ci5sZW5ndGg7XG4gICAgdmFyIGMgPSAwO1xuICAgIHZhciBoO1xuICAgIHZhciBpID0gMDtcbiAgICB3aGlsZSAoYyA8IGUpIHtcbiAgICAgIGggPSBzdHIuY2hhckNvZGVBdChjKyspLnRvU3RyaW5nKDE2KTtcbiAgICAgIHdoaWxlIChoLmxlbmd0aCA8IDIpIGggPSBcIjBcIiArIGg7XG4gICAgICByLnB1c2goXCIgXCIgKyBoKTtcbiAgICAgIGkrKztcbiAgICAgIGlmIChpICUgMzIgPT0gMClcbiAgICAgICAgci5wdXNoKFwiXFxuICAgICAgICAgICBcIik7XG4gICAgfVxuICAgIHJldHVybiByLmpvaW4oJycpO1xuICB9O1xuXG4gIC8qKlxuICAgKiBDcmVhdGUgaGV4c3RyaW5nIGZyb20gYSBiaW5hcnlcbiAgICogQHBhcmFtIHtTdHJpbmd9IHN0ciBTdHJpbmcgdG8gY29udmVydFxuICAgKiBAcmV0dXJuIHtTdHJpbmd9IFN0cmluZyBjb250YWluaW5nIHRoZSBoZXhhZGVjaW1hbCB2YWx1ZXNcbiAgICovXG4gIHRoaXMuaGV4c3RyZHVtcCA9IGZ1bmN0aW9uKHN0cikge1xuICAgIGlmIChzdHIgPT0gbnVsbClcbiAgICAgIHJldHVybiBcIlwiO1xuICAgIHZhciByID0gW107XG4gICAgdmFyIGUgPSBzdHIubGVuZ3RoO1xuICAgIHZhciBjID0gMDtcbiAgICB2YXIgaDtcbiAgICB3aGlsZSAoYyA8IGUpIHtcbiAgICAgIGggPSBzdHIuY2hhckNvZGVBdChjKyspLnRvU3RyaW5nKDE2KTtcbiAgICAgIHdoaWxlIChoLmxlbmd0aCA8IDIpIGggPSBcIjBcIiArIGg7XG4gICAgICByLnB1c2goXCJcIiArIGgpO1xuICAgIH1cbiAgICByZXR1cm4gci5qb2luKCcnKTtcbiAgfTtcblxuICAvKipcbiAgICogQ3JlYXRlIGJpbmFyeSBzdHJpbmcgZnJvbSBhIGhleCBlbmNvZGVkIHN0cmluZ1xuICAgKiBAcGFyYW0ge1N0cmluZ30gc3RyIEhleCBzdHJpbmcgdG8gY29udmVydFxuICAgKiBAcmV0dXJuIHtTdHJpbmd9IFN0cmluZyBjb250YWluaW5nIHRoZSBiaW5hcnkgdmFsdWVzXG4gICAqL1xuICB0aGlzLmhleDJiaW4gPSBmdW5jdGlvbihoZXgpIHtcbiAgICB2YXIgc3RyID0gJyc7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBoZXgubGVuZ3RoOyBpICs9IDIpXG4gICAgICBzdHIgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShwYXJzZUludChoZXguc3Vic3RyKGksIDIpLCAxNikpO1xuICAgIHJldHVybiBzdHI7XG4gIH07XG5cbiAgLyoqXG4gICAqIENyZWF0aW5nIGEgaGV4IHN0cmluZyBmcm9tIGFuIGJpbmFyeSBhcnJheSBvZiBpbnRlZ2VycyAoMC4uMjU1KVxuICAgKiBAcGFyYW0ge1N0cmluZ30gc3RyIEFycmF5IG9mIGJ5dGVzIHRvIGNvbnZlcnRcbiAgICogQHJldHVybiB7U3RyaW5nfSBIZXhhZGVjaW1hbCByZXByZXNlbnRhdGlvbiBvZiB0aGUgYXJyYXlcbiAgICovXG4gIHRoaXMuaGV4aWR1bXAgPSBmdW5jdGlvbihzdHIpIHtcbiAgICB2YXIgciA9IFtdO1xuICAgIHZhciBlID0gc3RyLmxlbmd0aDtcbiAgICB2YXIgYyA9IDA7XG4gICAgdmFyIGg7XG4gICAgd2hpbGUgKGMgPCBlKSB7XG4gICAgICBoID0gc3RyW2MrK10udG9TdHJpbmcoMTYpO1xuICAgICAgd2hpbGUgKGgubGVuZ3RoIDwgMikgaCA9IFwiMFwiICsgaDtcbiAgICAgIHIucHVzaChcIlwiICsgaCk7XG4gICAgfVxuICAgIHJldHVybiByLmpvaW4oJycpO1xuICB9O1xuXG5cbiAgLyoqXG4gICAqIENvbnZlcnQgYSBuYXRpdmUgamF2YXNjcmlwdCBzdHJpbmcgdG8gYSBzdHJpbmcgb2YgdXRmOCBieXRlc1xuICAgKiBAcGFyYW0ge1N0cmluZ30gc3RyIFRoZSBzdHJpbmcgdG8gY29udmVydFxuICAgKiBAcmV0dXJuIHtTdHJpbmd9IEEgdmFsaWQgc3F1ZW5jZSBvZiB1dGY4IGJ5dGVzXG4gICAqL1xuICB0aGlzLmVuY29kZV91dGY4ID0gZnVuY3Rpb24oc3RyKSB7XG4gICAgcmV0dXJuIHVuZXNjYXBlKGVuY29kZVVSSUNvbXBvbmVudChzdHIpKTtcbiAgfTtcblxuICAvKipcbiAgICogQ29udmVydCBhIHN0cmluZyBvZiB1dGY4IGJ5dGVzIHRvIGEgbmF0aXZlIGphdmFzY3JpcHQgc3RyaW5nXG4gICAqIEBwYXJhbSB7U3RyaW5nfSB1dGY4IEEgdmFsaWQgc3F1ZW5jZSBvZiB1dGY4IGJ5dGVzXG4gICAqIEByZXR1cm4ge1N0cmluZ30gQSBuYXRpdmUgamF2YXNjcmlwdCBzdHJpbmdcbiAgICovXG4gIHRoaXMuZGVjb2RlX3V0ZjggPSBmdW5jdGlvbih1dGY4KSB7XG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiBkZWNvZGVVUklDb21wb25lbnQoZXNjYXBlKHV0ZjgpKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICByZXR1cm4gdXRmODtcbiAgICB9XG4gIH07XG5cbiAgdmFyIHN0cjJiaW4gPSBmdW5jdGlvbihzdHIsIHJlc3VsdCkge1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgc3RyLmxlbmd0aDsgaSsrKSB7XG4gICAgICByZXN1bHRbaV0gPSBzdHIuY2hhckNvZGVBdChpKTtcbiAgICB9XG5cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9O1xuXG4gIHZhciBiaW4yc3RyID0gZnVuY3Rpb24oYmluKSB7XG4gICAgdmFyIHJlc3VsdCA9IFtdO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBiaW4ubGVuZ3RoOyBpKyspIHtcbiAgICAgIHJlc3VsdC5wdXNoKFN0cmluZy5mcm9tQ2hhckNvZGUoYmluW2ldKSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHJlc3VsdC5qb2luKCcnKTtcbiAgfTtcblxuICAvKipcbiAgICogQ29udmVydCBhIHN0cmluZyB0byBhbiBhcnJheSBvZiBpbnRlZ2VycygwLjI1NSlcbiAgICogQHBhcmFtIHtTdHJpbmd9IHN0ciBTdHJpbmcgdG8gY29udmVydFxuICAgKiBAcmV0dXJuIHtJbnRlZ2VyW119IEFuIGFycmF5IG9mIChiaW5hcnkpIGludGVnZXJzXG4gICAqL1xuICB0aGlzLnN0cjJiaW4gPSBmdW5jdGlvbihzdHIpIHtcbiAgICByZXR1cm4gc3RyMmJpbihzdHIsIG5ldyBBcnJheShzdHIubGVuZ3RoKSk7XG4gIH07XG5cblxuICAvKipcbiAgICogQ29udmVydCBhbiBhcnJheSBvZiBpbnRlZ2VycygwLjI1NSkgdG8gYSBzdHJpbmcgXG4gICAqIEBwYXJhbSB7SW50ZWdlcltdfSBiaW4gQW4gYXJyYXkgb2YgKGJpbmFyeSkgaW50ZWdlcnMgdG8gY29udmVydFxuICAgKiBAcmV0dXJuIHtTdHJpbmd9IFRoZSBzdHJpbmcgcmVwcmVzZW50YXRpb24gb2YgdGhlIGFycmF5XG4gICAqL1xuICB0aGlzLmJpbjJzdHIgPSBiaW4yc3RyO1xuXG4gIC8qKlxuICAgKiBDb252ZXJ0IGEgc3RyaW5nIHRvIGEgVWludDhBcnJheVxuICAgKiBAcGFyYW0ge1N0cmluZ30gc3RyIFN0cmluZyB0byBjb252ZXJ0XG4gICAqIEByZXR1cm4ge1VpbnQ4QXJyYXl9IFRoZSBhcnJheSBvZiAoYmluYXJ5KSBpbnRlZ2Vyc1xuICAgKi9cbiAgdGhpcy5zdHIyVWludDhBcnJheSA9IGZ1bmN0aW9uKHN0cikge1xuICAgIHJldHVybiBzdHIyYmluKHN0ciwgbmV3IFVpbnQ4QXJyYXkobmV3IEFycmF5QnVmZmVyKHN0ci5sZW5ndGgpKSk7XG4gIH07XG5cbiAgLyoqXG4gICAqIENvbnZlcnQgYSBVaW50OEFycmF5IHRvIGEgc3RyaW5nLiBUaGlzIGN1cnJlbnRseSBmdW5jdGlvbnMgXG4gICAqIHRoZSBzYW1lIGFzIGJpbjJzdHIuIFxuICAgKiBAcGFyYW0ge1VpbnQ4QXJyYXl9IGJpbiBBbiBhcnJheSBvZiAoYmluYXJ5KSBpbnRlZ2VycyB0byBjb252ZXJ0XG4gICAqIEByZXR1cm4ge1N0cmluZ30gU3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBhcnJheVxuICAgKi9cbiAgdGhpcy5VaW50OEFycmF5MnN0ciA9IGJpbjJzdHI7XG5cbiAgLyoqXG4gICAqIENhbGN1bGF0ZXMgYSAxNmJpdCBzdW0gb2YgYSBzdHJpbmcgYnkgYWRkaW5nIGVhY2ggY2hhcmFjdGVyIFxuICAgKiBjb2RlcyBtb2R1bHVzIDY1NTM1XG4gICAqIEBwYXJhbSB7U3RyaW5nfSB0ZXh0IFN0cmluZyB0byBjcmVhdGUgYSBzdW0gb2ZcbiAgICogQHJldHVybiB7SW50ZWdlcn0gQW4gaW50ZWdlciBjb250YWluaW5nIHRoZSBzdW0gb2YgYWxsIGNoYXJhY3RlciBcbiAgICogY29kZXMgJSA2NTUzNVxuICAgKi9cbiAgdGhpcy5jYWxjX2NoZWNrc3VtID0gZnVuY3Rpb24odGV4dCkge1xuICAgIHZhciBjaGVja3N1bSA9IHtcbiAgICAgIHM6IDAsXG4gICAgICBhZGQ6IGZ1bmN0aW9uKHNhZGQpIHtcbiAgICAgICAgdGhpcy5zID0gKHRoaXMucyArIHNhZGQpICUgNjU1MzY7XG4gICAgICB9XG4gICAgfTtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRleHQubGVuZ3RoOyBpKyspIHtcbiAgICAgIGNoZWNrc3VtLmFkZCh0ZXh0LmNoYXJDb2RlQXQoaSkpO1xuICAgIH1cbiAgICByZXR1cm4gY2hlY2tzdW0ucztcbiAgfTtcblxuICAvKipcbiAgICogSGVscGVyIGZ1bmN0aW9uIHRvIHByaW50IGEgZGVidWcgbWVzc2FnZS4gRGVidWcgXG4gICAqIG1lc3NhZ2VzIGFyZSBvbmx5IHByaW50ZWQgaWZcbiAgICogb3BlbnBncC5jb25maWcuZGVidWcgaXMgc2V0IHRvIHRydWUuXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBzdHIgU3RyaW5nIG9mIHRoZSBkZWJ1ZyBtZXNzYWdlXG4gICAqL1xuICB0aGlzLnByaW50X2RlYnVnID0gZnVuY3Rpb24oc3RyKSB7XG4gICAgaWYgKGNvbmZpZy5kZWJ1Zykge1xuICAgICAgY29uc29sZS5sb2coc3RyKTtcbiAgICB9XG4gIH07XG5cbiAgLyoqXG4gICAqIEhlbHBlciBmdW5jdGlvbiB0byBwcmludCBhIGRlYnVnIG1lc3NhZ2UuIERlYnVnIFxuICAgKiBtZXNzYWdlcyBhcmUgb25seSBwcmludGVkIGlmXG4gICAqIG9wZW5wZ3AuY29uZmlnLmRlYnVnIGlzIHNldCB0byB0cnVlLlxuICAgKiBEaWZmZXJlbnQgdGhhbiBwcmludF9kZWJ1ZyBiZWNhdXNlIHdpbGwgY2FsbCBoZXhzdHJkdW1wIGlmZiBuZWNlc3NhcnkuXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBzdHIgU3RyaW5nIG9mIHRoZSBkZWJ1ZyBtZXNzYWdlXG4gICAqL1xuICB0aGlzLnByaW50X2RlYnVnX2hleHN0cl9kdW1wID0gZnVuY3Rpb24oc3RyLCBzdHJUb0hleCkge1xuICAgIGlmIChjb25maWcuZGVidWcpIHtcbiAgICAgIHN0ciA9IHN0ciArIHRoaXMuaGV4c3RyZHVtcChzdHJUb0hleCk7XG4gICAgICBjb25zb2xlLmxvZyhzdHIpO1xuICAgIH1cbiAgfTtcblxuICAvKipcbiAgICogSGVscGVyIGZ1bmN0aW9uIHRvIHByaW50IGFuIGVycm9yIG1lc3NhZ2UuIFxuICAgKiBAcGFyYW0ge1N0cmluZ30gc3RyIFN0cmluZyBvZiB0aGUgZXJyb3IgbWVzc2FnZVxuICAgKi9cbiAgdGhpcy5wcmludF9lcnJvciA9IGZ1bmN0aW9uKHN0cikge1xuICAgIGlmIChjb25maWcuZGVidWcpXG4gICAgICB0aHJvdyBzdHI7XG4gICAgY29uc29sZS5sb2coc3RyKTtcbiAgfTtcblxuICAvKipcbiAgICogSGVscGVyIGZ1bmN0aW9uIHRvIHByaW50IGFuIGluZm8gbWVzc2FnZS4gXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBzdHIgU3RyaW5nIG9mIHRoZSBpbmZvIG1lc3NhZ2VcbiAgICovXG4gIHRoaXMucHJpbnRfaW5mbyA9IGZ1bmN0aW9uKHN0cikge1xuICAgIGlmIChjb25maWcuZGVidWcpXG4gICAgICBjb25zb2xlLmxvZyhzdHIpO1xuICB9O1xuXG4gIHRoaXMucHJpbnRfd2FybmluZyA9IGZ1bmN0aW9uKHN0cikge1xuICAgIGNvbnNvbGUubG9nKHN0cik7XG4gIH07XG5cbiAgdGhpcy5nZXRMZWZ0TkJpdHMgPSBmdW5jdGlvbihzdHJpbmcsIGJpdGNvdW50KSB7XG4gICAgdmFyIHJlc3QgPSBiaXRjb3VudCAlIDg7XG4gICAgaWYgKHJlc3QgPT0gMClcbiAgICAgIHJldHVybiBzdHJpbmcuc3Vic3RyaW5nKDAsIGJpdGNvdW50IC8gOCk7XG4gICAgdmFyIGJ5dGVzID0gKGJpdGNvdW50IC0gcmVzdCkgLyA4ICsgMTtcbiAgICB2YXIgcmVzdWx0ID0gc3RyaW5nLnN1YnN0cmluZygwLCBieXRlcyk7XG4gICAgcmV0dXJuIHRoaXMuc2hpZnRSaWdodChyZXN1bHQsIDggLSByZXN0KTsgLy8gK1N0cmluZy5mcm9tQ2hhckNvZGUoc3RyaW5nLmNoYXJDb2RlQXQoYnl0ZXMgLTEpIDw8ICg4LXJlc3QpICYgMHhGRik7XG4gIH07XG5cbiAgLyoqXG4gICAqIFNoaWZ0aW5nIGEgc3RyaW5nIHRvIG4gYml0cyByaWdodFxuICAgKiBAcGFyYW0ge1N0cmluZ30gdmFsdWUgVGhlIHN0cmluZyB0byBzaGlmdFxuICAgKiBAcGFyYW0ge0ludGVnZXJ9IGJpdGNvdW50IEFtb3VudCBvZiBiaXRzIHRvIHNoaWZ0IChNVVNUIGJlIHNtYWxsZXIgXG4gICAqIHRoYW4gOSlcbiAgICogQHJldHVybiB7U3RyaW5nfSBSZXN1bHRpbmcgc3RyaW5nLiBcbiAgICovXG4gIHRoaXMuc2hpZnRSaWdodCA9IGZ1bmN0aW9uKHZhbHVlLCBiaXRjb3VudCkge1xuICAgIHZhciB0ZW1wID0gdXRpbC5zdHIyYmluKHZhbHVlKTtcbiAgICBpZiAoYml0Y291bnQgJSA4ICE9IDApIHtcbiAgICAgIGZvciAodmFyIGkgPSB0ZW1wLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tKSB7XG4gICAgICAgIHRlbXBbaV0gPj49IGJpdGNvdW50ICUgODtcbiAgICAgICAgaWYgKGkgPiAwKVxuICAgICAgICAgIHRlbXBbaV0gfD0gKHRlbXBbaSAtIDFdIDw8ICg4IC0gKGJpdGNvdW50ICUgOCkpKSAmIDB4RkY7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiB2YWx1ZTtcbiAgICB9XG4gICAgcmV0dXJuIHV0aWwuYmluMnN0cih0ZW1wKTtcbiAgfTtcblxuICAvKipcbiAgICogUmV0dXJuIHRoZSBhbGdvcml0aG0gdHlwZSBhcyBzdHJpbmdcbiAgICogQHJldHVybiB7U3RyaW5nfSBTdHJpbmcgcmVwcmVzZW50aW5nIHRoZSBtZXNzYWdlIHR5cGVcbiAgICovXG4gIHRoaXMuZ2V0X2hhc2hBbGdvcml0aG1TdHJpbmcgPSBmdW5jdGlvbihhbGdvKSB7XG4gICAgc3dpdGNoIChhbGdvKSB7XG4gICAgICBjYXNlIDE6XG4gICAgICAgIHJldHVybiBcIk1ENVwiO1xuICAgICAgY2FzZSAyOlxuICAgICAgICByZXR1cm4gXCJTSEExXCI7XG4gICAgICBjYXNlIDM6XG4gICAgICAgIHJldHVybiBcIlJJUEVNRDE2MFwiO1xuICAgICAgY2FzZSA4OlxuICAgICAgICByZXR1cm4gXCJTSEEyNTZcIjtcbiAgICAgIGNhc2UgOTpcbiAgICAgICAgcmV0dXJuIFwiU0hBMzg0XCI7XG4gICAgICBjYXNlIDEwOlxuICAgICAgICByZXR1cm4gXCJTSEE1MTJcIjtcbiAgICAgIGNhc2UgMTE6XG4gICAgICAgIHJldHVybiBcIlNIQTIyNFwiO1xuICAgIH1cbiAgICByZXR1cm4gXCJ1bmtub3duXCI7XG4gIH07XG5cbn07XG5cbi8qKlxuICogYW4gaW5zdGFuY2UgdGhhdCBzaG91bGQgYmUgdXNlZC4gXG4gKi9cbm1vZHVsZS5leHBvcnRzID0gbmV3IFV0aWwoKTtcbiJdfQ==
|
||
; |