11934 lines
1.0 MiB
11934 lines
1.0 MiB
require=(function(e,t,n){function i(n,s){if(!t[n]){if(!e[n]){var o=typeof require=="function"&&require;if(!s&&o)return o(n,!0);if(r)return r(n,!0);throw new Error("Cannot find module '"+n+"'")}var u=t[n]={exports:{}};e[n][0].call(u.exports,function(t){var r=e[n][1][t];return i(r?r:t)},u,u.exports)}return t[n].exports}var r=typeof require=="function"&&require;for(var s=0;s<n.length;s++)i(n[s]);return i})({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
|
||
|
||
/**
|
||
* @fileoverview The openpgp base class 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.
|
||
*/
|
||
|
||
/**
|
||
* GPG4Browsers Core interface. A single instance is hold
|
||
* from the beginning. To use this library call "openpgp.init()"
|
||
* @alias openpgp
|
||
* @class
|
||
* @classdesc Main Openpgp.js class. Use this to initiate and make all calls to this library.
|
||
*/
|
||
function _openpgp () {
|
||
this.tostring = "";
|
||
|
||
/**
|
||
* initializes the library:
|
||
* - reading the keyring from local storage
|
||
* - reading the config from local storage
|
||
*/
|
||
function init() {
|
||
this.config = new openpgp_config();
|
||
this.config.read();
|
||
this.keyring = new openpgp_keyring();
|
||
this.keyring.init();
|
||
}
|
||
|
||
/**
|
||
* reads several publicKey objects from a ascii armored
|
||
* representation an returns openpgp_msg_publickey packets
|
||
* @param {String} armoredText OpenPGP armored text containing
|
||
* the public key(s)
|
||
* @return {openpgp_msg_publickey[]} on error the function
|
||
* returns null
|
||
*/
|
||
function read_publicKey(armoredText) {
|
||
var mypos = 0;
|
||
var publicKeys = new Array();
|
||
var publicKeyCount = 0;
|
||
var input = openpgp_encoding_deArmor(armoredText.replace(/\r/g,'')).openpgp;
|
||
var l = input.length;
|
||
while (mypos != input.length) {
|
||
var first_packet = openpgp_packet.read_packet(input, mypos, l);
|
||
// public key parser
|
||
if (input[mypos].charCodeAt() == 0x99 || first_packet.tagType == 6) {
|
||
publicKeys[publicKeyCount] = new openpgp_msg_publickey();
|
||
publicKeys[publicKeyCount].header = input.substring(mypos,mypos+3);
|
||
if (input[mypos].charCodeAt() == 0x99) {
|
||
// parse the length and read a tag6 packet
|
||
mypos++;
|
||
var l = (input[mypos++].charCodeAt() << 8)
|
||
| input[mypos++].charCodeAt();
|
||
publicKeys[publicKeyCount].publicKeyPacket = new openpgp_packet_keymaterial();
|
||
publicKeys[publicKeyCount].publicKeyPacket.header = publicKeys[publicKeyCount].header;
|
||
publicKeys[publicKeyCount].publicKeyPacket.read_tag6(input, mypos, l);
|
||
mypos += publicKeys[publicKeyCount].publicKeyPacket.packetLength;
|
||
mypos += publicKeys[publicKeyCount].read_nodes(publicKeys[publicKeyCount].publicKeyPacket, input, mypos, (input.length - mypos));
|
||
} else {
|
||
publicKeys[publicKeyCount] = new openpgp_msg_publickey();
|
||
publicKeys[publicKeyCount].publicKeyPacket = first_packet;
|
||
mypos += first_packet.headerLength+first_packet.packetLength;
|
||
mypos += publicKeys[publicKeyCount].read_nodes(first_packet, input, mypos, input.length -mypos);
|
||
}
|
||
} else {
|
||
util.print_error("no public key found!");
|
||
return null;
|
||
}
|
||
publicKeys[publicKeyCount].data = input.substring(0,mypos);
|
||
publicKeyCount++;
|
||
}
|
||
return publicKeys;
|
||
}
|
||
|
||
/**
|
||
* reads several privateKey objects from a ascii armored
|
||
* representation an returns openpgp_msg_privatekey objects
|
||
* @param {String} armoredText OpenPGP armored text containing
|
||
* the private key(s)
|
||
* @return {openpgp_msg_privatekey[]} on error the function
|
||
* returns null
|
||
*/
|
||
function read_privateKey(armoredText) {
|
||
var privateKeys = new Array();
|
||
var privateKeyCount = 0;
|
||
var mypos = 0;
|
||
var input = openpgp_encoding_deArmor(armoredText.replace(/\r/g,'')).openpgp;
|
||
var l = input.length;
|
||
while (mypos != input.length) {
|
||
var first_packet = openpgp_packet.read_packet(input, mypos, l);
|
||
if (first_packet.tagType == 5) {
|
||
privateKeys[privateKeys.length] = new openpgp_msg_privatekey();
|
||
mypos += first_packet.headerLength+first_packet.packetLength;
|
||
mypos += privateKeys[privateKeyCount].read_nodes(first_packet, input, mypos, l);
|
||
// other blocks
|
||
} else {
|
||
util.print_error('no block packet found!');
|
||
return null;
|
||
}
|
||
privateKeys[privateKeyCount].data = input.substring(0,mypos);
|
||
privateKeyCount++;
|
||
}
|
||
return privateKeys;
|
||
}
|
||
|
||
/**
|
||
* reads message packets out of an OpenPGP armored text and
|
||
* returns an array of message objects
|
||
* @param {String} armoredText text to be parsed
|
||
* @return {openpgp_msg_message[]} on error the function
|
||
* returns null
|
||
*/
|
||
function read_message(armoredText) {
|
||
var dearmored;
|
||
try{
|
||
dearmored = openpgp_encoding_deArmor(armoredText.replace(/\r/g,''));
|
||
}
|
||
catch(e){
|
||
util.print_error('no message found!');
|
||
return null;
|
||
}
|
||
return read_messages_dearmored(dearmored);
|
||
}
|
||
|
||
/**
|
||
* reads message packets out of an OpenPGP armored text and
|
||
* returns an array of message objects. Can be called externally or internally.
|
||
* External call will parse a de-armored messaged and return messages found.
|
||
* Internal will be called to read packets wrapped in other packets (i.e. compressed)
|
||
* @param {String} input dearmored text of OpenPGP packets, to be parsed
|
||
* @return {openpgp_msg_message[]} on error the function
|
||
* returns null
|
||
*/
|
||
function read_messages_dearmored(input){
|
||
var messageString = input.openpgp;
|
||
var signatureText = input.text; //text to verify signatures against. Modified by Tag11.
|
||
var messages = new Array();
|
||
var messageCount = 0;
|
||
var mypos = 0;
|
||
var l = messageString.length;
|
||
while (mypos < messageString.length) {
|
||
var first_packet = openpgp_packet.read_packet(messageString, mypos, l);
|
||
if (!first_packet) {
|
||
break;
|
||
}
|
||
// public key parser (definition from the standard:)
|
||
// OpenPGP Message :- Encrypted Message | Signed Message |
|
||
// Compressed Message | Literal Message.
|
||
// Compressed Message :- Compressed Data Packet.
|
||
//
|
||
// Literal Message :- Literal Data Packet.
|
||
//
|
||
// ESK :- Public-Key Encrypted Session Key Packet |
|
||
// Symmetric-Key Encrypted Session Key Packet.
|
||
//
|
||
// ESK Sequence :- ESK | ESK Sequence, ESK.
|
||
//
|
||
// Encrypted Data :- Symmetrically Encrypted Data Packet |
|
||
// Symmetrically Encrypted Integrity Protected Data Packet
|
||
//
|
||
// Encrypted Message :- Encrypted Data | ESK Sequence, Encrypted Data.
|
||
//
|
||
// One-Pass Signed Message :- One-Pass Signature Packet,
|
||
// OpenPGP Message, Corresponding Signature Packet.
|
||
|
||
// Signed Message :- Signature Packet, OpenPGP Message |
|
||
// One-Pass Signed Message.
|
||
if (first_packet.tagType == 1 ||
|
||
(first_packet.tagType == 2 && first_packet.signatureType < 16) ||
|
||
first_packet.tagType == 3 ||
|
||
first_packet.tagType == 4 ||
|
||
first_packet.tagType == 8 ||
|
||
first_packet.tagType == 9 ||
|
||
first_packet.tagType == 10 ||
|
||
first_packet.tagType == 11 ||
|
||
first_packet.tagType == 18 ||
|
||
first_packet.tagType == 19) {
|
||
messages[messages.length] = new openpgp_msg_message();
|
||
messages[messageCount].messagePacket = first_packet;
|
||
messages[messageCount].type = input.type;
|
||
// Encrypted Message
|
||
if (first_packet.tagType == 9 ||
|
||
first_packet.tagType == 1 ||
|
||
first_packet.tagType == 3 ||
|
||
first_packet.tagType == 18) {
|
||
if (first_packet.tagType == 9) {
|
||
util.print_error("unexpected openpgp packet");
|
||
break;
|
||
} else if (first_packet.tagType == 1) {
|
||
util.print_debug("session key found:\n "+first_packet.toString());
|
||
var issessionkey = true;
|
||
messages[messageCount].sessionKeys = new Array();
|
||
var sessionKeyCount = 0;
|
||
while (issessionkey) {
|
||
messages[messageCount].sessionKeys[sessionKeyCount] = first_packet;
|
||
mypos += first_packet.packetLength + first_packet.headerLength;
|
||
l -= (first_packet.packetLength + first_packet.headerLength);
|
||
first_packet = openpgp_packet.read_packet(messageString, mypos, l);
|
||
|
||
if (first_packet.tagType != 1 && first_packet.tagType != 3)
|
||
issessionkey = false;
|
||
sessionKeyCount++;
|
||
}
|
||
if (first_packet.tagType == 18 || first_packet.tagType == 9) {
|
||
util.print_debug("encrypted data found:\n "+first_packet.toString());
|
||
messages[messageCount].encryptedData = first_packet;
|
||
mypos += first_packet.packetLength+first_packet.headerLength;
|
||
l -= (first_packet.packetLength+first_packet.headerLength);
|
||
messageCount++;
|
||
|
||
} else {
|
||
util.print_debug("something is wrong: "+first_packet.tagType);
|
||
}
|
||
|
||
} else if (first_packet.tagType == 18) {
|
||
util.print_debug("symmetric encrypted data");
|
||
break;
|
||
}
|
||
} else
|
||
if (first_packet.tagType == 2 && first_packet.signatureType < 3) {
|
||
// Signed Message
|
||
mypos += first_packet.packetLength + first_packet.headerLength;
|
||
l -= (first_packet.packetLength + first_packet.headerLength);
|
||
messages[messageCount].text = signatureText;
|
||
messages[messageCount].signature = first_packet;
|
||
messageCount++;
|
||
} else
|
||
// Signed Message
|
||
if (first_packet.tagType == 4) {
|
||
//TODO: Implement check
|
||
mypos += first_packet.packetLength + first_packet.headerLength;
|
||
l -= (first_packet.packetLength + first_packet.headerLength);
|
||
} else
|
||
if (first_packet.tagType == 8) {
|
||
// Compressed Message
|
||
mypos += first_packet.packetLength + first_packet.headerLength;
|
||
l -= (first_packet.packetLength + first_packet.headerLength);
|
||
var decompressedText = first_packet.decompress();
|
||
messages = messages.concat(openpgp.read_messages_dearmored({text: decompressedText, openpgp: decompressedText}));
|
||
} else
|
||
// Marker Packet (Obsolete Literal Packet) (Tag 10)
|
||
// "Such a packet MUST be ignored when received." see http://tools.ietf.org/html/rfc4880#section-5.8
|
||
if (first_packet.tagType == 10) {
|
||
// reset messages
|
||
messages.length = 0;
|
||
// continue with next packet
|
||
mypos += first_packet.packetLength + first_packet.headerLength;
|
||
l -= (first_packet.packetLength + first_packet.headerLength);
|
||
} else
|
||
if (first_packet.tagType == 11) {
|
||
// Literal Message -- work is already done in read_packet
|
||
mypos += first_packet.packetLength + first_packet.headerLength;
|
||
l -= (first_packet.packetLength + first_packet.headerLength);
|
||
signatureText = first_packet.data;
|
||
messages[messageCount].data = first_packet.data;
|
||
messageCount++;
|
||
} else
|
||
if (first_packet.tagType == 19) {
|
||
// Modification Detect Code
|
||
mypos += first_packet.packetLength + first_packet.headerLength;
|
||
l -= (first_packet.packetLength + first_packet.headerLength);
|
||
}
|
||
} else {
|
||
util.print_error('no message found!');
|
||
return null;
|
||
}
|
||
}
|
||
|
||
return messages;
|
||
}
|
||
|
||
/**
|
||
* creates a binary string representation of an encrypted and signed message.
|
||
* The message will be encrypted with the public keys specified and signed
|
||
* with the specified private key.
|
||
* @param {Object} privatekey {obj: [openpgp_msg_privatekey]} Private key
|
||
* to be used to sign the message
|
||
* @param {Object[]} publickeys An arraf of {obj: [openpgp_msg_publickey]}
|
||
* - public keys to be used to encrypt the message
|
||
* @param {String} messagetext message text to encrypt and sign
|
||
* @return {String} a binary string representation of the message which
|
||
* can be OpenPGP armored
|
||
*/
|
||
function write_signed_and_encrypted_message(privatekey, publickeys, messagetext) {
|
||
var result = "";
|
||
var literal = new openpgp_packet_literaldata().write_packet(messagetext.replace(/\r\n/g,"\n").replace(/\n/g,"\r\n"));
|
||
util.print_debug_hexstr_dump("literal_packet: |"+literal+"|\n",literal);
|
||
for (var i = 0; i < publickeys.length; i++) {
|
||
var onepasssignature = new openpgp_packet_onepasssignature();
|
||
var onepasssigstr = "";
|
||
if (i == 0)
|
||
onepasssigstr = onepasssignature.write_packet(1, openpgp.config.config.prefer_hash_algorithm, privatekey, false);
|
||
else
|
||
onepasssigstr = onepasssignature.write_packet(1, openpgp.config.config.prefer_hash_algorithm, privatekey, false);
|
||
util.print_debug_hexstr_dump("onepasssigstr: |"+onepasssigstr+"|\n",onepasssigstr);
|
||
var datasignature = new openpgp_packet_signature().write_message_signature(1, messagetext.replace(/\r\n/g,"\n").replace(/\n/g,"\r\n"), privatekey);
|
||
util.print_debug_hexstr_dump("datasignature: |"+datasignature.openpgp+"|\n",datasignature.openpgp);
|
||
if (i == 0) {
|
||
result = onepasssigstr+literal+datasignature.openpgp;
|
||
} else {
|
||
result = onepasssigstr+result+datasignature.openpgp;
|
||
}
|
||
}
|
||
|
||
util.print_debug_hexstr_dump("signed packet: |"+result+"|\n",result);
|
||
// signatures done.. now encryption
|
||
var sessionkey = openpgp_crypto_generateSessionKey(openpgp.config.config.encryption_cipher);
|
||
var result2 = "";
|
||
|
||
// creating session keys for each recipient
|
||
for (var i = 0; i < publickeys.length; i++) {
|
||
var pkey = publickeys[i].getEncryptionKey();
|
||
if (pkey == null) {
|
||
util.print_error("no encryption key found! Key is for signing only.");
|
||
return null;
|
||
}
|
||
result2 += new openpgp_packet_encryptedsessionkey().
|
||
write_pub_key_packet(
|
||
pkey.getKeyId(),
|
||
pkey.MPIs,
|
||
pkey.publicKeyAlgorithm,
|
||
openpgp.config.config.encryption_cipher,
|
||
sessionkey);
|
||
}
|
||
if (openpgp.config.config.integrity_protect) {
|
||
result2 += new openpgp_packet_encryptedintegrityprotecteddata().write_packet(openpgp.config.config.encryption_cipher, sessionkey, result);
|
||
} else {
|
||
result2 += new openpgp_packet_encrypteddata().write_packet(openpgp.config.config.encryption_cipher, sessionkey, result);
|
||
}
|
||
return openpgp_encoding_armor(3,result2,null,null);
|
||
}
|
||
/**
|
||
* creates a binary string representation of an encrypted message.
|
||
* The message will be encrypted with the public keys specified
|
||
* @param {Object[]} publickeys An array of {obj: [openpgp_msg_publickey]}
|
||
* -public keys to be used to encrypt the message
|
||
* @param {String} messagetext message text to encrypt
|
||
* @return {String} a binary string representation of the message
|
||
* which can be OpenPGP armored
|
||
*/
|
||
function write_encrypted_message(publickeys, messagetext) {
|
||
var result = "";
|
||
var literal = new openpgp_packet_literaldata().write_packet(messagetext.replace(/\r\n/g,"\n").replace(/\n/g,"\r\n"));
|
||
util.print_debug_hexstr_dump("literal_packet: |"+literal+"|\n",literal);
|
||
result = literal;
|
||
|
||
// signatures done.. now encryption
|
||
var sessionkey = openpgp_crypto_generateSessionKey(openpgp.config.config.encryption_cipher);
|
||
var result2 = "";
|
||
|
||
// creating session keys for each recipient
|
||
for (var i = 0; i < publickeys.length; i++) {
|
||
var pkey = publickeys[i].getEncryptionKey();
|
||
if (pkey == null) {
|
||
util.print_error("no encryption key found! Key is for signing only.");
|
||
return null;
|
||
}
|
||
result2 += new openpgp_packet_encryptedsessionkey().
|
||
write_pub_key_packet(
|
||
pkey.getKeyId(),
|
||
pkey.MPIs,
|
||
pkey.publicKeyAlgorithm,
|
||
openpgp.config.config.encryption_cipher,
|
||
sessionkey);
|
||
}
|
||
if (openpgp.config.config.integrity_protect) {
|
||
result2 += new openpgp_packet_encryptedintegrityprotecteddata().write_packet(openpgp.config.config.encryption_cipher, sessionkey, result);
|
||
} else {
|
||
result2 += new openpgp_packet_encrypteddata().write_packet(openpgp.config.config.encryption_cipher, sessionkey, result);
|
||
}
|
||
return openpgp_encoding_armor(3,result2,null,null);
|
||
}
|
||
|
||
/**
|
||
* creates a binary string representation a signed message.
|
||
* The message will be signed with the specified private key.
|
||
* @param {Object} privatekey {obj: [openpgp_msg_privatekey]}
|
||
* - the private key to be used to sign the message
|
||
* @param {String} messagetext message text to sign
|
||
* @return {Object} {Object: text [String]}, openpgp: {String} a binary
|
||
* string representation of the message which can be OpenPGP
|
||
* armored(openpgp) and a text representation of the message (text).
|
||
* This can be directly used to OpenPGP armor the message
|
||
*/
|
||
function write_signed_message(privatekey, messagetext) {
|
||
var sig = new openpgp_packet_signature().write_message_signature(1, messagetext.replace(/\r\n/g,"\n").replace(/\n/,"\r\n"), privatekey);
|
||
var result = {text: messagetext.replace(/\r\n/g,"\n").replace(/\n/,"\r\n"), openpgp: sig.openpgp, hash: sig.hash};
|
||
return openpgp_encoding_armor(2,result, null, null)
|
||
}
|
||
|
||
/**
|
||
* generates a new key pair for openpgp. Beta stage. Currently only
|
||
* supports RSA keys, and no subkeys.
|
||
* @param {Integer} keyType to indicate what type of key to make.
|
||
* RSA is 1. Follows algorithms outlined in OpenPGP.
|
||
* @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} {privateKey: [openpgp_msg_privatekey],
|
||
* privateKeyArmored: [string], publicKeyArmored: [string]}
|
||
*/
|
||
function generate_key_pair(keyType, numBits, userId, passphrase){
|
||
var userIdPacket = new openpgp_packet_userid();
|
||
var userIdString = userIdPacket.write_packet(userId);
|
||
|
||
var keyPair = openpgp_crypto_generateKeyPair(keyType,numBits, passphrase, openpgp.config.config.prefer_hash_algorithm, 3);
|
||
var privKeyString = keyPair.privateKey;
|
||
var privKeyPacket = new openpgp_packet_keymaterial().read_priv_key(privKeyString.string,3,privKeyString.string.length);
|
||
if(!privKeyPacket.decryptSecretMPIs(passphrase))
|
||
util.print_error('Issue creating key. Unable to read resulting private key');
|
||
var privKey = new openpgp_msg_privatekey();
|
||
privKey.privateKeyPacket = privKeyPacket;
|
||
privKey.getPreferredSignatureHashAlgorithm = function(){return openpgp.config.config.prefer_hash_algorithm};//need to override this to solve catch 22 to generate signature. 8 is value for SHA256
|
||
|
||
var publicKeyString = privKey.privateKeyPacket.publicKey.data;
|
||
var hashData = String.fromCharCode(0x99)+ String.fromCharCode(((publicKeyString.length) >> 8) & 0xFF)
|
||
+ String.fromCharCode((publicKeyString.length) & 0xFF) +publicKeyString+String.fromCharCode(0xB4) +
|
||
String.fromCharCode((userId.length) >> 24) +String.fromCharCode(((userId.length) >> 16) & 0xFF)
|
||
+ String.fromCharCode(((userId.length) >> 8) & 0xFF) + String.fromCharCode((userId.length) & 0xFF) + userId
|
||
var signature = new openpgp_packet_signature();
|
||
signature = signature.write_message_signature(16,hashData, privKey);
|
||
var publicArmored = openpgp_encoding_armor(4, keyPair.publicKey.string + userIdString + signature.openpgp );
|
||
|
||
var privArmored = openpgp_encoding_armor(5,privKeyString.string+userIdString+signature.openpgp);
|
||
|
||
return {privateKey : privKey, privateKeyArmored: privArmored, publicKeyArmored: publicArmored}
|
||
}
|
||
|
||
this.generate_key_pair = generate_key_pair;
|
||
this.write_signed_message = write_signed_message;
|
||
this.write_signed_and_encrypted_message = write_signed_and_encrypted_message;
|
||
this.write_encrypted_message = write_encrypted_message;
|
||
this.read_message = read_message;
|
||
this.read_messages_dearmored = read_messages_dearmored;
|
||
this.read_publicKey = read_publicKey;
|
||
this.read_privateKey = read_privateKey;
|
||
this.init = init;
|
||
}
|
||
|
||
module.exports = new _openpgp();
|
||
|
||
|
||
},{}],2:[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 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.
|
||
*/
|
||
module.exports = function keyid() {
|
||
var bytes = '';
|
||
|
||
for(var i = 0; i < 8; i++)
|
||
bytes += String.fromCharCode(0);
|
||
/**
|
||
* 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;
|
||
}
|
||
};
|
||
|
||
},{}],"openpgp":[function(require,module,exports){
|
||
module.exports=require('d5yVPw');
|
||
},{}],"d5yVPw":[function(require,module,exports){
|
||
|
||
|
||
|
||
var crypto = require('./crypto');
|
||
|
||
module.exports = require('./openpgp.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');
|
||
|
||
for(var i in crypto)
|
||
module.exports[i] = crypto[i];
|
||
|
||
|
||
},{"./openpgp.js":1,"./type/mpi.js":3,"./type/s2k.js":4,"./type/keyid.js":2,"./encoding/armor.js":5,"./crypto":6,"./util":7,"./packet":8}],5:[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');
|
||
|
||
|
||
|
||
/**
|
||
* 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 splittedtext = text.split('-----');
|
||
// 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 (splittedtext[1].match(/BEGIN PGP MESSAGE, PART \d+\/\d+/)) {
|
||
return 0;
|
||
} 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 (splittedtext[1].match(/BEGIN PGP MESSAGE, PART \d+/)) {
|
||
return 1;
|
||
|
||
} 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 (splittedtext[1].match(/BEGIN PGP SIGNED MESSAGE/)) {
|
||
return 2;
|
||
|
||
} else
|
||
// BEGIN PGP MESSAGE
|
||
// Used for signed, encrypted, or compressed files.
|
||
if (splittedtext[1].match(/BEGIN PGP MESSAGE/)) {
|
||
return 3;
|
||
|
||
} else
|
||
// BEGIN PGP PUBLIC KEY BLOCK
|
||
// Used for armoring public keys.
|
||
if (splittedtext[1].match(/BEGIN PGP PUBLIC KEY BLOCK/)) {
|
||
return 4;
|
||
|
||
} else
|
||
// BEGIN PGP PRIVATE KEY BLOCK
|
||
// Used for armoring private keys.
|
||
if (splittedtext[1].match(/BEGIN PGP PRIVATE KEY BLOCK/)) {
|
||
return 5;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 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 (openpgp.config.config.show_version) {
|
||
result += "Version: "+openpgp.config.versionstring+'\r\n';
|
||
}
|
||
if (openpgp.config.config.show_comment) {
|
||
result += "Comment: "+openpgp.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;
|
||
}
|
||
|
||
/**
|
||
* 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 "openpgp" containing the bytes.
|
||
*/
|
||
function dearmor(text) {
|
||
text = text.replace(/\r/g, '')
|
||
|
||
var type = get_type(text);
|
||
|
||
if (type != 2) {
|
||
var splittedtext = text.split('-----');
|
||
|
||
var data = {
|
||
openpgp: base64.decode(
|
||
splittedtext[2]
|
||
.split('\n\n')[1]
|
||
.split("\n=")[0]
|
||
.replace(/\n- /g,"\n")),
|
||
type: type
|
||
};
|
||
|
||
if (verifyCheckSum(data.openpgp,
|
||
splittedtext[2]
|
||
.split('\n\n')[1]
|
||
.split("\n=")[1]
|
||
.split('\n')[0]))
|
||
|
||
return data;
|
||
else {
|
||
util.print_error("Ascii armor integrity check on message failed: '"
|
||
+ splittedtext[2]
|
||
.split('\n\n')[1]
|
||
.split("\n=")[1]
|
||
.split('\n')[0]
|
||
+ "' should be '"
|
||
+ getCheckSum(data)) + "'";
|
||
return false;
|
||
}
|
||
} else {
|
||
var splittedtext = text.split('-----');
|
||
|
||
var result = {
|
||
text: splittedtext[2]
|
||
.replace(/\n- /g,"\n")
|
||
.split("\n\n")[1],
|
||
openpgp: base64_decode(splittedtext[4]
|
||
.split("\n\n")[1]
|
||
.split("\n=")[0]),
|
||
type: type
|
||
};
|
||
|
||
if (verifyCheckSum(result.openpgp, splittedtext[4]
|
||
.split("\n\n")[1]
|
||
.split("\n=")[1]))
|
||
|
||
return result;
|
||
else {
|
||
util.print_error("Ascii armor integrity check on message failed");
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
/**
|
||
* Armor an OpenPGP binary packet block
|
||
* @param {Integer} messagetype type of the message
|
||
* @param data
|
||
* @param {Integer} partindex
|
||
* @param {Integer} parttotal
|
||
* @returns {String} Armored text
|
||
*/
|
||
function armor(messagetype, data, partindex, parttotal) {
|
||
var result = "";
|
||
switch(messagetype) {
|
||
case 0:
|
||
result += "-----BEGIN PGP MESSAGE, PART "+partindex+"/"+parttotal+"-----\r\n";
|
||
result += armor_addheader();
|
||
result += base64.encode(data);
|
||
result += "\r\n="+getCheckSum(data)+"\r\n";
|
||
result += "-----END PGP MESSAGE, PART "+partindex+"/"+parttotal+"-----\r\n";
|
||
break;
|
||
case 1:
|
||
result += "-----BEGIN PGP MESSAGE, PART "+partindex+"-----\r\n";
|
||
result += armor_addheader();
|
||
result += base64.encode(data);
|
||
result += "\r\n="+getCheckSum(data)+"\r\n";
|
||
result += "-----END PGP MESSAGE, PART "+partindex+"-----\r\n";
|
||
break;
|
||
case 2:
|
||
result += "\r\n-----BEGIN PGP SIGNED MESSAGE-----\r\nHash: "+data.hash+"\r\n\r\n";
|
||
result += data.text.replace(/\n-/g,"\n- -");
|
||
result += "\r\n-----BEGIN PGP SIGNATURE-----\r\n";
|
||
result += armor_addheader();
|
||
result += base64.encode(data.openpgp);
|
||
result += "\r\n="+getCheckSum(data.openpgp)+"\r\n";
|
||
result += "-----END PGP SIGNATURE-----\r\n";
|
||
break;
|
||
case 3:
|
||
result += "-----BEGIN PGP MESSAGE-----\r\n";
|
||
result += armor_addheader();
|
||
result += base64.encode(data);
|
||
result += "\r\n="+getCheckSum(data)+"\r\n";
|
||
result += "-----END PGP MESSAGE-----\r\n";
|
||
break;
|
||
case 4:
|
||
result += "-----BEGIN PGP PUBLIC KEY BLOCK-----\r\n";
|
||
result += armor_addheader();
|
||
result += base64.encode(data);
|
||
result += "\r\n="+getCheckSum(data)+"\r\n";
|
||
result += "-----END PGP PUBLIC KEY BLOCK-----\r\n\r\n";
|
||
break;
|
||
case 5:
|
||
result += "-----BEGIN PGP PRIVATE KEY BLOCK-----\r\n";
|
||
result += armor_addheader();
|
||
result += base64.encode(data);
|
||
result += "\r\n="+getCheckSum(data)+"\r\n";
|
||
result += "-----END PGP PRIVATE KEY BLOCK-----\r\n";
|
||
break;
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
module.exports = {
|
||
encode: armor,
|
||
decode: dearmor
|
||
}
|
||
|
||
},{"./base64.js":9}],7:[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 = function() {
|
||
|
||
|
||
|
||
this.readNumber = function (bytes) {
|
||
var n = 0;
|
||
|
||
for(var i = 0; i < bytes.length; i++) {
|
||
n <<= 8;
|
||
n += bytes[i].charCodeAt()
|
||
}
|
||
|
||
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-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/;
|
||
|
||
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[c++].charCodeAt().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) {
|
||
return decodeURIComponent(escape(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. The calling
|
||
* Javascript context MUST define
|
||
* a "showMessages(text)" function. Line feeds ('\n')
|
||
* are automatically converted to HTML line feeds '<br/>'
|
||
* @param {String} str String of the debug message
|
||
* @return {String} An HTML tt entity containing a paragraph with a
|
||
* style attribute where the debug message is HTMLencoded in.
|
||
*/
|
||
this.print_debug = function(str) {
|
||
if (this.debug) {
|
||
console.log(str);
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Helper function to print a debug message. Debug
|
||
* messages are only printed if
|
||
* openpgp.config.debug is set to true. The calling
|
||
* Javascript context MUST define
|
||
* a "showMessages(text)" function. Line feeds ('\n')
|
||
* are automatically converted to HTML line feeds '<br/>'
|
||
* Different than print_debug because will call hexstrdump iff necessary.
|
||
* @param {String} str String of the debug message
|
||
* @return {String} An HTML tt entity containing a paragraph with a
|
||
* style attribute where the debug message is HTMLencoded in.
|
||
*/
|
||
this.print_debug_hexstr_dump = function(str,strToHex) {
|
||
if (this.debug) {
|
||
str = str + this.hexstrdump(strToHex);
|
||
console.log(str);
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Helper function to print an error message.
|
||
* The calling Javascript context MUST define
|
||
* a "showMessages(text)" function. Line feeds ('\n')
|
||
* are automatically converted to HTML line feeds '<br/>'
|
||
* @param {String} str String of the error message
|
||
* @return {String} A HTML paragraph entity with a style attribute
|
||
* containing the HTML encoded error message
|
||
*/
|
||
this.print_error = function(str) {
|
||
if(this.debug)
|
||
throw str;
|
||
console.log(str);
|
||
};
|
||
|
||
/**
|
||
* Helper function to print an info message.
|
||
* The calling Javascript context MUST define
|
||
* a "showMessages(text)" function. Line feeds ('\n')
|
||
* are automatically converted to HTML line feeds '<br/>'.
|
||
* @param {String} str String of the info message
|
||
* @return {String} A HTML paragraph entity with a style attribute
|
||
* containing the HTML encoded info message
|
||
*/
|
||
this.print_info = function(str) {
|
||
if(this.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();
|
||
|
||
},{}],10:[function(require,module,exports){
|
||
module.exports = {
|
||
|
||
|
||
/** 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
|
||
},
|
||
|
||
// 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.');
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
},{}],9:[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
|
||
}
|
||
|
||
},{}],8:[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":10,"./packetlist.js":11,"./all_packets.js":12}],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
|
||
|
||
// 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[0].charCodeAt() << 8) | bytes[1].charCodeAt();
|
||
|
||
// 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":13,"../util":7}],4:[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[i++].charCodeAt());
|
||
this.algorithm = enums.read(enums.hash, bytes[i++].charCodeAt());
|
||
|
||
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[i++].charCodeAt();
|
||
break;
|
||
|
||
case 'gnu':
|
||
if(bytes.substr(i, 3) == "GNU") {
|
||
i += 3; // GNU
|
||
var gnuExtType = 1000 + bytes[i++].charCodeAt();
|
||
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);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
},{"../enums.js":10,"../util":7,"../crypto":6}],14:[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
|
||
|
||
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;
|
||
}
|
||
}
|
||
|
||
},{}],6:[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'),
|
||
symmetric: require('./sym.js')
|
||
|
||
}
|
||
|
||
var crypto = require('./crypto.js');
|
||
|
||
for(var i in crypto)
|
||
module.exports[i] = crypto[i];
|
||
|
||
|
||
|
||
|
||
},{"./cfb.js":15,"./signature.js":16,"./random.js":14,"./pkcs1.js":17,"./sym.js":18,"./crypto.js":19,"./cipher":20,"./hash":21,"./public_key":22}],11:[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 = new packetlist();
|
||
|
||
this[this.length] = packet;
|
||
this.length++;
|
||
}
|
||
|
||
}
|
||
|
||
},{"./packet.js":23,"./all_packets.js":12,"../enums.js":10}],12:[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":10,"./compressed.js":24,"./sym_encrypted_integrity_protected.js":25,"./public_key_encrypted_session_key.js":26,"./sym_encrypted_session_key.js":27,"./literal.js":28,"./public_key.js":29,"./symmetrically_encrypted.js":30,"./marker.js":31,"./public_subkey.js":32,"./user_attribute.js":33,"./one_pass_signature.js":34,"./secret_key.js":35,"./userid.js":36,"./secret_subkey.js":37,"./signature.js":38,"./trust.js":39}],13:[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.appName == "Microsoft Internet Explorer")) {
|
||
BigInteger.prototype.am = am2;
|
||
dbits = 30;
|
||
}
|
||
else if(j_lm && (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();
|
||
for(var i = 0; i < t; ++i) {
|
||
//Pick bases at random, instead of starting at 2
|
||
a.fromInt(lowprimes[Math.floor(Math.random()*lowprimes.length)]);
|
||
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;
|
||
|
||
|
||
|
||
},{"./jsbn.js":13,"../../util":7}],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
|
||
|
||
/**
|
||
* @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[0].charCodeAt() == 0x50 && // P
|
||
bytes[1].charCodeAt() == 0x47 && // G
|
||
bytes[2].charCodeAt() == 0x50) // P
|
||
return true;
|
||
// marker packet does not contain "PGP"
|
||
return false;
|
||
}
|
||
}
|
||
|
||
module.exports = packet_marker;
|
||
|
||
},{}],33:[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;
|
||
}
|
||
}
|
||
};
|
||
|
||
},{}],39:[function(require,module,exports){
|
||
|
||
module.exports = function packet_trust() {
|
||
|
||
};
|
||
|
||
},{}],20:[function(require,module,exports){
|
||
|
||
module.exports = {
|
||
aes: require('./aes.js'),
|
||
des: require('./des.js'),
|
||
cast5: require('./cast5.js'),
|
||
twofish: require('./twofish.js'),
|
||
blowfish: require('./blowfish.js')
|
||
}
|
||
|
||
|
||
},{"./aes.js":40,"./des.js":41,"./cast5.js":42,"./twofish.js":43,"./blowfish.js":44}],21:[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.');
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
|
||
},{"./sha.js":45,"./md5.js":46,"./ripe-md.js":47}],15:[function(require,module,exports){
|
||
(function(){// 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');
|
||
|
||
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, blockcipherencryptfn, plaintext, block_size, key, resync) {
|
||
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 = blockcipherencryptfn(FR, key);
|
||
// 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 = blockcipherencryptfn(FR, key);
|
||
|
||
// 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 = blockcipherencryptfn(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 = blockcipherencryptfn(FR, key);
|
||
|
||
// 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 = blockcipherencryptfn(FR, key);
|
||
|
||
// 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('');
|
||
|
||
}
|
||
return ciphertext;
|
||
},
|
||
|
||
/**
|
||
* Decrypts the prefixed data for the Modification Detection Code (MDC) computation
|
||
* @param {openpgp_block_cipher_fn} blockcipherencryptfn 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 (blockcipherencryptfn, block_size, key, ciphertext) {
|
||
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 = blockcipherencryptfn(iblock, key);
|
||
for(i = 0; i < block_size; i++)
|
||
{
|
||
ablock[i] = ciphertext.charCodeAt(i);
|
||
iblock[i] ^= ablock[i];
|
||
}
|
||
|
||
ablock = blockcipherencryptfn(ablock, key);
|
||
|
||
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 (blockcipherencryptfn, block_size, key, ciphertext, resync)
|
||
{
|
||
util.print_debug("resync:"+resync);
|
||
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 = blockcipherencryptfn(iblock, key);
|
||
for(i = 0; i < block_size; i++)
|
||
{
|
||
ablock[i] = ciphertext.charCodeAt(i);
|
||
iblock[i] ^= ablock[i];
|
||
}
|
||
|
||
ablock = blockcipherencryptfn(ablock, key);
|
||
|
||
util.print_debug("openpgp_cfb_decrypt:\niblock:"+util.hexidump(iblock)+"\nablock:"+util.hexidump(ablock)+"\n");
|
||
util.print_debug((ablock[0]^ciphertext.charCodeAt(block_size)).toString(16)+(ablock[1]^ciphertext.charCodeAt(block_size+1)).toString(16));
|
||
|
||
// 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)))
|
||
{
|
||
util.print_eror("error duding decryption. Symmectric encrypted data not valid.");
|
||
return text.join('');
|
||
}
|
||
|
||
/* 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 = blockcipherencryptfn(iblock, key);
|
||
|
||
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 = blockcipherencryptfn(iblock, key);
|
||
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]));
|
||
}
|
||
}
|
||
}
|
||
|
||
return text.join('');
|
||
},
|
||
|
||
|
||
normalEncrypt: function(blockcipherencryptfn, block_size, key, plaintext, iv) {
|
||
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 = blockcipherencryptfn(blockc, key);
|
||
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(blockcipherencryptfn, block_size, key, ciphertext, iv) {
|
||
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 = blockcipherencryptfn(blockp, key);
|
||
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":7}],22:[function(require,module,exports){
|
||
|
||
module.exports = {
|
||
rsa: require('./rsa.js'),
|
||
elgamal: require('./elgamal.js'),
|
||
dsa: require('./dsa.js')
|
||
}
|
||
|
||
|
||
},{"./rsa.js":48,"./elgamal.js":49,"./dsa.js":50}],16:[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.');
|
||
}
|
||
}
|
||
}
|
||
|
||
},{"./pkcs1.js":17,"./public_key":22,"./hash":21}],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);
|
||
}
|
||
}
|
||
}
|
||
|
||
},{"./crypto.js":19,"./random.js":14,"./public_key/jsbn.js":13,"../util":7,"./hash":21}],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
|
||
|
||
// The GPG4Browsers symmetric crypto interface
|
||
|
||
var cfb = require('./cfb.js'),
|
||
cipher = require('./cipher');
|
||
|
||
module.exports = {
|
||
|
||
/**
|
||
* Symmetrically encrypts data using prefixedrandom, a key with length
|
||
* depending on the algorithm in openpgp_cfb mode with or without resync
|
||
* (MDC style)
|
||
* @param {String} prefixrandom Secure random bytes as string in
|
||
* length equal to the block size of the algorithm used (use
|
||
* openpgp_crypto_getPrefixRandom(algo) to retrieve that string
|
||
* @param {Integer} algo Algorithm to use (see RFC4880 9.2)
|
||
* @param {String} key Key as string. length is depending on the algorithm used
|
||
* @param {String} data Data to encrypt
|
||
* @param {Boolean} openpgp_cfb
|
||
* @return {String} Encrypted data
|
||
*/
|
||
encrypt: function (prefixrandom, algo, key, data, openpgp_cfb) {
|
||
switch(algo) {
|
||
case 'plaintext': // Plaintext or unencrypted data
|
||
return data; // blockcipherencryptfn, plaintext, block_size, key
|
||
case 'des': // TripleDES (DES-EDE, [SCHNEIER] [HAC] - 168 bit key derived from 192)
|
||
return cfb.encrypt(prefixrandom, cipher.des, data,8,key, openpgp_cfb).substring(0, data.length + 10);
|
||
case 'cast5': // CAST5 (128 bit key, as per [RFC2144])
|
||
return cfb.encrypt(prefixrandom, cipher.cast5, data,8,key, openpgp_cfb).substring(0, data.length + 10);
|
||
case 'blowfish': // Blowfish (128 bit key, 16 rounds) [BLOWFISH]
|
||
return cfb.encrypt(prefixrandom, cipher.blowfish, data,8,key, openpgp_cfb).substring(0, data.length + 10);
|
||
case 'aes128': // AES with 128-bit key [AES]
|
||
case 'aes192': // AES with 192-bit key
|
||
case 'aes256': // AES with 256-bit key
|
||
return cfb.encrypt(prefixrandom, cipher.aes.encrypt, data, 16, cipher.aes.keyExpansion(key), openpgp_cfb).substring(0, data.length + 18);
|
||
case 'twofish': // Twofish with 256-bit key [TWOFISH]
|
||
return cfb.encrypt(prefixrandom, cipher.twofish, data,16, key, openpgp_cfb).substring(0, data.length + 18);
|
||
default:
|
||
throw new Error('Invalid algorithm.');
|
||
}
|
||
},
|
||
|
||
/**
|
||
* Symmetrically decrypts data using a key with length depending on the
|
||
* algorithm in openpgp_cfb mode with or without resync (MDC style)
|
||
* @param {Integer} algo Algorithm to use (see RFC4880 9.2)
|
||
* @param {String} key Key as string. length is depending on the algorithm used
|
||
* @param {String} data Data to be decrypted
|
||
* @param {Boolean} openpgp_cfb If true use the resync (for encrypteddata);
|
||
* otherwise use without the resync (for MDC encrypted data)
|
||
* @return {String} Plaintext data
|
||
*/
|
||
decrypt: function (algo, key, data, openpgp_cfb) {
|
||
var n = 0;
|
||
if (!openpgp_cfb)
|
||
n = 2;
|
||
switch(algo) {
|
||
case 'plaintext': // Plaintext or unencrypted data
|
||
return data;
|
||
case 'des': // TripleDES (DES-EDE, [SCHNEIER] [HAC] - 168 bit key derived from 192)
|
||
return cfb.decrypt(cipher.des, 8, key, data, openpgp_cfb).substring(n, (data.length+n)-10);
|
||
case 'cast5': // CAST5 (128 bit key, as per [RFC2144])
|
||
return cfb.decrypt(cipher.cast5, 8, key, data, openpgp_cfb).substring(n, (data.length+n)-10);
|
||
case 'blowfish': // Blowfish (128 bit key, 16 rounds) [BLOWFISH]
|
||
return cfb.decrypt(cipher.blowfish, 8, key, data, openpgp_cfb).substring(n, (data.length+n)-10);
|
||
case 'aes128': // AES with 128-bit key [AES]
|
||
case 'aes192': // AES with 192-bit key
|
||
case 'aes256': // AES with 256-bit key
|
||
return cfb.decrypt(cipher.aes.encrypt, 16, cipher.aes.keyExpansion(key), data, openpgp_cfb).substring(n, (data.length+n)-18);
|
||
case 'twofish': // Twofish with 256-bit key [TWOFISH]
|
||
var result = cfb.decrypt(cipher.twofish, 16, key, data, openpgp_cfb).substring(n, (data.length+n)-18);
|
||
return result;
|
||
default:
|
||
throw new Error('Invalid algorithm');
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
},{"./cfb.js":15,"./cipher":20}],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
|
||
|
||
// The GPG4Browsers crypto interface
|
||
|
||
var random = require('./random.js'),
|
||
cipher = require('./cipher'),
|
||
cfb = require('./cfb.js'),
|
||
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.');
|
||
}
|
||
},
|
||
|
||
|
||
/**
|
||
* 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(this.getBlockLength(algo));
|
||
},
|
||
|
||
/**
|
||
* retrieve the MDC prefixed bytes by decrypting them
|
||
* @param {Integer} algo Algorithm to use (see RFC4880 9.2)
|
||
* @param {String} key Key as string. length is depending on the algorithm used
|
||
* @param {String} data Encrypted data where the prefix is decrypted from
|
||
* @return {String} Plain text data of the prefixed data
|
||
*/
|
||
MDCSystemBytes: function(algo, key, data) {
|
||
|
||
switch(algo) {
|
||
case 'plaintext': // Plaintext or unencrypted data
|
||
return data;
|
||
case 'des': // TripleDES (DES-EDE, [SCHNEIER] [HAC] - 168 bit key derived from 192)
|
||
return cfb.mdc(cipher.des, 8, key, data);
|
||
case 'cast5': // CAST5 (128 bit key, as per [RFC2144])
|
||
return cfb.mdc(cipher.cast5, 8, key, data);
|
||
case 'blowfish': // Blowfish (128 bit key, 16 rounds) [BLOWFISH]
|
||
return cfb.mdc(cipher.blowfish, 8, key, data);
|
||
case 'aes128': // AES with 128-bit key [AES]
|
||
case 'aes192': // AES with 192-bit key
|
||
case 'aes256': // AES with 256-bit key
|
||
return cfb.mdc(cipher.aes.encrypt, 16, cipher.aes.keyExpansion(key), data);
|
||
case 'twofish':
|
||
return cfb.mdc(cipher.twofish, 16, key, data);
|
||
case 'idea': // IDEA [IDEA]
|
||
throw new Error('IDEA Algorithm not implemented');
|
||
default:
|
||
throw new Error('Invalid algorithm.');
|
||
}
|
||
},
|
||
/**
|
||
* 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(this.getKeyLength(algo));
|
||
},
|
||
|
||
/**
|
||
* Get the key length by symmetric algorithm id.
|
||
* @param {Integer} algo Algorithm to use (see RFC4880 9.2)
|
||
* @return {String} Random bytes as a string to be used as a key
|
||
*/
|
||
getKeyLength: function(algo) {
|
||
switch (algo) {
|
||
case 'des': // TripleDES (DES-EDE, [SCHNEIER] [HAC] - 168 bit key derived from 192)
|
||
case 'aes192': // AES with 192-bit key
|
||
return 24;
|
||
case 'cast5': // CAST5 (128 bit key, as per [RFC2144])
|
||
case 'blowfish': // Blowfish (128 bit key, 16 rounds) [BLOWFISH]
|
||
case 'aes128': // AES with 128-bit key [AES]
|
||
return 16;
|
||
case 'aes256': // AES with 256-bit key
|
||
case 'twofish':// Twofish with 256-bit key [TWOFISH]
|
||
return 32;
|
||
default:
|
||
throw new Error('Invalid algorithm.');
|
||
}
|
||
},
|
||
|
||
/**
|
||
* Returns the block length of the specified symmetric encryption algorithm
|
||
* @param {openpgp.symmetric} algo Symmetric algorithm idenhifier
|
||
* @return {Integer} The number of bytes in a single block encrypted by the algorithm
|
||
*/
|
||
getBlockLength: function(algo) {
|
||
switch (algo) {
|
||
case 'des':
|
||
case 'cast5':
|
||
return 8;
|
||
case 'blowfish':
|
||
case 'aes128':
|
||
case 'aes192':
|
||
case 'aes256':
|
||
return 16;
|
||
case 'twofish':
|
||
return 32;
|
||
default:
|
||
throw new Error('Invalid algorithm.');
|
||
}
|
||
},
|
||
|
||
/**
|
||
* 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 = random.getRandomBytes(numBytes);
|
||
if (bits % 8 > 0) {
|
||
|
||
randomBits = String.fromCharCode(
|
||
(Math.pow(2,bits % 8)-1) &
|
||
randomBits.charCodeAt(0)) +
|
||
randomBits.substring(1);
|
||
}
|
||
return new type_mpi().create(randomBits).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);
|
||
},
|
||
|
||
}
|
||
|
||
},{"./random.js":14,"./cfb.js":15,"../type/mpi.js":3,"./cipher":20,"./public_key":22}],24:[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;
|
||
}
|
||
}
|
||
};
|
||
|
||
},{"../enums.js":10,"../compression/jxg.js":51,"../encoding/base64.js":9}],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
|
||
|
||
var public_key = require('./public_key.js');
|
||
|
||
module.exports = function public_subkey() {
|
||
public_key.call(this);
|
||
}
|
||
|
||
},{"./public_key.js":29}],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
|
||
|
||
/**
|
||
* @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
|
||
* @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 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
|
||
* @param {Integer} type Signature types as described in RFC4880 Section 5.2.1.
|
||
* @param {Integer} hashalgorithm the hash algorithm used within the signature
|
||
* @param {openpgp_msg_privatekey} privatekey the private key used to generate the signature
|
||
* @param {Integer} length length of data to be signed
|
||
* @param {boolean} nested boolean showing whether the signature is nested.
|
||
* "true" indicates that the next packet is another One-Pass Signature packet
|
||
* that describes another signature to be applied to the same message data.
|
||
* @return {String} a string representation of a one-pass signature packet
|
||
*/
|
||
this.write = function(type, hashalgorithm, privatekey, length, nested) {
|
||
var result ="";
|
||
|
||
result += String.fromCharCode(3);
|
||
result += String.fromCharCode(enums.write(enums.signature, type));
|
||
result += String.fromCharCode(enums.write(enums.hash, this.hashAlgorithm));
|
||
result += String.fromCharCode(enums.write(enums.publicKey, privatekey.algorithm));
|
||
result += privatekey.getKeyId();
|
||
if (nested)
|
||
result += String.fromCharCode(0);
|
||
else
|
||
result += String.fromCharCode(1);
|
||
|
||
return result;
|
||
}
|
||
};
|
||
|
||
},{"../enums.js":10,"../type/keyid.js":2}],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
|
||
|
||
var secret_key = require('./secret_key.js');
|
||
|
||
module.exports = function secret_subkey() {
|
||
secret_key.call(this);
|
||
}
|
||
|
||
},{"./secret_key.js":35}],45:[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");
|
||
}
|
||
}
|
||
|
||
},{}],47:[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;
|
||
|
||
},{}],50:[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
|
||
|
||
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(openpgp_crypto_hashData(hashalgo,m),q.bitLength());
|
||
var hash = new BigInteger(util.hexstrdump(hashed_data), 16);
|
||
var k = openpgp_crypto_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(openpgp_crypto_hashData(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;
|
||
|
||
},{}],51:[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];
|
||
}
|
||
}
|
||
if (debug)
|
||
document.write("ret3");
|
||
return -1;
|
||
};
|
||
|
||
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;
|
||
|
||
},{}],46:[function(require,module,exports){
|
||
(function(){/**
|
||
* 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":7}],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
|
||
|
||
var enums = require('../enums.js'),
|
||
util = require('../util');
|
||
|
||
|
||
module.exports = {
|
||
readSimpleLength: function(bytes) {
|
||
var len = 0,
|
||
offset,
|
||
type = bytes[0].charCodeAt();
|
||
|
||
|
||
if (type < 192) {
|
||
len = bytes[0].charCodeAt();
|
||
offset = 1;
|
||
} else if (type < 255) {
|
||
len = ((bytes[0].charCodeAt() - 192) << 8) + (bytes[1].charCodeAt()) + 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[position].charCodeAt() & 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[mypos].charCodeAt() & 0x40) != 0) {
|
||
format = 1;
|
||
}
|
||
|
||
var packet_length_type;
|
||
if (format) {
|
||
// new format header
|
||
tag = input[mypos].charCodeAt() & 0x3F; // bit 5-0
|
||
} else {
|
||
// old format header
|
||
tag = (input[mypos].charCodeAt() & 0x3F) >> 2; // bit 5-2
|
||
packet_length_type = input[mypos].charCodeAt() & 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[mypos++].charCodeAt();
|
||
break;
|
||
case 1: // The packet has a two-octet length. The header is 3 octets
|
||
// long.
|
||
packet_length = (input[mypos++].charCodeAt() << 8)
|
||
| input[mypos++].charCodeAt();
|
||
break;
|
||
case 2: // The packet has a four-octet length. The header is 5
|
||
// octets long.
|
||
packet_length = (input[mypos++].charCodeAt() << 24)
|
||
| (input[mypos++].charCodeAt() << 16)
|
||
| (input[mypos++].charCodeAt() << 8)
|
||
| input[mypos++].charCodeAt();
|
||
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[mypos].charCodeAt() < 192) {
|
||
packet_length = input[mypos++].charCodeAt();
|
||
util.print_debug("1 byte length:" + packet_length);
|
||
// 4.2.2.2. Two-Octet Lengths
|
||
} else if (input[mypos].charCodeAt() >= 192
|
||
&& input[mypos].charCodeAt() < 224) {
|
||
packet_length = ((input[mypos++].charCodeAt() - 192) << 8)
|
||
+ (input[mypos++].charCodeAt()) + 192;
|
||
util.print_debug("2 byte length:" + packet_length);
|
||
// 4.2.2.4. Partial Body Lengths
|
||
} else if (input[mypos].charCodeAt() > 223
|
||
&& input[mypos].charCodeAt() < 255) {
|
||
packet_length = 1 << (input[mypos++].charCodeAt() & 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[mypos2].charCodeAt() < 192) {
|
||
var tmplen = input[mypos2++].charCodeAt();
|
||
packet_length += tmplen;
|
||
bodydata += input.substring(mypos2, mypos2 + tmplen);
|
||
mypos2 += tmplen;
|
||
break;
|
||
} else if (input[mypos2].charCodeAt() >= 192
|
||
&& input[mypos2].charCodeAt() < 224) {
|
||
var tmplen = ((input[mypos2++].charCodeAt() - 192) << 8)
|
||
+ (input[mypos2++].charCodeAt()) + 192;
|
||
packet_length += tmplen;
|
||
bodydata += input.substring(mypos2, mypos2 + tmplen);
|
||
mypos2 += tmplen;
|
||
break;
|
||
} else if (input[mypos2].charCodeAt() > 223
|
||
&& input[mypos2].charCodeAt() < 255) {
|
||
var tmplen = 1 << (input[mypos2++].charCodeAt() & 0x1F);
|
||
packet_length += tmplen;
|
||
bodydata += input.substring(mypos2, mypos2 + tmplen);
|
||
mypos2 += tmplen;
|
||
} else {
|
||
mypos2++;
|
||
var tmplen = (input[mypos2++].charCodeAt() << 24)
|
||
| (input[mypos2++].charCodeAt() << 16)
|
||
| (input[mypos2++].charCodeAt() << 8)
|
||
| input[mypos2++].charCodeAt();
|
||
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[mypos++].charCodeAt() << 24)
|
||
| (input[mypos++].charCodeAt() << 16)
|
||
| (input[mypos++].charCodeAt() << 8)
|
||
| input[mypos++].charCodeAt();
|
||
}
|
||
}
|
||
|
||
// 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":10,"../util":7}],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 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[0].charCodeAt();
|
||
|
||
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.symmetric.encrypt(prefixrandom,
|
||
sessionKeyAlgorithm, key, tohash, 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.symmetric.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.MDCSystemBytes(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));
|
||
}
|
||
};
|
||
|
||
},{"../util":7,"../crypto":6}],26:[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[0].charCodeAt();
|
||
this.publicKeyId.read(bytes.substr(1));
|
||
this.publicKeyAlgorithm = enums.read(enums.publicKey, bytes[9].charCodeAt());
|
||
|
||
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));
|
||
}
|
||
}
|
||
};
|
||
|
||
|
||
},{"../type/keyid.js":2,"../type/mpi.js":3,"../enums.js":10,"../util":7,"../crypto":6}],27:[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[0].charCodeAt();
|
||
|
||
// A one-octet number describing the symmetric algorithm used.
|
||
var algo = enums.read(enums.symmetric, bytes[1].charCodeAt());
|
||
|
||
// 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.getKeyLength(algo);
|
||
var key = this.s2k.produce_key(passphrase, length);
|
||
|
||
if(this.encrypted == null) {
|
||
this.sessionKey = key;
|
||
|
||
} else {
|
||
var decrypted = crypto.symmetric.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.symmetric.encrypt(
|
||
crypto.getPrefixRandom(this.sessionKeyEncryptionAlgorithm),
|
||
this.sessionKeyEncryptionAlgorithm, key, private_key, true);
|
||
}
|
||
};
|
||
|
||
|
||
},{"../type/s2k.js":4,"../enums.js":10,"../crypto":6}],28:[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';
|
||
this.data = '';
|
||
this.date = new Date();
|
||
|
||
|
||
/**
|
||
* Set the packet data to a javascript native string or a squence of
|
||
* bytes. Conversion to a proper utf8 encoding takes place when the
|
||
* packet is written.
|
||
* @param {String} str Any native javascript string
|
||
* @param {openpgp_packet_literaldata.format} format
|
||
*/
|
||
this.set = function(str, format) {
|
||
this.format = format;
|
||
this.data = str;
|
||
}
|
||
|
||
/**
|
||
* Set the packet data to value represented by the provided string
|
||
* of bytes together with the appropriate conversion format.
|
||
* @param {String} bytes The string of bytes
|
||
* @param {openpgp_packet_literaldata.format} format
|
||
*/
|
||
this.setBytes = function(bytes, format) {
|
||
this.format = format;
|
||
|
||
if(format == 'utf8')
|
||
bytes = util.decode_utf8(bytes);
|
||
|
||
this.data = bytes;
|
||
}
|
||
|
||
/**
|
||
* Get the byte sequence representing the literal packet data
|
||
* @returns {String} A sequence of bytes
|
||
*/
|
||
this.getBytes = function() {
|
||
if(this.format == 'utf8')
|
||
return util.encode_utf8(this.data);
|
||
else
|
||
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[0].charCodeAt());
|
||
|
||
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":10,"../util":7}],29:[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'),
|
||
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[0].charCodeAt();
|
||
|
||
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[5].charCodeAt());
|
||
|
||
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() {
|
||
return this.getFingerprint().substr(12, 8);
|
||
}
|
||
|
||
/**
|
||
* 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);
|
||
}
|
||
|
||
}
|
||
|
||
},{"../type/mpi.js":3,"../enums.js":10,"../util":7,"../crypto":6}],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 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.symmetric.decrypt(
|
||
sessionKeyAlgorithm, key, this.encrypted, true);
|
||
|
||
this.packets.read(decrypted);
|
||
}
|
||
|
||
this.encrypt = function(algo, key) {
|
||
var data = this.packets.write();
|
||
|
||
this.encrypted = crypto.symmetric.encrypt(
|
||
crypto.getPrefixRandom(algo), algo, key, data, true);
|
||
}
|
||
};
|
||
|
||
},{"../crypto":6}],35:[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);
|
||
|
||
this.encrypted = null;
|
||
|
||
|
||
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)
|
||
throw 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
|
||
* @param {Integer} position Start position for the parser
|
||
* @param {Integer} len Length of the packet or remaining length of bytes
|
||
* @return {Object} This object with attributes set by the parser
|
||
*/
|
||
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[0].charCodeAt();
|
||
|
||
if(isEncrypted) {
|
||
this.encrypted = bytes;
|
||
} else {
|
||
|
||
// - Plain or encrypted multiprecision integers comprising the secret
|
||
// key data. These algorithm-specific fields are as described
|
||
// below.
|
||
|
||
this.mpi = this.mpi.concat(parse_cleartext_mpi('mod', bytes.substr(1),
|
||
this.algorithm));
|
||
}
|
||
|
||
}
|
||
|
||
/*
|
||
* Creates an OpenPGP key packet for the given key. much
|
||
* TODO in regards to s2k, subkeys.
|
||
* @param {Integer} keyType Follows the OpenPGP algorithm standard,
|
||
* IE 1 corresponds to RSA.
|
||
* @param {RSA.keyObject} key
|
||
* @param passphrase
|
||
* @param s2kHash
|
||
* @param symmetricEncryptionAlgorithm
|
||
* @param timePacket
|
||
* @return {Object} {body: [string]OpenPGP packet body contents,
|
||
header: [string] OpenPGP packet header, string: [string] header+body}
|
||
*/
|
||
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.getBlockLength(symmetric),
|
||
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;
|
||
|
||
|
||
var fn;
|
||
|
||
switch(symmetric) {
|
||
case 'cast5':
|
||
fn = crypto.cipher.cast5;
|
||
break;
|
||
case 'aes128':
|
||
case 'aes192':
|
||
case 'aes256':
|
||
var fn = function(block,key) {
|
||
return crypto.cipher.aes.encrypt(util.str2bin(block),key);
|
||
}
|
||
|
||
key = new crypto.cipher.aes.keyExpansion(key);
|
||
break;
|
||
|
||
default:
|
||
throw new Error("Unsupported symmetric encryption algorithm.");
|
||
}
|
||
|
||
console.log(cleartext);
|
||
|
||
this.encrypted += crypto.cfb.normalEncrypt(fn, iv.length, key, cleartext, iv);
|
||
}
|
||
|
||
function produceEncryptionKey(s2k, passphrase, algorithm) {
|
||
return s2k.produce_key(passphrase,
|
||
crypto.getKeyLength(algorithm));
|
||
}
|
||
|
||
/**
|
||
* 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; false if not
|
||
*/
|
||
this.decrypt = function(passphrase) {
|
||
if (!this.encrypted)
|
||
return;
|
||
|
||
var i = 0,
|
||
symmetric,
|
||
key;
|
||
|
||
var s2k_usage = this.encrypted[i++].charCodeAt();
|
||
|
||
// - [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[i++].charCodeAt();
|
||
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.getBlockLength(symmetric));
|
||
|
||
i += iv.length;
|
||
|
||
var cleartext,
|
||
ciphertext = this.encrypted.substr(i);
|
||
|
||
switch (symmetric) {
|
||
case 'idea': // - IDEA [IDEA]
|
||
throw new Error("IDEA is not implemented.");
|
||
return false;
|
||
case 'des': // - TripleDES (DES-EDE, [SCHNEIER] [HAC] - 168 bit key derived from 192)
|
||
cleartext = crypto.cfb.normal_decrypt(function(block, key) {
|
||
return crypto.cipher.des(key, block,1,null,0);
|
||
}, iv.length, key, ciphertext, iv);
|
||
break;
|
||
case 'cast5': // - CAST5 (128 bit key, as per [RFC2144])
|
||
cleartext = crypto.cfb.normalDecrypt(
|
||
function(block, key) {
|
||
var cast5 = new crypto.cipher.cast5.castClass();
|
||
cast5.setKey(key);
|
||
return cast5.encrypt(util.str2bin(block));
|
||
}
|
||
, iv.length,
|
||
util.str2bin(key.substring(0,16)), ciphertext, iv);
|
||
break;
|
||
case 'blowfish': // - Blowfish (128 bit key, 16 rounds) [BLOWFISH]
|
||
cleartext = normal_cfb_decrypt(function(block, key) {
|
||
var blowfish = new Blowfish(key);
|
||
return blowfish.encrypt(block);
|
||
}, iv.length, key, ciphertext, iv);
|
||
break;
|
||
case 'aes128': // - AES with 128-bit key [AES]
|
||
case 'aes192': // - AES with 192-bit key
|
||
case 'aes256': // - AES with 256-bit key
|
||
cleartext = crypto.cfb.normalDecrypt(function(block,key){
|
||
return crypto.cipher.aes.encrypt(util.str2bin(block),key);
|
||
},
|
||
iv.length, new crypto.cipher.aes.keyExpansion(key),
|
||
ciphertext, iv);
|
||
break;
|
||
case 'twofish': // - Twofish with 256-bit key [TWOFISH]
|
||
throw new Error("Twofish is not implemented.");
|
||
return false;
|
||
default:
|
||
throw new Error("Unknown symmetric algorithm.");
|
||
return false;
|
||
}
|
||
|
||
var hash = s2k_usage == 254 ?
|
||
'sha1' :
|
||
'mod';
|
||
|
||
|
||
this.mpi = this.mpi.concat(parse_cleartext_mpi(hash, cleartext,
|
||
this.algorithm));
|
||
}
|
||
|
||
}
|
||
|
||
packet_secret_key.prototype = new publicKey;
|
||
|
||
module.exports = packet_secret_key;
|
||
|
||
},{"./public_key.js":29,"../enums.js":10,"../type/mpi.js":3,"../type/s2k.js":4,"../util":7,"../crypto":6}],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');
|
||
|
||
/**
|
||
* @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":7}],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
|
||
|
||
var util = require('../util'),
|
||
packet = require('./packet.js'),
|
||
enums = require('../enums.js'),
|
||
crypto = require('../crypto'),
|
||
type_mpi = require('../type/mpi.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.signatureType = null;
|
||
this.hashAlgorithm = null;
|
||
this.publicKeyAlgorithm = null;
|
||
|
||
this.signatureData = null;
|
||
this.signedHashValue = null;
|
||
this.mpi = null;
|
||
|
||
this.created = null;
|
||
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 = null;
|
||
this.notation = {};
|
||
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.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;
|
||
|
||
var version = bytes[i++].charCodeAt();
|
||
// switch on version (3 and 4)
|
||
switch (version) {
|
||
case 3:
|
||
// One-octet length of following hashed material. MUST be 5.
|
||
if (bytes[i++].charCodeAt() != 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[i++].charCodeAt();
|
||
|
||
// 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(position, i);
|
||
|
||
// Eight-octet Key ID of signer.
|
||
this.issuerKeyId = bytes.substring(i, i +8);
|
||
i += 8;
|
||
|
||
// One-octet public-key algorithm.
|
||
this.publicKeyAlgorithm = bytes[i++].charCodeAt();
|
||
|
||
// One-octet hash algorithm.
|
||
this.hashAlgorithm = bytes[i++].charCodeAt();
|
||
break;
|
||
case 4:
|
||
this.signatureType = bytes[i++].charCodeAt();
|
||
this.publicKeyAlgorithm = bytes[i++].charCodeAt();
|
||
this.hashAlgorithm = bytes[i++].charCodeAt();
|
||
|
||
|
||
function subpackets(bytes, signed) {
|
||
// Two-octet scalar octet count for following hashed subpacket
|
||
// data.
|
||
var subpacket_length = util.readNumber(
|
||
bytes.substr(0, 2));
|
||
|
||
var i = 2;
|
||
|
||
// Hashed 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;
|
||
|
||
// Since it is trivial to add data to the unhashed portion of
|
||
// the packet we simply ignore all unauthenticated data.
|
||
if(signed)
|
||
this.read_sub_packet(bytes.substr(i, len.len));
|
||
|
||
i += len.len;
|
||
}
|
||
|
||
return i;
|
||
}
|
||
|
||
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);
|
||
|
||
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);
|
||
|
||
|
||
// Add subpackets here
|
||
result += util.writeNumber(0, 2);
|
||
|
||
|
||
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 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[i].charCodeAt());
|
||
}
|
||
}
|
||
|
||
// The leftwost bit denotes a "critical" packet, but we ignore it.
|
||
var type = bytes[mypos++].charCodeAt() & 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[mypos++].charCodeAt() == 1;
|
||
break;
|
||
case 5: // Trust Signature
|
||
this.trustLevel = bytes[mypos++].charCodeAt();
|
||
this.trustAmount = bytes[mypos++].charCodeAt();
|
||
break;
|
||
case 6: // Regular Expression
|
||
this.regularExpression = bytes.substr(mypos);
|
||
break;
|
||
case 7: // Revocable
|
||
this.revocable = bytes[mypos++].charCodeAt() == 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[mypos++].charCodeAt());
|
||
}
|
||
|
||
break;
|
||
case 12: // Revocation Key
|
||
// (1 octet of class, 1 octet of public-key algorithm ID, 20
|
||
// octets of
|
||
// fingerprint)
|
||
this.revocationKeyClass = bytes[mypos++].charCodeAt();
|
||
this.revocationKeyAlgorithm = bytes[mypos++].charCodeAt();
|
||
this.revocationKeyFingerprint = bytes.substr(mypos, 20);
|
||
break;
|
||
|
||
case 16: // Issuer
|
||
this.issuerKeyId = bytes.substr(mypos, 8);
|
||
break;
|
||
|
||
case 20: // Notation Data
|
||
// We don't know how to handle anything but a text flagged data.
|
||
if(bytes[mypos].charCodeAt() == 0x80) {
|
||
|
||
// We extract key/value tuple from the byte stream.
|
||
mypos += 4;
|
||
var m = util.writeNumber(bytes.substr(mypos, 2));
|
||
mypos += 2
|
||
var n = util.writeNumber(bytes.substr(mypos, 2));
|
||
mypos += 2
|
||
|
||
var name = bytes.substr(mypos, m),
|
||
value = bytes.substr(mypos + m, n);
|
||
|
||
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[mypos++].charCodeAt();
|
||
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[mypos++].charCodeAt();
|
||
this.signatureTargetHashAlgorithm = bytes[mypos++].charCodeAt();
|
||
|
||
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:
|
||
return data.literal.getBytes();
|
||
|
||
case t.text:
|
||
return this.toSign(t.binary, data)
|
||
.replace(/\r\n/g, '\n')
|
||
.replace(/\n/g, '\r\n');
|
||
|
||
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.thrid_party:
|
||
throw new Error('Not implemented');
|
||
break;
|
||
default:
|
||
throw new Error('Unknown signature type.')
|
||
}
|
||
}
|
||
|
||
|
||
this.calculateTrailer = function() {
|
||
// calculating the trailer
|
||
var 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} data data which on the signature applies
|
||
* @param {openpgp_msg_privatekey} 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;
|
||
}
|
||
}
|
||
|
||
|
||
},{"./packet.js":23,"../enums.js":10,"../type/mpi.js":3,"../util":7,"../crypto":6}],40:[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);
|
||
}
|
||
|
||
module.exports = {
|
||
encrypt: AESencrypt,
|
||
keyExpansion: keyExpansion
|
||
}
|
||
|
||
},{"../../util":7}],41:[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
|
||
|
||
var util = require('../../util');
|
||
|
||
// added by Recurity Labs
|
||
function desede(block,key) {
|
||
var key1 = key.substring(0,8);
|
||
var key2 = key.substring(8,16);
|
||
var key3 = key.substring(16,24);
|
||
return util.str2bin(des(des_createKeys(key3),des(des_createKeys(key2),des(des_createKeys(key1),util.bin2str(block), true, 0,null,null), false, 0,null,null), true, 0,null,null));
|
||
}
|
||
|
||
|
||
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
|
||
if (padding == 2) message += " "; //pad the message with spaces
|
||
else if (padding == 1) {temp = 8-(len%8); message += String.fromCharCode (temp,temp,temp,temp,temp,temp,temp,temp); if (temp==8) len+=8;} //PKCS7 padding
|
||
else if (!padding) message += "\0\0\0\0\0\0\0\0"; //pad the message out with null bytes
|
||
|
||
//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;
|
||
result = result.replace(/\0*$/g, "");
|
||
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
|
||
|
||
|
||
module.exports = desede;
|
||
|
||
},{"../../util":7}],42:[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
|
||
|
||
var util = require('../../util');
|
||
|
||
function cast5_encrypt(block, key) {
|
||
var cast5 = new openpgp_symenc_cast5();
|
||
cast5.setKey(util.str2bin(key));
|
||
return cast5.encrypt(block);
|
||
}
|
||
|
||
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);
|
||
|
||
};
|
||
|
||
|
||
module.exports = cast5_encrypt;
|
||
module.exports.castClass = openpgp_symenc_cast5;
|
||
|
||
},{"../../util":7}],43:[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.
|
||
*
|
||
*/
|
||
|
||
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;
|
||
}
|
||
|
||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
//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
|
||
};
|
||
}
|
||
|
||
module.exports = TFencrypt;
|
||
|
||
},{"../../util":7}],44:[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);
|
||
}
|
||
|
||
module.exports = BFencrypt;
|
||
|
||
},{"../../util":7}],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
|
||
//
|
||
// 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;
|
||
|
||
},{"./jsbn.js":13,"../random.js":14,"../../util":7}],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
|
||
//
|
||
// ElGamal implementation
|
||
|
||
var BigInteger = require('./jsbn.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 = openpgp_crypto_getRandomBigIntegerInRange(two, pMinus2);
|
||
var k = k.mod(pMinus2).add(BigInteger.ONE);
|
||
var c = new Array();
|
||
c[0] = g.modPow(k, p);
|
||
c[1] = y.modPow(k, p).multiply(m).mod(p).toMPI();
|
||
c[0] = c[0].toMPI();
|
||
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;
|
||
|
||
},{"./jsbn.js":13,"../../util":7}]},{},[])
|
||
//@ sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlcyI6WyIvaG9tZS9wYW5jYWtlL2NvZGUvb3BlbnBncGpzL3NyYy9vcGVucGdwLmpzIiwiL2hvbWUvcGFuY2FrZS9jb2RlL29wZW5wZ3Bqcy9zcmMvdHlwZS9rZXlpZC5qcyIsIi9ob21lL3BhbmNha2UvY29kZS9vcGVucGdwanMvc3JjL2luZGV4LmpzIiwiL2hvbWUvcGFuY2FrZS9jb2RlL29wZW5wZ3Bqcy9zcmMvZW5jb2RpbmcvYXJtb3IuanMiLCIvaG9tZS9wYW5jYWtlL2NvZGUvb3BlbnBncGpzL3NyYy91dGlsL3V0aWwuanMiLCIvaG9tZS9wYW5jYWtlL2NvZGUvb3BlbnBncGpzL3NyYy9lbnVtcy5qcyIsIi9ob21lL3BhbmNha2UvY29kZS9vcGVucGdwanMvc3JjL2VuY29kaW5nL2Jhc2U2NC5qcyIsIi9ob21lL3BhbmNha2UvY29kZS9vcGVucGdwanMvc3JjL3BhY2tldC9pbmRleC5qcyIsIi9ob21lL3BhbmNha2UvY29kZS9vcGVucGdwanMvc3JjL3R5cGUvbXBpLmpzIiwiL2hvbWUvcGFuY2FrZS9jb2RlL29wZW5wZ3Bqcy9zcmMvdHlwZS9zMmsuanMiLCIvaG9tZS9wYW5jYWtlL2NvZGUvb3BlbnBncGpzL3NyYy9jcnlwdG8vcmFuZG9tLmpzIiwiL2hvbWUvcGFuY2FrZS9jb2RlL29wZW5wZ3Bqcy9zcmMvY3J5cHRvL2luZGV4LmpzIiwiL2hvbWUvcGFuY2FrZS9jb2RlL29wZW5wZ3Bqcy9zcmMvcGFja2V0L3BhY2tldGxpc3QuanMiLCIvaG9tZS9wYW5jYWtlL2NvZGUvb3BlbnBncGpzL3NyYy9wYWNrZXQvYWxsX3BhY2tldHMuanMiLCIvaG9tZS9wYW5jYWtlL2NvZGUvb3BlbnBncGpzL3NyYy9jcnlwdG8vcHVibGljX2tleS9qc2JuLmpzIiwiL2hvbWUvcGFuY2FrZS9jb2RlL29wZW5wZ3Bqcy9zcmMvcGFja2V0L21hcmtlci5qcyIsIi9ob21lL3BhbmNha2UvY29kZS9vcGVucGdwanMvc3JjL3BhY2tldC91c2VyX2F0dHJpYnV0ZS5qcyIsIi9ob21lL3BhbmNha2UvY29kZS9vcGVucGdwanMvc3JjL3BhY2tldC90cnVzdC5qcyIsIi9ob21lL3BhbmNha2UvY29kZS9vcGVucGdwanMvc3JjL2NyeXB0by9jaXBoZXIvaW5kZXguanMiLCIvaG9tZS9wYW5jYWtlL2NvZGUvb3BlbnBncGpzL3NyYy9jcnlwdG8vaGFzaC9pbmRleC5qcyIsIi9ob21lL3BhbmNha2UvY29kZS9vcGVucGdwanMvc3JjL2NyeXB0by9jZmIuanMiLCIvaG9tZS9wYW5jYWtlL2NvZGUvb3BlbnBncGpzL3NyYy9jcnlwdG8vcHVibGljX2tleS9pbmRleC5qcyIsIi9ob21lL3BhbmNha2UvY29kZS9vcGVucGdwanMvc3JjL2NyeXB0by9zaWduYXR1cmUuanMiLCIvaG9tZS9wYW5jYWtlL2NvZGUvb3BlbnBncGpzL3NyYy9jcnlwdG8vcGtjczEuanMiLCIvaG9tZS9wYW5jYWtlL2NvZGUvb3BlbnBncGpzL3NyYy9jcnlwdG8vc3ltLmpzIiwiL2hvbWUvcGFuY2FrZS9jb2RlL29wZW5wZ3Bqcy9zcmMvY3J5cHRvL2NyeXB0by5qcyIsIi9ob21lL3BhbmNha2UvY29kZS9vcGVucGdwanMvc3JjL3BhY2tldC9jb21wcmVzc2VkLmpzIiwiL2hvbWUvcGFuY2FrZS9jb2RlL29wZW5wZ3Bqcy9zcmMvcGFja2V0L3B1YmxpY19zdWJrZXkuanMiLCIvaG9tZS9wYW5jYWtlL2NvZGUvb3BlbnBncGpzL3NyYy9wYWNrZXQvb25lX3Bhc3Nfc2lnbmF0dXJlLmpzIiwiL2hvbWUvcGFuY2FrZS9jb2RlL29wZW5wZ3Bqcy9zcmMvcGFja2V0L3NlY3JldF9zdWJrZXkuanMiLCIvaG9tZS9wYW5jYWtlL2NvZGUvb3BlbnBncGpzL3NyYy9jcnlwdG8vaGFzaC9zaGEuanMiLCIvaG9tZS9wYW5jYWtlL2NvZGUvb3BlbnBncGpzL3NyYy9jcnlwdG8vaGFzaC9yaXBlLW1kLmpzIiwiL2hvbWUvcGFuY2FrZS9jb2RlL29wZW5wZ3Bqcy9zcmMvY3J5cHRvL3B1YmxpY19rZXkvZHNhLmpzIiwiL2hvbWUvcGFuY2FrZS9jb2RlL29wZW5wZ3Bqcy9zcmMvY29tcHJlc3Npb24vanhnLmpzIiwiL2hvbWUvcGFuY2FrZS9jb2RlL29wZW5wZ3Bqcy9zcmMvY3J5cHRvL2hhc2gvbWQ1LmpzIiwiL2hvbWUvcGFuY2FrZS9jb2RlL29wZW5wZ3Bqcy9zcmMvcGFja2V0L3BhY2tldC5qcyIsIi9ob21lL3BhbmNha2UvY29kZS9vcGVucGdwanMvc3JjL3BhY2tldC9zeW1fZW5jcnlwdGVkX2ludGVncml0eV9wcm90ZWN0ZWQuanMiLCIvaG9tZS9wYW5jYWtlL2NvZGUvb3BlbnBncGpzL3NyYy9wYWNrZXQvcHVibGljX2tleV9lbmNyeXB0ZWRfc2Vzc2lvbl9rZXkuanMiLCIvaG9tZS9wYW5jYWtlL2NvZGUvb3BlbnBncGpzL3NyYy9wYWNrZXQvc3ltX2VuY3J5cHRlZF9zZXNzaW9uX2tleS5qcyIsIi9ob21lL3BhbmNha2UvY29kZS9vcGVucGdwanMvc3JjL3BhY2tldC9saXRlcmFsLmpzIiwiL2hvbWUvcGFuY2FrZS9jb2RlL29wZW5wZ3Bqcy9zcmMvcGFja2V0L3B1YmxpY19rZXkuanMiLCIvaG9tZS9wYW5jYWtlL2NvZGUvb3BlbnBncGpzL3NyYy9wYWNrZXQvc3ltbWV0cmljYWxseV9lbmNyeXB0ZWQuanMiLCIvaG9tZS9wYW5jYWtlL2NvZGUvb3BlbnBncGpzL3NyYy9wYWNrZXQvc2VjcmV0X2tleS5qcyIsIi9ob21lL3BhbmNha2UvY29kZS9vcGVucGdwanMvc3JjL3BhY2tldC91c2VyaWQuanMiLCIvaG9tZS9wYW5jYWtlL2NvZGUvb3BlbnBncGpzL3NyYy9wYWNrZXQvc2lnbmF0dXJlLmpzIiwiL2hvbWUvcGFuY2FrZS9jb2RlL29wZW5wZ3Bqcy9zcmMvY3J5cHRvL2NpcGhlci9hZXMuanMiLCIvaG9tZS9wYW5jYWtlL2NvZGUvb3BlbnBncGpzL3NyYy9jcnlwdG8vY2lwaGVyL2Rlcy5qcyIsIi9ob21lL3BhbmNha2UvY29kZS9vcGVucGdwanMvc3JjL2NyeXB0by9jaXBoZXIvY2FzdDUuanMiLCIvaG9tZS9wYW5jYWtlL2NvZGUvb3BlbnBncGpzL3NyYy9jcnlwdG8vY2lwaGVyL3R3b2Zpc2guanMiLCIvaG9tZS9wYW5jYWtlL2NvZGUvb3BlbnBncGpzL3NyYy9jcnlwdG8vY2lwaGVyL2Jsb3dmaXNoLmpzIiwiL2hvbWUvcGFuY2FrZS9jb2RlL29wZW5wZ3Bqcy9zcmMvY3J5cHRvL3B1YmxpY19rZXkvcnNhLmpzIiwiL2hvbWUvcGFuY2FrZS9jb2RlL29wZW5wZ3Bqcy9zcmMvY3J5cHRvL3B1YmxpY19rZXkvZWxnYW1hbC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1Y0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7QUM3Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdFNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNyVkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMU9BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDWEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDN0tBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaEVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDckVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM3QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcHpDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ0pBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZTQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1BBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDN0hBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOUZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdlNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaEtBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsc0NBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdlNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pKQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVzQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pOQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVRQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdkhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbExBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0lBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUlBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdEVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoVUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM2VBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzZUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuTkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeGlCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDalRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDN1lBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdJQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBHUEc0QnJvd3NlcnMgLSBBbiBPcGVuUEdQIGltcGxlbWVudGF0aW9uIGluIGphdmFzY3JpcHRcbi8vIENvcHlyaWdodCAoQykgMjAxMSBSZWN1cml0eSBMYWJzIEdtYkhcbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vclxuLy8gbW9kaWZ5IGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyXG4vLyB2ZXJzaW9uIDIuMSBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4vLyBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuLy8gTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZSBHTlVcbi8vIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG4vLyBcbi8vIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYWxvbmcgd2l0aCB0aGlzIGxpYnJhcnk7IGlmIG5vdCwgd3JpdGUgdG8gdGhlIEZyZWUgU29mdHdhcmVcbi8vIEZvdW5kYXRpb24sIEluYy4sIDUxIEZyYW5rbGluIFN0cmVldCwgRmlmdGggRmxvb3IsIEJvc3RvbiwgTUEgIDAyMTEwLTEzMDEgIFVTQVxuXG4vKipcbiAqIEBmaWxlb3ZlcnZpZXcgVGhlIG9wZW5wZ3AgYmFzZSBjbGFzcyBzaG91bGQgcHJvdmlkZSBhbGwgb2YgdGhlIGZ1bmN0aW9uYWxpdHkgXG4gKiB0byBjb25zdW1lIHRoZSBvcGVucGdwLmpzIGxpYnJhcnkuIEFsbCBhZGRpdGlvbmFsIGNsYXNzZXMgYXJlIGRvY3VtZW50ZWQgXG4gKiBmb3IgZXh0ZW5kaW5nIGFuZCBkZXZlbG9waW5nIG9uIHRvcCBvZiB0aGUgYmFzZSBsaWJyYXJ5LlxuICovXG5cbi8qKlxuICogR1BHNEJyb3dzZXJzIENvcmUgaW50ZXJmYWNlLiBBIHNpbmdsZSBpbnN0YW5jZSBpcyBob2xkXG4gKiBmcm9tIHRoZSBiZWdpbm5pbmcuIFRvIHVzZSB0aGlzIGxpYnJhcnkgY2FsbCBcIm9wZW5wZ3AuaW5pdCgpXCJcbiAqIEBhbGlhcyBvcGVucGdwXG4gKiBAY2xhc3NcbiAqIEBjbGFzc2Rlc2MgTWFpbiBPcGVucGdwLmpzIGNsYXNzLiBVc2UgdGhpcyB0byBpbml0aWF0ZSBhbmQgbWFrZSBhbGwgY2FsbHMgdG8gdGhpcyBsaWJyYXJ5LlxuICovXG5mdW5jdGlvbiBfb3BlbnBncCAoKSB7XG5cdHRoaXMudG9zdHJpbmcgPSBcIlwiO1xuXHRcblx0LyoqXG5cdCAqIGluaXRpYWxpemVzIHRoZSBsaWJyYXJ5OlxuXHQgKiAtIHJlYWRpbmcgdGhlIGtleXJpbmcgZnJvbSBsb2NhbCBzdG9yYWdlXG5cdCAqIC0gcmVhZGluZyB0aGUgY29uZmlnIGZyb20gbG9jYWwgc3RvcmFnZVxuXHQgKi9cblx0ZnVuY3Rpb24gaW5pdCgpIHtcblx0XHR0aGlzLmNvbmZpZyA9IG5ldyBvcGVucGdwX2NvbmZpZygpO1xuXHRcdHRoaXMuY29uZmlnLnJlYWQoKTtcblx0XHR0aGlzLmtleXJpbmcgPSBuZXcgb3BlbnBncF9rZXlyaW5nKCk7XG5cdFx0dGhpcy5rZXlyaW5nLmluaXQoKTtcblx0fVxuXHRcblx0LyoqXG5cdCAqIHJlYWRzIHNldmVyYWwgcHVibGljS2V5IG9iamVjdHMgZnJvbSBhIGFzY2lpIGFybW9yZWRcblx0ICogcmVwcmVzZW50YXRpb24gYW4gcmV0dXJucyBvcGVucGdwX21zZ19wdWJsaWNrZXkgcGFja2V0c1xuXHQgKiBAcGFyYW0ge1N0cmluZ30gYXJtb3JlZFRleHQgT3BlblBHUCBhcm1vcmVkIHRleHQgY29udGFpbmluZ1xuXHQgKiB0aGUgcHVibGljIGtleShzKVxuXHQgKiBAcmV0dXJuIHtvcGVucGdwX21zZ19wdWJsaWNrZXlbXX0gb24gZXJyb3IgdGhlIGZ1bmN0aW9uXG5cdCAqIHJldHVybnMgbnVsbFxuXHQgKi9cblx0ZnVuY3Rpb24gcmVhZF9wdWJsaWNLZXkoYXJtb3JlZFRleHQpIHtcblx0XHR2YXIgbXlwb3MgPSAwO1xuXHRcdHZhciBwdWJsaWNLZXlzID0gbmV3IEFycmF5KCk7XG5cdFx0dmFyIHB1YmxpY0tleUNvdW50ID0gMDtcblx0XHR2YXIgaW5wdXQgPSBvcGVucGdwX2VuY29kaW5nX2RlQXJtb3IoYXJtb3JlZFRleHQucmVwbGFjZSgvXFxyL2csJycpKS5vcGVucGdwO1xuXHRcdHZhciBsID0gaW5wdXQubGVuZ3RoO1xuXHRcdHdoaWxlIChteXBvcyAhPSBpbnB1dC5sZW5ndGgpIHtcblx0XHRcdHZhciBmaXJzdF9wYWNrZXQgPSBvcGVucGdwX3BhY2tldC5yZWFkX3BhY2tldChpbnB1dCwgbXlwb3MsIGwpO1xuXHRcdFx0Ly8gcHVibGljIGtleSBwYXJzZXJcblx0XHRcdGlmIChpbnB1dFtteXBvc10uY2hhckNvZGVBdCgpID09IDB4OTkgfHwgZmlyc3RfcGFja2V0LnRhZ1R5cGUgPT0gNikge1xuXHRcdFx0XHRwdWJsaWNLZXlzW3B1YmxpY0tleUNvdW50XSA9IG5ldyBvcGVucGdwX21zZ19wdWJsaWNrZXkoKTtcdFx0XHRcdFxuXHRcdFx0XHRwdWJsaWNLZXlzW3B1YmxpY0tleUNvdW50XS5oZWFkZXIgPSBpbnB1dC5zdWJzdHJpbmcobXlwb3MsbXlwb3MrMyk7XG5cdFx0XHRcdGlmIChpbnB1dFtteXBvc10uY2hhckNvZGVBdCgpID09IDB4OTkpIHtcblx0XHRcdFx0XHQvLyBwYXJzZSB0aGUgbGVuZ3RoIGFuZCByZWFkIGEgdGFnNiBwYWNrZXRcblx0XHRcdFx0XHRteXBvcysrO1xuXHRcdFx0XHRcdHZhciBsID0gKGlucHV0W215cG9zKytdLmNoYXJDb2RlQXQoKSA8PCA4KVxuXHRcdFx0XHRcdFx0XHR8IGlucHV0W215cG9zKytdLmNoYXJDb2RlQXQoKTtcblx0XHRcdFx0XHRwdWJsaWNLZXlzW3B1YmxpY0tleUNvdW50XS5wdWJsaWNLZXlQYWNrZXQgPSBuZXcgb3BlbnBncF9wYWNrZXRfa2V5bWF0ZXJpYWwoKTtcblx0XHRcdFx0XHRwdWJsaWNLZXlzW3B1YmxpY0tleUNvdW50XS5wdWJsaWNLZXlQYWNrZXQuaGVhZGVyID0gcHVibGljS2V5c1twdWJsaWNLZXlDb3VudF0uaGVhZGVyO1xuXHRcdFx0XHRcdHB1YmxpY0tleXNbcHVibGljS2V5Q291bnRdLnB1YmxpY0tleVBhY2tldC5yZWFkX3RhZzYoaW5wdXQsIG15cG9zLCBsKTtcblx0XHRcdFx0XHRteXBvcyArPSBwdWJsaWNLZXlzW3B1YmxpY0tleUNvdW50XS5wdWJsaWNLZXlQYWNrZXQucGFja2V0TGVuZ3RoO1xuXHRcdFx0XHRcdG15cG9zICs9IHB1YmxpY0tleXNbcHVibGljS2V5Q291bnRdLnJlYWRfbm9kZXMocHVibGljS2V5c1twdWJsaWNLZXlDb3VudF0ucHVibGljS2V5UGFja2V0LCBpbnB1dCwgbXlwb3MsIChpbnB1dC5sZW5ndGggLSBteXBvcykpO1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdHB1YmxpY0tleXNbcHVibGljS2V5Q291bnRdID0gbmV3IG9wZW5wZ3BfbXNnX3B1YmxpY2tleSgpO1xuXHRcdFx0XHRcdHB1YmxpY0tleXNbcHVibGljS2V5Q291bnRdLnB1YmxpY0tleVBhY2tldCA9IGZpcnN0X3BhY2tldDtcblx0XHRcdFx0XHRteXBvcyArPSBmaXJzdF9wYWNrZXQuaGVhZGVyTGVuZ3RoK2ZpcnN0X3BhY2tldC5wYWNrZXRMZW5ndGg7XG5cdFx0XHRcdFx0bXlwb3MgKz0gcHVibGljS2V5c1twdWJsaWNLZXlDb3VudF0ucmVhZF9ub2RlcyhmaXJzdF9wYWNrZXQsIGlucHV0LCBteXBvcywgaW5wdXQubGVuZ3RoIC1teXBvcyk7XG5cdFx0XHRcdH1cblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHV0aWwucHJpbnRfZXJyb3IoXCJubyBwdWJsaWMga2V5IGZvdW5kIVwiKTtcblx0XHRcdFx0cmV0dXJuIG51bGw7XG5cdFx0XHR9XG5cdFx0XHRwdWJsaWNLZXlzW3B1YmxpY0tleUNvdW50XS5kYXRhID0gaW5wdXQuc3Vic3RyaW5nKDAsbXlwb3MpO1xuXHRcdFx0cHVibGljS2V5Q291bnQrKztcblx0XHR9XG5cdFx0cmV0dXJuIHB1YmxpY0tleXM7XG5cdH1cblx0XG5cdC8qKlxuXHQgKiByZWFkcyBzZXZlcmFsIHByaXZhdGVLZXkgb2JqZWN0cyBmcm9tIGEgYXNjaWkgYXJtb3JlZFxuXHQgKiByZXByZXNlbnRhdGlvbiBhbiByZXR1cm5zIG9wZW5wZ3BfbXNnX3ByaXZhdGVrZXkgb2JqZWN0c1xuXHQgKiBAcGFyYW0ge1N0cmluZ30gYXJtb3JlZFRleHQgT3BlblBHUCBhcm1vcmVkIHRleHQgY29udGFpbmluZ1xuXHQgKiB0aGUgcHJpdmF0ZSBrZXkocylcblx0ICogQHJldHVybiB7b3BlbnBncF9tc2dfcHJpdmF0ZWtleVtdfSBvbiBlcnJvciB0aGUgZnVuY3Rpb25cblx0ICogcmV0dXJucyBudWxsXG5cdCAqL1xuXHRmdW5jdGlvbiByZWFkX3ByaXZhdGVLZXkoYXJtb3JlZFRleHQpIHtcblx0XHR2YXIgcHJpdmF0ZUtleXMgPSBuZXcgQXJyYXkoKTtcblx0XHR2YXIgcHJpdmF0ZUtleUNvdW50ID0gMDtcblx0XHR2YXIgbXlwb3MgPSAwO1xuXHRcdHZhciBpbnB1dCA9IG9wZW5wZ3BfZW5jb2RpbmdfZGVBcm1vcihhcm1vcmVkVGV4dC5yZXBsYWNlKC9cXHIvZywnJykpLm9wZW5wZ3A7XG5cdFx0dmFyIGwgPSBpbnB1dC5sZW5ndGg7XG5cdFx0d2hpbGUgKG15cG9zICE9IGlucHV0Lmxlbmd0aCkge1xuXHRcdFx0dmFyIGZpcnN0X3BhY2tldCA9IG9wZW5wZ3BfcGFja2V0LnJlYWRfcGFja2V0KGlucHV0LCBteXBvcywgbCk7XG5cdFx0XHRpZiAoZmlyc3RfcGFja2V0LnRhZ1R5cGUgPT0gNSkge1xuXHRcdFx0XHRwcml2YXRlS2V5c1twcml2YXRlS2V5cy5sZW5ndGhdID0gbmV3IG9wZW5wZ3BfbXNnX3ByaXZhdGVrZXkoKTtcblx0XHRcdFx0bXlwb3MgKz0gZmlyc3RfcGFja2V0LmhlYWRlckxlbmd0aCtmaXJzdF9wYWNrZXQucGFja2V0TGVuZ3RoO1xuXHRcdFx0XHRteXBvcyArPSBwcml2YXRlS2V5c1twcml2YXRlS2V5Q291bnRdLnJlYWRfbm9kZXMoZmlyc3RfcGFja2V0LCBpbnB1dCwgbXlwb3MsIGwpO1xuXHRcdFx0Ly8gb3RoZXIgYmxvY2tzXHQgICAgICAgICAgICBcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHV0aWwucHJpbnRfZXJyb3IoJ25vIGJsb2NrIHBhY2tldCBmb3VuZCEnKTtcblx0XHRcdFx0cmV0dXJuIG51bGw7XG5cdFx0XHR9XG5cdFx0XHRwcml2YXRlS2V5c1twcml2YXRlS2V5Q291bnRdLmRhdGEgPSBpbnB1dC5zdWJzdHJpbmcoMCxteXBvcyk7XG5cdFx0XHRwcml2YXRlS2V5Q291bnQrKztcblx0XHR9XG5cdFx0cmV0dXJuIHByaXZhdGVLZXlzO1x0XHRcblx0fVxuXG5cdC8qKlxuXHQgKiByZWFkcyBtZXNzYWdlIHBhY2tldHMgb3V0IG9mIGFuIE9wZW5QR1AgYXJtb3JlZCB0ZXh0IGFuZFxuXHQgKiByZXR1cm5zIGFuIGFycmF5IG9mIG1lc3NhZ2Ugb2JqZWN0c1xuXHQgKiBAcGFyYW0ge1N0cmluZ30gYXJtb3JlZFRleHQgdGV4dCB0byBiZSBwYXJzZWRcblx0ICogQHJldHVybiB7b3BlbnBncF9tc2dfbWVzc2FnZVtdfSBvbiBlcnJvciB0aGUgZnVuY3Rpb25cblx0ICogcmV0dXJucyBudWxsXG5cdCAqL1xuXHRmdW5jdGlvbiByZWFkX21lc3NhZ2UoYXJtb3JlZFRleHQpIHtcblx0XHR2YXIgZGVhcm1vcmVkO1xuXHRcdHRyeXtcbiAgICBcdFx0ZGVhcm1vcmVkID0gb3BlbnBncF9lbmNvZGluZ19kZUFybW9yKGFybW9yZWRUZXh0LnJlcGxhY2UoL1xcci9nLCcnKSk7XG5cdFx0fVxuXHRcdGNhdGNoKGUpe1xuICAgIFx0XHR1dGlsLnByaW50X2Vycm9yKCdubyBtZXNzYWdlIGZvdW5kIScpO1xuICAgIFx0XHRyZXR1cm4gbnVsbDtcblx0XHR9XG5cdFx0cmV0dXJuIHJlYWRfbWVzc2FnZXNfZGVhcm1vcmVkKGRlYXJtb3JlZCk7XG5cdFx0fVxuXHRcdFxuXHQvKipcblx0ICogcmVhZHMgbWVzc2FnZSBwYWNrZXRzIG91dCBvZiBhbiBPcGVuUEdQIGFybW9yZWQgdGV4dCBhbmRcblx0ICogcmV0dXJucyBhbiBhcnJheSBvZiBtZXNzYWdlIG9iamVjdHMuIENhbiBiZSBjYWxsZWQgZXh0ZXJuYWxseSBvciBpbnRlcm5hbGx5LlxuXHQgKiBFeHRlcm5hbCBjYWxsIHdpbGwgcGFyc2UgYSBkZS1hcm1vcmVkIG1lc3NhZ2VkIGFuZCByZXR1cm4gbWVzc2FnZXMgZm91bmQuXG5cdCAqIEludGVybmFsIHdpbGwgYmUgY2FsbGVkIHRvIHJlYWQgcGFja2V0cyB3cmFwcGVkIGluIG90aGVyIHBhY2tldHMgKGkuZS4gY29tcHJlc3NlZClcblx0ICogQHBhcmFtIHtTdHJpbmd9IGlucHV0IGRlYXJtb3JlZCB0ZXh0IG9mIE9wZW5QR1AgcGFja2V0cywgdG8gYmUgcGFyc2VkXG5cdCAqIEByZXR1cm4ge29wZW5wZ3BfbXNnX21lc3NhZ2VbXX0gb24gZXJyb3IgdGhlIGZ1bmN0aW9uXG5cdCAqIHJldHVybnMgbnVsbFxuXHQgKi9cblx0ZnVuY3Rpb24gcmVhZF9tZXNzYWdlc19kZWFybW9yZWQoaW5wdXQpe1xuXHRcdHZhciBtZXNzYWdlU3RyaW5nID0gaW5wdXQub3BlbnBncDtcblx0XHR2YXIgc2lnbmF0dXJlVGV4dCA9IGlucHV0LnRleHQ7IC8vdGV4dCB0byB2ZXJpZnkgc2lnbmF0dXJlcyBhZ2FpbnN0LiBNb2RpZmllZCBieSBUYWcxMS5cblx0XHR2YXIgbWVzc2FnZXMgPSBuZXcgQXJyYXkoKTtcblx0XHR2YXIgbWVzc2FnZUNvdW50ID0gMDtcblx0XHR2YXIgbXlwb3MgPSAwO1xuXHRcdHZhciBsID0gbWVzc2FnZVN0cmluZy5sZW5ndGg7XG5cdFx0d2hpbGUgKG15cG9zIDwgbWVzc2FnZVN0cmluZy5sZW5ndGgpIHtcblx0XHRcdHZhciBmaXJzdF9wYWNrZXQgPSBvcGVucGdwX3BhY2tldC5yZWFkX3BhY2tldChtZXNzYWdlU3RyaW5nLCBteXBvcywgbCk7XG5cdFx0XHRpZiAoIWZpcnN0X3BhY2tldCkge1xuXHRcdFx0XHRicmVhaztcblx0XHRcdH1cblx0XHRcdC8vIHB1YmxpYyBrZXkgcGFyc2VyIChkZWZpbml0aW9uIGZyb20gdGhlIHN0YW5kYXJkOilcblx0XHRcdC8vIE9wZW5QR1AgTWVzc2FnZSAgICAgIDotIEVuY3J5cHRlZCBNZXNzYWdlIHwgU2lnbmVkIE1lc3NhZ2UgfFxuXHRcdFx0Ly8gICAgICAgICAgICAgICAgICAgICAgICAgQ29tcHJlc3NlZCBNZXNzYWdlIHwgTGl0ZXJhbCBNZXNzYWdlLlxuXHRcdFx0Ly8gQ29tcHJlc3NlZCBNZXNzYWdlICAgOi0gQ29tcHJlc3NlZCBEYXRhIFBhY2tldC5cblx0XHRcdC8vIFxuXHRcdFx0Ly8gTGl0ZXJhbCBNZXNzYWdlICAgICAgOi0gTGl0ZXJhbCBEYXRhIFBhY2tldC5cblx0XHRcdC8vIFxuXHRcdFx0Ly8gRVNLICAgICAgICAgICAgICAgICAgOi0gUHVibGljLUtleSBFbmNyeXB0ZWQgU2Vzc2lvbiBLZXkgUGFja2V0IHxcblx0XHRcdC8vICAgICAgICAgICAgICAgICAgICAgICAgIFN5bW1ldHJpYy1LZXkgRW5jcnlwdGVkIFNlc3Npb24gS2V5IFBhY2tldC5cblx0XHRcdC8vIFxuXHRcdFx0Ly8gRVNLIFNlcXVlbmNlICAgICAgICAgOi0gRVNLIHwgRVNLIFNlcXVlbmNlLCBFU0suXG5cdFx0XHQvLyBcblx0XHRcdC8vIEVuY3J5cHRlZCBEYXRhICAgICAgIDotIFN5bW1ldHJpY2FsbHkgRW5jcnlwdGVkIERhdGEgUGFja2V0IHxcblx0XHRcdC8vICAgICAgICAgICAgICAgICAgICAgICAgIFN5bW1ldHJpY2FsbHkgRW5jcnlwdGVkIEludGVncml0eSBQcm90ZWN0ZWQgRGF0YSBQYWNrZXRcblx0XHRcdC8vIFxuXHRcdFx0Ly8gRW5jcnlwdGVkIE1lc3NhZ2UgICAgOi0gRW5jcnlwdGVkIERhdGEgfCBFU0sgU2VxdWVuY2UsIEVuY3J5cHRlZCBEYXRhLlxuXHRcdFx0Ly8gXG5cdFx0XHQvLyBPbmUtUGFzcyBTaWduZWQgTWVzc2FnZSA6LSBPbmUtUGFzcyBTaWduYXR1cmUgUGFja2V0LFxuXHRcdFx0Ly8gICAgICAgICAgICAgICAgICAgICAgICAgT3BlblBHUCBNZXNzYWdlLCBDb3JyZXNwb25kaW5nIFNpZ25hdHVyZSBQYWNrZXQuXG5cblx0XHRcdC8vIFNpZ25lZCBNZXNzYWdlICAgICAgIDotIFNpZ25hdHVyZSBQYWNrZXQsIE9wZW5QR1AgTWVzc2FnZSB8XG5cdFx0XHQvLyAgICAgICAgICAgICAgICAgICAgICAgICBPbmUtUGFzcyBTaWduZWQgTWVzc2FnZS5cblx0XHRcdGlmIChmaXJzdF9wYWNrZXQudGFnVHlwZSA9PSAgMSB8fFxuXHRcdFx0ICAgIChmaXJzdF9wYWNrZXQudGFnVHlwZSA9PSAyICYmIGZpcnN0X3BhY2tldC5zaWduYXR1cmVUeXBlIDwgMTYpIHx8XG5cdFx0XHQgICAgIGZpcnN0X3BhY2tldC50YWdUeXBlID09ICAzIHx8XG5cdFx0XHQgICAgIGZpcnN0X3BhY2tldC50YWdUeXBlID09ICA0IHx8XG5cdFx0XHRcdCBmaXJzdF9wYWNrZXQudGFnVHlwZSA9PSAgOCB8fFxuXHRcdFx0XHQgZmlyc3RfcGFja2V0LnRhZ1R5cGUgPT0gIDkgfHxcblx0XHRcdFx0IGZpcnN0X3BhY2tldC50YWdUeXBlID09IDEwIHx8XG5cdFx0XHRcdCBmaXJzdF9wYWNrZXQudGFnVHlwZSA9PSAxMSB8fFxuXHRcdFx0XHQgZmlyc3RfcGFja2V0LnRhZ1R5cGUgPT0gMTggfHxcblx0XHRcdFx0IGZpcnN0X3BhY2tldC50YWdUeXBlID09IDE5KSB7XG5cdFx0XHRcdG1lc3NhZ2VzW21lc3NhZ2VzLmxlbmd0aF0gPSBuZXcgb3BlbnBncF9tc2dfbWVzc2FnZSgpO1xuXHRcdFx0XHRtZXNzYWdlc1ttZXNzYWdlQ291bnRdLm1lc3NhZ2VQYWNrZXQgPSBmaXJzdF9wYWNrZXQ7XG5cdFx0XHRcdG1lc3NhZ2VzW21lc3NhZ2VDb3VudF0udHlwZSA9IGlucHV0LnR5cGU7XG5cdFx0XHRcdC8vIEVuY3J5cHRlZCBNZXNzYWdlXG5cdFx0XHRcdGlmIChmaXJzdF9wYWNrZXQudGFnVHlwZSA9PSA5IHx8XG5cdFx0XHRcdCAgICBmaXJzdF9wYWNrZXQudGFnVHlwZSA9PSAxIHx8XG5cdFx0XHRcdCAgICBmaXJzdF9wYWNrZXQudGFnVHlwZSA9PSAzIHx8XG5cdFx0XHRcdCAgICBmaXJzdF9wYWNrZXQudGFnVHlwZSA9PSAxOCkge1xuXHRcdFx0XHRcdGlmIChmaXJzdF9wYWNrZXQudGFnVHlwZSA9PSA5KSB7XG5cdFx0XHRcdFx0XHR1dGlsLnByaW50X2Vycm9yKFwidW5leHBlY3RlZCBvcGVucGdwIHBhY2tldFwiKTtcblx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRcdH0gZWxzZSBpZiAoZmlyc3RfcGFja2V0LnRhZ1R5cGUgPT0gMSkge1xuXHRcdFx0XHRcdFx0dXRpbC5wcmludF9kZWJ1ZyhcInNlc3Npb24ga2V5IGZvdW5kOlxcbiBcIitmaXJzdF9wYWNrZXQudG9TdHJpbmcoKSk7XG5cdFx0XHRcdFx0XHR2YXIgaXNzZXNzaW9ua2V5ID0gdHJ1ZTtcblx0XHRcdFx0XHRcdG1lc3NhZ2VzW21lc3NhZ2VDb3VudF0uc2Vzc2lvbktleXMgPSBuZXcgQXJyYXkoKTtcblx0XHRcdFx0XHRcdHZhciBzZXNzaW9uS2V5Q291bnQgPSAwO1xuXHRcdFx0XHRcdFx0d2hpbGUgKGlzc2Vzc2lvbmtleSkge1xuXHRcdFx0XHRcdFx0XHRtZXNzYWdlc1ttZXNzYWdlQ291bnRdLnNlc3Npb25LZXlzW3Nlc3Npb25LZXlDb3VudF0gPSBmaXJzdF9wYWNrZXQ7XG5cdFx0XHRcdFx0XHRcdG15cG9zICs9IGZpcnN0X3BhY2tldC5wYWNrZXRMZW5ndGggKyBmaXJzdF9wYWNrZXQuaGVhZGVyTGVuZ3RoO1xuXHRcdFx0XHRcdFx0XHRsIC09IChmaXJzdF9wYWNrZXQucGFja2V0TGVuZ3RoICsgZmlyc3RfcGFja2V0LmhlYWRlckxlbmd0aCk7XG5cdFx0XHRcdFx0XHRcdGZpcnN0X3BhY2tldCA9IG9wZW5wZ3BfcGFja2V0LnJlYWRfcGFja2V0KG1lc3NhZ2VTdHJpbmcsIG15cG9zLCBsKTtcblx0XHRcdFx0XHRcdFx0XG5cdFx0XHRcdFx0XHRcdGlmIChmaXJzdF9wYWNrZXQudGFnVHlwZSAhPSAxICYmIGZpcnN0X3BhY2tldC50YWdUeXBlICE9IDMpXG5cdFx0XHRcdFx0XHRcdFx0aXNzZXNzaW9ua2V5ID0gZmFsc2U7XG5cdFx0XHRcdFx0XHRcdHNlc3Npb25LZXlDb3VudCsrO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0aWYgKGZpcnN0X3BhY2tldC50YWdUeXBlID09IDE4IHx8IGZpcnN0X3BhY2tldC50YWdUeXBlID09IDkpIHtcblx0XHRcdFx0XHRcdFx0dXRpbC5wcmludF9kZWJ1ZyhcImVuY3J5cHRlZCBkYXRhIGZvdW5kOlxcbiBcIitmaXJzdF9wYWNrZXQudG9TdHJpbmcoKSk7XG5cdFx0XHRcdFx0XHRcdG1lc3NhZ2VzW21lc3NhZ2VDb3VudF0uZW5jcnlwdGVkRGF0YSA9IGZpcnN0X3BhY2tldDtcblx0XHRcdFx0XHRcdFx0bXlwb3MgKz0gZmlyc3RfcGFja2V0LnBhY2tldExlbmd0aCtmaXJzdF9wYWNrZXQuaGVhZGVyTGVuZ3RoO1xuXHRcdFx0XHRcdFx0XHRsIC09IChmaXJzdF9wYWNrZXQucGFja2V0TGVuZ3RoK2ZpcnN0X3BhY2tldC5oZWFkZXJMZW5ndGgpO1xuXHRcdFx0XHRcdFx0XHRtZXNzYWdlQ291bnQrKztcblx0XHRcdFx0XHRcdFx0XG5cdFx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0XHR1dGlsLnByaW50X2RlYnVnKFwic29tZXRoaW5nIGlzIHdyb25nOiBcIitmaXJzdF9wYWNrZXQudGFnVHlwZSk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcblx0XHRcdFx0XHR9IGVsc2UgaWYgKGZpcnN0X3BhY2tldC50YWdUeXBlID09IDE4KSB7XG5cdFx0XHRcdFx0XHR1dGlsLnByaW50X2RlYnVnKFwic3ltbWV0cmljIGVuY3J5cHRlZCBkYXRhXCIpO1xuXHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9IGVsc2UgXG5cdFx0XHRcdFx0aWYgKGZpcnN0X3BhY2tldC50YWdUeXBlID09IDIgJiYgZmlyc3RfcGFja2V0LnNpZ25hdHVyZVR5cGUgPCAzKSB7XG5cdFx0XHRcdFx0Ly8gU2lnbmVkIE1lc3NhZ2Vcblx0XHRcdFx0XHRcdG15cG9zICs9IGZpcnN0X3BhY2tldC5wYWNrZXRMZW5ndGggKyBmaXJzdF9wYWNrZXQuaGVhZGVyTGVuZ3RoO1xuXHRcdFx0XHRcdFx0bCAtPSAoZmlyc3RfcGFja2V0LnBhY2tldExlbmd0aCArIGZpcnN0X3BhY2tldC5oZWFkZXJMZW5ndGgpO1xuXHRcdFx0XHRcdFx0bWVzc2FnZXNbbWVzc2FnZUNvdW50XS50ZXh0ID0gc2lnbmF0dXJlVGV4dDtcblx0XHRcdFx0XHRcdG1lc3NhZ2VzW21lc3NhZ2VDb3VudF0uc2lnbmF0dXJlID0gZmlyc3RfcGFja2V0O1xuXHRcdFx0XHQgICAgICAgIG1lc3NhZ2VDb3VudCsrO1xuXHRcdFx0XHR9IGVsc2UgXG5cdFx0XHRcdFx0Ly8gU2lnbmVkIE1lc3NhZ2Vcblx0XHRcdFx0XHRpZiAoZmlyc3RfcGFja2V0LnRhZ1R5cGUgPT0gNCkge1xuXHRcdFx0XHRcdFx0Ly9UT0RPOiBJbXBsZW1lbnQgY2hlY2tcblx0XHRcdFx0XHRcdG15cG9zICs9IGZpcnN0X3BhY2tldC5wYWNrZXRMZW5ndGggKyBmaXJzdF9wYWNrZXQuaGVhZGVyTGVuZ3RoO1xuXHRcdFx0XHRcdFx0bCAtPSAoZmlyc3RfcGFja2V0LnBhY2tldExlbmd0aCArIGZpcnN0X3BhY2tldC5oZWFkZXJMZW5ndGgpO1xuXHRcdFx0XHR9IGVsc2UgXG5cdFx0XHRcdFx0aWYgKGZpcnN0X3BhY2tldC50YWdUeXBlID09IDgpIHtcblx0XHRcdFx0XHQvLyBDb21wcmVzc2VkIE1lc3NhZ2Vcblx0XHRcdFx0XHRcdG15cG9zICs9IGZpcnN0X3BhY2tldC5wYWNrZXRMZW5ndGggKyBmaXJzdF9wYWNrZXQuaGVhZGVyTGVuZ3RoO1xuXHRcdFx0XHRcdFx0bCAtPSAoZmlyc3RfcGFja2V0LnBhY2tldExlbmd0aCArIGZpcnN0X3BhY2tldC5oZWFkZXJMZW5ndGgpO1xuXHRcdFx0XHQgICAgICAgIHZhciBkZWNvbXByZXNzZWRUZXh0ID0gZmlyc3RfcGFja2V0LmRlY29tcHJlc3MoKTtcblx0XHRcdFx0ICAgICAgICBtZXNzYWdlcyA9IG1lc3NhZ2VzLmNvbmNhdChvcGVucGdwLnJlYWRfbWVzc2FnZXNfZGVhcm1vcmVkKHt0ZXh0OiBkZWNvbXByZXNzZWRUZXh0LCBvcGVucGdwOiBkZWNvbXByZXNzZWRUZXh0fSkpO1xuXHRcdFx0XHR9IGVsc2Vcblx0XHRcdFx0XHQvLyBNYXJrZXIgUGFja2V0IChPYnNvbGV0ZSBMaXRlcmFsIFBhY2tldCkgKFRhZyAxMClcblx0XHRcdFx0XHQvLyBcIlN1Y2ggYSBwYWNrZXQgTVVTVCBiZSBpZ25vcmVkIHdoZW4gcmVjZWl2ZWQuXCIgc2VlIGh0dHA6Ly90b29scy5pZXRmLm9yZy9odG1sL3JmYzQ4ODAjc2VjdGlvbi01Ljhcblx0XHRcdFx0XHRpZiAoZmlyc3RfcGFja2V0LnRhZ1R5cGUgPT0gMTApIHtcblx0XHRcdFx0XHRcdC8vIHJlc2V0IG1lc3NhZ2VzXG5cdFx0XHRcdFx0XHRtZXNzYWdlcy5sZW5ndGggPSAwO1xuXHRcdFx0XHRcdFx0Ly8gY29udGludWUgd2l0aCBuZXh0IHBhY2tldFxuXHRcdFx0XHRcdFx0bXlwb3MgKz0gZmlyc3RfcGFja2V0LnBhY2tldExlbmd0aCArIGZpcnN0X3BhY2tldC5oZWFkZXJMZW5ndGg7XG5cdFx0XHRcdFx0XHRsIC09IChmaXJzdF9wYWNrZXQucGFja2V0TGVuZ3RoICsgZmlyc3RfcGFja2V0LmhlYWRlckxlbmd0aCk7XG5cdFx0XHRcdH0gZWxzZSBcblx0XHRcdFx0XHRpZiAoZmlyc3RfcGFja2V0LnRhZ1R5cGUgPT0gMTEpIHtcblx0XHRcdFx0XHQvLyBMaXRlcmFsIE1lc3NhZ2UgLS0gd29yayBpcyBhbHJlYWR5IGRvbmUgaW4gcmVhZF9wYWNrZXRcblx0XHRcdFx0XHRteXBvcyArPSBmaXJzdF9wYWNrZXQucGFja2V0TGVuZ3RoICsgZmlyc3RfcGFja2V0LmhlYWRlckxlbmd0aDtcblx0XHRcdFx0XHRsIC09IChmaXJzdF9wYWNrZXQucGFja2V0TGVuZ3RoICsgZmlyc3RfcGFja2V0LmhlYWRlckxlbmd0aCk7XG5cdFx0XHRcdFx0c2lnbmF0dXJlVGV4dCA9IGZpcnN0X3BhY2tldC5kYXRhO1xuXHRcdFx0XHRcdG1lc3NhZ2VzW21lc3NhZ2VDb3VudF0uZGF0YSA9IGZpcnN0X3BhY2tldC5kYXRhO1xuXHRcdFx0XHRcdG1lc3NhZ2VDb3VudCsrO1xuXHRcdFx0XHR9IGVsc2UgXG5cdFx0XHRcdFx0aWYgKGZpcnN0X3BhY2tldC50YWdUeXBlID09IDE5KSB7XG5cdFx0XHRcdFx0Ly8gTW9kaWZpY2F0aW9uIERldGVjdCBDb2RlXG5cdFx0XHRcdFx0XHRteXBvcyArPSBmaXJzdF9wYWNrZXQucGFja2V0TGVuZ3RoICsgZmlyc3RfcGFja2V0LmhlYWRlckxlbmd0aDtcblx0XHRcdFx0XHRcdGwgLT0gKGZpcnN0X3BhY2tldC5wYWNrZXRMZW5ndGggKyBmaXJzdF9wYWNrZXQuaGVhZGVyTGVuZ3RoKTtcblx0XHRcdFx0fVxuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0dXRpbC5wcmludF9lcnJvcignbm8gbWVzc2FnZSBmb3VuZCEnKTtcblx0XHRcdFx0cmV0dXJuIG51bGw7XG5cdFx0XHR9XG5cdFx0fVxuXHRcdFxuXHRcdHJldHVybiBtZXNzYWdlcztcblx0fVxuXHRcblx0LyoqXG5cdCAqIGNyZWF0ZXMgYSBiaW5hcnkgc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIGFuIGVuY3J5cHRlZCBhbmQgc2lnbmVkIG1lc3NhZ2UuXG5cdCAqIFRoZSBtZXNzYWdlIHdpbGwgYmUgZW5jcnlwdGVkIHdpdGggdGhlIHB1YmxpYyBrZXlzIHNwZWNpZmllZCBhbmQgc2lnbmVkXG5cdCAqIHdpdGggdGhlIHNwZWNpZmllZCBwcml2YXRlIGtleS5cblx0ICogQHBhcmFtIHtPYmplY3R9IHByaXZhdGVrZXkge29iajogW29wZW5wZ3BfbXNnX3ByaXZhdGVrZXldfSBQcml2YXRlIGtleSBcblx0ICogdG8gYmUgdXNlZCB0byBzaWduIHRoZSBtZXNzYWdlXG5cdCAqIEBwYXJhbSB7T2JqZWN0W119IHB1YmxpY2tleXMgQW4gYXJyYWYgb2Yge29iajogW29wZW5wZ3BfbXNnX3B1YmxpY2tleV19XG5cdCAqIC0gcHVibGljIGtleXMgdG8gYmUgdXNlZCB0byBlbmNyeXB0IHRoZSBtZXNzYWdlIFxuXHQgKiBAcGFyYW0ge1N0cmluZ30gbWVzc2FnZXRleHQgbWVzc2FnZSB0ZXh0IHRvIGVuY3J5cHQgYW5kIHNpZ25cblx0ICogQHJldHVybiB7U3RyaW5nfSBhIGJpbmFyeSBzdHJpbmcgcmVwcmVzZW50YXRpb24gb2YgdGhlIG1lc3NhZ2Ugd2hpY2ggXG5cdCAqIGNhbiBiZSBPcGVuUEdQIGFybW9yZWRcblx0ICovXG5cdGZ1bmN0aW9uIHdyaXRlX3NpZ25lZF9hbmRfZW5jcnlwdGVkX21lc3NhZ2UocHJpdmF0ZWtleSwgcHVibGlja2V5cywgbWVzc2FnZXRleHQpIHtcblx0XHR2YXIgcmVzdWx0ID0gXCJcIjtcblx0XHR2YXIgbGl0ZXJhbCA9IG5ldyBvcGVucGdwX3BhY2tldF9saXRlcmFsZGF0YSgpLndyaXRlX3BhY2tldChtZXNzYWdldGV4dC5yZXBsYWNlKC9cXHJcXG4vZyxcIlxcblwiKS5yZXBsYWNlKC9cXG4vZyxcIlxcclxcblwiKSk7XG5cdFx0dXRpbC5wcmludF9kZWJ1Z19oZXhzdHJfZHVtcChcImxpdGVyYWxfcGFja2V0OiB8XCIrbGl0ZXJhbCtcInxcXG5cIixsaXRlcmFsKTtcblx0XHRmb3IgKHZhciBpID0gMDsgaSA8IHB1YmxpY2tleXMubGVuZ3RoOyBpKyspIHtcblx0XHRcdHZhciBvbmVwYXNzc2lnbmF0dXJlID0gbmV3IG9wZW5wZ3BfcGFja2V0X29uZXBhc3NzaWduYXR1cmUoKTtcblx0XHRcdHZhciBvbmVwYXNzc2lnc3RyID0gXCJcIjtcblx0XHRcdGlmIChpID09IDApXG5cdFx0XHRcdG9uZXBhc3NzaWdzdHIgPSBvbmVwYXNzc2lnbmF0dXJlLndyaXRlX3BhY2tldCgxLCBvcGVucGdwLmNvbmZpZy5jb25maWcucHJlZmVyX2hhc2hfYWxnb3JpdGhtLCAgcHJpdmF0ZWtleSwgZmFsc2UpO1xuXHRcdFx0ZWxzZVxuXHRcdFx0XHRvbmVwYXNzc2lnc3RyID0gb25lcGFzc3NpZ25hdHVyZS53cml0ZV9wYWNrZXQoMSwgb3BlbnBncC5jb25maWcuY29uZmlnLnByZWZlcl9oYXNoX2FsZ29yaXRobSwgIHByaXZhdGVrZXksIGZhbHNlKTtcblx0XHRcdHV0aWwucHJpbnRfZGVidWdfaGV4c3RyX2R1bXAoXCJvbmVwYXNzc2lnc3RyOiB8XCIrb25lcGFzc3NpZ3N0citcInxcXG5cIixvbmVwYXNzc2lnc3RyKTtcblx0XHRcdHZhciBkYXRhc2lnbmF0dXJlID0gbmV3IG9wZW5wZ3BfcGFja2V0X3NpZ25hdHVyZSgpLndyaXRlX21lc3NhZ2Vfc2lnbmF0dXJlKDEsIG1lc3NhZ2V0ZXh0LnJlcGxhY2UoL1xcclxcbi9nLFwiXFxuXCIpLnJlcGxhY2UoL1xcbi9nLFwiXFxyXFxuXCIpLCBwcml2YXRla2V5KTtcblx0XHRcdHV0aWwucHJpbnRfZGVidWdfaGV4c3RyX2R1bXAoXCJkYXRhc2lnbmF0dXJlOiB8XCIrZGF0YXNpZ25hdHVyZS5vcGVucGdwK1wifFxcblwiLGRhdGFzaWduYXR1cmUub3BlbnBncCk7XG5cdFx0XHRpZiAoaSA9PSAwKSB7XG5cdFx0XHRcdHJlc3VsdCA9IG9uZXBhc3NzaWdzdHIrbGl0ZXJhbCtkYXRhc2lnbmF0dXJlLm9wZW5wZ3A7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRyZXN1bHQgPSBvbmVwYXNzc2lnc3RyK3Jlc3VsdCtkYXRhc2lnbmF0dXJlLm9wZW5wZ3A7XG5cdFx0XHR9XG5cdFx0fVxuXHRcdFxuXHRcdHV0aWwucHJpbnRfZGVidWdfaGV4c3RyX2R1bXAoXCJzaWduZWQgcGFja2V0OiB8XCIrcmVzdWx0K1wifFxcblwiLHJlc3VsdCk7XG5cdFx0Ly8gc2lnbmF0dXJlcyBkb25lLi4gbm93IGVuY3J5cHRpb25cblx0XHR2YXIgc2Vzc2lvbmtleSA9IG9wZW5wZ3BfY3J5cHRvX2dlbmVyYXRlU2Vzc2lvbktleShvcGVucGdwLmNvbmZpZy5jb25maWcuZW5jcnlwdGlvbl9jaXBoZXIpOyBcblx0XHR2YXIgcmVzdWx0MiA9IFwiXCI7XG5cdFx0XG5cdFx0Ly8gY3JlYXRpbmcgc2Vzc2lvbiBrZXlzIGZvciBlYWNoIHJlY2lwaWVudFxuXHRcdGZvciAodmFyIGkgPSAwOyBpIDwgcHVibGlja2V5cy5sZW5ndGg7IGkrKykge1xuXHRcdFx0dmFyIHBrZXkgPSBwdWJsaWNrZXlzW2ldLmdldEVuY3J5cHRpb25LZXkoKTtcblx0XHRcdGlmIChwa2V5ID09IG51bGwpIHtcblx0XHRcdFx0dXRpbC5wcmludF9lcnJvcihcIm5vIGVuY3J5cHRpb24ga2V5IGZvdW5kISBLZXkgaXMgZm9yIHNpZ25pbmcgb25seS5cIik7XG5cdFx0XHRcdHJldHVybiBudWxsO1xuXHRcdFx0fVxuXHRcdFx0cmVzdWx0MiArPSBuZXcgb3BlbnBncF9wYWNrZXRfZW5jcnlwdGVkc2Vzc2lvbmtleSgpLlxuXHRcdFx0XHRcdHdyaXRlX3B1Yl9rZXlfcGFja2V0KFxuXHRcdFx0XHRcdFx0cGtleS5nZXRLZXlJZCgpLFxuXHRcdFx0XHRcdFx0cGtleS5NUElzLFxuXHRcdFx0XHRcdFx0cGtleS5wdWJsaWNLZXlBbGdvcml0aG0sXG5cdFx0XHRcdFx0XHRvcGVucGdwLmNvbmZpZy5jb25maWcuZW5jcnlwdGlvbl9jaXBoZXIsXG5cdFx0XHRcdFx0XHRzZXNzaW9ua2V5KTtcblx0XHR9XG5cdFx0aWYgKG9wZW5wZ3AuY29uZmlnLmNvbmZpZy5pbnRlZ3JpdHlfcHJvdGVjdCkge1xuXHRcdFx0cmVzdWx0MiArPSBuZXcgb3BlbnBncF9wYWNrZXRfZW5jcnlwdGVkaW50ZWdyaXR5cHJvdGVjdGVkZGF0YSgpLndyaXRlX3BhY2tldChvcGVucGdwLmNvbmZpZy5jb25maWcuZW5jcnlwdGlvbl9jaXBoZXIsIHNlc3Npb25rZXksIHJlc3VsdCk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHJlc3VsdDIgKz0gbmV3IG9wZW5wZ3BfcGFja2V0X2VuY3J5cHRlZGRhdGEoKS53cml0ZV9wYWNrZXQob3BlbnBncC5jb25maWcuY29uZmlnLmVuY3J5cHRpb25fY2lwaGVyLCBzZXNzaW9ua2V5LCByZXN1bHQpO1xuXHRcdH1cblx0XHRyZXR1cm4gb3BlbnBncF9lbmNvZGluZ19hcm1vcigzLHJlc3VsdDIsbnVsbCxudWxsKTtcblx0fVxuXHQvKipcblx0ICogY3JlYXRlcyBhIGJpbmFyeSBzdHJpbmcgcmVwcmVzZW50YXRpb24gb2YgYW4gZW5jcnlwdGVkIG1lc3NhZ2UuXG5cdCAqIFRoZSBtZXNzYWdlIHdpbGwgYmUgZW5jcnlwdGVkIHdpdGggdGhlIHB1YmxpYyBrZXlzIHNwZWNpZmllZCBcblx0ICogQHBhcmFtIHtPYmplY3RbXX0gcHVibGlja2V5cyBBbiBhcnJheSBvZiB7b2JqOiBbb3BlbnBncF9tc2dfcHVibGlja2V5XX1cblx0ICogLXB1YmxpYyBrZXlzIHRvIGJlIHVzZWQgdG8gZW5jcnlwdCB0aGUgbWVzc2FnZSBcblx0ICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2V0ZXh0IG1lc3NhZ2UgdGV4dCB0byBlbmNyeXB0XG5cdCAqIEByZXR1cm4ge1N0cmluZ30gYSBiaW5hcnkgc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBtZXNzYWdlXG5cdCAqIHdoaWNoIGNhbiBiZSBPcGVuUEdQIGFybW9yZWRcblx0ICovXG5cdGZ1bmN0aW9uIHdyaXRlX2VuY3J5cHRlZF9tZXNzYWdlKHB1YmxpY2tleXMsIG1lc3NhZ2V0ZXh0KSB7XG5cdFx0dmFyIHJlc3VsdCA9IFwiXCI7XG5cdFx0dmFyIGxpdGVyYWwgPSBuZXcgb3BlbnBncF9wYWNrZXRfbGl0ZXJhbGRhdGEoKS53cml0ZV9wYWNrZXQobWVzc2FnZXRleHQucmVwbGFjZSgvXFxyXFxuL2csXCJcXG5cIikucmVwbGFjZSgvXFxuL2csXCJcXHJcXG5cIikpO1xuXHRcdHV0aWwucHJpbnRfZGVidWdfaGV4c3RyX2R1bXAoXCJsaXRlcmFsX3BhY2tldDogfFwiK2xpdGVyYWwrXCJ8XFxuXCIsbGl0ZXJhbCk7XG5cdFx0cmVzdWx0ID0gbGl0ZXJhbDtcblx0XHRcblx0XHQvLyBzaWduYXR1cmVzIGRvbmUuLiBub3cgZW5jcnlwdGlvblxuXHRcdHZhciBzZXNzaW9ua2V5ID0gb3BlbnBncF9jcnlwdG9fZ2VuZXJhdGVTZXNzaW9uS2V5KG9wZW5wZ3AuY29uZmlnLmNvbmZpZy5lbmNyeXB0aW9uX2NpcGhlcik7IFxuXHRcdHZhciByZXN1bHQyID0gXCJcIjtcblx0XHRcblx0XHQvLyBjcmVhdGluZyBzZXNzaW9uIGtleXMgZm9yIGVhY2ggcmVjaXBpZW50XG5cdFx0Zm9yICh2YXIgaSA9IDA7IGkgPCBwdWJsaWNrZXlzLmxlbmd0aDsgaSsrKSB7XG5cdFx0XHR2YXIgcGtleSA9IHB1YmxpY2tleXNbaV0uZ2V0RW5jcnlwdGlvbktleSgpO1xuXHRcdFx0aWYgKHBrZXkgPT0gbnVsbCkge1xuXHRcdFx0XHR1dGlsLnByaW50X2Vycm9yKFwibm8gZW5jcnlwdGlvbiBrZXkgZm91bmQhIEtleSBpcyBmb3Igc2lnbmluZyBvbmx5LlwiKTtcblx0XHRcdFx0cmV0dXJuIG51bGw7XG5cdFx0XHR9XG5cdFx0XHRyZXN1bHQyICs9IG5ldyBvcGVucGdwX3BhY2tldF9lbmNyeXB0ZWRzZXNzaW9ua2V5KCkuXG5cdFx0XHRcdFx0d3JpdGVfcHViX2tleV9wYWNrZXQoXG5cdFx0XHRcdFx0XHRwa2V5LmdldEtleUlkKCksXG5cdFx0XHRcdFx0XHRwa2V5Lk1QSXMsXG5cdFx0XHRcdFx0XHRwa2V5LnB1YmxpY0tleUFsZ29yaXRobSxcblx0XHRcdFx0XHRcdG9wZW5wZ3AuY29uZmlnLmNvbmZpZy5lbmNyeXB0aW9uX2NpcGhlcixcblx0XHRcdFx0XHRcdHNlc3Npb25rZXkpO1xuXHRcdH1cblx0XHRpZiAob3BlbnBncC5jb25maWcuY29uZmlnLmludGVncml0eV9wcm90ZWN0KSB7XG5cdFx0XHRyZXN1bHQyICs9IG5ldyBvcGVucGdwX3BhY2tldF9lbmNyeXB0ZWRpbnRlZ3JpdHlwcm90ZWN0ZWRkYXRhKCkud3JpdGVfcGFja2V0KG9wZW5wZ3AuY29uZmlnLmNvbmZpZy5lbmNyeXB0aW9uX2NpcGhlciwgc2Vzc2lvbmtleSwgcmVzdWx0KTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0cmVzdWx0MiArPSBuZXcgb3BlbnBncF9wYWNrZXRfZW5jcnlwdGVkZGF0YSgpLndyaXRlX3BhY2tldChvcGVucGdwLmNvbmZpZy5jb25maWcuZW5jcnlwdGlvbl9jaXBoZXIsIHNlc3Npb25rZXksIHJlc3VsdCk7XG5cdFx0fVxuXHRcdHJldHVybiBvcGVucGdwX2VuY29kaW5nX2FybW9yKDMscmVzdWx0MixudWxsLG51bGwpO1xuXHR9XG5cdFxuXHQvKipcblx0ICogY3JlYXRlcyBhIGJpbmFyeSBzdHJpbmcgcmVwcmVzZW50YXRpb24gYSBzaWduZWQgbWVzc2FnZS5cblx0ICogVGhlIG1lc3NhZ2Ugd2lsbCBiZSBzaWduZWQgd2l0aCB0aGUgc3BlY2lmaWVkIHByaXZhdGUga2V5LlxuXHQgKiBAcGFyYW0ge09iamVjdH0gcHJpdmF0ZWtleSB7b2JqOiBbb3BlbnBncF9tc2dfcHJpdmF0ZWtleV19XG5cdCAqIC0gdGhlIHByaXZhdGUga2V5IHRvIGJlIHVzZWQgdG8gc2lnbiB0aGUgbWVzc2FnZSBcblx0ICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2V0ZXh0IG1lc3NhZ2UgdGV4dCB0byBzaWduXG5cdCAqIEByZXR1cm4ge09iamVjdH0ge09iamVjdDogdGV4dCBbU3RyaW5nXX0sIG9wZW5wZ3A6IHtTdHJpbmd9IGEgYmluYXJ5XG5cdCAqICBzdHJpbmcgcmVwcmVzZW50YXRpb24gb2YgdGhlIG1lc3NhZ2Ugd2hpY2ggY2FuIGJlIE9wZW5QR1Bcblx0ICogICBhcm1vcmVkKG9wZW5wZ3ApIGFuZCBhIHRleHQgcmVwcmVzZW50YXRpb24gb2YgdGhlIG1lc3NhZ2UgKHRleHQpLiBcblx0ICogVGhpcyBjYW4gYmUgZGlyZWN0bHkgdXNlZCB0byBPcGVuUEdQIGFybW9yIHRoZSBtZXNzYWdlXG5cdCAqL1xuXHRmdW5jdGlvbiB3cml0ZV9zaWduZWRfbWVzc2FnZShwcml2YXRla2V5LCBtZXNzYWdldGV4dCkge1xuXHRcdHZhciBzaWcgPSBuZXcgb3BlbnBncF9wYWNrZXRfc2lnbmF0dXJlKCkud3JpdGVfbWVzc2FnZV9zaWduYXR1cmUoMSwgbWVzc2FnZXRleHQucmVwbGFjZSgvXFxyXFxuL2csXCJcXG5cIikucmVwbGFjZSgvXFxuLyxcIlxcclxcblwiKSwgcHJpdmF0ZWtleSk7XG5cdFx0dmFyIHJlc3VsdCA9IHt0ZXh0OiBtZXNzYWdldGV4dC5yZXBsYWNlKC9cXHJcXG4vZyxcIlxcblwiKS5yZXBsYWNlKC9cXG4vLFwiXFxyXFxuXCIpLCBvcGVucGdwOiBzaWcub3BlbnBncCwgaGFzaDogc2lnLmhhc2h9O1xuXHRcdHJldHVybiBvcGVucGdwX2VuY29kaW5nX2FybW9yKDIscmVzdWx0LCBudWxsLCBudWxsKVxuXHR9XG5cdFxuXHQvKipcblx0ICogZ2VuZXJhdGVzIGEgbmV3IGtleSBwYWlyIGZvciBvcGVucGdwLiBCZXRhIHN0YWdlLiBDdXJyZW50bHkgb25seSBcblx0ICogc3VwcG9ydHMgUlNBIGtleXMsIGFuZCBubyBzdWJrZXlzLlxuXHQgKiBAcGFyYW0ge0ludGVnZXJ9IGtleVR5cGUgdG8gaW5kaWNhdGUgd2hhdCB0eXBlIG9mIGtleSB0byBtYWtlLiBcblx0ICogUlNBIGlzIDEuIEZvbGxvd3MgYWxnb3JpdGhtcyBvdXRsaW5lZCBpbiBPcGVuUEdQLlxuXHQgKiBAcGFyYW0ge0ludGVnZXJ9IG51bUJpdHMgbnVtYmVyIG9mIGJpdHMgZm9yIHRoZSBrZXkgY3JlYXRpb24uIChzaG91bGQgXG5cdCAqIGJlIDEwMjQrLCBnZW5lcmFsbHkpXG5cdCAqIEBwYXJhbSB7U3RyaW5nfSB1c2VySWQgYXNzdW1lcyBhbHJlYWR5IGluIGZvcm0gb2YgXCJVc2VyIE5hbWUgXG5cdCAqIDx1c2VybmFtZUBlbWFpbC5jb20+XCJcblx0ICogQHBhcmFtIHtTdHJpbmd9IHBhc3NwaHJhc2UgVGhlIHBhc3NwaHJhc2UgdXNlZCB0byBlbmNyeXB0IHRoZSByZXN1bHRpbmcgcHJpdmF0ZSBrZXlcblx0ICogQHJldHVybiB7T2JqZWN0fSB7cHJpdmF0ZUtleTogW29wZW5wZ3BfbXNnX3ByaXZhdGVrZXldLCBcblx0ICogcHJpdmF0ZUtleUFybW9yZWQ6IFtzdHJpbmddLCBwdWJsaWNLZXlBcm1vcmVkOiBbc3RyaW5nXX1cblx0ICovXG5cdGZ1bmN0aW9uIGdlbmVyYXRlX2tleV9wYWlyKGtleVR5cGUsIG51bUJpdHMsIHVzZXJJZCwgcGFzc3BocmFzZSl7XG5cdFx0dmFyIHVzZXJJZFBhY2tldCA9IG5ldyBvcGVucGdwX3BhY2tldF91c2VyaWQoKTtcblx0XHR2YXIgdXNlcklkU3RyaW5nID0gdXNlcklkUGFja2V0LndyaXRlX3BhY2tldCh1c2VySWQpO1xuXHRcdFxuXHRcdHZhciBrZXlQYWlyID0gb3BlbnBncF9jcnlwdG9fZ2VuZXJhdGVLZXlQYWlyKGtleVR5cGUsbnVtQml0cywgcGFzc3BocmFzZSwgb3BlbnBncC5jb25maWcuY29uZmlnLnByZWZlcl9oYXNoX2FsZ29yaXRobSwgMyk7XG5cdFx0dmFyIHByaXZLZXlTdHJpbmcgPSBrZXlQYWlyLnByaXZhdGVLZXk7XG5cdFx0dmFyIHByaXZLZXlQYWNrZXQgPSBuZXcgb3BlbnBncF9wYWNrZXRfa2V5bWF0ZXJpYWwoKS5yZWFkX3ByaXZfa2V5KHByaXZLZXlTdHJpbmcuc3RyaW5nLDMscHJpdktleVN0cmluZy5zdHJpbmcubGVuZ3RoKTtcblx0XHRpZighcHJpdktleVBhY2tldC5kZWNyeXB0U2VjcmV0TVBJcyhwYXNzcGhyYXNlKSlcblx0XHQgICAgdXRpbC5wcmludF9lcnJvcignSXNzdWUgY3JlYXRpbmcga2V5LiBVbmFibGUgdG8gcmVhZCByZXN1bHRpbmcgcHJpdmF0ZSBrZXknKTtcblx0XHR2YXIgcHJpdktleSA9IG5ldyBvcGVucGdwX21zZ19wcml2YXRla2V5KCk7XG5cdFx0cHJpdktleS5wcml2YXRlS2V5UGFja2V0ID0gcHJpdktleVBhY2tldDtcblx0XHRwcml2S2V5LmdldFByZWZlcnJlZFNpZ25hdHVyZUhhc2hBbGdvcml0aG0gPSBmdW5jdGlvbigpe3JldHVybiBvcGVucGdwLmNvbmZpZy5jb25maWcucHJlZmVyX2hhc2hfYWxnb3JpdGhtfTsvL25lZWQgdG8gb3ZlcnJpZGUgdGhpcyB0byBzb2x2ZSBjYXRjaCAyMiB0byBnZW5lcmF0ZSBzaWduYXR1cmUuIDggaXMgdmFsdWUgZm9yIFNIQTI1NlxuXHRcdFxuXHRcdHZhciBwdWJsaWNLZXlTdHJpbmcgPSBwcml2S2V5LnByaXZhdGVLZXlQYWNrZXQucHVibGljS2V5LmRhdGE7XG5cdFx0dmFyIGhhc2hEYXRhID0gU3RyaW5nLmZyb21DaGFyQ29kZSgweDk5KSsgU3RyaW5nLmZyb21DaGFyQ29kZSgoKHB1YmxpY0tleVN0cmluZy5sZW5ndGgpID4+IDgpICYgMHhGRikgXG5cdFx0XHQrIFN0cmluZy5mcm9tQ2hhckNvZGUoKHB1YmxpY0tleVN0cmluZy5sZW5ndGgpICYgMHhGRikgK3B1YmxpY0tleVN0cmluZytTdHJpbmcuZnJvbUNoYXJDb2RlKDB4QjQpICtcblx0XHRcdFN0cmluZy5mcm9tQ2hhckNvZGUoKHVzZXJJZC5sZW5ndGgpID4+IDI0KSArU3RyaW5nLmZyb21DaGFyQ29kZSgoKHVzZXJJZC5sZW5ndGgpID4+IDE2KSAmIDB4RkYpIFxuXHRcdFx0KyBTdHJpbmcuZnJvbUNoYXJDb2RlKCgodXNlcklkLmxlbmd0aCkgPj4gOCkgJiAweEZGKSArIFN0cmluZy5mcm9tQ2hhckNvZGUoKHVzZXJJZC5sZW5ndGgpICYgMHhGRikgKyB1c2VySWRcblx0XHR2YXIgc2lnbmF0dXJlID0gbmV3IG9wZW5wZ3BfcGFja2V0X3NpZ25hdHVyZSgpO1xuXHRcdHNpZ25hdHVyZSA9IHNpZ25hdHVyZS53cml0ZV9tZXNzYWdlX3NpZ25hdHVyZSgxNixoYXNoRGF0YSwgcHJpdktleSk7XG5cdFx0dmFyIHB1YmxpY0FybW9yZWQgPSBvcGVucGdwX2VuY29kaW5nX2FybW9yKDQsIGtleVBhaXIucHVibGljS2V5LnN0cmluZyArIHVzZXJJZFN0cmluZyArIHNpZ25hdHVyZS5vcGVucGdwICk7XG5cblx0XHR2YXIgcHJpdkFybW9yZWQgPSBvcGVucGdwX2VuY29kaW5nX2FybW9yKDUscHJpdktleVN0cmluZy5zdHJpbmcrdXNlcklkU3RyaW5nK3NpZ25hdHVyZS5vcGVucGdwKTtcblx0XHRcblx0XHRyZXR1cm4ge3ByaXZhdGVLZXkgOiBwcml2S2V5LCBwcml2YXRlS2V5QXJtb3JlZDogcHJpdkFybW9yZWQsIHB1YmxpY0tleUFybW9yZWQ6IHB1YmxpY0FybW9yZWR9XG5cdH1cblx0XG5cdHRoaXMuZ2VuZXJhdGVfa2V5X3BhaXIgPSBnZW5lcmF0ZV9rZXlfcGFpcjtcblx0dGhpcy53cml0ZV9zaWduZWRfbWVzc2FnZSA9IHdyaXRlX3NpZ25lZF9tZXNzYWdlOyBcblx0dGhpcy53cml0ZV9zaWduZWRfYW5kX2VuY3J5cHRlZF9tZXNzYWdlID0gd3JpdGVfc2lnbmVkX2FuZF9lbmNyeXB0ZWRfbWVzc2FnZTtcblx0dGhpcy53cml0ZV9lbmNyeXB0ZWRfbWVzc2FnZSA9IHdyaXRlX2VuY3J5cHRlZF9tZXNzYWdlO1xuXHR0aGlzLnJlYWRfbWVzc2FnZSA9IHJlYWRfbWVzc2FnZTtcblx0dGhpcy5yZWFkX21lc3NhZ2VzX2RlYXJtb3JlZCA9IHJlYWRfbWVzc2FnZXNfZGVhcm1vcmVkO1xuXHR0aGlzLnJlYWRfcHVibGljS2V5ID0gcmVhZF9wdWJsaWNLZXk7XG5cdHRoaXMucmVhZF9wcml2YXRlS2V5ID0gcmVhZF9wcml2YXRlS2V5O1xuXHR0aGlzLmluaXQgPSBpbml0O1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IG5ldyBfb3BlbnBncCgpO1xuXG4iLCIvLyBHUEc0QnJvd3NlcnMgLSBBbiBPcGVuUEdQIGltcGxlbWVudGF0aW9uIGluIGphdmFzY3JpcHRcbi8vIENvcHlyaWdodCAoQykgMjAxMSBSZWN1cml0eSBMYWJzIEdtYkhcbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vclxuLy8gbW9kaWZ5IGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyXG4vLyB2ZXJzaW9uIDIuMSBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4vLyBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuLy8gTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZSBHTlVcbi8vIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG4vLyBcbi8vIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYWxvbmcgd2l0aCB0aGlzIGxpYnJhcnk7IGlmIG5vdCwgd3JpdGUgdG8gdGhlIEZyZWUgU29mdHdhcmVcbi8vIEZvdW5kYXRpb24sIEluYy4sIDUxIEZyYW5rbGluIFN0cmVldCwgRmlmdGggRmxvb3IsIEJvc3RvbiwgTUEgIDAyMTEwLTEzMDEgIFVTQVxuXG4vKipcbiAqIEBjbGFzc1xuICogQGNsYXNzZGVzYyBJbXBsZW1lbnRhdGlvbiBvZiB0eXBlIGtleSBpZCAoUkZDNDg4MCAzLjMpXG4gKiAgQSBLZXkgSUQgaXMgYW4gZWlnaHQtb2N0ZXQgc2NhbGFyIHRoYXQgaWRlbnRpZmllcyBhIGtleS5cbiAgIEltcGxlbWVudGF0aW9ucyBTSE9VTEQgTk9UIGFzc3VtZSB0aGF0IEtleSBJRHMgYXJlIHVuaXF1ZS4gIFRoZVxuICAgc2VjdGlvbiBcIkVuaGFuY2VkIEtleSBGb3JtYXRzXCIgYmVsb3cgZGVzY3JpYmVzIGhvdyBLZXkgSURzIGFyZVxuICAgZm9ybWVkLlxuICovXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIGtleWlkKCkge1xuXHR2YXIgYnl0ZXMgPSAnJztcblxuXHRmb3IodmFyIGkgPSAwOyBpIDwgODsgaSsrKVxuXHRcdGJ5dGVzICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoMCk7XG5cdC8qKlxuXHQgKiBQYXJzaW5nIG1ldGhvZCBmb3IgYSBrZXkgaWRcblx0ICogQHBhcmFtIHtTdHJpbmd9IGlucHV0IElucHV0IHRvIHJlYWQgdGhlIGtleSBpZCBmcm9tIFxuXHQgKiBAcGFyYW0ge2ludGVnZXJ9IHBvc2l0aW9uIFBvc2l0aW9uIHdoZXJlIHRvIHN0YXJ0IHJlYWRpbmcgdGhlIGtleSBcblx0ICogaWQgZnJvbSBpbnB1dFxuXHQgKiBAcmV0dXJuIHtvcGVucGdwX3R5cGVfa2V5aWR9IFRoaXMgb2JqZWN0XG5cdCAqL1xuXHR0aGlzLnJlYWQgPSBmdW5jdGlvbihieXRlcykge1xuXHRcdHRoaXMuYnl0ZXMgPSBieXRlcy5zdWJzdHIoMCwgOCk7XG5cdH1cblxuXHR0aGlzLndyaXRlID0gZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIHRoaXMuYnl0ZXM7XG5cdH1cbn07XG4iLCJcblxuXG52YXIgY3J5cHRvID0gcmVxdWlyZSgnLi9jcnlwdG8nKTtcblxubW9kdWxlLmV4cG9ydHMgPSByZXF1aXJlKCcuL29wZW5wZ3AuanMnKTtcbm1vZHVsZS5leHBvcnRzLnV0aWwgPSByZXF1aXJlKCcuL3V0aWwnKTtcbm1vZHVsZS5leHBvcnRzLnBhY2tldCA9IHJlcXVpcmUoJy4vcGFja2V0Jyk7XG5tb2R1bGUuZXhwb3J0cy5tcGkgPSByZXF1aXJlKCcuL3R5cGUvbXBpLmpzJyk7XG5tb2R1bGUuZXhwb3J0cy5zMmsgPSByZXF1aXJlKCcuL3R5cGUvczJrLmpzJyk7XG5tb2R1bGUuZXhwb3J0cy5rZXlpZCA9IHJlcXVpcmUoJy4vdHlwZS9rZXlpZC5qcycpO1xubW9kdWxlLmV4cG9ydHMuYXJtb3IgPSByZXF1aXJlKCcuL2VuY29kaW5nL2FybW9yLmpzJyk7XG5cbmZvcih2YXIgaSBpbiBjcnlwdG8pXG5cdG1vZHVsZS5leHBvcnRzW2ldID0gY3J5cHRvW2ldO1xuXG4iLCIvLyBHUEc0QnJvd3NlcnMgLSBBbiBPcGVuUEdQIGltcGxlbWVudGF0aW9uIGluIGphdmFzY3JpcHRcbi8vIENvcHlyaWdodCAoQykgMjAxMSBSZWN1cml0eSBMYWJzIEdtYkhcbi8vXG4vLyBUaGlzIGxpYnJhcnkgaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yXG4vLyBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uOyBlaXRoZXJcbi8vIHZlcnNpb24gMi4xIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuLy9cbi8vIFRoaXMgbGlicmFyeSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuLy8gYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2Zcbi8vIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUgR05VXG4vLyBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuLy9cbi8vIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYWxvbmcgd2l0aCB0aGlzIGxpYnJhcnk7IGlmIG5vdCwgd3JpdGUgdG8gdGhlIEZyZWUgU29mdHdhcmVcbi8vIEZvdW5kYXRpb24sIEluYy4sIDUxIEZyYW5rbGluIFN0cmVldCwgRmlmdGggRmxvb3IsIEJvc3RvbiwgTUEgIDAyMTEwLTEzMDEgIFVTQVxuXG52YXIgYmFzZTY0ID0gcmVxdWlyZSgnLi9iYXNlNjQuanMnKTtcblxuXG5cbi8qKlxuICogRmluZHMgb3V0IHdoaWNoIEFzY2lpIEFybW9yaW5nIHR5cGUgaXMgdXNlZC4gVGhpcyBpcyBhbiBpbnRlcm5hbCBmdW5jdGlvblxuICogQHBhcmFtIHtTdHJpbmd9IHRleHQgW1N0cmluZ10gYXNjaWkgYXJtb3JlZCB0ZXh0XG4gKiBAcmV0dXJucyB7SW50ZWdlcn0gMCA9IE1FU1NBR0UgUEFSVCBuIG9mIG1cbiAqICAgICAgICAgMSA9IE1FU1NBR0UgUEFSVCBuXG4gKiAgICAgICAgIDIgPSBTSUdORUQgTUVTU0FHRVxuICogICAgICAgICAzID0gUEdQIE1FU1NBR0VcbiAqICAgICAgICAgNCA9IFBVQkxJQyBLRVkgQkxPQ0tcbiAqICAgICAgICAgNSA9IFBSSVZBVEUgS0VZIEJMT0NLXG4gKiAgICAgICAgIG51bGwgPSB1bmtub3duXG4gKi9cbmZ1bmN0aW9uIGdldF90eXBlKHRleHQpIHtcblx0dmFyIHNwbGl0dGVkdGV4dCA9IHRleHQuc3BsaXQoJy0tLS0tJyk7XG5cdC8vIEJFR0lOIFBHUCBNRVNTQUdFLCBQQVJUIFgvWVxuXHQvLyBVc2VkIGZvciBtdWx0aS1wYXJ0IG1lc3NhZ2VzLCB3aGVyZSB0aGUgYXJtb3IgaXMgc3BsaXQgYW1vbmdzdCBZXG5cdC8vIHBhcnRzLCBhbmQgdGhpcyBpcyB0aGUgWHRoIHBhcnQgb3V0IG9mIFkuXG5cdGlmIChzcGxpdHRlZHRleHRbMV0ubWF0Y2goL0JFR0lOIFBHUCBNRVNTQUdFLCBQQVJUIFxcZCtcXC9cXGQrLykpIHtcblx0XHRyZXR1cm4gMDtcblx0fSBlbHNlXG5cdFx0Ly8gQkVHSU4gUEdQIE1FU1NBR0UsIFBBUlQgWFxuXHRcdC8vIFVzZWQgZm9yIG11bHRpLXBhcnQgbWVzc2FnZXMsIHdoZXJlIHRoaXMgaXMgdGhlIFh0aCBwYXJ0IG9mIGFuXG5cdFx0Ly8gdW5zcGVjaWZpZWQgbnVtYmVyIG9mIHBhcnRzLiBSZXF1aXJlcyB0aGUgTUVTU0FHRS1JRCBBcm1vclxuXHRcdC8vIEhlYWRlciB0byBiZSB1c2VkLlxuXHRpZiAoc3BsaXR0ZWR0ZXh0WzFdLm1hdGNoKC9CRUdJTiBQR1AgTUVTU0FHRSwgUEFSVCBcXGQrLykpIHtcblx0XHRyZXR1cm4gMTtcblxuXHR9IGVsc2Vcblx0XHQvLyBCRUdJTiBQR1AgU0lHTkFUVVJFXG5cdFx0Ly8gVXNlZCBmb3IgZGV0YWNoZWQgc2lnbmF0dXJlcywgT3BlblBHUC9NSU1FIHNpZ25hdHVyZXMsIGFuZFxuXHRcdC8vIGNsZWFydGV4dCBzaWduYXR1cmVzLiBOb3RlIHRoYXQgUEdQIDIueCB1c2VzIEJFR0lOIFBHUCBNRVNTQUdFXG5cdFx0Ly8gZm9yIGRldGFjaGVkIHNpZ25hdHVyZXMuXG5cdGlmIChzcGxpdHRlZHRleHRbMV0ubWF0Y2goL0JFR0lOIFBHUCBTSUdORUQgTUVTU0FHRS8pKSB7XG5cdFx0cmV0dXJuIDI7XG5cblx0fSBlbHNlXG4gIFx0ICAgIC8vIEJFR0lOIFBHUCBNRVNTQUdFXG5cdCAgICAvLyBVc2VkIGZvciBzaWduZWQsIGVuY3J5cHRlZCwgb3IgY29tcHJlc3NlZCBmaWxlcy5cblx0aWYgKHNwbGl0dGVkdGV4dFsxXS5tYXRjaCgvQkVHSU4gUEdQIE1FU1NBR0UvKSkge1xuXHRcdHJldHVybiAzO1xuXG5cdH0gZWxzZVxuXHRcdC8vIEJFR0lOIFBHUCBQVUJMSUMgS0VZIEJMT0NLXG5cdFx0Ly8gVXNlZCBmb3IgYXJtb3JpbmcgcHVibGljIGtleXMuXG5cdGlmIChzcGxpdHRlZHRleHRbMV0ubWF0Y2goL0JFR0lOIFBHUCBQVUJMSUMgS0VZIEJMT0NLLykpIHtcblx0XHRyZXR1cm4gNDtcblxuXHR9IGVsc2Vcblx0XHQvLyBCRUdJTiBQR1AgUFJJVkFURSBLRVkgQkxPQ0tcblx0XHQvLyBVc2VkIGZvciBhcm1vcmluZyBwcml2YXRlIGtleXMuXG5cdGlmIChzcGxpdHRlZHRleHRbMV0ubWF0Y2goL0JFR0lOIFBHUCBQUklWQVRFIEtFWSBCTE9DSy8pKSB7XG5cdFx0cmV0dXJuIDU7XG5cdH1cbn1cblxuLyoqXG4gKiBBZGQgYWRkaXRpb25hbCBpbmZvcm1hdGlvbiB0byB0aGUgYXJtb3IgdmVyc2lvbiBvZiBhbiBPcGVuUEdQIGJpbmFyeVxuICogcGFja2V0IGJsb2NrLlxuICogQGF1dGhvciAgQWxleFxuICogQHZlcnNpb24gMjAxMS0xMi0xNlxuICogQHJldHVybnMge1N0cmluZ30gVGhlIGhlYWRlciBpbmZvcm1hdGlvblxuICovXG5mdW5jdGlvbiBhcm1vcl9hZGRoZWFkZXIoKSB7XG4gICAgdmFyIHJlc3VsdCA9IFwiXCI7XG5cdGlmIChvcGVucGdwLmNvbmZpZy5jb25maWcuc2hvd192ZXJzaW9uKSB7XG4gICAgICAgIHJlc3VsdCArPSBcIlZlcnNpb246IFwiK29wZW5wZ3AuY29uZmlnLnZlcnNpb25zdHJpbmcrJ1xcclxcbic7XG4gICAgfVxuXHRpZiAob3BlbnBncC5jb25maWcuY29uZmlnLnNob3dfY29tbWVudCkge1xuICAgICAgICByZXN1bHQgKz0gXCJDb21tZW50OiBcIitvcGVucGdwLmNvbmZpZy5jb21tZW50c3RyaW5nKydcXHJcXG4nO1xuICAgIH1cbiAgICByZXN1bHQgKz0gJ1xcclxcbic7XG4gICAgcmV0dXJuIHJlc3VsdDtcbn1cblxuXG5cbi8qKlxuICogQ2FsY3VsYXRlcyBhIGNoZWNrc3VtIG92ZXIgdGhlIGdpdmVuIGRhdGEgYW5kIHJldHVybnMgaXQgYmFzZTY0IGVuY29kZWRcbiAqIEBwYXJhbSB7U3RyaW5nfSBkYXRhIERhdGEgdG8gY3JlYXRlIGEgQ1JDLTI0IGNoZWNrc3VtIGZvclxuICogQHJldHVybiB7U3RyaW5nfSBCYXNlNjQgZW5jb2RlZCBjaGVja3N1bVxuICovXG5mdW5jdGlvbiBnZXRDaGVja1N1bShkYXRhKSB7XG5cdHZhciBjID0gY3JlYXRlY3JjMjQoZGF0YSk7XG5cdHZhciBzdHIgPSBcIlwiICsgU3RyaW5nLmZyb21DaGFyQ29kZShjID4+IDE2KStcblx0XHRcdFx0ICAgU3RyaW5nLmZyb21DaGFyQ29kZSgoYyA+PiA4KSAmIDB4RkYpK1xuXHRcdFx0XHQgICBTdHJpbmcuZnJvbUNoYXJDb2RlKGMgJiAweEZGKTtcblx0cmV0dXJuIGJhc2U2NC5lbmNvZGUoc3RyKTtcbn1cblxuLyoqXG4gKiBDYWxjdWxhdGVzIHRoZSBjaGVja3N1bSBvdmVyIHRoZSBnaXZlbiBkYXRhIGFuZCBjb21wYXJlcyBpdCB3aXRoIHRoZSBcbiAqIGdpdmVuIGJhc2U2NCBlbmNvZGVkIGNoZWNrc3VtXG4gKiBAcGFyYW0ge1N0cmluZ30gZGF0YSBEYXRhIHRvIGNyZWF0ZSBhIENSQy0yNCBjaGVja3N1bSBmb3JcbiAqIEBwYXJhbSB7U3RyaW5nfSBjaGVja3N1bSBCYXNlNjQgZW5jb2RlZCBjaGVja3N1bVxuICogQHJldHVybiB7Qm9vbGVhbn0gVHJ1ZSBpZiB0aGUgZ2l2ZW4gY2hlY2tzdW0gaXMgY29ycmVjdDsgb3RoZXJ3aXNlIGZhbHNlXG4gKi9cbmZ1bmN0aW9uIHZlcmlmeUNoZWNrU3VtKGRhdGEsIGNoZWNrc3VtKSB7XG5cdHZhciBjID0gZ2V0Q2hlY2tTdW0oZGF0YSk7XG5cdHZhciBkID0gY2hlY2tzdW07XG5cdHJldHVybiBjWzBdID09IGRbMF0gJiYgY1sxXSA9PSBkWzFdICYmIGNbMl0gPT0gZFsyXTtcbn1cbi8qKlxuICogSW50ZXJuYWwgZnVuY3Rpb24gdG8gY2FsY3VsYXRlIGEgQ1JDLTI0IGNoZWNrc3VtIG92ZXIgYSBnaXZlbiBzdHJpbmcgKGRhdGEpXG4gKiBAcGFyYW0ge1N0cmluZ30gZGF0YSBEYXRhIHRvIGNyZWF0ZSBhIENSQy0yNCBjaGVja3N1bSBmb3JcbiAqIEByZXR1cm4ge0ludGVnZXJ9IFRoZSBDUkMtMjQgY2hlY2tzdW0gYXMgbnVtYmVyXG4gKi9cbnZhciBjcmNfdGFibGUgPSBbXG4weDAwMDAwMDAwLCAweDAwODY0Y2ZiLCAweDAxOGFkNTBkLCAweDAxMGM5OWY2LCAweDAzOTNlNmUxLCAweDAzMTVhYTFhLCAweDAyMTkzM2VjLCAweDAyOWY3ZjE3LCAweDA3YTE4MTM5LCAweDA3MjdjZGMyLCAweDA2MmI1NDM0LCAweDA2YWQxOGNmLCAweDA0MzI2N2Q4LCAweDA0YjQyYjIzLCAweDA1YjhiMmQ1LCAweDA1M2VmZTJlLCAweDBmYzU0ZTg5LCAweDBmNDMwMjcyLCAweDBlNGY5Yjg0LCAweDBlYzlkNzdmLCAweDBjNTZhODY4LCAweDBjZDBlNDkzLCAweDBkZGM3ZDY1LCAweDBkNWEzMTllLCAweDA4NjRjZmIwLCAweDA4ZTI4MzRiLCAweDA5ZWUxYWJkLCAweDA5Njg1NjQ2LCAweDBiZjcyOTUxLCAweDBiNzE2NWFhLCAweDBhN2RmYzVjLCAweDBhZmJiMGE3LCAweDFmMGNkMWU5LCAweDFmOGE5ZDEyLCAweDFlODYwNGU0LCAweDFlMDA0ODFmLCAweDFjOWYzNzA4LCAweDFjMTk3YmYzLCAweDFkMTVlMjA1LCAweDFkOTNhZWZlLCAweDE4YWQ1MGQwLCAweDE4MmIxYzJiLCAweDE5Mjc4NWRkLCAweDE5YTFjOTI2LCAweDFiM2ViNjMxLCAweDFiYjhmYWNhLCAweDFhYjQ2MzNjLCAweDFhMzIyZmM3LCAweDEwYzk5ZjYwLCAweDEwNGZkMzliLCAweDExNDM0YTZkLCAweDExYzUwNjk2LCAweDEzNWE3OTgxLCAweDEzZGMzNTdhLCAweDEyZDBhYzhjLCAweDEyNTZlMDc3LCAweDE3NjgxZTU5LCAweDE3ZWU1MmEyLCAweDE2ZTJjYjU0LCAweDE2NjQ4N2FmLCAweDE0ZmJmOGI4LCAweDE0N2RiNDQzLCAweDE1NzEyZGI1LCAweDE1Zjc2MTRlLCAweDNlMTlhM2QyLCAweDNlOWZlZjI5LCAweDNmOTM3NmRmLCAweDNmMTUzYTI0LCAweDNkOGE0NTMzLCAweDNkMGMwOWM4LCAweDNjMDA5MDNlLCAweDNjODZkY2M1LCAweDM5YjgyMmViLCAweDM5M2U2ZTEwLCAweDM4MzJmN2U2LCAweDM4YjRiYjFkLCAweDNhMmJjNDBhLCAweDNhYWQ4OGYxLCAweDNiYTExMTA3LCAweDNiMjc1ZGZjLCAweDMxZGNlZDViLCAweDMxNWFhMWEwLFxuMHgzMDU2Mzg1NiwgMHgzMGQwNzRhZCwgMHgzMjRmMGJiYSwgMHgzMmM5NDc0MSwgMHgzM2M1ZGViNywgMHgzMzQzOTI0YywgMHgzNjdkNmM2MiwgMHgzNmZiMjA5OSwgMHgzN2Y3Yjk2ZiwgMHgzNzcxZjU5NCwgMHgzNWVlOGE4MywgMHgzNTY4YzY3OCwgMHgzNDY0NWY4ZSwgMHgzNGUyMTM3NSwgMHgyMTE1NzIzYiwgMHgyMTkzM2VjMCwgMHgyMDlmYTczNiwgMHgyMDE5ZWJjZCwgMHgyMjg2OTRkYSwgMHgyMjAwZDgyMSwgMHgyMzBjNDFkNywgMHgyMzhhMGQyYywgMHgyNmI0ZjMwMiwgMHgyNjMyYmZmOSwgMHgyNzNlMjYwZiwgMHgyN2I4NmFmNCwgMHgyNTI3MTVlMywgMHgyNWExNTkxOCwgMHgyNGFkYzBlZSwgMHgyNDJiOGMxNSwgMHgyZWQwM2NiMiwgMHgyZTU2NzA0OSwgMHgyZjVhZTliZiwgMHgyZmRjYTU0NCwgMHgyZDQzZGE1MywgMHgyZGM1OTZhOCwgMHgyY2M5MGY1ZSwgMHgyYzRmNDNhNSwgMHgyOTcxYmQ4YiwgMHgyOWY3ZjE3MCwgMHgyOGZiNjg4NiwgMHgyODdkMjQ3ZCwgMHgyYWUyNWI2YSwgMHgyYTY0MTc5MSwgMHgyYjY4OGU2NywgMHgyYmVlYzI5YywgMHg3YzMzNDdhNCwgMHg3Y2I1MGI1ZiwgMHg3ZGI5OTJhOSwgMHg3ZDNmZGU1MiwgMHg3ZmEwYTE0NSwgMHg3ZjI2ZWRiZSwgMHg3ZTJhNzQ0OCwgMHg3ZWFjMzhiMywgMHg3YjkyYzY5ZCwgMHg3YjE0OGE2NiwgMHg3YTE4MTM5MCwgMHg3YTllNWY2YiwgMHg3ODAxMjA3YywgMHg3ODg3NmM4NywgMHg3OThiZjU3MSwgMHg3OTBkYjk4YSwgMHg3M2Y2MDkyZCwgMHg3MzcwNDVkNiwgMHg3MjdjZGMyMCwgMHg3MmZhOTBkYiwgMHg3MDY1ZWZjYywgMHg3MGUzYTMzNywgMHg3MWVmM2FjMSwgMHg3MTY5NzYzYSwgMHg3NDU3ODgxNCwgMHg3NGQxYzRlZiwgMHg3NWRkNWQxOSwgMHg3NTViMTFlMiwgMHg3N2M0NmVmNSwgMHg3NzQyMjIwZSwgMHg3NjRlYmJmOCwgMHg3NmM4ZjcwMywgMHg2MzNmOTY0ZCwgMHg2M2I5ZGFiNiwgMHg2MmI1NDM0MCwgMHg2MjMzMGZiYixcbjB4NjBhYzcwYWMsIDB4NjAyYTNjNTcsIDB4NjEyNmE1YTEsIDB4NjFhMGU5NWEsIDB4NjQ5ZTE3NzQsIDB4NjQxODViOGYsIDB4NjUxNGMyNzksIDB4NjU5MjhlODIsIDB4NjcwZGYxOTUsIDB4Njc4YmJkNmUsIDB4NjY4NzI0OTgsIDB4NjYwMTY4NjMsIDB4NmNmYWQ4YzQsIDB4NmM3Yzk0M2YsIDB4NmQ3MDBkYzksIDB4NmRmNjQxMzIsIDB4NmY2OTNlMjUsIDB4NmZlZjcyZGUsIDB4NmVlM2ViMjgsIDB4NmU2NWE3ZDMsIDB4NmI1YjU5ZmQsIDB4NmJkZDE1MDYsIDB4NmFkMThjZjAsIDB4NmE1N2MwMGIsIDB4NjhjOGJmMWMsIDB4Njg0ZWYzZTcsIDB4Njk0MjZhMTEsIDB4NjljNDI2ZWEsIDB4NDIyYWU0NzYsIDB4NDJhY2E4OGQsIDB4NDNhMDMxN2IsIDB4NDMyNjdkODAsIDB4NDFiOTAyOTcsIDB4NDEzZjRlNmMsIDB4NDAzM2Q3OWEsIDB4NDBiNTliNjEsIDB4NDU4YjY1NGYsIDB4NDUwZDI5YjQsIDB4NDQwMWIwNDIsIDB4NDQ4N2ZjYjksIDB4NDYxODgzYWUsIDB4NDY5ZWNmNTUsIDB4NDc5MjU2YTMsIDB4NDcxNDFhNTgsIDB4NGRlZmFhZmYsIDB4NGQ2OWU2MDQsIDB4NGM2NTdmZjIsIDB4NGNlMzMzMDksIDB4NGU3YzRjMWUsIDB4NGVmYTAwZTUsIDB4NGZmNjk5MTMsIDB4NGY3MGQ1ZTgsIDB4NGE0ZTJiYzYsIDB4NGFjODY3M2QsIDB4NGJjNGZlY2IsIDB4NGI0MmIyMzAsIDB4NDlkZGNkMjcsIDB4NDk1YjgxZGMsIDB4NDg1NzE4MmEsIDB4NDhkMTU0ZDEsIDB4NWQyNjM1OWYsIDB4NWRhMDc5NjQsIDB4NWNhY2UwOTIsIDB4NWMyYWFjNjksIDB4NWViNWQzN2UsIDB4NWUzMzlmODUsIDB4NWYzZjA2NzMsIDB4NWZiOTRhODgsIDB4NWE4N2I0YTYsIDB4NWEwMWY4NWQsIDB4NWIwZDYxYWIsIDB4NWI4YjJkNTAsIDB4NTkxNDUyNDcsIDB4NTk5MjFlYmMsIDB4NTg5ZTg3NGEsIDB4NTgxOGNiYjEsIDB4NTJlMzdiMTYsIDB4NTI2NTM3ZWQsIDB4NTM2OWFlMWIsIDB4NTNlZmUyZTAsIDB4NTE3MDlkZjcsIDB4NTFmNmQxMGMsXG4weDUwZmE0OGZhLCAweDUwN2MwNDAxLCAweDU1NDJmYTJmLCAweDU1YzRiNmQ0LCAweDU0YzgyZjIyLCAweDU0NGU2M2Q5LCAweDU2ZDExY2NlLCAweDU2NTc1MDM1LCAweDU3NWJjOWMzLCAweDU3ZGQ4NTM4XTtcblxuZnVuY3Rpb24gY3JlYXRlY3JjMjQoaW5wdXQpIHtcbiAgdmFyIGNyYyA9IDB4QjcwNENFO1xuICB2YXIgaW5kZXggPSAwO1xuXG4gIHdoaWxlKChpbnB1dC5sZW5ndGggLSBpbmRleCkgPiAxNikgIHtcbiAgIGNyYyA9IChjcmMgPDwgOCkgXiBjcmNfdGFibGVbKChjcmMgPj4gMTYpIF4gaW5wdXQuY2hhckNvZGVBdChpbmRleCkpICYgMHhmZl07XG4gICBjcmMgPSAoY3JjIDw8IDgpIF4gY3JjX3RhYmxlWygoY3JjID4+IDE2KSBeIGlucHV0LmNoYXJDb2RlQXQoaW5kZXgrMSkpICYgMHhmZl07XG4gICBjcmMgPSAoY3JjIDw8IDgpIF4gY3JjX3RhYmxlWygoY3JjID4+IDE2KSBeIGlucHV0LmNoYXJDb2RlQXQoaW5kZXgrMikpICYgMHhmZl07XG4gICBjcmMgPSAoY3JjIDw8IDgpIF4gY3JjX3RhYmxlWygoY3JjID4+IDE2KSBeIGlucHV0LmNoYXJDb2RlQXQoaW5kZXgrMykpICYgMHhmZl07XG4gICBjcmMgPSAoY3JjIDw8IDgpIF4gY3JjX3RhYmxlWygoY3JjID4+IDE2KSBeIGlucHV0LmNoYXJDb2RlQXQoaW5kZXgrNCkpICYgMHhmZl07XG4gICBjcmMgPSAoY3JjIDw8IDgpIF4gY3JjX3RhYmxlWygoY3JjID4+IDE2KSBeIGlucHV0LmNoYXJDb2RlQXQoaW5kZXgrNSkpICYgMHhmZl07XG4gICBjcmMgPSAoY3JjIDw8IDgpIF4gY3JjX3RhYmxlWygoY3JjID4+IDE2KSBeIGlucHV0LmNoYXJDb2RlQXQoaW5kZXgrNikpICYgMHhmZl07XG4gICBjcmMgPSAoY3JjIDw8IDgpIF4gY3JjX3RhYmxlWygoY3JjID4+IDE2KSBeIGlucHV0LmNoYXJDb2RlQXQoaW5kZXgrNykpICYgMHhmZl07XG4gICBjcmMgPSAoY3JjIDw8IDgpIF4gY3JjX3RhYmxlWygoY3JjID4+IDE2KSBeIGlucHV0LmNoYXJDb2RlQXQoaW5kZXgrOCkpICYgMHhmZl07XG4gICBjcmMgPSAoY3JjIDw8IDgpIF4gY3JjX3RhYmxlWygoY3JjID4+IDE2KSBeIGlucHV0LmNoYXJDb2RlQXQoaW5kZXgrOSkpICYgMHhmZl07XG4gICBjcmMgPSAoY3JjIDw8IDgpIF4gY3JjX3RhYmxlWygoY3JjID4+IDE2KSBeIGlucHV0LmNoYXJDb2RlQXQoaW5kZXgrMTApKSAmIDB4ZmZdO1xuICAgY3JjID0gKGNyYyA8PCA4KSBeIGNyY190YWJsZVsoKGNyYyA+PiAxNikgXiBpbnB1dC5jaGFyQ29kZUF0KGluZGV4KzExKSkgJiAweGZmXTtcbiAgIGNyYyA9IChjcmMgPDwgOCkgXiBjcmNfdGFibGVbKChjcmMgPj4gMTYpIF4gaW5wdXQuY2hhckNvZGVBdChpbmRleCsxMikpICYgMHhmZl07XG4gICBjcmMgPSAoY3JjIDw8IDgpIF4gY3JjX3RhYmxlWygoY3JjID4+IDE2KSBeIGlucHV0LmNoYXJDb2RlQXQoaW5kZXgrMTMpKSAmIDB4ZmZdO1xuICAgY3JjID0gKGNyYyA8PCA4KSBeIGNyY190YWJsZVsoKGNyYyA+PiAxNikgXiBpbnB1dC5jaGFyQ29kZUF0KGluZGV4KzE0KSkgJiAweGZmXTtcbiAgIGNyYyA9IChjcmMgPDwgOCkgXiBjcmNfdGFibGVbKChjcmMgPj4gMTYpIF4gaW5wdXQuY2hhckNvZGVBdChpbmRleCsxNSkpICYgMHhmZl07XG4gICBpbmRleCArPSAxNjtcbiAgfVxuXG4gIGZvcih2YXIgaiA9IGluZGV4OyBqIDwgaW5wdXQubGVuZ3RoOyBqKyspIHtcbiAgIGNyYyA9IChjcmMgPDwgOCkgXiBjcmNfdGFibGVbKChjcmMgPj4gMTYpIF4gaW5wdXQuY2hhckNvZGVBdChpbmRleCsrKSkgJiAweGZmXVxuICB9XG4gIHJldHVybiBjcmMgJiAweGZmZmZmZjtcbn1cblxuLyoqXG4gKiBEZUFybW9yIGFuIE9wZW5QR1AgYXJtb3JlZCBtZXNzYWdlOyB2ZXJpZnkgdGhlIGNoZWNrc3VtIGFuZCByZXR1cm4gXG4gKiB0aGUgZW5jb2RlZCBieXRlc1xuICogQHBhcmFtIHtTdHJpbmd9IHRleHQgT3BlblBHUCBhcm1vcmVkIG1lc3NhZ2VcbiAqIEByZXR1cm5zIHsoQm9vbGVhbnxPYmplY3QpfSBFaXRoZXIgZmFsc2UgaW4gY2FzZSBvZiBhbiBlcnJvciBcbiAqIG9yIGFuIG9iamVjdCB3aXRoIGF0dHJpYnV0ZSBcInRleHRcIiBjb250YWluaW5nIHRoZSBtZXNzYWdlIHRleHRcbiAqIGFuZCBhbiBhdHRyaWJ1dGUgXCJvcGVucGdwXCIgY29udGFpbmluZyB0aGUgYnl0ZXMuXG4gKi9cbmZ1bmN0aW9uIGRlYXJtb3IodGV4dCkge1xuXHR0ZXh0ID0gdGV4dC5yZXBsYWNlKC9cXHIvZywgJycpXG5cblx0dmFyIHR5cGUgPSBnZXRfdHlwZSh0ZXh0KTtcblxuXHRpZiAodHlwZSAhPSAyKSB7XG5cdFx0dmFyIHNwbGl0dGVkdGV4dCA9IHRleHQuc3BsaXQoJy0tLS0tJyk7XG5cblx0XHR2YXIgZGF0YSA9IHsgXG5cdFx0XHRvcGVucGdwOiBiYXNlNjQuZGVjb2RlKFxuXHRcdFx0XHRzcGxpdHRlZHRleHRbMl1cblx0XHRcdFx0XHQuc3BsaXQoJ1xcblxcbicpWzFdXG5cdFx0XHRcdFx0LnNwbGl0KFwiXFxuPVwiKVswXVxuXHRcdFx0XHRcdC5yZXBsYWNlKC9cXG4tIC9nLFwiXFxuXCIpKSxcblx0XHRcdHR5cGU6IHR5cGVcblx0XHR9O1xuXG5cdFx0aWYgKHZlcmlmeUNoZWNrU3VtKGRhdGEub3BlbnBncCwgXG5cdFx0XHRzcGxpdHRlZHRleHRbMl1cblx0XHRcdFx0LnNwbGl0KCdcXG5cXG4nKVsxXVxuXHRcdFx0XHQuc3BsaXQoXCJcXG49XCIpWzFdXG5cdFx0XHRcdC5zcGxpdCgnXFxuJylbMF0pKVxuXG5cdFx0XHRyZXR1cm4gZGF0YTtcblx0XHRlbHNlIHtcblx0XHRcdHV0aWwucHJpbnRfZXJyb3IoXCJBc2NpaSBhcm1vciBpbnRlZ3JpdHkgY2hlY2sgb24gbWVzc2FnZSBmYWlsZWQ6ICdcIlxuXHRcdFx0XHQrIHNwbGl0dGVkdGV4dFsyXVxuXHRcdFx0XHRcdC5zcGxpdCgnXFxuXFxuJylbMV1cblx0XHRcdFx0XHQuc3BsaXQoXCJcXG49XCIpWzFdXG5cdFx0XHRcdFx0LnNwbGl0KCdcXG4nKVswXSBcblx0XHRcdFx0KyBcIicgc2hvdWxkIGJlICdcIlxuXHRcdFx0XHQrIGdldENoZWNrU3VtKGRhdGEpKSArIFwiJ1wiO1xuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH1cblx0fSBlbHNlIHtcblx0XHR2YXIgc3BsaXR0ZWR0ZXh0ID0gdGV4dC5zcGxpdCgnLS0tLS0nKTtcblxuXHRcdHZhciByZXN1bHQgPSB7XG5cdFx0XHR0ZXh0OiBzcGxpdHRlZHRleHRbMl1cblx0XHRcdFx0LnJlcGxhY2UoL1xcbi0gL2csXCJcXG5cIilcblx0XHRcdFx0LnNwbGl0KFwiXFxuXFxuXCIpWzFdLFxuXHRcdFx0b3BlbnBncDogYmFzZTY0X2RlY29kZShzcGxpdHRlZHRleHRbNF1cblx0XHRcdFx0LnNwbGl0KFwiXFxuXFxuXCIpWzFdXG5cdFx0XHRcdC5zcGxpdChcIlxcbj1cIilbMF0pLFxuXHRcdFx0dHlwZTogdHlwZVxuXHRcdH07XG5cblx0XHRpZiAodmVyaWZ5Q2hlY2tTdW0ocmVzdWx0Lm9wZW5wZ3AsIHNwbGl0dGVkdGV4dFs0XVxuXHRcdFx0LnNwbGl0KFwiXFxuXFxuXCIpWzFdXG5cdFx0XHQuc3BsaXQoXCJcXG49XCIpWzFdKSlcblxuXHRcdFx0XHRyZXR1cm4gcmVzdWx0O1xuXHRcdGVsc2Uge1xuXHRcdFx0dXRpbC5wcmludF9lcnJvcihcIkFzY2lpIGFybW9yIGludGVncml0eSBjaGVjayBvbiBtZXNzYWdlIGZhaWxlZFwiKTtcblx0XHRcdHJldHVybiBmYWxzZTtcblx0XHR9XG5cdH1cbn1cblxuXG4vKipcbiAqIEFybW9yIGFuIE9wZW5QR1AgYmluYXJ5IHBhY2tldCBibG9ja1xuICogQHBhcmFtIHtJbnRlZ2VyfSBtZXNzYWdldHlwZSB0eXBlIG9mIHRoZSBtZXNzYWdlXG4gKiBAcGFyYW0gZGF0YVxuICogQHBhcmFtIHtJbnRlZ2VyfSBwYXJ0aW5kZXhcbiAqIEBwYXJhbSB7SW50ZWdlcn0gcGFydHRvdGFsXG4gKiBAcmV0dXJucyB7U3RyaW5nfSBBcm1vcmVkIHRleHRcbiAqL1xuZnVuY3Rpb24gYXJtb3IobWVzc2FnZXR5cGUsIGRhdGEsIHBhcnRpbmRleCwgcGFydHRvdGFsKSB7XG5cdHZhciByZXN1bHQgPSBcIlwiO1xuXHRzd2l0Y2gobWVzc2FnZXR5cGUpIHtcblx0Y2FzZSAwOlxuXHRcdHJlc3VsdCArPSBcIi0tLS0tQkVHSU4gUEdQIE1FU1NBR0UsIFBBUlQgXCIrcGFydGluZGV4K1wiL1wiK3BhcnR0b3RhbCtcIi0tLS0tXFxyXFxuXCI7XG5cdFx0cmVzdWx0ICs9IGFybW9yX2FkZGhlYWRlcigpO1xuXHRcdHJlc3VsdCArPSBiYXNlNjQuZW5jb2RlKGRhdGEpO1xuXHRcdHJlc3VsdCArPSBcIlxcclxcbj1cIitnZXRDaGVja1N1bShkYXRhKStcIlxcclxcblwiO1xuXHRcdHJlc3VsdCArPSBcIi0tLS0tRU5EIFBHUCBNRVNTQUdFLCBQQVJUIFwiK3BhcnRpbmRleCtcIi9cIitwYXJ0dG90YWwrXCItLS0tLVxcclxcblwiO1xuXHRcdGJyZWFrO1xuXHRjYXNlIDE6XG5cdFx0cmVzdWx0ICs9IFwiLS0tLS1CRUdJTiBQR1AgTUVTU0FHRSwgUEFSVCBcIitwYXJ0aW5kZXgrXCItLS0tLVxcclxcblwiO1xuXHRcdHJlc3VsdCArPSBhcm1vcl9hZGRoZWFkZXIoKTtcblx0XHRyZXN1bHQgKz0gYmFzZTY0LmVuY29kZShkYXRhKTtcblx0XHRyZXN1bHQgKz0gXCJcXHJcXG49XCIrZ2V0Q2hlY2tTdW0oZGF0YSkrXCJcXHJcXG5cIjtcblx0XHRyZXN1bHQgKz0gXCItLS0tLUVORCBQR1AgTUVTU0FHRSwgUEFSVCBcIitwYXJ0aW5kZXgrXCItLS0tLVxcclxcblwiO1xuXHRcdGJyZWFrO1xuXHRjYXNlIDI6XG5cdFx0cmVzdWx0ICs9IFwiXFxyXFxuLS0tLS1CRUdJTiBQR1AgU0lHTkVEIE1FU1NBR0UtLS0tLVxcclxcbkhhc2g6IFwiK2RhdGEuaGFzaCtcIlxcclxcblxcclxcblwiO1xuXHRcdHJlc3VsdCArPSBkYXRhLnRleHQucmVwbGFjZSgvXFxuLS9nLFwiXFxuLSAtXCIpO1xuXHRcdHJlc3VsdCArPSBcIlxcclxcbi0tLS0tQkVHSU4gUEdQIFNJR05BVFVSRS0tLS0tXFxyXFxuXCI7XG5cdFx0cmVzdWx0ICs9IGFybW9yX2FkZGhlYWRlcigpO1xuXHRcdHJlc3VsdCArPSBiYXNlNjQuZW5jb2RlKGRhdGEub3BlbnBncCk7XG5cdFx0cmVzdWx0ICs9IFwiXFxyXFxuPVwiK2dldENoZWNrU3VtKGRhdGEub3BlbnBncCkrXCJcXHJcXG5cIjtcblx0XHRyZXN1bHQgKz0gXCItLS0tLUVORCBQR1AgU0lHTkFUVVJFLS0tLS1cXHJcXG5cIjtcblx0XHRicmVhaztcblx0Y2FzZSAzOlxuXHRcdHJlc3VsdCArPSBcIi0tLS0tQkVHSU4gUEdQIE1FU1NBR0UtLS0tLVxcclxcblwiO1xuXHRcdHJlc3VsdCArPSBhcm1vcl9hZGRoZWFkZXIoKTtcblx0XHRyZXN1bHQgKz0gYmFzZTY0LmVuY29kZShkYXRhKTtcblx0XHRyZXN1bHQgKz0gXCJcXHJcXG49XCIrZ2V0Q2hlY2tTdW0oZGF0YSkrXCJcXHJcXG5cIjtcblx0XHRyZXN1bHQgKz0gXCItLS0tLUVORCBQR1AgTUVTU0FHRS0tLS0tXFxyXFxuXCI7XG5cdFx0YnJlYWs7XG5cdGNhc2UgNDpcblx0XHRyZXN1bHQgKz0gXCItLS0tLUJFR0lOIFBHUCBQVUJMSUMgS0VZIEJMT0NLLS0tLS1cXHJcXG5cIjtcblx0XHRyZXN1bHQgKz0gYXJtb3JfYWRkaGVhZGVyKCk7XG5cdFx0cmVzdWx0ICs9IGJhc2U2NC5lbmNvZGUoZGF0YSk7XG5cdFx0cmVzdWx0ICs9IFwiXFxyXFxuPVwiK2dldENoZWNrU3VtKGRhdGEpK1wiXFxyXFxuXCI7XG5cdFx0cmVzdWx0ICs9IFwiLS0tLS1FTkQgUEdQIFBVQkxJQyBLRVkgQkxPQ0stLS0tLVxcclxcblxcclxcblwiO1xuXHRcdGJyZWFrO1xuXHRjYXNlIDU6XG5cdFx0cmVzdWx0ICs9IFwiLS0tLS1CRUdJTiBQR1AgUFJJVkFURSBLRVkgQkxPQ0stLS0tLVxcclxcblwiO1xuXHRcdHJlc3VsdCArPSBhcm1vcl9hZGRoZWFkZXIoKTtcblx0XHRyZXN1bHQgKz0gYmFzZTY0LmVuY29kZShkYXRhKTtcblx0XHRyZXN1bHQgKz0gXCJcXHJcXG49XCIrZ2V0Q2hlY2tTdW0oZGF0YSkrXCJcXHJcXG5cIjtcblx0XHRyZXN1bHQgKz0gXCItLS0tLUVORCBQR1AgUFJJVkFURSBLRVkgQkxPQ0stLS0tLVxcclxcblwiO1xuXHRcdGJyZWFrO1xuXHR9XG5cblx0cmV0dXJuIHJlc3VsdDtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSB7XG5cdGVuY29kZTogYXJtb3IsXG5cdGRlY29kZTogZGVhcm1vclxufVxuIiwiLy8gR1BHNEJyb3dzZXJzIC0gQW4gT3BlblBHUCBpbXBsZW1lbnRhdGlvbiBpbiBqYXZhc2NyaXB0XG4vLyBDb3B5cmlnaHQgKEMpIDIwMTEgUmVjdXJpdHkgTGFicyBHbWJIXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3Jcbi8vIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlclxuLy8gdmVyc2lvbiAyLjEgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuLy8gYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2Zcbi8vIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUgR05VXG4vLyBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuLy8gXG4vLyBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFsb25nIHdpdGggdGhpcyBsaWJyYXJ5OyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlXG4vLyBGb3VuZGF0aW9uLCBJbmMuLCA1MSBGcmFua2xpbiBTdHJlZXQsIEZpZnRoIEZsb29yLCBCb3N0b24sIE1BICAwMjExMC0xMzAxICBVU0FcblxudmFyIFV0aWwgPSBmdW5jdGlvbigpIHtcblxuXG5cblx0dGhpcy5yZWFkTnVtYmVyID0gZnVuY3Rpb24gKGJ5dGVzKSB7XG5cdFx0dmFyIG4gPSAwO1xuXG5cdFx0Zm9yKHZhciBpID0gMDsgaSA8IGJ5dGVzLmxlbmd0aDsgaSsrKSB7XG5cdFx0XHRuIDw8PSA4O1xuXHRcdFx0biArPSBieXRlc1tpXS5jaGFyQ29kZUF0KClcblx0XHR9XG5cblx0XHRyZXR1cm4gbjtcblx0fVxuXG5cdHRoaXMud3JpdGVOdW1iZXIgPSBmdW5jdGlvbihuLCBieXRlcykge1xuXHRcdHZhciBiID0gJyc7XG5cdFx0Zm9yKHZhciBpID0gMDsgaSA8IGJ5dGVzOyBpKyspIHtcblx0XHRcdGIgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSgobiA+PiAoOCAqIChieXRlcy0gaSAtIDEpKSkgJiAweEZGKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gYjtcblx0fVxuXG5cblxuXHR0aGlzLnJlYWREYXRlID0gZnVuY3Rpb24oYnl0ZXMpIHtcblx0XHR2YXIgbiA9IHRoaXMucmVhZE51bWJlcihieXRlcyk7XG5cdFx0dmFyIGQgPSBuZXcgRGF0ZSgpO1xuXHRcdGQuc2V0VGltZShuICogMTAwMCk7XG5cdFx0cmV0dXJuIGQ7XG5cdH1cblxuXHR0aGlzLndyaXRlRGF0ZSA9IGZ1bmN0aW9uKHRpbWUpIHtcblx0XHR2YXIgbnVtZXJpYyA9IE1hdGgucm91bmQodGltZS5nZXRUaW1lKCkgLyAxMDAwKTtcblxuXHRcdHJldHVybiB0aGlzLndyaXRlTnVtYmVyKG51bWVyaWMsIDQpO1xuXHR9XG5cbiAgICB0aGlzLmVtYWlsUmVnRXggPSAvW2EtejAtOSEjJCUmJyorLz0/Xl9ge3x9fi1dKyg/OlxcLlthLXowLTkhIyQlJicqKy89P15fYHt8fX4tXSspKkAoPzpbYS16MC05XSg/OlthLXowLTktXSpbYS16MC05XSk/XFwuKStbYS16MC05XSg/OlthLXowLTktXSpbYS16MC05XSk/Lztcblx0XG5cdHRoaXMuZGVidWcgPSBmYWxzZTtcblxuXHR0aGlzLmhleGR1bXAgPSBmdW5jdGlvbihzdHIpIHtcblx0ICAgIHZhciByPVtdO1xuXHQgICAgdmFyIGU9c3RyLmxlbmd0aDtcblx0ICAgIHZhciBjPTA7XG5cdCAgICB2YXIgaDtcblx0ICAgIHZhciBpID0gMDtcblx0ICAgIHdoaWxlKGM8ZSl7XG5cdCAgICAgICAgaD1zdHIuY2hhckNvZGVBdChjKyspLnRvU3RyaW5nKDE2KTtcblx0ICAgICAgICB3aGlsZShoLmxlbmd0aDwyKSBoPVwiMFwiK2g7XG5cdCAgICAgICAgci5wdXNoKFwiIFwiK2gpO1xuXHQgICAgICAgIGkrKztcblx0ICAgICAgICBpZiAoaSAlIDMyID09IDApXG5cdCAgICAgICAgXHRyLnB1c2goXCJcXG4gICAgICAgICAgIFwiKTtcblx0ICAgIH1cblx0ICAgIHJldHVybiByLmpvaW4oJycpO1xuXHR9O1xuXHRcblx0LyoqXG5cdCAqIENyZWF0ZSBoZXhzdHJpbmcgZnJvbSBhIGJpbmFyeVxuXHQgKiBAcGFyYW0ge1N0cmluZ30gc3RyIFN0cmluZyB0byBjb252ZXJ0XG5cdCAqIEByZXR1cm4ge1N0cmluZ30gU3RyaW5nIGNvbnRhaW5pbmcgdGhlIGhleGFkZWNpbWFsIHZhbHVlc1xuXHQgKi9cblx0dGhpcy5oZXhzdHJkdW1wID0gZnVuY3Rpb24oc3RyKSB7XG5cdFx0aWYgKHN0ciA9PSBudWxsKVxuXHRcdFx0cmV0dXJuIFwiXCI7XG5cdCAgICB2YXIgcj1bXTtcblx0ICAgIHZhciBlPXN0ci5sZW5ndGg7XG5cdCAgICB2YXIgYz0wO1xuXHQgICAgdmFyIGg7XG5cdCAgICB3aGlsZShjPGUpe1xuXHQgICAgICAgIGg9c3RyW2MrK10uY2hhckNvZGVBdCgpLnRvU3RyaW5nKDE2KTtcblx0ICAgICAgICB3aGlsZShoLmxlbmd0aDwyKSBoPVwiMFwiK2g7XG5cdCAgICAgICAgci5wdXNoKFwiXCIraCk7XG5cdCAgICB9XG5cdCAgICByZXR1cm4gci5qb2luKCcnKTtcblx0fTtcblx0XG5cdC8qKlxuXHQgKiBDcmVhdGUgYmluYXJ5IHN0cmluZyBmcm9tIGEgaGV4IGVuY29kZWQgc3RyaW5nXG5cdCAqIEBwYXJhbSB7U3RyaW5nfSBzdHIgSGV4IHN0cmluZyB0byBjb252ZXJ0XG5cdCAqIEByZXR1cm4ge1N0cmluZ30gU3RyaW5nIGNvbnRhaW5pbmcgdGhlIGJpbmFyeSB2YWx1ZXNcblx0ICovXG5cdHRoaXMuaGV4MmJpbiA9IGZ1bmN0aW9uKGhleCkge1xuXHQgICAgdmFyIHN0ciA9ICcnO1xuXHQgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBoZXgubGVuZ3RoOyBpICs9IDIpXG5cdCAgICAgICAgc3RyICs9IFN0cmluZy5mcm9tQ2hhckNvZGUocGFyc2VJbnQoaGV4LnN1YnN0cihpLCAyKSwgMTYpKTtcblx0ICAgIHJldHVybiBzdHI7XG5cdH07XG5cdFxuXHQvKipcblx0ICogQ3JlYXRpbmcgYSBoZXggc3RyaW5nIGZyb20gYW4gYmluYXJ5IGFycmF5IG9mIGludGVnZXJzICgwLi4yNTUpXG5cdCAqIEBwYXJhbSB7U3RyaW5nfSBzdHIgQXJyYXkgb2YgYnl0ZXMgdG8gY29udmVydFxuXHQgKiBAcmV0dXJuIHtTdHJpbmd9IEhleGFkZWNpbWFsIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBhcnJheVxuXHQgKi9cblx0dGhpcy5oZXhpZHVtcCA9IGZ1bmN0aW9uKHN0cikge1xuXHQgICAgdmFyIHI9W107XG5cdCAgICB2YXIgZT1zdHIubGVuZ3RoO1xuXHQgICAgdmFyIGM9MDtcblx0ICAgIHZhciBoO1xuXHQgICAgd2hpbGUoYzxlKXtcblx0ICAgICAgICBoPXN0cltjKytdLnRvU3RyaW5nKDE2KTtcblx0ICAgICAgICB3aGlsZShoLmxlbmd0aDwyKSBoPVwiMFwiK2g7XG5cdCAgICAgICAgci5wdXNoKFwiXCIraCk7XG5cdCAgICB9XG5cdCAgICByZXR1cm4gci5qb2luKCcnKTtcblx0fTtcblxuXG5cdC8qKlxuXHQgKiBDb252ZXJ0IGEgbmF0aXZlIGphdmFzY3JpcHQgc3RyaW5nIHRvIGEgc3RyaW5nIG9mIHV0ZjggYnl0ZXNcblx0ICogQHBhcmFtIHtTdHJpbmd9IHN0ciBUaGUgc3RyaW5nIHRvIGNvbnZlcnRcblx0ICogQHJldHVybiB7U3RyaW5nfSBBIHZhbGlkIHNxdWVuY2Ugb2YgdXRmOCBieXRlc1xuXHQgKi9cblx0dGhpcy5lbmNvZGVfdXRmOCA9IGZ1bmN0aW9uKHN0cikge1xuXHRcdHJldHVybiB1bmVzY2FwZShlbmNvZGVVUklDb21wb25lbnQoc3RyKSk7XG5cdH07XG5cblx0LyoqXG5cdCAqIENvbnZlcnQgYSBzdHJpbmcgb2YgdXRmOCBieXRlcyB0byBhIG5hdGl2ZSBqYXZhc2NyaXB0IHN0cmluZ1xuXHQgKiBAcGFyYW0ge1N0cmluZ30gdXRmOCBBIHZhbGlkIHNxdWVuY2Ugb2YgdXRmOCBieXRlc1xuXHQgKiBAcmV0dXJuIHtTdHJpbmd9IEEgbmF0aXZlIGphdmFzY3JpcHQgc3RyaW5nXG5cdCAqL1xuXHR0aGlzLmRlY29kZV91dGY4ID0gZnVuY3Rpb24odXRmOCkge1xuXHRcdHJldHVybiBkZWNvZGVVUklDb21wb25lbnQoZXNjYXBlKHV0ZjgpKTtcblx0fTtcblxuXHR2YXIgc3RyMmJpbiA9IGZ1bmN0aW9uKHN0ciwgcmVzdWx0KSB7XG5cdFx0Zm9yICh2YXIgaSA9IDA7IGkgPCBzdHIubGVuZ3RoOyBpKyspIHtcblx0XHRcdHJlc3VsdFtpXSA9IHN0ci5jaGFyQ29kZUF0KGkpO1xuXHRcdH1cblxuXHRcdHJldHVybiByZXN1bHQ7XG5cdH07XG5cdFxuXHR2YXIgYmluMnN0ciA9IGZ1bmN0aW9uKGJpbikge1xuXHRcdHZhciByZXN1bHQgPSBbXTtcblxuXHRcdGZvciAodmFyIGkgPSAwOyBpIDwgYmluLmxlbmd0aDsgaSsrKSB7XG5cdFx0XHRyZXN1bHQucHVzaChTdHJpbmcuZnJvbUNoYXJDb2RlKGJpbltpXSkpO1xuXHRcdH1cblxuXHRcdHJldHVybiByZXN1bHQuam9pbignJyk7XG5cdH07XG5cblx0LyoqXG5cdCAqIENvbnZlcnQgYSBzdHJpbmcgdG8gYW4gYXJyYXkgb2YgaW50ZWdlcnMoMC4yNTUpXG5cdCAqIEBwYXJhbSB7U3RyaW5nfSBzdHIgU3RyaW5nIHRvIGNvbnZlcnRcblx0ICogQHJldHVybiB7SW50ZWdlcltdfSBBbiBhcnJheSBvZiAoYmluYXJ5KSBpbnRlZ2Vyc1xuXHQgKi9cblx0dGhpcy5zdHIyYmluID0gZnVuY3Rpb24oc3RyKSB7IFxuXHRcdHJldHVybiBzdHIyYmluKHN0ciwgbmV3IEFycmF5KHN0ci5sZW5ndGgpKTtcblx0fTtcblx0XG5cdFxuXHQvKipcblx0ICogQ29udmVydCBhbiBhcnJheSBvZiBpbnRlZ2VycygwLjI1NSkgdG8gYSBzdHJpbmcgXG5cdCAqIEBwYXJhbSB7SW50ZWdlcltdfSBiaW4gQW4gYXJyYXkgb2YgKGJpbmFyeSkgaW50ZWdlcnMgdG8gY29udmVydFxuXHQgKiBAcmV0dXJuIHtTdHJpbmd9IFRoZSBzdHJpbmcgcmVwcmVzZW50YXRpb24gb2YgdGhlIGFycmF5XG5cdCAqL1xuXHR0aGlzLmJpbjJzdHIgPSBiaW4yc3RyO1xuXHRcblx0LyoqXG5cdCAqIENvbnZlcnQgYSBzdHJpbmcgdG8gYSBVaW50OEFycmF5XG5cdCAqIEBwYXJhbSB7U3RyaW5nfSBzdHIgU3RyaW5nIHRvIGNvbnZlcnRcblx0ICogQHJldHVybiB7VWludDhBcnJheX0gVGhlIGFycmF5IG9mIChiaW5hcnkpIGludGVnZXJzXG5cdCAqL1xuXHR0aGlzLnN0cjJVaW50OEFycmF5ID0gZnVuY3Rpb24oc3RyKSB7IFxuXHRcdHJldHVybiBzdHIyYmluKHN0ciwgbmV3IFVpbnQ4QXJyYXkobmV3IEFycmF5QnVmZmVyKHN0ci5sZW5ndGgpKSk7IFxuXHR9O1xuXHRcblx0LyoqXG5cdCAqIENvbnZlcnQgYSBVaW50OEFycmF5IHRvIGEgc3RyaW5nLiBUaGlzIGN1cnJlbnRseSBmdW5jdGlvbnMgXG5cdCAqIHRoZSBzYW1lIGFzIGJpbjJzdHIuIFxuXHQgKiBAcGFyYW0ge1VpbnQ4QXJyYXl9IGJpbiBBbiBhcnJheSBvZiAoYmluYXJ5KSBpbnRlZ2VycyB0byBjb252ZXJ0XG5cdCAqIEByZXR1cm4ge1N0cmluZ30gU3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBhcnJheVxuXHQgKi9cblx0dGhpcy5VaW50OEFycmF5MnN0ciA9IGJpbjJzdHI7XG5cdFxuXHQvKipcblx0ICogQ2FsY3VsYXRlcyBhIDE2Yml0IHN1bSBvZiBhIHN0cmluZyBieSBhZGRpbmcgZWFjaCBjaGFyYWN0ZXIgXG5cdCAqIGNvZGVzIG1vZHVsdXMgNjU1MzVcblx0ICogQHBhcmFtIHtTdHJpbmd9IHRleHQgU3RyaW5nIHRvIGNyZWF0ZSBhIHN1bSBvZlxuXHQgKiBAcmV0dXJuIHtJbnRlZ2VyfSBBbiBpbnRlZ2VyIGNvbnRhaW5pbmcgdGhlIHN1bSBvZiBhbGwgY2hhcmFjdGVyIFxuXHQgKiBjb2RlcyAlIDY1NTM1XG5cdCAqL1xuXHR0aGlzLmNhbGNfY2hlY2tzdW0gPSBmdW5jdGlvbih0ZXh0KSB7XG5cdFx0dmFyIGNoZWNrc3VtID0geyAgczogMCwgYWRkOiBmdW5jdGlvbiAoc2FkZCkgeyB0aGlzLnMgPSAodGhpcy5zICsgc2FkZCkgJSA2NTUzNjsgfX07XG5cdFx0Zm9yICh2YXIgaSA9IDA7IGkgPCB0ZXh0Lmxlbmd0aDsgaSsrKSB7XG5cdFx0XHRjaGVja3N1bS5hZGQodGV4dC5jaGFyQ29kZUF0KGkpKTtcblx0XHR9XG5cdFx0cmV0dXJuIGNoZWNrc3VtLnM7XG5cdH07XG5cdFxuXHQvKipcblx0ICogSGVscGVyIGZ1bmN0aW9uIHRvIHByaW50IGEgZGVidWcgbWVzc2FnZS4gRGVidWcgXG5cdCAqIG1lc3NhZ2VzIGFyZSBvbmx5IHByaW50ZWQgaWZcblx0ICogb3BlbnBncC5jb25maWcuZGVidWcgaXMgc2V0IHRvIHRydWUuIFRoZSBjYWxsaW5nXG5cdCAqIEphdmFzY3JpcHQgY29udGV4dCBNVVNUIGRlZmluZVxuXHQgKiBhIFwic2hvd01lc3NhZ2VzKHRleHQpXCIgZnVuY3Rpb24uIExpbmUgZmVlZHMgKCdcXG4nKVxuXHQgKiBhcmUgYXV0b21hdGljYWxseSBjb252ZXJ0ZWQgdG8gSFRNTCBsaW5lIGZlZWRzICc8YnIvPidcblx0ICogQHBhcmFtIHtTdHJpbmd9IHN0ciBTdHJpbmcgb2YgdGhlIGRlYnVnIG1lc3NhZ2Vcblx0ICogQHJldHVybiB7U3RyaW5nfSBBbiBIVE1MIHR0IGVudGl0eSBjb250YWluaW5nIGEgcGFyYWdyYXBoIHdpdGggYSBcblx0ICogc3R5bGUgYXR0cmlidXRlIHdoZXJlIHRoZSBkZWJ1ZyBtZXNzYWdlIGlzIEhUTUxlbmNvZGVkIGluLiBcblx0ICovXG5cdHRoaXMucHJpbnRfZGVidWcgPSBmdW5jdGlvbihzdHIpIHtcblx0XHRpZiAodGhpcy5kZWJ1Zykge1xuXHRcdFx0Y29uc29sZS5sb2coc3RyKTtcblx0XHR9XG5cdH07XG5cdFxuXHQvKipcblx0ICogSGVscGVyIGZ1bmN0aW9uIHRvIHByaW50IGEgZGVidWcgbWVzc2FnZS4gRGVidWcgXG5cdCAqIG1lc3NhZ2VzIGFyZSBvbmx5IHByaW50ZWQgaWZcblx0ICogb3BlbnBncC5jb25maWcuZGVidWcgaXMgc2V0IHRvIHRydWUuIFRoZSBjYWxsaW5nXG5cdCAqIEphdmFzY3JpcHQgY29udGV4dCBNVVNUIGRlZmluZVxuXHQgKiBhIFwic2hvd01lc3NhZ2VzKHRleHQpXCIgZnVuY3Rpb24uIExpbmUgZmVlZHMgKCdcXG4nKVxuXHQgKiBhcmUgYXV0b21hdGljYWxseSBjb252ZXJ0ZWQgdG8gSFRNTCBsaW5lIGZlZWRzICc8YnIvPidcblx0ICogRGlmZmVyZW50IHRoYW4gcHJpbnRfZGVidWcgYmVjYXVzZSB3aWxsIGNhbGwgaGV4c3RyZHVtcCBpZmYgbmVjZXNzYXJ5LlxuXHQgKiBAcGFyYW0ge1N0cmluZ30gc3RyIFN0cmluZyBvZiB0aGUgZGVidWcgbWVzc2FnZVxuXHQgKiBAcmV0dXJuIHtTdHJpbmd9IEFuIEhUTUwgdHQgZW50aXR5IGNvbnRhaW5pbmcgYSBwYXJhZ3JhcGggd2l0aCBhIFxuXHQgKiBzdHlsZSBhdHRyaWJ1dGUgd2hlcmUgdGhlIGRlYnVnIG1lc3NhZ2UgaXMgSFRNTGVuY29kZWQgaW4uIFxuXHQgKi9cblx0dGhpcy5wcmludF9kZWJ1Z19oZXhzdHJfZHVtcCA9IGZ1bmN0aW9uKHN0cixzdHJUb0hleCkge1xuXHRcdGlmICh0aGlzLmRlYnVnKSB7XG5cdFx0XHRzdHIgPSBzdHIgKyB0aGlzLmhleHN0cmR1bXAoc3RyVG9IZXgpO1xuXHRcdFx0Y29uc29sZS5sb2coc3RyKTtcblx0XHR9XG5cdH07XG5cdFxuXHQvKipcblx0ICogSGVscGVyIGZ1bmN0aW9uIHRvIHByaW50IGFuIGVycm9yIG1lc3NhZ2UuIFxuXHQgKiBUaGUgY2FsbGluZyBKYXZhc2NyaXB0IGNvbnRleHQgTVVTVCBkZWZpbmVcblx0ICogYSBcInNob3dNZXNzYWdlcyh0ZXh0KVwiIGZ1bmN0aW9uLiBMaW5lIGZlZWRzICgnXFxuJylcblx0ICogYXJlIGF1dG9tYXRpY2FsbHkgY29udmVydGVkIHRvIEhUTUwgbGluZSBmZWVkcyAnPGJyLz4nXG5cdCAqIEBwYXJhbSB7U3RyaW5nfSBzdHIgU3RyaW5nIG9mIHRoZSBlcnJvciBtZXNzYWdlXG5cdCAqIEByZXR1cm4ge1N0cmluZ30gQSBIVE1MIHBhcmFncmFwaCBlbnRpdHkgd2l0aCBhIHN0eWxlIGF0dHJpYnV0ZSBcblx0ICogY29udGFpbmluZyB0aGUgSFRNTCBlbmNvZGVkIGVycm9yIG1lc3NhZ2Vcblx0ICovXG5cdHRoaXMucHJpbnRfZXJyb3IgPSBmdW5jdGlvbihzdHIpIHtcblx0XHRpZih0aGlzLmRlYnVnKVxuXHRcdFx0dGhyb3cgc3RyO1xuXHRcdGNvbnNvbGUubG9nKHN0cik7XG5cdH07XG5cdFxuXHQvKipcblx0ICogSGVscGVyIGZ1bmN0aW9uIHRvIHByaW50IGFuIGluZm8gbWVzc2FnZS4gXG5cdCAqIFRoZSBjYWxsaW5nIEphdmFzY3JpcHQgY29udGV4dCBNVVNUIGRlZmluZVxuXHQgKiBhIFwic2hvd01lc3NhZ2VzKHRleHQpXCIgZnVuY3Rpb24uIExpbmUgZmVlZHMgKCdcXG4nKVxuXHQgKiBhcmUgYXV0b21hdGljYWxseSBjb252ZXJ0ZWQgdG8gSFRNTCBsaW5lIGZlZWRzICc8YnIvPicuXG5cdCAqIEBwYXJhbSB7U3RyaW5nfSBzdHIgU3RyaW5nIG9mIHRoZSBpbmZvIG1lc3NhZ2Vcblx0ICogQHJldHVybiB7U3RyaW5nfSBBIEhUTUwgcGFyYWdyYXBoIGVudGl0eSB3aXRoIGEgc3R5bGUgYXR0cmlidXRlIFxuXHQgKiBjb250YWluaW5nIHRoZSBIVE1MIGVuY29kZWQgaW5mbyBtZXNzYWdlXG5cdCAqL1xuXHR0aGlzLnByaW50X2luZm8gPSBmdW5jdGlvbihzdHIpIHtcblx0XHRpZih0aGlzLmRlYnVnKVxuXHRcdFx0Y29uc29sZS5sb2coc3RyKTtcblx0fTtcblx0XG5cdHRoaXMucHJpbnRfd2FybmluZyA9IGZ1bmN0aW9uKHN0cikge1xuXHRcdGNvbnNvbGUubG9nKHN0cik7XG5cdH07XG5cdFxuXHR0aGlzLmdldExlZnROQml0cyA9IGZ1bmN0aW9uIChzdHJpbmcsIGJpdGNvdW50KSB7XG5cdFx0dmFyIHJlc3QgPSBiaXRjb3VudCAlIDg7XG5cdFx0aWYgKHJlc3QgPT0gMClcblx0XHRcdHJldHVybiBzdHJpbmcuc3Vic3RyaW5nKDAsIGJpdGNvdW50IC8gOCk7XG5cdFx0dmFyIGJ5dGVzID0gKGJpdGNvdW50IC0gcmVzdCkgLyA4ICsxO1xuXHRcdHZhciByZXN1bHQgPSBzdHJpbmcuc3Vic3RyaW5nKDAsIGJ5dGVzKTtcblx0XHRyZXR1cm4gdGhpcy5zaGlmdFJpZ2h0KHJlc3VsdCwgOC1yZXN0KTsgLy8gK1N0cmluZy5mcm9tQ2hhckNvZGUoc3RyaW5nLmNoYXJDb2RlQXQoYnl0ZXMgLTEpIDw8ICg4LXJlc3QpICYgMHhGRik7XG5cdH07XG5cblx0LyoqXG5cdCAqIFNoaWZ0aW5nIGEgc3RyaW5nIHRvIG4gYml0cyByaWdodFxuXHQgKiBAcGFyYW0ge1N0cmluZ30gdmFsdWUgVGhlIHN0cmluZyB0byBzaGlmdFxuXHQgKiBAcGFyYW0ge0ludGVnZXJ9IGJpdGNvdW50IEFtb3VudCBvZiBiaXRzIHRvIHNoaWZ0IChNVVNUIGJlIHNtYWxsZXIgXG5cdCAqIHRoYW4gOSlcblx0ICogQHJldHVybiB7U3RyaW5nfSBSZXN1bHRpbmcgc3RyaW5nLiBcblx0ICovXG5cdHRoaXMuc2hpZnRSaWdodCA9IGZ1bmN0aW9uKHZhbHVlLCBiaXRjb3VudCkge1xuXHRcdHZhciB0ZW1wID0gdXRpbC5zdHIyYmluKHZhbHVlKTtcbiAgICAgICAgaWYgKGJpdGNvdW50ICUgOCAhPSAwKSB7XG4gICAgICAgIFx0Zm9yICh2YXIgaSA9IHRlbXAubGVuZ3RoLTE7IGkgPj0gMDsgaS0tKSB7XG4gICAgICAgIFx0XHR0ZW1wW2ldID4+PSBiaXRjb3VudCAlIDg7XG4gICAgICAgIFx0XHRpZiAoaSA+IDApXG4gICAgICAgIFx0XHRcdHRlbXBbaV0gfD0gKHRlbXBbaSAtIDFdIDw8ICg4IC0gKGJpdGNvdW50ICUgOCkpKSAmIDB4RkY7XG4gICAgICAgIFx0fVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICBcdHJldHVybiB2YWx1ZTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdXRpbC5iaW4yc3RyKHRlbXApO1xuXHR9O1xuXHRcblx0LyoqXG5cdCAqIFJldHVybiB0aGUgYWxnb3JpdGhtIHR5cGUgYXMgc3RyaW5nXG5cdCAqIEByZXR1cm4ge1N0cmluZ30gU3RyaW5nIHJlcHJlc2VudGluZyB0aGUgbWVzc2FnZSB0eXBlXG5cdCAqL1xuXHR0aGlzLmdldF9oYXNoQWxnb3JpdGhtU3RyaW5nID0gZnVuY3Rpb24oYWxnbykge1xuXHRcdHN3aXRjaChhbGdvKSB7XG5cdFx0Y2FzZSAxOlxuXHRcdFx0cmV0dXJuIFwiTUQ1XCI7XG5cdFx0Y2FzZSAyOlxuXHRcdFx0cmV0dXJuIFwiU0hBMVwiO1xuXHRcdGNhc2UgMzpcblx0XHRcdHJldHVybiBcIlJJUEVNRDE2MFwiO1xuXHRcdGNhc2UgODpcblx0XHRcdHJldHVybiBcIlNIQTI1NlwiO1xuXHRcdGNhc2UgOTpcblx0XHRcdHJldHVybiBcIlNIQTM4NFwiO1xuXHRcdGNhc2UgMTA6XG5cdFx0XHRyZXR1cm4gXCJTSEE1MTJcIjtcblx0XHRjYXNlIDExOlxuXHRcdFx0cmV0dXJuIFwiU0hBMjI0XCI7XG5cdFx0fVxuXHRcdHJldHVybiBcInVua25vd25cIjtcblx0fTtcbn07XG5cbi8qKlxuICogYW4gaW5zdGFuY2UgdGhhdCBzaG91bGQgYmUgdXNlZC4gXG4gKi9cbm1vZHVsZS5leHBvcnRzID0gbmV3IFV0aWwoKTtcbiIsIm1vZHVsZS5leHBvcnRzID0ge1xuXG5cblx0LyoqIEEgc3RyaW5nIHRvIGtleSBzcGVjaWZpZXIgdHlwZVxuXHQgKiBAZW51bSB7SW50ZWdlcn1cblx0ICovXG5cdHMyazoge1xuXHRcdHNpbXBsZTogMCxcblx0XHRzYWx0ZWQ6IDEsXG5cdFx0aXRlcmF0ZWQ6IDMsXG5cdFx0Z251OiAxMDFcblx0fSxcblxuXHQvKiogUkZDNDg4MCwgc2VjdGlvbiA5LjEgXG5cdCAqIEBlbnVtIHtTdHJpbmd9XG5cdCAqL1xuXHRwdWJsaWNLZXk6IHtcblx0XHRyc2FfZW5jcnlwdF9zaWduOiAxLFxuXHRcdHJzYV9lbmNyeXB0OiAyLFxuXHRcdHJzYV9zaWduOiAzLFxuXHRcdGVsZ2FtYWw6IDE2LFxuXHRcdGRzYTogMTdcblx0fSxcblxuXHQvKiogUkZDNDg4MCwgc2VjdGlvbiA5LjIgXG5cdCAqIEBlbnVtIHtTdHJpbmd9XG5cdCAqL1xuXHRzeW1tZXRyaWM6IHtcblx0XHRwbGFpbnRleHQ6IDAsXG5cdFx0LyoqIE5vdCBpbXBsZW1lbnRlZCEgKi9cblx0XHRpZGVhOiAxLFxuXHRcdHRyaXBsZWRlczogMixcblx0XHRjYXN0NTogMyxcblx0XHRibG93ZmlzaDogNCxcblx0XHRhZXMxMjg6IDcsXG5cdFx0YWVzMTkyOiA4LFxuXHRcdGFlczI1NjogOSxcblx0XHR0d29maXNoOiAxMFxuXHR9LFxuXG5cdC8qKiBSRkM0ODgwLCBzZWN0aW9uIDkuM1xuXHQgKiBAZW51bSB7U3RyaW5nfVxuXHQgKi9cblx0Y29tcHJlc3Npb246IHtcblx0XHR1bmNvbXByZXNzZWQ6IDAsXG5cdFx0LyoqIFJGQzE5NTEgKi9cblx0XHR6aXA6IDEsXG5cdFx0LyoqIFJGQzE5NTAgKi9cblx0XHR6bGliOiAyLFxuXHRcdGJ6aXAyOiAzXG5cdH0sXG5cblx0LyoqIFJGQzQ4ODAsIHNlY3Rpb24gOS40XG5cdCAqIEBlbnVtIHtTdHJpbmd9XG5cdCAqL1xuXHRoYXNoOiB7XG5cdFx0bWQ1OiAxLFxuXHRcdHNoYTE6IDIsXG5cdFx0cmlwZW1kOiAzLFxuXHRcdHNoYTI1NjogOCxcblx0XHRzaGEzODQ6IDksXG5cdFx0c2hhNTEyOiAxMCxcblx0XHRzaGEyMjQ6IDExXG5cdH0sXG5cblxuXHQvKipcblx0ICogQGVudW0ge1N0cmluZ31cblx0ICogQSBsaXN0IG9mIHBhY2tldCB0eXBlcyBhbmQgbnVtZXJpYyB0YWdzIGFzc29jaWF0ZWQgd2l0aCB0aGVtLlxuXHQgKi9cblx0cGFja2V0OiB7XG5cdFx0cHVibGljX2tleV9lbmNyeXB0ZWRfc2Vzc2lvbl9rZXk6IDEsXG5cdFx0c2lnbmF0dXJlOiAyLFxuXHRcdHN5bV9lbmNyeXB0ZWRfc2Vzc2lvbl9rZXk6IDMsXG5cdFx0b25lX3Bhc3Nfc2lnbmF0dXJlOiA0LFxuXHRcdHNlY3JldF9rZXk6IDUsXG5cdFx0cHVibGljX2tleTogNixcblx0XHRzZWNyZXRfc3Via2V5OiA3LFxuXHRcdGNvbXByZXNzZWQ6IDgsXG5cdFx0c3ltbWV0cmljYWxseV9lbmNyeXB0ZWQ6IDksXG5cdFx0bWFya2VyOiAxMCxcblx0XHRsaXRlcmFsOiAxMSxcblx0XHR0cnVzdDogMTIsXG5cdFx0dXNlcmlkOiAxMyxcblx0XHRwdWJsaWNfc3Via2V5OiAxNCxcblx0XHR1c2VyX2F0dHJpYnV0ZTogMTcsXG5cdFx0c3ltX2VuY3J5cHRlZF9pbnRlZ3JpdHlfcHJvdGVjdGVkOiAxOCxcblx0XHRtb2RpZmljYXRpb25fZGV0ZWN0aW9uX2NvZGU6IDE5XG5cdH0sXG5cblxuXHQvKipcblx0ICogRGF0YSB0eXBlcyBpbiB0aGUgbGl0ZXJhbCBwYWNrZXRcblx0ICogQHJlYWRvbmx5XG5cdCAqIEBlbnVtIHtTdHJpbmd9XG5cdCAqL1xuXHRsaXRlcmFsOiB7XG5cdFx0LyoqIEJpbmFyeSBkYXRhICovXG5cdFx0YmluYXJ5OiAnYicuY2hhckNvZGVBdCgpLFxuXHRcdC8qKiBUZXh0IGRhdGEgKi9cblx0XHR0ZXh0OiAndCcuY2hhckNvZGVBdCgpLFxuXHRcdC8qKiBVdGY4IGRhdGEgKi9cblx0XHR1dGY4OiAndScuY2hhckNvZGVBdCgpXG5cdH0sXG5cblxuXHQvKiogT25lIHBhc3Mgc2lnbmF0dXJlIHBhY2tldCB0eXBlXG5cdCAqIEBlbnVtIHtTdHJpbmd9ICovXG5cdHNpZ25hdHVyZToge1xuXHRcdC8qKiAweDAwOiBTaWduYXR1cmUgb2YgYSBiaW5hcnkgZG9jdW1lbnQuICovXG5cdFx0YmluYXJ5OiAwLFxuXHRcdC8qKiAweDAxOiBTaWduYXR1cmUgb2YgYSBjYW5vbmljYWwgdGV4dCBkb2N1bWVudC5cblx0XHQgKiBDYW5vbmljYWx5emluZyB0aGUgZG9jdW1lbnQgYnkgY29udmVydGluZyBsaW5lIGVuZGluZ3MuICovXG5cdFx0dGV4dDogMSxcblx0XHQvKiogMHgwMjogU3RhbmRhbG9uZSBzaWduYXR1cmUuXG5cdFx0KiBUaGlzIHNpZ25hdHVyZSBpcyBhIHNpZ25hdHVyZSBvZiBvbmx5IGl0cyBvd24gc3VicGFja2V0IGNvbnRlbnRzLlxuXHRcdCogSXQgaXMgY2FsY3VsYXRlZCBpZGVudGljYWxseSB0byBhIHNpZ25hdHVyZSBvdmVyIGEgemVyby1sZW5naFxuXHRcdCogYmluYXJ5IGRvY3VtZW50LiAgTm90ZSB0aGF0IGl0IGRvZXNuJ3QgbWFrZSBzZW5zZSB0byBoYXZlIGEgVjNcblx0XHQqIHN0YW5kYWxvbmUgc2lnbmF0dXJlLiAqL1xuXHRcdHN0YW5kYWxvbmU6IDIsXG5cdFx0LyoqIDB4MTA6IEdlbmVyaWMgY2VydGlmaWNhdGlvbiBvZiBhIFVzZXIgSUQgYW5kIFB1YmxpYy1LZXkgcGFja2V0LlxuXHRcdCogVGhlIGlzc3VlciBvZiB0aGlzIGNlcnRpZmljYXRpb24gZG9lcyBub3QgbWFrZSBhbnkgcGFydGljdWxhclxuXHRcdCogYXNzZXJ0aW9uIGFzIHRvIGhvdyB3ZWxsIHRoZSBjZXJ0aWZpZXIgaGFzIGNoZWNrZWQgdGhhdCB0aGUgb3duZXJcblx0XHQqIG9mIHRoZSBrZXkgaXMgaW4gZmFjdCB0aGUgcGVyc29uIGRlc2NyaWJlZCBieSB0aGUgVXNlciBJRC4gKi9cblx0XHRjZXJ0X2dlbmVyaWM6IDE2LFxuXHRcdC8qKiAweDExOiBQZXJzb25hIGNlcnRpZmljYXRpb24gb2YgYSBVc2VyIElEIGFuZCBQdWJsaWMtS2V5IHBhY2tldC5cblx0XHQqIFRoZSBpc3N1ZXIgb2YgdGhpcyBjZXJ0aWZpY2F0aW9uIGhhcyBub3QgZG9uZSBhbnkgdmVyaWZpY2F0aW9uIG9mXG5cdFx0KiB0aGUgY2xhaW0gdGhhdCB0aGUgb3duZXIgb2YgdGhpcyBrZXkgaXMgdGhlIFVzZXIgSUQgc3BlY2lmaWVkLiAqL1xuXHRcdGNlcnRfcGVyc29uYTogMTcsXG5cdFx0LyoqIDB4MTI6IENhc3VhbCBjZXJ0aWZpY2F0aW9uIG9mIGEgVXNlciBJRCBhbmQgUHVibGljLUtleSBwYWNrZXQuXG5cdFx0KiBUaGUgaXNzdWVyIG9mIHRoaXMgY2VydGlmaWNhdGlvbiBoYXMgZG9uZSBzb21lIGNhc3VhbFxuXHRcdCogdmVyaWZpY2F0aW9uIG9mIHRoZSBjbGFpbSBvZiBpZGVudGl0eS4gKi9cblx0XHRjZXJ0X2Nhc3VhbDogMTgsXG5cdFx0LyoqIDB4MTM6IFBvc2l0aXZlIGNlcnRpZmljYXRpb24gb2YgYSBVc2VyIElEIGFuZCBQdWJsaWMtS2V5IHBhY2tldC5cblx0XHQqIFRoZSBpc3N1ZXIgb2YgdGhpcyBjZXJ0aWZpY2F0aW9uIGhhcyBkb25lIHN1YnN0YW50aWFsXG5cdFx0KiB2ZXJpZmljYXRpb24gb2YgdGhlIGNsYWltIG9mIGlkZW50aXR5LlxuXHRcdCogXG5cdFx0KiBNb3N0IE9wZW5QR1AgaW1wbGVtZW50YXRpb25zIG1ha2UgdGhlaXIgXCJrZXkgc2lnbmF0dXJlc1wiIGFzIDB4MTBcblx0XHQqIGNlcnRpZmljYXRpb25zLiAgU29tZSBpbXBsZW1lbnRhdGlvbnMgY2FuIGlzc3VlIDB4MTEtMHgxM1xuXHRcdCogY2VydGlmaWNhdGlvbnMsIGJ1dCBmZXcgZGlmZmVyZW50aWF0ZSBiZXR3ZWVuIHRoZSB0eXBlcy4gKi9cblx0XHRjZXJ0X3Bvc2l0aXZlOiAxOSxcblx0XHQvKiogMHgzMDogQ2VydGlmaWNhdGlvbiByZXZvY2F0aW9uIHNpZ25hdHVyZVxuXHRcdCogVGhpcyBzaWduYXR1cmUgcmV2b2tlcyBhbiBlYXJsaWVyIFVzZXIgSUQgY2VydGlmaWNhdGlvbiBzaWduYXR1cmVcblx0XHQqIChzaWduYXR1cmUgY2xhc3MgMHgxMCB0aHJvdWdoIDB4MTMpIG9yIGRpcmVjdC1rZXkgc2lnbmF0dXJlXG5cdFx0KiAoMHgxRikuICBJdCBzaG91bGQgYmUgaXNzdWVkIGJ5IHRoZSBzYW1lIGtleSB0aGF0IGlzc3VlZCB0aGVcblx0XHQqIHJldm9rZWQgc2lnbmF0dXJlIG9yIGFuIGF1dGhvcml6ZWQgcmV2b2NhdGlvbiBrZXkuICBUaGUgc2lnbmF0dXJlXG5cdFx0KiBpcyBjb21wdXRlZCBvdmVyIHRoZSBzYW1lIGRhdGEgYXMgdGhlIGNlcnRpZmljYXRlIHRoYXQgaXRcblx0XHQqIHJldm9rZXMsIGFuZCBzaG91bGQgaGF2ZSBhIGxhdGVyIGNyZWF0aW9uIGRhdGUgdGhhbiB0aGF0XG5cdFx0KiBjZXJ0aWZpY2F0ZS4gKi9cblx0XHRjZXJ0X3Jldm9jYXRpb246IDQ4LFxuXHRcdC8qKiAweDE4OiBTdWJrZXkgQmluZGluZyBTaWduYXR1cmVcblx0XHQqIFRoaXMgc2lnbmF0dXJlIGlzIGEgc3RhdGVtZW50IGJ5IHRoZSB0b3AtbGV2ZWwgc2lnbmluZyBrZXkgdGhhdFxuXHRcdCogaW5kaWNhdGVzIHRoYXQgaXQgb3ducyB0aGUgc3Via2V5LiAgVGhpcyBzaWduYXR1cmUgaXMgY2FsY3VsYXRlZFxuXHRcdCogZGlyZWN0bHkgb24gdGhlIHByaW1hcnkga2V5IGFuZCBzdWJrZXksIGFuZCBub3Qgb24gYW55IFVzZXIgSUQgb3Jcblx0XHQqIG90aGVyIHBhY2tldHMuICBBIHNpZ25hdHVyZSB0aGF0IGJpbmRzIGEgc2lnbmluZyBzdWJrZXkgTVVTVCBoYXZlXG5cdFx0KiBhbiBFbWJlZGRlZCBTaWduYXR1cmUgc3VicGFja2V0IGluIHRoaXMgYmluZGluZyBzaWduYXR1cmUgdGhhdFxuXHRcdCogY29udGFpbnMgYSAweDE5IHNpZ25hdHVyZSBtYWRlIGJ5IHRoZSBzaWduaW5nIHN1YmtleSBvbiB0aGVcblx0XHQqIHByaW1hcnkga2V5IGFuZCBzdWJrZXkuICovXG5cdFx0c3Via2V5X2JpbmRpbmc6IDI0LFxuXHRcdC8qKiAweDE5OiBQcmltYXJ5IEtleSBCaW5kaW5nIFNpZ25hdHVyZVxuXHRcdCogVGhpcyBzaWduYXR1cmUgaXMgYSBzdGF0ZW1lbnQgYnkgYSBzaWduaW5nIHN1YmtleSwgaW5kaWNhdGluZ1xuXHRcdCogdGhhdCBpdCBpcyBvd25lZCBieSB0aGUgcHJpbWFyeSBrZXkgYW5kIHN1YmtleS4gIFRoaXMgc2lnbmF0dXJlXG5cdFx0KiBpcyBjYWxjdWxhdGVkIHRoZSBzYW1lIHdheSBhcyBhIDB4MTggc2lnbmF0dXJlOiBkaXJlY3RseSBvbiB0aGVcblx0XHQqIHByaW1hcnkga2V5IGFuZCBzdWJrZXksIGFuZCBub3Qgb24gYW55IFVzZXIgSUQgb3Igb3RoZXIgcGFja2V0cy5cblx0XHRcblx0XHQqIFdoZW4gYSBzaWduYXR1cmUgaXMgbWFkZSBvdmVyIGEga2V5LCB0aGUgaGFzaCBkYXRhIHN0YXJ0cyB3aXRoIHRoZVxuXHRcdCogb2N0ZXQgMHg5OSwgZm9sbG93ZWQgYnkgYSB0d28tb2N0ZXQgbGVuZ3RoIG9mIHRoZSBrZXksIGFuZCB0aGVuIGJvZHlcblx0XHQqIG9mIHRoZSBrZXkgcGFja2V0LiAgKE5vdGUgdGhhdCB0aGlzIGlzIGFuIG9sZC1zdHlsZSBwYWNrZXQgaGVhZGVyIGZvclxuXHRcdCogYSBrZXkgcGFja2V0IHdpdGggdHdvLW9jdGV0IGxlbmd0aC4pICBBIHN1YmtleSBiaW5kaW5nIHNpZ25hdHVyZVxuXHRcdCogKHR5cGUgMHgxOCkgb3IgcHJpbWFyeSBrZXkgYmluZGluZyBzaWduYXR1cmUgKHR5cGUgMHgxOSkgdGhlbiBoYXNoZXNcblx0XHQqIHRoZSBzdWJrZXkgdXNpbmcgdGhlIHNhbWUgZm9ybWF0IGFzIHRoZSBtYWluIGtleSAoYWxzbyB1c2luZyAweDk5IGFzXG5cdFx0KiB0aGUgZmlyc3Qgb2N0ZXQpLiAqL1xuXHRcdGtleV9iaW5kaW5nOiAyNSxcblx0XHQvKiogMHgxRjogU2lnbmF0dXJlIGRpcmVjdGx5IG9uIGEga2V5XG5cdFx0KiBUaGlzIHNpZ25hdHVyZSBpcyBjYWxjdWxhdGVkIGRpcmVjdGx5IG9uIGEga2V5LiAgSXQgYmluZHMgdGhlXG5cdFx0KiBpbmZvcm1hdGlvbiBpbiB0aGUgU2lnbmF0dXJlIHN1YnBhY2tldHMgdG8gdGhlIGtleSwgYW5kIGlzXG5cdFx0KiBhcHByb3ByaWF0ZSB0byBiZSB1c2VkIGZvciBzdWJwYWNrZXRzIHRoYXQgcHJvdmlkZSBpbmZvcm1hdGlvblxuXHRcdCogYWJvdXQgdGhlIGtleSwgc3VjaCBhcyB0aGUgUmV2b2NhdGlvbiBLZXkgc3VicGFja2V0LiAgSXQgaXMgYWxzb1xuXHRcdCogYXBwcm9wcmlhdGUgZm9yIHN0YXRlbWVudHMgdGhhdCBub24tc2VsZiBjZXJ0aWZpZXJzIHdhbnQgdG8gbWFrZVxuXHRcdCogYWJvdXQgdGhlIGtleSBpdHNlbGYsIHJhdGhlciB0aGFuIHRoZSBiaW5kaW5nIGJldHdlZW4gYSBrZXkgYW5kIGFcblx0XHQqIG5hbWUuICovXG5cdFx0a2V5OiAzMSxcblx0XHQvKiogMHgyMDogS2V5IHJldm9jYXRpb24gc2lnbmF0dXJlXG5cdFx0KiBUaGUgc2lnbmF0dXJlIGlzIGNhbGN1bGF0ZWQgZGlyZWN0bHkgb24gdGhlIGtleSBiZWluZyByZXZva2VkLiAgQVxuXHRcdCogcmV2b2tlZCBrZXkgaXMgbm90IHRvIGJlIHVzZWQuICBPbmx5IHJldm9jYXRpb24gc2lnbmF0dXJlcyBieSB0aGVcblx0XHQqIGtleSBiZWluZyByZXZva2VkLCBvciBieSBhbiBhdXRob3JpemVkIHJldm9jYXRpb24ga2V5LCBzaG91bGQgYmVcblx0XHQqIGNvbnNpZGVyZWQgdmFsaWQgcmV2b2NhdGlvbiBzaWduYXR1cmVzLmEgKi9cblx0XHRrZXlfcmV2b2NhdGlvbjogMzIsXG5cdFx0LyoqIDB4Mjg6IFN1YmtleSByZXZvY2F0aW9uIHNpZ25hdHVyZVxuXHRcdCogVGhlIHNpZ25hdHVyZSBpcyBjYWxjdWxhdGVkIGRpcmVjdGx5IG9uIHRoZSBzdWJrZXkgYmVpbmcgcmV2b2tlZC5cblx0XHQqIEEgcmV2b2tlZCBzdWJrZXkgaXMgbm90IHRvIGJlIHVzZWQuICBPbmx5IHJldm9jYXRpb24gc2lnbmF0dXJlc1xuXHRcdCogYnkgdGhlIHRvcC1sZXZlbCBzaWduYXR1cmUga2V5IHRoYXQgaXMgYm91bmQgdG8gdGhpcyBzdWJrZXksIG9yXG5cdFx0KiBieSBhbiBhdXRob3JpemVkIHJldm9jYXRpb24ga2V5LCBzaG91bGQgYmUgY29uc2lkZXJlZCB2YWxpZFxuXHRcdCogcmV2b2NhdGlvbiBzaWduYXR1cmVzLlxuXHRcdCogS2V5IHJldm9jYXRpb24gc2lnbmF0dXJlcyAodHlwZXMgMHgyMCBhbmQgMHgyOClcblx0XHQqIGhhc2ggb25seSB0aGUga2V5IGJlaW5nIHJldm9rZWQuICovXG5cdFx0c3Via2V5X3Jldm9jYXRpb246IDQwLFxuXHRcdC8qKiAweDQwOiBUaW1lc3RhbXAgc2lnbmF0dXJlLlxuXHRcdCogVGhpcyBzaWduYXR1cmUgaXMgb25seSBtZWFuaW5nZnVsIGZvciB0aGUgdGltZXN0YW1wIGNvbnRhaW5lZCBpblxuXHRcdCogaXQuICovXG5cdFx0dGltZXN0YW1wOiA2NCxcblx0XHQvKiogICAgMHg1MDogVGhpcmQtUGFydHkgQ29uZmlybWF0aW9uIHNpZ25hdHVyZS5cblx0XHQqIFRoaXMgc2lnbmF0dXJlIGlzIGEgc2lnbmF0dXJlIG92ZXIgc29tZSBvdGhlciBPcGVuUEdQIFNpZ25hdHVyZVxuXHRcdCogcGFja2V0KHMpLiAgSXQgaXMgYW5hbG9nb3VzIHRvIGEgbm90YXJ5IHNlYWwgb24gdGhlIHNpZ25lZCBkYXRhLlxuXHRcdCogQSB0aGlyZC1wYXJ0eSBzaWduYXR1cmUgU0hPVUxEIGluY2x1ZGUgU2lnbmF0dXJlIFRhcmdldFxuXHRcdCogc3VicGFja2V0KHMpIHRvIGdpdmUgZWFzeSBpZGVudGlmaWNhdGlvbi4gIE5vdGUgdGhhdCB3ZSByZWFsbHkgZG9cblx0XHQqIG1lYW4gU0hPVUxELiAgVGhlcmUgYXJlIHBsYXVzaWJsZSB1c2VzIGZvciB0aGlzIChzdWNoIGFzIGEgYmxpbmRcblx0XHQqIHBhcnR5IHRoYXQgb25seSBzZWVzIHRoZSBzaWduYXR1cmUsIG5vdCB0aGUga2V5IG9yIHNvdXJjZVxuXHRcdCogZG9jdW1lbnQpIHRoYXQgY2Fubm90IGluY2x1ZGUgYSB0YXJnZXQgc3VicGFja2V0LiAqL1xuXHRcdHRoaXJkX3BhcnR5OiA4MFxuXHR9LFxuXG5cdC8vIEFzc2VydHMgdmFsaWRpdHkgYW5kIGNvbnZlcnRzIGZyb20gc3RyaW5nL2ludGVnZXIgdG8gaW50ZWdlci5cblx0d3JpdGU6IGZ1bmN0aW9uKHR5cGUsIGUpIHtcblx0XHRpZih0eXBlb2YgZSA9PSAnbnVtYmVyJykge1xuXHRcdFx0ZSA9IHRoaXMucmVhZCh0eXBlLCBlKTtcblx0XHR9XG5cdFx0XG5cdFx0aWYodHlwZVtlXSAhPSB1bmRlZmluZWQpIHtcblx0XHRcdHJldHVybiB0eXBlW2VdO1xuXHRcdH0gZWxzZSB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgZW51bSB2YWx1ZS4nKTtcblx0fSxcblx0Ly8gQ29udmVydHMgZnJvbSBhbiBpbnRlZ2VyIHRvIHN0cmluZy5cblx0cmVhZDogZnVuY3Rpb24odHlwZSwgZSkge1xuXHRcdGZvcih2YXIgaSBpbiB0eXBlKVxuXHRcdFx0aWYodHlwZVtpXSA9PSBlKSByZXR1cm4gaTtcblxuXHRcdHRocm93IG5ldyBFcnJvcignSW52YWxpZCBlbnVtIHZhbHVlLicpO1xuXHR9XG59XG5cblxuXG5cbiIsIi8qIE9wZW5QR1AgcmFkaXgtNjQvYmFzZTY0IHN0cmluZyBlbmNvZGluZy9kZWNvZGluZ1xyXG4gKiBDb3B5cmlnaHQgMjAwNSBIZXJiZXJ0IEhhbmV3aW5rZWwsIHd3dy5oYW5lV0lOLmRlXHJcbiAqIHZlcnNpb24gMS4wLCBjaGVjayB3d3cuaGFuZVdJTi5kZSBmb3IgdGhlIGxhdGVzdCB2ZXJzaW9uXHJcbiAqXHJcbiAqIFRoaXMgc29mdHdhcmUgaXMgcHJvdmlkZWQgYXMtaXMsIHdpdGhvdXQgZXhwcmVzcyBvciBpbXBsaWVkIHdhcnJhbnR5LiAgXHJcbiAqIFBlcm1pc3Npb24gdG8gdXNlLCBjb3B5LCBtb2RpZnksIGRpc3RyaWJ1dGUgb3Igc2VsbCB0aGlzIHNvZnR3YXJlLCB3aXRoIG9yXHJcbiAqIHdpdGhvdXQgZmVlLCBmb3IgYW55IHB1cnBvc2UgYW5kIGJ5IGFueSBpbmRpdmlkdWFsIG9yIG9yZ2FuaXphdGlvbiwgaXMgaGVyZWJ5XHJcbiAqIGdyYW50ZWQsIHByb3ZpZGVkIHRoYXQgdGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGFyYWdyYXBoIGFwcGVhciBcclxuICogaW4gYWxsIGNvcGllcy4gRGlzdHJpYnV0aW9uIGFzIGEgcGFydCBvZiBhbiBhcHBsaWNhdGlvbiBvciBiaW5hcnkgbXVzdFxyXG4gKiBpbmNsdWRlIHRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGluIHRoZSBkb2N1bWVudGF0aW9uIGFuZC9vciBvdGhlciBtYXRlcmlhbHNcclxuICogcHJvdmlkZWQgd2l0aCB0aGUgYXBwbGljYXRpb24gb3IgZGlzdHJpYnV0aW9uLlxyXG4gKi9cclxuXHJcbnZhciBiNjRzID0gJ0FCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5Ky8nO1xyXG5cclxuZnVuY3Rpb24gczJyKHQpIHtcclxuXHR2YXIgYSwgYywgbjtcclxuXHR2YXIgciA9ICcnLCBsID0gMCwgcyA9IDA7XHJcblx0dmFyIHRsID0gdC5sZW5ndGg7XHJcblxyXG5cdGZvciAobiA9IDA7IG4gPCB0bDsgbisrKSB7XHJcblx0XHRjID0gdC5jaGFyQ29kZUF0KG4pO1xyXG5cdFx0aWYgKHMgPT0gMCkge1xyXG5cdFx0XHRyICs9IGI2NHMuY2hhckF0KChjID4+IDIpICYgNjMpO1xyXG5cdFx0XHRhID0gKGMgJiAzKSA8PCA0O1xyXG5cdFx0fSBlbHNlIGlmIChzID09IDEpIHtcclxuXHRcdFx0ciArPSBiNjRzLmNoYXJBdCgoYSB8IChjID4+IDQpICYgMTUpKTtcclxuXHRcdFx0YSA9IChjICYgMTUpIDw8IDI7XHJcblx0XHR9IGVsc2UgaWYgKHMgPT0gMikge1xyXG5cdFx0XHRyICs9IGI2NHMuY2hhckF0KGEgfCAoKGMgPj4gNikgJiAzKSk7XHJcblx0XHRcdGwgKz0gMTtcclxuXHRcdFx0aWYgKChsICUgNjApID09IDApXHJcblx0XHRcdFx0ciArPSBcIlxcblwiO1xyXG5cdFx0XHRyICs9IGI2NHMuY2hhckF0KGMgJiA2Myk7XHJcblx0XHR9XHJcblx0XHRsICs9IDE7XHJcblx0XHRpZiAoKGwgJSA2MCkgPT0gMClcclxuXHRcdFx0ciArPSBcIlxcblwiO1xyXG5cclxuXHRcdHMgKz0gMTtcclxuXHRcdGlmIChzID09IDMpXHJcblx0XHRcdHMgPSAwO1xyXG5cdH1cclxuXHRpZiAocyA+IDApIHtcclxuXHRcdHIgKz0gYjY0cy5jaGFyQXQoYSk7XHJcblx0XHRsICs9IDE7XHJcblx0XHRpZiAoKGwgJSA2MCkgPT0gMClcclxuXHRcdFx0ciArPSBcIlxcblwiO1xyXG5cdFx0ciArPSAnPSc7XHJcblx0XHRsICs9IDE7XHJcblx0fVxyXG5cdGlmIChzID09IDEpIHtcclxuXHRcdGlmICgobCAlIDYwKSA9PSAwKVxyXG5cdFx0XHRyICs9IFwiXFxuXCI7XHJcblx0XHRyICs9ICc9JztcclxuXHR9XHJcblxyXG5cdHJldHVybiByO1xyXG59XHJcblxyXG5mdW5jdGlvbiByMnModCkge1xyXG5cdHZhciBjLCBuO1xyXG5cdHZhciByID0gJycsIHMgPSAwLCBhID0gMDtcclxuXHR2YXIgdGwgPSB0Lmxlbmd0aDtcclxuXHJcblx0Zm9yIChuID0gMDsgbiA8IHRsOyBuKyspIHtcclxuXHRcdGMgPSBiNjRzLmluZGV4T2YodC5jaGFyQXQobikpO1xyXG5cdFx0aWYgKGMgPj0gMCkge1xyXG5cdFx0XHRpZiAocylcclxuXHRcdFx0XHRyICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoYSB8IChjID4+ICg2IC0gcykpICYgMjU1KTtcclxuXHRcdFx0cyA9IChzICsgMikgJiA3O1xyXG5cdFx0XHRhID0gKGMgPDwgcykgJiAyNTU7XHJcblx0XHR9XHJcblx0fVxyXG5cdHJldHVybiByO1xyXG59XHJcblxyXG5tb2R1bGUuZXhwb3J0cyA9IHtcclxuXHRlbmNvZGU6IHMycixcclxuXHRkZWNvZGU6IHIyc1xyXG59XHJcbiIsIlxudmFyIGVudW1zID0gcmVxdWlyZSgnLi4vZW51bXMuanMnKTtcblxubW9kdWxlLmV4cG9ydHMgPSB7XG5cdGxpc3Q6IHJlcXVpcmUoJy4vcGFja2V0bGlzdC5qcycpLFxufVxuXG52YXIgcGFja2V0cyA9IHJlcXVpcmUoJy4vYWxsX3BhY2tldHMuanMnKTtcblxuZm9yKHZhciBpIGluIHBhY2tldHMpXG5cdG1vZHVsZS5leHBvcnRzW2ldID0gcGFja2V0c1tpXTtcbiIsIi8vIEdQRzRCcm93c2VycyAtIEFuIE9wZW5QR1AgaW1wbGVtZW50YXRpb24gaW4gamF2YXNjcmlwdFxuLy8gQ29weXJpZ2h0IChDKSAyMDExIFJlY3VyaXR5IExhYnMgR21iSFxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yXG4vLyBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uOyBlaXRoZXJcbi8vIHZlcnNpb24gMi4xIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbi8vIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4vLyBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlIEdOVVxuLy8gTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cbi8vIFxuLy8gWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhbG9uZyB3aXRoIHRoaXMgbGlicmFyeTsgaWYgbm90LCB3cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZVxuLy8gRm91bmRhdGlvbiwgSW5jLiwgNTEgRnJhbmtsaW4gU3RyZWV0LCBGaWZ0aCBGbG9vciwgQm9zdG9uLCBNQSAgMDIxMTAtMTMwMSAgVVNBXG5cbi8vIEhpbnQ6IFdlIGhvbGQgb3VyIE1QSXMgYXMgYW4gYXJyYXkgb2Ygb2N0ZXRzIGluIGJpZyBlbmRpYW4gZm9ybWF0IHByZWNlZWRpbmcgYSB0d29cbi8vIG9jdGV0IHNjYWxhcjogTVBJOiBbYSxiLGMsZCxlLGZdXG4vLyAtIE1QSSBzaXplOiAoYSA8PCA4KSB8IGIgXG4vLyAtIE1QSSA9IGMgfCBkIDw8IDggfCBlIDw8ICgoTVBJLmxlbmd0aCAtMikqOCkgfCBmICgoTVBJLmxlbmd0aCAtMikqOClcblxudmFyIEJpZ0ludGVnZXIgPSByZXF1aXJlKCcuLi9jcnlwdG8vcHVibGljX2tleS9qc2JuLmpzJyksXG5cdHV0aWwgPSByZXF1aXJlKCcuLi91dGlsJyk7XG5cbi8qKlxuICogQGNsYXNzXG4gKiBAY2xhc3NkZXNjSW1wbGVtZW50YXRpb24gb2YgdHlwZSBNUEkgKFJGQzQ4ODAgMy4yKVxuICogTXVsdGlwcmVjaXNpb24gaW50ZWdlcnMgKGFsc28gY2FsbGVkIE1QSXMpIGFyZSB1bnNpZ25lZCBpbnRlZ2VycyB1c2VkXG4gKiB0byBob2xkIGxhcmdlIGludGVnZXJzIHN1Y2ggYXMgdGhlIG9uZXMgdXNlZCBpbiBjcnlwdG9ncmFwaGljXG4gKiBjYWxjdWxhdGlvbnMuXG4gKiBBbiBNUEkgY29uc2lzdHMgb2YgdHdvIHBpZWNlczogYSB0d28tb2N0ZXQgc2NhbGFyIHRoYXQgaXMgdGhlIGxlbmd0aFxuICogb2YgdGhlIE1QSSBpbiBiaXRzIGZvbGxvd2VkIGJ5IGEgc3RyaW5nIG9mIG9jdGV0cyB0aGF0IGNvbnRhaW4gdGhlXG4gKiBhY3R1YWwgaW50ZWdlci5cbiAqL1xubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiBtcGkoKSB7XG5cdC8qKiBBbiBpbXBsZW1lbnRhdGlvbiBkZXBlbmRlbnQgaW50ZWdlciAqL1xuXHR0aGlzLmRhdGEgPSBudWxsO1xuXG5cdC8qKlxuXHQgKiBQYXJzaW5nIGZ1bmN0aW9uIGZvciBhIG1waSAoUkZDIDQ4ODAgMy4yKS5cblx0ICogQHBhcmFtIHtTdHJpbmd9IGlucHV0IFBheWxvYWQgb2YgbXBpIGRhdGFcblx0ICogQHBhcmFtIHtJbnRlZ2VyfSBwb3NpdGlvbiBQb3NpdGlvbiB0byBzdGFydCByZWFkaW5nIGZyb20gdGhlIGlucHV0IFxuXHQgKiBzdHJpbmdcblx0ICogQHBhcmFtIHtJbnRlZ2VyfSBsZW4gTGVuZ3RoIG9mIHRoZSBwYWNrZXQgb3IgdGhlIHJlbWFpbmluZyBsZW5ndGggb2YgXG5cdCAqIGlucHV0IGF0IHBvc2l0aW9uXG5cdCAqIEByZXR1cm4ge29wZW5wZ3BfdHlwZV9tcGl9IE9iamVjdCByZXByZXNlbnRhdGlvblxuXHQgKi9cblx0dGhpcy5yZWFkID0gZnVuY3Rpb24oYnl0ZXMpIHtcblx0XHR2YXIgYml0cyA9IChieXRlc1swXS5jaGFyQ29kZUF0KCkgPDwgOCkgfCBieXRlc1sxXS5jaGFyQ29kZUF0KCk7XG5cdFx0XG5cdFx0Ly8gQWRkaXRpb25hbCBydWxlczpcblx0XHQvL1xuXHRcdC8vICAgIFRoZSBzaXplIG9mIGFuIE1QSSBpcyAoKE1QSS5sZW5ndGggKyA3KSAvIDgpICsgMiBvY3RldHMuXG5cdFx0Ly9cblx0XHQvLyAgICBUaGUgbGVuZ3RoIGZpZWxkIG9mIGFuIE1QSSBkZXNjcmliZXMgdGhlIGxlbmd0aCBzdGFydGluZyBmcm9tIGl0c1xuXHRcdC8vXHQgIG1vc3Qgc2lnbmlmaWNhbnQgbm9uLXplcm8gYml0LiAgVGh1cywgdGhlIE1QSSBbMDAgMDIgMDFdIGlzIG5vdFxuXHRcdC8vICAgIGZvcm1lZCBjb3JyZWN0bHkuICBJdCBzaG91bGQgYmUgWzAwIDAxIDAxXS5cblxuXHRcdC8vIFRPRE86IFZlcmlmaWNhdGlvbiBvZiB0aGlzIHNpemUgbWV0aG9kISBUaGlzIHNpemUgY2FsY3VsYXRpb24gYXNcblx0XHQvLyBcdFx0IHNwZWNpZmllZCBhYm92ZSBpcyBub3QgYXBwbGljYWJsZSBpbiBKYXZhU2NyaXB0XG5cdFx0dmFyIGJ5dGVsZW4gPSBNYXRoLmNlaWwoYml0cyAvIDgpO1xuXHRcdFxuXHRcdHZhciByYXcgPSBieXRlcy5zdWJzdHIoMiwgYnl0ZWxlbik7XG5cdFx0dGhpcy5mcm9tQnl0ZXMocmF3KTtcblxuXHRcdHJldHVybiAyICsgYnl0ZWxlbjtcblx0fVxuXG5cdHRoaXMuZnJvbUJ5dGVzID0gZnVuY3Rpb24oYnl0ZXMpIHtcblx0XHR0aGlzLmRhdGEgPSBuZXcgQmlnSW50ZWdlcih1dGlsLmhleHN0cmR1bXAoYnl0ZXMpLCAxNik7IFxuXHR9XG5cblx0dGhpcy50b0J5dGVzID0gZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIHRoaXMud3JpdGUoKS5zdWJzdHIoMik7XG5cdH1cblxuXHR0aGlzLmJ5dGVMZW5ndGggPSBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gdGhpcy50b0J5dGVzKCkubGVuZ3RoO1xuXHR9XG5cblx0LyoqXG5cdCAqIENvbnZlcnRzIHRoZSBtcGkgb2JqZWN0IHRvIGEgc3RyaW5nIGFzIHNwZWNpZmllZCBpbiBSRkM0ODgwIDMuMlxuXHQgKiBAcmV0dXJuIHtTdHJpbmd9IG1waSBCeXRlIHJlcHJlc2VudGF0aW9uXG5cdCAqL1xuXHR0aGlzLndyaXRlID0gZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIHRoaXMuZGF0YS50b01QSSgpO1xuXHR9XG5cblx0dGhpcy50b0JpZ0ludGVnZXIgPSBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gdGhpcy5kYXRhLmNsb25lKCk7XG5cdH1cblxuXHR0aGlzLmZyb21CaWdJbnRlZ2VyID0gZnVuY3Rpb24oYm4pIHtcblx0XHR0aGlzLmRhdGEgPSBibi5jbG9uZSgpO1xuXHR9XG59XG5cbiIsIi8vIEdQRzRCcm93c2VycyAtIEFuIE9wZW5QR1AgaW1wbGVtZW50YXRpb24gaW4gamF2YXNjcmlwdFxuLy8gQ29weXJpZ2h0IChDKSAyMDExIFJlY3VyaXR5IExhYnMgR21iSFxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yXG4vLyBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uOyBlaXRoZXJcbi8vIHZlcnNpb24gMi4xIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbi8vIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4vLyBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlIEdOVVxuLy8gTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cbi8vIFxuLy8gWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhbG9uZyB3aXRoIHRoaXMgbGlicmFyeTsgaWYgbm90LCB3cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZVxuLy8gRm91bmRhdGlvbiwgSW5jLiwgNTEgRnJhbmtsaW4gU3RyZWV0LCBGaWZ0aCBGbG9vciwgQm9zdG9uLCBNQSAgMDIxMTAtMTMwMSAgVVNBXG5cbnZhciBlbnVtcyA9IHJlcXVpcmUoJy4uL2VudW1zLmpzJyksXG5cdHV0aWwgPSByZXF1aXJlKCcuLi91dGlsJyksXG5cdGNyeXB0byA9IHJlcXVpcmUoJy4uL2NyeXB0bycpO1xuXG4vKipcbiAqIEBjbGFzc1xuICogQGNsYXNzZGVzYyBJbXBsZW1lbnRhdGlvbiBvZiB0aGUgU3RyaW5nLXRvLWtleSBzcGVjaWZpZXIgKFJGQzQ4ODAgMy43KVxuICogU3RyaW5nLXRvLWtleSAoUzJLKSBzcGVjaWZpZXJzIGFyZSB1c2VkIHRvIGNvbnZlcnQgcGFzc3BocmFzZSBzdHJpbmdzXG4gICBpbnRvIHN5bW1ldHJpYy1rZXkgZW5jcnlwdGlvbi9kZWNyeXB0aW9uIGtleXMuICBUaGV5IGFyZSB1c2VkIGluIHR3b1xuICAgcGxhY2VzLCBjdXJyZW50bHk6IHRvIGVuY3J5cHQgdGhlIHNlY3JldCBwYXJ0IG9mIHByaXZhdGUga2V5cyBpbiB0aGVcbiAgIHByaXZhdGUga2V5cmluZywgYW5kIHRvIGNvbnZlcnQgcGFzc3BocmFzZXMgdG8gZW5jcnlwdGlvbiBrZXlzIGZvclxuICAgc3ltbWV0cmljYWxseSBlbmNyeXB0ZWQgbWVzc2FnZXMuXG4gKi9cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gczJrKCkge1xuXHQvKiogQHR5cGUge29wZW5wZ3AuaGFzaH0gKi9cblx0dGhpcy5hbGdvcml0aG0gPSAnc2hhMjU2Jztcblx0LyoqIEB0eXBlIHtvcGVucGdwX3R5cGVfczJrLnR5cGV9ICovXG5cdHRoaXMudHlwZSA9ICdpdGVyYXRlZCc7XG5cdHRoaXMuYyA9IDk2O1xuXHQvKiogQHR5cGUge29wZW5wZ3BfYnl0ZWFycmF5fSBcblx0ICogRWlnaHQgYnl0ZXMgb2Ygc2FsdC4gKi9cblx0dGhpcy5zYWx0ID0gY3J5cHRvLnJhbmRvbS5nZXRSYW5kb21CeXRlcyg4KTtcblxuXG5cdC8vIEV4cG9uZW4gYmlhcywgZGVmaW5lZCBpbiBSRkM0ODgwXG5cdHZhciBleHBiaWFzID0gNjtcblxuXHR0aGlzLmdldF9jb3VudCA9IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiAoMTYgKyAodGhpcy5jICYgMTUpKSA8PCAoKHRoaXMuYyA+PiA0KSArIGV4cGJpYXMpO1xuXHR9XG5cblx0LyoqXG5cdCAqIFBhcnNpbmcgZnVuY3Rpb24gZm9yIGEgc3RyaW5nLXRvLWtleSBzcGVjaWZpZXIgKFJGQyA0ODgwIDMuNykuXG5cdCAqIEBwYXJhbSB7U3RyaW5nfSBpbnB1dCBQYXlsb2FkIG9mIHN0cmluZy10by1rZXkgc3BlY2lmaWVyXG5cdCAqIEByZXR1cm4ge0ludGVnZXJ9IEFjdHVhbCBsZW5ndGggb2YgdGhlIG9iamVjdFxuXHQgKi9cblx0dGhpcy5yZWFkID0gZnVuY3Rpb24oYnl0ZXMpIHtcblx0XHR2YXIgaSA9IDA7XG5cdFx0dGhpcy50eXBlID0gZW51bXMucmVhZChlbnVtcy5zMmssIGJ5dGVzW2krK10uY2hhckNvZGVBdCgpKTtcblx0XHR0aGlzLmFsZ29yaXRobSA9IGVudW1zLnJlYWQoZW51bXMuaGFzaCwgYnl0ZXNbaSsrXS5jaGFyQ29kZUF0KCkpO1xuXG5cdFx0c3dpdGNoICh0aGlzLnR5cGUpIHtcblx0XHRjYXNlICdzaW1wbGUnOlxuXHRcdFx0YnJlYWs7XG5cblx0XHRjYXNlICdzYWx0ZWQnOlxuXHRcdFx0dGhpcy5zYWx0ID0gYnl0ZXMuc3Vic3RyKGksIDgpO1xuXHRcdFx0aSArPSA4O1xuXHRcdFx0YnJlYWs7XG5cblx0XHRjYXNlICdpdGVyYXRlZCc6XG5cdFx0XHR0aGlzLnNhbHQgPSBieXRlcy5zdWJzdHIoaSwgOCk7XG5cdFx0XHRpICs9IDg7XG5cblx0XHRcdC8vIE9jdGV0IDEwOiBjb3VudCwgYSBvbmUtb2N0ZXQsIGNvZGVkIHZhbHVlXG5cdFx0XHR0aGlzLmMgPSBieXRlc1tpKytdLmNoYXJDb2RlQXQoKTtcblx0XHRcdGJyZWFrO1xuXG5cdFx0Y2FzZSAnZ251Jzpcblx0XHRcdGlmKGJ5dGVzLnN1YnN0cihpLCAzKSA9PSBcIkdOVVwiKSB7XG5cdFx0XHRcdGkgKz0gMzsgLy8gR05VXG5cdFx0XHRcdHZhciBnbnVFeHRUeXBlID0gMTAwMCArIGJ5dGVzW2krK10uY2hhckNvZGVBdCgpO1xuXHRcdFx0XHRpZihnbnVFeHRUeXBlID09IDEwMDEpIHtcblx0XHRcdFx0XHR0aGlzLnR5cGUgPSBnbnVFeHRUeXBlO1xuXHRcdFx0XHRcdC8vIEdudVBHIGV4dGVuc2lvbiBtb2RlIDEwMDEgLS0gZG9uJ3Qgd3JpdGUgc2VjcmV0IGtleSBhdCBhbGxcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHR0aHJvdyBuZXcgRXJyb3IoXCJVbmtub3duIHMyayBnbnUgcHJvdGVjdGlvbiBtb2RlLlwiKTtcblx0XHRcdFx0fVxuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0dGhyb3cgbmV3IEVycm9yKFwiVW5rbm93biBzMmsgdHlwZS5cIik7XG5cdFx0XHR9XG5cdFx0XHRicmVhaztcblxuXHRcdGRlZmF1bHQ6XG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoXCJVbmtub3duIHMyayB0eXBlLlwiKTtcblx0XHRcdGJyZWFrO1xuXHRcdH1cblxuXHRcdHJldHVybiBpO1xuXHR9XG5cdFxuXHRcblx0LyoqXG5cdCAqIHdyaXRlcyBhbiBzMmsgaGFzaCBiYXNlZCBvbiB0aGUgaW5wdXRzLlxuXHQgKiBAcmV0dXJuIHtTdHJpbmd9IFByb2R1Y2VkIGtleSBvZiBoYXNoQWxnb3JpdGhtIGhhc2ggbGVuZ3RoXG5cdCAqL1xuXHR0aGlzLndyaXRlID0gZnVuY3Rpb24oKSB7XG5cdFx0dmFyIGJ5dGVzID0gU3RyaW5nLmZyb21DaGFyQ29kZShlbnVtcy53cml0ZShlbnVtcy5zMmssIHRoaXMudHlwZSkpO1xuXHRcdGJ5dGVzICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoZW51bXMud3JpdGUoZW51bXMuaGFzaCwgdGhpcy5hbGdvcml0aG0pKTtcblxuXHRcdHN3aXRjaCh0aGlzLnR5cGUpIHtcblx0XHRcdGNhc2UgJ3NpbXBsZSc6XG5cdFx0XHRcdGJyZWFrO1xuXHRcdFx0Y2FzZSAnc2FsdGVkJzpcblx0XHRcdFx0Ynl0ZXMgKz0gdGhpcy5zYWx0O1xuXHRcdFx0XHRicmVhaztcblx0XHRcdGNhc2UgJ2l0ZXJhdGVkJzpcblx0XHRcdFx0Ynl0ZXMgKz0gdGhpcy5zYWx0O1xuXHRcdFx0XHRieXRlcyArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKHRoaXMuYyk7XG5cdFx0XHRcdGJyZWFrO1xuXHRcdH07XG5cblx0XHRyZXR1cm4gYnl0ZXM7XG5cdH1cblxuXHQvKipcblx0ICogUHJvZHVjZXMgYSBrZXkgdXNpbmcgdGhlIHNwZWNpZmllZCBwYXNzcGhyYXNlIGFuZCB0aGUgZGVmaW5lZCBcblx0ICogaGFzaEFsZ29yaXRobSBcblx0ICogQHBhcmFtIHtTdHJpbmd9IHBhc3NwaHJhc2UgUGFzc3BocmFzZSBjb250YWluaW5nIHVzZXIgaW5wdXRcblx0ICogQHJldHVybiB7U3RyaW5nfSBQcm9kdWNlZCBrZXkgd2l0aCBhIGxlbmd0aCBjb3JyZXNwb25kaW5nIHRvIFxuXHQgKiBoYXNoQWxnb3JpdGhtIGhhc2ggbGVuZ3RoXG5cdCAqL1xuXHR0aGlzLnByb2R1Y2Vfa2V5ID0gZnVuY3Rpb24ocGFzc3BocmFzZSwgbnVtQnl0ZXMpIHtcblx0XHRwYXNzcGhyYXNlID0gdXRpbC5lbmNvZGVfdXRmOChwYXNzcGhyYXNlKTtcblxuXHRcdGZ1bmN0aW9uIHJvdW5kKHByZWZpeCwgczJrKSB7XG5cdFx0XHR2YXIgYWxnb3JpdGhtID0gZW51bXMud3JpdGUoZW51bXMuaGFzaCwgczJrLmFsZ29yaXRobSk7XG5cblx0XHRcdHN3aXRjaChzMmsudHlwZSkge1xuXHRcdFx0XHRjYXNlICdzaW1wbGUnOlxuXHRcdFx0XHRcdHJldHVybiBjcnlwdG8uaGFzaC5kaWdlc3QoYWxnb3JpdGhtLCBwcmVmaXggKyBwYXNzcGhyYXNlKTtcblxuXHRcdFx0XHRjYXNlICdzYWx0ZWQnOlxuXHRcdFx0XHRcdHJldHVybiBjcnlwdG8uaGFzaC5kaWdlc3QoYWxnb3JpdGhtLCBcblx0XHRcdFx0XHRcdHByZWZpeCArIHMyay5zYWx0ICsgcGFzc3BocmFzZSk7XG5cblx0XHRcdFx0Y2FzZSAnaXRlcmF0ZWQnOlxuXHRcdFx0XHRcdHZhciBpc3AgPSBbXSxcblx0XHRcdFx0XHRcdGNvdW50ID0gczJrLmdldF9jb3VudCgpO1xuXHRcdFx0XHRcdFx0ZGF0YSA9IHMyay5zYWx0ICsgcGFzc3BocmFzZTtcblxuXHRcdFx0XHRcdHdoaWxlIChpc3AubGVuZ3RoICogZGF0YS5sZW5ndGggPCBjb3VudClcblx0XHRcdFx0XHRcdGlzcC5wdXNoKGRhdGEpO1xuXG5cdFx0XHRcdFx0aXNwID0gaXNwLmpvaW4oJycpO1x0XHRcdFxuXG5cdFx0XHRcdFx0aWYgKGlzcC5sZW5ndGggPiBjb3VudClcblx0XHRcdFx0XHRcdGlzcCA9IGlzcC5zdWJzdHIoMCwgY291bnQpO1xuXG5cdFx0XHRcdFx0cmV0dXJuIGNyeXB0by5oYXNoLmRpZ2VzdChhbGdvcml0aG0sIHByZWZpeCArIGlzcCk7XG5cdFx0XHR9O1xuXHRcdH1cblx0XHRcblx0XHR2YXIgcmVzdWx0ID0gJycsXG5cdFx0XHRwcmVmaXggPSAnJztcblxuXHRcdHdoaWxlKHJlc3VsdC5sZW5ndGggPD0gbnVtQnl0ZXMpIHtcblx0XHRcdHJlc3VsdCArPSByb3VuZChwcmVmaXgsIHRoaXMpO1xuXHRcdFx0cHJlZml4ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoMCk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHJlc3VsdC5zdWJzdHIoMCwgbnVtQnl0ZXMpO1xuXHR9XG59XG5cblxuIiwiLy8gR1BHNEJyb3dzZXJzIC0gQW4gT3BlblBHUCBpbXBsZW1lbnRhdGlvbiBpbiBqYXZhc2NyaXB0XG4vLyBDb3B5cmlnaHQgKEMpIDIwMTEgUmVjdXJpdHkgTGFicyBHbWJIXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3Jcbi8vIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlclxuLy8gdmVyc2lvbiAyLjEgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuLy8gYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2Zcbi8vIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUgR05VXG4vLyBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuLy8gXG4vLyBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFsb25nIHdpdGggdGhpcyBsaWJyYXJ5OyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlXG4vLyBGb3VuZGF0aW9uLCBJbmMuLCA1MSBGcmFua2xpbiBTdHJlZXQsIEZpZnRoIEZsb29yLCBCb3N0b24sIE1BICAwMjExMC0xMzAxICBVU0EgXG5cbi8vIFRoZSBHUEc0QnJvd3NlcnMgY3J5cHRvIGludGVyZmFjZVxuXG5tb2R1bGUuZXhwb3J0cyA9IHtcblx0LyoqXG5cdCAqIFJldHJpZXZlIHNlY3VyZSByYW5kb20gYnl0ZSBzdHJpbmcgb2YgdGhlIHNwZWNpZmllZCBsZW5ndGhcblx0ICogQHBhcmFtIHtJbnRlZ2VyfSBsZW5ndGggTGVuZ3RoIGluIGJ5dGVzIHRvIGdlbmVyYXRlXG5cdCAqIEByZXR1cm4ge1N0cmluZ30gUmFuZG9tIGJ5dGUgc3RyaW5nXG5cdCAqL1xuXHRnZXRSYW5kb21CeXRlczogZnVuY3Rpb24obGVuZ3RoKSB7XG5cdFx0dmFyIHJlc3VsdCA9ICcnO1xuXHRcdGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpKyspIHtcblx0XHRcdHJlc3VsdCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKHRoaXMuZ2V0U2VjdXJlUmFuZG9tT2N0ZXQoKSk7XG5cdFx0fVxuXHRcdHJldHVybiByZXN1bHQ7XG5cdH0sXG5cblx0LyoqXG5cdCAqIFJldHVybiBhIHBzZXVkby1yYW5kb20gbnVtYmVyIGluIHRoZSBzcGVjaWZpZWQgcmFuZ2Vcblx0ICogQHBhcmFtIHtJbnRlZ2VyfSBmcm9tIE1pbiBvZiB0aGUgcmFuZG9tIG51bWJlclxuXHQgKiBAcGFyYW0ge0ludGVnZXJ9IHRvIE1heCBvZiB0aGUgcmFuZG9tIG51bWJlciAobWF4IDMyYml0KVxuXHQgKiBAcmV0dXJuIHtJbnRlZ2VyfSBBIHBzZXVkbyByYW5kb20gbnVtYmVyXG5cdCAqL1xuXHRnZXRQc2V1ZG9SYW5kb206IGZ1bmN0aW9uKGZyb20sIHRvKSB7XG5cdFx0cmV0dXJuIE1hdGgucm91bmQoTWF0aC5yYW5kb20oKSoodG8tZnJvbSkpK2Zyb207XG5cdH0sXG5cblx0LyoqXG5cdCAqIFJldHVybiBhIHNlY3VyZSByYW5kb20gbnVtYmVyIGluIHRoZSBzcGVjaWZpZWQgcmFuZ2Vcblx0ICogQHBhcmFtIHtJbnRlZ2VyfSBmcm9tIE1pbiBvZiB0aGUgcmFuZG9tIG51bWJlclxuXHQgKiBAcGFyYW0ge0ludGVnZXJ9IHRvIE1heCBvZiB0aGUgcmFuZG9tIG51bWJlciAobWF4IDMyYml0KVxuXHQgKiBAcmV0dXJuIHtJbnRlZ2VyfSBBIHNlY3VyZSByYW5kb20gbnVtYmVyXG5cdCAqL1xuXHRnZXRTZWN1cmVSYW5kb206IGZ1bmN0aW9uKGZyb20sIHRvKSB7XG5cdFx0dmFyIGJ1ZiA9IG5ldyBVaW50MzJBcnJheSgxKTtcblx0XHR3aW5kb3cuY3J5cHRvLmdldFJhbmRvbVZhbHVlcyhidWYpO1xuXHRcdHZhciBiaXRzID0gKCh0by1mcm9tKSkudG9TdHJpbmcoMikubGVuZ3RoO1xuXHRcdHdoaWxlICgoYnVmWzBdICYgKE1hdGgucG93KDIsIGJpdHMpIC0xKSkgPiAodG8tZnJvbSkpXG5cdFx0XHR3aW5kb3cuY3J5cHRvLmdldFJhbmRvbVZhbHVlcyhidWYpO1xuXHRcdHJldHVybiBmcm9tKyhNYXRoLmFicyhidWZbMF0gJiAoTWF0aC5wb3coMiwgYml0cykgLTEpKSk7XG5cdH0sXG5cblx0Z2V0U2VjdXJlUmFuZG9tT2N0ZXQ6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBidWYgPSBuZXcgVWludDMyQXJyYXkoMSk7XG5cdFx0d2luZG93LmNyeXB0by5nZXRSYW5kb21WYWx1ZXMoYnVmKTtcblx0XHRyZXR1cm4gYnVmWzBdICYgMHhGRjtcblx0fVxufVxuIiwiXG5tb2R1bGUuZXhwb3J0cyA9IHtcblx0Y2lwaGVyOiByZXF1aXJlKCcuL2NpcGhlcicpLFxuXHRoYXNoOiByZXF1aXJlKCcuL2hhc2gnKSxcblx0Y2ZiOiByZXF1aXJlKCcuL2NmYi5qcycpLFxuXHRwdWJsaWNLZXk6IHJlcXVpcmUoJy4vcHVibGljX2tleScpLFxuXHRzaWduYXR1cmU6IHJlcXVpcmUoJy4vc2lnbmF0dXJlLmpzJyksXG5cdHJhbmRvbTogcmVxdWlyZSgnLi9yYW5kb20uanMnKSxcblx0cGtjczE6IHJlcXVpcmUoJy4vcGtjczEuanMnKSxcblx0c3ltbWV0cmljOiByZXF1aXJlKCcuL3N5bS5qcycpXG5cbn1cblxudmFyIGNyeXB0byA9IHJlcXVpcmUoJy4vY3J5cHRvLmpzJyk7XG5cbmZvcih2YXIgaSBpbiBjcnlwdG8pXG5cdG1vZHVsZS5leHBvcnRzW2ldID0gY3J5cHRvW2ldO1xuXG5cblxuIiwiXG5cbnZhciBwYWNrZXRQYXJzZXIgPSByZXF1aXJlKCcuL3BhY2tldC5qcycpLFxuXHRwYWNrZXRzID0gcmVxdWlyZSgnLi9hbGxfcGFja2V0cy5qcycpLFxuXHRlbnVtcyA9IHJlcXVpcmUoJy4uL2VudW1zLmpzJyk7XG5cbi8qKlxuICogQGNsYXNzXG4gKiBAY2xhc3NkZXNjIFRoaXMgY2xhc3MgcmVwcmVzZW50cyBhIGxpc3Qgb2Ygb3BlbnBncCBwYWNrZXRzLlxuICogVGFrZSBjYXJlIHdoZW4gaXRlcmF0aW5nIG92ZXIgaXQgLSB0aGUgcGFja2V0cyB0aGVtc2VsdmVzXG4gKiBhcmUgc3RvcmVkIGFzIG51bWVyaWNhbCBpbmRpY2VzLlxuICovXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIHBhY2tldGxpc3QoKSB7XG5cdC8qKiBUaGUgbnVtYmVyIG9mIHBhY2tldHMgY29udGFpbmVkIHdpdGhpbiB0aGUgbGlzdC5cblx0ICogQHJlYWRvbmx5XG5cdCAqIEB0eXBlIHtJbnRlZ2VyfSAqL1xuXHR0aGlzLmxlbmd0aCA9IDA7XG5cblxuXG5cdC8qKlxuXHQgKiBSZWFkcyBhIHN0cmVhbSBvZiBiaW5hcnkgZGF0YSBhbmQgaW50ZXJwcmVudHMgaXQgYXMgYSBsaXN0IG9mIHBhY2tldHMuXG5cdCAqIEBwYXJhbSB7b3BlbnBncF9ieXRlYXJyYXl9IEFuIGFycmF5IG9mIGJ5dGVzLlxuXHQgKi9cblx0dGhpcy5yZWFkID0gZnVuY3Rpb24oYnl0ZXMpIHtcblx0XHR2YXIgaSA9IDA7XG5cblx0XHR3aGlsZShpIDwgYnl0ZXMubGVuZ3RoKSB7XG5cdFx0XHR2YXIgcGFyc2VkID0gcGFja2V0UGFyc2VyLnJlYWQoYnl0ZXMsIGksIGJ5dGVzLmxlbmd0aCAtIGkpO1xuXHRcdFx0aSA9IHBhcnNlZC5vZmZzZXQ7XG5cblx0XHRcdHZhciB0YWcgPSBlbnVtcy5yZWFkKGVudW1zLnBhY2tldCwgcGFyc2VkLnRhZyk7XG5cdFx0XHR2YXIgcGFja2V0ID0gbmV3IHBhY2tldHNbdGFnXSgpO1xuXG5cdFx0XHR0aGlzLnB1c2gocGFja2V0KTtcblxuXHRcdFx0cGFja2V0LnJlYWQocGFyc2VkLnBhY2tldCk7XG5cdFx0fVxuXHR9XG5cblx0LyoqXG5cdCAqIENyZWF0ZXMgYSBiaW5hcnkgcmVwcmVzZW50YXRpb24gb2Ygb3BlbnBncCBvYmplY3RzIGNvbnRhaW5lZCB3aXRoaW4gdGhlXG5cdCAqIGNsYXNzIGluc3RhbmNlLlxuXHQgKiBAcmV0dXJucyB7b3BlbnBncF9ieXRlYXJyYXl9IEFuIGFycmF5IG9mIGJ5dGVzIGNvbnRhaW5pbmcgdmFsaWQgb3BlbnBncCBwYWNrZXRzLlxuXHQgKi9cblx0dGhpcy53cml0ZSA9IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBieXRlcyA9ICcnO1xuXG5cdFx0Zm9yKHZhciBpID0gMDsgaSA8IHRoaXMubGVuZ3RoOyBpKyspIHtcblx0XHRcdHZhciBwYWNrZXRieXRlcyA9IHRoaXNbaV0ud3JpdGUoKTtcblx0XHRcdGJ5dGVzICs9IHBhY2tldFBhcnNlci53cml0ZUhlYWRlcih0aGlzW2ldLnRhZywgcGFja2V0Ynl0ZXMubGVuZ3RoKTtcblx0XHRcdGJ5dGVzICs9IHBhY2tldGJ5dGVzO1xuXHRcdH1cblx0XHRcblx0XHRyZXR1cm4gYnl0ZXM7XG5cdH1cblxuXHQvKipcblx0ICogQWRkcyBhIHBhY2tldCB0byB0aGUgbGlzdC4gVGhpcyBpcyB0aGUgb25seSBzdXBwb3J0ZWQgbWV0aG9kIG9mIGRvaW5nIHNvO1xuXHQgKiB3cml0aW5nIHRvIHBhY2tldGxpc3RbaV0gZGlyZWN0bHkgd2lsbCByZXN1bHQgaW4gYW4gZXJyb3IuXG5cdCAqL1xuXHR0aGlzLnB1c2ggPSBmdW5jdGlvbihwYWNrZXQpIHtcblx0XHRwYWNrZXQucGFja2V0cyA9IG5ldyBwYWNrZXRsaXN0KCk7XG5cblx0XHR0aGlzW3RoaXMubGVuZ3RoXSA9IHBhY2tldDtcblx0XHR0aGlzLmxlbmd0aCsrO1xuXHR9XG5cbn1cbiIsIlxudmFyIGVudW1zID0gcmVxdWlyZSgnLi4vZW51bXMuanMnKTtcblxuLy8gVGhpcyBpcyBwcmV0dHkgdWdseSwgYnV0IGJyb3dzZXJpZnkgbmVlZHMgdG8gaGF2ZSB0aGUgcmVxdWlyZXMgZXhwbGljaXRseSB3cml0dGVuLlxubW9kdWxlLmV4cG9ydHMgPSB7XG5cdGNvbXByZXNzZWQ6IHJlcXVpcmUoJy4vY29tcHJlc3NlZC5qcycpLFxuXHRzeW1fZW5jcnlwdGVkX2ludGVncml0eV9wcm90ZWN0ZWQ6IHJlcXVpcmUoJy4vc3ltX2VuY3J5cHRlZF9pbnRlZ3JpdHlfcHJvdGVjdGVkLmpzJyksXG5cdHB1YmxpY19rZXlfZW5jcnlwdGVkX3Nlc3Npb25fa2V5OiByZXF1aXJlKCcuL3B1YmxpY19rZXlfZW5jcnlwdGVkX3Nlc3Npb25fa2V5LmpzJyksXG5cdHN5bV9lbmNyeXB0ZWRfc2Vzc2lvbl9rZXk6IHJlcXVpcmUoJy4vc3ltX2VuY3J5cHRlZF9zZXNzaW9uX2tleS5qcycpLFxuXHRsaXRlcmFsOiByZXF1aXJlKCcuL2xpdGVyYWwuanMnKSxcblx0cHVibGljX2tleTogcmVxdWlyZSgnLi9wdWJsaWNfa2V5LmpzJyksXG5cdHN5bW1ldHJpY2FsbHlfZW5jcnlwdGVkOiByZXF1aXJlKCcuL3N5bW1ldHJpY2FsbHlfZW5jcnlwdGVkLmpzJyksXG5cdG1hcmtlcjogcmVxdWlyZSgnLi9tYXJrZXIuanMnKSxcblx0cHVibGljX3N1YmtleTogcmVxdWlyZSgnLi9wdWJsaWNfc3Via2V5LmpzJyksXG5cdHVzZXJfYXR0cmlidXRlOiByZXF1aXJlKCcuL3VzZXJfYXR0cmlidXRlLmpzJyksXG5cdG9uZV9wYXNzX3NpZ25hdHVyZTogcmVxdWlyZSgnLi9vbmVfcGFzc19zaWduYXR1cmUuanMnKSxcblx0c2VjcmV0X2tleTogcmVxdWlyZSgnLi9zZWNyZXRfa2V5LmpzJyksXG5cdHVzZXJpZDogcmVxdWlyZSgnLi91c2VyaWQuanMnKSxcblx0c2VjcmV0X3N1YmtleTogcmVxdWlyZSgnLi9zZWNyZXRfc3Via2V5LmpzJyksXG5cdHNpZ25hdHVyZTogcmVxdWlyZSgnLi9zaWduYXR1cmUuanMnKSxcblx0dHJ1c3Q6IHJlcXVpcmUoJy4vdHJ1c3QuanMnKVxufVxuXG5mb3IodmFyIGkgaW4gZW51bXMucGFja2V0KSB7XG5cdHZhciBwYWNrZXRDbGFzcyA9IG1vZHVsZS5leHBvcnRzW2ldO1xuXG5cdGlmKHBhY2tldENsYXNzICE9IHVuZGVmaW5lZClcblx0XHRwYWNrZXRDbGFzcy5wcm90b3R5cGUudGFnID0gZW51bXMucGFja2V0W2ldO1xufVxuIiwiLypcbiAqIENvcHlyaWdodCAoYykgMjAwMy0yMDA1ICBUb20gV3UgKHRqd0Bjcy5TdGFuZm9yZC5FRFUpIFxuICogQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiBNb2RpZmllZCBieSBSZWN1cml0eSBMYWJzIEdtYkggXG4gKiBcbiAqIFBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZ1xuICogYSBjb3B5IG9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQgZG9jdW1lbnRhdGlvbiBmaWxlcyAodGhlXG4gKiBcIlNvZnR3YXJlXCIpLCB0byBkZWFsIGluIHRoZSBTb2Z0d2FyZSB3aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmdcbiAqIHdpdGhvdXQgbGltaXRhdGlvbiB0aGUgcmlnaHRzIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCxcbiAqIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsIGFuZC9vciBzZWxsIGNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0b1xuICogcGVybWl0IHBlcnNvbnMgdG8gd2hvbSB0aGUgU29mdHdhcmUgaXMgZnVybmlzaGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRvXG4gKiB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6XG4gKlxuICogVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmVcbiAqIGluY2x1ZGVkIGluIGFsbCBjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMgb2YgdGhlIFNvZnR3YXJlLlxuICpcbiAqIFRIRSBTT0ZUV0FSRSBJUyBQUk9WSURFRCBcIkFTLUlTXCIgQU5EIFdJVEhPVVQgV0FSUkFOVFkgT0YgQU5ZIEtJTkQsIFxuICogRVhQUkVTUywgSU1QTElFRCBPUiBPVEhFUldJU0UsIElOQ0xVRElORyBXSVRIT1VUIExJTUlUQVRJT04sIEFOWSBcbiAqIFdBUlJBTlRZIE9GIE1FUkNIQU5UQUJJTElUWSBPUiBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFxuICpcbiAqIElOIE5PIEVWRU5UIFNIQUxMIFRPTSBXVSBCRSBMSUFCTEUgRk9SIEFOWSBTUEVDSUFMLCBJTkNJREVOVEFMLFxuICogSU5ESVJFQ1QgT1IgQ09OU0VRVUVOVElBTCBEQU1BR0VTIE9GIEFOWSBLSU5ELCBPUiBBTlkgREFNQUdFUyBXSEFUU09FVkVSXG4gKiBSRVNVTFRJTkcgRlJPTSBMT1NTIE9GIFVTRSwgREFUQSBPUiBQUk9GSVRTLCBXSEVUSEVSIE9SIE5PVCBBRFZJU0VEIE9GXG4gKiBUSEUgUE9TU0lCSUxJVFkgT0YgREFNQUdFLCBBTkQgT04gQU5ZIFRIRU9SWSBPRiBMSUFCSUxJVFksIEFSSVNJTkcgT1VUXG4gKiBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFIFVTRSBPUiBQRVJGT1JNQU5DRSBPRiBUSElTIFNPRlRXQVJFLlxuICpcbiAqIEluIGFkZGl0aW9uLCB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbiBhcHBsaWVzOlxuICpcbiAqIEFsbCByZWRpc3RyaWJ1dGlvbnMgbXVzdCByZXRhaW4gYW4gaW50YWN0IGNvcHkgb2YgdGhpcyBjb3B5cmlnaHQgbm90aWNlXG4gKiBhbmQgZGlzY2xhaW1lci5cbiAqL1xuXG5cbnZhciB1dGlsID0gcmVxdWlyZSgnLi4vLi4vdXRpbCcpO1xuXG4vLyBCYXNpYyBKYXZhU2NyaXB0IEJOIGxpYnJhcnkgLSBzdWJzZXQgdXNlZnVsIGZvciBSU0EgZW5jcnlwdGlvbi5cblxuLy8gQml0cyBwZXIgZGlnaXRcbnZhciBkYml0cztcblxuLy8gSmF2YVNjcmlwdCBlbmdpbmUgYW5hbHlzaXNcbnZhciBjYW5hcnkgPSAweGRlYWRiZWVmY2FmZTtcbnZhciBqX2xtID0gKChjYW5hcnkmMHhmZmZmZmYpPT0weGVmY2FmZSk7XG5cbi8vIChwdWJsaWMpIENvbnN0cnVjdG9yXG5mdW5jdGlvbiBCaWdJbnRlZ2VyKGEsYixjKSB7XG4gIGlmKGEgIT0gbnVsbClcbiAgICBpZihcIm51bWJlclwiID09IHR5cGVvZiBhKSB0aGlzLmZyb21OdW1iZXIoYSxiLGMpO1xuICAgIGVsc2UgaWYoYiA9PSBudWxsICYmIFwic3RyaW5nXCIgIT0gdHlwZW9mIGEpIHRoaXMuZnJvbVN0cmluZyhhLDI1Nik7XG4gICAgZWxzZSB0aGlzLmZyb21TdHJpbmcoYSxiKTtcbn1cblxuLy8gcmV0dXJuIG5ldywgdW5zZXQgQmlnSW50ZWdlclxuZnVuY3Rpb24gbmJpKCkgeyByZXR1cm4gbmV3IEJpZ0ludGVnZXIobnVsbCk7IH1cblxuLy8gYW06IENvbXB1dGUgd19qICs9ICh4KnRoaXNfaSksIHByb3BhZ2F0ZSBjYXJyaWVzLFxuLy8gYyBpcyBpbml0aWFsIGNhcnJ5LCByZXR1cm5zIGZpbmFsIGNhcnJ5LlxuLy8gYyA8IDMqZHZhbHVlLCB4IDwgMipkdmFsdWUsIHRoaXNfaSA8IGR2YWx1ZVxuLy8gV2UgbmVlZCB0byBzZWxlY3QgdGhlIGZhc3Rlc3Qgb25lIHRoYXQgd29ya3MgaW4gdGhpcyBlbnZpcm9ubWVudC5cblxuLy8gYW0xOiB1c2UgYSBzaW5nbGUgbXVsdCBhbmQgZGl2aWRlIHRvIGdldCB0aGUgaGlnaCBiaXRzLFxuLy8gbWF4IGRpZ2l0IGJpdHMgc2hvdWxkIGJlIDI2IGJlY2F1c2Vcbi8vIG1heCBpbnRlcm5hbCB2YWx1ZSA9IDIqZHZhbHVlXjItMipkdmFsdWUgKDwgMl41MylcbmZ1bmN0aW9uIGFtMShpLHgsdyxqLGMsbikge1xuICB3aGlsZSgtLW4gPj0gMCkge1xuICAgIHZhciB2ID0geCp0aGlzW2krK10rd1tqXStjO1xuICAgIGMgPSBNYXRoLmZsb29yKHYvMHg0MDAwMDAwKTtcbiAgICB3W2orK10gPSB2JjB4M2ZmZmZmZjtcbiAgfVxuICByZXR1cm4gYztcbn1cbi8vIGFtMiBhdm9pZHMgYSBiaWcgbXVsdC1hbmQtZXh0cmFjdCBjb21wbGV0ZWx5LlxuLy8gTWF4IGRpZ2l0IGJpdHMgc2hvdWxkIGJlIDw9IDMwIGJlY2F1c2Ugd2UgZG8gYml0d2lzZSBvcHNcbi8vIG9uIHZhbHVlcyB1cCB0byAyKmhkdmFsdWVeMi1oZHZhbHVlLTEgKDwgMl4zMSlcbmZ1bmN0aW9uIGFtMihpLHgsdyxqLGMsbikge1xuICB2YXIgeGwgPSB4JjB4N2ZmZiwgeGggPSB4Pj4xNTtcbiAgd2hpbGUoLS1uID49IDApIHtcbiAgICB2YXIgbCA9IHRoaXNbaV0mMHg3ZmZmO1xuICAgIHZhciBoID0gdGhpc1tpKytdPj4xNTtcbiAgICB2YXIgbSA9IHhoKmwraCp4bDtcbiAgICBsID0geGwqbCsoKG0mMHg3ZmZmKTw8MTUpK3dbal0rKGMmMHgzZmZmZmZmZik7XG4gICAgYyA9IChsPj4+MzApKyhtPj4+MTUpK3hoKmgrKGM+Pj4zMCk7XG4gICAgd1tqKytdID0gbCYweDNmZmZmZmZmO1xuICB9XG4gIHJldHVybiBjO1xufVxuLy8gQWx0ZXJuYXRlbHksIHNldCBtYXggZGlnaXQgYml0cyB0byAyOCBzaW5jZSBzb21lXG4vLyBicm93c2VycyBzbG93IGRvd24gd2hlbiBkZWFsaW5nIHdpdGggMzItYml0IG51bWJlcnMuXG5mdW5jdGlvbiBhbTMoaSx4LHcsaixjLG4pIHtcbiAgdmFyIHhsID0geCYweDNmZmYsIHhoID0geD4+MTQ7XG4gIHdoaWxlKC0tbiA+PSAwKSB7XG4gICAgdmFyIGwgPSB0aGlzW2ldJjB4M2ZmZjtcbiAgICB2YXIgaCA9IHRoaXNbaSsrXT4+MTQ7XG4gICAgdmFyIG0gPSB4aCpsK2gqeGw7XG4gICAgbCA9IHhsKmwrKChtJjB4M2ZmZik8PDE0KSt3W2pdK2M7XG4gICAgYyA9IChsPj4yOCkrKG0+PjE0KSt4aCpoO1xuICAgIHdbaisrXSA9IGwmMHhmZmZmZmZmO1xuICB9XG4gIHJldHVybiBjO1xufVxuaWYoal9sbSAmJiAobmF2aWdhdG9yLmFwcE5hbWUgPT0gXCJNaWNyb3NvZnQgSW50ZXJuZXQgRXhwbG9yZXJcIikpIHtcbiAgQmlnSW50ZWdlci5wcm90b3R5cGUuYW0gPSBhbTI7XG4gIGRiaXRzID0gMzA7XG59XG5lbHNlIGlmKGpfbG0gJiYgKG5hdmlnYXRvci5hcHBOYW1lICE9IFwiTmV0c2NhcGVcIikpIHtcbiAgQmlnSW50ZWdlci5wcm90b3R5cGUuYW0gPSBhbTE7XG4gIGRiaXRzID0gMjY7XG59XG5lbHNlIHsgLy8gTW96aWxsYS9OZXRzY2FwZSBzZWVtcyB0byBwcmVmZXIgYW0zXG4gIEJpZ0ludGVnZXIucHJvdG90eXBlLmFtID0gYW0zO1xuICBkYml0cyA9IDI4O1xufVxuXG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5EQiA9IGRiaXRzO1xuQmlnSW50ZWdlci5wcm90b3R5cGUuRE0gPSAoKDE8PGRiaXRzKS0xKTtcbkJpZ0ludGVnZXIucHJvdG90eXBlLkRWID0gKDE8PGRiaXRzKTtcblxudmFyIEJJX0ZQID0gNTI7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5GViA9IE1hdGgucG93KDIsQklfRlApO1xuQmlnSW50ZWdlci5wcm90b3R5cGUuRjEgPSBCSV9GUC1kYml0cztcbkJpZ0ludGVnZXIucHJvdG90eXBlLkYyID0gMipkYml0cy1CSV9GUDtcblxuLy8gRGlnaXQgY29udmVyc2lvbnNcbnZhciBCSV9STSA9IFwiMDEyMzQ1Njc4OWFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6XCI7XG52YXIgQklfUkMgPSBuZXcgQXJyYXkoKTtcbnZhciBycix2djtcbnJyID0gXCIwXCIuY2hhckNvZGVBdCgwKTtcbmZvcih2diA9IDA7IHZ2IDw9IDk7ICsrdnYpIEJJX1JDW3JyKytdID0gdnY7XG5yciA9IFwiYVwiLmNoYXJDb2RlQXQoMCk7XG5mb3IodnYgPSAxMDsgdnYgPCAzNjsgKyt2dikgQklfUkNbcnIrK10gPSB2djtcbnJyID0gXCJBXCIuY2hhckNvZGVBdCgwKTtcbmZvcih2diA9IDEwOyB2diA8IDM2OyArK3Z2KSBCSV9SQ1tycisrXSA9IHZ2O1xuXG5mdW5jdGlvbiBpbnQyY2hhcihuKSB7IHJldHVybiBCSV9STS5jaGFyQXQobik7IH1cbmZ1bmN0aW9uIGludEF0KHMsaSkge1xuICB2YXIgYyA9IEJJX1JDW3MuY2hhckNvZGVBdChpKV07XG4gIHJldHVybiAoYz09bnVsbCk/LTE6Yztcbn1cblxuLy8gKHByb3RlY3RlZCkgY29weSB0aGlzIHRvIHJcbmZ1bmN0aW9uIGJucENvcHlUbyhyKSB7XG4gIGZvcih2YXIgaSA9IHRoaXMudC0xOyBpID49IDA7IC0taSkgcltpXSA9IHRoaXNbaV07XG4gIHIudCA9IHRoaXMudDtcbiAgci5zID0gdGhpcy5zO1xufVxuXG4vLyAocHJvdGVjdGVkKSBzZXQgZnJvbSBpbnRlZ2VyIHZhbHVlIHgsIC1EViA8PSB4IDwgRFZcbmZ1bmN0aW9uIGJucEZyb21JbnQoeCkge1xuICB0aGlzLnQgPSAxO1xuICB0aGlzLnMgPSAoeDwwKT8tMTowO1xuICBpZih4ID4gMCkgdGhpc1swXSA9IHg7XG4gIGVsc2UgaWYoeCA8IC0xKSB0aGlzWzBdID0geCtEVjtcbiAgZWxzZSB0aGlzLnQgPSAwO1xufVxuXG4vLyByZXR1cm4gYmlnaW50IGluaXRpYWxpemVkIHRvIHZhbHVlXG5mdW5jdGlvbiBuYnYoaSkgeyB2YXIgciA9IG5iaSgpOyByLmZyb21JbnQoaSk7IHJldHVybiByOyB9XG5cbi8vIChwcm90ZWN0ZWQpIHNldCBmcm9tIHN0cmluZyBhbmQgcmFkaXhcbmZ1bmN0aW9uIGJucEZyb21TdHJpbmcocyxiKSB7XG4gIHZhciBrO1xuICBpZihiID09IDE2KSBrID0gNDtcbiAgZWxzZSBpZihiID09IDgpIGsgPSAzO1xuICBlbHNlIGlmKGIgPT0gMjU2KSBrID0gODsgLy8gYnl0ZSBhcnJheVxuICBlbHNlIGlmKGIgPT0gMikgayA9IDE7XG4gIGVsc2UgaWYoYiA9PSAzMikgayA9IDU7XG4gIGVsc2UgaWYoYiA9PSA0KSBrID0gMjtcbiAgZWxzZSB7IHRoaXMuZnJvbVJhZGl4KHMsYik7IHJldHVybjsgfVxuICB0aGlzLnQgPSAwO1xuICB0aGlzLnMgPSAwO1xuICB2YXIgaSA9IHMubGVuZ3RoLCBtaSA9IGZhbHNlLCBzaCA9IDA7XG4gIHdoaWxlKC0taSA+PSAwKSB7XG4gICAgdmFyIHggPSAoaz09OCk/c1tpXSYweGZmOmludEF0KHMsaSk7XG4gICAgaWYoeCA8IDApIHtcbiAgICAgIGlmKHMuY2hhckF0KGkpID09IFwiLVwiKSBtaSA9IHRydWU7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG4gICAgbWkgPSBmYWxzZTtcbiAgICBpZihzaCA9PSAwKVxuICAgICAgdGhpc1t0aGlzLnQrK10gPSB4O1xuICAgIGVsc2UgaWYoc2grayA+IHRoaXMuREIpIHtcbiAgICAgIHRoaXNbdGhpcy50LTFdIHw9ICh4JigoMTw8KHRoaXMuREItc2gpKS0xKSk8PHNoO1xuICAgICAgdGhpc1t0aGlzLnQrK10gPSAoeD4+KHRoaXMuREItc2gpKTtcbiAgICB9XG4gICAgZWxzZVxuICAgICAgdGhpc1t0aGlzLnQtMV0gfD0geDw8c2g7XG4gICAgc2ggKz0gaztcbiAgICBpZihzaCA+PSB0aGlzLkRCKSBzaCAtPSB0aGlzLkRCO1xuICB9XG4gIGlmKGsgPT0gOCAmJiAoc1swXSYweDgwKSAhPSAwKSB7XG4gICAgdGhpcy5zID0gLTE7XG4gICAgaWYoc2ggPiAwKSB0aGlzW3RoaXMudC0xXSB8PSAoKDE8PCh0aGlzLkRCLXNoKSktMSk8PHNoO1xuICB9XG4gIHRoaXMuY2xhbXAoKTtcbiAgaWYobWkpIEJpZ0ludGVnZXIuWkVSTy5zdWJUbyh0aGlzLHRoaXMpO1xufVxuXG4vLyAocHJvdGVjdGVkKSBjbGFtcCBvZmYgZXhjZXNzIGhpZ2ggd29yZHNcbmZ1bmN0aW9uIGJucENsYW1wKCkge1xuICB2YXIgYyA9IHRoaXMucyZ0aGlzLkRNO1xuICB3aGlsZSh0aGlzLnQgPiAwICYmIHRoaXNbdGhpcy50LTFdID09IGMpIC0tdGhpcy50O1xufVxuXG4vLyAocHVibGljKSByZXR1cm4gc3RyaW5nIHJlcHJlc2VudGF0aW9uIGluIGdpdmVuIHJhZGl4XG5mdW5jdGlvbiBiblRvU3RyaW5nKGIpIHtcbiAgaWYodGhpcy5zIDwgMCkgcmV0dXJuIFwiLVwiK3RoaXMubmVnYXRlKCkudG9TdHJpbmcoYik7XG4gIHZhciBrO1xuICBpZihiID09IDE2KSBrID0gNDtcbiAgZWxzZSBpZihiID09IDgpIGsgPSAzO1xuICBlbHNlIGlmKGIgPT0gMikgayA9IDE7XG4gIGVsc2UgaWYoYiA9PSAzMikgayA9IDU7XG4gIGVsc2UgaWYoYiA9PSA0KSBrID0gMjtcbiAgZWxzZSByZXR1cm4gdGhpcy50b1JhZGl4KGIpO1xuICB2YXIga20gPSAoMTw8ayktMSwgZCwgbSA9IGZhbHNlLCByID0gXCJcIiwgaSA9IHRoaXMudDtcbiAgdmFyIHAgPSB0aGlzLkRCLShpKnRoaXMuREIpJWs7XG4gIGlmKGktLSA+IDApIHtcbiAgICBpZihwIDwgdGhpcy5EQiAmJiAoZCA9IHRoaXNbaV0+PnApID4gMCkgeyBtID0gdHJ1ZTsgciA9IGludDJjaGFyKGQpOyB9XG4gICAgd2hpbGUoaSA+PSAwKSB7XG4gICAgICBpZihwIDwgaykge1xuICAgICAgICBkID0gKHRoaXNbaV0mKCgxPDxwKS0xKSk8PChrLXApO1xuICAgICAgICBkIHw9IHRoaXNbLS1pXT4+KHArPXRoaXMuREItayk7XG4gICAgICB9XG4gICAgICBlbHNlIHtcbiAgICAgICAgZCA9ICh0aGlzW2ldPj4ocC09aykpJmttO1xuICAgICAgICBpZihwIDw9IDApIHsgcCArPSB0aGlzLkRCOyAtLWk7IH1cbiAgICAgIH1cbiAgICAgIGlmKGQgPiAwKSBtID0gdHJ1ZTtcbiAgICAgIGlmKG0pIHIgKz0gaW50MmNoYXIoZCk7XG4gICAgfVxuICB9XG4gIHJldHVybiBtP3I6XCIwXCI7XG59XG5cbi8vIChwdWJsaWMpIC10aGlzXG5mdW5jdGlvbiBibk5lZ2F0ZSgpIHsgdmFyIHIgPSBuYmkoKTsgQmlnSW50ZWdlci5aRVJPLnN1YlRvKHRoaXMscik7IHJldHVybiByOyB9XG5cbi8vIChwdWJsaWMpIHx0aGlzfFxuZnVuY3Rpb24gYm5BYnMoKSB7IHJldHVybiAodGhpcy5zPDApP3RoaXMubmVnYXRlKCk6dGhpczsgfVxuXG4vLyAocHVibGljKSByZXR1cm4gKyBpZiB0aGlzID4gYSwgLSBpZiB0aGlzIDwgYSwgMCBpZiBlcXVhbFxuZnVuY3Rpb24gYm5Db21wYXJlVG8oYSkge1xuICB2YXIgciA9IHRoaXMucy1hLnM7XG4gIGlmKHIgIT0gMCkgcmV0dXJuIHI7XG4gIHZhciBpID0gdGhpcy50O1xuICByID0gaS1hLnQ7XG4gIGlmKHIgIT0gMCkgcmV0dXJuIHI7XG4gIHdoaWxlKC0taSA+PSAwKSBpZigocj10aGlzW2ldLWFbaV0pICE9IDApIHJldHVybiByO1xuICByZXR1cm4gMDtcbn1cblxuLy8gcmV0dXJucyBiaXQgbGVuZ3RoIG9mIHRoZSBpbnRlZ2VyIHhcbmZ1bmN0aW9uIG5iaXRzKHgpIHtcbiAgdmFyIHIgPSAxLCB0O1xuICBpZigodD14Pj4+MTYpICE9IDApIHsgeCA9IHQ7IHIgKz0gMTY7IH1cbiAgaWYoKHQ9eD4+OCkgIT0gMCkgeyB4ID0gdDsgciArPSA4OyB9XG4gIGlmKCh0PXg+PjQpICE9IDApIHsgeCA9IHQ7IHIgKz0gNDsgfVxuICBpZigodD14Pj4yKSAhPSAwKSB7IHggPSB0OyByICs9IDI7IH1cbiAgaWYoKHQ9eD4+MSkgIT0gMCkgeyB4ID0gdDsgciArPSAxOyB9XG4gIHJldHVybiByO1xufVxuXG4vLyAocHVibGljKSByZXR1cm4gdGhlIG51bWJlciBvZiBiaXRzIGluIFwidGhpc1wiXG5mdW5jdGlvbiBibkJpdExlbmd0aCgpIHtcbiAgaWYodGhpcy50IDw9IDApIHJldHVybiAwO1xuICByZXR1cm4gdGhpcy5EQioodGhpcy50LTEpK25iaXRzKHRoaXNbdGhpcy50LTFdXih0aGlzLnMmdGhpcy5ETSkpO1xufVxuXG4vLyAocHJvdGVjdGVkKSByID0gdGhpcyA8PCBuKkRCXG5mdW5jdGlvbiBibnBETFNoaWZ0VG8obixyKSB7XG4gIHZhciBpO1xuICBmb3IoaSA9IHRoaXMudC0xOyBpID49IDA7IC0taSkgcltpK25dID0gdGhpc1tpXTtcbiAgZm9yKGkgPSBuLTE7IGkgPj0gMDsgLS1pKSByW2ldID0gMDtcbiAgci50ID0gdGhpcy50K247XG4gIHIucyA9IHRoaXMucztcbn1cblxuLy8gKHByb3RlY3RlZCkgciA9IHRoaXMgPj4gbipEQlxuZnVuY3Rpb24gYm5wRFJTaGlmdFRvKG4scikge1xuICBmb3IodmFyIGkgPSBuOyBpIDwgdGhpcy50OyArK2kpIHJbaS1uXSA9IHRoaXNbaV07XG4gIHIudCA9IE1hdGgubWF4KHRoaXMudC1uLDApO1xuICByLnMgPSB0aGlzLnM7XG59XG5cbi8vIChwcm90ZWN0ZWQpIHIgPSB0aGlzIDw8IG5cbmZ1bmN0aW9uIGJucExTaGlmdFRvKG4scikge1xuICB2YXIgYnMgPSBuJXRoaXMuREI7XG4gIHZhciBjYnMgPSB0aGlzLkRCLWJzO1xuICB2YXIgYm0gPSAoMTw8Y2JzKS0xO1xuICB2YXIgZHMgPSBNYXRoLmZsb29yKG4vdGhpcy5EQiksIGMgPSAodGhpcy5zPDxicykmdGhpcy5ETSwgaTtcbiAgZm9yKGkgPSB0aGlzLnQtMTsgaSA+PSAwOyAtLWkpIHtcbiAgICByW2krZHMrMV0gPSAodGhpc1tpXT4+Y2JzKXxjO1xuICAgIGMgPSAodGhpc1tpXSZibSk8PGJzO1xuICB9XG4gIGZvcihpID0gZHMtMTsgaSA+PSAwOyAtLWkpIHJbaV0gPSAwO1xuICByW2RzXSA9IGM7XG4gIHIudCA9IHRoaXMudCtkcysxO1xuICByLnMgPSB0aGlzLnM7XG4gIHIuY2xhbXAoKTtcbn1cblxuLy8gKHByb3RlY3RlZCkgciA9IHRoaXMgPj4gblxuZnVuY3Rpb24gYm5wUlNoaWZ0VG8obixyKSB7XG4gIHIucyA9IHRoaXMucztcbiAgdmFyIGRzID0gTWF0aC5mbG9vcihuL3RoaXMuREIpO1xuICBpZihkcyA+PSB0aGlzLnQpIHsgci50ID0gMDsgcmV0dXJuOyB9XG4gIHZhciBicyA9IG4ldGhpcy5EQjtcbiAgdmFyIGNicyA9IHRoaXMuREItYnM7XG4gIHZhciBibSA9ICgxPDxicyktMTtcbiAgclswXSA9IHRoaXNbZHNdPj5icztcbiAgZm9yKHZhciBpID0gZHMrMTsgaSA8IHRoaXMudDsgKytpKSB7XG4gICAgcltpLWRzLTFdIHw9ICh0aGlzW2ldJmJtKTw8Y2JzO1xuICAgIHJbaS1kc10gPSB0aGlzW2ldPj5icztcbiAgfVxuICBpZihicyA+IDApIHJbdGhpcy50LWRzLTFdIHw9ICh0aGlzLnMmYm0pPDxjYnM7XG4gIHIudCA9IHRoaXMudC1kcztcbiAgci5jbGFtcCgpO1xufVxuXG4vLyAocHJvdGVjdGVkKSByID0gdGhpcyAtIGFcbmZ1bmN0aW9uIGJucFN1YlRvKGEscikge1xuICB2YXIgaSA9IDAsIGMgPSAwLCBtID0gTWF0aC5taW4oYS50LHRoaXMudCk7XG4gIHdoaWxlKGkgPCBtKSB7XG4gICAgYyArPSB0aGlzW2ldLWFbaV07XG4gICAgcltpKytdID0gYyZ0aGlzLkRNO1xuICAgIGMgPj49IHRoaXMuREI7XG4gIH1cbiAgaWYoYS50IDwgdGhpcy50KSB7XG4gICAgYyAtPSBhLnM7XG4gICAgd2hpbGUoaSA8IHRoaXMudCkge1xuICAgICAgYyArPSB0aGlzW2ldO1xuICAgICAgcltpKytdID0gYyZ0aGlzLkRNO1xuICAgICAgYyA+Pj0gdGhpcy5EQjtcbiAgICB9XG4gICAgYyArPSB0aGlzLnM7XG4gIH1cbiAgZWxzZSB7XG4gICAgYyArPSB0aGlzLnM7XG4gICAgd2hpbGUoaSA8IGEudCkge1xuICAgICAgYyAtPSBhW2ldO1xuICAgICAgcltpKytdID0gYyZ0aGlzLkRNO1xuICAgICAgYyA+Pj0gdGhpcy5EQjtcbiAgICB9XG4gICAgYyAtPSBhLnM7XG4gIH1cbiAgci5zID0gKGM8MCk/LTE6MDtcbiAgaWYoYyA8IC0xKSByW2krK10gPSB0aGlzLkRWK2M7XG4gIGVsc2UgaWYoYyA+IDApIHJbaSsrXSA9IGM7XG4gIHIudCA9IGk7XG4gIHIuY2xhbXAoKTtcbn1cblxuLy8gKHByb3RlY3RlZCkgciA9IHRoaXMgKiBhLCByICE9IHRoaXMsYSAoSEFDIDE0LjEyKVxuLy8gXCJ0aGlzXCIgc2hvdWxkIGJlIHRoZSBsYXJnZXIgb25lIGlmIGFwcHJvcHJpYXRlLlxuZnVuY3Rpb24gYm5wTXVsdGlwbHlUbyhhLHIpIHtcbiAgdmFyIHggPSB0aGlzLmFicygpLCB5ID0gYS5hYnMoKTtcbiAgdmFyIGkgPSB4LnQ7XG4gIHIudCA9IGkreS50O1xuICB3aGlsZSgtLWkgPj0gMCkgcltpXSA9IDA7XG4gIGZvcihpID0gMDsgaSA8IHkudDsgKytpKSByW2kreC50XSA9IHguYW0oMCx5W2ldLHIsaSwwLHgudCk7XG4gIHIucyA9IDA7XG4gIHIuY2xhbXAoKTtcbiAgaWYodGhpcy5zICE9IGEucykgQmlnSW50ZWdlci5aRVJPLnN1YlRvKHIscik7XG59XG5cbi8vIChwcm90ZWN0ZWQpIHIgPSB0aGlzXjIsIHIgIT0gdGhpcyAoSEFDIDE0LjE2KVxuZnVuY3Rpb24gYm5wU3F1YXJlVG8ocikge1xuICB2YXIgeCA9IHRoaXMuYWJzKCk7XG4gIHZhciBpID0gci50ID0gMip4LnQ7XG4gIHdoaWxlKC0taSA+PSAwKSByW2ldID0gMDtcbiAgZm9yKGkgPSAwOyBpIDwgeC50LTE7ICsraSkge1xuICAgIHZhciBjID0geC5hbShpLHhbaV0sciwyKmksMCwxKTtcbiAgICBpZigocltpK3gudF0rPXguYW0oaSsxLDIqeFtpXSxyLDIqaSsxLGMseC50LWktMSkpID49IHguRFYpIHtcbiAgICAgIHJbaSt4LnRdIC09IHguRFY7XG4gICAgICByW2kreC50KzFdID0gMTtcbiAgICB9XG4gIH1cbiAgaWYoci50ID4gMCkgcltyLnQtMV0gKz0geC5hbShpLHhbaV0sciwyKmksMCwxKTtcbiAgci5zID0gMDtcbiAgci5jbGFtcCgpO1xufVxuXG4vLyAocHJvdGVjdGVkKSBkaXZpZGUgdGhpcyBieSBtLCBxdW90aWVudCBhbmQgcmVtYWluZGVyIHRvIHEsIHIgKEhBQyAxNC4yMClcbi8vIHIgIT0gcSwgdGhpcyAhPSBtLiAgcSBvciByIG1heSBiZSBudWxsLlxuZnVuY3Rpb24gYm5wRGl2UmVtVG8obSxxLHIpIHtcbiAgdmFyIHBtID0gbS5hYnMoKTtcbiAgaWYocG0udCA8PSAwKSByZXR1cm47XG4gIHZhciBwdCA9IHRoaXMuYWJzKCk7XG4gIGlmKHB0LnQgPCBwbS50KSB7XG4gICAgaWYocSAhPSBudWxsKSBxLmZyb21JbnQoMCk7XG4gICAgaWYociAhPSBudWxsKSB0aGlzLmNvcHlUbyhyKTtcbiAgICByZXR1cm47XG4gIH1cbiAgaWYociA9PSBudWxsKSByID0gbmJpKCk7XG4gIHZhciB5ID0gbmJpKCksIHRzID0gdGhpcy5zLCBtcyA9IG0ucztcbiAgdmFyIG5zaCA9IHRoaXMuREItbmJpdHMocG1bcG0udC0xXSk7XHQvLyBub3JtYWxpemUgbW9kdWx1c1xuICBpZihuc2ggPiAwKSB7IHBtLmxTaGlmdFRvKG5zaCx5KTsgcHQubFNoaWZ0VG8obnNoLHIpOyB9XG4gIGVsc2UgeyBwbS5jb3B5VG8oeSk7IHB0LmNvcHlUbyhyKTsgfVxuICB2YXIgeXMgPSB5LnQ7XG4gIHZhciB5MCA9IHlbeXMtMV07XG4gIGlmKHkwID09IDApIHJldHVybjtcbiAgdmFyIHl0ID0geTAqKDE8PHRoaXMuRjEpKygoeXM+MSk/eVt5cy0yXT4+dGhpcy5GMjowKTtcbiAgdmFyIGQxID0gdGhpcy5GVi95dCwgZDIgPSAoMTw8dGhpcy5GMSkveXQsIGUgPSAxPDx0aGlzLkYyO1xuICB2YXIgaSA9IHIudCwgaiA9IGkteXMsIHQgPSAocT09bnVsbCk/bmJpKCk6cTtcbiAgeS5kbFNoaWZ0VG8oaix0KTtcbiAgaWYoci5jb21wYXJlVG8odCkgPj0gMCkge1xuICAgIHJbci50KytdID0gMTtcbiAgICByLnN1YlRvKHQscik7XG4gIH1cbiAgQmlnSW50ZWdlci5PTkUuZGxTaGlmdFRvKHlzLHQpO1xuICB0LnN1YlRvKHkseSk7XHQvLyBcIm5lZ2F0aXZlXCIgeSBzbyB3ZSBjYW4gcmVwbGFjZSBzdWIgd2l0aCBhbSBsYXRlclxuICB3aGlsZSh5LnQgPCB5cykgeVt5LnQrK10gPSAwO1xuICB3aGlsZSgtLWogPj0gMCkge1xuICAgIC8vIEVzdGltYXRlIHF1b3RpZW50IGRpZ2l0XG4gICAgdmFyIHFkID0gKHJbLS1pXT09eTApP3RoaXMuRE06TWF0aC5mbG9vcihyW2ldKmQxKyhyW2ktMV0rZSkqZDIpO1xuICAgIGlmKChyW2ldKz15LmFtKDAscWQscixqLDAseXMpKSA8IHFkKSB7XHQvLyBUcnkgaXQgb3V0XG4gICAgICB5LmRsU2hpZnRUbyhqLHQpO1xuICAgICAgci5zdWJUbyh0LHIpO1xuICAgICAgd2hpbGUocltpXSA8IC0tcWQpIHIuc3ViVG8odCxyKTtcbiAgICB9XG4gIH1cbiAgaWYocSAhPSBudWxsKSB7XG4gICAgci5kclNoaWZ0VG8oeXMscSk7XG4gICAgaWYodHMgIT0gbXMpIEJpZ0ludGVnZXIuWkVSTy5zdWJUbyhxLHEpO1xuICB9XG4gIHIudCA9IHlzO1xuICByLmNsYW1wKCk7XG4gIGlmKG5zaCA+IDApIHIuclNoaWZ0VG8obnNoLHIpO1x0Ly8gRGVub3JtYWxpemUgcmVtYWluZGVyXG4gIGlmKHRzIDwgMCkgQmlnSW50ZWdlci5aRVJPLnN1YlRvKHIscik7XG59XG5cbi8vIChwdWJsaWMpIHRoaXMgbW9kIGFcbmZ1bmN0aW9uIGJuTW9kKGEpIHtcbiAgdmFyIHIgPSBuYmkoKTtcbiAgdGhpcy5hYnMoKS5kaXZSZW1UbyhhLG51bGwscik7XG4gIGlmKHRoaXMucyA8IDAgJiYgci5jb21wYXJlVG8oQmlnSW50ZWdlci5aRVJPKSA+IDApIGEuc3ViVG8ocixyKTtcbiAgcmV0dXJuIHI7XG59XG5cbi8vIE1vZHVsYXIgcmVkdWN0aW9uIHVzaW5nIFwiY2xhc3NpY1wiIGFsZ29yaXRobVxuZnVuY3Rpb24gQ2xhc3NpYyhtKSB7IHRoaXMubSA9IG07IH1cbmZ1bmN0aW9uIGNDb252ZXJ0KHgpIHtcbiAgaWYoeC5zIDwgMCB8fCB4LmNvbXBhcmVUbyh0aGlzLm0pID49IDApIHJldHVybiB4Lm1vZCh0aGlzLm0pO1xuICBlbHNlIHJldHVybiB4O1xufVxuZnVuY3Rpb24gY1JldmVydCh4KSB7IHJldHVybiB4OyB9XG5mdW5jdGlvbiBjUmVkdWNlKHgpIHsgeC5kaXZSZW1Ubyh0aGlzLm0sbnVsbCx4KTsgfVxuZnVuY3Rpb24gY011bFRvKHgseSxyKSB7IHgubXVsdGlwbHlUbyh5LHIpOyB0aGlzLnJlZHVjZShyKTsgfVxuZnVuY3Rpb24gY1NxclRvKHgscikgeyB4LnNxdWFyZVRvKHIpOyB0aGlzLnJlZHVjZShyKTsgfVxuXG5DbGFzc2ljLnByb3RvdHlwZS5jb252ZXJ0ID0gY0NvbnZlcnQ7XG5DbGFzc2ljLnByb3RvdHlwZS5yZXZlcnQgPSBjUmV2ZXJ0O1xuQ2xhc3NpYy5wcm90b3R5cGUucmVkdWNlID0gY1JlZHVjZTtcbkNsYXNzaWMucHJvdG90eXBlLm11bFRvID0gY011bFRvO1xuQ2xhc3NpYy5wcm90b3R5cGUuc3FyVG8gPSBjU3FyVG87XG5cbi8vIChwcm90ZWN0ZWQpIHJldHVybiBcIi0xL3RoaXMgJSAyXkRCXCI7IHVzZWZ1bCBmb3IgTW9udC4gcmVkdWN0aW9uXG4vLyBqdXN0aWZpY2F0aW9uOlxuLy8gICAgICAgICB4eSA9PSAxIChtb2QgbSlcbi8vICAgICAgICAgeHkgPSAgMStrbVxuLy8gICB4eSgyLXh5KSA9ICgxK2ttKSgxLWttKVxuLy8geFt5KDIteHkpXSA9IDEta14ybV4yXG4vLyB4W3koMi14eSldID09IDEgKG1vZCBtXjIpXG4vLyBpZiB5IGlzIDEveCBtb2QgbSwgdGhlbiB5KDIteHkpIGlzIDEveCBtb2QgbV4yXG4vLyBzaG91bGQgcmVkdWNlIHggYW5kIHkoMi14eSkgYnkgbV4yIGF0IGVhY2ggc3RlcCB0byBrZWVwIHNpemUgYm91bmRlZC5cbi8vIEpTIG11bHRpcGx5IFwib3ZlcmZsb3dzXCIgZGlmZmVyZW50bHkgZnJvbSBDL0MrKywgc28gY2FyZSBpcyBuZWVkZWQgaGVyZS5cbmZ1bmN0aW9uIGJucEludkRpZ2l0KCkge1xuICBpZih0aGlzLnQgPCAxKSByZXR1cm4gMDtcbiAgdmFyIHggPSB0aGlzWzBdO1xuICBpZigoeCYxKSA9PSAwKSByZXR1cm4gMDtcbiAgdmFyIHkgPSB4JjM7XHRcdC8vIHkgPT0gMS94IG1vZCAyXjJcbiAgeSA9ICh5KigyLSh4JjB4ZikqeSkpJjB4ZjtcdC8vIHkgPT0gMS94IG1vZCAyXjRcbiAgeSA9ICh5KigyLSh4JjB4ZmYpKnkpKSYweGZmO1x0Ly8geSA9PSAxL3ggbW9kIDJeOFxuICB5ID0gKHkqKDItKCgoeCYweGZmZmYpKnkpJjB4ZmZmZikpKSYweGZmZmY7XHQvLyB5ID09IDEveCBtb2QgMl4xNlxuICAvLyBsYXN0IHN0ZXAgLSBjYWxjdWxhdGUgaW52ZXJzZSBtb2QgRFYgZGlyZWN0bHk7XG4gIC8vIGFzc3VtZXMgMTYgPCBEQiA8PSAzMiBhbmQgYXNzdW1lcyBhYmlsaXR5IHRvIGhhbmRsZSA0OC1iaXQgaW50c1xuICB5ID0gKHkqKDIteCp5JXRoaXMuRFYpKSV0aGlzLkRWO1x0XHQvLyB5ID09IDEveCBtb2QgMl5kYml0c1xuICAvLyB3ZSByZWFsbHkgd2FudCB0aGUgbmVnYXRpdmUgaW52ZXJzZSwgYW5kIC1EViA8IHkgPCBEVlxuICByZXR1cm4gKHk+MCk/dGhpcy5EVi15Oi15O1xufVxuXG4vLyBNb250Z29tZXJ5IHJlZHVjdGlvblxuZnVuY3Rpb24gTW9udGdvbWVyeShtKSB7XG4gIHRoaXMubSA9IG07XG4gIHRoaXMubXAgPSBtLmludkRpZ2l0KCk7XG4gIHRoaXMubXBsID0gdGhpcy5tcCYweDdmZmY7XG4gIHRoaXMubXBoID0gdGhpcy5tcD4+MTU7XG4gIHRoaXMudW0gPSAoMTw8KG0uREItMTUpKS0xO1xuICB0aGlzLm10MiA9IDIqbS50O1xufVxuXG4vLyB4UiBtb2QgbVxuZnVuY3Rpb24gbW9udENvbnZlcnQoeCkge1xuICB2YXIgciA9IG5iaSgpO1xuICB4LmFicygpLmRsU2hpZnRUbyh0aGlzLm0udCxyKTtcbiAgci5kaXZSZW1Ubyh0aGlzLm0sbnVsbCxyKTtcbiAgaWYoeC5zIDwgMCAmJiByLmNvbXBhcmVUbyhCaWdJbnRlZ2VyLlpFUk8pID4gMCkgdGhpcy5tLnN1YlRvKHIscik7XG4gIHJldHVybiByO1xufVxuXG4vLyB4L1IgbW9kIG1cbmZ1bmN0aW9uIG1vbnRSZXZlcnQoeCkge1xuICB2YXIgciA9IG5iaSgpO1xuICB4LmNvcHlUbyhyKTtcbiAgdGhpcy5yZWR1Y2Uocik7XG4gIHJldHVybiByO1xufVxuXG4vLyB4ID0geC9SIG1vZCBtIChIQUMgMTQuMzIpXG5mdW5jdGlvbiBtb250UmVkdWNlKHgpIHtcbiAgd2hpbGUoeC50IDw9IHRoaXMubXQyKVx0Ly8gcGFkIHggc28gYW0gaGFzIGVub3VnaCByb29tIGxhdGVyXG4gICAgeFt4LnQrK10gPSAwO1xuICBmb3IodmFyIGkgPSAwOyBpIDwgdGhpcy5tLnQ7ICsraSkge1xuICAgIC8vIGZhc3RlciB3YXkgb2YgY2FsY3VsYXRpbmcgdTAgPSB4W2ldKm1wIG1vZCBEVlxuICAgIHZhciBqID0geFtpXSYweDdmZmY7XG4gICAgdmFyIHUwID0gKGoqdGhpcy5tcGwrKCgoaip0aGlzLm1waCsoeFtpXT4+MTUpKnRoaXMubXBsKSZ0aGlzLnVtKTw8MTUpKSZ4LkRNO1xuICAgIC8vIHVzZSBhbSB0byBjb21iaW5lIHRoZSBtdWx0aXBseS1zaGlmdC1hZGQgaW50byBvbmUgY2FsbFxuICAgIGogPSBpK3RoaXMubS50O1xuICAgIHhbal0gKz0gdGhpcy5tLmFtKDAsdTAseCxpLDAsdGhpcy5tLnQpO1xuICAgIC8vIHByb3BhZ2F0ZSBjYXJyeVxuICAgIHdoaWxlKHhbal0gPj0geC5EVikgeyB4W2pdIC09IHguRFY7IHhbKytqXSsrOyB9XG4gIH1cbiAgeC5jbGFtcCgpO1xuICB4LmRyU2hpZnRUbyh0aGlzLm0udCx4KTtcbiAgaWYoeC5jb21wYXJlVG8odGhpcy5tKSA+PSAwKSB4LnN1YlRvKHRoaXMubSx4KTtcbn1cblxuLy8gciA9IFwieF4yL1IgbW9kIG1cIjsgeCAhPSByXG5mdW5jdGlvbiBtb250U3FyVG8oeCxyKSB7IHguc3F1YXJlVG8ocik7IHRoaXMucmVkdWNlKHIpOyB9XG5cbi8vIHIgPSBcInh5L1IgbW9kIG1cIjsgeCx5ICE9IHJcbmZ1bmN0aW9uIG1vbnRNdWxUbyh4LHkscikgeyB4Lm11bHRpcGx5VG8oeSxyKTsgdGhpcy5yZWR1Y2Uocik7IH1cblxuTW9udGdvbWVyeS5wcm90b3R5cGUuY29udmVydCA9IG1vbnRDb252ZXJ0O1xuTW9udGdvbWVyeS5wcm90b3R5cGUucmV2ZXJ0ID0gbW9udFJldmVydDtcbk1vbnRnb21lcnkucHJvdG90eXBlLnJlZHVjZSA9IG1vbnRSZWR1Y2U7XG5Nb250Z29tZXJ5LnByb3RvdHlwZS5tdWxUbyA9IG1vbnRNdWxUbztcbk1vbnRnb21lcnkucHJvdG90eXBlLnNxclRvID0gbW9udFNxclRvO1xuXG4vLyAocHJvdGVjdGVkKSB0cnVlIGlmZiB0aGlzIGlzIGV2ZW5cbmZ1bmN0aW9uIGJucElzRXZlbigpIHsgcmV0dXJuICgodGhpcy50PjApPyh0aGlzWzBdJjEpOnRoaXMucykgPT0gMDsgfVxuXG4vLyAocHJvdGVjdGVkKSB0aGlzXmUsIGUgPCAyXjMyLCBkb2luZyBzcXIgYW5kIG11bCB3aXRoIFwiclwiIChIQUMgMTQuNzkpXG5mdW5jdGlvbiBibnBFeHAoZSx6KSB7XG4gIGlmKGUgPiAweGZmZmZmZmZmIHx8IGUgPCAxKSByZXR1cm4gQmlnSW50ZWdlci5PTkU7XG4gIHZhciByID0gbmJpKCksIHIyID0gbmJpKCksIGcgPSB6LmNvbnZlcnQodGhpcyksIGkgPSBuYml0cyhlKS0xO1xuICBnLmNvcHlUbyhyKTtcbiAgd2hpbGUoLS1pID49IDApIHtcbiAgICB6LnNxclRvKHIscjIpO1xuICAgIGlmKChlJigxPDxpKSkgPiAwKSB6Lm11bFRvKHIyLGcscik7XG4gICAgZWxzZSB7IHZhciB0ID0gcjsgciA9IHIyOyByMiA9IHQ7IH1cbiAgfVxuICByZXR1cm4gei5yZXZlcnQocik7XG59XG5cbi8vIChwdWJsaWMpIHRoaXNeZSAlIG0sIDAgPD0gZSA8IDJeMzJcbmZ1bmN0aW9uIGJuTW9kUG93SW50KGUsbSkge1xuICB2YXIgejtcbiAgaWYoZSA8IDI1NiB8fCBtLmlzRXZlbigpKSB6ID0gbmV3IENsYXNzaWMobSk7IGVsc2UgeiA9IG5ldyBNb250Z29tZXJ5KG0pO1xuICByZXR1cm4gdGhpcy5leHAoZSx6KTtcbn1cblxuLy8gcHJvdGVjdGVkXG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5jb3B5VG8gPSBibnBDb3B5VG87XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5mcm9tSW50ID0gYm5wRnJvbUludDtcbkJpZ0ludGVnZXIucHJvdG90eXBlLmZyb21TdHJpbmcgPSBibnBGcm9tU3RyaW5nO1xuQmlnSW50ZWdlci5wcm90b3R5cGUuY2xhbXAgPSBibnBDbGFtcDtcbkJpZ0ludGVnZXIucHJvdG90eXBlLmRsU2hpZnRUbyA9IGJucERMU2hpZnRUbztcbkJpZ0ludGVnZXIucHJvdG90eXBlLmRyU2hpZnRUbyA9IGJucERSU2hpZnRUbztcbkJpZ0ludGVnZXIucHJvdG90eXBlLmxTaGlmdFRvID0gYm5wTFNoaWZ0VG87XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5yU2hpZnRUbyA9IGJucFJTaGlmdFRvO1xuQmlnSW50ZWdlci5wcm90b3R5cGUuc3ViVG8gPSBibnBTdWJUbztcbkJpZ0ludGVnZXIucHJvdG90eXBlLm11bHRpcGx5VG8gPSBibnBNdWx0aXBseVRvO1xuQmlnSW50ZWdlci5wcm90b3R5cGUuc3F1YXJlVG8gPSBibnBTcXVhcmVUbztcbkJpZ0ludGVnZXIucHJvdG90eXBlLmRpdlJlbVRvID0gYm5wRGl2UmVtVG87XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5pbnZEaWdpdCA9IGJucEludkRpZ2l0O1xuQmlnSW50ZWdlci5wcm90b3R5cGUuaXNFdmVuID0gYm5wSXNFdmVuO1xuQmlnSW50ZWdlci5wcm90b3R5cGUuZXhwID0gYm5wRXhwO1xuXG4vLyBwdWJsaWNcbkJpZ0ludGVnZXIucHJvdG90eXBlLnRvU3RyaW5nID0gYm5Ub1N0cmluZztcbkJpZ0ludGVnZXIucHJvdG90eXBlLm5lZ2F0ZSA9IGJuTmVnYXRlO1xuQmlnSW50ZWdlci5wcm90b3R5cGUuYWJzID0gYm5BYnM7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5jb21wYXJlVG8gPSBibkNvbXBhcmVUbztcbkJpZ0ludGVnZXIucHJvdG90eXBlLmJpdExlbmd0aCA9IGJuQml0TGVuZ3RoO1xuQmlnSW50ZWdlci5wcm90b3R5cGUubW9kID0gYm5Nb2Q7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5tb2RQb3dJbnQgPSBibk1vZFBvd0ludDtcblxuLy8gXCJjb25zdGFudHNcIlxuQmlnSW50ZWdlci5aRVJPID0gbmJ2KDApO1xuQmlnSW50ZWdlci5PTkUgPSBuYnYoMSk7XG5cbm1vZHVsZS5leHBvcnRzID0gQmlnSW50ZWdlcjtcblxuXG5cblxuXG5cblxuXG5cblxuXG5cblxuXG5cblxuXG5cblxuLypcbiAqIENvcHlyaWdodCAoYykgMjAwMy0yMDA1ICBUb20gV3UgKHRqd0Bjcy5TdGFuZm9yZC5FRFUpIFxuICogQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqXG4gKiBNb2RpZmllZCBieSBSZWN1cml0eSBMYWJzIEdtYkhcbiAqXG4gKiBQZXJtaXNzaW9uIGlzIGhlcmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55IHBlcnNvbiBvYnRhaW5pbmdcbiAqIGEgY29weSBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRvY3VtZW50YXRpb24gZmlsZXMgKHRoZVxuICogXCJTb2Z0d2FyZVwiKSwgdG8gZGVhbCBpbiB0aGUgU29mdHdhcmUgd2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nXG4gKiB3aXRob3V0IGxpbWl0YXRpb24gdGhlIHJpZ2h0cyB0byB1c2UsIGNvcHksIG1vZGlmeSwgbWVyZ2UsIHB1Ymxpc2gsXG4gKiBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLCBhbmQvb3Igc2VsbCBjb3BpZXMgb2YgdGhlIFNvZnR3YXJlLCBhbmQgdG9cbiAqIHBlcm1pdCBwZXJzb25zIHRvIHdob20gdGhlIFNvZnR3YXJlIGlzIGZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0b1xuICogdGhlIGZvbGxvd2luZyBjb25kaXRpb25zOlxuICpcbiAqIFRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlIHNoYWxsIGJlXG4gKiBpbmNsdWRlZCBpbiBhbGwgY29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS5cbiAqXG4gKiBUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgXCJBUy1JU1wiIEFORCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBcbiAqIEVYUFJFU1MsIElNUExJRUQgT1IgT1RIRVJXSVNFLCBJTkNMVURJTkcgV0lUSE9VVCBMSU1JVEFUSU9OLCBBTlkgXG4gKiBXQVJSQU5UWSBPRiBNRVJDSEFOVEFCSUxJVFkgT1IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBcbiAqXG4gKiBJTiBOTyBFVkVOVCBTSEFMTCBUT00gV1UgQkUgTElBQkxFIEZPUiBBTlkgU1BFQ0lBTCwgSU5DSURFTlRBTCxcbiAqIElORElSRUNUIE9SIENPTlNFUVVFTlRJQUwgREFNQUdFUyBPRiBBTlkgS0lORCwgT1IgQU5ZIERBTUFHRVMgV0hBVFNPRVZFUlxuICogUkVTVUxUSU5HIEZST00gTE9TUyBPRiBVU0UsIERBVEEgT1IgUFJPRklUUywgV0hFVEhFUiBPUiBOT1QgQURWSVNFRCBPRlxuICogVEhFIFBPU1NJQklMSVRZIE9GIERBTUFHRSwgQU5EIE9OIEFOWSBUSEVPUlkgT0YgTElBQklMSVRZLCBBUklTSU5HIE9VVFxuICogT0YgT1IgSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBVU0UgT1IgUEVSRk9STUFOQ0UgT0YgVEhJUyBTT0ZUV0FSRS5cbiAqXG4gKiBJbiBhZGRpdGlvbiwgdGhlIGZvbGxvd2luZyBjb25kaXRpb24gYXBwbGllczpcbiAqXG4gKiBBbGwgcmVkaXN0cmlidXRpb25zIG11c3QgcmV0YWluIGFuIGludGFjdCBjb3B5IG9mIHRoaXMgY29weXJpZ2h0IG5vdGljZVxuICogYW5kIGRpc2NsYWltZXIuXG4gKi9cblxuXG4vLyBFeHRlbmRlZCBKYXZhU2NyaXB0IEJOIGZ1bmN0aW9ucywgcmVxdWlyZWQgZm9yIFJTQSBwcml2YXRlIG9wcy5cblxuLy8gVmVyc2lvbiAxLjE6IG5ldyBCaWdJbnRlZ2VyKFwiMFwiLCAxMCkgcmV0dXJucyBcInByb3BlclwiIHplcm9cbi8vIFZlcnNpb24gMS4yOiBzcXVhcmUoKSBBUEksIGlzUHJvYmFibGVQcmltZSBmaXhcblxuLy8gKHB1YmxpYylcbmZ1bmN0aW9uIGJuQ2xvbmUoKSB7IHZhciByID0gbmJpKCk7IHRoaXMuY29weVRvKHIpOyByZXR1cm4gcjsgfVxuXG4vLyAocHVibGljKSByZXR1cm4gdmFsdWUgYXMgaW50ZWdlclxuZnVuY3Rpb24gYm5JbnRWYWx1ZSgpIHtcbiAgaWYodGhpcy5zIDwgMCkge1xuICAgIGlmKHRoaXMudCA9PSAxKSByZXR1cm4gdGhpc1swXS10aGlzLkRWO1xuICAgIGVsc2UgaWYodGhpcy50ID09IDApIHJldHVybiAtMTtcbiAgfVxuICBlbHNlIGlmKHRoaXMudCA9PSAxKSByZXR1cm4gdGhpc1swXTtcbiAgZWxzZSBpZih0aGlzLnQgPT0gMCkgcmV0dXJuIDA7XG4gIC8vIGFzc3VtZXMgMTYgPCBEQiA8IDMyXG4gIHJldHVybiAoKHRoaXNbMV0mKCgxPDwoMzItdGhpcy5EQikpLTEpKTw8dGhpcy5EQil8dGhpc1swXTtcbn1cblxuLy8gKHB1YmxpYykgcmV0dXJuIHZhbHVlIGFzIGJ5dGVcbmZ1bmN0aW9uIGJuQnl0ZVZhbHVlKCkgeyByZXR1cm4gKHRoaXMudD09MCk/dGhpcy5zOih0aGlzWzBdPDwyNCk+PjI0OyB9XG5cbi8vIChwdWJsaWMpIHJldHVybiB2YWx1ZSBhcyBzaG9ydCAoYXNzdW1lcyBEQj49MTYpXG5mdW5jdGlvbiBiblNob3J0VmFsdWUoKSB7IHJldHVybiAodGhpcy50PT0wKT90aGlzLnM6KHRoaXNbMF08PDE2KT4+MTY7IH1cblxuLy8gKHByb3RlY3RlZCkgcmV0dXJuIHggcy50LiByXnggPCBEVlxuZnVuY3Rpb24gYm5wQ2h1bmtTaXplKHIpIHsgcmV0dXJuIE1hdGguZmxvb3IoTWF0aC5MTjIqdGhpcy5EQi9NYXRoLmxvZyhyKSk7IH1cblxuLy8gKHB1YmxpYykgMCBpZiB0aGlzID09IDAsIDEgaWYgdGhpcyA+IDBcbmZ1bmN0aW9uIGJuU2lnTnVtKCkge1xuICBpZih0aGlzLnMgPCAwKSByZXR1cm4gLTE7XG4gIGVsc2UgaWYodGhpcy50IDw9IDAgfHwgKHRoaXMudCA9PSAxICYmIHRoaXNbMF0gPD0gMCkpIHJldHVybiAwO1xuICBlbHNlIHJldHVybiAxO1xufVxuXG4vLyAocHJvdGVjdGVkKSBjb252ZXJ0IHRvIHJhZGl4IHN0cmluZ1xuZnVuY3Rpb24gYm5wVG9SYWRpeChiKSB7XG4gIGlmKGIgPT0gbnVsbCkgYiA9IDEwO1xuICBpZih0aGlzLnNpZ251bSgpID09IDAgfHwgYiA8IDIgfHwgYiA+IDM2KSByZXR1cm4gXCIwXCI7XG4gIHZhciBjcyA9IHRoaXMuY2h1bmtTaXplKGIpO1xuICB2YXIgYSA9IE1hdGgucG93KGIsY3MpO1xuICB2YXIgZCA9IG5idihhKSwgeSA9IG5iaSgpLCB6ID0gbmJpKCksIHIgPSBcIlwiO1xuICB0aGlzLmRpdlJlbVRvKGQseSx6KTtcbiAgd2hpbGUoeS5zaWdudW0oKSA+IDApIHtcbiAgICByID0gKGErei5pbnRWYWx1ZSgpKS50b1N0cmluZyhiKS5zdWJzdHIoMSkgKyByO1xuICAgIHkuZGl2UmVtVG8oZCx5LHopO1xuICB9XG4gIHJldHVybiB6LmludFZhbHVlKCkudG9TdHJpbmcoYikgKyByO1xufVxuXG4vLyAocHJvdGVjdGVkKSBjb252ZXJ0IGZyb20gcmFkaXggc3RyaW5nXG5mdW5jdGlvbiBibnBGcm9tUmFkaXgocyxiKSB7XG4gIHRoaXMuZnJvbUludCgwKTtcbiAgaWYoYiA9PSBudWxsKSBiID0gMTA7XG4gIHZhciBjcyA9IHRoaXMuY2h1bmtTaXplKGIpO1xuICB2YXIgZCA9IE1hdGgucG93KGIsY3MpLCBtaSA9IGZhbHNlLCBqID0gMCwgdyA9IDA7XG4gIGZvcih2YXIgaSA9IDA7IGkgPCBzLmxlbmd0aDsgKytpKSB7XG4gICAgdmFyIHggPSBpbnRBdChzLGkpO1xuICAgIGlmKHggPCAwKSB7XG4gICAgICBpZihzLmNoYXJBdChpKSA9PSBcIi1cIiAmJiB0aGlzLnNpZ251bSgpID09IDApIG1pID0gdHJ1ZTtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cbiAgICB3ID0gYip3K3g7XG4gICAgaWYoKytqID49IGNzKSB7XG4gICAgICB0aGlzLmRNdWx0aXBseShkKTtcbiAgICAgIHRoaXMuZEFkZE9mZnNldCh3LDApO1xuICAgICAgaiA9IDA7XG4gICAgICB3ID0gMDtcbiAgICB9XG4gIH1cbiAgaWYoaiA+IDApIHtcbiAgICB0aGlzLmRNdWx0aXBseShNYXRoLnBvdyhiLGopKTtcbiAgICB0aGlzLmRBZGRPZmZzZXQodywwKTtcbiAgfVxuICBpZihtaSkgQmlnSW50ZWdlci5aRVJPLnN1YlRvKHRoaXMsdGhpcyk7XG59XG5cbi8vIChwcm90ZWN0ZWQpIGFsdGVybmF0ZSBjb25zdHJ1Y3RvclxuZnVuY3Rpb24gYm5wRnJvbU51bWJlcihhLGIsYykge1xuICBpZihcIm51bWJlclwiID09IHR5cGVvZiBiKSB7XG4gICAgLy8gbmV3IEJpZ0ludGVnZXIoaW50LGludCxSTkcpXG4gICAgaWYoYSA8IDIpIHRoaXMuZnJvbUludCgxKTtcbiAgICBlbHNlIHtcbiAgICAgIHRoaXMuZnJvbU51bWJlcihhLGMpO1xuICAgICAgaWYoIXRoaXMudGVzdEJpdChhLTEpKVx0Ly8gZm9yY2UgTVNCIHNldFxuICAgICAgICB0aGlzLmJpdHdpc2VUbyhCaWdJbnRlZ2VyLk9ORS5zaGlmdExlZnQoYS0xKSxvcF9vcix0aGlzKTtcbiAgICAgIGlmKHRoaXMuaXNFdmVuKCkpIHRoaXMuZEFkZE9mZnNldCgxLDApOyAvLyBmb3JjZSBvZGRcbiAgICAgIHdoaWxlKCF0aGlzLmlzUHJvYmFibGVQcmltZShiKSkge1xuICAgICAgICB0aGlzLmRBZGRPZmZzZXQoMiwwKTtcbiAgICAgICAgaWYodGhpcy5iaXRMZW5ndGgoKSA+IGEpIHRoaXMuc3ViVG8oQmlnSW50ZWdlci5PTkUuc2hpZnRMZWZ0KGEtMSksdGhpcyk7XG4gICAgICB9XG4gICAgfVxuICB9XG4gIGVsc2Uge1xuICAgIC8vIG5ldyBCaWdJbnRlZ2VyKGludCxSTkcpXG4gICAgdmFyIHggPSBuZXcgQXJyYXkoKSwgdCA9IGEmNztcbiAgICB4Lmxlbmd0aCA9IChhPj4zKSsxO1xuICAgIGIubmV4dEJ5dGVzKHgpO1xuICAgIGlmKHQgPiAwKSB4WzBdICY9ICgoMTw8dCktMSk7IGVsc2UgeFswXSA9IDA7XG4gICAgdGhpcy5mcm9tU3RyaW5nKHgsMjU2KTtcbiAgfVxufVxuXG4vLyAocHVibGljKSBjb252ZXJ0IHRvIGJpZ2VuZGlhbiBieXRlIGFycmF5XG5mdW5jdGlvbiBiblRvQnl0ZUFycmF5KCkge1xuICB2YXIgaSA9IHRoaXMudCwgciA9IG5ldyBBcnJheSgpO1xuICByWzBdID0gdGhpcy5zO1xuICB2YXIgcCA9IHRoaXMuREItKGkqdGhpcy5EQiklOCwgZCwgayA9IDA7XG4gIGlmKGktLSA+IDApIHtcbiAgICBpZihwIDwgdGhpcy5EQiAmJiAoZCA9IHRoaXNbaV0+PnApICE9ICh0aGlzLnMmdGhpcy5ETSk+PnApXG4gICAgICByW2srK10gPSBkfCh0aGlzLnM8PCh0aGlzLkRCLXApKTtcbiAgICB3aGlsZShpID49IDApIHtcbiAgICAgIGlmKHAgPCA4KSB7XG4gICAgICAgIGQgPSAodGhpc1tpXSYoKDE8PHApLTEpKTw8KDgtcCk7XG4gICAgICAgIGQgfD0gdGhpc1stLWldPj4ocCs9dGhpcy5EQi04KTtcbiAgICAgIH1cbiAgICAgIGVsc2Uge1xuICAgICAgICBkID0gKHRoaXNbaV0+PihwLT04KSkmMHhmZjtcbiAgICAgICAgaWYocCA8PSAwKSB7IHAgKz0gdGhpcy5EQjsgLS1pOyB9XG4gICAgICB9XG4gICAgICAvL2lmKChkJjB4ODApICE9IDApIGQgfD0gLTI1NjtcbiAgICAgIC8vaWYoayA9PSAwICYmICh0aGlzLnMmMHg4MCkgIT0gKGQmMHg4MCkpICsraztcbiAgICAgIGlmKGsgPiAwIHx8IGQgIT0gdGhpcy5zKSByW2srK10gPSBkO1xuICAgIH1cbiAgfVxuICByZXR1cm4gcjtcbn1cblxuZnVuY3Rpb24gYm5FcXVhbHMoYSkgeyByZXR1cm4odGhpcy5jb21wYXJlVG8oYSk9PTApOyB9XG5mdW5jdGlvbiBibk1pbihhKSB7IHJldHVybih0aGlzLmNvbXBhcmVUbyhhKTwwKT90aGlzOmE7IH1cbmZ1bmN0aW9uIGJuTWF4KGEpIHsgcmV0dXJuKHRoaXMuY29tcGFyZVRvKGEpPjApP3RoaXM6YTsgfVxuXG4vLyAocHJvdGVjdGVkKSByID0gdGhpcyBvcCBhIChiaXR3aXNlKVxuZnVuY3Rpb24gYm5wQml0d2lzZVRvKGEsb3Ascikge1xuICB2YXIgaSwgZiwgbSA9IE1hdGgubWluKGEudCx0aGlzLnQpO1xuICBmb3IoaSA9IDA7IGkgPCBtOyArK2kpIHJbaV0gPSBvcCh0aGlzW2ldLGFbaV0pO1xuICBpZihhLnQgPCB0aGlzLnQpIHtcbiAgICBmID0gYS5zJnRoaXMuRE07XG4gICAgZm9yKGkgPSBtOyBpIDwgdGhpcy50OyArK2kpIHJbaV0gPSBvcCh0aGlzW2ldLGYpO1xuICAgIHIudCA9IHRoaXMudDtcbiAgfVxuICBlbHNlIHtcbiAgICBmID0gdGhpcy5zJnRoaXMuRE07XG4gICAgZm9yKGkgPSBtOyBpIDwgYS50OyArK2kpIHJbaV0gPSBvcChmLGFbaV0pO1xuICAgIHIudCA9IGEudDtcbiAgfVxuICByLnMgPSBvcCh0aGlzLnMsYS5zKTtcbiAgci5jbGFtcCgpO1xufVxuXG4vLyAocHVibGljKSB0aGlzICYgYVxuZnVuY3Rpb24gb3BfYW5kKHgseSkgeyByZXR1cm4geCZ5OyB9XG5mdW5jdGlvbiBibkFuZChhKSB7IHZhciByID0gbmJpKCk7IHRoaXMuYml0d2lzZVRvKGEsb3BfYW5kLHIpOyByZXR1cm4gcjsgfVxuXG4vLyAocHVibGljKSB0aGlzIHwgYVxuZnVuY3Rpb24gb3Bfb3IoeCx5KSB7IHJldHVybiB4fHk7IH1cbmZ1bmN0aW9uIGJuT3IoYSkgeyB2YXIgciA9IG5iaSgpOyB0aGlzLmJpdHdpc2VUbyhhLG9wX29yLHIpOyByZXR1cm4gcjsgfVxuXG4vLyAocHVibGljKSB0aGlzIF4gYVxuZnVuY3Rpb24gb3BfeG9yKHgseSkgeyByZXR1cm4geF55OyB9XG5mdW5jdGlvbiBiblhvcihhKSB7IHZhciByID0gbmJpKCk7IHRoaXMuYml0d2lzZVRvKGEsb3BfeG9yLHIpOyByZXR1cm4gcjsgfVxuXG4vLyAocHVibGljKSB0aGlzICYgfmFcbmZ1bmN0aW9uIG9wX2FuZG5vdCh4LHkpIHsgcmV0dXJuIHgmfnk7IH1cbmZ1bmN0aW9uIGJuQW5kTm90KGEpIHsgdmFyIHIgPSBuYmkoKTsgdGhpcy5iaXR3aXNlVG8oYSxvcF9hbmRub3Qscik7IHJldHVybiByOyB9XG5cbi8vIChwdWJsaWMpIH50aGlzXG5mdW5jdGlvbiBibk5vdCgpIHtcbiAgdmFyIHIgPSBuYmkoKTtcbiAgZm9yKHZhciBpID0gMDsgaSA8IHRoaXMudDsgKytpKSByW2ldID0gdGhpcy5ETSZ+dGhpc1tpXTtcbiAgci50ID0gdGhpcy50O1xuICByLnMgPSB+dGhpcy5zO1xuICByZXR1cm4gcjtcbn1cblxuLy8gKHB1YmxpYykgdGhpcyA8PCBuXG5mdW5jdGlvbiBiblNoaWZ0TGVmdChuKSB7XG4gIHZhciByID0gbmJpKCk7XG4gIGlmKG4gPCAwKSB0aGlzLnJTaGlmdFRvKC1uLHIpOyBlbHNlIHRoaXMubFNoaWZ0VG8obixyKTtcbiAgcmV0dXJuIHI7XG59XG5cbi8vIChwdWJsaWMpIHRoaXMgPj4gblxuZnVuY3Rpb24gYm5TaGlmdFJpZ2h0KG4pIHtcbiAgdmFyIHIgPSBuYmkoKTtcbiAgaWYobiA8IDApIHRoaXMubFNoaWZ0VG8oLW4scik7IGVsc2UgdGhpcy5yU2hpZnRUbyhuLHIpO1xuICByZXR1cm4gcjtcbn1cblxuLy8gcmV0dXJuIGluZGV4IG9mIGxvd2VzdCAxLWJpdCBpbiB4LCB4IDwgMl4zMVxuZnVuY3Rpb24gbGJpdCh4KSB7XG4gIGlmKHggPT0gMCkgcmV0dXJuIC0xO1xuICB2YXIgciA9IDA7XG4gIGlmKCh4JjB4ZmZmZikgPT0gMCkgeyB4ID4+PSAxNjsgciArPSAxNjsgfVxuICBpZigoeCYweGZmKSA9PSAwKSB7IHggPj49IDg7IHIgKz0gODsgfVxuICBpZigoeCYweGYpID09IDApIHsgeCA+Pj0gNDsgciArPSA0OyB9XG4gIGlmKCh4JjMpID09IDApIHsgeCA+Pj0gMjsgciArPSAyOyB9XG4gIGlmKCh4JjEpID09IDApICsrcjtcbiAgcmV0dXJuIHI7XG59XG5cbi8vIChwdWJsaWMpIHJldHVybnMgaW5kZXggb2YgbG93ZXN0IDEtYml0IChvciAtMSBpZiBub25lKVxuZnVuY3Rpb24gYm5HZXRMb3dlc3RTZXRCaXQoKSB7XG4gIGZvcih2YXIgaSA9IDA7IGkgPCB0aGlzLnQ7ICsraSlcbiAgICBpZih0aGlzW2ldICE9IDApIHJldHVybiBpKnRoaXMuREIrbGJpdCh0aGlzW2ldKTtcbiAgaWYodGhpcy5zIDwgMCkgcmV0dXJuIHRoaXMudCp0aGlzLkRCO1xuICByZXR1cm4gLTE7XG59XG5cbi8vIHJldHVybiBudW1iZXIgb2YgMSBiaXRzIGluIHhcbmZ1bmN0aW9uIGNiaXQoeCkge1xuICB2YXIgciA9IDA7XG4gIHdoaWxlKHggIT0gMCkgeyB4ICY9IHgtMTsgKytyOyB9XG4gIHJldHVybiByO1xufVxuXG4vLyAocHVibGljKSByZXR1cm4gbnVtYmVyIG9mIHNldCBiaXRzXG5mdW5jdGlvbiBibkJpdENvdW50KCkge1xuICB2YXIgciA9IDAsIHggPSB0aGlzLnMmdGhpcy5ETTtcbiAgZm9yKHZhciBpID0gMDsgaSA8IHRoaXMudDsgKytpKSByICs9IGNiaXQodGhpc1tpXV54KTtcbiAgcmV0dXJuIHI7XG59XG5cbi8vIChwdWJsaWMpIHRydWUgaWZmIG50aCBiaXQgaXMgc2V0XG5mdW5jdGlvbiBiblRlc3RCaXQobikge1xuICB2YXIgaiA9IE1hdGguZmxvb3Iobi90aGlzLkRCKTtcbiAgaWYoaiA+PSB0aGlzLnQpIHJldHVybih0aGlzLnMhPTApO1xuICByZXR1cm4oKHRoaXNbal0mKDE8PChuJXRoaXMuREIpKSkhPTApO1xufVxuXG4vLyAocHJvdGVjdGVkKSB0aGlzIG9wICgxPDxuKVxuZnVuY3Rpb24gYm5wQ2hhbmdlQml0KG4sb3ApIHtcbiAgdmFyIHIgPSBCaWdJbnRlZ2VyLk9ORS5zaGlmdExlZnQobik7XG4gIHRoaXMuYml0d2lzZVRvKHIsb3Ascik7XG4gIHJldHVybiByO1xufVxuXG4vLyAocHVibGljKSB0aGlzIHwgKDE8PG4pXG5mdW5jdGlvbiBiblNldEJpdChuKSB7IHJldHVybiB0aGlzLmNoYW5nZUJpdChuLG9wX29yKTsgfVxuXG4vLyAocHVibGljKSB0aGlzICYgfigxPDxuKVxuZnVuY3Rpb24gYm5DbGVhckJpdChuKSB7IHJldHVybiB0aGlzLmNoYW5nZUJpdChuLG9wX2FuZG5vdCk7IH1cblxuLy8gKHB1YmxpYykgdGhpcyBeICgxPDxuKVxuZnVuY3Rpb24gYm5GbGlwQml0KG4pIHsgcmV0dXJuIHRoaXMuY2hhbmdlQml0KG4sb3BfeG9yKTsgfVxuXG4vLyAocHJvdGVjdGVkKSByID0gdGhpcyArIGFcbmZ1bmN0aW9uIGJucEFkZFRvKGEscikge1xuICB2YXIgaSA9IDAsIGMgPSAwLCBtID0gTWF0aC5taW4oYS50LHRoaXMudCk7XG4gIHdoaWxlKGkgPCBtKSB7XG4gICAgYyArPSB0aGlzW2ldK2FbaV07XG4gICAgcltpKytdID0gYyZ0aGlzLkRNO1xuICAgIGMgPj49IHRoaXMuREI7XG4gIH1cbiAgaWYoYS50IDwgdGhpcy50KSB7XG4gICAgYyArPSBhLnM7XG4gICAgd2hpbGUoaSA8IHRoaXMudCkge1xuICAgICAgYyArPSB0aGlzW2ldO1xuICAgICAgcltpKytdID0gYyZ0aGlzLkRNO1xuICAgICAgYyA+Pj0gdGhpcy5EQjtcbiAgICB9XG4gICAgYyArPSB0aGlzLnM7XG4gIH1cbiAgZWxzZSB7XG4gICAgYyArPSB0aGlzLnM7XG4gICAgd2hpbGUoaSA8IGEudCkge1xuICAgICAgYyArPSBhW2ldO1xuICAgICAgcltpKytdID0gYyZ0aGlzLkRNO1xuICAgICAgYyA+Pj0gdGhpcy5EQjtcbiAgICB9XG4gICAgYyArPSBhLnM7XG4gIH1cbiAgci5zID0gKGM8MCk/LTE6MDtcbiAgaWYoYyA+IDApIHJbaSsrXSA9IGM7XG4gIGVsc2UgaWYoYyA8IC0xKSByW2krK10gPSB0aGlzLkRWK2M7XG4gIHIudCA9IGk7XG4gIHIuY2xhbXAoKTtcbn1cblxuLy8gKHB1YmxpYykgdGhpcyArIGFcbmZ1bmN0aW9uIGJuQWRkKGEpIHsgdmFyIHIgPSBuYmkoKTsgdGhpcy5hZGRUbyhhLHIpOyByZXR1cm4gcjsgfVxuXG4vLyAocHVibGljKSB0aGlzIC0gYVxuZnVuY3Rpb24gYm5TdWJ0cmFjdChhKSB7IHZhciByID0gbmJpKCk7IHRoaXMuc3ViVG8oYSxyKTsgcmV0dXJuIHI7IH1cblxuLy8gKHB1YmxpYykgdGhpcyAqIGFcbmZ1bmN0aW9uIGJuTXVsdGlwbHkoYSkgeyB2YXIgciA9IG5iaSgpOyB0aGlzLm11bHRpcGx5VG8oYSxyKTsgcmV0dXJuIHI7IH1cblxuLy8gKHB1YmxpYykgdGhpc14yXG5mdW5jdGlvbiBiblNxdWFyZSgpIHsgdmFyIHIgPSBuYmkoKTsgdGhpcy5zcXVhcmVUbyhyKTsgcmV0dXJuIHI7IH1cblxuLy8gKHB1YmxpYykgdGhpcyAvIGFcbmZ1bmN0aW9uIGJuRGl2aWRlKGEpIHsgdmFyIHIgPSBuYmkoKTsgdGhpcy5kaXZSZW1UbyhhLHIsbnVsbCk7IHJldHVybiByOyB9XG5cbi8vIChwdWJsaWMpIHRoaXMgJSBhXG5mdW5jdGlvbiBiblJlbWFpbmRlcihhKSB7IHZhciByID0gbmJpKCk7IHRoaXMuZGl2UmVtVG8oYSxudWxsLHIpOyByZXR1cm4gcjsgfVxuXG4vLyAocHVibGljKSBbdGhpcy9hLHRoaXMlYV1cbmZ1bmN0aW9uIGJuRGl2aWRlQW5kUmVtYWluZGVyKGEpIHtcbiAgdmFyIHEgPSBuYmkoKSwgciA9IG5iaSgpO1xuICB0aGlzLmRpdlJlbVRvKGEscSxyKTtcbiAgcmV0dXJuIG5ldyBBcnJheShxLHIpO1xufVxuXG4vLyAocHJvdGVjdGVkKSB0aGlzICo9IG4sIHRoaXMgPj0gMCwgMSA8IG4gPCBEVlxuZnVuY3Rpb24gYm5wRE11bHRpcGx5KG4pIHtcbiAgdGhpc1t0aGlzLnRdID0gdGhpcy5hbSgwLG4tMSx0aGlzLDAsMCx0aGlzLnQpO1xuICArK3RoaXMudDtcbiAgdGhpcy5jbGFtcCgpO1xufVxuXG4vLyAocHJvdGVjdGVkKSB0aGlzICs9IG4gPDwgdyB3b3JkcywgdGhpcyA+PSAwXG5mdW5jdGlvbiBibnBEQWRkT2Zmc2V0KG4sdykge1xuICBpZihuID09IDApIHJldHVybjtcbiAgd2hpbGUodGhpcy50IDw9IHcpIHRoaXNbdGhpcy50KytdID0gMDtcbiAgdGhpc1t3XSArPSBuO1xuICB3aGlsZSh0aGlzW3ddID49IHRoaXMuRFYpIHtcbiAgICB0aGlzW3ddIC09IHRoaXMuRFY7XG4gICAgaWYoKyt3ID49IHRoaXMudCkgdGhpc1t0aGlzLnQrK10gPSAwO1xuICAgICsrdGhpc1t3XTtcbiAgfVxufVxuXG4vLyBBIFwibnVsbFwiIHJlZHVjZXJcbmZ1bmN0aW9uIE51bGxFeHAoKSB7fVxuZnVuY3Rpb24gbk5vcCh4KSB7IHJldHVybiB4OyB9XG5mdW5jdGlvbiBuTXVsVG8oeCx5LHIpIHsgeC5tdWx0aXBseVRvKHkscik7IH1cbmZ1bmN0aW9uIG5TcXJUbyh4LHIpIHsgeC5zcXVhcmVUbyhyKTsgfVxuXG5OdWxsRXhwLnByb3RvdHlwZS5jb252ZXJ0ID0gbk5vcDtcbk51bGxFeHAucHJvdG90eXBlLnJldmVydCA9IG5Ob3A7XG5OdWxsRXhwLnByb3RvdHlwZS5tdWxUbyA9IG5NdWxUbztcbk51bGxFeHAucHJvdG90eXBlLnNxclRvID0gblNxclRvO1xuXG4vLyAocHVibGljKSB0aGlzXmVcbmZ1bmN0aW9uIGJuUG93KGUpIHsgcmV0dXJuIHRoaXMuZXhwKGUsbmV3IE51bGxFeHAoKSk7IH1cblxuLy8gKHByb3RlY3RlZCkgciA9IGxvd2VyIG4gd29yZHMgb2YgXCJ0aGlzICogYVwiLCBhLnQgPD0gblxuLy8gXCJ0aGlzXCIgc2hvdWxkIGJlIHRoZSBsYXJnZXIgb25lIGlmIGFwcHJvcHJpYXRlLlxuZnVuY3Rpb24gYm5wTXVsdGlwbHlMb3dlclRvKGEsbixyKSB7XG4gIHZhciBpID0gTWF0aC5taW4odGhpcy50K2EudCxuKTtcbiAgci5zID0gMDsgLy8gYXNzdW1lcyBhLHRoaXMgPj0gMFxuICByLnQgPSBpO1xuICB3aGlsZShpID4gMCkgclstLWldID0gMDtcbiAgdmFyIGo7XG4gIGZvcihqID0gci50LXRoaXMudDsgaSA8IGo7ICsraSkgcltpK3RoaXMudF0gPSB0aGlzLmFtKDAsYVtpXSxyLGksMCx0aGlzLnQpO1xuICBmb3IoaiA9IE1hdGgubWluKGEudCxuKTsgaSA8IGo7ICsraSkgdGhpcy5hbSgwLGFbaV0scixpLDAsbi1pKTtcbiAgci5jbGFtcCgpO1xufVxuXG4vLyAocHJvdGVjdGVkKSByID0gXCJ0aGlzICogYVwiIHdpdGhvdXQgbG93ZXIgbiB3b3JkcywgbiA+IDBcbi8vIFwidGhpc1wiIHNob3VsZCBiZSB0aGUgbGFyZ2VyIG9uZSBpZiBhcHByb3ByaWF0ZS5cbmZ1bmN0aW9uIGJucE11bHRpcGx5VXBwZXJUbyhhLG4scikge1xuICAtLW47XG4gIHZhciBpID0gci50ID0gdGhpcy50K2EudC1uO1xuICByLnMgPSAwOyAvLyBhc3N1bWVzIGEsdGhpcyA+PSAwXG4gIHdoaWxlKC0taSA+PSAwKSByW2ldID0gMDtcbiAgZm9yKGkgPSBNYXRoLm1heChuLXRoaXMudCwwKTsgaSA8IGEudDsgKytpKVxuICAgIHJbdGhpcy50K2ktbl0gPSB0aGlzLmFtKG4taSxhW2ldLHIsMCwwLHRoaXMudCtpLW4pO1xuICByLmNsYW1wKCk7XG4gIHIuZHJTaGlmdFRvKDEscik7XG59XG5cbi8vIEJhcnJldHQgbW9kdWxhciByZWR1Y3Rpb25cbmZ1bmN0aW9uIEJhcnJldHQobSkge1xuICAvLyBzZXR1cCBCYXJyZXR0XG4gIHRoaXMucjIgPSBuYmkoKTtcbiAgdGhpcy5xMyA9IG5iaSgpO1xuICBCaWdJbnRlZ2VyLk9ORS5kbFNoaWZ0VG8oMiptLnQsdGhpcy5yMik7XG4gIHRoaXMubXUgPSB0aGlzLnIyLmRpdmlkZShtKTtcbiAgdGhpcy5tID0gbTtcbn1cblxuZnVuY3Rpb24gYmFycmV0dENvbnZlcnQoeCkge1xuICBpZih4LnMgPCAwIHx8IHgudCA+IDIqdGhpcy5tLnQpIHJldHVybiB4Lm1vZCh0aGlzLm0pO1xuICBlbHNlIGlmKHguY29tcGFyZVRvKHRoaXMubSkgPCAwKSByZXR1cm4geDtcbiAgZWxzZSB7IHZhciByID0gbmJpKCk7IHguY29weVRvKHIpOyB0aGlzLnJlZHVjZShyKTsgcmV0dXJuIHI7IH1cbn1cblxuZnVuY3Rpb24gYmFycmV0dFJldmVydCh4KSB7IHJldHVybiB4OyB9XG5cbi8vIHggPSB4IG1vZCBtIChIQUMgMTQuNDIpXG5mdW5jdGlvbiBiYXJyZXR0UmVkdWNlKHgpIHtcbiAgeC5kclNoaWZ0VG8odGhpcy5tLnQtMSx0aGlzLnIyKTtcbiAgaWYoeC50ID4gdGhpcy5tLnQrMSkgeyB4LnQgPSB0aGlzLm0udCsxOyB4LmNsYW1wKCk7IH1cbiAgdGhpcy5tdS5tdWx0aXBseVVwcGVyVG8odGhpcy5yMix0aGlzLm0udCsxLHRoaXMucTMpO1xuICB0aGlzLm0ubXVsdGlwbHlMb3dlclRvKHRoaXMucTMsdGhpcy5tLnQrMSx0aGlzLnIyKTtcbiAgd2hpbGUoeC5jb21wYXJlVG8odGhpcy5yMikgPCAwKSB4LmRBZGRPZmZzZXQoMSx0aGlzLm0udCsxKTtcbiAgeC5zdWJUbyh0aGlzLnIyLHgpO1xuICB3aGlsZSh4LmNvbXBhcmVUbyh0aGlzLm0pID49IDApIHguc3ViVG8odGhpcy5tLHgpO1xufVxuXG4vLyByID0geF4yIG1vZCBtOyB4ICE9IHJcbmZ1bmN0aW9uIGJhcnJldHRTcXJUbyh4LHIpIHsgeC5zcXVhcmVUbyhyKTsgdGhpcy5yZWR1Y2Uocik7IH1cblxuLy8gciA9IHgqeSBtb2QgbTsgeCx5ICE9IHJcbmZ1bmN0aW9uIGJhcnJldHRNdWxUbyh4LHkscikgeyB4Lm11bHRpcGx5VG8oeSxyKTsgdGhpcy5yZWR1Y2Uocik7IH1cblxuQmFycmV0dC5wcm90b3R5cGUuY29udmVydCA9IGJhcnJldHRDb252ZXJ0O1xuQmFycmV0dC5wcm90b3R5cGUucmV2ZXJ0ID0gYmFycmV0dFJldmVydDtcbkJhcnJldHQucHJvdG90eXBlLnJlZHVjZSA9IGJhcnJldHRSZWR1Y2U7XG5CYXJyZXR0LnByb3RvdHlwZS5tdWxUbyA9IGJhcnJldHRNdWxUbztcbkJhcnJldHQucHJvdG90eXBlLnNxclRvID0gYmFycmV0dFNxclRvO1xuXG4vLyAocHVibGljKSB0aGlzXmUgJSBtIChIQUMgMTQuODUpXG5mdW5jdGlvbiBibk1vZFBvdyhlLG0pIHtcbiAgdmFyIGkgPSBlLmJpdExlbmd0aCgpLCBrLCByID0gbmJ2KDEpLCB6O1xuICBpZihpIDw9IDApIHJldHVybiByO1xuICBlbHNlIGlmKGkgPCAxOCkgayA9IDE7XG4gIGVsc2UgaWYoaSA8IDQ4KSBrID0gMztcbiAgZWxzZSBpZihpIDwgMTQ0KSBrID0gNDtcbiAgZWxzZSBpZihpIDwgNzY4KSBrID0gNTtcbiAgZWxzZSBrID0gNjtcbiAgaWYoaSA8IDgpXG4gICAgeiA9IG5ldyBDbGFzc2ljKG0pO1xuICBlbHNlIGlmKG0uaXNFdmVuKCkpXG4gICAgeiA9IG5ldyBCYXJyZXR0KG0pO1xuICBlbHNlXG4gICAgeiA9IG5ldyBNb250Z29tZXJ5KG0pO1xuXG4gIC8vIHByZWNvbXB1dGF0aW9uXG4gIHZhciBnID0gbmV3IEFycmF5KCksIG4gPSAzLCBrMSA9IGstMSwga20gPSAoMTw8ayktMTtcbiAgZ1sxXSA9IHouY29udmVydCh0aGlzKTtcbiAgaWYoayA+IDEpIHtcbiAgICB2YXIgZzIgPSBuYmkoKTtcbiAgICB6LnNxclRvKGdbMV0sZzIpO1xuICAgIHdoaWxlKG4gPD0ga20pIHtcbiAgICAgIGdbbl0gPSBuYmkoKTtcbiAgICAgIHoubXVsVG8oZzIsZ1tuLTJdLGdbbl0pO1xuICAgICAgbiArPSAyO1xuICAgIH1cbiAgfVxuXG4gIHZhciBqID0gZS50LTEsIHcsIGlzMSA9IHRydWUsIHIyID0gbmJpKCksIHQ7XG4gIGkgPSBuYml0cyhlW2pdKS0xO1xuICB3aGlsZShqID49IDApIHtcbiAgICBpZihpID49IGsxKSB3ID0gKGVbal0+PihpLWsxKSkma207XG4gICAgZWxzZSB7XG4gICAgICB3ID0gKGVbal0mKCgxPDwoaSsxKSktMSkpPDwoazEtaSk7XG4gICAgICBpZihqID4gMCkgdyB8PSBlW2otMV0+Pih0aGlzLkRCK2ktazEpO1xuICAgIH1cblxuICAgIG4gPSBrO1xuICAgIHdoaWxlKCh3JjEpID09IDApIHsgdyA+Pj0gMTsgLS1uOyB9XG4gICAgaWYoKGkgLT0gbikgPCAwKSB7IGkgKz0gdGhpcy5EQjsgLS1qOyB9XG4gICAgaWYoaXMxKSB7XHQvLyByZXQgPT0gMSwgZG9uJ3QgYm90aGVyIHNxdWFyaW5nIG9yIG11bHRpcGx5aW5nIGl0XG4gICAgICBnW3ddLmNvcHlUbyhyKTtcbiAgICAgIGlzMSA9IGZhbHNlO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgIHdoaWxlKG4gPiAxKSB7IHouc3FyVG8ocixyMik7IHouc3FyVG8ocjIscik7IG4gLT0gMjsgfVxuICAgICAgaWYobiA+IDApIHouc3FyVG8ocixyMik7IGVsc2UgeyB0ID0gcjsgciA9IHIyOyByMiA9IHQ7IH1cbiAgICAgIHoubXVsVG8ocjIsZ1t3XSxyKTtcbiAgICB9XG5cbiAgICB3aGlsZShqID49IDAgJiYgKGVbal0mKDE8PGkpKSA9PSAwKSB7XG4gICAgICB6LnNxclRvKHIscjIpOyB0ID0gcjsgciA9IHIyOyByMiA9IHQ7XG4gICAgICBpZigtLWkgPCAwKSB7IGkgPSB0aGlzLkRCLTE7IC0tajsgfVxuICAgIH1cbiAgfVxuICByZXR1cm4gei5yZXZlcnQocik7XG59XG5cbi8vIChwdWJsaWMpIGdjZCh0aGlzLGEpIChIQUMgMTQuNTQpXG5mdW5jdGlvbiBibkdDRChhKSB7XG4gIHZhciB4ID0gKHRoaXMuczwwKT90aGlzLm5lZ2F0ZSgpOnRoaXMuY2xvbmUoKTtcbiAgdmFyIHkgPSAoYS5zPDApP2EubmVnYXRlKCk6YS5jbG9uZSgpO1xuICBpZih4LmNvbXBhcmVUbyh5KSA8IDApIHsgdmFyIHQgPSB4OyB4ID0geTsgeSA9IHQ7IH1cbiAgdmFyIGkgPSB4LmdldExvd2VzdFNldEJpdCgpLCBnID0geS5nZXRMb3dlc3RTZXRCaXQoKTtcbiAgaWYoZyA8IDApIHJldHVybiB4O1xuICBpZihpIDwgZykgZyA9IGk7XG4gIGlmKGcgPiAwKSB7XG4gICAgeC5yU2hpZnRUbyhnLHgpO1xuICAgIHkuclNoaWZ0VG8oZyx5KTtcbiAgfVxuICB3aGlsZSh4LnNpZ251bSgpID4gMCkge1xuICAgIGlmKChpID0geC5nZXRMb3dlc3RTZXRCaXQoKSkgPiAwKSB4LnJTaGlmdFRvKGkseCk7XG4gICAgaWYoKGkgPSB5LmdldExvd2VzdFNldEJpdCgpKSA+IDApIHkuclNoaWZ0VG8oaSx5KTtcbiAgICBpZih4LmNvbXBhcmVUbyh5KSA+PSAwKSB7XG4gICAgICB4LnN1YlRvKHkseCk7XG4gICAgICB4LnJTaGlmdFRvKDEseCk7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgeS5zdWJUbyh4LHkpO1xuICAgICAgeS5yU2hpZnRUbygxLHkpO1xuICAgIH1cbiAgfVxuICBpZihnID4gMCkgeS5sU2hpZnRUbyhnLHkpO1xuICByZXR1cm4geTtcbn1cblxuLy8gKHByb3RlY3RlZCkgdGhpcyAlIG4sIG4gPCAyXjI2XG5mdW5jdGlvbiBibnBNb2RJbnQobikge1xuICBpZihuIDw9IDApIHJldHVybiAwO1xuICB2YXIgZCA9IHRoaXMuRFYlbiwgciA9ICh0aGlzLnM8MCk/bi0xOjA7XG4gIGlmKHRoaXMudCA+IDApXG4gICAgaWYoZCA9PSAwKSByID0gdGhpc1swXSVuO1xuICAgIGVsc2UgZm9yKHZhciBpID0gdGhpcy50LTE7IGkgPj0gMDsgLS1pKSByID0gKGQqcit0aGlzW2ldKSVuO1xuICByZXR1cm4gcjtcbn1cblxuLy8gKHB1YmxpYykgMS90aGlzICUgbSAoSEFDIDE0LjYxKVxuZnVuY3Rpb24gYm5Nb2RJbnZlcnNlKG0pIHtcbiAgdmFyIGFjID0gbS5pc0V2ZW4oKTtcbiAgaWYoKHRoaXMuaXNFdmVuKCkgJiYgYWMpIHx8IG0uc2lnbnVtKCkgPT0gMCkgcmV0dXJuIEJpZ0ludGVnZXIuWkVSTztcbiAgdmFyIHUgPSBtLmNsb25lKCksIHYgPSB0aGlzLmNsb25lKCk7XG4gIHZhciBhID0gbmJ2KDEpLCBiID0gbmJ2KDApLCBjID0gbmJ2KDApLCBkID0gbmJ2KDEpO1xuICB3aGlsZSh1LnNpZ251bSgpICE9IDApIHtcbiAgICB3aGlsZSh1LmlzRXZlbigpKSB7XG4gICAgICB1LnJTaGlmdFRvKDEsdSk7XG4gICAgICBpZihhYykge1xuICAgICAgICBpZighYS5pc0V2ZW4oKSB8fCAhYi5pc0V2ZW4oKSkgeyBhLmFkZFRvKHRoaXMsYSk7IGIuc3ViVG8obSxiKTsgfVxuICAgICAgICBhLnJTaGlmdFRvKDEsYSk7XG4gICAgICB9XG4gICAgICBlbHNlIGlmKCFiLmlzRXZlbigpKSBiLnN1YlRvKG0sYik7XG4gICAgICBiLnJTaGlmdFRvKDEsYik7XG4gICAgfVxuICAgIHdoaWxlKHYuaXNFdmVuKCkpIHtcbiAgICAgIHYuclNoaWZ0VG8oMSx2KTtcbiAgICAgIGlmKGFjKSB7XG4gICAgICAgIGlmKCFjLmlzRXZlbigpIHx8ICFkLmlzRXZlbigpKSB7IGMuYWRkVG8odGhpcyxjKTsgZC5zdWJUbyhtLGQpOyB9XG4gICAgICAgIGMuclNoaWZ0VG8oMSxjKTtcbiAgICAgIH1cbiAgICAgIGVsc2UgaWYoIWQuaXNFdmVuKCkpIGQuc3ViVG8obSxkKTtcbiAgICAgIGQuclNoaWZ0VG8oMSxkKTtcbiAgICB9XG4gICAgaWYodS5jb21wYXJlVG8odikgPj0gMCkge1xuICAgICAgdS5zdWJUbyh2LHUpO1xuICAgICAgaWYoYWMpIGEuc3ViVG8oYyxhKTtcbiAgICAgIGIuc3ViVG8oZCxiKTtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICB2LnN1YlRvKHUsdik7XG4gICAgICBpZihhYykgYy5zdWJUbyhhLGMpO1xuICAgICAgZC5zdWJUbyhiLGQpO1xuICAgIH1cbiAgfVxuICBpZih2LmNvbXBhcmVUbyhCaWdJbnRlZ2VyLk9ORSkgIT0gMCkgcmV0dXJuIEJpZ0ludGVnZXIuWkVSTztcbiAgaWYoZC5jb21wYXJlVG8obSkgPj0gMCkgcmV0dXJuIGQuc3VidHJhY3QobSk7XG4gIGlmKGQuc2lnbnVtKCkgPCAwKSBkLmFkZFRvKG0sZCk7IGVsc2UgcmV0dXJuIGQ7XG4gIGlmKGQuc2lnbnVtKCkgPCAwKSByZXR1cm4gZC5hZGQobSk7IGVsc2UgcmV0dXJuIGQ7XG59XG5cbnZhciBsb3dwcmltZXMgPSBbMiwzLDUsNywxMSwxMywxNywxOSwyMywyOSwzMSwzNyw0MSw0Myw0Nyw1Myw1OSw2MSw2Nyw3MSw3Myw3OSw4Myw4OSw5NywxMDEsMTAzLDEwNywxMDksMTEzLDEyNywxMzEsMTM3LDEzOSwxNDksMTUxLDE1NywxNjMsMTY3LDE3MywxNzksMTgxLDE5MSwxOTMsMTk3LDE5OSwyMTEsMjIzLDIyNywyMjksMjMzLDIzOSwyNDEsMjUxLDI1NywyNjMsMjY5LDI3MSwyNzcsMjgxLDI4MywyOTMsMzA3LDMxMSwzMTMsMzE3LDMzMSwzMzcsMzQ3LDM0OSwzNTMsMzU5LDM2NywzNzMsMzc5LDM4MywzODksMzk3LDQwMSw0MDksNDE5LDQyMSw0MzEsNDMzLDQzOSw0NDMsNDQ5LDQ1Nyw0NjEsNDYzLDQ2Nyw0NzksNDg3LDQ5MSw0OTksNTAzLDUwOSw1MjEsNTIzLDU0MSw1NDcsNTU3LDU2Myw1NjksNTcxLDU3Nyw1ODcsNTkzLDU5OSw2MDEsNjA3LDYxMyw2MTcsNjE5LDYzMSw2NDEsNjQzLDY0Nyw2NTMsNjU5LDY2MSw2NzMsNjc3LDY4Myw2OTEsNzAxLDcwOSw3MTksNzI3LDczMyw3MzksNzQzLDc1MSw3NTcsNzYxLDc2OSw3NzMsNzg3LDc5Nyw4MDksODExLDgyMSw4MjMsODI3LDgyOSw4MzksODUzLDg1Nyw4NTksODYzLDg3Nyw4ODEsODgzLDg4Nyw5MDcsOTExLDkxOSw5MjksOTM3LDk0MSw5NDcsOTUzLDk2Nyw5NzEsOTc3LDk4Myw5OTEsOTk3XTtcbnZhciBscGxpbSA9ICgxPDwyNikvbG93cHJpbWVzW2xvd3ByaW1lcy5sZW5ndGgtMV07XG5cbi8vIChwdWJsaWMpIHRlc3QgcHJpbWFsaXR5IHdpdGggY2VydGFpbnR5ID49IDEtLjVedFxuZnVuY3Rpb24gYm5Jc1Byb2JhYmxlUHJpbWUodCkge1xuICB2YXIgaSwgeCA9IHRoaXMuYWJzKCk7XG4gIGlmKHgudCA9PSAxICYmIHhbMF0gPD0gbG93cHJpbWVzW2xvd3ByaW1lcy5sZW5ndGgtMV0pIHtcbiAgICBmb3IoaSA9IDA7IGkgPCBsb3dwcmltZXMubGVuZ3RoOyArK2kpXG4gICAgICBpZih4WzBdID09IGxvd3ByaW1lc1tpXSkgcmV0dXJuIHRydWU7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG4gIGlmKHguaXNFdmVuKCkpIHJldHVybiBmYWxzZTtcbiAgaSA9IDE7XG4gIHdoaWxlKGkgPCBsb3dwcmltZXMubGVuZ3RoKSB7XG4gICAgdmFyIG0gPSBsb3dwcmltZXNbaV0sIGogPSBpKzE7XG4gICAgd2hpbGUoaiA8IGxvd3ByaW1lcy5sZW5ndGggJiYgbSA8IGxwbGltKSBtICo9IGxvd3ByaW1lc1tqKytdO1xuICAgIG0gPSB4Lm1vZEludChtKTtcbiAgICB3aGlsZShpIDwgaikgaWYobSVsb3dwcmltZXNbaSsrXSA9PSAwKSByZXR1cm4gZmFsc2U7XG4gIH1cbiAgcmV0dXJuIHgubWlsbGVyUmFiaW4odCk7XG59XG5cbi8qIGFkZGVkIGJ5IFJlY3VyaXR5IExhYnMgKi9cblxuZnVuY3Rpb24gbmJpdHMoeCkge1xuXHR2YXIgbiA9IDEsIHQ7XG5cdGlmICgodCA9IHggPj4+IDE2KSAhPSAwKSB7XG5cdFx0eCA9IHQ7XG5cdFx0biArPSAxNjtcblx0fVxuXHRpZiAoKHQgPSB4ID4+IDgpICE9IDApIHtcblx0XHR4ID0gdDtcblx0XHRuICs9IDg7XG5cdH1cblx0aWYgKCh0ID0geCA+PiA0KSAhPSAwKSB7XG5cdFx0eCA9IHQ7XG5cdFx0biArPSA0O1xuXHR9XG5cdGlmICgodCA9IHggPj4gMikgIT0gMCkge1xuXHRcdHggPSB0O1xuXHRcdG4gKz0gMjtcblx0fVxuXHRpZiAoKHQgPSB4ID4+IDEpICE9IDApIHtcblx0XHR4ID0gdDtcblx0XHRuICs9IDE7XG5cdH1cblx0cmV0dXJuIG47XG59XG5cbmZ1bmN0aW9uIGJuVG9NUEkgKCkge1xuXHR2YXIgYmEgPSB0aGlzLnRvQnl0ZUFycmF5KCk7XG5cdHZhciBzaXplID0gKGJhLmxlbmd0aC0xKSo4K25iaXRzKGJhWzBdKTtcblx0dmFyIHJlc3VsdCA9IFwiXCI7XG5cdHJlc3VsdCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKChzaXplICYgMHhGRjAwKSA+PiA4KTtcblx0cmVzdWx0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoc2l6ZSAmIDB4RkYpO1xuXHRyZXN1bHQgKz0gdXRpbC5iaW4yc3RyKGJhKTtcblx0cmV0dXJuIHJlc3VsdDtcbn1cbi8qIEVORCBvZiBhZGRpdGlvbiAqL1xuXG4vLyAocHJvdGVjdGVkKSB0cnVlIGlmIHByb2JhYmx5IHByaW1lIChIQUMgNC4yNCwgTWlsbGVyLVJhYmluKVxuZnVuY3Rpb24gYm5wTWlsbGVyUmFiaW4odCkge1xuICB2YXIgbjEgPSB0aGlzLnN1YnRyYWN0KEJpZ0ludGVnZXIuT05FKTtcbiAgdmFyIGsgPSBuMS5nZXRMb3dlc3RTZXRCaXQoKTtcbiAgaWYoayA8PSAwKSByZXR1cm4gZmFsc2U7XG4gIHZhciByID0gbjEuc2hpZnRSaWdodChrKTtcbiAgdCA9ICh0KzEpPj4xO1xuICBpZih0ID4gbG93cHJpbWVzLmxlbmd0aCkgdCA9IGxvd3ByaW1lcy5sZW5ndGg7XG4gIHZhciBhID0gbmJpKCk7XG4gIGZvcih2YXIgaSA9IDA7IGkgPCB0OyArK2kpIHtcbiAgICAvL1BpY2sgYmFzZXMgYXQgcmFuZG9tLCBpbnN0ZWFkIG9mIHN0YXJ0aW5nIGF0IDJcbiAgICBhLmZyb21JbnQobG93cHJpbWVzW01hdGguZmxvb3IoTWF0aC5yYW5kb20oKSpsb3dwcmltZXMubGVuZ3RoKV0pO1xuICAgIHZhciB5ID0gYS5tb2RQb3cocix0aGlzKTtcbiAgICBpZih5LmNvbXBhcmVUbyhCaWdJbnRlZ2VyLk9ORSkgIT0gMCAmJiB5LmNvbXBhcmVUbyhuMSkgIT0gMCkge1xuICAgICAgdmFyIGogPSAxO1xuICAgICAgd2hpbGUoaisrIDwgayAmJiB5LmNvbXBhcmVUbyhuMSkgIT0gMCkge1xuICAgICAgICB5ID0geS5tb2RQb3dJbnQoMix0aGlzKTtcbiAgICAgICAgaWYoeS5jb21wYXJlVG8oQmlnSW50ZWdlci5PTkUpID09IDApIHJldHVybiBmYWxzZTtcbiAgICAgIH1cbiAgICAgIGlmKHkuY29tcGFyZVRvKG4xKSAhPSAwKSByZXR1cm4gZmFsc2U7XG4gICAgfVxuICB9XG4gIHJldHVybiB0cnVlO1xufVxuXG52YXIgQmlnSW50ZWdlciA9IHJlcXVpcmUoJy4vanNibi5qcycpO1xuXG4vLyBwcm90ZWN0ZWRcbkJpZ0ludGVnZXIucHJvdG90eXBlLmNodW5rU2l6ZSA9IGJucENodW5rU2l6ZTtcbkJpZ0ludGVnZXIucHJvdG90eXBlLnRvUmFkaXggPSBibnBUb1JhZGl4O1xuQmlnSW50ZWdlci5wcm90b3R5cGUuZnJvbVJhZGl4ID0gYm5wRnJvbVJhZGl4O1xuQmlnSW50ZWdlci5wcm90b3R5cGUuZnJvbU51bWJlciA9IGJucEZyb21OdW1iZXI7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5iaXR3aXNlVG8gPSBibnBCaXR3aXNlVG87XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5jaGFuZ2VCaXQgPSBibnBDaGFuZ2VCaXQ7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5hZGRUbyA9IGJucEFkZFRvO1xuQmlnSW50ZWdlci5wcm90b3R5cGUuZE11bHRpcGx5ID0gYm5wRE11bHRpcGx5O1xuQmlnSW50ZWdlci5wcm90b3R5cGUuZEFkZE9mZnNldCA9IGJucERBZGRPZmZzZXQ7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5tdWx0aXBseUxvd2VyVG8gPSBibnBNdWx0aXBseUxvd2VyVG87XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5tdWx0aXBseVVwcGVyVG8gPSBibnBNdWx0aXBseVVwcGVyVG87XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5tb2RJbnQgPSBibnBNb2RJbnQ7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5taWxsZXJSYWJpbiA9IGJucE1pbGxlclJhYmluO1xuXG4vLyBwdWJsaWNcbkJpZ0ludGVnZXIucHJvdG90eXBlLmNsb25lID0gYm5DbG9uZTtcbkJpZ0ludGVnZXIucHJvdG90eXBlLmludFZhbHVlID0gYm5JbnRWYWx1ZTtcbkJpZ0ludGVnZXIucHJvdG90eXBlLmJ5dGVWYWx1ZSA9IGJuQnl0ZVZhbHVlO1xuQmlnSW50ZWdlci5wcm90b3R5cGUuc2hvcnRWYWx1ZSA9IGJuU2hvcnRWYWx1ZTtcbkJpZ0ludGVnZXIucHJvdG90eXBlLnNpZ251bSA9IGJuU2lnTnVtO1xuQmlnSW50ZWdlci5wcm90b3R5cGUudG9CeXRlQXJyYXkgPSBiblRvQnl0ZUFycmF5O1xuQmlnSW50ZWdlci5wcm90b3R5cGUuZXF1YWxzID0gYm5FcXVhbHM7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5taW4gPSBibk1pbjtcbkJpZ0ludGVnZXIucHJvdG90eXBlLm1heCA9IGJuTWF4O1xuQmlnSW50ZWdlci5wcm90b3R5cGUuYW5kID0gYm5BbmQ7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5vciA9IGJuT3I7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS54b3IgPSBiblhvcjtcbkJpZ0ludGVnZXIucHJvdG90eXBlLmFuZE5vdCA9IGJuQW5kTm90O1xuQmlnSW50ZWdlci5wcm90b3R5cGUubm90ID0gYm5Ob3Q7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5zaGlmdExlZnQgPSBiblNoaWZ0TGVmdDtcbkJpZ0ludGVnZXIucHJvdG90eXBlLnNoaWZ0UmlnaHQgPSBiblNoaWZ0UmlnaHQ7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5nZXRMb3dlc3RTZXRCaXQgPSBibkdldExvd2VzdFNldEJpdDtcbkJpZ0ludGVnZXIucHJvdG90eXBlLmJpdENvdW50ID0gYm5CaXRDb3VudDtcbkJpZ0ludGVnZXIucHJvdG90eXBlLnRlc3RCaXQgPSBiblRlc3RCaXQ7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5zZXRCaXQgPSBiblNldEJpdDtcbkJpZ0ludGVnZXIucHJvdG90eXBlLmNsZWFyQml0ID0gYm5DbGVhckJpdDtcbkJpZ0ludGVnZXIucHJvdG90eXBlLmZsaXBCaXQgPSBibkZsaXBCaXQ7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5hZGQgPSBibkFkZDtcbkJpZ0ludGVnZXIucHJvdG90eXBlLnN1YnRyYWN0ID0gYm5TdWJ0cmFjdDtcbkJpZ0ludGVnZXIucHJvdG90eXBlLm11bHRpcGx5ID0gYm5NdWx0aXBseTtcbkJpZ0ludGVnZXIucHJvdG90eXBlLmRpdmlkZSA9IGJuRGl2aWRlO1xuQmlnSW50ZWdlci5wcm90b3R5cGUucmVtYWluZGVyID0gYm5SZW1haW5kZXI7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5kaXZpZGVBbmRSZW1haW5kZXIgPSBibkRpdmlkZUFuZFJlbWFpbmRlcjtcbkJpZ0ludGVnZXIucHJvdG90eXBlLm1vZFBvdyA9IGJuTW9kUG93O1xuQmlnSW50ZWdlci5wcm90b3R5cGUubW9kSW52ZXJzZSA9IGJuTW9kSW52ZXJzZTtcbkJpZ0ludGVnZXIucHJvdG90eXBlLnBvdyA9IGJuUG93O1xuQmlnSW50ZWdlci5wcm90b3R5cGUuZ2NkID0gYm5HQ0Q7XG5CaWdJbnRlZ2VyLnByb3RvdHlwZS5pc1Byb2JhYmxlUHJpbWUgPSBibklzUHJvYmFibGVQcmltZTtcbkJpZ0ludGVnZXIucHJvdG90eXBlLnRvTVBJID0gYm5Ub01QSTtcblxuLy8gSlNCTi1zcGVjaWZpYyBleHRlbnNpb25cbkJpZ0ludGVnZXIucHJvdG90eXBlLnNxdWFyZSA9IGJuU3F1YXJlO1xuXG5cbiIsIi8vIEdQRzRCcm93c2VycyAtIEFuIE9wZW5QR1AgaW1wbGVtZW50YXRpb24gaW4gamF2YXNjcmlwdFxuLy8gQ29weXJpZ2h0IChDKSAyMDExIFJlY3VyaXR5IExhYnMgR21iSFxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yXG4vLyBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uOyBlaXRoZXJcbi8vIHZlcnNpb24gMi4xIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbi8vIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4vLyBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlIEdOVVxuLy8gTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cbi8vIFxuLy8gWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhbG9uZyB3aXRoIHRoaXMgbGlicmFyeTsgaWYgbm90LCB3cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZVxuLy8gRm91bmRhdGlvbiwgSW5jLiwgNTEgRnJhbmtsaW4gU3RyZWV0LCBGaWZ0aCBGbG9vciwgQm9zdG9uLCBNQSAgMDIxMTAtMTMwMSAgVVNBXG5cbi8qKlxuICogQGNsYXNzXG4gKiBAY2xhc3NkZXNjIEltcGxlbWVudGF0aW9uIG9mIHRoZSBzdHJhbmdlIFwiTWFya2VyIHBhY2tldFwiIChUYWcgMTApXG4gKiBcbiAqIFJGQzQ4ODAgNS44OiBBbiBleHBlcmltZW50YWwgdmVyc2lvbiBvZiBQR1AgdXNlZCB0aGlzIHBhY2tldCBhcyB0aGUgTGl0ZXJhbFxuICogcGFja2V0LCBidXQgbm8gcmVsZWFzZWQgdmVyc2lvbiBvZiBQR1AgZ2VuZXJhdGVkIExpdGVyYWwgcGFja2V0cyB3aXRoIHRoaXNcbiAqIHRhZy4gV2l0aCBQR1AgNS54LCB0aGlzIHBhY2tldCBoYXMgYmVlbiByZWFzc2lnbmVkIGFuZCBpcyByZXNlcnZlZCBmb3IgdXNlIGFzXG4gKiB0aGUgTWFya2VyIHBhY2tldC5cbiAqIFxuICogU3VjaCBhIHBhY2tldCBNVVNUIGJlIGlnbm9yZWQgd2hlbiByZWNlaXZlZC5cbiAqL1xuZnVuY3Rpb24gcGFja2V0X21hcmtlcigpIHtcblx0LyoqXG5cdCAqIFBhcnNpbmcgZnVuY3Rpb24gZm9yIGEgbGl0ZXJhbCBkYXRhIHBhY2tldCAodGFnIDEwKS5cblx0ICogXG5cdCAqIEBwYXJhbSB7U3RyaW5nfSBpbnB1dCBQYXlsb2FkIG9mIGEgdGFnIDEwIHBhY2tldFxuXHQgKiBAcGFyYW0ge0ludGVnZXJ9IHBvc2l0aW9uXG5cdCAqICAgICAgICAgICAgUG9zaXRpb24gdG8gc3RhcnQgcmVhZGluZyBmcm9tIHRoZSBpbnB1dCBzdHJpbmdcblx0ICogQHBhcmFtIHtJbnRlZ2VyfSBsZW5cblx0ICogICAgICAgICAgICBMZW5ndGggb2YgdGhlIHBhY2tldCBvciB0aGUgcmVtYWluaW5nIGxlbmd0aCBvZlxuXHQgKiAgICAgICAgICAgIGlucHV0IGF0IHBvc2l0aW9uXG5cdCAqIEByZXR1cm4ge29wZW5wZ3BfcGFja2V0X2VuY3J5cHRlZGRhdGF9IE9iamVjdCByZXByZXNlbnRhdGlvblxuXHQgKi9cblx0dGhpcy5yZWFkID0gZnVuY3Rpb24oYnl0ZXMpIHtcblx0XHRpZiAoYnl0ZXNbMF0uY2hhckNvZGVBdCgpID09IDB4NTAgJiYgLy8gUFxuXHRcdFx0XHRieXRlc1sxXS5jaGFyQ29kZUF0KCkgPT0gMHg0NyAmJiAvLyBHXG5cdFx0XHRcdGJ5dGVzWzJdLmNoYXJDb2RlQXQoKSA9PSAweDUwKSAvLyBQXG5cdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHQvLyBtYXJrZXIgcGFja2V0IGRvZXMgbm90IGNvbnRhaW4gXCJQR1BcIlxuXHRcdHJldHVybiBmYWxzZTtcblx0fVxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHBhY2tldF9tYXJrZXI7XG4iLCIvLyBHUEc0QnJvd3NlcnMgLSBBbiBPcGVuUEdQIGltcGxlbWVudGF0aW9uIGluIGphdmFzY3JpcHRcbi8vIENvcHlyaWdodCAoQykgMjAxMSBSZWN1cml0eSBMYWJzIEdtYkhcbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vclxuLy8gbW9kaWZ5IGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyXG4vLyB2ZXJzaW9uIDIuMSBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4vLyBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuLy8gTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZSBHTlVcbi8vIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG4vLyBcbi8vIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYWxvbmcgd2l0aCB0aGlzIGxpYnJhcnk7IGlmIG5vdCwgd3JpdGUgdG8gdGhlIEZyZWUgU29mdHdhcmVcbi8vIEZvdW5kYXRpb24sIEluYy4sIDUxIEZyYW5rbGluIFN0cmVldCwgRmlmdGggRmxvb3IsIEJvc3RvbiwgTUEgIDAyMTEwLTEzMDEgIFVTQVxuXG4vKiogXG4gKiBAY2xhc3NcbiAqIEBjbGFzc2Rlc2MgSW1wbGVtZW50YXRpb24gb2YgdGhlIFVzZXIgQXR0cmlidXRlIFBhY2tldCAoVGFnIDE3KVxuICogIFRoZSBVc2VyIEF0dHJpYnV0ZSBwYWNrZXQgaXMgYSB2YXJpYXRpb24gb2YgdGhlIFVzZXIgSUQgcGFja2V0LiAgSXRcbiAqICBpcyBjYXBhYmxlIG9mIHN0b3JpbmcgbW9yZSB0eXBlcyBvZiBkYXRhIHRoYW4gdGhlIFVzZXIgSUQgcGFja2V0LFxuICogIHdoaWNoIGlzIGxpbWl0ZWQgdG8gdGV4dC4gIExpa2UgdGhlIFVzZXIgSUQgcGFja2V0LCBhIFVzZXIgQXR0cmlidXRlXG4gKiAgcGFja2V0IG1heSBiZSBjZXJ0aWZpZWQgYnkgdGhlIGtleSBvd25lciAoXCJzZWxmLXNpZ25lZFwiKSBvciBhbnkgb3RoZXJcbiAqICBrZXkgb3duZXIgd2hvIGNhcmVzIHRvIGNlcnRpZnkgaXQuICBFeGNlcHQgYXMgbm90ZWQsIGEgVXNlciBBdHRyaWJ1dGVcbiAqICBwYWNrZXQgbWF5IGJlIHVzZWQgYW55d2hlcmUgdGhhdCBhIFVzZXIgSUQgcGFja2V0IG1heSBiZSB1c2VkLlxuICpcbiAqICBXaGlsZSBVc2VyIEF0dHJpYnV0ZSBwYWNrZXRzIGFyZSBub3QgYSByZXF1aXJlZCBwYXJ0IG9mIHRoZSBPcGVuUEdQXG4gKiAgc3RhbmRhcmQsIGltcGxlbWVudGF0aW9ucyBTSE9VTEQgcHJvdmlkZSBhdCBsZWFzdCBlbm91Z2hcbiAqICBjb21wYXRpYmlsaXR5IHRvIHByb3Blcmx5IGhhbmRsZSBhIGNlcnRpZmljYXRpb24gc2lnbmF0dXJlIG9uIHRoZVxuICogIFVzZXIgQXR0cmlidXRlIHBhY2tldC4gIEEgc2ltcGxlIHdheSB0byBkbyB0aGlzIGlzIGJ5IHRyZWF0aW5nIHRoZVxuICogIFVzZXIgQXR0cmlidXRlIHBhY2tldCBhcyBhIFVzZXIgSUQgcGFja2V0IHdpdGggb3BhcXVlIGNvbnRlbnRzLCBidXRcbiAqICBhbiBpbXBsZW1lbnRhdGlvbiBtYXkgdXNlIGFueSBtZXRob2QgZGVzaXJlZC5cbiAqL1xubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiBwYWNrZXRfdXNlcl9hdHRyaWJ1dGUoKSB7XG5cdHRoaXMudGFnID0gMTc7XG5cdHRoaXMuYXR0cmlidXRlcyA9IFtdO1xuXG5cdC8qKlxuXHQgKiBwYXJzaW5nIGZ1bmN0aW9uIGZvciBhIHVzZXIgYXR0cmlidXRlIHBhY2tldCAodGFnIDE3KS5cblx0ICogQHBhcmFtIHtTdHJpbmd9IGlucHV0IHBheWxvYWQgb2YgYSB0YWcgMTcgcGFja2V0XG5cdCAqIEBwYXJhbSB7SW50ZWdlcn0gcG9zaXRpb24gcG9zaXRpb24gdG8gc3RhcnQgcmVhZGluZyBmcm9tIHRoZSBpbnB1dCBzdHJpbmdcblx0ICogQHBhcmFtIHtJbnRlZ2VyfSBsZW4gbGVuZ3RoIG9mIHRoZSBwYWNrZXQgb3IgdGhlIHJlbWFpbmluZyBsZW5ndGggb2YgaW5wdXQgYXQgcG9zaXRpb25cblx0ICogQHJldHVybiB7b3BlbnBncF9wYWNrZXRfZW5jcnlwdGVkZGF0YX0gb2JqZWN0IHJlcHJlc2VudGF0aW9uXG5cdCAqL1xuXHR0aGlzLnJlYWQgPSBmdW5jdGlvbihieXRlcykge1xuXHRcdHZhciBpID0gMDtcblx0XHR3aGlsZShpIDwgYnl0ZXMubGVuZ3RoKSB7XG5cdFx0XHR2YXIgbGVuID0gb3BlbnBncF9wYWNrZXQucmVhZF9zaW1wbGVfbGVuZ3RoKGJ5dGVzKTtcblxuXHRcdFx0aSArPSBsZW4ub2Zmc2V0O1xuXHRcdFx0dGhpcy5hdHRyaWJ1dGVzLnB1c2goYnl0ZXMuc3Vic3RyKGksIGxlbi5sZW4pKTtcblx0XHRcdGkgKz0gbGVuLmxlbjtcblx0XHR9XG5cdH1cbn07XG4iLCJcbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gcGFja2V0X3RydXN0KCkge1xuXG59O1xuIiwiXG5tb2R1bGUuZXhwb3J0cyA9IHtcblx0YWVzOiByZXF1aXJlKCcuL2Flcy5qcycpLFxuXHRkZXM6IHJlcXVpcmUoJy4vZGVzLmpzJyksXG5cdGNhc3Q1OiByZXF1aXJlKCcuL2Nhc3Q1LmpzJyksXG5cdHR3b2Zpc2g6IHJlcXVpcmUoJy4vdHdvZmlzaC5qcycpLFxuXHRibG93ZmlzaDogcmVxdWlyZSgnLi9ibG93ZmlzaC5qcycpXG59XG5cbiIsIlxudmFyIHNoYSA9IHJlcXVpcmUoJy4vc2hhLmpzJyk7XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuXHRtZDU6IHJlcXVpcmUoJy4vbWQ1LmpzJyksXG5cdHNoYTE6IHNoYS5zaGExLFxuXHRzaGEyNTY6IHNoYS5zaGEyNTYsXG5cdHNoYTIyNDogc2hhLnNoYTIyNCxcblx0c2hhMzg0OiBzaGEuc2hhMzg0LFxuXHRzaGE1MTI6IHNoYS5zaGE1MTIsXG5cdHJpcGVtZDogcmVxdWlyZSgnLi9yaXBlLW1kLmpzJyksXG5cblx0LyoqXG5cdCAqIENyZWF0ZSBhIGhhc2ggb24gdGhlIHNwZWNpZmllZCBkYXRhIHVzaW5nIHRoZSBzcGVjaWZpZWQgYWxnb3JpdGhtXG5cdCAqIEBwYXJhbSB7SW50ZWdlcn0gYWxnbyBIYXNoIGFsZ29yaXRobSB0eXBlIChzZWUgUkZDNDg4MCA5LjQpXG5cdCAqIEBwYXJhbSB7U3RyaW5nfSBkYXRhIERhdGEgdG8gYmUgaGFzaGVkXG5cdCAqIEByZXR1cm4ge1N0cmluZ30gaGFzaCB2YWx1ZVxuXHQgKi9cblx0ZGlnZXN0OiBmdW5jdGlvbihhbGdvLCBkYXRhKSB7XG5cdFx0c3dpdGNoKGFsZ28pIHtcblx0XHRjYXNlIDE6IC8vIC0gTUQ1IFtIQUNdXG5cdFx0XHRyZXR1cm4gdGhpcy5tZDUoZGF0YSk7XG5cdFx0Y2FzZSAyOiAvLyAtIFNIQS0xIFtGSVBTMTgwXVxuXHRcdFx0cmV0dXJuIHRoaXMuc2hhMShkYXRhKTtcblx0XHRjYXNlIDM6IC8vIC0gUklQRS1NRC8xNjAgW0hBQ11cblx0XHRcdHJldHVybiB0aGlzLnJpcGVtZChkYXRhKTtcblx0XHRjYXNlIDg6IC8vIC0gU0hBMjU2IFtGSVBTMTgwXVxuXHRcdFx0cmV0dXJuIHRoaXMuc2hhMjU2KGRhdGEpO1xuXHRcdGNhc2UgOTogLy8gLSBTSEEzODQgW0ZJUFMxODBdXG5cdFx0XHRyZXR1cm4gdGhpcy5zaGEzODQoZGF0YSk7XG5cdFx0Y2FzZSAxMDovLyAtIFNIQTUxMiBbRklQUzE4MF1cblx0XHRcdHJldHVybiB0aGlzLnNoYTUxMihkYXRhKTtcblx0XHRjYXNlIDExOi8vIC0gU0hBMjI0IFtGSVBTMTgwXVxuXHRcdFx0cmV0dXJuIHRoaXMuc2hhMjI0KGRhdGEpO1xuXHRcdGRlZmF1bHQ6XG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgaGFzaCBmdW5jdGlvbi4nKTtcblx0XHR9XG5cdH0sXG5cblx0LyoqXG5cdCAqIFJldHVybnMgdGhlIGhhc2ggc2l6ZSBpbiBieXRlcyBvZiB0aGUgc3BlY2lmaWVkIGhhc2ggYWxnb3JpdGhtIHR5cGVcblx0ICogQHBhcmFtIHtJbnRlZ2VyfSBhbGdvIEhhc2ggYWxnb3JpdGhtIHR5cGUgKFNlZSBSRkM0ODgwIDkuNClcblx0ICogQHJldHVybiB7SW50ZWdlcn0gU2l6ZSBpbiBieXRlcyBvZiB0aGUgcmVzdWx0aW5nIGhhc2hcblx0ICovXG5cdGdldEhhc2hCeXRlTGVuZ3RoOiBmdW5jdGlvbihhbGdvKSB7XG5cdFx0c3dpdGNoKGFsZ28pIHtcblx0XHRjYXNlIDE6IC8vIC0gTUQ1IFtIQUNdXG5cdFx0XHRyZXR1cm4gMTY7XG5cdFx0Y2FzZSAyOiAvLyAtIFNIQS0xIFtGSVBTMTgwXVxuXHRcdGNhc2UgMzogLy8gLSBSSVBFLU1ELzE2MCBbSEFDXVxuXHRcdFx0cmV0dXJuIDIwO1xuXHRcdGNhc2UgODogLy8gLSBTSEEyNTYgW0ZJUFMxODBdXG5cdFx0XHRyZXR1cm4gMzI7XG5cdFx0Y2FzZSA5OiAvLyAtIFNIQTM4NCBbRklQUzE4MF1cblx0XHRcdHJldHVybiA0OFxuXHRcdGNhc2UgMTA6Ly8gLSBTSEE1MTIgW0ZJUFMxODBdXG5cdFx0XHRyZXR1cm4gNjQ7XG5cdFx0Y2FzZSAxMTovLyAtIFNIQTIyNCBbRklQUzE4MF1cblx0XHRcdHJldHVybiAyODtcblx0XHRkZWZhdWx0OlxuXHRcdFx0dGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIGhhc2ggYWxnb3JpdGhtLicpO1xuXHRcdH1cblx0fVxuXG59XG5cbiIsIihmdW5jdGlvbigpey8vIE1vZGlmaWVkIGJ5IFJlY3VyaXR5IExhYnMgR21iSCBcblxuLy8gbW9kaWZpZWQgdmVyc2lvbiBvZiBodHRwOi8vd3d3LmhhbmV3aW4ubmV0L2VuY3J5cHQvUEdkZWNvZGUuanM6XG5cbi8qIE9wZW5QR1AgZW5jcnlwdGlvbiB1c2luZyBSU0EvQUVTXG4gKiBDb3B5cmlnaHQgMjAwNS0yMDA2IEhlcmJlcnQgSGFuZXdpbmtlbCwgd3d3LmhhbmVXSU4uZGVcbiAqIHZlcnNpb24gMi4wLCBjaGVjayB3d3cuaGFuZVdJTi5kZSBmb3IgdGhlIGxhdGVzdCB2ZXJzaW9uXG5cbiAqIFRoaXMgc29mdHdhcmUgaXMgcHJvdmlkZWQgYXMtaXMsIHdpdGhvdXQgZXhwcmVzcyBvciBpbXBsaWVkIHdhcnJhbnR5LiAgXG4gKiBQZXJtaXNzaW9uIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBkaXN0cmlidXRlIG9yIHNlbGwgdGhpcyBzb2Z0d2FyZSwgd2l0aCBvclxuICogd2l0aG91dCBmZWUsIGZvciBhbnkgcHVycG9zZSBhbmQgYnkgYW55IGluZGl2aWR1YWwgb3Igb3JnYW5pemF0aW9uLCBpcyBoZXJlYnlcbiAqIGdyYW50ZWQsIHByb3ZpZGVkIHRoYXQgdGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGFyYWdyYXBoIGFwcGVhciBcbiAqIGluIGFsbCBjb3BpZXMuIERpc3RyaWJ1dGlvbiBhcyBhIHBhcnQgb2YgYW4gYXBwbGljYXRpb24gb3IgYmluYXJ5IG11c3RcbiAqIGluY2x1ZGUgdGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgaW4gdGhlIGRvY3VtZW50YXRpb24gYW5kL29yIG90aGVyXG4gKiBtYXRlcmlhbHMgcHJvdmlkZWQgd2l0aCB0aGUgYXBwbGljYXRpb24gb3IgZGlzdHJpYnV0aW9uLlxuICovXG5cbnZhciB1dGlsID0gcmVxdWlyZSgnLi4vdXRpbCcpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IHtcblxuXHQvKipcblx0ICogQW4gYXJyYXkgb2YgYnl0ZXMsIHRoYXQgaXMgaW50ZWdlcnMgd2l0aCB2YWx1ZXMgZnJvbSAwIHRvIDI1NVxuXHQgKiBAdHlwZWRlZiB7KEFycmF5fFVpbnQ4QXJyYXkpfSBvcGVucGdwX2J5dGVfYXJyYXlcblx0ICovXG5cblx0LyoqXG5cdCAqIEJsb2NrIGNpcGhlciBmdW5jdGlvblxuXHQgKiBAY2FsbGJhY2sgb3BlbnBncF9jaXBoZXJfYmxvY2tfZm5cblx0ICogQHBhcmFtIHtvcGVucGdwX2J5dGVfYXJyYXl9IGJsb2NrIEEgYmxvY2sgdG8gcGVyZm9ybSBvcGVyYXRpb25zIG9uXG5cdCAqIEBwYXJhbSB7b3BlbnBncF9ieXRlX2FycmF5fSBrZXkgdG8gdXNlIGluIGVuY3J5cHRpb24vZGVjcnlwdGlvblxuXHQgKiBAcmV0dXJuIHtvcGVucGdwX2J5dGVfYXJyYXl9IEVuY3J5cHRlZC9kZWNyeXB0ZWQgYmxvY2tcblx0ICovXG5cblxuXHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXHQvKipcblx0ICogVGhpcyBmdW5jdGlvbiBlbmNyeXB0cyBhIGdpdmVuIHdpdGggdGhlIHNwZWNpZmllZCBwcmVmaXhyYW5kb20gXG5cdCAqIHVzaW5nIHRoZSBzcGVjaWZpZWQgYmxvY2tjaXBoZXIgdG8gZW5jcnlwdCBhIG1lc3NhZ2Vcblx0ICogQHBhcmFtIHtTdHJpbmd9IHByZWZpeHJhbmRvbSByYW5kb20gYnl0ZXMgb2YgYmxvY2tfc2l6ZSBsZW5ndGggcHJvdmlkZWQgXG5cdCAqICBhcyBhIHN0cmluZyB0byBiZSB1c2VkIGluIHByZWZpeGluZyB0aGUgZGF0YVxuXHQgKiBAcGFyYW0ge29wZW5wZ3BfY2lwaGVyX2Jsb2NrX2ZufSBibG9ja2NpcGhlcmZuIHRoZSBhbGdvcml0aG0gZW5jcnlwdCBmdW5jdGlvbiB0byBlbmNyeXB0XG5cdCAqICBkYXRhIGluIG9uZSBibG9ja19zaXplIGVuY3J5cHRpb24uIFxuXHQgKiBAcGFyYW0ge0ludGVnZXJ9IGJsb2NrX3NpemUgdGhlIGJsb2NrIHNpemUgaW4gYnl0ZXMgb2YgdGhlIGFsZ29yaXRobSB1c2VkXG5cdCAqIEBwYXJhbSB7U3RyaW5nfSBwbGFpbnRleHQgZGF0YSB0byBiZSBlbmNyeXB0ZWQgcHJvdmlkZWQgYXMgYSBzdHJpbmdcblx0ICogQHBhcmFtIHtvcGVucGdwX2J5dGVfYXJyYXl9IGtleSBrZXkgdG8gYmUgdXNlZCB0byBlbmNyeXB0IHRoZSBkYXRhLiBUaGlzIHdpbGwgYmUgcGFzc2VkIHRvIHRoZSBcblx0ICogIGJsb2NrY2lwaGVyZm5cblx0ICogQHBhcmFtIHtCb29sZWFufSByZXN5bmMgYSBib29sZWFuIHZhbHVlIHNwZWNpZnlpbmcgaWYgYSByZXN5bmMgb2YgdGhlIFxuXHQgKiAgSVYgc2hvdWxkIGJlIHVzZWQgb3Igbm90LiBUaGUgZW5jcnlwdGVkZGF0YXBhY2tldCB1c2VzIHRoZSBcblx0ICogIFwib2xkXCIgc3R5bGUgd2l0aCBhIHJlc3luYy4gRW5jcnlwdGlvbiB3aXRoaW4gYW4gXG5cdCAqICBlbmNyeXB0ZWRpbnRlZ3JpdHlwcm90ZWN0ZWRkYXRhIHBhY2tldCBpcyBub3QgcmVzeW5jaW5nIHRoZSBJVi5cblx0ICogQHJldHVybiB7U3RyaW5nfSBhIHN0cmluZyB3aXRoIHRoZSBlbmNyeXB0ZWQgZGF0YVxuXHQgKi9cblx0ZW5jcnlwdDogZnVuY3Rpb24gKHByZWZpeHJhbmRvbSwgYmxvY2tjaXBoZXJlbmNyeXB0Zm4sIHBsYWludGV4dCwgYmxvY2tfc2l6ZSwga2V5LCByZXN5bmMpIHtcblx0XHR2YXIgRlIgPSBuZXcgQXJyYXkoYmxvY2tfc2l6ZSk7XG5cdFx0dmFyIEZSRSA9IG5ldyBBcnJheShibG9ja19zaXplKTtcblxuXHRcdHByZWZpeHJhbmRvbSA9IHByZWZpeHJhbmRvbSArIHByZWZpeHJhbmRvbS5jaGFyQXQoYmxvY2tfc2l6ZS0yKSArcHJlZml4cmFuZG9tLmNoYXJBdChibG9ja19zaXplLTEpO1xuXHRcdHV0aWwucHJpbnRfZGVidWcoXCJwcmVmaXhyYW5kb206XCIrdXRpbC5oZXhzdHJkdW1wKHByZWZpeHJhbmRvbSkpO1xuXHRcdHZhciBjaXBoZXJ0ZXh0ID0gXCJcIjtcblx0XHQvLyAxLiAgVGhlIGZlZWRiYWNrIHJlZ2lzdGVyIChGUikgaXMgc2V0IHRvIHRoZSBJViwgd2hpY2ggaXMgYWxsIHplcm9zLlxuXHRcdGZvciAodmFyIGkgPSAwOyBpIDwgYmxvY2tfc2l6ZTsgaSsrKSBGUltpXSA9IDA7XG5cdFx0XG5cdFx0Ly8gMi4gIEZSIGlzIGVuY3J5cHRlZCB0byBwcm9kdWNlIEZSRSAoRlIgRW5jcnlwdGVkKS4gIFRoaXMgaXMgdGhlXG5cdFx0Ly8gICAgIGVuY3J5cHRpb24gb2YgYW4gYWxsLXplcm8gdmFsdWUuXG5cdFx0RlJFID0gYmxvY2tjaXBoZXJlbmNyeXB0Zm4oRlIsIGtleSk7XG5cdFx0Ly8gMy4gIEZSRSBpcyB4b3JlZCB3aXRoIHRoZSBmaXJzdCBCUyBvY3RldHMgb2YgcmFuZG9tIGRhdGEgcHJlZml4ZWQgdG9cblx0XHQvLyAgICAgdGhlIHBsYWludGV4dCB0byBwcm9kdWNlIENbMV0gdGhyb3VnaCBDW0JTXSwgdGhlIGZpcnN0IEJTIG9jdGV0c1xuXHRcdC8vICAgICBvZiBjaXBoZXJ0ZXh0LlxuXHRcdGZvciAodmFyIGkgPSAwOyBpIDwgYmxvY2tfc2l6ZTsgaSsrKSBjaXBoZXJ0ZXh0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoRlJFW2ldIF4gcHJlZml4cmFuZG9tLmNoYXJDb2RlQXQoaSkpO1xuXHRcdFxuXHRcdC8vIDQuICBGUiBpcyBsb2FkZWQgd2l0aCBDWzFdIHRocm91Z2ggQ1tCU10uXG5cdFx0Zm9yICh2YXIgaSA9IDA7IGkgPCBibG9ja19zaXplOyBpKyspIEZSW2ldID0gY2lwaGVydGV4dC5jaGFyQ29kZUF0KGkpO1xuXHRcdFxuXHRcdC8vIDUuICBGUiBpcyBlbmNyeXB0ZWQgdG8gcHJvZHVjZSBGUkUsIHRoZSBlbmNyeXB0aW9uIG9mIHRoZSBmaXJzdCBCU1xuXHRcdC8vIFx0ICAgb2N0ZXRzIG9mIGNpcGhlcnRleHQuXG5cdFx0RlJFID0gYmxvY2tjaXBoZXJlbmNyeXB0Zm4oRlIsIGtleSk7XG5cblx0XHQvLyA2LiAgVGhlIGxlZnQgdHdvIG9jdGV0cyBvZiBGUkUgZ2V0IHhvcmVkIHdpdGggdGhlIG5leHQgdHdvIG9jdGV0cyBvZlxuXHRcdC8vICAgICBkYXRhIHRoYXQgd2VyZSBwcmVmaXhlZCB0byB0aGUgcGxhaW50ZXh0LiAgVGhpcyBwcm9kdWNlcyBDW0JTKzFdXG5cdFx0Ly8gICAgIGFuZCBDW0JTKzJdLCB0aGUgbmV4dCB0d28gb2N0ZXRzIG9mIGNpcGhlcnRleHQuXG5cdFx0Y2lwaGVydGV4dCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKEZSRVswXSBeIHByZWZpeHJhbmRvbS5jaGFyQ29kZUF0KGJsb2NrX3NpemUpKTtcblx0XHRjaXBoZXJ0ZXh0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoRlJFWzFdIF4gcHJlZml4cmFuZG9tLmNoYXJDb2RlQXQoYmxvY2tfc2l6ZSsxKSk7XG5cblx0XHRpZiAocmVzeW5jKSB7XG5cdFx0XHQvLyA3LiAgKFRoZSByZXN5bmMgc3RlcCkgRlIgaXMgbG9hZGVkIHdpdGggQzMtQzEwLlxuXHRcdFx0Zm9yICh2YXIgaSA9IDA7IGkgPCBibG9ja19zaXplOyBpKyspIEZSW2ldID0gY2lwaGVydGV4dC5jaGFyQ29kZUF0KGkrMik7XG5cdFx0fSBlbHNlIHtcblx0XHRcdGZvciAodmFyIGkgPSAwOyBpIDwgYmxvY2tfc2l6ZTsgaSsrKSBGUltpXSA9IGNpcGhlcnRleHQuY2hhckNvZGVBdChpKTtcblx0XHR9XG5cdFx0Ly8gOC4gIEZSIGlzIGVuY3J5cHRlZCB0byBwcm9kdWNlIEZSRS5cblx0XHRGUkUgPSBibG9ja2NpcGhlcmVuY3J5cHRmbihGUiwga2V5KTtcblx0XHRcblx0XHRpZiAocmVzeW5jKSB7XG5cdFx0XHQvLyA5LiAgRlJFIGlzIHhvcmVkIHdpdGggdGhlIGZpcnN0IDggb2N0ZXRzIG9mIHRoZSBnaXZlbiBwbGFpbnRleHQsIG5vd1xuXHRcdFx0Ly9cdCAgIHRoYXQgd2UgaGF2ZSBmaW5pc2hlZCBlbmNyeXB0aW5nIHRoZSAxMCBvY3RldHMgb2YgcHJlZml4ZWQgZGF0YS5cblx0XHRcdC8vIFx0ICAgVGhpcyBwcm9kdWNlcyBDMTEtQzE4LCB0aGUgbmV4dCA4IG9jdGV0cyBvZiBjaXBoZXJ0ZXh0LlxuXHRcdFx0Zm9yICh2YXIgaSA9IDA7IGkgPCBibG9ja19zaXplOyBpKyspXG5cdFx0XHRcdGNpcGhlcnRleHQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShGUkVbaV0gXiBwbGFpbnRleHQuY2hhckNvZGVBdChpKSk7XG5cdFx0XHRmb3Iobj1ibG9ja19zaXplKzI7IG4gPCBwbGFpbnRleHQubGVuZ3RoOyBuKz1ibG9ja19zaXplKSB7XG5cdFx0XHRcdC8vIDEwLiBGUiBpcyBsb2FkZWQgd2l0aCBDMTEtQzE4XG5cdFx0XHRcdGZvciAodmFyIGkgPSAwOyBpIDwgYmxvY2tfc2l6ZTsgaSsrKSBGUltpXSA9IGNpcGhlcnRleHQuY2hhckNvZGVBdChuK2kpO1xuXHRcdFx0XG5cdFx0XHRcdC8vIDExLiBGUiBpcyBlbmNyeXB0ZWQgdG8gcHJvZHVjZSBGUkUuXG5cdFx0XHRcdEZSRSA9IGJsb2NrY2lwaGVyZW5jcnlwdGZuKEZSLCBrZXkpO1xuXHRcdFx0XG5cdFx0XHRcdC8vIDEyLiBGUkUgaXMgeG9yZWQgd2l0aCB0aGUgbmV4dCA4IG9jdGV0cyBvZiBwbGFpbnRleHQsIHRvIHByb2R1Y2UgdGhlXG5cdFx0XHRcdC8vIG5leHQgOCBvY3RldHMgb2YgY2lwaGVydGV4dC4gIFRoZXNlIGFyZSBsb2FkZWQgaW50byBGUiBhbmQgdGhlXG5cdFx0XHRcdC8vIHByb2Nlc3MgaXMgcmVwZWF0ZWQgdW50aWwgdGhlIHBsYWludGV4dCBpcyB1c2VkIHVwLlxuXHRcdFx0XHRmb3IgKHZhciBpID0gMDsgaSA8IGJsb2NrX3NpemU7IGkrKykgY2lwaGVydGV4dCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKEZSRVtpXSBeIHBsYWludGV4dC5jaGFyQ29kZUF0KChuLTIpK2kpKTtcblx0XHRcdH1cblx0XHR9XG5cdFx0ZWxzZSB7XG5cdFx0XHRwbGFpbnRleHQgPSBcIiAgXCIrcGxhaW50ZXh0O1xuXHRcdFx0Ly8gOS4gIEZSRSBpcyB4b3JlZCB3aXRoIHRoZSBmaXJzdCA4IG9jdGV0cyBvZiB0aGUgZ2l2ZW4gcGxhaW50ZXh0LCBub3dcblx0XHRcdC8vXHQgICB0aGF0IHdlIGhhdmUgZmluaXNoZWQgZW5jcnlwdGluZyB0aGUgMTAgb2N0ZXRzIG9mIHByZWZpeGVkIGRhdGEuXG5cdFx0XHQvLyBcdCAgIFRoaXMgcHJvZHVjZXMgQzExLUMxOCwgdGhlIG5leHQgOCBvY3RldHMgb2YgY2lwaGVydGV4dC5cblx0XHRcdGZvciAodmFyIGkgPSAyOyBpIDwgYmxvY2tfc2l6ZTsgaSsrKSBjaXBoZXJ0ZXh0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoRlJFW2ldIF4gcGxhaW50ZXh0LmNoYXJDb2RlQXQoaSkpO1xuXHRcdFx0dmFyIHRlbXBDaXBoZXJ0ZXh0ID0gY2lwaGVydGV4dC5zdWJzdHJpbmcoMCwyKmJsb2NrX3NpemUpLnNwbGl0KCcnKTtcblx0XHRcdHZhciB0ZW1wQ2lwaGVydGV4dFN0cmluZyA9IGNpcGhlcnRleHQuc3Vic3RyaW5nKGJsb2NrX3NpemUpO1xuXHRcdFx0Zm9yKG49YmxvY2tfc2l6ZTsgbjxwbGFpbnRleHQubGVuZ3RoOyBuKz1ibG9ja19zaXplKSB7XG5cdFx0XHRcdC8vIDEwLiBGUiBpcyBsb2FkZWQgd2l0aCBDMTEtQzE4XG5cdFx0XHRcdGZvciAodmFyIGkgPSAwOyBpIDwgYmxvY2tfc2l6ZTsgaSsrKSBGUltpXSA9IHRlbXBDaXBoZXJ0ZXh0U3RyaW5nLmNoYXJDb2RlQXQoaSk7XG5cdFx0XHRcdHRlbXBDaXBoZXJ0ZXh0U3RyaW5nPScnO1xuXHRcdFx0XHRcblx0XHRcdFx0Ly8gMTEuIEZSIGlzIGVuY3J5cHRlZCB0byBwcm9kdWNlIEZSRS5cblx0XHRcdFx0RlJFID0gYmxvY2tjaXBoZXJlbmNyeXB0Zm4oRlIsIGtleSk7XG5cdFx0XHRcdFxuXHRcdFx0XHQvLyAxMi4gRlJFIGlzIHhvcmVkIHdpdGggdGhlIG5leHQgOCBvY3RldHMgb2YgcGxhaW50ZXh0LCB0byBwcm9kdWNlIHRoZVxuXHRcdFx0XHQvLyAgICAgbmV4dCA4IG9jdGV0cyBvZiBjaXBoZXJ0ZXh0LiAgVGhlc2UgYXJlIGxvYWRlZCBpbnRvIEZSIGFuZCB0aGVcblx0XHRcdFx0Ly8gICAgIHByb2Nlc3MgaXMgcmVwZWF0ZWQgdW50aWwgdGhlIHBsYWludGV4dCBpcyB1c2VkIHVwLlxuXHRcdFx0XHRmb3IgKHZhciBpID0gMDsgaSA8IGJsb2NrX3NpemU7IGkrKyl7IHRlbXBDaXBoZXJ0ZXh0LnB1c2goU3RyaW5nLmZyb21DaGFyQ29kZShGUkVbaV0gXiBwbGFpbnRleHQuY2hhckNvZGVBdChuK2kpKSk7XG5cdFx0XHRcdHRlbXBDaXBoZXJ0ZXh0U3RyaW5nICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoRlJFW2ldIF4gcGxhaW50ZXh0LmNoYXJDb2RlQXQobitpKSk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdGNpcGhlcnRleHQgPSB0ZW1wQ2lwaGVydGV4dC5qb2luKCcnKTtcblx0XHRcdFxuXHRcdH1cblx0XHRyZXR1cm4gY2lwaGVydGV4dDtcblx0fSxcblxuXHQvKipcblx0ICogRGVjcnlwdHMgdGhlIHByZWZpeGVkIGRhdGEgZm9yIHRoZSBNb2RpZmljYXRpb24gRGV0ZWN0aW9uIENvZGUgKE1EQykgY29tcHV0YXRpb25cblx0ICogQHBhcmFtIHtvcGVucGdwX2Jsb2NrX2NpcGhlcl9mbn0gYmxvY2tjaXBoZXJlbmNyeXB0Zm4gQ2lwaGVyIGZ1bmN0aW9uIHRvIHVzZVxuXHQgKiBAcGFyYW0ge0ludGVnZXJ9IGJsb2NrX3NpemUgQmxvY2tzaXplIG9mIHRoZSBhbGdvcml0aG1cblx0ICogQHBhcmFtIHtvcGVucGdwX2J5dGVfYXJyYXl9IGtleSBUaGUga2V5IGZvciBlbmNyeXB0aW9uXG5cdCAqIEBwYXJhbSB7U3RyaW5nfSBjaXBoZXJ0ZXh0IFRoZSBlbmNyeXB0ZWQgZGF0YVxuXHQgKiBAcmV0dXJuIHtTdHJpbmd9IHBsYWludGV4dCBEYXRhIG9mIEQoY2lwaGVydGV4dCkgd2l0aCBibG9ja3NpemUgbGVuZ3RoICsyXG5cdCAqL1xuXHRtZGM6IGZ1bmN0aW9uIChibG9ja2NpcGhlcmVuY3J5cHRmbiwgYmxvY2tfc2l6ZSwga2V5LCBjaXBoZXJ0ZXh0KSB7XG5cdFx0dmFyIGlibG9jayA9IG5ldyBBcnJheShibG9ja19zaXplKTtcblx0XHR2YXIgYWJsb2NrID0gbmV3IEFycmF5KGJsb2NrX3NpemUpO1xuXHRcdHZhciBpO1xuXG5cdFx0Ly8gaW5pdGlhbGlzYXRpb24gdmVjdG9yXG5cdFx0Zm9yKGk9MDsgaSA8IGJsb2NrX3NpemU7IGkrKykgaWJsb2NrW2ldID0gMDtcblxuXHRcdGlibG9jayA9IGJsb2NrY2lwaGVyZW5jcnlwdGZuKGlibG9jaywga2V5KTtcblx0XHRmb3IoaSA9IDA7IGkgPCBibG9ja19zaXplOyBpKyspXG5cdFx0e1xuXHRcdFx0YWJsb2NrW2ldID0gY2lwaGVydGV4dC5jaGFyQ29kZUF0KGkpO1xuXHRcdFx0aWJsb2NrW2ldIF49IGFibG9ja1tpXTtcblx0XHR9XG5cblx0XHRhYmxvY2sgPSBibG9ja2NpcGhlcmVuY3J5cHRmbihhYmxvY2ssIGtleSk7XG5cblx0XHRyZXR1cm4gdXRpbC5iaW4yc3RyKGlibG9jaykrXG5cdFx0XHRTdHJpbmcuZnJvbUNoYXJDb2RlKGFibG9ja1swXV5jaXBoZXJ0ZXh0LmNoYXJDb2RlQXQoYmxvY2tfc2l6ZSkpK1xuXHRcdFx0U3RyaW5nLmZyb21DaGFyQ29kZShhYmxvY2tbMV1eY2lwaGVydGV4dC5jaGFyQ29kZUF0KGJsb2NrX3NpemUrMSkpO1xuXHR9LFxuXHQvKipcblx0ICogVGhpcyBmdW5jdGlvbiBkZWNyeXB0cyBhIGdpdmVuIHBsYWludGV4dCB1c2luZyB0aGUgc3BlY2lmaWVkXG5cdCAqIGJsb2NrY2lwaGVyIHRvIGRlY3J5cHQgYSBtZXNzYWdlXG5cdCAqIEBwYXJhbSB7b3BlbnBncF9jaXBoZXJfYmxvY2tfZm59IGJsb2NrY2lwaGVyZm4gVGhlIGFsZ29yaXRobSBfZW5jcnlwdF8gZnVuY3Rpb24gdG8gZW5jcnlwdFxuXHQgKiAgZGF0YSBpbiBvbmUgYmxvY2tfc2l6ZSBlbmNyeXB0aW9uLlxuXHQgKiBAcGFyYW0ge0ludGVnZXJ9IGJsb2NrX3NpemUgdGhlIGJsb2NrIHNpemUgaW4gYnl0ZXMgb2YgdGhlIGFsZ29yaXRobSB1c2VkXG5cdCAqIEBwYXJhbSB7U3RyaW5nfSBwbGFpbnRleHQgY2lwaGVydGV4dCB0byBiZSBkZWNyeXB0ZWQgcHJvdmlkZWQgYXMgYSBzdHJpbmdcblx0ICogQHBhcmFtIHtvcGVucGdwX2J5dGVfYXJyYXl9IGtleSBrZXkgdG8gYmUgdXNlZCB0byBkZWNyeXB0IHRoZSBjaXBoZXJ0ZXh0LiBUaGlzIHdpbGwgYmUgcGFzc2VkIHRvIHRoZSBcblx0ICogIGJsb2NrY2lwaGVyZm5cblx0ICogQHBhcmFtIHtCb29sZWFufSByZXN5bmMgYSBib29sZWFuIHZhbHVlIHNwZWNpZnlpbmcgaWYgYSByZXN5bmMgb2YgdGhlIFxuXHQgKiAgSVYgc2hvdWxkIGJlIHVzZWQgb3Igbm90LiBUaGUgZW5jcnlwdGVkZGF0YXBhY2tldCB1c2VzIHRoZSBcblx0ICogIFwib2xkXCIgc3R5bGUgd2l0aCBhIHJlc3luYy4gRGVjcnlwdGlvbiB3aXRoaW4gYW4gXG5cdCAqICBlbmNyeXB0ZWRpbnRlZ3JpdHlwcm90ZWN0ZWRkYXRhIHBhY2tldCBpcyBub3QgcmVzeW5jaW5nIHRoZSBJVi5cblx0ICogQHJldHVybiB7U3RyaW5nfSBhIHN0cmluZyB3aXRoIHRoZSBwbGFpbnRleHQgZGF0YVxuXHQgKi9cblxuXHRkZWNyeXB0OiBmdW5jdGlvbiAoYmxvY2tjaXBoZXJlbmNyeXB0Zm4sIGJsb2NrX3NpemUsIGtleSwgY2lwaGVydGV4dCwgcmVzeW5jKVxuXHR7XG5cdFx0dXRpbC5wcmludF9kZWJ1ZyhcInJlc3luYzpcIityZXN5bmMpO1xuXHRcdHZhciBpYmxvY2sgPSBuZXcgQXJyYXkoYmxvY2tfc2l6ZSk7XG5cdFx0dmFyIGFibG9jayA9IG5ldyBBcnJheShibG9ja19zaXplKTtcblx0XHR2YXIgaSwgbiA9ICcnO1xuXHRcdHZhciB0ZXh0ID0gW107XG5cblx0XHQvLyBpbml0aWFsaXNhdGlvbiB2ZWN0b3Jcblx0XHRmb3IoaT0wOyBpIDwgYmxvY2tfc2l6ZTsgaSsrKSBpYmxvY2tbaV0gPSAwO1xuXG5cdFx0aWJsb2NrID0gYmxvY2tjaXBoZXJlbmNyeXB0Zm4oaWJsb2NrLCBrZXkpO1xuXHRcdGZvcihpID0gMDsgaSA8IGJsb2NrX3NpemU7IGkrKylcblx0XHR7XG5cdFx0XHRhYmxvY2tbaV0gPSBjaXBoZXJ0ZXh0LmNoYXJDb2RlQXQoaSk7XG5cdFx0XHRpYmxvY2tbaV0gXj0gYWJsb2NrW2ldO1xuXHRcdH1cblxuXHRcdGFibG9jayA9IGJsb2NrY2lwaGVyZW5jcnlwdGZuKGFibG9jaywga2V5KTtcblxuXHRcdHV0aWwucHJpbnRfZGVidWcoXCJvcGVucGdwX2NmYl9kZWNyeXB0OlxcbmlibG9jazpcIit1dGlsLmhleGlkdW1wKGlibG9jaykrXCJcXG5hYmxvY2s6XCIrdXRpbC5oZXhpZHVtcChhYmxvY2spK1wiXFxuXCIpO1xuXHRcdHV0aWwucHJpbnRfZGVidWcoKGFibG9ja1swXV5jaXBoZXJ0ZXh0LmNoYXJDb2RlQXQoYmxvY2tfc2l6ZSkpLnRvU3RyaW5nKDE2KSsoYWJsb2NrWzFdXmNpcGhlcnRleHQuY2hhckNvZGVBdChibG9ja19zaXplKzEpKS50b1N0cmluZygxNikpO1xuXHRcdFxuXHRcdC8vIHRlc3QgY2hlY2sgb2N0ZXRzXG5cdFx0aWYoaWJsb2NrW2Jsb2NrX3NpemUtMl0hPShhYmxvY2tbMF1eY2lwaGVydGV4dC5jaGFyQ29kZUF0KGJsb2NrX3NpemUpKVxuXHRcdHx8IGlibG9ja1tibG9ja19zaXplLTFdIT0oYWJsb2NrWzFdXmNpcGhlcnRleHQuY2hhckNvZGVBdChibG9ja19zaXplKzEpKSlcblx0XHR7XG5cdFx0XHR1dGlsLnByaW50X2Vyb3IoXCJlcnJvciBkdWRpbmcgZGVjcnlwdGlvbi4gU3ltbWVjdHJpYyBlbmNyeXB0ZWQgZGF0YSBub3QgdmFsaWQuXCIpO1xuXHRcdFx0cmV0dXJuIHRleHQuam9pbignJyk7XG5cdFx0fVxuXHRcdFxuXHRcdC8qICBSRkM0ODgwOiBUYWcgMTggYW5kIFJlc3luYzpcblx0XHQgKiAgWy4uLl0gVW5saWtlIHRoZSBTeW1tZXRyaWNhbGx5IEVuY3J5cHRlZCBEYXRhIFBhY2tldCwgbm9cblx0XHQgKiAgc3BlY2lhbCBDRkIgcmVzeW5jaHJvbml6YXRpb24gaXMgZG9uZSBhZnRlciBlbmNyeXB0aW5nIHRoaXMgcHJlZml4XG5cdFx0ICogIGRhdGEuICBTZWUgXCJPcGVuUEdQIENGQiBNb2RlXCIgYmVsb3cgZm9yIG1vcmUgZGV0YWlscy5cblxuXHRcdCAqL1xuXHRcdFxuXHRcdGlmIChyZXN5bmMpIHtcblx0XHRcdGZvcihpPTA7IGk8YmxvY2tfc2l6ZTsgaSsrKSBpYmxvY2tbaV0gPSBjaXBoZXJ0ZXh0LmNoYXJDb2RlQXQoaSsyKTtcblx0XHRcdGZvcihuPWJsb2NrX3NpemUrMjsgbjxjaXBoZXJ0ZXh0Lmxlbmd0aDsgbis9YmxvY2tfc2l6ZSlcblx0XHRcdHtcblx0XHRcdFx0YWJsb2NrID0gYmxvY2tjaXBoZXJlbmNyeXB0Zm4oaWJsb2NrLCBrZXkpO1xuXG5cdFx0XHRcdGZvcihpID0gMDsgaTxibG9ja19zaXplICYmIGkrbiA8IGNpcGhlcnRleHQubGVuZ3RoOyBpKyspXG5cdFx0XHRcdHtcblx0XHRcdFx0XHRpYmxvY2tbaV0gPSBjaXBoZXJ0ZXh0LmNoYXJDb2RlQXQobitpKTtcblx0XHRcdFx0XHR0ZXh0LnB1c2goU3RyaW5nLmZyb21DaGFyQ29kZShhYmxvY2tbaV1eaWJsb2NrW2ldKSk7IFxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fSBlbHNlIHtcblx0XHRcdGZvcihpPTA7IGk8YmxvY2tfc2l6ZTsgaSsrKSBpYmxvY2tbaV0gPSBjaXBoZXJ0ZXh0LmNoYXJDb2RlQXQoaSk7XG5cdFx0XHRmb3Iobj1ibG9ja19zaXplOyBuPGNpcGhlcnRleHQubGVuZ3RoOyBuKz1ibG9ja19zaXplKVxuXHRcdFx0e1xuXHRcdFx0XHRhYmxvY2sgPSBibG9ja2NpcGhlcmVuY3J5cHRmbihpYmxvY2ssIGtleSk7XG5cdFx0XHRcdGZvcihpID0gMDsgaTxibG9ja19zaXplICYmIGkrbiA8IGNpcGhlcnRleHQubGVuZ3RoOyBpKyspXG5cdFx0XHRcdHtcblx0XHRcdFx0XHRpYmxvY2tbaV0gPSBjaXBoZXJ0ZXh0LmNoYXJDb2RlQXQobitpKTtcblx0XHRcdFx0XHR0ZXh0LnB1c2goU3RyaW5nLmZyb21DaGFyQ29kZShhYmxvY2tbaV1eaWJsb2NrW2ldKSk7IFxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXHRcdFxuXHRcdHJldHVybiB0ZXh0LmpvaW4oJycpO1xuXHR9LFxuXG5cblx0bm9ybWFsRW5jcnlwdDogZnVuY3Rpb24oYmxvY2tjaXBoZXJlbmNyeXB0Zm4sIGJsb2NrX3NpemUsIGtleSwgcGxhaW50ZXh0LCBpdikge1xuXHRcdHZhciBibG9ja2kgPVwiXCI7XG5cdFx0dmFyIGJsb2NrYyA9IFwiXCI7XG5cdFx0dmFyIHBvcyA9IDA7XG5cdFx0dmFyIGN5cGhlcnRleHQgPSBbXTtcblx0XHR2YXIgdGVtcEJsb2NrID0gW107XG5cdFx0YmxvY2tjID0gaXYuc3Vic3RyaW5nKDAsYmxvY2tfc2l6ZSk7XG5cdFx0d2hpbGUgKHBsYWludGV4dC5sZW5ndGggPiBibG9ja19zaXplKnBvcykge1xuXHRcdFx0dmFyIGVuY2Jsb2NrID0gYmxvY2tjaXBoZXJlbmNyeXB0Zm4oYmxvY2tjLCBrZXkpO1xuXHRcdFx0YmxvY2tpID0gcGxhaW50ZXh0LnN1YnN0cmluZygocG9zKmJsb2NrX3NpemUpLChwb3MqYmxvY2tfc2l6ZSkrYmxvY2tfc2l6ZSk7XG5cdFx0XHRmb3IgKHZhciBpPTA7IGkgPCBibG9ja2kubGVuZ3RoOyBpKyspXG5cdFx0XHRcdHRlbXBCbG9jay5wdXNoKFN0cmluZy5mcm9tQ2hhckNvZGUoYmxvY2tpLmNoYXJDb2RlQXQoaSkgXiBlbmNibG9ja1tpXSkpO1xuXHRcdFx0YmxvY2tjID0gdGVtcEJsb2NrLmpvaW4oJycpO1xuXHRcdFx0dGVtcEJsb2NrID0gW107XG5cdFx0XHRjeXBoZXJ0ZXh0LnB1c2goYmxvY2tjKTtcblx0XHRcdHBvcysrO1xuXHRcdH1cblx0XHRyZXR1cm4gY3lwaGVydGV4dC5qb2luKCcnKTtcblx0fSxcblxuXHRub3JtYWxEZWNyeXB0OiBmdW5jdGlvbihibG9ja2NpcGhlcmVuY3J5cHRmbiwgYmxvY2tfc2l6ZSwga2V5LCBjaXBoZXJ0ZXh0LCBpdikgeyBcblx0XHR2YXIgYmxvY2twID1cIlwiO1xuXHRcdHZhciBwb3MgPSAwO1xuXHRcdHZhciBwbGFpbnRleHQgPSBbXTtcblx0XHR2YXIgb2Zmc2V0ID0gMDtcblx0XHRpZiAoaXYgPT0gbnVsbClcblx0XHRcdGZvciAodmFyIGkgPSAwOyBpIDwgYmxvY2tfc2l6ZTsgaSsrKSBibG9ja3AgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSgwKTtcblx0XHRlbHNlXG5cdFx0XHRibG9ja3AgPSBpdi5zdWJzdHJpbmcoMCxibG9ja19zaXplKTtcblx0XHR3aGlsZSAoY2lwaGVydGV4dC5sZW5ndGggPiAoYmxvY2tfc2l6ZSpwb3MpKSB7XG5cdFx0XHR2YXIgZGVjYmxvY2sgPSBibG9ja2NpcGhlcmVuY3J5cHRmbihibG9ja3AsIGtleSk7XG5cdFx0XHRibG9ja3AgPSBjaXBoZXJ0ZXh0LnN1YnN0cmluZygocG9zKihibG9ja19zaXplKSkrb2Zmc2V0LChwb3MqKGJsb2NrX3NpemUpKSsoYmxvY2tfc2l6ZSkrb2Zmc2V0KTtcblx0XHRcdGZvciAodmFyIGk9MDsgaSA8IGJsb2NrcC5sZW5ndGg7IGkrKykge1xuXHRcdFx0XHRwbGFpbnRleHQucHVzaChTdHJpbmcuZnJvbUNoYXJDb2RlKGJsb2NrcC5jaGFyQ29kZUF0KGkpIF4gZGVjYmxvY2tbaV0pKTtcblx0XHRcdH1cblx0XHRcdHBvcysrO1xuXHRcdH1cblx0XHRcblx0XHRyZXR1cm4gcGxhaW50ZXh0LmpvaW4oJycpO1xuXHR9XG59XG5cbn0pKCkiLCJcbm1vZHVsZS5leHBvcnRzID0ge1xuXHRyc2E6IHJlcXVpcmUoJy4vcnNhLmpzJyksXG5cdGVsZ2FtYWw6IHJlcXVpcmUoJy4vZWxnYW1hbC5qcycpLFxuXHRkc2E6IHJlcXVpcmUoJy4vZHNhLmpzJylcbn1cblxuIiwiXG52YXIgcHVibGljS2V5ID0gcmVxdWlyZSgnLi9wdWJsaWNfa2V5JyksXG5cdHBrY3MxID0gcmVxdWlyZSgnLi9wa2NzMS5qcycpLFxuXHRoYXNoTW9kdWxlID0gcmVxdWlyZSgnLi9oYXNoJyk7XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuXHQvKipcblx0ICogXG5cdCAqIEBwYXJhbSB7SW50ZWdlcn0gYWxnbyBwdWJsaWMgS2V5IGFsZ29yaXRobVxuXHQgKiBAcGFyYW0ge0ludGVnZXJ9IGhhc2hfYWxnbyBIYXNoIGFsZ29yaXRobVxuXHQgKiBAcGFyYW0ge29wZW5wZ3BfdHlwZV9tcGlbXX0gbXNnX01QSXMgU2lnbmF0dXJlIG11bHRpcHJlY2lzaW9uIGludGVnZXJzXG5cdCAqIEBwYXJhbSB7b3BlbnBncF90eXBlX21waVtdfSBwdWJsaWNrZXlfTVBJcyBQdWJsaWMga2V5IG11bHRpcHJlY2lzaW9uIGludGVnZXJzIFxuXHQgKiBAcGFyYW0ge1N0cmluZ30gZGF0YSBEYXRhIG9uIHdoZXJlIHRoZSBzaWduYXR1cmUgd2FzIGNvbXB1dGVkIG9uLlxuXHQgKiBAcmV0dXJuIHtCb29sZWFufSB0cnVlIGlmIHNpZ25hdHVyZSAoc2lnX2RhdGEgd2FzIGVxdWFsIHRvIGRhdGEgb3ZlciBoYXNoKVxuXHQgKi9cblx0dmVyaWZ5OiBmdW5jdGlvbihhbGdvLCBoYXNoX2FsZ28sIG1zZ19NUElzLCBwdWJsaWNrZXlfTVBJcywgZGF0YSkge1xuXHRcdHZhciBjYWxjX2hhc2ggPSBoYXNoTW9kdWxlLmRpZ2VzdChoYXNoX2FsZ28sIGRhdGEpO1xuXG5cdFx0c3dpdGNoKGFsZ28pIHtcblx0XHRjYXNlIDE6IC8vIFJTQSAoRW5jcnlwdCBvciBTaWduKSBbSEFDXSAgXG5cdFx0Y2FzZSAyOiAvLyBSU0EgRW5jcnlwdC1Pbmx5IFtIQUNdXG5cdFx0Y2FzZSAzOiAvLyBSU0EgU2lnbi1Pbmx5IFtIQUNdXG5cdFx0XHR2YXIgcnNhID0gbmV3IHB1YmxpY0tleS5yc2EoKTtcblx0XHRcdHZhciBuID0gcHVibGlja2V5X01QSXNbMF0udG9CaWdJbnRlZ2VyKCk7XG5cdFx0XHR2YXIgZSA9IHB1YmxpY2tleV9NUElzWzFdLnRvQmlnSW50ZWdlcigpO1xuXHRcdFx0dmFyIHggPSBtc2dfTVBJc1swXS50b0JpZ0ludGVnZXIoKTtcblx0XHRcdHZhciBkb3B1YmxpYyA9IHJzYS52ZXJpZnkoeCxlLG4pO1xuXHRcdFx0dmFyIGhhc2ggID0gcGtjczEuZW1zYS5kZWNvZGUoaGFzaF9hbGdvLGRvcHVibGljLnRvTVBJKCkuc3Vic3RyaW5nKDIpKTtcblx0XHRcdGlmIChoYXNoID09IC0xKSB7XG5cdFx0XHRcdHRocm93IG5ldyBFcnJvcignUEtDUzEgcGFkZGluZyBpbiBtZXNzYWdlIG9yIGtleSBpbmNvcnJlY3QuIEFib3J0aW5nLi4uJyk7XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gaGFzaCA9PSBjYWxjX2hhc2g7XG5cdFx0XHRcblx0XHRjYXNlIDE2OiAvLyBFbGdhbWFsIChFbmNyeXB0LU9ubHkpIFtFTEdBTUFMXSBbSEFDXVxuXHRcdFx0dGhyb3cgbmV3IEVycm9yKFwic2lnbmluZyB3aXRoIEVsZ2FtYWwgaXMgbm90IGRlZmluZWQgaW4gdGhlIE9wZW5QR1Agc3RhbmRhcmQuXCIpO1xuXHRcdGNhc2UgMTc6IC8vIERTQSAoRGlnaXRhbCBTaWduYXR1cmUgQWxnb3JpdGhtKSBbRklQUzE4Nl0gW0hBQ11cblx0XHRcdHZhciBkc2EgPSBuZXcgcHVibGljS2V5LmRzYSgpO1xuXHRcdFx0dmFyIHMxID0gbXNnX01QSXNbMF0udG9CaWdJbnRlZ2VyKCk7XG5cdFx0XHR2YXIgczIgPSBtc2dfTVBJc1sxXS50b0JpZ0ludGVnZXIoKTtcblx0XHRcdHZhciBwID0gcHVibGlja2V5X01QSXNbMF0udG9CaWdJbnRlZ2VyKCk7XG5cdFx0XHR2YXIgcSA9IHB1YmxpY2tleV9NUElzWzFdLnRvQmlnSW50ZWdlcigpO1xuXHRcdFx0dmFyIGcgPSBwdWJsaWNrZXlfTVBJc1syXS50b0JpZ0ludGVnZXIoKTtcblx0XHRcdHZhciB5ID0gcHVibGlja2V5X01QSXNbM10udG9CaWdJbnRlZ2VyKCk7XG5cdFx0XHR2YXIgbSA9IGRhdGE7XG5cdFx0XHR2YXIgZG9wdWJsaWMgPSBkc2EudmVyaWZ5KGhhc2hfYWxnbyxzMSxzMixtLHAscSxnLHkpO1xuXHRcdFx0cmV0dXJuIGRvcHVibGljLmNvbXBhcmVUbyhzMSkgPT0gMDtcblx0XHRkZWZhdWx0OlxuXHRcdFx0dGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIHNpZ25hdHVyZSBhbGdvcml0aG0uJyk7XG5cdFx0fVxuXHRcdFxuXHR9LFxuXHQgICBcblx0LyoqXG5cdCAqIENyZWF0ZSBhIHNpZ25hdHVyZSBvbiBkYXRhIHVzaW5nIHRoZSBzcGVjaWZpZWQgYWxnb3JpdGhtXG5cdCAqIEBwYXJhbSB7SW50ZWdlcn0gaGFzaF9hbGdvIGhhc2ggQWxnb3JpdGhtIHRvIHVzZSAoU2VlIFJGQzQ4ODAgOS40KVxuXHQgKiBAcGFyYW0ge0ludGVnZXJ9IGFsZ28gQXN5bW1ldHJpYyBjaXBoZXIgYWxnb3JpdGhtIHRvIHVzZSAoU2VlIFJGQzQ4ODAgOS4xKVxuXHQgKiBAcGFyYW0ge29wZW5wZ3BfdHlwZV9tcGlbXX0gcHVibGljTVBJcyBQdWJsaWMga2V5IG11bHRpcHJlY2lzaW9uIGludGVnZXJzIFxuXHQgKiBvZiB0aGUgcHJpdmF0ZSBrZXkgXG5cdCAqIEBwYXJhbSB7b3BlbnBncF90eXBlX21waVtdfSBzZWNyZXRNUElzIFByaXZhdGUga2V5IG11bHRpcHJlY2lzaW9uIFxuXHQgKiBpbnRlZ2VycyB3aGljaCBpcyB1c2VkIHRvIHNpZ24gdGhlIGRhdGFcblx0ICogQHBhcmFtIHtTdHJpbmd9IGRhdGEgRGF0YSB0byBiZSBzaWduZWRcblx0ICogQHJldHVybiB7b3BlbnBncF90eXBlX21waVtdfVxuXHQgKi9cblx0c2lnbjogZnVuY3Rpb24oaGFzaF9hbGdvLCBhbGdvLCBrZXlJbnRlZ2VycywgZGF0YSkge1xuXHRcdFxuXHRcdHN3aXRjaChhbGdvKSB7XG5cdFx0Y2FzZSAxOiAvLyBSU0EgKEVuY3J5cHQgb3IgU2lnbikgW0hBQ10gIFxuXHRcdGNhc2UgMjogLy8gUlNBIEVuY3J5cHQtT25seSBbSEFDXVxuXHRcdGNhc2UgMzogLy8gUlNBIFNpZ24tT25seSBbSEFDXVxuXHRcdFx0dmFyIHJzYSA9IG5ldyBwdWJsaWNLZXkucnNhKCk7XG5cdFx0XHR2YXIgZCA9IGtleUludGVnZXJzWzJdLnRvQmlnSW50ZWdlcigpO1xuXHRcdFx0dmFyIG4gPSBrZXlJbnRlZ2Vyc1swXS50b0JpZ0ludGVnZXIoKTtcblx0XHRcdHZhciBtID0gcGtjczEuZW1zYS5lbmNvZGUoaGFzaF9hbGdvLCBcblx0XHRcdFx0ZGF0YSwga2V5SW50ZWdlcnNbMF0uYnl0ZUxlbmd0aCgpKTtcblxuXHRcdFx0cmV0dXJuIHJzYS5zaWduKG0sIGQsIG4pLnRvTVBJKCk7XG5cblx0XHRjYXNlIDE3OiAvLyBEU0EgKERpZ2l0YWwgU2lnbmF0dXJlIEFsZ29yaXRobSkgW0ZJUFMxODZdIFtIQUNdXG5cdFx0XHR2YXIgZHNhID0gbmV3IHB1YmxpY0tleS5kc2EoKTtcblxuXHRcdFx0dmFyIHAgPSBrZXlJbnRlZ2Vyc1swXS50b0JpZ0ludGVnZXIoKTtcblx0XHRcdHZhciBxID0ga2V5SW50ZWdlcnNbMV0udG9CaWdJbnRlZ2VyKCk7XG5cdFx0XHR2YXIgZyA9IGtleUludGVnZXJzWzJdLnRvQmlnSW50ZWdlcigpO1xuXHRcdFx0dmFyIHkgPSBrZXlJbnRlZ2Vyc1szXS50b0JpZ0ludGVnZXIoKTtcblx0XHRcdHZhciB4ID0ga2V5SW50ZWdlcnNbNF0udG9CaWdJbnRlZ2VyKCk7XG5cdFx0XHR2YXIgbSA9IGRhdGE7XG5cdFx0XHR2YXIgcmVzdWx0ID0gZHNhLnNpZ24oaGFzaF9hbGdvLG0sIGcsIHAsIHEsIHgpO1xuXG5cdFx0XHRyZXR1cm4gcmVzdWx0WzBdLnRvU3RyaW5nKCkgKyByZXN1bHRbMV0udG9TdHJpbmcoKTtcblx0XHRjYXNlIDE2OiAvLyBFbGdhbWFsIChFbmNyeXB0LU9ubHkpIFtFTEdBTUFMXSBbSEFDXVxuXHRcdFx0dGhyb3cgbmV3IEVycm9yKCdTaWduaW5nIHdpdGggRWxnYW1hbCBpcyBub3QgZGVmaW5lZCBpbiB0aGUgT3BlblBHUCBzdGFuZGFyZC4nKTtcblx0XHRkZWZhdWx0OlxuXHRcdFx0dGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIHNpZ25hdHVyZSBhbGdvcml0aG0uJyk7XG5cdFx0fVx0XG5cdH1cbn1cbiIsIi8vIEdQRzRCcm93c2VycyAtIEFuIE9wZW5QR1AgaW1wbGVtZW50YXRpb24gaW4gamF2YXNjcmlwdFxuLy8gQ29weXJpZ2h0IChDKSAyMDExIFJlY3VyaXR5IExhYnMgR21iSFxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yXG4vLyBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uOyBlaXRoZXJcbi8vIHZlcnNpb24gMi4xIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbi8vIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4vLyBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlIEdOVVxuLy8gTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cbi8vIFxuLy8gWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhbG9uZyB3aXRoIHRoaXMgbGlicmFyeTsgaWYgbm90LCB3cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZVxuLy8gRm91bmRhdGlvbiwgSW5jLiwgNTEgRnJhbmtsaW4gU3RyZWV0LCBGaWZ0aCBGbG9vciwgQm9zdG9uLCBNQSAgMDIxMTAtMTMwMSAgVVNBXG5cbi8qKlxuICogQVNOMSBvYmplY3QgaWRlbnRpZmllcnMgZm9yIGhhc2hlcyAoU2VlIFJGQzQ4ODAgNS4yLjIpXG4gKi9cbmhhc2hfaGVhZGVycyA9IG5ldyBBcnJheSgpO1xuaGFzaF9oZWFkZXJzWzFdICA9IFsweDMwLDB4MjAsMHgzMCwweDBjLDB4MDYsMHgwOCwweDJhLDB4ODYsMHg0OCwweDg2LDB4ZjcsMHgwZCwweDAyLDB4MDUsMHgwNSwweDAwLDB4MDQsMHgxMF07XG5oYXNoX2hlYWRlcnNbM10gID0gWzB4MzAsMHgyMSwweDMwLDB4MDksMHgwNiwweDA1LDB4MkIsMHgyNCwweDAzLDB4MDIsMHgwMSwweDA1LDB4MDAsMHgwNCwweDE0XTtcbmhhc2hfaGVhZGVyc1syXSAgPSBbMHgzMCwweDIxLDB4MzAsMHgwOSwweDA2LDB4MDUsMHgyYiwweDBlLDB4MDMsMHgwMiwweDFhLDB4MDUsMHgwMCwweDA0LDB4MTRdO1xuaGFzaF9oZWFkZXJzWzhdICA9IFsweDMwLDB4MzEsMHgzMCwweDBkLDB4MDYsMHgwOSwweDYwLDB4ODYsMHg0OCwweDAxLDB4NjUsMHgwMywweDA0LDB4MDIsMHgwMSwweDA1LDB4MDAsMHgwNCwweDIwXTtcbmhhc2hfaGVhZGVyc1s5XSAgPSBbMHgzMCwweDQxLDB4MzAsMHgwZCwweDA2LDB4MDksMHg2MCwweDg2LDB4NDgsMHgwMSwweDY1LDB4MDMsMHgwNCwweDAyLDB4MDIsMHgwNSwweDAwLDB4MDQsMHgzMF07XG5oYXNoX2hlYWRlcnNbMTBdID0gWzB4MzAsMHg1MSwweDMwLDB4MGQsMHgwNiwweDA5LDB4NjAsMHg4NiwweDQ4LDB4MDEsMHg2NSwweDAzLDB4MDQsMHgwMiwweDAzLDB4MDUsMHgwMCwweDA0LDB4NDBdO1xuaGFzaF9oZWFkZXJzWzExXSA9IFsweDMwLDB4MzEsMHgzMCwweDBkLDB4MDYsMHgwOSwweDYwLDB4ODYsMHg0OCwweDAxLDB4NjUsMHgwMywweDA0LDB4MDIsMHgwNCwweDA1LDB4MDAsMHgwNCwweDFDXTtcblxuXG52YXIgY3J5cHRvID0gcmVxdWlyZSgnLi9jcnlwdG8uanMnKSxcblx0cmFuZG9tID0gcmVxdWlyZSgnLi9yYW5kb20uanMnKSxcblx0dXRpbCA9IHJlcXVpcmUoJy4uL3V0aWwnKSxcblx0QmlnSW50ZWdlciA9IHJlcXVpcmUoJy4vcHVibGljX2tleS9qc2JuLmpzJyksXG5cdGhhc2ggPSByZXF1aXJlKCcuL2hhc2gnKTtcblx0XG5tb2R1bGUuZXhwb3J0cyA9IHtcblx0ZW1lOiB7XG5cdC8qKlxuXHQgKiBjcmVhdGUgYSBFTUUtUEtDUzEtdjFfNSBwYWRkaW5nIChTZWUgUkZDNDg4MCAxMy4xLjEpXG5cdCAqIEBwYXJhbSB7U3RyaW5nfSBtZXNzYWdlIG1lc3NhZ2UgdG8gYmUgcGFkZGVkXG5cdCAqIEBwYXJhbSB7SW50ZWdlcn0gbGVuZ3RoIExlbmd0aCB0byB0aGUgcmVzdWx0aW5nIG1lc3NhZ2Vcblx0ICogQHJldHVybiB7U3RyaW5nfSBFTUUtUEtDUzEgcGFkZGVkIG1lc3NhZ2Vcblx0ICovXG5cdGVuY29kZTogZnVuY3Rpb24obWVzc2FnZSwgbGVuZ3RoKSB7XG5cdFx0aWYgKG1lc3NhZ2UubGVuZ3RoID4gbGVuZ3RoLTExKVxuXHRcdFx0cmV0dXJuIC0xO1xuXHRcdHZhciByZXN1bHQgPSBcIlwiO1xuXHRcdHJlc3VsdCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKDApO1xuXHRcdHJlc3VsdCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKDIpO1xuXHRcdGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoIC0gbWVzc2FnZS5sZW5ndGggLSAzOyBpKyspIHtcblx0XHRcdHJlc3VsdCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKHJhbmRvbS5nZXRQc2V1ZG9SYW5kb20oMSwyNTUpKTtcblx0XHR9XG5cdFx0cmVzdWx0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoMCk7XG5cdFx0cmVzdWx0ICs9IG1lc3NhZ2U7XG5cdFx0cmV0dXJuIHJlc3VsdDtcblx0fSxcblxuXHQvKipcblx0ICogZGVjb2RlcyBhIEVNRS1QS0NTMS12MV81IHBhZGRpbmcgKFNlZSBSRkM0ODgwIDEzLjEuMilcblx0ICogQHBhcmFtIHtTdHJpbmd9IG1lc3NhZ2UgRU1FLVBLQ1MxIHBhZGRlZCBtZXNzYWdlXG5cdCAqIEByZXR1cm4ge1N0cmluZ30gZGVjb2RlZCBtZXNzYWdlIFxuXHQgKi9cblx0IGRlY29kZTogZnVuY3Rpb24obWVzc2FnZSwgbGVuKSB7XG5cdFx0aWYgKG1lc3NhZ2UubGVuZ3RoIDwgbGVuKVxuXHRcdFx0bWVzc2FnZSA9IFN0cmluZy5mcm9tQ2hhckNvZGUoMCkrbWVzc2FnZTtcblx0XHRpZiAobWVzc2FnZS5sZW5ndGggPCAxMiB8fCBtZXNzYWdlLmNoYXJDb2RlQXQoMCkgIT0gMCB8fCBtZXNzYWdlLmNoYXJDb2RlQXQoMSkgIT0gMilcblx0XHRcdHJldHVybiAtMTtcblx0XHR2YXIgaSA9IDI7XG5cdFx0d2hpbGUgKG1lc3NhZ2UuY2hhckNvZGVBdChpKSAhPSAwICYmIG1lc3NhZ2UubGVuZ3RoID4gaSlcblx0XHRcdGkrKztcblx0XHRyZXR1cm4gbWVzc2FnZS5zdWJzdHJpbmcoaSsxLCBtZXNzYWdlLmxlbmd0aCk7XG5cdH0sXG5cdH0sXG5cblx0ZW1zYToge1xuXG5cdC8qKlxuXHQgKiBjcmVhdGUgYSBFTVNBLVBLQ1MxLXYxXzUgcGFkZGluZyAoU2VlIFJGQzQ4ODAgMTMuMS4zKVxuXHQgKiBAcGFyYW0ge0ludGVnZXJ9IGFsZ28gSGFzaCBhbGdvcml0aG0gdHlwZSB1c2VkXG5cdCAqIEBwYXJhbSB7U3RyaW5nfSBkYXRhIERhdGEgdG8gYmUgaGFzaGVkXG5cdCAqIEBwYXJhbSB7SW50ZWdlcn0ga2V5bGVuZ3RoIEtleSBzaXplIG9mIHRoZSBwdWJsaWMgbXBpIGluIGJ5dGVzXG5cdCAqIEByZXR1cm5zIHtTdHJpbmd9IEhhc2hjb2RlIHdpdGggcGtjczFwYWRkaW5nIGFzIHN0cmluZ1xuXHQgKi9cblx0ZW5jb2RlOiBmdW5jdGlvbihhbGdvLCBkYXRhLCBrZXlsZW5ndGgpIHtcblx0XHR2YXIgZGF0YTIgPSBcIlwiO1xuXHRcdGRhdGEyICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoMHgwMCk7XG5cdFx0ZGF0YTIgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSgweDAxKTtcblx0XHRmb3IgKHZhciBpID0gMDsgaSA8IChrZXlsZW5ndGggLSBoYXNoX2hlYWRlcnNbYWxnb10ubGVuZ3RoIC0gMyAtIFxuXHRcdFx0aGFzaC5nZXRIYXNoQnl0ZUxlbmd0aChhbGdvKSk7IGkrKylcblxuXHRcdFx0ZGF0YTIgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSgweGZmKTtcblxuXHRcdGRhdGEyICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoMHgwMCk7XG5cdFx0XG5cdFx0Zm9yICh2YXIgaSA9IDA7IGkgPCBoYXNoX2hlYWRlcnNbYWxnb10ubGVuZ3RoOyBpKyspXG5cdFx0XHRkYXRhMiArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGhhc2hfaGVhZGVyc1thbGdvXVtpXSk7XG5cdFx0XG5cdFx0ZGF0YTIgKz0gaGFzaC5kaWdlc3QoYWxnbywgZGF0YSk7XG5cdFx0cmV0dXJuIG5ldyBCaWdJbnRlZ2VyKHV0aWwuaGV4c3RyZHVtcChkYXRhMiksMTYpO1xuXHR9LFxuXG5cdC8qKlxuXHQgKiBleHRyYWN0IHRoZSBoYXNoIG91dCBvZiBhbiBFTVNBLVBLQ1MxLXYxLjUgcGFkZGluZyAoU2VlIFJGQzQ4ODAgMTMuMS4zKSBcblx0ICogQHBhcmFtIHtTdHJpbmd9IGRhdGEgSGFzaCBpbiBwa2NzMSBlbmNvZGluZ1xuXHQgKiBAcmV0dXJucyB7U3RyaW5nfSBUaGUgaGFzaCBhcyBzdHJpbmdcblx0ICovXG5cdGRlY29kZTogZnVuY3Rpb24oYWxnbywgZGF0YSkgeyBcblx0XHR2YXIgaSA9IDA7XG5cdFx0aWYgKGRhdGEuY2hhckNvZGVBdCgwKSA9PSAwKSBpKys7XG5cdFx0ZWxzZSBpZiAoZGF0YS5jaGFyQ29kZUF0KDApICE9IDEpIHJldHVybiAtMTtcblx0XHRlbHNlIGkrKztcblxuXHRcdHdoaWxlIChkYXRhLmNoYXJDb2RlQXQoaSkgPT0gMHhGRikgaSsrO1xuXHRcdGlmIChkYXRhLmNoYXJDb2RlQXQoaSsrKSAhPSAwKSByZXR1cm4gLTE7XG5cdFx0dmFyIGogPSAwO1xuXHRcdGZvciAoaiA9IDA7IGogPCBoYXNoX2hlYWRlcnNbYWxnb10ubGVuZ3RoICYmIGoraSA8IGRhdGEubGVuZ3RoOyBqKyspIHtcblx0XHRcdGlmIChkYXRhLmNoYXJDb2RlQXQoaitpKSAhPSBoYXNoX2hlYWRlcnNbYWxnb11bal0pIHJldHVybiAtMTtcblx0XHR9XG5cdFx0aSs9IGo7XHRcblx0XHRpZiAoZGF0YS5zdWJzdHJpbmcoaSkubGVuZ3RoIDwgaGFzaC5nZXRIYXNoQnl0ZUxlbmd0aChhbGdvKSkgcmV0dXJuIC0xO1xuXHRcdHJldHVybiBkYXRhLnN1YnN0cmluZyhpKTtcblx0fVxuXHR9XG59XG4iLCIvLyBHUEc0QnJvd3NlcnMgLSBBbiBPcGVuUEdQIGltcGxlbWVudGF0aW9uIGluIGphdmFzY3JpcHRcbi8vIENvcHlyaWdodCAoQykgMjAxMSBSZWN1cml0eSBMYWJzIEdtYkhcbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vclxuLy8gbW9kaWZ5IGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyXG4vLyB2ZXJzaW9uIDIuMSBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4vLyBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuLy8gTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZSBHTlVcbi8vIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG4vLyBcbi8vIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYWxvbmcgd2l0aCB0aGlzIGxpYnJhcnk7IGlmIG5vdCwgd3JpdGUgdG8gdGhlIEZyZWUgU29mdHdhcmVcbi8vIEZvdW5kYXRpb24sIEluYy4sIDUxIEZyYW5rbGluIFN0cmVldCwgRmlmdGggRmxvb3IsIEJvc3RvbiwgTUEgIDAyMTEwLTEzMDEgIFVTQSBcblxuLy8gVGhlIEdQRzRCcm93c2VycyBzeW1tZXRyaWMgY3J5cHRvIGludGVyZmFjZVxuXG52YXIgY2ZiID0gcmVxdWlyZSgnLi9jZmIuanMnKSxcblx0Y2lwaGVyID0gcmVxdWlyZSgnLi9jaXBoZXInKTtcblxubW9kdWxlLmV4cG9ydHMgPSB7XG5cbi8qKlxuICogU3ltbWV0cmljYWxseSBlbmNyeXB0cyBkYXRhIHVzaW5nIHByZWZpeGVkcmFuZG9tLCBhIGtleSB3aXRoIGxlbmd0aCBcbiAqIGRlcGVuZGluZyBvbiB0aGUgYWxnb3JpdGhtIGluIG9wZW5wZ3BfY2ZiIG1vZGUgd2l0aCBvciB3aXRob3V0IHJlc3luY1xuICogKE1EQyBzdHlsZSlcbiAqIEBwYXJhbSB7U3RyaW5nfSBwcmVmaXhyYW5kb20gU2VjdXJlIHJhbmRvbSBieXRlcyBhcyBzdHJpbmcgaW4gXG4gKiBsZW5ndGggZXF1YWwgdG8gdGhlIGJsb2NrIHNpemUgb2YgdGhlIGFsZ29yaXRobSB1c2VkICh1c2UgXG4gKiBvcGVucGdwX2NyeXB0b19nZXRQcmVmaXhSYW5kb20oYWxnbykgdG8gcmV0cmlldmUgdGhhdCBzdHJpbmdcbiAqIEBwYXJhbSB7SW50ZWdlcn0gYWxnbyBBbGdvcml0aG0gdG8gdXNlIChzZWUgUkZDNDg4MCA5LjIpXG4gKiBAcGFyYW0ge1N0cmluZ30ga2V5IEtleSBhcyBzdHJpbmcuIGxlbmd0aCBpcyBkZXBlbmRpbmcgb24gdGhlIGFsZ29yaXRobSB1c2VkXG4gKiBAcGFyYW0ge1N0cmluZ30gZGF0YSBEYXRhIHRvIGVuY3J5cHRcbiAqIEBwYXJhbSB7Qm9vbGVhbn0gb3BlbnBncF9jZmJcbiAqIEByZXR1cm4ge1N0cmluZ30gRW5jcnlwdGVkIGRhdGFcbiAqL1xuZW5jcnlwdDogZnVuY3Rpb24gKHByZWZpeHJhbmRvbSwgYWxnbywga2V5LCBkYXRhLCBvcGVucGdwX2NmYikge1xuXHRzd2l0Y2goYWxnbykge1xuXHRcdGNhc2UgJ3BsYWludGV4dCc6IC8vIFBsYWludGV4dCBvciB1bmVuY3J5cHRlZCBkYXRhXG5cdFx0XHRyZXR1cm4gZGF0YTsgLy8gYmxvY2tjaXBoZXJlbmNyeXB0Zm4sIHBsYWludGV4dCwgYmxvY2tfc2l6ZSwga2V5XG5cdFx0Y2FzZSAnZGVzJzogLy8gVHJpcGxlREVTIChERVMtRURFLCBbU0NITkVJRVJdIFtIQUNdIC0gMTY4IGJpdCBrZXkgZGVyaXZlZCBmcm9tIDE5Milcblx0XHRcdHJldHVybiBjZmIuZW5jcnlwdChwcmVmaXhyYW5kb20sIGNpcGhlci5kZXMsIGRhdGEsOCxrZXksIG9wZW5wZ3BfY2ZiKS5zdWJzdHJpbmcoMCwgZGF0YS5sZW5ndGggKyAxMCk7XG5cdFx0Y2FzZSAnY2FzdDUnOiAvLyBDQVNUNSAoMTI4IGJpdCBrZXksIGFzIHBlciBbUkZDMjE0NF0pXG5cdFx0XHRyZXR1cm4gY2ZiLmVuY3J5cHQocHJlZml4cmFuZG9tLCBjaXBoZXIuY2FzdDUsIGRhdGEsOCxrZXksIG9wZW5wZ3BfY2ZiKS5zdWJzdHJpbmcoMCwgZGF0YS5sZW5ndGggKyAxMCk7XG5cdFx0Y2FzZSAnYmxvd2Zpc2gnOiAvLyBCbG93ZmlzaCAoMTI4IGJpdCBrZXksIDE2IHJvdW5kcykgW0JMT1dGSVNIXVxuXHRcdFx0cmV0dXJuIGNmYi5lbmNyeXB0KHByZWZpeHJhbmRvbSwgY2lwaGVyLmJsb3dmaXNoLCBkYXRhLDgsa2V5LCBvcGVucGdwX2NmYikuc3Vic3RyaW5nKDAsIGRhdGEubGVuZ3RoICsgMTApO1xuXHRcdGNhc2UgJ2FlczEyOCc6IC8vIEFFUyB3aXRoIDEyOC1iaXQga2V5IFtBRVNdXG5cdFx0Y2FzZSAnYWVzMTkyJzogLy8gQUVTIHdpdGggMTkyLWJpdCBrZXlcblx0XHRjYXNlICdhZXMyNTYnOiAvLyBBRVMgd2l0aCAyNTYtYml0IGtleVxuXHRcdFx0cmV0dXJuIGNmYi5lbmNyeXB0KHByZWZpeHJhbmRvbSwgY2lwaGVyLmFlcy5lbmNyeXB0LCBkYXRhLCAxNiwgY2lwaGVyLmFlcy5rZXlFeHBhbnNpb24oa2V5KSwgb3BlbnBncF9jZmIpLnN1YnN0cmluZygwLCBkYXRhLmxlbmd0aCArIDE4KTtcblx0XHRjYXNlICd0d29maXNoJzogLy8gVHdvZmlzaCB3aXRoIDI1Ni1iaXQga2V5IFtUV09GSVNIXVxuXHRcdFx0cmV0dXJuIGNmYi5lbmNyeXB0KHByZWZpeHJhbmRvbSwgY2lwaGVyLnR3b2Zpc2gsIGRhdGEsMTYsIGtleSwgb3BlbnBncF9jZmIpLnN1YnN0cmluZygwLCBkYXRhLmxlbmd0aCArIDE4KTtcblx0XHRkZWZhdWx0OlxuXHRcdFx0dGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIGFsZ29yaXRobS4nKTtcblx0fVxufSxcblxuLyoqXG4gKiBTeW1tZXRyaWNhbGx5IGRlY3J5cHRzIGRhdGEgdXNpbmcgYSBrZXkgd2l0aCBsZW5ndGggZGVwZW5kaW5nIG9uIHRoZVxuICogYWxnb3JpdGhtIGluIG9wZW5wZ3BfY2ZiIG1vZGUgd2l0aCBvciB3aXRob3V0IHJlc3luYyAoTURDIHN0eWxlKVxuICogQHBhcmFtIHtJbnRlZ2VyfSBhbGdvIEFsZ29yaXRobSB0byB1c2UgKHNlZSBSRkM0ODgwIDkuMilcbiAqIEBwYXJhbSB7U3RyaW5nfSBrZXkgS2V5IGFzIHN0cmluZy4gbGVuZ3RoIGlzIGRlcGVuZGluZyBvbiB0aGUgYWxnb3JpdGhtIHVzZWRcbiAqIEBwYXJhbSB7U3RyaW5nfSBkYXRhIERhdGEgdG8gYmUgZGVjcnlwdGVkXG4gKiBAcGFyYW0ge0Jvb2xlYW59IG9wZW5wZ3BfY2ZiIElmIHRydWUgdXNlIHRoZSByZXN5bmMgKGZvciBlbmNyeXB0ZWRkYXRhKTsgXG4gKiBvdGhlcndpc2UgdXNlIHdpdGhvdXQgdGhlIHJlc3luYyAoZm9yIE1EQyBlbmNyeXB0ZWQgZGF0YSlcbiAqIEByZXR1cm4ge1N0cmluZ30gUGxhaW50ZXh0IGRhdGFcbiAqL1xuZGVjcnlwdDogZnVuY3Rpb24gKGFsZ28sIGtleSwgZGF0YSwgb3BlbnBncF9jZmIpIHtcblx0dmFyIG4gPSAwO1xuXHRpZiAoIW9wZW5wZ3BfY2ZiKVxuXHRcdG4gPSAyO1xuXHRzd2l0Y2goYWxnbykge1xuXHRjYXNlICdwbGFpbnRleHQnOiAvLyBQbGFpbnRleHQgb3IgdW5lbmNyeXB0ZWQgZGF0YVxuXHRcdHJldHVybiBkYXRhO1xuXHRjYXNlICdkZXMnOiAvLyBUcmlwbGVERVMgKERFUy1FREUsIFtTQ0hORUlFUl0gW0hBQ10gLSAxNjggYml0IGtleSBkZXJpdmVkIGZyb20gMTkyKVxuXHRcdHJldHVybiBjZmIuZGVjcnlwdChjaXBoZXIuZGVzLCA4LCBrZXksIGRhdGEsIG9wZW5wZ3BfY2ZiKS5zdWJzdHJpbmcobiwgKGRhdGEubGVuZ3RoK24pLTEwKTtcblx0Y2FzZSAnY2FzdDUnOiAvLyBDQVNUNSAoMTI4IGJpdCBrZXksIGFzIHBlciBbUkZDMjE0NF0pXG5cdFx0cmV0dXJuIGNmYi5kZWNyeXB0KGNpcGhlci5jYXN0NSwgOCwga2V5LCBkYXRhLCBvcGVucGdwX2NmYikuc3Vic3RyaW5nKG4sIChkYXRhLmxlbmd0aCtuKS0xMCk7XG5cdGNhc2UgJ2Jsb3dmaXNoJzogLy8gQmxvd2Zpc2ggKDEyOCBiaXQga2V5LCAxNiByb3VuZHMpIFtCTE9XRklTSF1cblx0XHRyZXR1cm4gY2ZiLmRlY3J5cHQoY2lwaGVyLmJsb3dmaXNoLCA4LCBrZXksIGRhdGEsIG9wZW5wZ3BfY2ZiKS5zdWJzdHJpbmcobiwgKGRhdGEubGVuZ3RoK24pLTEwKTtcblx0Y2FzZSAnYWVzMTI4JzogLy8gQUVTIHdpdGggMTI4LWJpdCBrZXkgW0FFU11cblx0Y2FzZSAnYWVzMTkyJzogLy8gQUVTIHdpdGggMTkyLWJpdCBrZXlcblx0Y2FzZSAnYWVzMjU2JzogLy8gQUVTIHdpdGggMjU2LWJpdCBrZXlcblx0XHRyZXR1cm4gY2ZiLmRlY3J5cHQoY2lwaGVyLmFlcy5lbmNyeXB0LCAxNiwgY2lwaGVyLmFlcy5rZXlFeHBhbnNpb24oa2V5KSwgZGF0YSwgb3BlbnBncF9jZmIpLnN1YnN0cmluZyhuLCAoZGF0YS5sZW5ndGgrbiktMTgpO1xuXHRjYXNlICd0d29maXNoJzogLy8gVHdvZmlzaCB3aXRoIDI1Ni1iaXQga2V5IFtUV09GSVNIXVxuXHRcdHZhciByZXN1bHQgPSBjZmIuZGVjcnlwdChjaXBoZXIudHdvZmlzaCwgMTYsIGtleSwgZGF0YSwgb3BlbnBncF9jZmIpLnN1YnN0cmluZyhuLCAoZGF0YS5sZW5ndGgrbiktMTgpO1xuXHRcdHJldHVybiByZXN1bHQ7XG5cdGRlZmF1bHQ6XG5cdFx0dGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIGFsZ29yaXRobScpO1xuXHR9XG59XG5cbn1cbiIsIi8vIEdQRzRCcm93c2VycyAtIEFuIE9wZW5QR1AgaW1wbGVtZW50YXRpb24gaW4gamF2YXNjcmlwdFxuLy8gQ29weXJpZ2h0IChDKSAyMDExIFJlY3VyaXR5IExhYnMgR21iSFxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yXG4vLyBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uOyBlaXRoZXJcbi8vIHZlcnNpb24gMi4xIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbi8vIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4vLyBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlIEdOVVxuLy8gTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cbi8vIFxuLy8gWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhbG9uZyB3aXRoIHRoaXMgbGlicmFyeTsgaWYgbm90LCB3cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZVxuLy8gRm91bmRhdGlvbiwgSW5jLiwgNTEgRnJhbmtsaW4gU3RyZWV0LCBGaWZ0aCBGbG9vciwgQm9zdG9uLCBNQSAgMDIxMTAtMTMwMSAgVVNBIFxuXG4vLyBUaGUgR1BHNEJyb3dzZXJzIGNyeXB0byBpbnRlcmZhY2VcblxudmFyIHJhbmRvbSA9IHJlcXVpcmUoJy4vcmFuZG9tLmpzJyksXG5cdGNpcGhlciA9IHJlcXVpcmUoJy4vY2lwaGVyJyksXG5cdGNmYiA9IHJlcXVpcmUoJy4vY2ZiLmpzJyksXG5cdHB1YmxpY0tleT0gcmVxdWlyZSgnLi9wdWJsaWNfa2V5JyksXG5cdHR5cGVfbXBpID0gcmVxdWlyZSgnLi4vdHlwZS9tcGkuanMnKTtcblxubW9kdWxlLmV4cG9ydHMgPSB7XG4vKipcbiAqIEVuY3J5cHRzIGRhdGEgdXNpbmcgdGhlIHNwZWNpZmllZCBwdWJsaWMga2V5IG11bHRpcHJlY2lzaW9uIGludGVnZXJzIFxuICogYW5kIHRoZSBzcGVjaWZpZWQgYWxnb3JpdGhtLlxuICogQHBhcmFtIHtJbnRlZ2VyfSBhbGdvIEFsZ29yaXRobSB0byBiZSB1c2VkIChTZWUgUkZDNDg4MCA5LjEpXG4gKiBAcGFyYW0ge29wZW5wZ3BfdHlwZV9tcGlbXX0gcHVibGljTVBJcyBBbGdvcml0aG0gZGVwZW5kZW50IG11bHRpcHJlY2lzaW9uIGludGVnZXJzXG4gKiBAcGFyYW0ge29wZW5wZ3BfdHlwZV9tcGl9IGRhdGEgRGF0YSB0byBiZSBlbmNyeXB0ZWQgYXMgTVBJXG4gKiBAcmV0dXJuIHtvcGVucGdwX3R5cGVfbXBpW119IGlmIFJTQSBhbiBvcGVucGdwX3R5cGVfbXBpOyBcbiAqIGlmIGVsZ2FtYWwgZW5jcnlwdGlvbiBhbiBhcnJheSBvZiB0d28gb3BlbnBncF90eXBlX21waSBpcyByZXR1cm5lZDsgb3RoZXJ3aXNlIG51bGxcbiAqL1xucHVibGljS2V5RW5jcnlwdDogZnVuY3Rpb24oYWxnbywgcHVibGljTVBJcywgZGF0YSkge1xuXHR2YXIgcmVzdWx0ID0gKGZ1bmN0aW9uKCkge1xuXHRcdHN3aXRjaChhbGdvKSB7XG5cdFx0Y2FzZSAncnNhX2VuY3J5cHQnOlxuXHRcdGNhc2UgJ3JzYV9lbmNyeXB0X3NpZ24nOlxuXHRcdFx0dmFyIHJzYSA9IG5ldyBwdWJsaWNLZXkucnNhKCk7XG5cdFx0XHR2YXIgbiA9IHB1YmxpY01QSXNbMF0udG9CaWdJbnRlZ2VyKCk7XG5cdFx0XHR2YXIgZSA9IHB1YmxpY01QSXNbMV0udG9CaWdJbnRlZ2VyKCk7XG5cdFx0XHR2YXIgbSA9IGRhdGEudG9CaWdJbnRlZ2VyKCk7XG5cdFx0XHRyZXR1cm4gW3JzYS5lbmNyeXB0KG0sZSxuKV07XG5cblx0XHRjYXNlICdlbGdhbWFsJzpcblx0XHRcdHZhciBlbGdhbWFsID0gbmV3IHB1YmxpY0tleS5lbGdhbWFsKCk7XG5cdFx0XHR2YXIgcCA9IHB1YmxpY01QSXNbMF0udG9CaWdJbnRlZ2VyKCk7XG5cdFx0XHR2YXIgZyA9IHB1YmxpY01QSXNbMV0udG9CaWdJbnRlZ2VyKCk7XG5cdFx0XHR2YXIgeSA9IHB1YmxpY01QSXNbMl0udG9CaWdJbnRlZ2VyKCk7XG5cdFx0XHR2YXIgbSA9IGRhdGEudG9CaWdJbnRlZ2VyKCk7XG5cdFx0XHRyZXR1cm4gZWxnYW1hbC5lbmNyeXB0KG0sZyxwLHkpO1xuXG5cdFx0ZGVmYXVsdDpcblx0XHRcdHJldHVybiBbXTtcblx0XHR9XG5cdH0pKCk7XG5cblx0cmV0dXJuIHJlc3VsdC5tYXAoZnVuY3Rpb24oYm4pIHtcblx0XHR2YXIgbXBpID0gbmV3IHR5cGVfbXBpKCk7XG5cdFx0bXBpLmZyb21CaWdJbnRlZ2VyKGJuKTtcblx0XHRyZXR1cm4gbXBpO1xuXHR9KTtcbn0sXG5cbi8qKlxuICogRGVjcnlwdHMgZGF0YSB1c2luZyB0aGUgc3BlY2lmaWVkIHB1YmxpYyBrZXkgbXVsdGlwcmVjaXNpb24gaW50ZWdlcnMgb2YgdGhlIHByaXZhdGUga2V5LFxuICogdGhlIHNwZWNpZmllZCBzZWNyZXRNUElzIG9mIHRoZSBwcml2YXRlIGtleSBhbmQgdGhlIHNwZWNpZmllZCBhbGdvcml0aG0uXG4gKiBAcGFyYW0ge0ludGVnZXJ9IGFsZ28gQWxnb3JpdGhtIHRvIGJlIHVzZWQgKFNlZSBSRkM0ODgwIDkuMSlcbiAqIEBwYXJhbSB7b3BlbnBncF90eXBlX21waVtdfSBwdWJsaWNNUElzIEFsZ29yaXRobSBkZXBlbmRlbnQgbXVsdGlwcmVjaXNpb24gaW50ZWdlcnMgXG4gKiBvZiB0aGUgcHVibGljIGtleSBwYXJ0IG9mIHRoZSBwcml2YXRlIGtleVxuICogQHBhcmFtIHtvcGVucGdwX3R5cGVfbXBpW119IHNlY3JldE1QSXMgQWxnb3JpdGhtIGRlcGVuZGVudCBtdWx0aXByZWNpc2lvbiBpbnRlZ2VycyBcbiAqIG9mIHRoZSBwcml2YXRlIGtleSB1c2VkXG4gKiBAcGFyYW0ge29wZW5wZ3BfdHlwZV9tcGl9IGRhdGEgRGF0YSB0byBiZSBlbmNyeXB0ZWQgYXMgTVBJXG4gKiBAcmV0dXJuIHtvcGVucGdwX3R5cGVfbXBpfSByZXR1cm5zIGEgYmlnIGludGVnZXIgY29udGFpbmluZyB0aGUgZGVjcnlwdGVkIGRhdGE7IG90aGVyd2lzZSBudWxsXG4gKi9cblxucHVibGljS2V5RGVjcnlwdDogZnVuY3Rpb24gKGFsZ28sIGtleUludGVnZXJzLCBkYXRhSW50ZWdlcnMpIHtcblx0dmFyIGJuID0gKGZ1bmN0aW9uKCkge1xuXHRcdHN3aXRjaChhbGdvKSB7XG5cdFx0Y2FzZSAncnNhX2VuY3J5cHRfc2lnbic6XG5cdFx0Y2FzZSAncnNhX2VuY3J5cHQnOlxuXHRcdFx0dmFyIHJzYSA9IG5ldyBwdWJsaWNLZXkucnNhKCk7XG5cdFx0XHQvLyAwIGFuZCAxIGFyZSB0aGUgcHVibGljIGtleS5cblx0XHRcdHZhciBkID0ga2V5SW50ZWdlcnNbMl0udG9CaWdJbnRlZ2VyKCk7XG5cdFx0XHR2YXIgcCA9IGtleUludGVnZXJzWzNdLnRvQmlnSW50ZWdlcigpO1xuXHRcdFx0dmFyIHEgPSBrZXlJbnRlZ2Vyc1s0XS50b0JpZ0ludGVnZXIoKTtcblx0XHRcdHZhciB1ID0ga2V5SW50ZWdlcnNbNV0udG9CaWdJbnRlZ2VyKCk7XG5cdFx0XHR2YXIgbSA9IGRhdGFJbnRlZ2Vyc1swXS50b0JpZ0ludGVnZXIoKTtcblx0XHRcdHJldHVybiByc2EuZGVjcnlwdChtLCBkLCBwLCBxLCB1KTtcblx0XHRjYXNlICdlbGdhbWFsJzpcblx0XHRcdHZhciBlbGdhbWFsID0gbmV3IHB1YmxpY0tleS5lbGdhbWFsKCk7XG5cdFx0XHR2YXIgeCA9IGtleUludGVnZXJzWzNdLnRvQmlnSW50ZWdlcigpO1xuXHRcdFx0dmFyIGMxID0gZGF0YUludGVnZXJzWzBdLnRvQmlnSW50ZWdlcigpO1xuXHRcdFx0dmFyIGMyID0gZGF0YUludGVnZXJzWzFdLnRvQmlnSW50ZWdlcigpO1xuXHRcdFx0dmFyIHAgPSBrZXlJbnRlZ2Vyc1swXS50b0JpZ0ludGVnZXIoKTtcblx0XHRcdHJldHVybiBlbGdhbWFsLmRlY3J5cHQoYzEsYzIscCx4KTtcblx0XHRkZWZhdWx0OlxuXHRcdFx0cmV0dXJuIG51bGw7XG5cdFx0fVxuXHR9KSgpO1xuXG5cdHZhciByZXN1bHQgPSBuZXcgdHlwZV9tcGkoKTtcblx0cmVzdWx0LmZyb21CaWdJbnRlZ2VyKGJuKTtcblx0cmV0dXJuIHJlc3VsdDtcbn0sXG5cbi8qKiBSZXR1cm5zIHRoZSBudW1iZXIgb2YgaW50ZWdlcnMgY29tcHJpc2luZyB0aGUgcHJpdmF0ZSBrZXkgb2YgYW4gYWxnb3JpdGhtXG4gKiBAcGFyYW0ge29wZW5wZ3AucHVibGlja2V5fSBhbGdvIFRoZSBwdWJsaWMga2V5IGFsZ29yaXRobVxuICogQHJldHVybiB7SW50ZWdlcn0gVGhlIG51bWJlciBvZiBpbnRlZ2Vycy5cbiAqL1xuZ2V0UHJpdmF0ZU1waUNvdW50OiBmdW5jdGlvbihhbGdvKSB7XG5cdHN3aXRjaChhbGdvKSB7XG5cdFx0Y2FzZSAncnNhX2VuY3J5cHQnOlxuXHRcdGNhc2UgJ3JzYV9lbmNyeXB0X3NpZ24nOlxuXHRcdGNhc2UgJ3JzYV9zaWduJzpcblx0XHQvLyAgIEFsZ29yaXRobS1TcGVjaWZpYyBGaWVsZHMgZm9yIFJTQSBzZWNyZXQga2V5czpcblx0XHQvLyAgIC0gbXVsdGlwcmVjaXNpb24gaW50ZWdlciAoTVBJKSBvZiBSU0Egc2VjcmV0IGV4cG9uZW50IGQuXG5cdFx0Ly8gICAtIE1QSSBvZiBSU0Egc2VjcmV0IHByaW1lIHZhbHVlIHAuXG5cdFx0Ly8gICAtIE1QSSBvZiBSU0Egc2VjcmV0IHByaW1lIHZhbHVlIHEgKHAgPCBxKS5cblx0XHQvLyAgIC0gTVBJIG9mIHUsIHRoZSBtdWx0aXBsaWNhdGl2ZSBpbnZlcnNlIG9mIHAsIG1vZCBxLlxuXHRcdHJldHVybiA0O1xuXHRjYXNlICdlbGdhbWFsJzpcblx0XHQvLyBBbGdvcml0aG0tU3BlY2lmaWMgRmllbGRzIGZvciBFbGdhbWFsIHNlY3JldCBrZXlzOlxuXHRcdC8vICAgLSBNUEkgb2YgRWxnYW1hbCBzZWNyZXQgZXhwb25lbnQgeC5cblx0XHRyZXR1cm4gMTtcblx0Y2FzZSAnZHNhJzpcblx0XHQvLyBBbGdvcml0aG0tU3BlY2lmaWMgRmllbGRzIGZvciBEU0Egc2VjcmV0IGtleXM6XG5cdFx0Ly8gICAtIE1QSSBvZiBEU0Egc2VjcmV0IGV4cG9uZW50IHguXG5cdFx0cmV0dXJuIDE7XG5cdGRlZmF1bHQ6XG5cdFx0dGhyb3cgbmV3IEVycm9yKCdVbmtub3duIGFsZ29yaXRobScpO1xuXHR9XG59LFxuXHRcbmdldFB1YmxpY01waUNvdW50OiBmdW5jdGlvbihhbGdvKSB7XG5cdC8vIC0gQSBzZXJpZXMgb2YgbXVsdGlwcmVjaXNpb24gaW50ZWdlcnMgY29tcHJpc2luZyB0aGUga2V5IG1hdGVyaWFsOlxuXHQvLyAgIEFsZ29yaXRobS1TcGVjaWZpYyBGaWVsZHMgZm9yIFJTQSBwdWJsaWMga2V5czpcblx0Ly8gICAgICAgLSBhIG11bHRpcHJlY2lzaW9uIGludGVnZXIgKE1QSSkgb2YgUlNBIHB1YmxpYyBtb2R1bHVzIG47XG5cdC8vICAgICAgIC0gYW4gTVBJIG9mIFJTQSBwdWJsaWMgZW5jcnlwdGlvbiBleHBvbmVudCBlLlxuXHRzd2l0Y2goYWxnbykge1xuXHRcdGNhc2UgJ3JzYV9lbmNyeXB0Jzpcblx0XHRjYXNlICdyc2FfZW5jcnlwdF9zaWduJzpcblx0XHRjYXNlICdyc2Ffc2lnbic6XG5cdFx0cmV0dXJuIDI7XG5cblx0Ly8gICBBbGdvcml0aG0tU3BlY2lmaWMgRmllbGRzIGZvciBFbGdhbWFsIHB1YmxpYyBrZXlzOlxuXHQvLyAgICAgLSBNUEkgb2YgRWxnYW1hbCBwcmltZSBwO1xuXHQvLyAgICAgLSBNUEkgb2YgRWxnYW1hbCBncm91cCBnZW5lcmF0b3IgZztcblx0Ly8gICAgIC0gTVBJIG9mIEVsZ2FtYWwgcHVibGljIGtleSB2YWx1ZSB5ICg9IGcqKnggbW9kIHAgd2hlcmUgeCAgaXMgc2VjcmV0KS5cblx0XHRjYXNlICdlbGdhbWFsJzpcblx0XHRyZXR1cm4gMztcblxuXHQvLyAgIEFsZ29yaXRobS1TcGVjaWZpYyBGaWVsZHMgZm9yIERTQSBwdWJsaWMga2V5czpcblx0Ly8gICAgICAgLSBNUEkgb2YgRFNBIHByaW1lIHA7XG5cdC8vICAgICAgIC0gTVBJIG9mIERTQSBncm91cCBvcmRlciBxIChxIGlzIGEgcHJpbWUgZGl2aXNvciBvZiBwLTEpO1xuXHQvLyAgICAgICAtIE1QSSBvZiBEU0EgZ3JvdXAgZ2VuZXJhdG9yIGc7XG5cdC8vICAgICAgIC0gTVBJIG9mIERTQSBwdWJsaWMta2V5IHZhbHVlIHkgKD0gZyoqeCBtb2QgcCB3aGVyZSB4ICBpcyBzZWNyZXQpLlxuXHRcdGNhc2UgJ2RzYSc6XG5cdFx0cmV0dXJuIDQ7XG5cblx0XHRkZWZhdWx0OlxuXHRcdFx0dGhyb3cgbmV3IEVycm9yKCdVbmtub3duIGFsZ29yaXRobS4nKTtcblx0fVxufSxcblxuXG4vKipcbiAqIGdlbmVyYXRlIHJhbmRvbSBieXRlIHByZWZpeCBhcyBzdHJpbmcgZm9yIHRoZSBzcGVjaWZpZWQgYWxnb3JpdGhtXG4gKiBAcGFyYW0ge0ludGVnZXJ9IGFsZ28gQWxnb3JpdGhtIHRvIHVzZSAoc2VlIFJGQzQ4ODAgOS4yKVxuICogQHJldHVybiB7U3RyaW5nfSBSYW5kb20gYnl0ZXMgd2l0aCBsZW5ndGggZXF1YWwgdG8gdGhlIGJsb2NrXG4gKiBzaXplIG9mIHRoZSBjaXBoZXJcbiAqL1xuZ2V0UHJlZml4UmFuZG9tOiBmdW5jdGlvbihhbGdvKSB7XG5cdHJldHVybiByYW5kb20uZ2V0UmFuZG9tQnl0ZXModGhpcy5nZXRCbG9ja0xlbmd0aChhbGdvKSk7XG59LFxuXG4vKipcbiAqIHJldHJpZXZlIHRoZSBNREMgcHJlZml4ZWQgYnl0ZXMgYnkgZGVjcnlwdGluZyB0aGVtXG4gKiBAcGFyYW0ge0ludGVnZXJ9IGFsZ28gQWxnb3JpdGhtIHRvIHVzZSAoc2VlIFJGQzQ4ODAgOS4yKVxuICogQHBhcmFtIHtTdHJpbmd9IGtleSBLZXkgYXMgc3RyaW5nLiBsZW5ndGggaXMgZGVwZW5kaW5nIG9uIHRoZSBhbGdvcml0aG0gdXNlZFxuICogQHBhcmFtIHtTdHJpbmd9IGRhdGEgRW5jcnlwdGVkIGRhdGEgd2hlcmUgdGhlIHByZWZpeCBpcyBkZWNyeXB0ZWQgZnJvbVxuICogQHJldHVybiB7U3RyaW5nfSBQbGFpbiB0ZXh0IGRhdGEgb2YgdGhlIHByZWZpeGVkIGRhdGFcbiAqL1xuTURDU3lzdGVtQnl0ZXM6IGZ1bmN0aW9uKGFsZ28sIGtleSwgZGF0YSkge1xuXG5cdHN3aXRjaChhbGdvKSB7XG5cdGNhc2UgJ3BsYWludGV4dCc6IC8vIFBsYWludGV4dCBvciB1bmVuY3J5cHRlZCBkYXRhXG5cdFx0cmV0dXJuIGRhdGE7XG5cdGNhc2UgJ2Rlcyc6IC8vIFRyaXBsZURFUyAoREVTLUVERSwgW1NDSE5FSUVSXSBbSEFDXSAtIDE2OCBiaXQga2V5IGRlcml2ZWQgZnJvbSAxOTIpXG5cdFx0cmV0dXJuIGNmYi5tZGMoY2lwaGVyLmRlcywgOCwga2V5LCBkYXRhKTtcblx0Y2FzZSAnY2FzdDUnOiAvLyBDQVNUNSAoMTI4IGJpdCBrZXksIGFzIHBlciBbUkZDMjE0NF0pXG5cdFx0cmV0dXJuIGNmYi5tZGMoY2lwaGVyLmNhc3Q1LCA4LCBrZXksIGRhdGEpO1xuXHRjYXNlICdibG93ZmlzaCc6IC8vIEJsb3dmaXNoICgxMjggYml0IGtleSwgMTYgcm91bmRzKSBbQkxPV0ZJU0hdXG5cdFx0cmV0dXJuIGNmYi5tZGMoY2lwaGVyLmJsb3dmaXNoLCA4LCBrZXksIGRhdGEpO1xuXHRjYXNlICdhZXMxMjgnOiAvLyBBRVMgd2l0aCAxMjgtYml0IGtleSBbQUVTXVxuXHRjYXNlICdhZXMxOTInOiAvLyBBRVMgd2l0aCAxOTItYml0IGtleVxuXHRjYXNlICdhZXMyNTYnOiAvLyBBRVMgd2l0aCAyNTYtYml0IGtleVxuXHRcdHJldHVybiBjZmIubWRjKGNpcGhlci5hZXMuZW5jcnlwdCwgMTYsIGNpcGhlci5hZXMua2V5RXhwYW5zaW9uKGtleSksIGRhdGEpO1xuXHRjYXNlICd0d29maXNoJzogXG5cdFx0cmV0dXJuIGNmYi5tZGMoY2lwaGVyLnR3b2Zpc2gsIDE2LCBrZXksIGRhdGEpO1xuXHRjYXNlICdpZGVhJzogLy8gSURFQSBbSURFQV1cblx0XHR0aHJvdyBuZXcgRXJyb3IoJ0lERUEgQWxnb3JpdGhtIG5vdCBpbXBsZW1lbnRlZCcpO1xuXHRkZWZhdWx0OlxuXHRcdHRocm93IG5ldyBFcnJvcignSW52YWxpZCBhbGdvcml0aG0uJyk7XG5cdH1cbn0sXG4vKipcbiAqIEdlbmVyYXRpbmcgYSBzZXNzaW9uIGtleSBmb3IgdGhlIHNwZWNpZmllZCBzeW1tZXRyaWMgYWxnb3JpdGhtXG4gKiBAcGFyYW0ge0ludGVnZXJ9IGFsZ28gQWxnb3JpdGhtIHRvIHVzZSAoc2VlIFJGQzQ4ODAgOS4yKVxuICogQHJldHVybiB7U3RyaW5nfSBSYW5kb20gYnl0ZXMgYXMgYSBzdHJpbmcgdG8gYmUgdXNlZCBhcyBhIGtleVxuICovXG5nZW5lcmF0ZVNlc3Npb25LZXk6IGZ1bmN0aW9uKGFsZ28pIHtcblx0cmV0dXJuIHJhbmRvbS5nZXRSYW5kb21CeXRlcyh0aGlzLmdldEtleUxlbmd0aChhbGdvKSk7IFxufSxcblxuLyoqXG4gKiBHZXQgdGhlIGtleSBsZW5ndGggYnkgc3ltbWV0cmljIGFsZ29yaXRobSBpZC5cbiAqIEBwYXJhbSB7SW50ZWdlcn0gYWxnbyBBbGdvcml0aG0gdG8gdXNlIChzZWUgUkZDNDg4MCA5LjIpXG4gKiBAcmV0dXJuIHtTdHJpbmd9IFJhbmRvbSBieXRlcyBhcyBhIHN0cmluZyB0byBiZSB1c2VkIGFzIGEga2V5XG4gKi9cbmdldEtleUxlbmd0aDogZnVuY3Rpb24oYWxnbykge1xuXHRzd2l0Y2ggKGFsZ28pIHtcblx0Y2FzZSAnZGVzJzogLy8gVHJpcGxlREVTIChERVMtRURFLCBbU0NITkVJRVJdIFtIQUNdIC0gMTY4IGJpdCBrZXkgZGVyaXZlZCBmcm9tIDE5Milcblx0Y2FzZSAnYWVzMTkyJzogLy8gQUVTIHdpdGggMTkyLWJpdCBrZXlcblx0XHRyZXR1cm4gMjQ7XG5cdGNhc2UgJ2Nhc3Q1JzogLy8gQ0FTVDUgKDEyOCBiaXQga2V5LCBhcyBwZXIgW1JGQzIxNDRdKVxuXHRjYXNlICdibG93ZmlzaCc6IC8vIEJsb3dmaXNoICgxMjggYml0IGtleSwgMTYgcm91bmRzKSBbQkxPV0ZJU0hdXG5cdGNhc2UgJ2FlczEyOCc6IC8vIEFFUyB3aXRoIDEyOC1iaXQga2V5IFtBRVNdXG5cdFx0cmV0dXJuIDE2O1xuXHRjYXNlICdhZXMyNTYnOiAvLyBBRVMgd2l0aCAyNTYtYml0IGtleVxuXHRjYXNlICd0d29maXNoJzovLyBUd29maXNoIHdpdGggMjU2LWJpdCBrZXkgW1RXT0ZJU0hdXG5cdFx0cmV0dXJuIDMyO1xuXHRkZWZhdWx0OlxuXHRcdHRocm93IG5ldyBFcnJvcignSW52YWxpZCBhbGdvcml0aG0uJyk7XG5cdH1cbn0sXG5cbi8qKlxuICogUmV0dXJucyB0aGUgYmxvY2sgbGVuZ3RoIG9mIHRoZSBzcGVjaWZpZWQgc3ltbWV0cmljIGVuY3J5cHRpb24gYWxnb3JpdGhtXG4gKiBAcGFyYW0ge29wZW5wZ3Auc3ltbWV0cmljfSBhbGdvIFN5bW1ldHJpYyBhbGdvcml0aG0gaWRlbmhpZmllclxuICogQHJldHVybiB7SW50ZWdlcn0gVGhlIG51bWJlciBvZiBieXRlcyBpbiBhIHNpbmdsZSBibG9jayBlbmNyeXB0ZWQgYnkgdGhlIGFsZ29yaXRobVxuICovXG5nZXRCbG9ja0xlbmd0aDogZnVuY3Rpb24oYWxnbykge1xuXHRzd2l0Y2ggKGFsZ28pIHtcblx0Y2FzZSAnZGVzJzpcblx0Y2FzZSAnY2FzdDUnOlxuXHRcdHJldHVybiA4O1xuXHRjYXNlICdibG93ZmlzaCc6XG5cdGNhc2UgJ2FlczEyOCc6XG5cdGNhc2UgJ2FlczE5Mic6XG5cdGNhc2UgJ2FlczI1Nic6XG5cdFx0cmV0dXJuIDE2O1xuXHRjYXNlICd0d29maXNoJzpcblx0XHRyZXR1cm4gMzI7XHQgICAgXHRcdFxuXHRkZWZhdWx0OlxuXHRcdHRocm93IG5ldyBFcnJvcignSW52YWxpZCBhbGdvcml0aG0uJyk7XG5cdH1cbn0sXG5cbi8qKlxuICogQ3JlYXRlIGEgc2VjdXJlIHJhbmRvbSBiaWcgaW50ZWdlciBvZiBiaXRzIGxlbmd0aFxuICogQHBhcmFtIHtJbnRlZ2VyfSBiaXRzIEJpdCBsZW5ndGggb2YgdGhlIE1QSSB0byBjcmVhdGVcbiAqIEByZXR1cm4ge0JpZ0ludGVnZXJ9IFJlc3VsdGluZyBiaWcgaW50ZWdlclxuICovXG5nZXRSYW5kb21CaWdJbnRlZ2VyOiBmdW5jdGlvbihiaXRzKSB7XG5cdGlmIChiaXRzIDwgMClcblx0ICAgcmV0dXJuIG51bGw7XG5cdHZhciBudW1CeXRlcyA9IE1hdGguZmxvb3IoKGJpdHMrNykvOCk7XG5cblx0dmFyIHJhbmRvbUJpdHMgPSByYW5kb20uZ2V0UmFuZG9tQnl0ZXMobnVtQnl0ZXMpO1xuXHRpZiAoYml0cyAlIDggPiAwKSB7XG5cdFx0XG5cdFx0cmFuZG9tQml0cyA9IFN0cmluZy5mcm9tQ2hhckNvZGUoXG5cdFx0XHRcdFx0XHQoTWF0aC5wb3coMixiaXRzICUgOCktMSkgJlxuXHRcdFx0XHRcdFx0cmFuZG9tQml0cy5jaGFyQ29kZUF0KDApKSArXG5cdFx0XHRyYW5kb21CaXRzLnN1YnN0cmluZygxKTtcblx0fVxuXHRyZXR1cm4gbmV3IHR5cGVfbXBpKCkuY3JlYXRlKHJhbmRvbUJpdHMpLnRvQmlnSW50ZWdlcigpO1xufSxcblxuZ2V0UmFuZG9tQmlnSW50ZWdlckluUmFuZ2U6IGZ1bmN0aW9uKG1pbiwgbWF4KSB7XG5cdGlmIChtYXguY29tcGFyZVRvKG1pbikgPD0gMClcblx0XHRyZXR1cm47XG5cblx0dmFyIHJhbmdlID0gbWF4LnN1YnRyYWN0KG1pbik7XG5cdHZhciByID0gdGhpcy5nZXRSYW5kb21CaWdJbnRlZ2VyKHJhbmdlLmJpdExlbmd0aCgpKTtcblx0d2hpbGUgKHIgPiByYW5nZSkge1xuXHRcdHIgPSB0aGlzLmdldFJhbmRvbUJpZ0ludGVnZXIocmFuZ2UuYml0TGVuZ3RoKCkpO1xuXHR9XG5cdHJldHVybiBtaW4uYWRkKHIpO1xufSxcblxufVxuIiwiLy8gR1BHNEJyb3dzZXJzIC0gQW4gT3BlblBHUCBpbXBsZW1lbnRhdGlvbiBpbiBqYXZhc2NyaXB0XG4vLyBDb3B5cmlnaHQgKEMpIDIwMTEgUmVjdXJpdHkgTGFicyBHbWJIXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3Jcbi8vIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlclxuLy8gdmVyc2lvbiAyLjEgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuLy8gYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2Zcbi8vIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUgR05VXG4vLyBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuLy8gXG4vLyBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFsb25nIHdpdGggdGhpcyBsaWJyYXJ5OyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlXG4vLyBGb3VuZGF0aW9uLCBJbmMuLCA1MSBGcmFua2xpbiBTdHJlZXQsIEZpZnRoIEZsb29yLCBCb3N0b24sIE1BICAwMjExMC0xMzAxICBVU0FcblxudmFyIGVudW1zID0gcmVxdWlyZSgnLi4vZW51bXMuanMnKSxcblx0SlhHID0gcmVxdWlyZSgnLi4vY29tcHJlc3Npb24vanhnLmpzJyksXG5cdGJhc2U2NCA9IHJlcXVpcmUoJy4uL2VuY29kaW5nL2Jhc2U2NC5qcycpO1xuXG4vKipcbiAqIEBjbGFzc1xuICogQGNsYXNzZGVzYyBJbXBsZW1lbnRhdGlvbiBvZiB0aGUgQ29tcHJlc3NlZCBEYXRhIFBhY2tldCAoVGFnIDgpXG4gKiBcbiAqIFJGQzQ4ODAgNS42OlxuICogVGhlIENvbXByZXNzZWQgRGF0YSBwYWNrZXQgY29udGFpbnMgY29tcHJlc3NlZCBkYXRhLiAgVHlwaWNhbGx5LCB0aGlzXG4gKiBwYWNrZXQgaXMgZm91bmQgYXMgdGhlIGNvbnRlbnRzIG9mIGFuIGVuY3J5cHRlZCBwYWNrZXQsIG9yIGZvbGxvd2luZ1xuICogYSBTaWduYXR1cmUgb3IgT25lLVBhc3MgU2lnbmF0dXJlIHBhY2tldCwgYW5kIGNvbnRhaW5zIGEgbGl0ZXJhbCBkYXRhXG4gKiBwYWNrZXQuXG4gKi8gICBcbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gcGFja2V0X2NvbXByZXNzZWQoKSB7XG5cdC8qKiBAdHlwZSB7cGFja2V0bGlzdH0gKi9cblx0dGhpcy5wYWNrZXRzO1xuXHQvKiogQHR5cGUge2NvbXByZXNzaW9ufSAqL1xuXHR0aGlzLmFsZ29yaXRobSA9ICd1bmNvbXByZXNzZWQnO1xuXG5cdHRoaXMuY29tcHJlc3NlZCA9IG51bGw7XG5cblx0XG5cdC8qKlxuXHQgKiBQYXJzaW5nIGZ1bmN0aW9uIGZvciB0aGUgcGFja2V0LlxuXHQgKiBAcGFyYW0ge1N0cmluZ30gaW5wdXQgUGF5bG9hZCBvZiBhIHRhZyA4IHBhY2tldFxuXHQgKiBAcGFyYW0ge0ludGVnZXJ9IHBvc2l0aW9uIFBvc2l0aW9uIHRvIHN0YXJ0IHJlYWRpbmcgZnJvbSB0aGUgaW5wdXQgc3RyaW5nXG5cdCAqIEBwYXJBTSB7aU5URUdFUn0gTEVOIGxFTkdUSCBPRiB0aGUgcGFja2V0IG9yIHRoZSByZW1haW5pbmcgbGVuZ3RoIG9mIFxuXHQgKiBpbnB1dCBhdCBwb3NpdGlvblxuXHQgKiBAcmV0dXJuIHtvcGVucGdwX3BhY2tldF9jb21wcmVzc2VkfSBPYmplY3QgcmVwcmVzZW50YXRpb25cblx0ICovXG5cdHRoaXMucmVhZCA9IGZ1bmN0aW9uKGJ5dGVzKSB7XG5cdFx0Ly8gT25lIG9jdGV0IHRoYXQgZ2l2ZXMgdGhlIGFsZ29yaXRobSB1c2VkIHRvIGNvbXByZXNzIHRoZSBwYWNrZXQuXG5cdFx0dGhpcy5hbGdvcml0aG0gPSBlbnVtcy5yZWFkKGVudW1zLmNvbXByZXNzaW9uLCBieXRlcy5jaGFyQ29kZUF0KDApKTtcblxuXHRcdC8vIENvbXByZXNzZWQgZGF0YSwgd2hpY2ggbWFrZXMgdXAgdGhlIHJlbWFpbmRlciBvZiB0aGUgcGFja2V0LlxuXHRcdHRoaXMuY29tcHJlc3NlZCA9IGJ5dGVzLnN1YnN0cigxKTtcblxuXHRcdHRoaXMuZGVjb21wcmVzcygpO1xuXHR9XG5cblx0XG5cdFxuXHR0aGlzLndyaXRlID0gZnVuY3Rpb24oKSB7XG5cdFx0aWYodGhpcy5jb21wcmVzc2VkID09IG51bGwpXG5cdFx0XHR0aGlzLmNvbXByZXNzKCk7XG5cblx0XHRyZXR1cm4gU3RyaW5nLmZyb21DaGFyQ29kZShlbnVtcy53cml0ZShlbnVtcy5jb21wcmVzc2lvbiwgdGhpcy5hbGdvcml0aG0pKSBcblx0XHRcdCsgdGhpcy5jb21wcmVzc2VkO1xuXHR9XG5cblxuXHQvKipcblx0ICogRGVjb21wcmVzc2lvbiBtZXRob2QgZm9yIGRlY29tcHJlc3NpbmcgdGhlIGNvbXByZXNzZWQgZGF0YVxuXHQgKiByZWFkIGJ5IHJlYWRfcGFja2V0XG5cdCAqIEByZXR1cm4ge1N0cmluZ30gVGhlIGRlY29tcHJlc3NlZCBkYXRhXG5cdCAqL1xuXHR0aGlzLmRlY29tcHJlc3MgPSBmdW5jdGlvbigpIHtcblx0XHR2YXIgZGVjb21wcmVzc2VkO1xuXG5cdFx0c3dpdGNoICh0aGlzLmFsZ29yaXRobSkge1xuXHRcdGNhc2UgJ3VuY29tcHJlc3NlZCc6XG5cdFx0XHRkZWNvbXByZXNzZWQgPSB0aGlzLmNvbXByZXNzZWQ7XG5cdFx0XHRicmVhaztcblxuXHRcdGNhc2UgJ3ppcCc6XG5cdFx0XHR2YXIgY29tcERhdGEgPSB0aGlzLmNvbXByZXNzZWQ7XG5cblx0XHRcdHZhciByYWRpeCA9IGJhc2U2NC5lbmNvZGUoY29tcERhdGEpLnJlcGxhY2UoL1xcbi9nLFwiXCIpO1xuXHRcdFx0Ly8gbm8gaGVhZGVyIGluIHRoaXMgY2FzZSwgZGlyZWN0bHkgY2FsbCBkZWZsYXRlXG5cdFx0XHR2YXIganhnX29iaiA9IG5ldyBKWEcuVXRpbC5VbnppcChKWEcuVXRpbC5CYXNlNjQuZGVjb2RlQXNBcnJheShyYWRpeCkpO1xuXG5cdFx0XHRkZWNvbXByZXNzZWQgPSB1bmVzY2FwZShqeGdfb2JqLmRlZmxhdGUoKVswXVswXSk7XG5cdFx0XHRicmVhaztcblxuXHRcdGNhc2UgJ3psaWInOlxuXHRcdFx0Ly9SRkMgMTk1MC4gQml0cyAwLTMgQ29tcHJlc3Npb24gTWV0aG9kXG5cdFx0XHR2YXIgY29tcHJlc3Npb25NZXRob2QgPSB0aGlzLmNvbXByZXNzZWQuY2hhckNvZGVBdCgwKSAlIDB4MTA7XG5cblx0XHRcdC8vQml0cyA0LTcgUkZDIDE5NTAgYXJlIExaNzcgV2luZG93LiBHZW5lcmFsbHkgdGhpcyB2YWx1ZSBpcyA3ID09IDMyayB3aW5kb3cgc2l6ZS5cblx0XHRcdC8vIDJuZCBCeXRlIGluIFJGQyAxOTUwIGlzIGZvciBcIkZMQUdzXCIgQWxsb3dzIGZvciBhIERpY3Rpb25hcnkgXG5cdFx0XHQvLyAoaG93IGlzIHRoaXMgZGVmaW5lZCkuIEJhc2ljIGNoZWNrc3VtLCBhbmQgY29tcHJlc3Npb24gbGV2ZWwuXG5cblx0XHRcdGlmIChjb21wcmVzc2lvbk1ldGhvZCA9PSA4KSB7IC8vQ00gOCBpcyBmb3IgREVGTEFURSwgUkZDIDE5NTFcblx0XHRcdFx0Ly8gcmVtb3ZlIDQgYnl0ZXMgQURMRVIzMiBjaGVja3N1bSBmcm9tIHRoZSBlbmRcblx0XHRcdFx0dmFyIGNvbXBEYXRhID0gdGhpcy5jb21wcmVzc2VkLnN1YnN0cmluZygwLCB0aGlzLmNvbXByZXNzZWQubGVuZ3RoIC0gNCk7XG5cdFx0XHRcdHZhciByYWRpeCA9IGJhc2U2NC5lbmNvZGUoY29tcERhdGEpLnJlcGxhY2UoL1xcbi9nLFwiXCIpO1xuXHRcdFx0XHQvL1RPRE8gY2hlY2sgQURMRVIzMiBjaGVja3N1bVxuXHRcdFx0XHRkZWNvbXByZXNzZWQgPSBKWEcuZGVjb21wcmVzcyhyYWRpeCk7XG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHR1dGlsLnByaW50X2Vycm9yKFwiQ29tcHJlc3Npb24gYWxnb3JpdGhtIFpMSUIgb25seSBzdXBwb3J0cyBcIiArXG5cdFx0XHRcdFx0XCJERUZMQVRFIGNvbXByZXNzaW9uIG1ldGhvZC5cIik7XG5cdFx0XHR9XG5cdFx0XHRicmVhaztcblxuXHRcdGNhc2UgJ2J6aXAyJzpcblx0XHRcdC8vIFRPRE86IG5lZWQgdG8gaW1wbGVtZW50IHRoaXNcblx0XHRcdHRocm93IG5ldyBFcnJvcignQ29tcHJlc3Npb24gYWxnb3JpdGhtIEJaaXAyIFtCWjJdIGlzIG5vdCBpbXBsZW1lbnRlZC4nKTtcblx0XHRcdGJyZWFrO1xuXG5cdFx0ZGVmYXVsdDpcblx0XHRcdHRocm93IG5ldyBFcnJvcihcIkNvbXByZXNzaW9uIGFsZ29yaXRobSB1bmtub3duIDpcIiArIHRoaXMuYWxvZ3JpdGhtKTtcblx0XHRcdGJyZWFrO1xuXHRcdH1cblxuXHRcdHRoaXMucGFja2V0cy5yZWFkKGRlY29tcHJlc3NlZCk7XG5cdH1cblxuXHQvKipcblx0ICogQ29tcHJlc3MgdGhlIHBhY2tldCBkYXRhIChtZW1iZXIgZGVjb21wcmVzc2VkRGF0YSlcblx0ICogQHBhcmFtIHtJbnRlZ2VyfSB0eXBlIEFsZ29yaXRobSB0byBiZSB1c2VkIC8vIFNlZSBSRkMgNDg4MCA5LjNcblx0ICogQHBhcmFtIHtTdHJpbmd9IGRhdGEgRGF0YSB0byBiZSBjb21wcmVzc2VkXG5cdCAqIEByZXR1cm4ge1N0cmluZ30gVGhlIGNvbXByZXNzZWQgZGF0YSBzdG9yZWQgaW4gYXR0cmlidXRlIGNvbXByZXNzZWREYXRhXG5cdCAqL1xuXHR0aGlzLmNvbXByZXNzID0gZnVuY3Rpb24oKSB7XG5cdFx0c3dpdGNoICh0aGlzLmFsZ29yaXRobSkge1xuXG5cdFx0Y2FzZSAndW5jb21wcmVzc2VkJzogLy8gLSBVbmNvbXByZXNzZWRcblx0XHRcdHRoaXMuY29tcHJlc3NlZCA9IHRoaXMucGFja2V0cy53cml0ZSgpO1xuXHRcdFx0YnJlYWs7XG5cblx0XHRjYXNlICd6aXAnOiAvLyAtIFpJUCBbUkZDMTk1MV1cblx0XHRcdHV0aWwucHJpbnRfZXJyb3IoXCJDb21wcmVzc2lvbiBhbGdvcml0aG0gWklQIFtSRkMxOTUxXSBpcyBub3QgaW1wbGVtZW50ZWQuXCIpO1xuXHRcdFx0YnJlYWs7XG5cblx0XHRjYXNlICd6bGliJzogLy8gLSBaTElCIFtSRkMxOTUwXVxuXHRcdFx0Ly8gVE9ETzogbmVlZCB0byBpbXBsZW1lbnQgdGhpc1xuXHRcdFx0dXRpbC5wcmludF9lcnJvcihcIkNvbXByZXNzaW9uIGFsZ29yaXRobSBaTElCIFtSRkMxOTUwXSBpcyBub3QgaW1wbGVtZW50ZWQuXCIpO1xuXHRcdFx0YnJlYWs7XG5cblx0XHRjYXNlICdiemlwMic6IC8vICAtIEJaaXAyIFtCWjJdXG5cdFx0XHQvLyBUT0RPOiBuZWVkIHRvIGltcGxlbWVudCB0aGlzXG5cdFx0XHR1dGlsLnByaW50X2Vycm9yKFwiQ29tcHJlc3Npb24gYWxnb3JpdGhtIEJaaXAyIFtCWjJdIGlzIG5vdCBpbXBsZW1lbnRlZC5cIik7XG5cdFx0XHRicmVhaztcblxuXHRcdGRlZmF1bHQ6XG5cdFx0XHR1dGlsLnByaW50X2Vycm9yKFwiQ29tcHJlc3Npb24gYWxnb3JpdGhtIHVua25vd24gOlwiK3RoaXMudHlwZSk7XG5cdFx0XHRicmVhaztcblx0XHR9XG5cdH1cbn07XG4iLCIvLyBHUEc0QnJvd3NlcnMgLSBBbiBPcGVuUEdQIGltcGxlbWVudGF0aW9uIGluIGphdmFzY3JpcHRcbi8vIENvcHlyaWdodCAoQykgMjAxMSBSZWN1cml0eSBMYWJzIEdtYkhcbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vclxuLy8gbW9kaWZ5IGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyXG4vLyB2ZXJzaW9uIDIuMSBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4vLyBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuLy8gTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZSBHTlVcbi8vIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG4vLyBcbi8vIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYWxvbmcgd2l0aCB0aGlzIGxpYnJhcnk7IGlmIG5vdCwgd3JpdGUgdG8gdGhlIEZyZWUgU29mdHdhcmVcbi8vIEZvdW5kYXRpb24sIEluYy4sIDUxIEZyYW5rbGluIFN0cmVldCwgRmlmdGggRmxvb3IsIEJvc3RvbiwgTUEgIDAyMTEwLTEzMDEgIFVTQVxuXG52YXIgcHVibGljX2tleSA9IHJlcXVpcmUoJy4vcHVibGljX2tleS5qcycpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIHB1YmxpY19zdWJrZXkoKSB7XG5cdHB1YmxpY19rZXkuY2FsbCh0aGlzKTtcbn1cbiIsIi8vIEdQRzRCcm93c2VycyAtIEFuIE9wZW5QR1AgaW1wbGVtZW50YXRpb24gaW4gamF2YXNjcmlwdFxuLy8gQ29weXJpZ2h0IChDKSAyMDExIFJlY3VyaXR5IExhYnMgR21iSFxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yXG4vLyBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uOyBlaXRoZXJcbi8vIHZlcnNpb24gMi4xIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbi8vIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4vLyBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlIEdOVVxuLy8gTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cbi8vIFxuLy8gWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhbG9uZyB3aXRoIHRoaXMgbGlicmFyeTsgaWYgbm90LCB3cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZVxuLy8gRm91bmRhdGlvbiwgSW5jLiwgNTEgRnJhbmtsaW4gU3RyZWV0LCBGaWZ0aCBGbG9vciwgQm9zdG9uLCBNQSAgMDIxMTAtMTMwMSAgVVNBXG5cbi8qKlxuICogQGNsYXNzXG4gKiBAY2xhc3NkZXNjIEltcGxlbWVudGF0aW9uIG9mIHRoZSBPbmUtUGFzcyBTaWduYXR1cmUgUGFja2V0cyAoVGFnIDQpXG4gKiBcbiAqIFJGQzQ4ODAgNS40OlxuICogVGhlIE9uZS1QYXNzIFNpZ25hdHVyZSBwYWNrZXQgcHJlY2VkZXMgdGhlIHNpZ25lZCBkYXRhIGFuZCBjb250YWluc1xuICogZW5vdWdoIGluZm9ybWF0aW9uIHRvIGFsbG93IHRoZSByZWNlaXZlciB0byBiZWdpbiBjYWxjdWxhdGluZyBhbnlcbiAqIGhhc2hlcyBuZWVkZWQgdG8gdmVyaWZ5IHRoZSBzaWduYXR1cmUuICBJdCBhbGxvd3MgdGhlIFNpZ25hdHVyZVxuICogcGFja2V0IHRvIGJlIHBsYWNlZCBhdCB0aGUgZW5kIG9mIHRoZSBtZXNzYWdlLCBzbyB0aGF0IHRoZSBzaWduZXJcbiAqIGNhbiBjb21wdXRlIHRoZSBlbnRpcmUgc2lnbmVkIG1lc3NhZ2UgaW4gb25lIHBhc3MuXG4gKi9cblxudmFyIGVudW1zID0gcmVxdWlyZSgnLi4vZW51bXMuanMnKSxcblx0dHlwZV9rZXlpZCA9IHJlcXVpcmUoJy4uL3R5cGUva2V5aWQuanMnKTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiBwYWNrZXRfb25lX3Bhc3Nfc2lnbmF0dXJlKCkge1xuXHR0aGlzLnZlcnNpb24gPSBudWxsOyAvLyBBIG9uZS1vY3RldCB2ZXJzaW9uIG51bWJlci4gIFRoZSBjdXJyZW50IHZlcnNpb24gaXMgMy5cblx0dGhpcy50eXBlID0gbnVsbDsgXHQgLy8gQSBvbmUtb2N0ZXQgc2lnbmF0dXJlIHR5cGUuICBTaWduYXR1cmUgdHlwZXMgYXJlIGRlc2NyaWJlZCBpbiBSRkM0ODgwIFNlY3Rpb24gNS4yLjEuXG5cdHRoaXMuaGFzaEFsZ29yaXRobSA9IG51bGw7IFx0ICAgLy8gQSBvbmUtb2N0ZXQgbnVtYmVyIGRlc2NyaWJpbmcgdGhlIGhhc2ggYWxnb3JpdGhtIHVzZWQuIChTZWUgUkZDNDg4MCA5LjQpXG5cdHRoaXMucHVibGljS2V5QWxnb3JpdGhtID0gbnVsbDtcdCAgICAgLy8gQSBvbmUtb2N0ZXQgbnVtYmVyIGRlc2NyaWJpbmcgdGhlIHB1YmxpYy1rZXkgYWxnb3JpdGhtIHVzZWQuIChTZWUgUkZDNDg4MCA5LjEpXG5cdHRoaXMuc2lnbmluZ0tleUlkID0gbnVsbDsgLy8gQW4gZWlnaHQtb2N0ZXQgbnVtYmVyIGhvbGRpbmcgdGhlIEtleSBJRCBvZiB0aGUgc2lnbmluZyBrZXkuXG5cdHRoaXMuZmxhZ3MgPSBudWxsOyBcdC8vICBBIG9uZS1vY3RldCBudW1iZXIgaG9sZGluZyBhIGZsYWcgc2hvd2luZyB3aGV0aGVyIHRoZSBzaWduYXR1cmUgaXMgbmVzdGVkLiAgQSB6ZXJvIHZhbHVlIGluZGljYXRlcyB0aGF0IHRoZSBuZXh0IHBhY2tldCBpcyBhbm90aGVyIE9uZS1QYXNzIFNpZ25hdHVyZSBwYWNrZXQgdGhhdCBkZXNjcmliZXMgYW5vdGhlciBzaWduYXR1cmUgdG8gYmUgYXBwbGllZCB0byB0aGUgc2FtZSBtZXNzYWdlIGRhdGEuXG5cblx0LyoqXG5cdCAqIHBhcnNpbmcgZnVuY3Rpb24gZm9yIGEgb25lLXBhc3Mgc2lnbmF0dXJlIHBhY2tldCAodGFnIDQpLlxuXHQgKiBAcGFyYW0ge1N0cmluZ30gYnl0ZXMgcGF5bG9hZCBvZiBhIHRhZyA0IHBhY2tldFxuXHQgKiBAcGFyYW0ge0ludGVnZXJ9IHBvc2l0aW9uIHBvc2l0aW9uIHRvIHN0YXJ0IHJlYWRpbmcgZnJvbSB0aGUgYnl0ZXMgc3RyaW5nXG5cdCAqIEBwYXJhbSB7SW50ZWdlcn0gbGVuIGxlbmd0aCBvZiB0aGUgcGFja2V0IG9yIHRoZSByZW1haW5pbmcgbGVuZ3RoIG9mIGJ5dGVzIGF0IHBvc2l0aW9uXG5cdCAqIEByZXR1cm4ge29wZW5wZ3BfcGFja2V0X2VuY3J5cHRlZGRhdGF9IG9iamVjdCByZXByZXNlbnRhdGlvblxuXHQgKi9cblx0dGhpcy5yZWFkID0gZnVuY3Rpb24oYnl0ZXMpIHtcblx0XHR2YXIgbXlwb3MgPSAwO1xuXHRcdC8vIEEgb25lLW9jdGV0IHZlcnNpb24gbnVtYmVyLiAgVGhlIGN1cnJlbnQgdmVyc2lvbiBpcyAzLlxuXHRcdHRoaXMudmVyc2lvbiA9IGJ5dGVzLmNoYXJDb2RlQXQobXlwb3MrKyk7XG5cblx0ICAgICAvLyBBIG9uZS1vY3RldCBzaWduYXR1cmUgdHlwZS4gIFNpZ25hdHVyZSB0eXBlcyBhcmUgZGVzY3JpYmVkIGluXG5cdCAgICAgLy8gICBTZWN0aW9uIDUuMi4xLlxuXHRcdHRoaXMudHlwZSA9IGVudW1zLnJlYWQoZW51bXMuc2lnbmF0dXJlLCBieXRlcy5jaGFyQ29kZUF0KG15cG9zKyspKTtcblxuXHQgICAgIC8vIEEgb25lLW9jdGV0IG51bWJlciBkZXNjcmliaW5nIHRoZSBoYXNoIGFsZ29yaXRobSB1c2VkLlxuXHRcdHRoaXMuaGFzaEFsZ29yaXRobSA9IGVudW1zLnJlYWQoZW51bXMuaGFzaCwgYnl0ZXMuY2hhckNvZGVBdChteXBvcysrKSk7XG5cblx0ICAgICAvLyBBIG9uZS1vY3RldCBudW1iZXIgZGVzY3JpYmluZyB0aGUgcHVibGljLWtleSBhbGdvcml0aG0gdXNlZC5cblx0XHR0aGlzLnB1YmxpY0tleUFsZ29yaXRobSA9IGVudW1zLnJlYWQoZW51bXMucHVibGljS2V5LCBieXRlcy5jaGFyQ29kZUF0KG15cG9zKyspKTtcblxuXHQgICAgIC8vIEFuIGVpZ2h0LW9jdGV0IG51bWJlciBob2xkaW5nIHRoZSBLZXkgSUQgb2YgdGhlIHNpZ25pbmcga2V5LlxuXHRcdHRoaXMuc2lnbmluZ0tleUlkID0gbmV3IHR5cGVfa2V5aWQoKTtcblx0XHR0aGlzLnNpZ25pbmdLZXlJZC5yZWFkKGJ5dGVzLnN1YnN0cihteXBvcykpO1xuXHRcdG15cG9zICs9IDg7XG5cdFx0XG5cdCAgICAgLy8gQSBvbmUtb2N0ZXQgbnVtYmVyIGhvbGRpbmcgYSBmbGFnIHNob3dpbmcgd2hldGhlciB0aGUgc2lnbmF0dXJlXG5cdCAgICAgLy8gICBpcyBuZXN0ZWQuICBBIHplcm8gdmFsdWUgaW5kaWNhdGVzIHRoYXQgdGhlIG5leHQgcGFja2V0IGlzXG5cdCAgICAgLy8gICBhbm90aGVyIE9uZS1QYXNzIFNpZ25hdHVyZSBwYWNrZXQgdGhhdCBkZXNjcmliZXMgYW5vdGhlclxuXHQgICAgIC8vICAgc2lnbmF0dXJlIHRvIGJlIGFwcGxpZWQgdG8gdGhlIHNhbWUgbWVzc2FnZSBkYXRhLlxuXHRcdHRoaXMuZmxhZ3MgPSBieXRlcy5jaGFyQ29kZUF0KG15cG9zKyspO1xuXHRcdHJldHVybiB0aGlzO1xuXHR9XG5cblx0LyoqXG5cdCAqIGNyZWF0ZXMgYSBzdHJpbmcgcmVwcmVzZW50YXRpb24gb2YgYSBvbmUtcGFzcyBzaWduYXR1cmUgcGFja2V0XG5cdCAqIEBwYXJhbSB7SW50ZWdlcn0gdHlwZSBTaWduYXR1cmUgdHlwZXMgYXMgZGVzY3JpYmVkIGluIFJGQzQ4ODAgU2VjdGlvbiA1LjIuMS5cblx0ICogQHBhcmFtIHtJbnRlZ2VyfSBoYXNoYWxnb3JpdGhtIHRoZSBoYXNoIGFsZ29yaXRobSB1c2VkIHdpdGhpbiB0aGUgc2lnbmF0dXJlXG5cdCAqIEBwYXJhbSB7b3BlbnBncF9tc2dfcHJpdmF0ZWtleX0gcHJpdmF0ZWtleSB0aGUgcHJpdmF0ZSBrZXkgdXNlZCB0byBnZW5lcmF0ZSB0aGUgc2lnbmF0dXJlXG5cdCAqIEBwYXJhbSB7SW50ZWdlcn0gbGVuZ3RoIGxlbmd0aCBvZiBkYXRhIHRvIGJlIHNpZ25lZFxuXHQgKiBAcGFyYW0ge2Jvb2xlYW59IG5lc3RlZCBib29sZWFuIHNob3dpbmcgd2hldGhlciB0aGUgc2lnbmF0dXJlIGlzIG5lc3RlZC4gXG5cdCAqICBcInRydWVcIiBpbmRpY2F0ZXMgdGhhdCB0aGUgbmV4dCBwYWNrZXQgaXMgYW5vdGhlciBPbmUtUGFzcyBTaWduYXR1cmUgcGFja2V0XG5cdCAqICAgdGhhdCBkZXNjcmliZXMgYW5vdGhlciBzaWduYXR1cmUgdG8gYmUgYXBwbGllZCB0byB0aGUgc2FtZSBtZXNzYWdlIGRhdGEuIFxuXHQgKiBAcmV0dXJuIHtTdHJpbmd9IGEgc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIGEgb25lLXBhc3Mgc2lnbmF0dXJlIHBhY2tldFxuXHQgKi9cblx0dGhpcy53cml0ZSA9IGZ1bmN0aW9uKHR5cGUsIGhhc2hhbGdvcml0aG0sIHByaXZhdGVrZXksIGxlbmd0aCwgbmVzdGVkKSB7XG5cdFx0dmFyIHJlc3VsdCA9XCJcIjsgXG5cdFx0XG5cdFx0cmVzdWx0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoMyk7XG5cdFx0cmVzdWx0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoZW51bXMud3JpdGUoZW51bXMuc2lnbmF0dXJlLCB0eXBlKSk7XG5cdFx0cmVzdWx0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoZW51bXMud3JpdGUoZW51bXMuaGFzaCwgdGhpcy5oYXNoQWxnb3JpdGhtKSk7XG5cdFx0cmVzdWx0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoZW51bXMud3JpdGUoZW51bXMucHVibGljS2V5LCBwcml2YXRla2V5LmFsZ29yaXRobSkpO1xuXHRcdHJlc3VsdCArPSBwcml2YXRla2V5LmdldEtleUlkKCk7XG5cdFx0aWYgKG5lc3RlZClcblx0XHRcdHJlc3VsdCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKDApO1xuXHRcdGVsc2Vcblx0XHRcdHJlc3VsdCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKDEpO1xuXHRcdFxuXHRcdHJldHVybiByZXN1bHQ7XG5cdH1cbn07XG4iLCIvLyBHUEc0QnJvd3NlcnMgLSBBbiBPcGVuUEdQIGltcGxlbWVudGF0aW9uIGluIGphdmFzY3JpcHRcbi8vIENvcHlyaWdodCAoQykgMjAxMSBSZWN1cml0eSBMYWJzIEdtYkhcbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vclxuLy8gbW9kaWZ5IGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyXG4vLyB2ZXJzaW9uIDIuMSBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4vLyBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuLy8gTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZSBHTlVcbi8vIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG4vLyBcbi8vIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYWxvbmcgd2l0aCB0aGlzIGxpYnJhcnk7IGlmIG5vdCwgd3JpdGUgdG8gdGhlIEZyZWUgU29mdHdhcmVcbi8vIEZvdW5kYXRpb24sIEluYy4sIDUxIEZyYW5rbGluIFN0cmVldCwgRmlmdGggRmxvb3IsIEJvc3RvbiwgTUEgIDAyMTEwLTEzMDEgIFVTQVxuXG52YXIgc2VjcmV0X2tleSA9IHJlcXVpcmUoJy4vc2VjcmV0X2tleS5qcycpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIHNlY3JldF9zdWJrZXkoKSB7XG5cdHNlY3JldF9rZXkuY2FsbCh0aGlzKTtcbn1cbiIsIi8qIEEgSmF2YVNjcmlwdCBpbXBsZW1lbnRhdGlvbiBvZiB0aGUgU0hBIGZhbWlseSBvZiBoYXNoZXMsIGFzIGRlZmluZWQgaW4gRklQUyBcbiAqIFBVQiAxODAtMiBhcyB3ZWxsIGFzIHRoZSBjb3JyZXNwb25kaW5nIEhNQUMgaW1wbGVtZW50YXRpb24gYXMgZGVmaW5lZCBpblxuICogRklQUyBQVUIgMTk4YVxuICpcbiAqIFZlcnNpb24gMS4zIENvcHlyaWdodCBCcmlhbiBUdXJlayAyMDA4LTIwMTBcbiAqIERpc3RyaWJ1dGVkIHVuZGVyIHRoZSBCU0QgTGljZW5zZVxuICogU2VlIGh0dHA6Ly9qc3NoYS5zb3VyY2Vmb3JnZS5uZXQvIGZvciBtb3JlIGluZm9ybWF0aW9uXG4gKlxuICogU2V2ZXJhbCBmdW5jdGlvbnMgdGFrZW4gZnJvbSBQYXVsIEpvaG5zb25cbiAqL1xuXG4vKiBNb2RpZmllZCBieSBSZWN1cml0eSBMYWJzIEdtYkhcbiAqIFxuICogVGhpcyBjb2RlIGhhcyBiZWVuIHNsaWdodGx5IG1vZGlmaWVkIGRpcmVjdCBzdHJpbmcgb3V0cHV0OlxuICogLSBiaW4yYnN0ciBoYXMgYmVlbiBhZGRlZFxuICogLSBmb2xsb3dpbmcgd3JhcHBlcnMgb2YgdGhpcyBsaWJyYXJ5IGhhdmUgYmVlbiBhZGRlZDpcbiAqICAgLSBzdHJfc2hhMVxuICogICAtIHN0cl9zaGEyNTZcbiAqICAgLSBzdHJfc2hhMjI0XG4gKiAgIC0gc3RyX3NoYTM4NFxuICogICAtIHN0cl9zaGE1MTJcbiAqL1xuXG52YXIganNTSEEgPSAoZnVuY3Rpb24gKCkge1xuXHRcblx0Lypcblx0ICogQ29uZmlndXJhYmxlIHZhcmlhYmxlcy4gRGVmYXVsdHMgdHlwaWNhbGx5IHdvcmtcblx0ICovXG5cdC8qIE51bWJlciBvZiBCaXRzIFBlciBjaGFyYWN0ZXIgKDggZm9yIEFTQ0lJLCAxNiBmb3IgVW5pY29kZSkgKi9cblx0dmFyIGNoYXJTaXplID0gOCwgXG5cdC8qIGJhc2UtNjQgcGFkIGNoYXJhY3Rlci4gXCI9XCIgZm9yIHN0cmljdCBSRkMgY29tcGxpYW5jZSAqL1xuXHRiNjRwYWQgPSBcIlwiLCBcblx0LyogaGV4IG91dHB1dCBmb3JtYXQuIDAgLSBsb3dlcmNhc2U7IDEgLSB1cHBlcmNhc2UgKi9cblx0aGV4Q2FzZSA9IDAsIFxuXG5cdC8qXG5cdCAqIEludF82NCBpcyBhIG9iamVjdCBmb3IgMiAzMi1iaXQgbnVtYmVycyBlbXVsYXRpbmcgYSA2NC1iaXQgbnVtYmVyXG5cdCAqXG5cdCAqIEBjb25zdHJ1Y3RvclxuXHQgKiBAcGFyYW0ge051bWJlcn0gbXNpbnRfMzIgVGhlIG1vc3Qgc2lnbmlmaWNhbnQgMzItYml0cyBvZiBhIDY0LWJpdCBudW1iZXJcblx0ICogQHBhcmFtIHtOdW1iZXJ9IGxzaW50XzMyIFRoZSBsZWFzdCBzaWduaWZpY2FudCAzMi1iaXRzIG9mIGEgNjQtYml0IG51bWJlclxuXHQgKi9cblx0SW50XzY0ID0gZnVuY3Rpb24gKG1zaW50XzMyLCBsc2ludF8zMilcblx0e1xuXHRcdHRoaXMuaGlnaE9yZGVyID0gbXNpbnRfMzI7XG5cdFx0dGhpcy5sb3dPcmRlciA9IGxzaW50XzMyO1xuXHR9LFxuXG5cdC8qXG5cdCAqIENvbnZlcnQgYSBzdHJpbmcgdG8gYW4gYXJyYXkgb2YgYmlnLWVuZGlhbiB3b3Jkc1xuXHQgKiBJZiBjaGFyU2l6ZSBpcyBBU0NJSSwgY2hhcmFjdGVycyA+MjU1IGhhdmUgdGhlaXIgaGktYnl0ZSBzaWxlbnRseVxuXHQgKiBpZ25vcmVkLlxuXHQgKlxuXHQgKiBAcGFyYW0ge1N0cmluZ30gc3RyIFN0cmluZyB0byBiZSBjb252ZXJ0ZWQgdG8gYmluYXJ5IHJlcHJlc2VudGF0aW9uXG5cdCAqIEByZXR1cm4gSW50ZWdlciBhcnJheSByZXByZXNlbnRhdGlvbiBvZiB0aGUgcGFyYW1ldGVyXG5cdCAqL1xuXHRzdHIyYmluYiA9IGZ1bmN0aW9uIChzdHIpXG5cdHtcblx0XHR2YXIgYmluID0gW10sIG1hc2sgPSAoMSA8PCBjaGFyU2l6ZSkgLSAxLFxuXHRcdFx0bGVuZ3RoID0gc3RyLmxlbmd0aCAqIGNoYXJTaXplLCBpO1xuXG5cdFx0Zm9yIChpID0gMDsgaSA8IGxlbmd0aDsgaSArPSBjaGFyU2l6ZSlcblx0XHR7XG5cdFx0XHRiaW5baSA+PiA1XSB8PSAoc3RyLmNoYXJDb2RlQXQoaSAvIGNoYXJTaXplKSAmIG1hc2spIDw8XG5cdFx0XHRcdCgzMiAtIGNoYXJTaXplIC0gKGkgJSAzMikpO1xuXHRcdH1cblxuXHRcdHJldHVybiBiaW47XG5cdH0sXG5cblx0Lypcblx0ICogQ29udmVydCBhIGhleCBzdHJpbmcgdG8gYW4gYXJyYXkgb2YgYmlnLWVuZGlhbiB3b3Jkc1xuXHQgKlxuXHQgKiBAcGFyYW0ge1N0cmluZ30gc3RyIFN0cmluZyB0byBiZSBjb252ZXJ0ZWQgdG8gYmluYXJ5IHJlcHJlc2VudGF0aW9uXG5cdCAqIEByZXR1cm4gSW50ZWdlciBhcnJheSByZXByZXNlbnRhdGlvbiBvZiB0aGUgcGFyYW1ldGVyXG5cdCAqL1xuXHRoZXgyYmluYiA9IGZ1bmN0aW9uIChzdHIpXG5cdHtcblx0XHR2YXIgYmluID0gW10sIGxlbmd0aCA9IHN0ci5sZW5ndGgsIGksIG51bTtcblxuXHRcdGZvciAoaSA9IDA7IGkgPCBsZW5ndGg7IGkgKz0gMilcblx0XHR7XG5cdFx0XHRudW0gPSBwYXJzZUludChzdHIuc3Vic3RyKGksIDIpLCAxNik7XG5cdFx0XHRpZiAoIWlzTmFOKG51bSkpXG5cdFx0XHR7XG5cdFx0XHRcdGJpbltpID4+IDNdIHw9IG51bSA8PCAoMjQgLSAoNCAqIChpICUgOCkpKTtcblx0XHRcdH1cblx0XHRcdGVsc2Vcblx0XHRcdHtcblx0XHRcdFx0cmV0dXJuIFwiSU5WQUxJRCBIRVggU1RSSU5HXCI7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGJpbjtcblx0fSxcblxuXHQvKlxuXHQgKiBDb252ZXJ0IGFuIGFycmF5IG9mIGJpZy1lbmRpYW4gd29yZHMgdG8gYSBoZXggc3RyaW5nLlxuXHQgKlxuXHQgKiBAcHJpdmF0ZVxuXHQgKiBAcGFyYW0ge0FycmF5fSBiaW5hcnJheSBBcnJheSBvZiBpbnRlZ2VycyB0byBiZSBjb252ZXJ0ZWQgdG8gaGV4aWRlY2ltYWxcblx0ICpcdCByZXByZXNlbnRhdGlvblxuXHQgKiBAcmV0dXJuIEhleGlkZWNpbWFsIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBwYXJhbWV0ZXIgaW4gU3RyaW5nIGZvcm1cblx0ICovXG5cdGJpbmIyaGV4ID0gZnVuY3Rpb24gKGJpbmFycmF5KVxuXHR7XG5cdFx0dmFyIGhleF90YWIgPSAoaGV4Q2FzZSkgPyBcIjAxMjM0NTY3ODlBQkNERUZcIiA6IFwiMDEyMzQ1Njc4OWFiY2RlZlwiLFxuXHRcdFx0c3RyID0gXCJcIiwgbGVuZ3RoID0gYmluYXJyYXkubGVuZ3RoICogNCwgaSwgc3JjQnl0ZTtcblxuXHRcdGZvciAoaSA9IDA7IGkgPCBsZW5ndGg7IGkgKz0gMSlcblx0XHR7XG5cdFx0XHRzcmNCeXRlID0gYmluYXJyYXlbaSA+PiAyXSA+PiAoKDMgLSAoaSAlIDQpKSAqIDgpO1xuXHRcdFx0c3RyICs9IGhleF90YWIuY2hhckF0KChzcmNCeXRlID4+IDQpICYgMHhGKSArXG5cdFx0XHRcdGhleF90YWIuY2hhckF0KHNyY0J5dGUgJiAweEYpO1xuXHRcdH1cblxuXHRcdHJldHVybiBzdHI7XG5cdH0sXG5cblx0Lypcblx0ICogQ29udmVydCBhbiBhcnJheSBvZiBiaWctZW5kaWFuIHdvcmRzIHRvIGEgYmFzZS02NCBzdHJpbmdcblx0ICpcblx0ICogQHByaXZhdGVcblx0ICogQHBhcmFtIHtBcnJheX0gYmluYXJyYXkgQXJyYXkgb2YgaW50ZWdlcnMgdG8gYmUgY29udmVydGVkIHRvIGJhc2UtNjRcblx0ICpcdCByZXByZXNlbnRhdGlvblxuXHQgKiBAcmV0dXJuIEJhc2UtNjQgZW5jb2RlZCByZXByZXNlbnRhdGlvbiBvZiB0aGUgcGFyYW1ldGVyIGluIFN0cmluZyBmb3JtXG5cdCAqL1xuXHRiaW5iMmI2NCA9IGZ1bmN0aW9uIChiaW5hcnJheSlcblx0e1xuXHRcdHZhciB0YWIgPSBcIkFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpcIiArXG5cdFx0XHRcIjAxMjM0NTY3ODkrL1wiLCBzdHIgPSBcIlwiLCBsZW5ndGggPSBiaW5hcnJheS5sZW5ndGggKiA0LCBpLCBqLFxuXHRcdFx0dHJpcGxldDtcblxuXHRcdGZvciAoaSA9IDA7IGkgPCBsZW5ndGg7IGkgKz0gMylcblx0XHR7XG5cdFx0XHR0cmlwbGV0ID0gKCgoYmluYXJyYXlbaSA+PiAyXSA+PiA4ICogKDMgLSBpICUgNCkpICYgMHhGRikgPDwgMTYpIHxcblx0XHRcdFx0KCgoYmluYXJyYXlbaSArIDEgPj4gMl0gPj4gOCAqICgzIC0gKGkgKyAxKSAlIDQpKSAmIDB4RkYpIDw8IDgpIHxcblx0XHRcdFx0KChiaW5hcnJheVtpICsgMiA+PiAyXSA+PiA4ICogKDMgLSAoaSArIDIpICUgNCkpICYgMHhGRik7XG5cdFx0XHRmb3IgKGogPSAwOyBqIDwgNDsgaiArPSAxKVxuXHRcdFx0e1xuXHRcdFx0XHRpZiAoaSAqIDggKyBqICogNiA8PSBiaW5hcnJheS5sZW5ndGggKiAzMilcblx0XHRcdFx0e1xuXHRcdFx0XHRcdHN0ciArPSB0YWIuY2hhckF0KCh0cmlwbGV0ID4+IDYgKiAoMyAtIGopKSAmIDB4M0YpO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGVsc2Vcblx0XHRcdFx0e1xuXHRcdFx0XHRcdHN0ciArPSBiNjRwYWQ7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cdFx0cmV0dXJuIHN0cjtcblx0fSxcblxuXHQvKlxuXHQgKiBDb252ZXJ0IGFuIGFycmF5IG9mIGJpZy1lbmRpYW4gd29yZHMgdG8gYSBzdHJpbmdcblx0ICovXG5cdGJpbmIyc3RyID0gZnVuY3Rpb24gKGJpbilcblx0e1xuXHQgIHZhciBzdHIgPSBcIlwiO1xuXHQgIHZhciBtYXNrID0gKDEgPDwgOCkgLSAxO1xuXHQgIGZvcih2YXIgaSA9IDA7IGkgPCBiaW4ubGVuZ3RoICogMzI7IGkgKz0gOClcblx0ICAgIHN0ciArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKChiaW5baT4+NV0gPj4+ICgyNCAtIGklMzIpKSAmIG1hc2spO1xuXHQgIHJldHVybiBzdHI7XG5cdH0sXG5cdC8qXG5cdCAqIFRoZSAzMi1iaXQgaW1wbGVtZW50YXRpb24gb2YgY2lyY3VsYXIgcm90YXRlIGxlZnRcblx0ICpcblx0ICogQHByaXZhdGVcblx0ICogQHBhcmFtIHtOdW1iZXJ9IHggVGhlIDMyLWJpdCBpbnRlZ2VyIGFyZ3VtZW50XG5cdCAqIEBwYXJhbSB7TnVtYmVyfSBuIFRoZSBudW1iZXIgb2YgYml0cyB0byBzaGlmdFxuXHQgKiBAcmV0dXJuIFRoZSB4IHNoaWZ0ZWQgY2lyY3VsYXJseSBieSBuIGJpdHNcblx0ICovXG5cdHJvdGxfMzIgPSBmdW5jdGlvbiAoeCwgbilcblx0e1xuXHRcdHJldHVybiAoeCA8PCBuKSB8ICh4ID4+PiAoMzIgLSBuKSk7XG5cdH0sXG5cblx0Lypcblx0ICogVGhlIDMyLWJpdCBpbXBsZW1lbnRhdGlvbiBvZiBjaXJjdWxhciByb3RhdGUgcmlnaHRcblx0ICpcblx0ICogQHByaXZhdGVcblx0ICogQHBhcmFtIHtOdW1iZXJ9IHggVGhlIDMyLWJpdCBpbnRlZ2VyIGFyZ3VtZW50XG5cdCAqIEBwYXJhbSB7TnVtYmVyfSBuIFRoZSBudW1iZXIgb2YgYml0cyB0byBzaGlmdFxuXHQgKiBAcmV0dXJuIFRoZSB4IHNoaWZ0ZWQgY2lyY3VsYXJseSBieSBuIGJpdHNcblx0ICovXG5cdHJvdHJfMzIgPSBmdW5jdGlvbiAoeCwgbilcblx0e1xuXHRcdHJldHVybiAoeCA+Pj4gbikgfCAoeCA8PCAoMzIgLSBuKSk7XG5cdH0sXG5cblx0Lypcblx0ICogVGhlIDY0LWJpdCBpbXBsZW1lbnRhdGlvbiBvZiBjaXJjdWxhciByb3RhdGUgcmlnaHRcblx0ICpcblx0ICogQHByaXZhdGVcblx0ICogQHBhcmFtIHtJbnRfNjR9IHggVGhlIDY0LWJpdCBpbnRlZ2VyIGFyZ3VtZW50XG5cdCAqIEBwYXJhbSB7TnVtYmVyfSBuIFRoZSBudW1iZXIgb2YgYml0cyB0byBzaGlmdFxuXHQgKiBAcmV0dXJuIFRoZSB4IHNoaWZ0ZWQgY2lyY3VsYXJseSBieSBuIGJpdHNcblx0ICovXG5cdHJvdHJfNjQgPSBmdW5jdGlvbiAoeCwgbilcblx0e1xuXHRcdGlmIChuIDw9IDMyKVxuXHRcdHtcblx0XHRcdHJldHVybiBuZXcgSW50XzY0KFxuXHRcdFx0XHRcdCh4LmhpZ2hPcmRlciA+Pj4gbikgfCAoeC5sb3dPcmRlciA8PCAoMzIgLSBuKSksXG5cdFx0XHRcdFx0KHgubG93T3JkZXIgPj4+IG4pIHwgKHguaGlnaE9yZGVyIDw8ICgzMiAtIG4pKVxuXHRcdFx0XHQpO1xuXHRcdH1cblx0XHRlbHNlXG5cdFx0e1xuXHRcdFx0cmV0dXJuIG5ldyBJbnRfNjQoXG5cdFx0XHRcdFx0KHgubG93T3JkZXIgPj4+IG4pIHwgKHguaGlnaE9yZGVyIDw8ICgzMiAtIG4pKSxcblx0XHRcdFx0XHQoeC5oaWdoT3JkZXIgPj4+IG4pIHwgKHgubG93T3JkZXIgPDwgKDMyIC0gbikpXG5cdFx0XHRcdCk7XG5cdFx0fVxuXHR9LFxuXG5cdC8qXG5cdCAqIFRoZSAzMi1iaXQgaW1wbGVtZW50YXRpb24gb2Ygc2hpZnQgcmlnaHRcblx0ICpcblx0ICogQHByaXZhdGVcblx0ICogQHBhcmFtIHtOdW1iZXJ9IHggVGhlIDMyLWJpdCBpbnRlZ2VyIGFyZ3VtZW50XG5cdCAqIEBwYXJhbSB7TnVtYmVyfSBuIFRoZSBudW1iZXIgb2YgYml0cyB0byBzaGlmdFxuXHQgKiBAcmV0dXJuIFRoZSB4IHNoaWZ0ZWQgYnkgbiBiaXRzXG5cdCAqL1xuXHRzaHJfMzIgPSBmdW5jdGlvbiAoeCwgbilcblx0e1xuXHRcdHJldHVybiB4ID4+PiBuO1xuXHR9LFxuXG5cdC8qXG5cdCAqIFRoZSA2NC1iaXQgaW1wbGVtZW50YXRpb24gb2Ygc2hpZnQgcmlnaHRcblx0ICpcblx0ICogQHByaXZhdGVcblx0ICogQHBhcmFtIHtJbnRfNjR9IHggVGhlIDY0LWJpdCBpbnRlZ2VyIGFyZ3VtZW50XG5cdCAqIEBwYXJhbSB7TnVtYmVyfSBuIFRoZSBudW1iZXIgb2YgYml0cyB0byBzaGlmdFxuXHQgKiBAcmV0dXJuIFRoZSB4IHNoaWZ0ZWQgYnkgbiBiaXRzXG5cdCAqL1xuXHRzaHJfNjQgPSBmdW5jdGlvbiAoeCwgbilcblx0e1xuXHRcdGlmIChuIDw9IDMyKVxuXHRcdHtcblx0XHRcdHJldHVybiBuZXcgSW50XzY0KFxuXHRcdFx0XHRcdHguaGlnaE9yZGVyID4+PiBuLFxuXHRcdFx0XHRcdHgubG93T3JkZXIgPj4+IG4gfCAoeC5oaWdoT3JkZXIgPDwgKDMyIC0gbikpXG5cdFx0XHRcdCk7XG5cdFx0fVxuXHRcdGVsc2Vcblx0XHR7XG5cdFx0XHRyZXR1cm4gbmV3IEludF82NChcblx0XHRcdFx0XHQwLFxuXHRcdFx0XHRcdHguaGlnaE9yZGVyIDw8ICgzMiAtIG4pXG5cdFx0XHRcdCk7XG5cdFx0fVxuXHR9LFxuXG5cdC8qXG5cdCAqIFRoZSAzMi1iaXQgaW1wbGVtZW50YXRpb24gb2YgdGhlIE5JU1Qgc3BlY2lmaWVkIFBhcml0eSBmdW5jdGlvblxuXHQgKlxuXHQgKiBAcHJpdmF0ZVxuXHQgKiBAcGFyYW0ge051bWJlcn0geCBUaGUgZmlyc3QgMzItYml0IGludGVnZXIgYXJndW1lbnRcblx0ICogQHBhcmFtIHtOdW1iZXJ9IHkgVGhlIHNlY29uZCAzMi1iaXQgaW50ZWdlciBhcmd1bWVudFxuXHQgKiBAcGFyYW0ge051bWJlcn0geiBUaGUgdGhpcmQgMzItYml0IGludGVnZXIgYXJndW1lbnRcblx0ICogQHJldHVybiBUaGUgTklTVCBzcGVjaWZpZWQgb3V0cHV0IG9mIHRoZSBmdW5jdGlvblxuXHQgKi9cblx0cGFyaXR5XzMyID0gZnVuY3Rpb24gKHgsIHksIHopXG5cdHtcblx0XHRyZXR1cm4geCBeIHkgXiB6O1xuXHR9LFxuXG5cdC8qXG5cdCAqIFRoZSAzMi1iaXQgaW1wbGVtZW50YXRpb24gb2YgdGhlIE5JU1Qgc3BlY2lmaWVkIENoIGZ1bmN0aW9uXG5cdCAqXG5cdCAqIEBwcml2YXRlXG5cdCAqIEBwYXJhbSB7TnVtYmVyfSB4IFRoZSBmaXJzdCAzMi1iaXQgaW50ZWdlciBhcmd1bWVudFxuXHQgKiBAcGFyYW0ge051bWJlcn0geSBUaGUgc2Vjb25kIDMyLWJpdCBpbnRlZ2VyIGFyZ3VtZW50XG5cdCAqIEBwYXJhbSB7TnVtYmVyfSB6IFRoZSB0aGlyZCAzMi1iaXQgaW50ZWdlciBhcmd1bWVudFxuXHQgKiBAcmV0dXJuIFRoZSBOSVNUIHNwZWNpZmllZCBvdXRwdXQgb2YgdGhlIGZ1bmN0aW9uXG5cdCAqL1xuXHRjaF8zMiA9IGZ1bmN0aW9uICh4LCB5LCB6KVxuXHR7XG5cdFx0cmV0dXJuICh4ICYgeSkgXiAofnggJiB6KTtcblx0fSxcblxuXHQvKlxuXHQgKiBUaGUgNjQtYml0IGltcGxlbWVudGF0aW9uIG9mIHRoZSBOSVNUIHNwZWNpZmllZCBDaCBmdW5jdGlvblxuXHQgKlxuXHQgKiBAcHJpdmF0ZVxuXHQgKiBAcGFyYW0ge0ludF82NH0geCBUaGUgZmlyc3QgNjQtYml0IGludGVnZXIgYXJndW1lbnRcblx0ICogQHBhcmFtIHtJbnRfNjR9IHkgVGhlIHNlY29uZCA2NC1iaXQgaW50ZWdlciBhcmd1bWVudFxuXHQgKiBAcGFyYW0ge0ludF82NH0geiBUaGUgdGhpcmQgNjQtYml0IGludGVnZXIgYXJndW1lbnRcblx0ICogQHJldHVybiBUaGUgTklTVCBzcGVjaWZpZWQgb3V0cHV0IG9mIHRoZSBmdW5jdGlvblxuXHQgKi9cblx0Y2hfNjQgPSBmdW5jdGlvbiAoeCwgeSwgeilcblx0e1xuXHRcdHJldHVybiBuZXcgSW50XzY0KFxuXHRcdFx0XHQoeC5oaWdoT3JkZXIgJiB5LmhpZ2hPcmRlcikgXiAofnguaGlnaE9yZGVyICYgei5oaWdoT3JkZXIpLFxuXHRcdFx0XHQoeC5sb3dPcmRlciAmIHkubG93T3JkZXIpIF4gKH54Lmxvd09yZGVyICYgei5sb3dPcmRlcilcblx0XHRcdCk7XG5cdH0sXG5cblx0Lypcblx0ICogVGhlIDMyLWJpdCBpbXBsZW1lbnRhdGlvbiBvZiB0aGUgTklTVCBzcGVjaWZpZWQgTWFqIGZ1bmN0aW9uXG5cdCAqXG5cdCAqIEBwcml2YXRlXG5cdCAqIEBwYXJhbSB7TnVtYmVyfSB4IFRoZSBmaXJzdCAzMi1iaXQgaW50ZWdlciBhcmd1bWVudFxuXHQgKiBAcGFyYW0ge051bWJlcn0geSBUaGUgc2Vjb25kIDMyLWJpdCBpbnRlZ2VyIGFyZ3VtZW50XG5cdCAqIEBwYXJhbSB7TnVtYmVyfSB6IFRoZSB0aGlyZCAzMi1iaXQgaW50ZWdlciBhcmd1bWVudFxuXHQgKiBAcmV0dXJuIFRoZSBOSVNUIHNwZWNpZmllZCBvdXRwdXQgb2YgdGhlIGZ1bmN0aW9uXG5cdCAqL1xuXHRtYWpfMzIgPSBmdW5jdGlvbiAoeCwgeSwgeilcblx0e1xuXHRcdHJldHVybiAoeCAmIHkpIF4gKHggJiB6KSBeICh5ICYgeik7XG5cdH0sXG5cblx0Lypcblx0ICogVGhlIDY0LWJpdCBpbXBsZW1lbnRhdGlvbiBvZiB0aGUgTklTVCBzcGVjaWZpZWQgTWFqIGZ1bmN0aW9uXG5cdCAqXG5cdCAqIEBwcml2YXRlXG5cdCAqIEBwYXJhbSB7SW50XzY0fSB4IFRoZSBmaXJzdCA2NC1iaXQgaW50ZWdlciBhcmd1bWVudFxuXHQgKiBAcGFyYW0ge0ludF82NH0geSBUaGUgc2Vjb25kIDY0LWJpdCBpbnRlZ2VyIGFyZ3VtZW50XG5cdCAqIEBwYXJhbSB7SW50XzY0fSB6IFRoZSB0aGlyZCA2NC1iaXQgaW50ZWdlciBhcmd1bWVudFxuXHQgKiBAcmV0dXJuIFRoZSBOSVNUIHNwZWNpZmllZCBvdXRwdXQgb2YgdGhlIGZ1bmN0aW9uXG5cdCAqL1xuXHRtYWpfNjQgPSBmdW5jdGlvbiAoeCwgeSwgeilcblx0e1xuXHRcdHJldHVybiBuZXcgSW50XzY0KFxuXHRcdFx0XHQoeC5oaWdoT3JkZXIgJiB5LmhpZ2hPcmRlcikgXlxuXHRcdFx0XHQoeC5oaWdoT3JkZXIgJiB6LmhpZ2hPcmRlcikgXlxuXHRcdFx0XHQoeS5oaWdoT3JkZXIgJiB6LmhpZ2hPcmRlciksXG5cdFx0XHRcdCh4Lmxvd09yZGVyICYgeS5sb3dPcmRlcikgXlxuXHRcdFx0XHQoeC5sb3dPcmRlciAmIHoubG93T3JkZXIpIF5cblx0XHRcdFx0KHkubG93T3JkZXIgJiB6Lmxvd09yZGVyKVxuXHRcdFx0KTtcblx0fSxcblxuXHQvKlxuXHQgKiBUaGUgMzItYml0IGltcGxlbWVudGF0aW9uIG9mIHRoZSBOSVNUIHNwZWNpZmllZCBTaWdtYTAgZnVuY3Rpb25cblx0ICpcblx0ICogQHByaXZhdGVcblx0ICogQHBhcmFtIHtOdW1iZXJ9IHggVGhlIDMyLWJpdCBpbnRlZ2VyIGFyZ3VtZW50XG5cdCAqIEByZXR1cm4gVGhlIE5JU1Qgc3BlY2lmaWVkIG91dHB1dCBvZiB0aGUgZnVuY3Rpb25cblx0ICovXG5cdHNpZ21hMF8zMiA9IGZ1bmN0aW9uICh4KVxuXHR7XG5cdFx0cmV0dXJuIHJvdHJfMzIoeCwgMikgXiByb3RyXzMyKHgsIDEzKSBeIHJvdHJfMzIoeCwgMjIpO1xuXHR9LFxuXG5cdC8qXG5cdCAqIFRoZSA2NC1iaXQgaW1wbGVtZW50YXRpb24gb2YgdGhlIE5JU1Qgc3BlY2lmaWVkIFNpZ21hMCBmdW5jdGlvblxuXHQgKlxuXHQgKiBAcHJpdmF0ZVxuXHQgKiBAcGFyYW0ge0ludF82NH0geCBUaGUgNjQtYml0IGludGVnZXIgYXJndW1lbnRcblx0ICogQHJldHVybiBUaGUgTklTVCBzcGVjaWZpZWQgb3V0cHV0IG9mIHRoZSBmdW5jdGlvblxuXHQgKi9cblx0c2lnbWEwXzY0ID0gZnVuY3Rpb24gKHgpXG5cdHtcblx0XHR2YXIgcm90cjI4ID0gcm90cl82NCh4LCAyOCksIHJvdHIzNCA9IHJvdHJfNjQoeCwgMzQpLFxuXHRcdFx0cm90cjM5ID0gcm90cl82NCh4LCAzOSk7XG5cblx0XHRyZXR1cm4gbmV3IEludF82NChcblx0XHRcdFx0cm90cjI4LmhpZ2hPcmRlciBeIHJvdHIzNC5oaWdoT3JkZXIgXiByb3RyMzkuaGlnaE9yZGVyLFxuXHRcdFx0XHRyb3RyMjgubG93T3JkZXIgXiByb3RyMzQubG93T3JkZXIgXiByb3RyMzkubG93T3JkZXIpO1xuXHR9LFxuXG5cdC8qXG5cdCAqIFRoZSAzMi1iaXQgaW1wbGVtZW50YXRpb24gb2YgdGhlIE5JU1Qgc3BlY2lmaWVkIFNpZ21hMSBmdW5jdGlvblxuXHQgKlxuXHQgKiBAcHJpdmF0ZVxuXHQgKiBAcGFyYW0ge051bWJlcn0geCBUaGUgMzItYml0IGludGVnZXIgYXJndW1lbnRcblx0ICogQHJldHVybiBUaGUgTklTVCBzcGVjaWZpZWQgb3V0cHV0IG9mIHRoZSBmdW5jdGlvblxuXHQgKi9cblx0c2lnbWExXzMyID0gZnVuY3Rpb24gKHgpXG5cdHtcblx0XHRyZXR1cm4gcm90cl8zMih4LCA2KSBeIHJvdHJfMzIoeCwgMTEpIF4gcm90cl8zMih4LCAyNSk7XG5cdH0sXG5cblx0Lypcblx0ICogVGhlIDY0LWJpdCBpbXBsZW1lbnRhdGlvbiBvZiB0aGUgTklTVCBzcGVjaWZpZWQgU2lnbWExIGZ1bmN0aW9uXG5cdCAqXG5cdCAqIEBwcml2YXRlXG5cdCAqIEBwYXJhbSB7SW50XzY0fSB4IFRoZSA2NC1iaXQgaW50ZWdlciBhcmd1bWVudFxuXHQgKiBAcmV0dXJuIFRoZSBOSVNUIHNwZWNpZmllZCBvdXRwdXQgb2YgdGhlIGZ1bmN0aW9uXG5cdCAqL1xuXHRzaWdtYTFfNjQgPSBmdW5jdGlvbiAoeClcblx0e1xuXHRcdHZhciByb3RyMTQgPSByb3RyXzY0KHgsIDE0KSwgcm90cjE4ID0gcm90cl82NCh4LCAxOCksXG5cdFx0XHRyb3RyNDEgPSByb3RyXzY0KHgsIDQxKTtcblxuXHRcdHJldHVybiBuZXcgSW50XzY0KFxuXHRcdFx0XHRyb3RyMTQuaGlnaE9yZGVyIF4gcm90cjE4LmhpZ2hPcmRlciBeIHJvdHI0MS5oaWdoT3JkZXIsXG5cdFx0XHRcdHJvdHIxNC5sb3dPcmRlciBeIHJvdHIxOC5sb3dPcmRlciBeIHJvdHI0MS5sb3dPcmRlcik7XG5cdH0sXG5cblx0Lypcblx0ICogVGhlIDMyLWJpdCBpbXBsZW1lbnRhdGlvbiBvZiB0aGUgTklTVCBzcGVjaWZpZWQgR2FtbWEwIGZ1bmN0aW9uXG5cdCAqXG5cdCAqIEBwcml2YXRlXG5cdCAqIEBwYXJhbSB7TnVtYmVyfSB4IFRoZSAzMi1iaXQgaW50ZWdlciBhcmd1bWVudFxuXHQgKiBAcmV0dXJuIFRoZSBOSVNUIHNwZWNpZmllZCBvdXRwdXQgb2YgdGhlIGZ1bmN0aW9uXG5cdCAqL1xuXHRnYW1tYTBfMzIgPSBmdW5jdGlvbiAoeClcblx0e1xuXHRcdHJldHVybiByb3RyXzMyKHgsIDcpIF4gcm90cl8zMih4LCAxOCkgXiBzaHJfMzIoeCwgMyk7XG5cdH0sXG5cblx0Lypcblx0ICogVGhlIDY0LWJpdCBpbXBsZW1lbnRhdGlvbiBvZiB0aGUgTklTVCBzcGVjaWZpZWQgR2FtbWEwIGZ1bmN0aW9uXG5cdCAqXG5cdCAqIEBwcml2YXRlXG5cdCAqIEBwYXJhbSB7SW50XzY0fSB4IFRoZSA2NC1iaXQgaW50ZWdlciBhcmd1bWVudFxuXHQgKiBAcmV0dXJuIFRoZSBOSVNUIHNwZWNpZmllZCBvdXRwdXQgb2YgdGhlIGZ1bmN0aW9uXG5cdCAqL1xuXHRnYW1tYTBfNjQgPSBmdW5jdGlvbiAoeClcblx0e1xuXHRcdHZhciByb3RyMSA9IHJvdHJfNjQoeCwgMSksIHJvdHI4ID0gcm90cl82NCh4LCA4KSwgc2hyNyA9IHNocl82NCh4LCA3KTtcblxuXHRcdHJldHVybiBuZXcgSW50XzY0KFxuXHRcdFx0XHRyb3RyMS5oaWdoT3JkZXIgXiByb3RyOC5oaWdoT3JkZXIgXiBzaHI3LmhpZ2hPcmRlcixcblx0XHRcdFx0cm90cjEubG93T3JkZXIgXiByb3RyOC5sb3dPcmRlciBeIHNocjcubG93T3JkZXJcblx0XHRcdCk7XG5cdH0sXG5cblx0Lypcblx0ICogVGhlIDMyLWJpdCBpbXBsZW1lbnRhdGlvbiBvZiB0aGUgTklTVCBzcGVjaWZpZWQgR2FtbWExIGZ1bmN0aW9uXG5cdCAqXG5cdCAqIEBwcml2YXRlXG5cdCAqIEBwYXJhbSB7TnVtYmVyfSB4IFRoZSAzMi1iaXQgaW50ZWdlciBhcmd1bWVudFxuXHQgKiBAcmV0dXJuIFRoZSBOSVNUIHNwZWNpZmllZCBvdXRwdXQgb2YgdGhlIGZ1bmN0aW9uXG5cdCAqL1xuXHRnYW1tYTFfMzIgPSBmdW5jdGlvbiAoeClcblx0e1xuXHRcdHJldHVybiByb3RyXzMyKHgsIDE3KSBeIHJvdHJfMzIoeCwgMTkpIF4gc2hyXzMyKHgsIDEwKTtcblx0fSxcblxuXHQvKlxuXHQgKiBUaGUgNjQtYml0IGltcGxlbWVudGF0aW9uIG9mIHRoZSBOSVNUIHNwZWNpZmllZCBHYW1tYTEgZnVuY3Rpb25cblx0ICpcblx0ICogQHByaXZhdGVcblx0ICogQHBhcmFtIHtJbnRfNjR9IHggVGhlIDY0LWJpdCBpbnRlZ2VyIGFyZ3VtZW50XG5cdCAqIEByZXR1cm4gVGhlIE5JU1Qgc3BlY2lmaWVkIG91dHB1dCBvZiB0aGUgZnVuY3Rpb25cblx0ICovXG5cdGdhbW1hMV82NCA9IGZ1bmN0aW9uICh4KVxuXHR7XG5cdFx0dmFyIHJvdHIxOSA9IHJvdHJfNjQoeCwgMTkpLCByb3RyNjEgPSByb3RyXzY0KHgsIDYxKSxcblx0XHRcdHNocjYgPSBzaHJfNjQoeCwgNik7XG5cblx0XHRyZXR1cm4gbmV3IEludF82NChcblx0XHRcdFx0cm90cjE5LmhpZ2hPcmRlciBeIHJvdHI2MS5oaWdoT3JkZXIgXiBzaHI2LmhpZ2hPcmRlcixcblx0XHRcdFx0cm90cjE5Lmxvd09yZGVyIF4gcm90cjYxLmxvd09yZGVyIF4gc2hyNi5sb3dPcmRlclxuXHRcdFx0KTtcblx0fSxcblxuXHQvKlxuXHQgKiBBZGQgdHdvIDMyLWJpdCBpbnRlZ2Vycywgd3JhcHBpbmcgYXQgMl4zMi4gVGhpcyB1c2VzIDE2LWJpdCBvcGVyYXRpb25zXG5cdCAqIGludGVybmFsbHkgdG8gd29yayBhcm91bmQgYnVncyBpbiBzb21lIEpTIGludGVycHJldGVycy5cblx0ICpcblx0ICogQHByaXZhdGVcblx0ICogQHBhcmFtIHtOdW1iZXJ9IHggVGhlIGZpcnN0IDMyLWJpdCBpbnRlZ2VyIGFyZ3VtZW50IHRvIGJlIGFkZGVkXG5cdCAqIEBwYXJhbSB7TnVtYmVyfSB5IFRoZSBzZWNvbmQgMzItYml0IGludGVnZXIgYXJndW1lbnQgdG8gYmUgYWRkZWRcblx0ICogQHJldHVybiBUaGUgc3VtIG9mIHggKyB5XG5cdCAqL1xuXHRzYWZlQWRkXzMyXzIgPSBmdW5jdGlvbiAoeCwgeSlcblx0e1xuXHRcdHZhciBsc3cgPSAoeCAmIDB4RkZGRikgKyAoeSAmIDB4RkZGRiksXG5cdFx0XHRtc3cgPSAoeCA+Pj4gMTYpICsgKHkgPj4+IDE2KSArIChsc3cgPj4+IDE2KTtcblxuXHRcdHJldHVybiAoKG1zdyAmIDB4RkZGRikgPDwgMTYpIHwgKGxzdyAmIDB4RkZGRik7XG5cdH0sXG5cblx0Lypcblx0ICogQWRkIGZvdXIgMzItYml0IGludGVnZXJzLCB3cmFwcGluZyBhdCAyXjMyLiBUaGlzIHVzZXMgMTYtYml0IG9wZXJhdGlvbnNcblx0ICogaW50ZXJuYWxseSB0byB3b3JrIGFyb3VuZCBidWdzIGluIHNvbWUgSlMgaW50ZXJwcmV0ZXJzLlxuXHQgKlxuXHQgKiBAcHJpdmF0ZVxuXHQgKiBAcGFyYW0ge051bWJlcn0gYSBUaGUgZmlyc3QgMzItYml0IGludGVnZXIgYXJndW1lbnQgdG8gYmUgYWRkZWRcblx0ICogQHBhcmFtIHtOdW1iZXJ9IGIgVGhlIHNlY29uZCAzMi1iaXQgaW50ZWdlciBhcmd1bWVudCB0byBiZSBhZGRlZFxuXHQgKiBAcGFyYW0ge051bWJlcn0gYyBUaGUgdGhpcmQgMzItYml0IGludGVnZXIgYXJndW1lbnQgdG8gYmUgYWRkZWRcblx0ICogQHBhcmFtIHtOdW1iZXJ9IGQgVGhlIGZvdXJ0aCAzMi1iaXQgaW50ZWdlciBhcmd1bWVudCB0byBiZSBhZGRlZFxuXHQgKiBAcmV0dXJuIFRoZSBzdW0gb2YgYSArIGIgKyBjICsgZFxuXHQgKi9cblx0c2FmZUFkZF8zMl80ID0gZnVuY3Rpb24gKGEsIGIsIGMsIGQpXG5cdHtcblx0XHR2YXIgbHN3ID0gKGEgJiAweEZGRkYpICsgKGIgJiAweEZGRkYpICsgKGMgJiAweEZGRkYpICsgKGQgJiAweEZGRkYpLFxuXHRcdFx0bXN3ID0gKGEgPj4+IDE2KSArIChiID4+PiAxNikgKyAoYyA+Pj4gMTYpICsgKGQgPj4+IDE2KSArXG5cdFx0XHRcdChsc3cgPj4+IDE2KTtcblxuXHRcdHJldHVybiAoKG1zdyAmIDB4RkZGRikgPDwgMTYpIHwgKGxzdyAmIDB4RkZGRik7XG5cdH0sXG5cblx0Lypcblx0ICogQWRkIGZpdmUgMzItYml0IGludGVnZXJzLCB3cmFwcGluZyBhdCAyXjMyLiBUaGlzIHVzZXMgMTYtYml0IG9wZXJhdGlvbnNcblx0ICogaW50ZXJuYWxseSB0byB3b3JrIGFyb3VuZCBidWdzIGluIHNvbWUgSlMgaW50ZXJwcmV0ZXJzLlxuXHQgKlxuXHQgKiBAcHJpdmF0ZVxuXHQgKiBAcGFyYW0ge051bWJlcn0gYSBUaGUgZmlyc3QgMzItYml0IGludGVnZXIgYXJndW1lbnQgdG8gYmUgYWRkZWRcblx0ICogQHBhcmFtIHtOdW1iZXJ9IGIgVGhlIHNlY29uZCAzMi1iaXQgaW50ZWdlciBhcmd1bWVudCB0byBiZSBhZGRlZFxuXHQgKiBAcGFyYW0ge051bWJlcn0gYyBUaGUgdGhpcmQgMzItYml0IGludGVnZXIgYXJndW1lbnQgdG8gYmUgYWRkZWRcblx0ICogQHBhcmFtIHtOdW1iZXJ9IGQgVGhlIGZvdXJ0aCAzMi1iaXQgaW50ZWdlciBhcmd1bWVudCB0byBiZSBhZGRlZFxuXHQgKiBAcGFyYW0ge051bWJlcn0gZSBUaGUgZmlmdGggMzItYml0IGludGVnZXIgYXJndW1lbnQgdG8gYmUgYWRkZWRcblx0ICogQHJldHVybiBUaGUgc3VtIG9mIGEgKyBiICsgYyArIGQgKyBlXG5cdCAqL1xuXHRzYWZlQWRkXzMyXzUgPSBmdW5jdGlvbiAoYSwgYiwgYywgZCwgZSlcblx0e1xuXHRcdHZhciBsc3cgPSAoYSAmIDB4RkZGRikgKyAoYiAmIDB4RkZGRikgKyAoYyAmIDB4RkZGRikgKyAoZCAmIDB4RkZGRikgK1xuXHRcdFx0XHQoZSAmIDB4RkZGRiksXG5cdFx0XHRtc3cgPSAoYSA+Pj4gMTYpICsgKGIgPj4+IDE2KSArIChjID4+PiAxNikgKyAoZCA+Pj4gMTYpICtcblx0XHRcdFx0KGUgPj4+IDE2KSArIChsc3cgPj4+IDE2KTtcblxuXHRcdHJldHVybiAoKG1zdyAmIDB4RkZGRikgPDwgMTYpIHwgKGxzdyAmIDB4RkZGRik7XG5cdH0sXG5cblx0Lypcblx0ICogQWRkIHR3byA2NC1iaXQgaW50ZWdlcnMsIHdyYXBwaW5nIGF0IDJeNjQuIFRoaXMgdXNlcyAxNi1iaXQgb3BlcmF0aW9uc1xuXHQgKiBpbnRlcm5hbGx5IHRvIHdvcmsgYXJvdW5kIGJ1Z3MgaW4gc29tZSBKUyBpbnRlcnByZXRlcnMuXG5cdCAqXG5cdCAqIEBwcml2YXRlXG5cdCAqIEBwYXJhbSB7SW50XzY0fSB4IFRoZSBmaXJzdCA2NC1iaXQgaW50ZWdlciBhcmd1bWVudCB0byBiZSBhZGRlZFxuXHQgKiBAcGFyYW0ge0ludF82NH0geSBUaGUgc2Vjb25kIDY0LWJpdCBpbnRlZ2VyIGFyZ3VtZW50IHRvIGJlIGFkZGVkXG5cdCAqIEByZXR1cm4gVGhlIHN1bSBvZiB4ICsgeVxuXHQgKi9cblx0c2FmZUFkZF82NF8yID0gZnVuY3Rpb24gKHgsIHkpXG5cdHtcblx0XHR2YXIgbHN3LCBtc3csIGxvd09yZGVyLCBoaWdoT3JkZXI7XG5cblx0XHRsc3cgPSAoeC5sb3dPcmRlciAmIDB4RkZGRikgKyAoeS5sb3dPcmRlciAmIDB4RkZGRik7XG5cdFx0bXN3ID0gKHgubG93T3JkZXIgPj4+IDE2KSArICh5Lmxvd09yZGVyID4+PiAxNikgKyAobHN3ID4+PiAxNik7XG5cdFx0bG93T3JkZXIgPSAoKG1zdyAmIDB4RkZGRikgPDwgMTYpIHwgKGxzdyAmIDB4RkZGRik7XG5cblx0XHRsc3cgPSAoeC5oaWdoT3JkZXIgJiAweEZGRkYpICsgKHkuaGlnaE9yZGVyICYgMHhGRkZGKSArIChtc3cgPj4+IDE2KTtcblx0XHRtc3cgPSAoeC5oaWdoT3JkZXIgPj4+IDE2KSArICh5LmhpZ2hPcmRlciA+Pj4gMTYpICsgKGxzdyA+Pj4gMTYpO1xuXHRcdGhpZ2hPcmRlciA9ICgobXN3ICYgMHhGRkZGKSA8PCAxNikgfCAobHN3ICYgMHhGRkZGKTtcblxuXHRcdHJldHVybiBuZXcgSW50XzY0KGhpZ2hPcmRlciwgbG93T3JkZXIpO1xuXHR9LFxuXG5cdC8qXG5cdCAqIEFkZCBmb3VyIDY0LWJpdCBpbnRlZ2Vycywgd3JhcHBpbmcgYXQgMl42NC4gVGhpcyB1c2VzIDE2LWJpdCBvcGVyYXRpb25zXG5cdCAqIGludGVybmFsbHkgdG8gd29yayBhcm91bmQgYnVncyBpbiBzb21lIEpTIGludGVycHJldGVycy5cblx0ICpcblx0ICogQHByaXZhdGVcblx0ICogQHBhcmFtIHtJbnRfNjR9IGEgVGhlIGZpcnN0IDY0LWJpdCBpbnRlZ2VyIGFyZ3VtZW50IHRvIGJlIGFkZGVkXG5cdCAqIEBwYXJhbSB7SW50XzY0fSBiIFRoZSBzZWNvbmQgNjQtYml0IGludGVnZXIgYXJndW1lbnQgdG8gYmUgYWRkZWRcblx0ICogQHBhcmFtIHtJbnRfNjR9IGMgVGhlIHRoaXJkIDY0LWJpdCBpbnRlZ2VyIGFyZ3VtZW50IHRvIGJlIGFkZGVkXG5cdCAqIEBwYXJhbSB7SW50XzY0fSBkIFRoZSBmb3V0aCA2NC1iaXQgaW50ZWdlciBhcmd1bWVudCB0byBiZSBhZGRlZFxuXHQgKiBAcmV0dXJuIFRoZSBzdW0gb2YgYSArIGIgKyBjICsgZFxuXHQgKi9cblx0c2FmZUFkZF82NF80ID0gZnVuY3Rpb24gKGEsIGIsIGMsIGQpXG5cdHtcblx0XHR2YXIgbHN3LCBtc3csIGxvd09yZGVyLCBoaWdoT3JkZXI7XG5cblx0XHRsc3cgPSAoYS5sb3dPcmRlciAmIDB4RkZGRikgKyAoYi5sb3dPcmRlciAmIDB4RkZGRikgK1xuXHRcdFx0KGMubG93T3JkZXIgJiAweEZGRkYpICsgKGQubG93T3JkZXIgJiAweEZGRkYpO1xuXHRcdG1zdyA9IChhLmxvd09yZGVyID4+PiAxNikgKyAoYi5sb3dPcmRlciA+Pj4gMTYpICtcblx0XHRcdChjLmxvd09yZGVyID4+PiAxNikgKyAoZC5sb3dPcmRlciA+Pj4gMTYpICsgKGxzdyA+Pj4gMTYpO1xuXHRcdGxvd09yZGVyID0gKChtc3cgJiAweEZGRkYpIDw8IDE2KSB8IChsc3cgJiAweEZGRkYpO1xuXG5cdFx0bHN3ID0gKGEuaGlnaE9yZGVyICYgMHhGRkZGKSArIChiLmhpZ2hPcmRlciAmIDB4RkZGRikgK1xuXHRcdFx0KGMuaGlnaE9yZGVyICYgMHhGRkZGKSArIChkLmhpZ2hPcmRlciAmIDB4RkZGRikgKyAobXN3ID4+PiAxNik7XG5cdFx0bXN3ID0gKGEuaGlnaE9yZGVyID4+PiAxNikgKyAoYi5oaWdoT3JkZXIgPj4+IDE2KSArXG5cdFx0XHQoYy5oaWdoT3JkZXIgPj4+IDE2KSArIChkLmhpZ2hPcmRlciA+Pj4gMTYpICsgKGxzdyA+Pj4gMTYpO1xuXHRcdGhpZ2hPcmRlciA9ICgobXN3ICYgMHhGRkZGKSA8PCAxNikgfCAobHN3ICYgMHhGRkZGKTtcblxuXHRcdHJldHVybiBuZXcgSW50XzY0KGhpZ2hPcmRlciwgbG93T3JkZXIpO1xuXHR9LFxuXG5cdC8qXG5cdCAqIEFkZCBmaXZlIDY0LWJpdCBpbnRlZ2Vycywgd3JhcHBpbmcgYXQgMl42NC4gVGhpcyB1c2VzIDE2LWJpdCBvcGVyYXRpb25zXG5cdCAqIGludGVybmFsbHkgdG8gd29yayBhcm91bmQgYnVncyBpbiBzb21lIEpTIGludGVycHJldGVycy5cblx0ICpcblx0ICogQHByaXZhdGVcblx0ICogQHBhcmFtIHtJbnRfNjR9IGEgVGhlIGZpcnN0IDY0LWJpdCBpbnRlZ2VyIGFyZ3VtZW50IHRvIGJlIGFkZGVkXG5cdCAqIEBwYXJhbSB7SW50XzY0fSBiIFRoZSBzZWNvbmQgNjQtYml0IGludGVnZXIgYXJndW1lbnQgdG8gYmUgYWRkZWRcblx0ICogQHBhcmFtIHtJbnRfNjR9IGMgVGhlIHRoaXJkIDY0LWJpdCBpbnRlZ2VyIGFyZ3VtZW50IHRvIGJlIGFkZGVkXG5cdCAqIEBwYXJhbSB7SW50XzY0fSBkIFRoZSBmb3V0aCA2NC1iaXQgaW50ZWdlciBhcmd1bWVudCB0byBiZSBhZGRlZFxuXHQgKiBAcGFyYW0ge0ludF82NH0gZSBUaGUgZm91dGggNjQtYml0IGludGVnZXIgYXJndW1lbnQgdG8gYmUgYWRkZWRcblx0ICogQHJldHVybiBUaGUgc3VtIG9mIGEgKyBiICsgYyArIGQgKyBlXG5cdCAqL1xuXHRzYWZlQWRkXzY0XzUgPSBmdW5jdGlvbiAoYSwgYiwgYywgZCwgZSlcblx0e1xuXHRcdHZhciBsc3csIG1zdywgbG93T3JkZXIsIGhpZ2hPcmRlcjtcblxuXHRcdGxzdyA9IChhLmxvd09yZGVyICYgMHhGRkZGKSArIChiLmxvd09yZGVyICYgMHhGRkZGKSArXG5cdFx0XHQoYy5sb3dPcmRlciAmIDB4RkZGRikgKyAoZC5sb3dPcmRlciAmIDB4RkZGRikgK1xuXHRcdFx0KGUubG93T3JkZXIgJiAweEZGRkYpO1xuXHRcdG1zdyA9IChhLmxvd09yZGVyID4+PiAxNikgKyAoYi5sb3dPcmRlciA+Pj4gMTYpICtcblx0XHRcdChjLmxvd09yZGVyID4+PiAxNikgKyAoZC5sb3dPcmRlciA+Pj4gMTYpICsgKGUubG93T3JkZXIgPj4+IDE2KSArXG5cdFx0XHQobHN3ID4+PiAxNik7XG5cdFx0bG93T3JkZXIgPSAoKG1zdyAmIDB4RkZGRikgPDwgMTYpIHwgKGxzdyAmIDB4RkZGRik7XG5cblx0XHRsc3cgPSAoYS5oaWdoT3JkZXIgJiAweEZGRkYpICsgKGIuaGlnaE9yZGVyICYgMHhGRkZGKSArXG5cdFx0XHQoYy5oaWdoT3JkZXIgJiAweEZGRkYpICsgKGQuaGlnaE9yZGVyICYgMHhGRkZGKSArXG5cdFx0XHQoZS5oaWdoT3JkZXIgJiAweEZGRkYpICsgKG1zdyA+Pj4gMTYpO1xuXHRcdG1zdyA9IChhLmhpZ2hPcmRlciA+Pj4gMTYpICsgKGIuaGlnaE9yZGVyID4+PiAxNikgK1xuXHRcdFx0KGMuaGlnaE9yZGVyID4+PiAxNikgKyAoZC5oaWdoT3JkZXIgPj4+IDE2KSArXG5cdFx0XHQoZS5oaWdoT3JkZXIgPj4+IDE2KSArIChsc3cgPj4+IDE2KTtcblx0XHRoaWdoT3JkZXIgPSAoKG1zdyAmIDB4RkZGRikgPDwgMTYpIHwgKGxzdyAmIDB4RkZGRik7XG5cblx0XHRyZXR1cm4gbmV3IEludF82NChoaWdoT3JkZXIsIGxvd09yZGVyKTtcblx0fSxcblxuXHQvKlxuXHQgKiBDYWxjdWxhdGVzIHRoZSBTSEEtMSBoYXNoIG9mIHRoZSBzdHJpbmcgc2V0IGF0IGluc3RhbnRpYXRpb25cblx0ICpcblx0ICogQHByaXZhdGVcblx0ICogQHBhcmFtIHtBcnJheX0gbWVzc2FnZSBUaGUgYmluYXJ5IGFycmF5IHJlcHJlc2VudGF0aW9uIG9mIHRoZSBzdHJpbmcgdG9cblx0ICpcdCBoYXNoXG5cdCAqIEBwYXJhbSB7TnVtYmVyfSBtZXNzYWdlTGVuIFRoZSBudW1iZXIgb2YgYml0cyBpbiB0aGUgbWVzc2FnZVxuXHQgKiBAcmV0dXJuIFRoZSBhcnJheSBvZiBpbnRlZ2VycyByZXByZXNlbnRpbmcgdGhlIFNIQS0xIGhhc2ggb2YgbWVzc2FnZVxuXHQgKi9cblx0Y29yZVNIQTEgPSBmdW5jdGlvbiAobWVzc2FnZSwgbWVzc2FnZUxlbilcblx0e1xuXHRcdHZhciBXID0gW10sIGEsIGIsIGMsIGQsIGUsIFQsIGNoID0gY2hfMzIsIHBhcml0eSA9IHBhcml0eV8zMixcblx0XHRcdG1haiA9IG1hal8zMiwgcm90bCA9IHJvdGxfMzIsIHNhZmVBZGRfMiA9IHNhZmVBZGRfMzJfMiwgaSwgdCxcblx0XHRcdHNhZmVBZGRfNSA9IHNhZmVBZGRfMzJfNSwgYXBwZW5kZWRNZXNzYWdlTGVuZ3RoLFxuXHRcdFx0SCA9IFtcblx0XHRcdFx0MHg2NzQ1MjMwMSwgMHhlZmNkYWI4OSwgMHg5OGJhZGNmZSwgMHgxMDMyNTQ3NiwgMHhjM2QyZTFmMFxuXHRcdFx0XSxcblx0XHRcdEsgPSBbXG5cdFx0XHRcdDB4NWE4Mjc5OTksIDB4NWE4Mjc5OTksIDB4NWE4Mjc5OTksIDB4NWE4Mjc5OTksXG5cdFx0XHRcdDB4NWE4Mjc5OTksIDB4NWE4Mjc5OTksIDB4NWE4Mjc5OTksIDB4NWE4Mjc5OTksXG5cdFx0XHRcdDB4NWE4Mjc5OTksIDB4NWE4Mjc5OTksIDB4NWE4Mjc5OTksIDB4NWE4Mjc5OTksXG5cdFx0XHRcdDB4NWE4Mjc5OTksIDB4NWE4Mjc5OTksIDB4NWE4Mjc5OTksIDB4NWE4Mjc5OTksXG5cdFx0XHRcdDB4NWE4Mjc5OTksIDB4NWE4Mjc5OTksIDB4NWE4Mjc5OTksIDB4NWE4Mjc5OTksXG5cdFx0XHRcdDB4NmVkOWViYTEsIDB4NmVkOWViYTEsIDB4NmVkOWViYTEsIDB4NmVkOWViYTEsXG5cdFx0XHRcdDB4NmVkOWViYTEsIDB4NmVkOWViYTEsIDB4NmVkOWViYTEsIDB4NmVkOWViYTEsXG5cdFx0XHRcdDB4NmVkOWViYTEsIDB4NmVkOWViYTEsIDB4NmVkOWViYTEsIDB4NmVkOWViYTEsXG5cdFx0XHRcdDB4NmVkOWViYTEsIDB4NmVkOWViYTEsIDB4NmVkOWViYTEsIDB4NmVkOWViYTEsXG5cdFx0XHRcdDB4NmVkOWViYTEsIDB4NmVkOWViYTEsIDB4NmVkOWViYTEsIDB4NmVkOWViYTEsXG5cdFx0XHRcdDB4OGYxYmJjZGMsIDB4OGYxYmJjZGMsIDB4OGYxYmJjZGMsIDB4OGYxYmJjZGMsXG5cdFx0XHRcdDB4OGYxYmJjZGMsIDB4OGYxYmJjZGMsIDB4OGYxYmJjZGMsIDB4OGYxYmJjZGMsXG5cdFx0XHRcdDB4OGYxYmJjZGMsIDB4OGYxYmJjZGMsIDB4OGYxYmJjZGMsIDB4OGYxYmJjZGMsXG5cdFx0XHRcdDB4OGYxYmJjZGMsIDB4OGYxYmJjZGMsIDB4OGYxYmJjZGMsIDB4OGYxYmJjZGMsXG5cdFx0XHRcdDB4OGYxYmJjZGMsIDB4OGYxYmJjZGMsIDB4OGYxYmJjZGMsIDB4OGYxYmJjZGMsXG5cdFx0XHRcdDB4Y2E2MmMxZDYsIDB4Y2E2MmMxZDYsIDB4Y2E2MmMxZDYsIDB4Y2E2MmMxZDYsXG5cdFx0XHRcdDB4Y2E2MmMxZDYsIDB4Y2E2MmMxZDYsIDB4Y2E2MmMxZDYsIDB4Y2E2MmMxZDYsXG5cdFx0XHRcdDB4Y2E2MmMxZDYsIDB4Y2E2MmMxZDYsIDB4Y2E2MmMxZDYsIDB4Y2E2MmMxZDYsXG5cdFx0XHRcdDB4Y2E2MmMxZDYsIDB4Y2E2MmMxZDYsIDB4Y2E2MmMxZDYsIDB4Y2E2MmMxZDYsXG5cdFx0XHRcdDB4Y2E2MmMxZDYsIDB4Y2E2MmMxZDYsIDB4Y2E2MmMxZDYsIDB4Y2E2MmMxZDZcblx0XHRcdF07XG5cblx0XHQvKiBBcHBlbmQgJzEnIGF0IHRoZSBlbmQgb2YgdGhlIGJpbmFyeSBzdHJpbmcgKi9cblx0XHRtZXNzYWdlW21lc3NhZ2VMZW4gPj4gNV0gfD0gMHg4MCA8PCAoMjQgLSAobWVzc2FnZUxlbiAlIDMyKSk7XG5cdFx0LyogQXBwZW5kIGxlbmd0aCBvZiBiaW5hcnkgc3RyaW5nIGluIHRoZSBwb3NpdGlvbiBzdWNoIHRoYXQgdGhlIG5ld1xuXHRcdGxlbmd0aCBpcyBhIG11bHRpcGxlIG9mIDUxMi4gIExvZ2ljIGRvZXMgbm90IHdvcmsgZm9yIGV2ZW4gbXVsdGlwbGVzXG5cdFx0b2YgNTEyIGJ1dCB0aGVyZSBjYW4gbmV2ZXIgYmUgZXZlbiBtdWx0aXBsZXMgb2YgNTEyICovXG5cdFx0bWVzc2FnZVsoKChtZXNzYWdlTGVuICsgNjUpID4+IDkpIDw8IDQpICsgMTVdID0gbWVzc2FnZUxlbjtcblxuXHRcdGFwcGVuZGVkTWVzc2FnZUxlbmd0aCA9IG1lc3NhZ2UubGVuZ3RoO1xuXG5cdFx0Zm9yIChpID0gMDsgaSA8IGFwcGVuZGVkTWVzc2FnZUxlbmd0aDsgaSArPSAxNilcblx0XHR7XG5cdFx0XHRhID0gSFswXTtcblx0XHRcdGIgPSBIWzFdO1xuXHRcdFx0YyA9IEhbMl07XG5cdFx0XHRkID0gSFszXTtcblx0XHRcdGUgPSBIWzRdO1xuXG5cdFx0XHRmb3IgKHQgPSAwOyB0IDwgODA7IHQgKz0gMSlcblx0XHRcdHtcblx0XHRcdFx0aWYgKHQgPCAxNilcblx0XHRcdFx0e1xuXHRcdFx0XHRcdFdbdF0gPSBtZXNzYWdlW3QgKyBpXTtcblx0XHRcdFx0fVxuXHRcdFx0XHRlbHNlXG5cdFx0XHRcdHtcblx0XHRcdFx0XHRXW3RdID0gcm90bChXW3QgLSAzXSBeIFdbdCAtIDhdIF4gV1t0IC0gMTRdIF4gV1t0IC0gMTZdLCAxKTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmICh0IDwgMjApXG5cdFx0XHRcdHtcblx0XHRcdFx0XHRUID0gc2FmZUFkZF81KHJvdGwoYSwgNSksIGNoKGIsIGMsIGQpLCBlLCBLW3RdLCBXW3RdKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRlbHNlIGlmICh0IDwgNDApXG5cdFx0XHRcdHtcblx0XHRcdFx0XHRUID0gc2FmZUFkZF81KHJvdGwoYSwgNSksIHBhcml0eShiLCBjLCBkKSwgZSwgS1t0XSwgV1t0XSk7XG5cdFx0XHRcdH1cblx0XHRcdFx0ZWxzZSBpZiAodCA8IDYwKVxuXHRcdFx0XHR7XG5cdFx0XHRcdFx0VCA9IHNhZmVBZGRfNShyb3RsKGEsIDUpLCBtYWooYiwgYywgZCksIGUsIEtbdF0sIFdbdF0pO1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFQgPSBzYWZlQWRkXzUocm90bChhLCA1KSwgcGFyaXR5KGIsIGMsIGQpLCBlLCBLW3RdLCBXW3RdKTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdGUgPSBkO1xuXHRcdFx0XHRkID0gYztcblx0XHRcdFx0YyA9IHJvdGwoYiwgMzApO1xuXHRcdFx0XHRiID0gYTtcblx0XHRcdFx0YSA9IFQ7XG5cdFx0XHR9XG5cblx0XHRcdEhbMF0gPSBzYWZlQWRkXzIoYSwgSFswXSk7XG5cdFx0XHRIWzFdID0gc2FmZUFkZF8yKGIsIEhbMV0pO1xuXHRcdFx0SFsyXSA9IHNhZmVBZGRfMihjLCBIWzJdKTtcblx0XHRcdEhbM10gPSBzYWZlQWRkXzIoZCwgSFszXSk7XG5cdFx0XHRIWzRdID0gc2FmZUFkZF8yKGUsIEhbNF0pO1xuXHRcdH1cblxuXHRcdHJldHVybiBIO1xuXHR9LFxuXG5cdC8qXG5cdCAqIENhbGN1bGF0ZXMgdGhlIGRlc2lyZWQgU0hBLTIgaGFzaCBvZiB0aGUgc3RyaW5nIHNldCBhdCBpbnN0YW50aWF0aW9uXG5cdCAqXG5cdCAqIEBwcml2YXRlXG5cdCAqIEBwYXJhbSB7QXJyYXl9IFRoZSBiaW5hcnkgYXJyYXkgcmVwcmVzZW50YXRpb24gb2YgdGhlIHN0cmluZyB0byBoYXNoXG5cdCAqIEBwYXJhbSB7TnVtYmVyfSBUaGUgbnVtYmVyIG9mIGJpdHMgaW4gbWVzc2FnZVxuXHQgKiBAcGFyYW0ge1N0cmluZ30gdmFyaWFudCBUaGUgZGVzaXJlZCBTSEEtMiB2YXJpYW50XG5cdCAqIEByZXR1cm4gVGhlIGFycmF5IG9mIGludGVnZXJzIHJlcHJlc2VudGluZyB0aGUgU0hBLTIgaGFzaCBvZiBtZXNzYWdlXG5cdCAqL1xuXHRjb3JlU0hBMiA9IGZ1bmN0aW9uIChtZXNzYWdlLCBtZXNzYWdlTGVuLCB2YXJpYW50KVxuXHR7XG5cdFx0dmFyIGEsIGIsIGMsIGQsIGUsIGYsIGcsIGgsIFQxLCBUMiwgSCwgbnVtUm91bmRzLCBsZW5ndGhQb3NpdGlvbiwgaSwgdCxcblx0XHRcdGJpbmFyeVN0cmluZ0luYywgYmluYXJ5U3RyaW5nTXVsdCwgc2FmZUFkZF8yLCBzYWZlQWRkXzQsIHNhZmVBZGRfNSxcblx0XHRcdGdhbW1hMCwgZ2FtbWExLCBzaWdtYTAsIHNpZ21hMSwgY2gsIG1haiwgSW50LCBLLCBXID0gW10sXG5cdFx0XHRhcHBlbmRlZE1lc3NhZ2VMZW5ndGg7XG5cblx0XHQvKiBTZXQgdXAgdGhlIHZhcmlvdXMgZnVuY3Rpb24gaGFuZGxlcyBhbmQgdmFyaWFibGUgZm9yIHRoZSBzcGVjaWZpYyBcblx0XHQgKiB2YXJpYW50ICovXG5cdFx0aWYgKHZhcmlhbnQgPT09IFwiU0hBLTIyNFwiIHx8IHZhcmlhbnQgPT09IFwiU0hBLTI1NlwiKVxuXHRcdHtcblx0XHRcdC8qIDMyLWJpdCB2YXJpYW50ICovXG5cdFx0XHRudW1Sb3VuZHMgPSA2NDtcblx0XHRcdGxlbmd0aFBvc2l0aW9uID0gKCgobWVzc2FnZUxlbiArIDY1KSA+PiA5KSA8PCA0KSArIDE1O1xuXHRcdFx0YmluYXJ5U3RyaW5nSW5jID0gMTY7XG5cdFx0XHRiaW5hcnlTdHJpbmdNdWx0ID0gMTtcblx0XHRcdEludCA9IE51bWJlcjtcblx0XHRcdHNhZmVBZGRfMiA9IHNhZmVBZGRfMzJfMjtcblx0XHRcdHNhZmVBZGRfNCA9IHNhZmVBZGRfMzJfNDtcblx0XHRcdHNhZmVBZGRfNSA9IHNhZmVBZGRfMzJfNTtcblx0XHRcdGdhbW1hMCA9IGdhbW1hMF8zMjtcblx0XHRcdGdhbW1hMSA9IGdhbW1hMV8zMjtcblx0XHRcdHNpZ21hMCA9IHNpZ21hMF8zMjtcblx0XHRcdHNpZ21hMSA9IHNpZ21hMV8zMjtcblx0XHRcdG1haiA9IG1hal8zMjtcblx0XHRcdGNoID0gY2hfMzI7XG5cdFx0XHRLID0gW1xuXHRcdFx0XHRcdDB4NDI4QTJGOTgsIDB4NzEzNzQ0OTEsIDB4QjVDMEZCQ0YsIDB4RTlCNURCQTUsXG5cdFx0XHRcdFx0MHgzOTU2QzI1QiwgMHg1OUYxMTFGMSwgMHg5MjNGODJBNCwgMHhBQjFDNUVENSxcblx0XHRcdFx0XHQweEQ4MDdBQTk4LCAweDEyODM1QjAxLCAweDI0MzE4NUJFLCAweDU1MEM3REMzLFxuXHRcdFx0XHRcdDB4NzJCRTVENzQsIDB4ODBERUIxRkUsIDB4OUJEQzA2QTcsIDB4QzE5QkYxNzQsXG5cdFx0XHRcdFx0MHhFNDlCNjlDMSwgMHhFRkJFNDc4NiwgMHgwRkMxOURDNiwgMHgyNDBDQTFDQyxcblx0XHRcdFx0XHQweDJERTkyQzZGLCAweDRBNzQ4NEFBLCAweDVDQjBBOURDLCAweDc2Rjk4OERBLFxuXHRcdFx0XHRcdDB4OTgzRTUxNTIsIDB4QTgzMUM2NkQsIDB4QjAwMzI3QzgsIDB4QkY1OTdGQzcsXG5cdFx0XHRcdFx0MHhDNkUwMEJGMywgMHhENUE3OTE0NywgMHgwNkNBNjM1MSwgMHgxNDI5Mjk2Nyxcblx0XHRcdFx0XHQweDI3QjcwQTg1LCAweDJFMUIyMTM4LCAweDREMkM2REZDLCAweDUzMzgwRDEzLFxuXHRcdFx0XHRcdDB4NjUwQTczNTQsIDB4NzY2QTBBQkIsIDB4ODFDMkM5MkUsIDB4OTI3MjJDODUsXG5cdFx0XHRcdFx0MHhBMkJGRThBMSwgMHhBODFBNjY0QiwgMHhDMjRCOEI3MCwgMHhDNzZDNTFBMyxcblx0XHRcdFx0XHQweEQxOTJFODE5LCAweEQ2OTkwNjI0LCAweEY0MEUzNTg1LCAweDEwNkFBMDcwLFxuXHRcdFx0XHRcdDB4MTlBNEMxMTYsIDB4MUUzNzZDMDgsIDB4Mjc0ODc3NEMsIDB4MzRCMEJDQjUsXG5cdFx0XHRcdFx0MHgzOTFDMENCMywgMHg0RUQ4QUE0QSwgMHg1QjlDQ0E0RiwgMHg2ODJFNkZGMyxcblx0XHRcdFx0XHQweDc0OEY4MkVFLCAweDc4QTU2MzZGLCAweDg0Qzg3ODE0LCAweDhDQzcwMjA4LFxuXHRcdFx0XHRcdDB4OTBCRUZGRkEsIDB4QTQ1MDZDRUIsIDB4QkVGOUEzRjcsIDB4QzY3MTc4RjJcblx0XHRcdFx0XTtcblxuXHRcdFx0aWYgKHZhcmlhbnQgPT09IFwiU0hBLTIyNFwiKVxuXHRcdFx0e1xuXHRcdFx0XHRIID0gW1xuXHRcdFx0XHRcdFx0MHhjMTA1OWVkOCwgMHgzNjdjZDUwNywgMHgzMDcwZGQxNywgMHhmNzBlNTkzOSxcblx0XHRcdFx0XHRcdDB4ZmZjMDBiMzEsIDB4Njg1ODE1MTEsIDB4NjRmOThmYTcsIDB4YmVmYTRmYTRcblx0XHRcdFx0XHRdO1xuXHRcdFx0fVxuXHRcdFx0ZWxzZVxuXHRcdFx0e1xuXHRcdFx0XHRIID0gW1xuXHRcdFx0XHRcdFx0MHg2QTA5RTY2NywgMHhCQjY3QUU4NSwgMHgzQzZFRjM3MiwgMHhBNTRGRjUzQSxcblx0XHRcdFx0XHRcdDB4NTEwRTUyN0YsIDB4OUIwNTY4OEMsIDB4MUY4M0Q5QUIsIDB4NUJFMENEMTlcblx0XHRcdFx0XHRdO1xuXHRcdFx0fVxuXHRcdH1cblx0XHRlbHNlIGlmICh2YXJpYW50ID09PSBcIlNIQS0zODRcIiB8fCB2YXJpYW50ID09PSBcIlNIQS01MTJcIilcblx0XHR7XG5cdFx0XHQvKiA2NC1iaXQgdmFyaWFudCAqL1xuXHRcdFx0bnVtUm91bmRzID0gODA7XG5cdFx0XHRsZW5ndGhQb3NpdGlvbiA9ICgoKG1lc3NhZ2VMZW4gKyAxMjgpID4+IDEwKSA8PCA1KSArIDMxO1xuXHRcdFx0YmluYXJ5U3RyaW5nSW5jID0gMzI7XG5cdFx0XHRiaW5hcnlTdHJpbmdNdWx0ID0gMjtcblx0XHRcdEludCA9IEludF82NDtcblx0XHRcdHNhZmVBZGRfMiA9IHNhZmVBZGRfNjRfMjtcblx0XHRcdHNhZmVBZGRfNCA9IHNhZmVBZGRfNjRfNDtcblx0XHRcdHNhZmVBZGRfNSA9IHNhZmVBZGRfNjRfNTtcblx0XHRcdGdhbW1hMCA9IGdhbW1hMF82NDtcblx0XHRcdGdhbW1hMSA9IGdhbW1hMV82NDtcblx0XHRcdHNpZ21hMCA9IHNpZ21hMF82NDtcblx0XHRcdHNpZ21hMSA9IHNpZ21hMV82NDtcblx0XHRcdG1haiA9IG1hal82NDtcblx0XHRcdGNoID0gY2hfNjQ7XG5cblx0XHRcdEsgPSBbXG5cdFx0XHRcdG5ldyBJbnQoMHg0MjhhMmY5OCwgMHhkNzI4YWUyMiksIG5ldyBJbnQoMHg3MTM3NDQ5MSwgMHgyM2VmNjVjZCksXG5cdFx0XHRcdG5ldyBJbnQoMHhiNWMwZmJjZiwgMHhlYzRkM2IyZiksIG5ldyBJbnQoMHhlOWI1ZGJhNSwgMHg4MTg5ZGJiYyksXG5cdFx0XHRcdG5ldyBJbnQoMHgzOTU2YzI1YiwgMHhmMzQ4YjUzOCksIG5ldyBJbnQoMHg1OWYxMTFmMSwgMHhiNjA1ZDAxOSksXG5cdFx0XHRcdG5ldyBJbnQoMHg5MjNmODJhNCwgMHhhZjE5NGY5YiksIG5ldyBJbnQoMHhhYjFjNWVkNSwgMHhkYTZkODExOCksXG5cdFx0XHRcdG5ldyBJbnQoMHhkODA3YWE5OCwgMHhhMzAzMDI0MiksIG5ldyBJbnQoMHgxMjgzNWIwMSwgMHg0NTcwNmZiZSksXG5cdFx0XHRcdG5ldyBJbnQoMHgyNDMxODViZSwgMHg0ZWU0YjI4YyksIG5ldyBJbnQoMHg1NTBjN2RjMywgMHhkNWZmYjRlMiksXG5cdFx0XHRcdG5ldyBJbnQoMHg3MmJlNWQ3NCwgMHhmMjdiODk2ZiksIG5ldyBJbnQoMHg4MGRlYjFmZSwgMHgzYjE2OTZiMSksXG5cdFx0XHRcdG5ldyBJbnQoMHg5YmRjMDZhNywgMHgyNWM3MTIzNSksIG5ldyBJbnQoMHhjMTliZjE3NCwgMHhjZjY5MjY5NCksXG5cdFx0XHRcdG5ldyBJbnQoMHhlNDliNjljMSwgMHg5ZWYxNGFkMiksIG5ldyBJbnQoMHhlZmJlNDc4NiwgMHgzODRmMjVlMyksXG5cdFx0XHRcdG5ldyBJbnQoMHgwZmMxOWRjNiwgMHg4YjhjZDViNSksIG5ldyBJbnQoMHgyNDBjYTFjYywgMHg3N2FjOWM2NSksXG5cdFx0XHRcdG5ldyBJbnQoMHgyZGU5MmM2ZiwgMHg1OTJiMDI3NSksIG5ldyBJbnQoMHg0YTc0ODRhYSwgMHg2ZWE2ZTQ4MyksXG5cdFx0XHRcdG5ldyBJbnQoMHg1Y2IwYTlkYywgMHhiZDQxZmJkNCksIG5ldyBJbnQoMHg3NmY5ODhkYSwgMHg4MzExNTNiNSksXG5cdFx0XHRcdG5ldyBJbnQoMHg5ODNlNTE1MiwgMHhlZTY2ZGZhYiksIG5ldyBJbnQoMHhhODMxYzY2ZCwgMHgyZGI0MzIxMCksXG5cdFx0XHRcdG5ldyBJbnQoMHhiMDAzMjdjOCwgMHg5OGZiMjEzZiksIG5ldyBJbnQoMHhiZjU5N2ZjNywgMHhiZWVmMGVlNCksXG5cdFx0XHRcdG5ldyBJbnQoMHhjNmUwMGJmMywgMHgzZGE4OGZjMiksIG5ldyBJbnQoMHhkNWE3OTE0NywgMHg5MzBhYTcyNSksXG5cdFx0XHRcdG5ldyBJbnQoMHgwNmNhNjM1MSwgMHhlMDAzODI2ZiksIG5ldyBJbnQoMHgxNDI5Mjk2NywgMHgwYTBlNmU3MCksXG5cdFx0XHRcdG5ldyBJbnQoMHgyN2I3MGE4NSwgMHg0NmQyMmZmYyksIG5ldyBJbnQoMHgyZTFiMjEzOCwgMHg1YzI2YzkyNiksXG5cdFx0XHRcdG5ldyBJbnQoMHg0ZDJjNmRmYywgMHg1YWM0MmFlZCksIG5ldyBJbnQoMHg1MzM4MGQxMywgMHg5ZDk1YjNkZiksXG5cdFx0XHRcdG5ldyBJbnQoMHg2NTBhNzM1NCwgMHg4YmFmNjNkZSksIG5ldyBJbnQoMHg3NjZhMGFiYiwgMHgzYzc3YjJhOCksXG5cdFx0XHRcdG5ldyBJbnQoMHg4MWMyYzkyZSwgMHg0N2VkYWVlNiksIG5ldyBJbnQoMHg5MjcyMmM4NSwgMHgxNDgyMzUzYiksXG5cdFx0XHRcdG5ldyBJbnQoMHhhMmJmZThhMSwgMHg0Y2YxMDM2NCksIG5ldyBJbnQoMHhhODFhNjY0YiwgMHhiYzQyMzAwMSksXG5cdFx0XHRcdG5ldyBJbnQoMHhjMjRiOGI3MCwgMHhkMGY4OTc5MSksIG5ldyBJbnQoMHhjNzZjNTFhMywgMHgwNjU0YmUzMCksXG5cdFx0XHRcdG5ldyBJbnQoMHhkMTkyZTgxOSwgMHhkNmVmNTIxOCksIG5ldyBJbnQoMHhkNjk5MDYyNCwgMHg1NTY1YTkxMCksXG5cdFx0XHRcdG5ldyBJbnQoMHhmNDBlMzU4NSwgMHg1NzcxMjAyYSksIG5ldyBJbnQoMHgxMDZhYTA3MCwgMHgzMmJiZDFiOCksXG5cdFx0XHRcdG5ldyBJbnQoMHgxOWE0YzExNiwgMHhiOGQyZDBjOCksIG5ldyBJbnQoMHgxZTM3NmMwOCwgMHg1MTQxYWI1MyksXG5cdFx0XHRcdG5ldyBJbnQoMHgyNzQ4Nzc0YywgMHhkZjhlZWI5OSksIG5ldyBJbnQoMHgzNGIwYmNiNSwgMHhlMTliNDhhOCksXG5cdFx0XHRcdG5ldyBJbnQoMHgzOTFjMGNiMywgMHhjNWM5NWE2MyksIG5ldyBJbnQoMHg0ZWQ4YWE0YSwgMHhlMzQxOGFjYiksXG5cdFx0XHRcdG5ldyBJbnQoMHg1YjljY2E0ZiwgMHg3NzYzZTM3MyksIG5ldyBJbnQoMHg2ODJlNmZmMywgMHhkNmIyYjhhMyksXG5cdFx0XHRcdG5ldyBJbnQoMHg3NDhmODJlZSwgMHg1ZGVmYjJmYyksIG5ldyBJbnQoMHg3OGE1NjM2ZiwgMHg0MzE3MmY2MCksXG5cdFx0XHRcdG5ldyBJbnQoMHg4NGM4NzgxNCwgMHhhMWYwYWI3MiksIG5ldyBJbnQoMHg4Y2M3MDIwOCwgMHgxYTY0MzllYyksXG5cdFx0XHRcdG5ldyBJbnQoMHg5MGJlZmZmYSwgMHgyMzYzMWUyOCksIG5ldyBJbnQoMHhhNDUwNmNlYiwgMHhkZTgyYmRlOSksXG5cdFx0XHRcdG5ldyBJbnQoMHhiZWY5YTNmNywgMHhiMmM2NzkxNSksIG5ldyBJbnQoMHhjNjcxNzhmMiwgMHhlMzcyNTMyYiksXG5cdFx0XHRcdG5ldyBJbnQoMHhjYTI3M2VjZSwgMHhlYTI2NjE5YyksIG5ldyBJbnQoMHhkMTg2YjhjNywgMHgyMWMwYzIwNyksXG5cdFx0XHRcdG5ldyBJbnQoMHhlYWRhN2RkNiwgMHhjZGUwZWIxZSksIG5ldyBJbnQoMHhmNTdkNGY3ZiwgMHhlZTZlZDE3OCksXG5cdFx0XHRcdG5ldyBJbnQoMHgwNmYwNjdhYSwgMHg3MjE3NmZiYSksIG5ldyBJbnQoMHgwYTYzN2RjNSwgMHhhMmM4OThhNiksXG5cdFx0XHRcdG5ldyBJbnQoMHgxMTNmOTgwNCwgMHhiZWY5MGRhZSksIG5ldyBJbnQoMHgxYjcxMGIzNSwgMHgxMzFjNDcxYiksXG5cdFx0XHRcdG5ldyBJbnQoMHgyOGRiNzdmNSwgMHgyMzA0N2Q4NCksIG5ldyBJbnQoMHgzMmNhYWI3YiwgMHg0MGM3MjQ5MyksXG5cdFx0XHRcdG5ldyBJbnQoMHgzYzllYmUwYSwgMHgxNWM5YmViYyksIG5ldyBJbnQoMHg0MzFkNjdjNCwgMHg5YzEwMGQ0YyksXG5cdFx0XHRcdG5ldyBJbnQoMHg0Y2M1ZDRiZSwgMHhjYjNlNDJiNiksIG5ldyBJbnQoMHg1OTdmMjk5YywgMHhmYzY1N2UyYSksXG5cdFx0XHRcdG5ldyBJbnQoMHg1ZmNiNmZhYiwgMHgzYWQ2ZmFlYyksIG5ldyBJbnQoMHg2YzQ0MTk4YywgMHg0YTQ3NTgxNylcblx0XHRcdF07XG5cblx0XHRcdGlmICh2YXJpYW50ID09PSBcIlNIQS0zODRcIilcblx0XHRcdHtcblx0XHRcdFx0SCA9IFtcblx0XHRcdFx0XHRuZXcgSW50KDB4Y2JiYjlkNWQsIDB4YzEwNTllZDgpLCBuZXcgSW50KDB4MDYyOWEyOTJhLCAweDM2N2NkNTA3KSxcblx0XHRcdFx0XHRuZXcgSW50KDB4OTE1OTAxNWEsIDB4MzA3MGRkMTcpLCBuZXcgSW50KDB4MDE1MmZlY2Q4LCAweGY3MGU1OTM5KSxcblx0XHRcdFx0XHRuZXcgSW50KDB4NjczMzI2NjcsIDB4ZmZjMDBiMzEpLCBuZXcgSW50KDB4OThlYjQ0YTg3LCAweDY4NTgxNTExKSxcblx0XHRcdFx0XHRuZXcgSW50KDB4ZGIwYzJlMGQsIDB4NjRmOThmYTcpLCBuZXcgSW50KDB4MDQ3YjU0ODFkLCAweGJlZmE0ZmE0KVxuXHRcdFx0XHRdO1xuXHRcdFx0fVxuXHRcdFx0ZWxzZVxuXHRcdFx0e1xuXHRcdFx0XHRIID0gW1xuXHRcdFx0XHRcdG5ldyBJbnQoMHg2YTA5ZTY2NywgMHhmM2JjYzkwOCksIG5ldyBJbnQoMHhiYjY3YWU4NSwgMHg4NGNhYTczYiksXG5cdFx0XHRcdFx0bmV3IEludCgweDNjNmVmMzcyLCAweGZlOTRmODJiKSwgbmV3IEludCgweGE1NGZmNTNhLCAweDVmMWQzNmYxKSxcblx0XHRcdFx0XHRuZXcgSW50KDB4NTEwZTUyN2YsIDB4YWRlNjgyZDEpLCBuZXcgSW50KDB4OWIwNTY4OGMsIDB4MmIzZTZjMWYpLFxuXHRcdFx0XHRcdG5ldyBJbnQoMHgxZjgzZDlhYiwgMHhmYjQxYmQ2YiksIG5ldyBJbnQoMHg1YmUwY2QxOSwgMHgxMzdlMjE3OSlcblx0XHRcdFx0XTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHQvKiBBcHBlbmQgJzEnIGF0IHRoZSBlbmQgb2YgdGhlIGJpbmFyeSBzdHJpbmcgKi9cblx0XHRtZXNzYWdlW21lc3NhZ2VMZW4gPj4gNV0gfD0gMHg4MCA8PCAoMjQgLSBtZXNzYWdlTGVuICUgMzIpO1xuXHRcdC8qIEFwcGVuZCBsZW5ndGggb2YgYmluYXJ5IHN0cmluZyBpbiB0aGUgcG9zaXRpb24gc3VjaCB0aGF0IHRoZSBuZXdcblx0XHQgKiBsZW5ndGggaXMgY29ycmVjdCAqL1xuXHRcdG1lc3NhZ2VbbGVuZ3RoUG9zaXRpb25dID0gbWVzc2FnZUxlbjtcblxuXHRcdGFwcGVuZGVkTWVzc2FnZUxlbmd0aCA9IG1lc3NhZ2UubGVuZ3RoO1xuXG5cdFx0Zm9yIChpID0gMDsgaSA8IGFwcGVuZGVkTWVzc2FnZUxlbmd0aDsgaSArPSBiaW5hcnlTdHJpbmdJbmMpXG5cdFx0e1xuXHRcdFx0YSA9IEhbMF07XG5cdFx0XHRiID0gSFsxXTtcblx0XHRcdGMgPSBIWzJdO1xuXHRcdFx0ZCA9IEhbM107XG5cdFx0XHRlID0gSFs0XTtcblx0XHRcdGYgPSBIWzVdO1xuXHRcdFx0ZyA9IEhbNl07XG5cdFx0XHRoID0gSFs3XTtcblxuXHRcdFx0Zm9yICh0ID0gMDsgdCA8IG51bVJvdW5kczsgdCArPSAxKVxuXHRcdFx0e1xuXHRcdFx0XHRpZiAodCA8IDE2KVxuXHRcdFx0XHR7XG5cdFx0XHRcdFx0LyogQml0IG9mIGEgaGFjayAtIGZvciAzMi1iaXQsIHRoZSBzZWNvbmQgdGVybSBpcyBpZ25vcmVkICovXG5cdFx0XHRcdFx0V1t0XSA9IG5ldyBJbnQobWVzc2FnZVt0ICogYmluYXJ5U3RyaW5nTXVsdCArIGldLFxuXHRcdFx0XHRcdFx0XHRtZXNzYWdlW3QgKiBiaW5hcnlTdHJpbmdNdWx0ICsgaSArIDFdKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRlbHNlXG5cdFx0XHRcdHtcblx0XHRcdFx0XHRXW3RdID0gc2FmZUFkZF80KFxuXHRcdFx0XHRcdFx0XHRnYW1tYTEoV1t0IC0gMl0pLCBXW3QgLSA3XSxcblx0XHRcdFx0XHRcdFx0Z2FtbWEwKFdbdCAtIDE1XSksIFdbdCAtIDE2XVxuXHRcdFx0XHRcdFx0KTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdFQxID0gc2FmZUFkZF81KGgsIHNpZ21hMShlKSwgY2goZSwgZiwgZyksIEtbdF0sIFdbdF0pO1xuXHRcdFx0XHRUMiA9IHNhZmVBZGRfMihzaWdtYTAoYSksIG1haihhLCBiLCBjKSk7XG5cdFx0XHRcdGggPSBnO1xuXHRcdFx0XHRnID0gZjtcblx0XHRcdFx0ZiA9IGU7XG5cdFx0XHRcdGUgPSBzYWZlQWRkXzIoZCwgVDEpO1xuXHRcdFx0XHRkID0gYztcblx0XHRcdFx0YyA9IGI7XG5cdFx0XHRcdGIgPSBhO1xuXHRcdFx0XHRhID0gc2FmZUFkZF8yKFQxLCBUMik7XG5cdFx0XHR9XG5cblx0XHRcdEhbMF0gPSBzYWZlQWRkXzIoYSwgSFswXSk7XG5cdFx0XHRIWzFdID0gc2FmZUFkZF8yKGIsIEhbMV0pO1xuXHRcdFx0SFsyXSA9IHNhZmVBZGRfMihjLCBIWzJdKTtcblx0XHRcdEhbM10gPSBzYWZlQWRkXzIoZCwgSFszXSk7XG5cdFx0XHRIWzRdID0gc2FmZUFkZF8yKGUsIEhbNF0pO1xuXHRcdFx0SFs1XSA9IHNhZmVBZGRfMihmLCBIWzVdKTtcblx0XHRcdEhbNl0gPSBzYWZlQWRkXzIoZywgSFs2XSk7XG5cdFx0XHRIWzddID0gc2FmZUFkZF8yKGgsIEhbN10pO1xuXHRcdH1cblxuXHRcdHN3aXRjaCAodmFyaWFudClcblx0XHR7XG5cdFx0Y2FzZSBcIlNIQS0yMjRcIjpcblx0XHRcdHJldHVyblx0W1xuXHRcdFx0XHRIWzBdLCBIWzFdLCBIWzJdLCBIWzNdLFxuXHRcdFx0XHRIWzRdLCBIWzVdLCBIWzZdXG5cdFx0XHRdO1xuXHRcdGNhc2UgXCJTSEEtMjU2XCI6XG5cdFx0XHRyZXR1cm4gSDtcblx0XHRjYXNlIFwiU0hBLTM4NFwiOlxuXHRcdFx0cmV0dXJuIFtcblx0XHRcdFx0SFswXS5oaWdoT3JkZXIsIEhbMF0ubG93T3JkZXIsXG5cdFx0XHRcdEhbMV0uaGlnaE9yZGVyLCBIWzFdLmxvd09yZGVyLFxuXHRcdFx0XHRIWzJdLmhpZ2hPcmRlciwgSFsyXS5sb3dPcmRlcixcblx0XHRcdFx0SFszXS5oaWdoT3JkZXIsIEhbM10ubG93T3JkZXIsXG5cdFx0XHRcdEhbNF0uaGlnaE9yZGVyLCBIWzRdLmxvd09yZGVyLFxuXHRcdFx0XHRIWzVdLmhpZ2hPcmRlciwgSFs1XS5sb3dPcmRlclxuXHRcdFx0XTtcblx0XHRjYXNlIFwiU0hBLTUxMlwiOlxuXHRcdFx0cmV0dXJuIFtcblx0XHRcdFx0SFswXS5oaWdoT3JkZXIsIEhbMF0ubG93T3JkZXIsXG5cdFx0XHRcdEhbMV0uaGlnaE9yZGVyLCBIWzFdLmxvd09yZGVyLFxuXHRcdFx0XHRIWzJdLmhpZ2hPcmRlciwgSFsyXS5sb3dPcmRlcixcblx0XHRcdFx0SFszXS5oaWdoT3JkZXIsIEhbM10ubG93T3JkZXIsXG5cdFx0XHRcdEhbNF0uaGlnaE9yZGVyLCBIWzRdLmxvd09yZGVyLFxuXHRcdFx0XHRIWzVdLmhpZ2hPcmRlciwgSFs1XS5sb3dPcmRlcixcblx0XHRcdFx0SFs2XS5oaWdoT3JkZXIsIEhbNl0ubG93T3JkZXIsXG5cdFx0XHRcdEhbN10uaGlnaE9yZGVyLCBIWzddLmxvd09yZGVyXG5cdFx0XHRdO1xuXHRcdGRlZmF1bHQ6XG5cdFx0XHQvKiBUaGlzIHNob3VsZCBuZXZlciBiZSByZWFjaGVkICovXG5cdFx0XHRyZXR1cm4gW107IFxuXHRcdH1cblx0fSxcblxuXHQvKlxuXHQgKiBqc1NIQSBpcyB0aGUgd29ya2hvcnNlIG9mIHRoZSBsaWJyYXJ5LiAgSW5zdGFudGlhdGUgaXQgd2l0aCB0aGUgc3RyaW5nIHRvXG5cdCAqIGJlIGhhc2hlZCBhcyB0aGUgcGFyYW1ldGVyXG5cdCAqXG5cdCAqIEBjb25zdHJ1Y3RvclxuXHQgKiBAcGFyYW0ge1N0cmluZ30gc3JjU3RyaW5nIFRoZSBzdHJpbmcgdG8gYmUgaGFzaGVkXG5cdCAqIEBwYXJhbSB7U3RyaW5nfSBpbnB1dEZvcm1hdCBUaGUgZm9ybWF0IG9mIHNyY1N0cmluZywgQVNDSUkgb3IgSEVYXG5cdCAqL1xuXHRqc1NIQSA9IGZ1bmN0aW9uIChzcmNTdHJpbmcsIGlucHV0Rm9ybWF0KVxuXHR7XG5cblx0XHR0aGlzLnNoYTEgPSBudWxsO1xuXHRcdHRoaXMuc2hhMjI0ID0gbnVsbDtcblx0XHR0aGlzLnNoYTI1NiA9IG51bGw7XG5cdFx0dGhpcy5zaGEzODQgPSBudWxsO1xuXHRcdHRoaXMuc2hhNTEyID0gbnVsbDtcblxuXHRcdHRoaXMuc3RyQmluTGVuID0gbnVsbDtcblx0XHR0aGlzLnN0clRvSGFzaCA9IG51bGw7XG5cblx0XHQvKiBDb252ZXJ0IHRoZSBpbnB1dCBzdHJpbmcgaW50byB0aGUgY29ycmVjdCB0eXBlICovXG5cdFx0aWYgKFwiSEVYXCIgPT09IGlucHV0Rm9ybWF0KVxuXHRcdHtcblx0XHRcdGlmICgwICE9PSAoc3JjU3RyaW5nLmxlbmd0aCAlIDIpKVxuXHRcdFx0e1xuXHRcdFx0XHRyZXR1cm4gXCJURVhUIE1VU1QgQkUgSU4gQllURSBJTkNSRU1FTlRTXCI7XG5cdFx0XHR9XG5cdFx0XHR0aGlzLnN0ckJpbkxlbiA9IHNyY1N0cmluZy5sZW5ndGggKiA0O1xuXHRcdFx0dGhpcy5zdHJUb0hhc2ggPSBoZXgyYmluYihzcmNTdHJpbmcpO1xuXHRcdH1cblx0XHRlbHNlIGlmICgoXCJBU0NJSVwiID09PSBpbnB1dEZvcm1hdCkgfHxcblx0XHRcdCAoJ3VuZGVmaW5lZCcgPT09IHR5cGVvZihpbnB1dEZvcm1hdCkpKVxuXHRcdHtcblx0XHRcdHRoaXMuc3RyQmluTGVuID0gc3JjU3RyaW5nLmxlbmd0aCAqIGNoYXJTaXplO1xuXHRcdFx0dGhpcy5zdHJUb0hhc2ggPSBzdHIyYmluYihzcmNTdHJpbmcpO1xuXHRcdH1cblx0XHRlbHNlXG5cdFx0e1xuXHRcdFx0cmV0dXJuIFwiVU5LTk9XTiBURVhUIElOUFVUIFRZUEVcIjtcblx0XHR9XG5cdH07XG5cblx0anNTSEEucHJvdG90eXBlID0ge1xuXHRcdC8qXG5cdFx0ICogUmV0dXJucyB0aGUgZGVzaXJlZCBTSEEgaGFzaCBvZiB0aGUgc3RyaW5nIHNwZWNpZmllZCBhdCBpbnN0YW50aWF0aW9uXG5cdFx0ICogdXNpbmcgdGhlIHNwZWNpZmllZCBwYXJhbWV0ZXJzXG5cdFx0ICpcblx0XHQgKiBAcGFyYW0ge1N0cmluZ30gdmFyaWFudCBUaGUgZGVzaXJlZCBTSEEgdmFyaWFudCAoU0hBLTEsIFNIQS0yMjQsXG5cdFx0ICpcdCBTSEEtMjU2LCBTSEEtMzg0LCBvciBTSEEtNTEyKVxuXHRcdCAqIEBwYXJhbSB7U3RyaW5nfSBmb3JtYXQgVGhlIGRlc2lyZWQgb3V0cHV0IGZvcm1hdHRpbmcgKEI2NCBvciBIRVgpXG5cdFx0ICogQHJldHVybiBUaGUgc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBoYXNoIGluIHRoZSBmb3JtYXQgc3BlY2lmaWVkXG5cdFx0ICovXG5cdFx0Z2V0SGFzaCA6IGZ1bmN0aW9uICh2YXJpYW50LCBmb3JtYXQpXG5cdFx0e1xuXHRcdFx0dmFyIGZvcm1hdEZ1bmMgPSBudWxsLCBtZXNzYWdlID0gdGhpcy5zdHJUb0hhc2guc2xpY2UoKTtcblxuXHRcdFx0c3dpdGNoIChmb3JtYXQpXG5cdFx0XHR7XG5cdFx0XHRjYXNlIFwiSEVYXCI6XG5cdFx0XHRcdGZvcm1hdEZ1bmMgPSBiaW5iMmhleDtcblx0XHRcdFx0YnJlYWs7XG5cdFx0XHRjYXNlIFwiQjY0XCI6XG5cdFx0XHRcdGZvcm1hdEZ1bmMgPSBiaW5iMmI2NDtcblx0XHRcdFx0YnJlYWs7XG5cdFx0XHRjYXNlIFwiQVNDSUlcIjpcblx0XHRcdFx0Zm9ybWF0RnVuYyA9IGJpbmIyc3RyO1xuXHRcdFx0XHRicmVhaztcblx0XHRcdGRlZmF1bHQ6XG5cdFx0XHRcdHJldHVybiBcIkZPUk1BVCBOT1QgUkVDT0dOSVpFRFwiO1xuXHRcdFx0fVxuXG5cdFx0XHRzd2l0Y2ggKHZhcmlhbnQpXG5cdFx0XHR7XG5cdFx0XHRjYXNlIFwiU0hBLTFcIjpcblx0XHRcdFx0aWYgKG51bGwgPT09IHRoaXMuc2hhMSlcblx0XHRcdFx0e1xuXHRcdFx0XHRcdHRoaXMuc2hhMSA9IGNvcmVTSEExKG1lc3NhZ2UsIHRoaXMuc3RyQmluTGVuKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRyZXR1cm4gZm9ybWF0RnVuYyh0aGlzLnNoYTEpO1xuXHRcdFx0Y2FzZSBcIlNIQS0yMjRcIjpcblx0XHRcdFx0aWYgKG51bGwgPT09IHRoaXMuc2hhMjI0KVxuXHRcdFx0XHR7XG5cdFx0XHRcdFx0dGhpcy5zaGEyMjQgPSBjb3JlU0hBMihtZXNzYWdlLCB0aGlzLnN0ckJpbkxlbiwgdmFyaWFudCk7XG5cdFx0XHRcdH1cblx0XHRcdFx0cmV0dXJuIGZvcm1hdEZ1bmModGhpcy5zaGEyMjQpO1xuXHRcdFx0Y2FzZSBcIlNIQS0yNTZcIjpcblx0XHRcdFx0aWYgKG51bGwgPT09IHRoaXMuc2hhMjU2KVxuXHRcdFx0XHR7XG5cdFx0XHRcdFx0dGhpcy5zaGEyNTYgPSBjb3JlU0hBMihtZXNzYWdlLCB0aGlzLnN0ckJpbkxlbiwgdmFyaWFudCk7XG5cdFx0XHRcdH1cblx0XHRcdFx0cmV0dXJuIGZvcm1hdEZ1bmModGhpcy5zaGEyNTYpO1xuXHRcdFx0Y2FzZSBcIlNIQS0zODRcIjpcblx0XHRcdFx0aWYgKG51bGwgPT09IHRoaXMuc2hhMzg0KVxuXHRcdFx0XHR7XG5cdFx0XHRcdFx0dGhpcy5zaGEzODQgPSBjb3JlU0hBMihtZXNzYWdlLCB0aGlzLnN0ckJpbkxlbiwgdmFyaWFudCk7XG5cdFx0XHRcdH1cblx0XHRcdFx0cmV0dXJuIGZvcm1hdEZ1bmModGhpcy5zaGEzODQpO1xuXHRcdFx0Y2FzZSBcIlNIQS01MTJcIjpcblx0XHRcdFx0aWYgKG51bGwgPT09IHRoaXMuc2hhNTEyKVxuXHRcdFx0XHR7XG5cdFx0XHRcdFx0dGhpcy5zaGE1MTIgPSBjb3JlU0hBMihtZXNzYWdlLCB0aGlzLnN0ckJpbkxlbiwgdmFyaWFudCk7XG5cdFx0XHRcdH1cblx0XHRcdFx0cmV0dXJuIGZvcm1hdEZ1bmModGhpcy5zaGE1MTIpO1xuXHRcdFx0ZGVmYXVsdDpcblx0XHRcdFx0cmV0dXJuIFwiSEFTSCBOT1QgUkVDT0dOSVpFRFwiO1xuXHRcdFx0fVxuXHRcdH0sXG5cblx0XHQvKlxuXHRcdCAqIFJldHVybnMgdGhlIGRlc2lyZWQgSE1BQyBvZiB0aGUgc3RyaW5nIHNwZWNpZmllZCBhdCBpbnN0YW50aWF0aW9uXG5cdFx0ICogdXNpbmcgdGhlIGtleSBhbmQgdmFyaWFudCBwYXJhbS5cblx0XHQgKlxuXHRcdCAqIEBwYXJhbSB7U3RyaW5nfSBrZXkgVGhlIGtleSB1c2VkIHRvIGNhbGN1bGF0ZSB0aGUgSE1BQ1xuXHRcdCAqIEBwYXJhbSB7U3RyaW5nfSBpbnB1dEZvcm1hdCBUaGUgZm9ybWF0IG9mIGtleSwgQVNDSUkgb3IgSEVYXG5cdFx0ICogQHBhcmFtIHtTdHJpbmd9IHZhcmlhbnQgVGhlIGRlc2lyZWQgU0hBIHZhcmlhbnQgKFNIQS0xLCBTSEEtMjI0LFxuXHRcdCAqXHQgU0hBLTI1NiwgU0hBLTM4NCwgb3IgU0hBLTUxMilcblx0XHQgKiBAcGFyYW0ge1N0cmluZ30gb3V0cHV0Rm9ybWF0IFRoZSBkZXNpcmVkIG91dHB1dCBmb3JtYXR0aW5nXG5cdFx0ICpcdCAoQjY0IG9yIEhFWClcblx0XHQgKiBAcmV0dXJuIFRoZSBzdHJpbmcgcmVwcmVzZW50YXRpb24gb2YgdGhlIGhhc2ggaW4gdGhlIGZvcm1hdCBzcGVjaWZpZWRcblx0XHQgKi9cblx0XHRnZXRITUFDIDogZnVuY3Rpb24gKGtleSwgaW5wdXRGb3JtYXQsIHZhcmlhbnQsIG91dHB1dEZvcm1hdClcblx0XHR7XG5cdFx0XHR2YXIgZm9ybWF0RnVuYywga2V5VG9Vc2UsIGJsb2NrQnl0ZVNpemUsIGJsb2NrQml0U2l6ZSwgaSxcblx0XHRcdFx0cmV0VmFsLCBsYXN0QXJyYXlJbmRleCwga2V5QmluTGVuLCBoYXNoQml0U2l6ZSxcblx0XHRcdFx0a2V5V2l0aElQYWQgPSBbXSwga2V5V2l0aE9QYWQgPSBbXTtcblxuXHRcdFx0LyogVmFsaWRhdGUgdGhlIG91dHB1dCBmb3JtYXQgc2VsZWN0aW9uICovXG5cdFx0XHRzd2l0Y2ggKG91dHB1dEZvcm1hdClcblx0XHRcdHtcblx0XHRcdGNhc2UgXCJIRVhcIjpcblx0XHRcdFx0Zm9ybWF0RnVuYyA9IGJpbmIyaGV4O1xuXHRcdFx0XHRicmVhaztcblx0XHRcdGNhc2UgXCJCNjRcIjpcblx0XHRcdFx0Zm9ybWF0RnVuYyA9IGJpbmIyYjY0O1xuXHRcdFx0XHRicmVhaztcblx0XHRcdGNhc2UgXCJBU0NJSVwiOlxuXHRcdFx0XHRmb3JtYXRGdW5jID0gYmluYjJzdHI7XG5cdFx0XHRcdGJyZWFrO1xuXHRcdFx0ZGVmYXVsdDpcblx0XHRcdFx0cmV0dXJuIFwiRk9STUFUIE5PVCBSRUNPR05JWkVEXCI7XG5cdFx0XHR9XG5cblx0XHRcdC8qIFZhbGlkYXRlIHRoZSBoYXNoIHZhcmlhbnQgc2VsZWN0aW9uIGFuZCBzZXQgbmVlZGVkIHZhcmlhYmxlcyAqL1xuXHRcdFx0c3dpdGNoICh2YXJpYW50KVxuXHRcdFx0e1xuXHRcdFx0Y2FzZSBcIlNIQS0xXCI6XG5cdFx0XHRcdGJsb2NrQnl0ZVNpemUgPSA2NDtcblx0XHRcdFx0aGFzaEJpdFNpemUgPSAxNjA7XG5cdFx0XHRcdGJyZWFrO1xuXHRcdFx0Y2FzZSBcIlNIQS0yMjRcIjpcblx0XHRcdFx0YmxvY2tCeXRlU2l6ZSA9IDY0O1xuXHRcdFx0XHRoYXNoQml0U2l6ZSA9IDIyNDtcblx0XHRcdFx0YnJlYWs7XG5cdFx0XHRjYXNlIFwiU0hBLTI1NlwiOlxuXHRcdFx0XHRibG9ja0J5dGVTaXplID0gNjQ7XG5cdFx0XHRcdGhhc2hCaXRTaXplID0gMjU2O1xuXHRcdFx0XHRicmVhaztcblx0XHRcdGNhc2UgXCJTSEEtMzg0XCI6XG5cdFx0XHRcdGJsb2NrQnl0ZVNpemUgPSAxMjg7XG5cdFx0XHRcdGhhc2hCaXRTaXplID0gMzg0O1xuXHRcdFx0XHRicmVhaztcblx0XHRcdGNhc2UgXCJTSEEtNTEyXCI6XG5cdFx0XHRcdGJsb2NrQnl0ZVNpemUgPSAxMjg7XG5cdFx0XHRcdGhhc2hCaXRTaXplID0gNTEyO1xuXHRcdFx0XHRicmVhaztcblx0XHRcdGRlZmF1bHQ6XG5cdFx0XHRcdHJldHVybiBcIkhBU0ggTk9UIFJFQ09HTklaRURcIjtcblx0XHRcdH1cblxuXHRcdFx0LyogVmFsaWRhdGUgaW5wdXQgZm9ybWF0IHNlbGVjdGlvbiAqL1xuXHRcdFx0aWYgKFwiSEVYXCIgPT09IGlucHV0Rm9ybWF0KVxuXHRcdFx0e1xuXHRcdFx0XHQvKiBOaWJibGVzIG11c3QgY29tZSBpbiBwYWlycyAqL1xuXHRcdFx0XHRpZiAoMCAhPT0gKGtleS5sZW5ndGggJSAyKSlcblx0XHRcdFx0e1xuXHRcdFx0XHRcdHJldHVybiBcIktFWSBNVVNUIEJFIElOIEJZVEUgSU5DUkVNRU5UU1wiO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGtleVRvVXNlID0gaGV4MmJpbmIoa2V5KTtcblx0XHRcdFx0a2V5QmluTGVuID0ga2V5Lmxlbmd0aCAqIDQ7XG5cdFx0XHR9XG5cdFx0XHRlbHNlIGlmIChcIkFTQ0lJXCIgPT09IGlucHV0Rm9ybWF0KVxuXHRcdFx0e1xuXHRcdFx0XHRrZXlUb1VzZSA9IHN0cjJiaW5iKGtleSk7XG5cdFx0XHRcdGtleUJpbkxlbiA9IGtleS5sZW5ndGggKiBjaGFyU2l6ZTtcblx0XHRcdH1cblx0XHRcdGVsc2Vcblx0XHRcdHtcblx0XHRcdFx0cmV0dXJuIFwiVU5LTk9XTiBLRVkgSU5QVVQgVFlQRVwiO1xuXHRcdFx0fVxuXG5cdFx0XHQvKiBUaGVzZSBhcmUgdXNlZCBtdWx0aXBsZSB0aW1lcywgY2FsY3VsYXRlIGFuZCBzdG9yZSB0aGVtICovXG5cdFx0XHRibG9ja0JpdFNpemUgPSBibG9ja0J5dGVTaXplICogODtcblx0XHRcdGxhc3RBcnJheUluZGV4ID0gKGJsb2NrQnl0ZVNpemUgLyA0KSAtIDE7XG5cblx0XHRcdC8qIEZpZ3VyZSBvdXQgd2hhdCB0byBkbyB3aXRoIHRoZSBrZXkgYmFzZWQgb24gaXRzIHNpemUgcmVsYXRpdmUgdG9cblx0XHRcdCAqIHRoZSBoYXNoJ3MgYmxvY2sgc2l6ZSAqL1xuXHRcdFx0aWYgKGJsb2NrQnl0ZVNpemUgPCAoa2V5QmluTGVuIC8gOCkpXG5cdFx0XHR7XG5cdFx0XHRcdGlmIChcIlNIQS0xXCIgPT09IHZhcmlhbnQpXG5cdFx0XHRcdHtcblx0XHRcdFx0XHRrZXlUb1VzZSA9IGNvcmVTSEExKGtleVRvVXNlLCBrZXlCaW5MZW4pO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGVsc2Vcblx0XHRcdFx0e1xuXHRcdFx0XHRcdGtleVRvVXNlID0gY29yZVNIQTIoa2V5VG9Vc2UsIGtleUJpbkxlbiwgdmFyaWFudCk7XG5cdFx0XHRcdH1cblx0XHRcdFx0LyogRm9yIGFsbCB2YXJpYW50cywgdGhlIGJsb2NrIHNpemUgaXMgYmlnZ2VyIHRoYW4gdGhlIG91dHB1dFxuXHRcdFx0XHQgKiBzaXplIHNvIHRoZXJlIHdpbGwgbmV2ZXIgYmUgYSB1c2VmdWwgYnl0ZSBhdCB0aGUgZW5kIG9mIHRoZVxuXHRcdFx0XHQgKiBzdHJpbmcgKi9cblx0XHRcdFx0a2V5VG9Vc2VbbGFzdEFycmF5SW5kZXhdICY9IDB4RkZGRkZGMDA7XG5cdFx0XHR9XG5cdFx0XHRlbHNlIGlmIChibG9ja0J5dGVTaXplID4gKGtleUJpbkxlbiAvIDgpKVxuXHRcdFx0e1xuXHRcdFx0XHQvKiBJZiB0aGUgYmxvY2tCeXRlU2l6ZSBpcyBncmVhdGVyIHRoYW4gdGhlIGtleSBsZW5ndGgsIHRoZXJlXG5cdFx0XHRcdCAqIHdpbGwgYWx3YXlzIGJlIGF0IExFQVNUIG9uZSBcInVzZWxlc3NcIiBieXRlIGF0IHRoZSBlbmQgb2YgdGhlXG5cdFx0XHRcdCAqIHN0cmluZyAqL1xuXHRcdFx0XHRrZXlUb1VzZVtsYXN0QXJyYXlJbmRleF0gJj0gMHhGRkZGRkYwMDtcblx0XHRcdH1cblxuXHRcdFx0LyogQ3JlYXRlIGlwYWQgYW5kIG9wYWQgKi9cblx0XHRcdGZvciAoaSA9IDA7IGkgPD0gbGFzdEFycmF5SW5kZXg7IGkgKz0gMSlcblx0XHRcdHtcblx0XHRcdFx0a2V5V2l0aElQYWRbaV0gPSBrZXlUb1VzZVtpXSBeIDB4MzYzNjM2MzY7XG5cdFx0XHRcdGtleVdpdGhPUGFkW2ldID0ga2V5VG9Vc2VbaV0gXiAweDVDNUM1QzVDO1xuXHRcdFx0fVxuXG5cdFx0XHQvKiBDYWxjdWxhdGUgdGhlIEhNQUMgKi9cblx0XHRcdGlmIChcIlNIQS0xXCIgPT09IHZhcmlhbnQpXG5cdFx0XHR7XG5cdFx0XHRcdHJldFZhbCA9IGNvcmVTSEExKFxuXHRcdFx0XHRcdFx0XHRrZXlXaXRoSVBhZC5jb25jYXQodGhpcy5zdHJUb0hhc2gpLFxuXHRcdFx0XHRcdFx0XHRibG9ja0JpdFNpemUgKyB0aGlzLnN0ckJpbkxlbik7XG5cdFx0XHRcdHJldFZhbCA9IGNvcmVTSEExKFxuXHRcdFx0XHRcdFx0XHRrZXlXaXRoT1BhZC5jb25jYXQocmV0VmFsKSxcblx0XHRcdFx0XHRcdFx0YmxvY2tCaXRTaXplICsgaGFzaEJpdFNpemUpO1xuXHRcdFx0fVxuXHRcdFx0ZWxzZVxuXHRcdFx0e1xuXHRcdFx0XHRyZXRWYWwgPSBjb3JlU0hBMihcblx0XHRcdFx0XHRcdFx0a2V5V2l0aElQYWQuY29uY2F0KHRoaXMuc3RyVG9IYXNoKSxcblx0XHRcdFx0XHRcdFx0YmxvY2tCaXRTaXplICsgdGhpcy5zdHJCaW5MZW4sIHZhcmlhbnQpO1xuXHRcdFx0XHRyZXRWYWwgPSBjb3JlU0hBMihcblx0XHRcdFx0XHRcdFx0a2V5V2l0aE9QYWQuY29uY2F0KHJldFZhbCksXG5cdFx0XHRcdFx0XHRcdGJsb2NrQml0U2l6ZSArIGhhc2hCaXRTaXplLCB2YXJpYW50KTtcblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIChmb3JtYXRGdW5jKHJldFZhbCkpO1xuXHRcdH1cblx0fTtcblxuXHRyZXR1cm4ganNTSEE7XG59KCkpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IHtcblx0c2hhMTogZnVuY3Rpb24oc3RyKSB7XG5cdFx0dmFyIHNoYU9iaiA9IG5ldyBqc1NIQShzdHIsIFwiQVNDSUlcIik7XG5cdFx0cmV0dXJuIHNoYU9iai5nZXRIYXNoKFwiU0hBLTFcIiwgXCJBU0NJSVwiKTtcblx0fSxcblx0c2hhMjI0OiBmdW5jdGlvbihzdHIpIHtcblx0XHR2YXIgc2hhT2JqID0gbmV3IGpzU0hBKHN0ciwgXCJBU0NJSVwiKTtcblx0XHRyZXR1cm4gc2hhT2JqLmdldEhhc2goXCJTSEEtMjI0XCIsIFwiQVNDSUlcIik7XG5cdH0sXG5cdHNoYTI1NjogZnVuY3Rpb24oc3RyKSB7XG5cdFx0dmFyIHNoYU9iaiA9IG5ldyBqc1NIQShzdHIsIFwiQVNDSUlcIik7XG5cdFx0cmV0dXJuIHNoYU9iai5nZXRIYXNoKFwiU0hBLTI1NlwiLCBcIkFTQ0lJXCIpO1xuXHR9LFxuXHRzaGEzODQ6IGZ1bmN0aW9uKHN0cikge1xuXHRcdHZhciBzaGFPYmogPSBuZXcganNTSEEoc3RyLCBcIkFTQ0lJXCIpO1xuXHRcdHJldHVybiBzaGFPYmouZ2V0SGFzaChcIlNIQS0zODRcIiwgXCJBU0NJSVwiKTtcblxuXHR9LFxuXHRzaGE1MTI6IGZ1bmN0aW9uKHN0cikge1xuXHRcdHZhciBzaGFPYmogPSBuZXcganNTSEEoc3RyLCBcIkFTQ0lJXCIpO1xuXHRcdHJldHVybiBzaGFPYmouZ2V0SGFzaChcIlNIQS01MTJcIiwgXCJBU0NJSVwiKTtcblx0fVxufVxuIiwiLypcbiAqIENyeXB0b01YIFRvb2xzXG4gKiBDb3B5cmlnaHQgKEMpIDIwMDQgLSAyMDA2IERlcmVrIEJ1aXRlbmh1aXNcbiAqXG4gKiBUaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yXG4gKiBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuICogYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlciB2ZXJzaW9uIDJcbiAqIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuICpcbiAqIFRoaXMgcHJvZ3JhbSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuICogYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2ZcbiAqIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGVcbiAqIEdOVSBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG4gKlxuICogWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAqIGFsb25nIHdpdGggdGhpcyBwcm9ncmFtOyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlXG4gKiBGb3VuZGF0aW9uLCBJbmMuLCA1OSBUZW1wbGUgUGxhY2UgLSBTdWl0ZSAzMzAsIEJvc3RvbiwgTUEgIDAyMTExLTEzMDcsIFVTQS5cbiAqL1xuXG4vKiBNb2RpZmllZCBieSBSZWN1cml0eSBMYWJzIEdtYkhcbiAqL1xuXG52YXIgUk1Ec2l6ZSAgID0gMTYwO1xudmFyIFggPSBuZXcgQXJyYXkoKTtcblxuZnVuY3Rpb24gUk9MKHgsIG4pXG57XG4gIHJldHVybiBuZXcgTnVtYmVyICgoeCA8PCBuKSB8ICggeCA+Pj4gKDMyIC0gbikpKTtcbn1cblxuZnVuY3Rpb24gRih4LCB5LCB6KVxue1xuICByZXR1cm4gbmV3IE51bWJlcih4IF4geSBeIHopO1xufVxuXG5mdW5jdGlvbiBHKHgsIHksIHopXG57XG4gIHJldHVybiBuZXcgTnVtYmVyKCh4ICYgeSkgfCAofnggJiB6KSk7XG59XG5cbmZ1bmN0aW9uIEgoeCwgeSwgeilcbntcbiAgcmV0dXJuIG5ldyBOdW1iZXIoKHggfCB+eSkgXiB6KTtcbn1cblxuZnVuY3Rpb24gSSh4LCB5LCB6KVxue1xuICByZXR1cm4gbmV3IE51bWJlcigoeCAmIHopIHwgKHkgJiB+eikpO1xufVxuXG5mdW5jdGlvbiBKKHgsIHksIHopXG57XG4gIHJldHVybiBuZXcgTnVtYmVyKHggXiAoeSB8IH56KSk7XG59XG5cbmZ1bmN0aW9uIG1peE9uZVJvdW5kKGEsIGIsIGMsIGQsIGUsIHgsIHMsIHJvdW5kTnVtYmVyKVxue1xuICBzd2l0Y2ggKHJvdW5kTnVtYmVyKVxuICB7XG4gICAgY2FzZSAwIDogYSArPSBGKGIsIGMsIGQpICsgeCArIDB4MDAwMDAwMDA7IGJyZWFrO1xuICAgIGNhc2UgMSA6IGEgKz0gRyhiLCBjLCBkKSArIHggKyAweDVhODI3OTk5OyBicmVhaztcbiAgICBjYXNlIDIgOiBhICs9IEgoYiwgYywgZCkgKyB4ICsgMHg2ZWQ5ZWJhMTsgYnJlYWs7XG4gICAgY2FzZSAzIDogYSArPSBJKGIsIGMsIGQpICsgeCArIDB4OGYxYmJjZGM7IGJyZWFrO1xuICAgIGNhc2UgNCA6IGEgKz0gSihiLCBjLCBkKSArIHggKyAweGE5NTNmZDRlOyBicmVhaztcbiAgICBjYXNlIDUgOiBhICs9IEooYiwgYywgZCkgKyB4ICsgMHg1MGEyOGJlNjsgYnJlYWs7XG4gICAgY2FzZSA2IDogYSArPSBJKGIsIGMsIGQpICsgeCArIDB4NWM0ZGQxMjQ7IGJyZWFrO1xuICAgIGNhc2UgNyA6IGEgKz0gSChiLCBjLCBkKSArIHggKyAweDZkNzAzZWYzOyBicmVhaztcbiAgICBjYXNlIDggOiBhICs9IEcoYiwgYywgZCkgKyB4ICsgMHg3YTZkNzZlOTsgYnJlYWs7XG4gICAgY2FzZSA5IDogYSArPSBGKGIsIGMsIGQpICsgeCArIDB4MDAwMDAwMDA7IGJyZWFrO1xuICAgIFxuICAgIGRlZmF1bHQgOiBkb2N1bWVudC53cml0ZShcIkJvZ3VzIHJvdW5kIG51bWJlclwiKTsgYnJlYWs7XG4gIH0gIFxuICBcbiAgYSA9IFJPTChhLCBzKSArIGU7XG4gIGMgPSBST0woYywgMTApO1xuXG4gIGEgJj0gMHhmZmZmZmZmZjtcbiAgYiAmPSAweGZmZmZmZmZmO1xuICBjICY9IDB4ZmZmZmZmZmY7XG4gIGQgJj0gMHhmZmZmZmZmZjtcbiAgZSAmPSAweGZmZmZmZmZmO1xuXG4gIHZhciByZXRCbG9jayA9IG5ldyBBcnJheSgpO1xuICByZXRCbG9ja1swXSA9IGE7XG4gIHJldEJsb2NrWzFdID0gYjtcbiAgcmV0QmxvY2tbMl0gPSBjO1xuICByZXRCbG9ja1szXSA9IGQ7XG4gIHJldEJsb2NrWzRdID0gZTtcbiAgcmV0QmxvY2tbNV0gPSB4O1xuICByZXRCbG9ja1s2XSA9IHM7XG5cbiAgcmV0dXJuIHJldEJsb2NrO1xufVxuXG5mdW5jdGlvbiBNRGluaXQgKE1EYnVmKVxue1xuICBNRGJ1ZlswXSA9IDB4Njc0NTIzMDE7XG4gIE1EYnVmWzFdID0gMHhlZmNkYWI4OTtcbiAgTURidWZbMl0gPSAweDk4YmFkY2ZlO1xuICBNRGJ1ZlszXSA9IDB4MTAzMjU0NzY7XG4gIE1EYnVmWzRdID0gMHhjM2QyZTFmMDtcbn1cblxudmFyIFJPTHMgPSBbXG4gIFsxMSwgMTQsIDE1LCAxMiwgIDUsICA4LCAgNywgIDksIDExLCAxMywgMTQsIDE1LCAgNiwgIDcsICA5LCAgOF0sXG4gIFsgNywgIDYsICA4LCAxMywgMTEsICA5LCAgNywgMTUsICA3LCAxMiwgMTUsICA5LCAxMSwgIDcsIDEzLCAxMl0sXG4gIFsxMSwgMTMsICA2LCAgNywgMTQsICA5LCAxMywgMTUsIDE0LCAgOCwgMTMsICA2LCAgNSwgMTIsICA3LCAgNV0sXG4gIFsxMSwgMTIsIDE0LCAxNSwgMTQsIDE1LCAgOSwgIDgsICA5LCAxNCwgIDUsICA2LCAgOCwgIDYsICA1LCAxMl0sXG4gIFsgOSwgMTUsICA1LCAxMSwgIDYsICA4LCAxMywgMTIsICA1LCAxMiwgMTMsIDE0LCAxMSwgIDgsICA1LCAgNl0sXG4gIFsgOCwgIDksICA5LCAxMSwgMTMsIDE1LCAxNSwgIDUsICA3LCAgNywgIDgsIDExLCAxNCwgMTQsIDEyLCAgNl0sXG4gIFsgOSwgMTMsIDE1LCAgNywgMTIsICA4LCAgOSwgMTEsICA3LCAgNywgMTIsICA3LCAgNiwgMTUsIDEzLCAxMV0sXG4gIFsgOSwgIDcsIDE1LCAxMSwgIDgsICA2LCAgNiwgMTQsIDEyLCAxMywgIDUsIDE0LCAxMywgMTMsICA3LCAgNV0sXG4gIFsxNSwgIDUsICA4LCAxMSwgMTQsIDE0LCAgNiwgMTQsICA2LCAgOSwgMTIsICA5LCAxMiwgIDUsIDE1LCAgOF0sXG4gIFsgOCwgIDUsIDEyLCAgOSwgMTIsICA1LCAxNCwgIDYsICA4LCAxMywgIDYsICA1LCAxNSwgMTMsIDExLCAxMV1cbl07XG5cbnZhciBpbmRleGVzID0gW1xuICBbIDAsICAxLCAgMiwgIDMsICA0LCAgNSwgIDYsICA3LCAgOCwgIDksIDEwLCAxMSwgMTIsIDEzLCAxNCwgMTVdLFxuICBbIDcsICA0LCAxMywgIDEsIDEwLCAgNiwgMTUsICAzLCAxMiwgIDAsICA5LCAgNSwgIDIsIDE0LCAxMSwgIDhdLFxuICBbIDMsIDEwLCAxNCwgIDQsICA5LCAxNSwgIDgsICAxLCAgMiwgIDcsICAwLCAgNiwgMTMsIDExLCAgNSwgMTJdLFxuICBbIDEsICA5LCAxMSwgMTAsICAwLCAgOCwgMTIsICA0LCAxMywgIDMsICA3LCAxNSwgMTQsICA1LCAgNiwgIDJdLFxuICBbIDQsICAwLCAgNSwgIDksICA3LCAxMiwgIDIsIDEwLCAxNCwgIDEsICAzLCAgOCwgMTEsICA2LCAxNSwgMTNdLFxuICBbIDUsIDE0LCAgNywgIDAsICA5LCAgMiwgMTEsICA0LCAxMywgIDYsIDE1LCAgOCwgIDEsIDEwLCAgMywgMTJdLFxuICBbIDYsIDExLCAgMywgIDcsICAwLCAxMywgIDUsIDEwLCAxNCwgMTUsICA4LCAxMiwgIDQsICA5LCAgMSwgIDJdLFxuICBbMTUsICA1LCAgMSwgIDMsICA3LCAxNCwgIDYsICA5LCAxMSwgIDgsIDEyLCAgMiwgMTAsICAwLCAgNCwgMTNdLFxuICBbIDgsICA2LCAgNCwgIDEsICAzLCAxMSwgMTUsICAwLCAgNSwgMTIsICAyLCAxMywgIDksICA3LCAxMCwgMTRdLFxuICBbMTIsIDE1LCAxMCwgIDQsICAxLCAgNSwgIDgsICA3LCAgNiwgIDIsIDEzLCAxNCwgIDAsICAzLCAgOSwgMTFdXG5dO1xuXG5mdW5jdGlvbiBjb21wcmVzcyAoTURidWYsIFgpXG57XG4gIGJsb2NrQSA9IG5ldyBBcnJheSgpO1xuICBibG9ja0IgPSBuZXcgQXJyYXkoKTtcblxuICB2YXIgcmV0QmxvY2s7XG5cbiAgZm9yICh2YXIgaT0wOyBpIDwgNTsgaSsrKVxuICB7XG4gICAgYmxvY2tBW2ldID0gbmV3IE51bWJlcihNRGJ1ZltpXSk7XG4gICAgYmxvY2tCW2ldID0gbmV3IE51bWJlcihNRGJ1ZltpXSk7XG4gIH1cblxuICB2YXIgc3RlcCA9IDA7XG4gIGZvciAodmFyIGogPSAwOyBqIDwgNTsgaisrKVxuICB7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCAxNjsgaSsrKVxuICAgIHtcbiAgICAgIHJldEJsb2NrID0gbWl4T25lUm91bmQoXG4gICAgICAgIGJsb2NrQVsoc3RlcCswKSAlIDVdLFxuICAgICAgICBibG9ja0FbKHN0ZXArMSkgJSA1XSwgICBcbiAgICAgICAgYmxvY2tBWyhzdGVwKzIpICUgNV0sICAgXG4gICAgICAgIGJsb2NrQVsoc3RlcCszKSAlIDVdLCAgIFxuICAgICAgICBibG9ja0FbKHN0ZXArNCkgJSA1XSwgIFxuICAgICAgICBYW2luZGV4ZXNbal1baV1dLCBcbiAgICAgICAgUk9Mc1tqXVtpXSxcbiAgICAgICAgalxuICAgICAgKTtcblxuICAgICAgYmxvY2tBWyhzdGVwKzApICUgNV0gPSByZXRCbG9ja1swXTtcbiAgICAgIGJsb2NrQVsoc3RlcCsxKSAlIDVdID0gcmV0QmxvY2tbMV07XG4gICAgICBibG9ja0FbKHN0ZXArMikgJSA1XSA9IHJldEJsb2NrWzJdO1xuICAgICAgYmxvY2tBWyhzdGVwKzMpICUgNV0gPSByZXRCbG9ja1szXTtcbiAgICAgIGJsb2NrQVsoc3RlcCs0KSAlIDVdID0gcmV0QmxvY2tbNF07XG5cbiAgICAgIHN0ZXAgKz0gNDtcbiAgICB9XG4gIH1cblxuICBzdGVwID0gMDtcbiAgZm9yICh2YXIgaiA9IDU7IGogPCAxMDsgaisrKVxuICB7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCAxNjsgaSsrKVxuICAgIHsgIFxuICAgICAgcmV0QmxvY2sgPSBtaXhPbmVSb3VuZChcbiAgICAgICAgYmxvY2tCWyhzdGVwKzApICUgNV0sIFxuICAgICAgICBibG9ja0JbKHN0ZXArMSkgJSA1XSwgXG4gICAgICAgIGJsb2NrQlsoc3RlcCsyKSAlIDVdLCBcbiAgICAgICAgYmxvY2tCWyhzdGVwKzMpICUgNV0sIFxuICAgICAgICBibG9ja0JbKHN0ZXArNCkgJSA1XSwgIFxuICAgICAgICBYW2luZGV4ZXNbal1baV1dLCBcbiAgICAgICAgUk9Mc1tqXVtpXSxcbiAgICAgICAgalxuICAgICAgKTtcblxuICAgICAgYmxvY2tCWyhzdGVwKzApICUgNV0gPSByZXRCbG9ja1swXTtcbiAgICAgIGJsb2NrQlsoc3RlcCsxKSAlIDVdID0gcmV0QmxvY2tbMV07XG4gICAgICBibG9ja0JbKHN0ZXArMikgJSA1XSA9IHJldEJsb2NrWzJdO1xuICAgICAgYmxvY2tCWyhzdGVwKzMpICUgNV0gPSByZXRCbG9ja1szXTtcbiAgICAgIGJsb2NrQlsoc3RlcCs0KSAlIDVdID0gcmV0QmxvY2tbNF07XG5cbiAgICAgIHN0ZXAgKz0gNDtcbiAgICB9XG4gIH1cblxuICBibG9ja0JbM10gKz0gYmxvY2tBWzJdICsgTURidWZbMV07XG4gIE1EYnVmWzFdICA9IE1EYnVmWzJdICsgYmxvY2tBWzNdICsgYmxvY2tCWzRdO1xuICBNRGJ1ZlsyXSAgPSBNRGJ1ZlszXSArIGJsb2NrQVs0XSArIGJsb2NrQlswXTtcbiAgTURidWZbM10gID0gTURidWZbNF0gKyBibG9ja0FbMF0gKyBibG9ja0JbMV07XG4gIE1EYnVmWzRdICA9IE1EYnVmWzBdICsgYmxvY2tBWzFdICsgYmxvY2tCWzJdO1xuICBNRGJ1ZlswXSAgPSBibG9ja0JbM107XG59XG5cbmZ1bmN0aW9uIHplcm9YKFgpXG57XG4gIGZvciAodmFyIGkgPSAwOyBpIDwgMTY7IGkrKykgeyBYW2ldID0gMDsgfVxufVxuXG5mdW5jdGlvbiBNRGZpbmlzaCAoTURidWYsIHN0cnB0ciwgbHN3bGVuLCBtc3dsZW4pXG57XG4gIHZhciBYID0gbmV3IEFycmF5KDE2KTtcbiAgemVyb1goWCk7XG5cbiAgdmFyIGogPSAwO1xuICBmb3IgKHZhciBpPTA7IGkgPCAobHN3bGVuICYgNjMpOyBpKyspXG4gIHtcbiAgICBYW2kgPj4+IDJdIF49IChzdHJwdHIuY2hhckNvZGVBdChqKyspICYgMjU1KSA8PCAoOCAqIChpICYgMykpO1xuICB9XG5cbiAgWFsobHN3bGVuID4+PiAyKSAmIDE1XSBePSAxIDw8ICg4ICogKGxzd2xlbiAmIDMpICsgNyk7XG5cbiAgaWYgKChsc3dsZW4gJiA2MykgPiA1NSlcbiAge1xuICAgIGNvbXByZXNzKE1EYnVmLCBYKTtcbiAgICB2YXIgWCA9IG5ldyBBcnJheSgxNik7XG4gICAgemVyb1goWCk7XG4gIH1cblxuICBYWzE0XSA9IGxzd2xlbiA8PCAzO1xuICBYWzE1XSA9IChsc3dsZW4gPj4+IDI5KSB8IChtc3dsZW4gPDwgMyk7XG5cbiAgY29tcHJlc3MoTURidWYsIFgpO1xufVxuXG5mdW5jdGlvbiBCWVRFU19UT19EV09SRChmb3VyQ2hhcnMpXG57XG4gIHZhciB0bXAgID0gKGZvdXJDaGFycy5jaGFyQ29kZUF0KDMpICYgMjU1KSA8PCAyNDtcbiAgdG1wICAgfD0gKGZvdXJDaGFycy5jaGFyQ29kZUF0KDIpICYgMjU1KSA8PCAxNjtcbiAgdG1wICAgfD0gKGZvdXJDaGFycy5jaGFyQ29kZUF0KDEpICYgMjU1KSA8PCA4O1xuICB0bXAgICB8PSAoZm91ckNoYXJzLmNoYXJDb2RlQXQoMCkgJiAyNTUpOyAgXG5cbiAgcmV0dXJuIHRtcDtcbn1cblxuZnVuY3Rpb24gUk1EKG1lc3NhZ2UpXG57XG4gIHZhciBNRGJ1ZiAgID0gbmV3IEFycmF5KFJNRHNpemUgLyAzMik7XG4gIHZhciBoYXNoY29kZSAgID0gbmV3IEFycmF5KFJNRHNpemUgLyA4KTtcbiAgdmFyIGxlbmd0aDsgIFxuICB2YXIgbmJ5dGVzO1xuXG4gIE1EaW5pdChNRGJ1Zik7XG4gIGxlbmd0aCA9IG1lc3NhZ2UubGVuZ3RoO1xuXG4gIHZhciBYID0gbmV3IEFycmF5KDE2KTtcbiAgemVyb1goWCk7XG5cbiAgdmFyIGo9MDtcbiAgZm9yICh2YXIgbmJ5dGVzPWxlbmd0aDsgbmJ5dGVzID4gNjM7IG5ieXRlcyAtPSA2NClcbiAge1xuICAgIGZvciAodmFyIGk9MDsgaSA8IDE2OyBpKyspXG4gICAge1xuICAgICAgWFtpXSA9IEJZVEVTX1RPX0RXT1JEKG1lc3NhZ2Uuc3Vic3RyKGosIDQpKTtcbiAgICAgIGogKz0gNDtcbiAgICB9XG4gICAgY29tcHJlc3MoTURidWYsIFgpO1xuICB9XG5cbiAgTURmaW5pc2goTURidWYsIG1lc3NhZ2Uuc3Vic3RyKGopLCBsZW5ndGgsIDApO1xuXG4gIGZvciAodmFyIGk9MDsgaSA8IFJNRHNpemUgLyA4OyBpICs9IDQpXG4gIHtcbiAgICBoYXNoY29kZVtpXSAgID0gIE1EYnVmW2kgPj4+IDJdICAgJiAyNTU7XG4gICAgaGFzaGNvZGVbaSsxXSA9IChNRGJ1ZltpID4+PiAyXSA+Pj4gOCkgICAmIDI1NTtcbiAgICBoYXNoY29kZVtpKzJdID0gKE1EYnVmW2kgPj4+IDJdID4+PiAxNikgJiAyNTU7XG4gICAgaGFzaGNvZGVbaSszXSA9IChNRGJ1ZltpID4+PiAyXSA+Pj4gMjQpICYgMjU1O1xuICB9XG5cbiAgcmV0dXJuIGhhc2hjb2RlO1xufVxuXG5cbmZ1bmN0aW9uIFJNRHN0cmluZyhtZXNzYWdlKVxue1xuICB2YXIgaGFzaGNvZGUgPSBSTUQobWVzc2FnZSk7XG4gIHZhciByZXRTdHJpbmcgPSBcIlwiO1xuXG4gIGZvciAodmFyIGk9MDsgaSA8IFJNRHNpemUvODsgaSsrKVxuICB7XG4gICAgcmV0U3RyaW5nICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoaGFzaGNvZGVbaV0pO1xuICB9ICBcblxuICByZXR1cm4gcmV0U3RyaW5nOyAgXG59XG5cbm1vZHVsZS5leHBvcnRzID0gUk1Ec3RyaW5nO1xuIiwiLy8gR1BHNEJyb3dzZXJzIC0gQW4gT3BlblBHUCBpbXBsZW1lbnRhdGlvbiBpbiBqYXZhc2NyaXB0XG4vLyBDb3B5cmlnaHQgKEMpIDIwMTEgUmVjdXJpdHkgTGFicyBHbWJIXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3Jcbi8vIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlclxuLy8gdmVyc2lvbiAyLjEgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuLy8gYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2Zcbi8vIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUgR05VXG4vLyBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuLy8gXG4vLyBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFsb25nIHdpdGggdGhpcyBsaWJyYXJ5OyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlXG4vLyBGb3VuZGF0aW9uLCBJbmMuLCA1MSBGcmFua2xpbiBTdHJlZXQsIEZpZnRoIEZsb29yLCBCb3N0b24sIE1BICAwMjExMC0xMzAxICBVU0Fcbi8vXG4vLyBBIERpZ2l0YWwgc2lnbmF0dXJlIGFsZ29yaXRobSBpbXBsZW1lbnRhdGlvblxuXG5mdW5jdGlvbiBEU0EoKSB7XG5cdC8vIHMxID0gKChnKipzKSBtb2QgcCkgbW9kIHFcblx0Ly8gczEgPSAoKHMqKi0xKSooc2hhLTEobSkrKHMxKngpIG1vZCBxKVxuXHRmdW5jdGlvbiBzaWduKGhhc2hhbGdvLCBtLCBnLCBwLCBxLCB4KSB7XG5cdFx0Ly8gSWYgdGhlIG91dHB1dCBzaXplIG9mIHRoZSBjaG9zZW4gaGFzaCBpcyBsYXJnZXIgdGhhbiB0aGUgbnVtYmVyIG9mXG5cdFx0Ly8gYml0cyBvZiBxLCB0aGUgaGFzaCByZXN1bHQgaXMgdHJ1bmNhdGVkIHRvIGZpdCBieSB0YWtpbmcgdGhlIG51bWJlclxuXHRcdC8vIG9mIGxlZnRtb3N0IGJpdHMgZXF1YWwgdG8gdGhlIG51bWJlciBvZiBiaXRzIG9mIHEuICBUaGlzIChwb3NzaWJseVxuXHRcdC8vIHRydW5jYXRlZCkgaGFzaCBmdW5jdGlvbiByZXN1bHQgaXMgdHJlYXRlZCBhcyBhIG51bWJlciBhbmQgdXNlZFxuXHRcdC8vIGRpcmVjdGx5IGluIHRoZSBEU0Egc2lnbmF0dXJlIGFsZ29yaXRobS5cblx0XHR2YXIgaGFzaGVkX2RhdGEgPSB1dGlsLmdldExlZnROQml0cyhvcGVucGdwX2NyeXB0b19oYXNoRGF0YShoYXNoYWxnbyxtKSxxLmJpdExlbmd0aCgpKTtcblx0XHR2YXIgaGFzaCA9IG5ldyBCaWdJbnRlZ2VyKHV0aWwuaGV4c3RyZHVtcChoYXNoZWRfZGF0YSksIDE2KTtcblx0XHR2YXIgayA9IG9wZW5wZ3BfY3J5cHRvX2dldFJhbmRvbUJpZ0ludGVnZXJJblJhbmdlKEJpZ0ludGVnZXIuT05FLmFkZChCaWdJbnRlZ2VyLk9ORSksIHEuc3VidHJhY3QoQmlnSW50ZWdlci5PTkUpKTtcblx0XHR2YXIgczEgPSAoZy5tb2RQb3coayxwKSkubW9kKHEpOyBcblx0XHR2YXIgczIgPSAoay5tb2RJbnZlcnNlKHEpLm11bHRpcGx5KGhhc2guYWRkKHgubXVsdGlwbHkoczEpKSkpLm1vZChxKTtcblx0XHR2YXIgcmVzdWx0ID0gbmV3IEFycmF5KCk7XG5cdFx0cmVzdWx0WzBdID0gczEudG9NUEkoKTtcblx0XHRyZXN1bHRbMV0gPSBzMi50b01QSSgpO1xuXHRcdHJldHVybiByZXN1bHQ7XG5cdH1cblx0ZnVuY3Rpb24gc2VsZWN0X2hhc2hfYWxnb3JpdGhtKHEpIHtcblx0XHR2YXIgdXNlcnNldHRpbmcgPSBvcGVucGdwLmNvbmZpZy5jb25maWcucHJlZmVyX2hhc2hfYWxnb3JpdGhtO1xuXHRcdC8qXG5cdFx0ICogMTAyNC1iaXQga2V5LCAxNjAtYml0IHEsIFNIQS0xLCBTSEEtMjI0LCBTSEEtMjU2LCBTSEEtMzg0LCBvciBTSEEtNTEyIGhhc2hcblx0XHQgKiAyMDQ4LWJpdCBrZXksIDIyNC1iaXQgcSwgU0hBLTIyNCwgU0hBLTI1NiwgU0hBLTM4NCwgb3IgU0hBLTUxMiBoYXNoXG5cdFx0ICogMjA0OC1iaXQga2V5LCAyNTYtYml0IHEsIFNIQS0yNTYsIFNIQS0zODQsIG9yIFNIQS01MTIgaGFzaFxuXHRcdCAqIDMwNzItYml0IGtleSwgMjU2LWJpdCBxLCBTSEEtMjU2LCBTSEEtMzg0LCBvciBTSEEtNTEyIGhhc2hcblx0XHQgKi9cblx0XHRzd2l0Y2ggKE1hdGgucm91bmQocS5iaXRMZW5ndGgoKSAvIDgpKSB7XG5cdFx0Y2FzZSAyMDogLy8gMTAyNCBiaXRcblx0XHRcdGlmICh1c2Vyc2V0dGluZyAhPSAyICYmXG5cdFx0XHRcdHVzZXJzZXR0aW5nID4gMTEgJiZcblx0XHRcdFx0dXNlcnNldHRpbmcgIT0gMTAgJiZcblx0XHRcdFx0dXNlcnNldHRpbmcgPCA4KVxuXHRcdFx0XHRyZXR1cm4gMjsgLy8gcHJlZmVyIHNoYTFcblx0XHRcdHJldHVybiB1c2Vyc2V0dGluZztcblx0XHRjYXNlIDI4OiAvLyAyMDQ4IGJpdFxuXHRcdFx0aWYgKHVzZXJzZXR0aW5nID4gMTEgJiZcblx0XHRcdFx0XHR1c2Vyc2V0dGluZyA8IDgpXG5cdFx0XHRcdFx0cmV0dXJuIDExO1xuXHRcdFx0cmV0dXJuIHVzZXJzZXR0aW5nO1xuXHRcdGNhc2UgMzI6IC8vIDQwOTYgYml0IC8vIHByZWZlciBzaGEyMjRcblx0XHRcdGlmICh1c2Vyc2V0dGluZyA+IDEwICYmXG5cdFx0XHRcdFx0dXNlcnNldHRpbmcgPCA4KVxuXHRcdFx0XHRcdHJldHVybiA4OyAvLyBwcmVmZXIgc2hhMjU2XG5cdFx0XHRyZXR1cm4gdXNlcnNldHRpbmc7XG5cdFx0ZGVmYXVsdDpcblx0XHRcdHV0aWwucHJpbnRfZGVidWcoXCJEU0Egc2VsZWN0IGhhc2ggYWxnb3JpdGhtOiByZXR1cm5pbmcgbnVsbCBmb3IgYW4gdW5rbm93biBsZW5ndGggb2YgcVwiKTtcblx0XHRcdHJldHVybiBudWxsO1xuXHRcdFx0XG5cdFx0fVxuXHR9XG5cdHRoaXMuc2VsZWN0X2hhc2hfYWxnb3JpdGhtID0gc2VsZWN0X2hhc2hfYWxnb3JpdGhtO1xuXHRcblx0ZnVuY3Rpb24gdmVyaWZ5KGhhc2hhbGdvLCBzMSxzMixtLHAscSxnLHkpIHtcblx0XHR2YXIgaGFzaGVkX2RhdGEgPSB1dGlsLmdldExlZnROQml0cyhvcGVucGdwX2NyeXB0b19oYXNoRGF0YShoYXNoYWxnbyxtKSxxLmJpdExlbmd0aCgpKTtcblx0XHR2YXIgaGFzaCA9IG5ldyBCaWdJbnRlZ2VyKHV0aWwuaGV4c3RyZHVtcChoYXNoZWRfZGF0YSksIDE2KTsgXG5cdFx0aWYgKEJpZ0ludGVnZXIuWkVSTy5jb21wYXJlVG8oczEpID4gMCB8fFxuXHRcdFx0XHRzMS5jb21wYXJlVG8ocSkgPiAwIHx8XG5cdFx0XHRcdEJpZ0ludGVnZXIuWkVSTy5jb21wYXJlVG8oczIpID4gMCB8fFxuXHRcdFx0XHRzMi5jb21wYXJlVG8ocSkgPiAwKSB7XG5cdFx0XHR1dGlsLnByaW50X2Vycm9yKFwiaW52YWxpZCBEU0EgU2lnbmF0dXJlXCIpO1xuXHRcdFx0cmV0dXJuIG51bGw7XG5cdFx0fVxuXHRcdHZhciB3ID0gczIubW9kSW52ZXJzZShxKTtcblx0XHR2YXIgdTEgPSBoYXNoLm11bHRpcGx5KHcpLm1vZChxKTtcblx0XHR2YXIgdTIgPSBzMS5tdWx0aXBseSh3KS5tb2QocSk7XG5cdFx0cmV0dXJuIGcubW9kUG93KHUxLHApLm11bHRpcGx5KHkubW9kUG93KHUyLHApKS5tb2QocCkubW9kKHEpO1xuXHR9XG5cdFxuXHQvKlxuXHQgKiB1bnVzZWQgY29kZS4gVGhpcyBjYW4gYmUgdXNlZCBhcyBhIHN0YXJ0IHRvIHdyaXRlIGEga2V5IGdlbmVyYXRvclxuXHQgKiBmdW5jdGlvbi5cblx0XG5cdGZ1bmN0aW9uIGdlbmVyYXRlS2V5KGJpdGNvdW50KSB7XG5cdCAgICB2YXIgcWkgPSBuZXcgQmlnSW50ZWdlcihiaXRjb3VudCwgcHJpbWVDZW50ZXJpZSk7XG5cdCAgICB2YXIgcGkgPSBnZW5lcmF0ZVAocSwgNTEyKTtcblx0ICAgIHZhciBnaSA9IGdlbmVyYXRlRyhwLCBxLCBiaXRjb3VudCk7XG5cdCAgICB2YXIgeGk7XG5cdCAgICBkbyB7XG5cdCAgICAgICAgeGkgPSBuZXcgQmlnSW50ZWdlcihxLmJpdENvdW50KCksIHJhbmQpO1xuXHQgICAgfSB3aGlsZSAoeC5jb21wYXJlVG8oQmlnSW50ZWdlci5aRVJPKSAhPSAxICYmIHguY29tcGFyZVRvKHEpICE9IC0xKTtcblx0ICAgIHZhciB5aSA9IGcubW9kUG93KHgsIHApO1xuXHQgICAgcmV0dXJuIHt4OiB4aSwgcTogcWksIHA6IHBpLCBnOiBnaSwgeTogeWl9O1xuXHR9XG5cblx0ZnVuY3Rpb24gZ2VuZXJhdGVQKHEsIGJpdGxlbmd0aCwgcmFuZG9tZm4pIHtcblx0ICAgIGlmIChiaXRsZW5ndGggJSA2NCAhPSAwKSB7XG5cdCAgICBcdHJldHVybiBmYWxzZTtcblx0ICAgIH1cblx0ICAgIHZhciBwVGVtcDtcblx0ICAgIHZhciBwVGVtcDI7XG5cdCAgICBkbyB7XG5cdCAgICAgICAgcFRlbXAgPSByYW5kb21mbihiaXRjb3VudCwgdHJ1ZSk7XG5cdCAgICAgICAgcFRlbXAyID0gcFRlbXAuc3VidHJhY3QoQmlnSW50ZWdlci5PTkUpO1xuXHQgICAgICAgIHBUZW1wID0gcFRlbXAuc3VidHJhY3QocFRlbXAyLnJlbWFpbmRlcihxKSk7XG5cdCAgICB9IHdoaWxlICghcFRlbXAuaXNQcm9iYWJsZVByaW1lKHByaW1lQ2VudGVyaWUpIHx8IHBUZW1wLmJpdExlbmd0aCgpICE9IGwpO1xuXHQgICAgcmV0dXJuIHBUZW1wO1xuXHR9XG5cdFxuXHRmdW5jdGlvbiBnZW5lcmF0ZUcocCwgcSwgYml0bGVuZ3RoLCByYW5kb21mbikge1xuXHQgICAgdmFyIGF1eCA9IHAuc3VidHJhY3QoQmlnSW50ZWdlci5PTkUpO1xuXHQgICAgdmFyIHBvdyA9IGF1eC5kaXZpZGUocSk7XG5cdCAgICB2YXIgZ1RlbXA7XG5cdCAgICBkbyB7XG5cdCAgICAgICAgZ1RlbXAgPSByYW5kb21mbihiaXRsZW5ndGgpO1xuXHQgICAgfSB3aGlsZSAoZ1RlbXAuY29tcGFyZVRvKGF1eCkgIT0gLTEgJiYgZ1RlbXAuY29tcGFyZVRvKEJpZ0ludGVnZXIuT05FKSAhPSAxKTtcblx0ICAgIHJldHVybiBnVGVtcC5tb2RQb3cocG93LCBwKTtcblx0fVxuXG5cdGZ1bmN0aW9uIGdlbmVyYXRlSyhxLCBiaXRsZW5ndGgsIHJhbmRvbWZuKSB7XG5cdCAgICB2YXIgdGVtcEs7XG5cdCAgICBkbyB7XG5cdCAgICAgICAgdGVtcEsgPSByYW5kb21mbihiaXRsZW5ndGgsIGZhbHNlKTtcblx0ICAgIH0gd2hpbGUgKHRlbXBLLmNvbXBhcmVUbyhxKSAhPSAtMSAmJiB0ZW1wSy5jb21wYXJlVG8oQmlnSW50ZWdlci5aRVJPKSAhPSAxKTtcblx0ICAgIHJldHVybiB0ZW1wSztcblx0fVxuXG5cdGZ1bmN0aW9uIGdlbmVyYXRlUihxLHApIHtcblx0ICAgIGsgPSBnZW5lcmF0ZUsocSk7XG5cdCAgICB2YXIgciA9IGcubW9kUG93KGssIHApLm1vZChxKTtcblx0ICAgIHJldHVybiByO1xuXHR9XG5cblx0ZnVuY3Rpb24gZ2VuZXJhdGVTKGhhc2hmbixrLHIsbSxxLHgpIHtcbiAgICAgICAgdmFyIGhhc2ggPSBoYXNoZm4obSk7XG4gICAgICAgIHMgPSAoay5tb2RJbnZlcnNlKHEpLm11bHRpcGx5KGhhc2guYWRkKHgubXVsdGlwbHkocikpKSkubW9kKHEpO1xuXHQgICAgcmV0dXJuIHM7XG5cdH0gKi9cblx0dGhpcy5zaWduID0gc2lnbjtcblx0dGhpcy52ZXJpZnkgPSB2ZXJpZnk7XG5cdC8vIHRoaXMuZ2VuZXJhdGUgPSBnZW5lcmF0ZUtleTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBEU0E7XG4iLCJKWEcgPSB7ZXhpc3RzOiAoZnVuY3Rpb24odW5kZWZpbmVkKXtyZXR1cm4gZnVuY3Rpb24odil7cmV0dXJuICEodj09PXVuZGVmaW5lZCB8fCB2PT09bnVsbCk7fX0pKCl9O1xuSlhHLmRlY29tcHJlc3MgPSBmdW5jdGlvbihzdHIpIHtyZXR1cm4gdW5lc2NhcGUoKG5ldyBKWEcuVXRpbC5VbnppcChKWEcuVXRpbC5CYXNlNjQuZGVjb2RlQXNBcnJheShzdHIpKSkudW56aXAoKVswXVswXSk7fTtcbi8qXG4gICAgQ29weXJpZ2h0IDIwMDgtMjAxMlxuICAgICAgICBNYXR0aGlhcyBFaG1hbm4sXG4gICAgICAgIE1pY2hhZWwgR2VyaGFldXNlcixcbiAgICAgICAgQ2Fyc3RlbiBNaWxsZXIsXG4gICAgICAgIEJpYW5jYSBWYWxlbnRpbixcbiAgICAgICAgQWxmcmVkIFdhc3Nlcm1hbm4sXG4gICAgICAgIFBldGVyIFdpbGZhaHJ0XG5cbiAgICBUaGlzIGZpbGUgaXMgcGFydCBvZiBKU1hHcmFwaC5cbiAgICBcbiAgICBEdWFsIGxpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSBWZXJzaW9uIDIuMCwgb3IgTEdQTCBWZXJzaW9uIDMgbGljZW5zZXMuXG5cbiAgICBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2VcbiAgICBhbG9uZyB3aXRoIEpTWENvbXByZXNzb3IuICBJZiBub3QsIHNlZSA8aHR0cDovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4gICAgXG4gICAgWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgQXBhY2hlIExpY2Vuc2UgYWxvbmcgd2l0aCBKU1hDb21wcmVzc29yLiAgXG4gICAgSWYgbm90LCBzZWUgPGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy8+LlxuXG4qL1xuXG4vKipcbiAgKiBAY2xhc3MgVXRpbCBjbGFzc1xuICAqIEBjbGFzc2Rlc2MgVXRpbGl0aWVzIGZvciB1bmNvbXByZXNzaW5nIGFuZCBiYXNlNjQgZGVjb2RpbmdcbiAgKiBDbGFzcyBmb3IgZ3VuemlwcGluZywgdW56aXBwaW5nIGFuZCBiYXNlNjQgZGVjb2Rpbmcgb2YgZmlsZXMuXG4gICogSXQgaXMgdXNlZCBmb3IgcmVhZGluZyBHRU9ORXhULCBHZW9nZWJyYSBhbmQgSW50ZXJnZW8gZmlsZXMuXG4gICpcbiAgKiBPbmx5IEh1ZmZtYW4gY29kZXMgYXJlIGRlY29kZWQgaW4gZ3VuemlwLlxuICAqIFRoZSBjb2RlIGlzIGJhc2VkIG9uIHRoZSBzb3VyY2UgY29kZSBmb3IgZ3VuemlwLmMgYnkgUGFzaSBPamFsYSBcbiAgKiB7QGxpbmsgaHR0cDovL3d3dy5jcy50dXQuZmkvfmFsYmVydC9EZXYvZ3VuemlwL2d1bnppcC5jfVxuICAqIHtAbGluayBodHRwOi8vd3d3LmNzLnR1dC5maS9+YWxiZXJ0fVxuICAqL1xuSlhHLlV0aWwgPSB7fTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxuLyoqXG4gKiBVbnppcCB6aXAgZmlsZXNcbiAqL1xuSlhHLlV0aWwuVW56aXAgPSBmdW5jdGlvbiAoYmFycmF5KXtcbiAgICB2YXIgb3V0cHV0QXJyID0gW10sXG4gICAgICAgIG91dHB1dCA9IFwiXCIsXG4gICAgICAgIGRlYnVnID0gZmFsc2UsXG4gICAgICAgIGdwZmxhZ3MsXG4gICAgICAgIGZpbGVzID0gMCxcbiAgICAgICAgdW56aXBwZWQgPSBbXSxcbiAgICAgICAgY3JjLFxuICAgICAgICBidWYzMmsgPSBuZXcgQXJyYXkoMzI3NjgpLFxuICAgICAgICBiSWR4ID0gMCxcbiAgICAgICAgbW9kZVpJUD1mYWxzZSxcblxuICAgICAgICBDUkMsIFNJWkUsXG4gICAgXG4gICAgICAgIGJpdFJldmVyc2UgPSBbXG4gICAgICAgIDB4MDAsIDB4ODAsIDB4NDAsIDB4YzAsIDB4MjAsIDB4YTAsIDB4NjAsIDB4ZTAsXG4gICAgICAgIDB4MTAsIDB4OTAsIDB4NTAsIDB4ZDAsIDB4MzAsIDB4YjAsIDB4NzAsIDB4ZjAsXG4gICAgICAgIDB4MDgsIDB4ODgsIDB4NDgsIDB4YzgsIDB4MjgsIDB4YTgsIDB4NjgsIDB4ZTgsXG4gICAgICAgIDB4MTgsIDB4OTgsIDB4NTgsIDB4ZDgsIDB4MzgsIDB4YjgsIDB4NzgsIDB4ZjgsXG4gICAgICAgIDB4MDQsIDB4ODQsIDB4NDQsIDB4YzQsIDB4MjQsIDB4YTQsIDB4NjQsIDB4ZTQsXG4gICAgICAgIDB4MTQsIDB4OTQsIDB4NTQsIDB4ZDQsIDB4MzQsIDB4YjQsIDB4NzQsIDB4ZjQsXG4gICAgICAgIDB4MGMsIDB4OGMsIDB4NGMsIDB4Y2MsIDB4MmMsIDB4YWMsIDB4NmMsIDB4ZWMsXG4gICAgICAgIDB4MWMsIDB4OWMsIDB4NWMsIDB4ZGMsIDB4M2MsIDB4YmMsIDB4N2MsIDB4ZmMsXG4gICAgICAgIDB4MDIsIDB4ODIsIDB4NDIsIDB4YzIsIDB4MjIsIDB4YTIsIDB4NjIsIDB4ZTIsXG4gICAgICAgIDB4MTIsIDB4OTIsIDB4NTIsIDB4ZDIsIDB4MzIsIDB4YjIsIDB4NzIsIDB4ZjIsXG4gICAgICAgIDB4MGEsIDB4OGEsIDB4NGEsIDB4Y2EsIDB4MmEsIDB4YWEsIDB4NmEsIDB4ZWEsXG4gICAgICAgIDB4MWEsIDB4OWEsIDB4NWEsIDB4ZGEsIDB4M2EsIDB4YmEsIDB4N2EsIDB4ZmEsXG4gICAgICAgIDB4MDYsIDB4ODYsIDB4NDYsIDB4YzYsIDB4MjYsIDB4YTYsIDB4NjYsIDB4ZTYsXG4gICAgICAgIDB4MTYsIDB4OTYsIDB4NTYsIDB4ZDYsIDB4MzYsIDB4YjYsIDB4NzYsIDB4ZjYsXG4gICAgICAgIDB4MGUsIDB4OGUsIDB4NGUsIDB4Y2UsIDB4MmUsIDB4YWUsIDB4NmUsIDB4ZWUsXG4gICAgICAgIDB4MWUsIDB4OWUsIDB4NWUsIDB4ZGUsIDB4M2UsIDB4YmUsIDB4N2UsIDB4ZmUsXG4gICAgICAgIDB4MDEsIDB4ODEsIDB4NDEsIDB4YzEsIDB4MjEsIDB4YTEsIDB4NjEsIDB4ZTEsXG4gICAgICAgIDB4MTEsIDB4OTEsIDB4NTEsIDB4ZDEsIDB4MzEsIDB4YjEsIDB4NzEsIDB4ZjEsXG4gICAgICAgIDB4MDksIDB4ODksIDB4NDksIDB4YzksIDB4MjksIDB4YTksIDB4NjksIDB4ZTksXG4gICAgICAgIDB4MTksIDB4OTksIDB4NTksIDB4ZDksIDB4MzksIDB4YjksIDB4NzksIDB4ZjksXG4gICAgICAgIDB4MDUsIDB4ODUsIDB4NDUsIDB4YzUsIDB4MjUsIDB4YTUsIDB4NjUsIDB4ZTUsXG4gICAgICAgIDB4MTUsIDB4OTUsIDB4NTUsIDB4ZDUsIDB4MzUsIDB4YjUsIDB4NzUsIDB4ZjUsXG4gICAgICAgIDB4MGQsIDB4OGQsIDB4NGQsIDB4Y2QsIDB4MmQsIDB4YWQsIDB4NmQsIDB4ZWQsXG4gICAgICAgIDB4MWQsIDB4OWQsIDB4NWQsIDB4ZGQsIDB4M2QsIDB4YmQsIDB4N2QsIDB4ZmQsXG4gICAgICAgIDB4MDMsIDB4ODMsIDB4NDMsIDB4YzMsIDB4MjMsIDB4YTMsIDB4NjMsIDB4ZTMsXG4gICAgICAgIDB4MTMsIDB4OTMsIDB4NTMsIDB4ZDMsIDB4MzMsIDB4YjMsIDB4NzMsIDB4ZjMsXG4gICAgICAgIDB4MGIsIDB4OGIsIDB4NGIsIDB4Y2IsIDB4MmIsIDB4YWIsIDB4NmIsIDB4ZWIsXG4gICAgICAgIDB4MWIsIDB4OWIsIDB4NWIsIDB4ZGIsIDB4M2IsIDB4YmIsIDB4N2IsIDB4ZmIsXG4gICAgICAgIDB4MDcsIDB4ODcsIDB4NDcsIDB4YzcsIDB4MjcsIDB4YTcsIDB4NjcsIDB4ZTcsXG4gICAgICAgIDB4MTcsIDB4OTcsIDB4NTcsIDB4ZDcsIDB4MzcsIDB4YjcsIDB4NzcsIDB4ZjcsXG4gICAgICAgIDB4MGYsIDB4OGYsIDB4NGYsIDB4Y2YsIDB4MmYsIDB4YWYsIDB4NmYsIDB4ZWYsXG4gICAgICAgIDB4MWYsIDB4OWYsIDB4NWYsIDB4ZGYsIDB4M2YsIDB4YmYsIDB4N2YsIDB4ZmZcbiAgICBdLFxuICAgIFxuICAgIGNwbGVucyA9IFtcbiAgICAgICAgMywgNCwgNSwgNiwgNywgOCwgOSwgMTAsIDExLCAxMywgMTUsIDE3LCAxOSwgMjMsIDI3LCAzMSxcbiAgICAgICAgMzUsIDQzLCA1MSwgNTksIDY3LCA4MywgOTksIDExNSwgMTMxLCAxNjMsIDE5NSwgMjI3LCAyNTgsIDAsIDBcbiAgICBdLFxuXG4gICAgY3BsZXh0ID0gW1xuICAgICAgICAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAxLCAxLCAxLCAxLCAyLCAyLCAyLCAyLFxuICAgICAgICAzLCAzLCAzLCAzLCA0LCA0LCA0LCA0LCA1LCA1LCA1LCA1LCAwLCA5OSwgOTlcbiAgICBdLCAvKiA5OT09aW52YWxpZCAqL1xuXG4gICAgY3BkaXN0ID0gW1xuICAgICAgICAweDAwMDEsIDB4MDAwMiwgMHgwMDAzLCAweDAwMDQsIDB4MDAwNSwgMHgwMDA3LCAweDAwMDksIDB4MDAwZCxcbiAgICAgICAgMHgwMDExLCAweDAwMTksIDB4MDAyMSwgMHgwMDMxLCAweDAwNDEsIDB4MDA2MSwgMHgwMDgxLCAweDAwYzEsXG4gICAgICAgIDB4MDEwMSwgMHgwMTgxLCAweDAyMDEsIDB4MDMwMSwgMHgwNDAxLCAweDA2MDEsIDB4MDgwMSwgMHgwYzAxLFxuICAgICAgICAweDEwMDEsIDB4MTgwMSwgMHgyMDAxLCAweDMwMDEsIDB4NDAwMSwgMHg2MDAxXG4gICAgXSxcblxuICAgIGNwZGV4dCA9IFtcbiAgICAgICAgMCwgIDAsICAwLCAgMCwgIDEsICAxLCAgMiwgIDIsXG4gICAgICAgIDMsICAzLCAgNCwgIDQsICA1LCAgNSwgIDYsICA2LFxuICAgICAgICA3LCAgNywgIDgsICA4LCAgOSwgIDksIDEwLCAxMCxcbiAgICAgICAgMTEsIDExLCAxMiwgMTIsIDEzLCAxM1xuICAgIF0sXG4gICAgXG4gICAgYm9yZGVyID0gWzE2LCAxNywgMTgsIDAsIDgsIDcsIDksIDYsIDEwLCA1LCAxMSwgNCwgMTIsIDMsIDEzLCAyLCAxNCwgMSwgMTVdLFxuICAgIFxuICAgIGJBID0gYmFycmF5LFxuXG4gICAgYnl0ZXBvcz0wLFxuICAgIGJpdHBvcz0wLFxuICAgIGJiID0gMSxcbiAgICBiaXRzPTAsXG4gICAgXG4gICAgTkFNRU1BWCA9IDI1NixcbiAgICBcbiAgICBuYW1lQnVmID0gW10sXG4gICAgXG4gICAgZmlsZW91dDtcbiAgICBcbiAgICBmdW5jdGlvbiByZWFkQnl0ZSgpe1xuICAgICAgICBiaXRzKz04O1xuICAgICAgICBpZiAoYnl0ZXBvczxiQS5sZW5ndGgpe1xuICAgICAgICAgICAgLy9pZiAoZGVidWcpXG4gICAgICAgICAgICAvLyAgICBkb2N1bWVudC53cml0ZShieXRlcG9zK1wiOiBcIitiQVtieXRlcG9zXStcIjxicj5cIik7XG4gICAgICAgICAgICByZXR1cm4gYkFbYnl0ZXBvcysrXTtcbiAgICAgICAgfSBlbHNlXG4gICAgICAgICAgICByZXR1cm4gLTE7XG4gICAgfTtcblxuICAgIGZ1bmN0aW9uIGJ5dGVBbGlnbigpe1xuICAgICAgICBiYiA9IDE7XG4gICAgfTtcbiAgICBcbiAgICBmdW5jdGlvbiByZWFkQml0KCl7XG4gICAgICAgIHZhciBjYXJyeTtcbiAgICAgICAgYml0cysrO1xuICAgICAgICBjYXJyeSA9IChiYiAmIDEpO1xuICAgICAgICBiYiA+Pj0gMTtcbiAgICAgICAgaWYgKGJiPT0wKXtcbiAgICAgICAgICAgIGJiID0gcmVhZEJ5dGUoKTtcbiAgICAgICAgICAgIGNhcnJ5ID0gKGJiICYgMSk7XG4gICAgICAgICAgICBiYiA9IChiYj4+MSkgfCAweDgwO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBjYXJyeTtcbiAgICB9O1xuXG4gICAgZnVuY3Rpb24gcmVhZEJpdHMoYSkge1xuICAgICAgICB2YXIgcmVzID0gMCxcbiAgICAgICAgICAgIGkgPSBhO1xuICAgIFxuICAgICAgICB3aGlsZShpLS0pIHtcbiAgICAgICAgICAgIHJlcyA9IChyZXM8PDEpIHwgcmVhZEJpdCgpO1xuICAgICAgICB9XG4gICAgICAgIGlmKGEpIHtcbiAgICAgICAgICAgIHJlcyA9IGJpdFJldmVyc2VbcmVzXT4+KDgtYSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHJlcztcbiAgICB9O1xuICAgICAgICBcbiAgICBmdW5jdGlvbiBmbHVzaEJ1ZmZlcigpe1xuICAgICAgICAvL2RvY3VtZW50LndyaXRlKCdGTFVTSEJVRkZFUjonK2J1ZjMyayk7XG4gICAgICAgIGJJZHggPSAwO1xuICAgIH07XG4gICAgZnVuY3Rpb24gYWRkQnVmZmVyKGEpe1xuICAgICAgICBTSVpFKys7XG4gICAgICAgIC8vQ1JDPXVwZGNyYyhhLGNyYyk7XG4gICAgICAgIGJ1ZjMya1tiSWR4KytdID0gYTtcbiAgICAgICAgb3V0cHV0QXJyLnB1c2goU3RyaW5nLmZyb21DaGFyQ29kZShhKSk7XG4gICAgICAgIC8vb3V0cHV0Kz1TdHJpbmcuZnJvbUNoYXJDb2RlKGEpO1xuICAgICAgICBpZihiSWR4PT0weDgwMDApe1xuICAgICAgICAgICAgLy9kb2N1bWVudC53cml0ZSgnQUREQlVGRkVSOicrYnVmMzJrKTtcbiAgICAgICAgICAgIGJJZHg9MDtcbiAgICAgICAgfVxuICAgIH07XG4gICAgXG4gICAgZnVuY3Rpb24gSHVmTm9kZSgpIHtcbiAgICAgICAgdGhpcy5iMD0wO1xuICAgICAgICB0aGlzLmIxPTA7XG4gICAgICAgIHRoaXMuanVtcCA9IG51bGw7XG4gICAgICAgIHRoaXMuanVtcHBvcyA9IC0xO1xuICAgIH07XG5cbiAgICB2YXIgTElURVJBTFMgPSAyODg7XG4gICAgXG4gICAgdmFyIGxpdGVyYWxUcmVlID0gbmV3IEFycmF5KExJVEVSQUxTKTtcbiAgICB2YXIgZGlzdGFuY2VUcmVlID0gbmV3IEFycmF5KDMyKTtcbiAgICB2YXIgdHJlZXBvcz0wO1xuICAgIHZhciBQbGFjZXMgPSBudWxsO1xuICAgIHZhciBQbGFjZXMyID0gbnVsbDtcbiAgICBcbiAgICB2YXIgaW1wRGlzdGFuY2VUcmVlID0gbmV3IEFycmF5KDY0KTtcbiAgICB2YXIgaW1wTGVuZ3RoVHJlZSA9IG5ldyBBcnJheSg2NCk7XG4gICAgXG4gICAgdmFyIGxlbiA9IDA7XG4gICAgdmFyIGZwb3MgPSBuZXcgQXJyYXkoMTcpO1xuICAgIGZwb3NbMF09MDtcbiAgICB2YXIgZmxlbnM7XG4gICAgdmFyIGZtYXg7XG4gICAgXG4gICAgZnVuY3Rpb24gSXNQYXQoKSB7XG4gICAgICAgIHdoaWxlICgxKSB7XG4gICAgICAgICAgICBpZiAoZnBvc1tsZW5dID49IGZtYXgpXG4gICAgICAgICAgICAgICAgcmV0dXJuIC0xO1xuICAgICAgICAgICAgaWYgKGZsZW5zW2Zwb3NbbGVuXV0gPT0gbGVuKVxuICAgICAgICAgICAgICAgIHJldHVybiBmcG9zW2xlbl0rKztcbiAgICAgICAgICAgIGZwb3NbbGVuXSsrO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIGZ1bmN0aW9uIFJlYygpIHtcbiAgICAgICAgdmFyIGN1cnBsYWNlID0gUGxhY2VzW3RyZWVwb3NdO1xuICAgICAgICB2YXIgdG1wO1xuICAgICAgICBpZiAoZGVidWcpXG4gICAgXHRcdGRvY3VtZW50LndyaXRlKFwiPGJyPmxlbjpcIitsZW4rXCIgdHJlZXBvczpcIit0cmVlcG9zKTtcbiAgICAgICAgaWYobGVuPT0xNykgeyAvL3dhciAxN1xuICAgICAgICAgICAgcmV0dXJuIC0xO1xuICAgICAgICB9XG4gICAgICAgIHRyZWVwb3MrKztcbiAgICAgICAgbGVuKys7XG4gICAgXHRcbiAgICAgICAgdG1wID0gSXNQYXQoKTtcbiAgICAgICAgaWYgKGRlYnVnKVxuICAgICAgICBcdGRvY3VtZW50LndyaXRlKFwiPGJyPklzUGF0IFwiK3RtcCk7XG4gICAgICAgIGlmKHRtcCA+PSAwKSB7XG4gICAgICAgICAgICBjdXJwbGFjZS5iMCA9IHRtcDsgICAgLyogbGVhZiBjZWxsIGZvciAwLWJpdCAqL1xuICAgICAgICAgICAgaWYgKGRlYnVnKVxuICAgICAgICAgICAgXHRkb2N1bWVudC53cml0ZShcIjxicj5iMCBcIitjdXJwbGFjZS5iMCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8qIE5vdCBhIExlYWYgY2VsbCAqL1xuICAgICAgICBjdXJwbGFjZS5iMCA9IDB4ODAwMDtcbiAgICAgICAgaWYgKGRlYnVnKVxuICAgICAgICBcdGRvY3VtZW50LndyaXRlKFwiPGJyPmIwIFwiK2N1cnBsYWNlLmIwKTtcbiAgICAgICAgaWYoUmVjKCkpXG4gICAgICAgICAgICByZXR1cm4gLTE7XG4gICAgICAgIH1cbiAgICAgICAgdG1wID0gSXNQYXQoKTtcbiAgICAgICAgaWYodG1wID49IDApIHtcbiAgICAgICAgICAgIGN1cnBsYWNlLmIxID0gdG1wOyAgICAvKiBsZWFmIGNlbGwgZm9yIDEtYml0ICovXG4gICAgICAgICAgICBpZiAoZGVidWcpXG4gICAgICAgICAgICBcdGRvY3VtZW50LndyaXRlKFwiPGJyPmIxIFwiK2N1cnBsYWNlLmIxKTtcbiAgICAgICAgICAgIGN1cnBsYWNlLmp1bXAgPSBudWxsOyAgICAvKiBKdXN0IGZvciB0aGUgZGlzcGxheSByb3V0aW5lICovXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvKiBOb3QgYSBMZWFmIGNlbGwgKi9cbiAgICAgICAgICAgIGN1cnBsYWNlLmIxID0gMHg4MDAwO1xuICAgICAgICAgICAgaWYgKGRlYnVnKVxuICAgICAgICAgICAgXHRkb2N1bWVudC53cml0ZShcIjxicj5iMSBcIitjdXJwbGFjZS5iMSk7XG4gICAgICAgICAgICBjdXJwbGFjZS5qdW1wID0gUGxhY2VzW3RyZWVwb3NdO1xuICAgICAgICAgICAgY3VycGxhY2UuanVtcHBvcyA9IHRyZWVwb3M7XG4gICAgICAgICAgICBpZihSZWMoKSlcbiAgICAgICAgICAgICAgICByZXR1cm4gLTE7XG4gICAgICAgIH1cbiAgICAgICAgbGVuLS07XG4gICAgICAgIHJldHVybiAwO1xuICAgIH07XG5cbiAgICBmdW5jdGlvbiBDcmVhdGVUcmVlKGN1cnJlbnRUcmVlLCBudW12YWwsIGxlbmd0aHMsIHNob3cpIHtcbiAgICAgICAgdmFyIGk7XG4gICAgICAgIC8qIENyZWF0ZSB0aGUgSHVmZm1hbiBkZWNvZGUgdHJlZS90YWJsZSAqL1xuICAgICAgICAvL2RvY3VtZW50LndyaXRlKFwiPGJyPmNyZWF0ZXRyZWU8YnI+XCIpO1xuICAgICAgICBpZiAoZGVidWcpXG4gICAgICAgIFx0ZG9jdW1lbnQud3JpdGUoXCJjdXJyZW50VHJlZSBcIitjdXJyZW50VHJlZStcIiBudW12YWwgXCIrbnVtdmFsK1wiIGxlbmd0aHMgXCIrbGVuZ3RocytcIiBzaG93IFwiK3Nob3cpO1xuICAgICAgICBQbGFjZXMgPSBjdXJyZW50VHJlZTtcbiAgICAgICAgdHJlZXBvcz0wO1xuICAgICAgICBmbGVucyA9IGxlbmd0aHM7XG4gICAgICAgIGZtYXggID0gbnVtdmFsO1xuICAgICAgICBmb3IgKGk9MDtpPDE3O2krKylcbiAgICAgICAgICAgIGZwb3NbaV0gPSAwO1xuICAgICAgICBsZW4gPSAwO1xuICAgICAgICBpZihSZWMoKSkge1xuICAgICAgICAgICAgLy9mcHJpbnRmKHN0ZGVyciwgXCJpbnZhbGlkIGh1ZmZtYW4gdHJlZVxcblwiKTtcbiAgICAgICAgICAgIGlmIChkZWJ1ZylcbiAgICAgICAgICAgIFx0YWxlcnQoXCJpbnZhbGlkIGh1ZmZtYW4gdHJlZVxcblwiKTtcbiAgICAgICAgICAgIHJldHVybiAtMTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoZGVidWcpe1xuICAgICAgICBcdGRvY3VtZW50LndyaXRlKCc8YnI+VHJlZTogJytQbGFjZXMubGVuZ3RoKTtcbiAgICAgICAgXHRmb3IgKHZhciBhPTA7YTwzMjthKyspe1xuICAgICAgICAgICAgXHRkb2N1bWVudC53cml0ZShcIlBsYWNlc1tcIithK1wiXS5iMD1cIitQbGFjZXNbYV0uYjArXCI8YnI+XCIpO1xuICAgICAgICAgICAgXHRkb2N1bWVudC53cml0ZShcIlBsYWNlc1tcIithK1wiXS5iMT1cIitQbGFjZXNbYV0uYjErXCI8YnI+XCIpO1xuICAgICAgICBcdH1cbiAgICAgICAgfVxuICAgIFxuICAgICAgICAvKmlmKHNob3cpIHtcbiAgICAgICAgICAgIHZhciB0bXA7XG4gICAgICAgICAgICBmb3IodG1wPWN1cnJlbnRUcmVlO3RtcDxQbGFjZXM7dG1wKyspIHtcbiAgICAgICAgICAgICAgICBmcHJpbnRmKHN0ZG91dCwgXCIweCUwM3ggIDB4JTAzeCAoMHglMDR4KVwiLHRtcC1jdXJyZW50VHJlZSwgdG1wLT5qdW1wP3RtcC0+anVtcC1jdXJyZW50VHJlZTowLCh0bXAtPmp1bXA/dG1wLT5qdW1wLWN1cnJlbnRUcmVlOjApKjYrMHhjZjApO1xuICAgICAgICAgICAgICAgIGlmKCEodG1wLmIwICYgMHg4MDAwKSkge1xuICAgICAgICAgICAgICAgICAgICAvL2ZwcmludGYoc3Rkb3V0LCBcIiAgMHglMDN4ICglYylcIiwgdG1wLT5iMCwodG1wLT5iMDwyNTYgJiYgaXNwcmludCh0bXAtPmIwKSk/dG1wLT5iMDon77+9Jyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmKCEodG1wLmIxICYgMHg4MDAwKSkge1xuICAgICAgICAgICAgICAgICAgICBpZigodG1wLmIwICYgMHg4MDAwKSlcbiAgICAgICAgICAgICAgICAgICAgICAgIGZwcmludGYoc3Rkb3V0LCBcIiAgICAgICAgICAgXCIpO1xuICAgICAgICAgICAgICAgICAgICBmcHJpbnRmKHN0ZG91dCwgXCIgIDB4JTAzeCAoJWMpXCIsIHRtcC0+YjEsKHRtcC0+YjE8MjU2ICYmIGlzcHJpbnQodG1wLT5iMSkpP3RtcC0+YjE6J++/vScpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBmcHJpbnRmKHN0ZG91dCwgXCJcXG5cIik7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0qL1xuICAgICAgICByZXR1cm4gMDtcbiAgICB9O1xuICAgIFxuICAgIGZ1bmN0aW9uIERlY29kZVZhbHVlKGN1cnJlbnRUcmVlKSB7XG4gICAgICAgIHZhciBsZW4sIGksXG4gICAgICAgICAgICB4dHJlZXBvcz0wLFxuICAgICAgICAgICAgWCA9IGN1cnJlbnRUcmVlW3h0cmVlcG9zXSxcbiAgICAgICAgICAgIGI7XG5cbiAgICAgICAgLyogZGVjb2RlIG9uZSBzeW1ib2wgb2YgdGhlIGRhdGEgKi9cbiAgICAgICAgd2hpbGUoMSkge1xuICAgICAgICAgICAgYj1yZWFkQml0KCk7XG4gICAgICAgICAgICBpZiAoZGVidWcpXG4gICAgICAgICAgICBcdGRvY3VtZW50LndyaXRlKFwiYj1cIitiKTtcbiAgICAgICAgICAgIGlmKGIpIHtcbiAgICAgICAgICAgICAgICBpZighKFguYjEgJiAweDgwMDApKXtcbiAgICAgICAgICAgICAgICBcdGlmIChkZWJ1ZylcbiAgICAgICAgICAgICAgICAgICAgXHRkb2N1bWVudC53cml0ZShcInJldDFcIik7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBYLmIxOyAgICAvKiBJZiBsZWFmIG5vZGUsIHJldHVybiBkYXRhICovXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIFggPSBYLmp1bXA7XG4gICAgICAgICAgICAgICAgbGVuID0gY3VycmVudFRyZWUubGVuZ3RoO1xuICAgICAgICAgICAgICAgIGZvciAoaT0wO2k8bGVuO2krKyl7XG4gICAgICAgICAgICAgICAgICAgIGlmIChjdXJyZW50VHJlZVtpXT09PVgpe1xuICAgICAgICAgICAgICAgICAgICAgICAgeHRyZWVwb3M9aTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIC8veHRyZWVwb3MrKztcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgaWYoIShYLmIwICYgMHg4MDAwKSl7XG4gICAgICAgICAgICAgICAgXHRpZiAoZGVidWcpXG4gICAgICAgICAgICAgICAgICAgIFx0ZG9jdW1lbnQud3JpdGUoXCJyZXQyXCIpO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gWC5iMDsgICAgLyogSWYgbGVhZiBub2RlLCByZXR1cm4gZGF0YSAqL1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAvL1grKzsgLy8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz9cbiAgICAgICAgICAgICAgICB4dHJlZXBvcysrO1xuICAgICAgICAgICAgICAgIFggPSBjdXJyZW50VHJlZVt4dHJlZXBvc107XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGRlYnVnKVxuICAgICAgICBcdGRvY3VtZW50LndyaXRlKFwicmV0M1wiKTtcbiAgICAgICAgcmV0dXJuIC0xO1xuICAgIH07XG4gICAgXG4gICAgZnVuY3Rpb24gRGVmbGF0ZUxvb3AoKSB7XG4gICAgdmFyIGxhc3QsIGMsIHR5cGUsIGksIGxlbjtcblxuICAgIGRvIHtcbiAgICAgICAgLyppZigobGFzdCA9IHJlYWRCaXQoKSkpe1xuICAgICAgICAgICAgZnByaW50ZihlcnJmcCwgXCJMYXN0IEJsb2NrOiBcIik7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBmcHJpbnRmKGVycmZwLCBcIk5vdCBMYXN0IEJsb2NrOiBcIik7XG4gICAgICAgIH0qL1xuICAgICAgICBsYXN0ID0gcmVhZEJpdCgpO1xuICAgICAgICB0eXBlID0gcmVhZEJpdHMoMik7XG4gICAgICAgIHN3aXRjaCh0eXBlKSB7XG4gICAgICAgICAgICBjYXNlIDA6XG4gICAgICAgICAgICBcdGlmIChkZWJ1ZylcbiAgICAgICAgICAgICAgICBcdGFsZXJ0KFwiU3RvcmVkXFxuXCIpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSAxOlxuICAgICAgICAgICAgXHRpZiAoZGVidWcpXG4gICAgICAgICAgICAgICAgXHRhbGVydChcIkZpeGVkIEh1ZmZtYW4gY29kZXNcXG5cIik7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIDI6XG4gICAgICAgICAgICBcdGlmIChkZWJ1ZylcbiAgICAgICAgICAgICAgICBcdGFsZXJ0KFwiRHluYW1pYyBIdWZmbWFuIGNvZGVzXFxuXCIpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSAzOlxuICAgICAgICAgICAgXHRpZiAoZGVidWcpXG4gICAgICAgICAgICAgICAgXHRhbGVydChcIlJlc2VydmVkIGJsb2NrIHR5cGUhIVxcblwiKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICBcdGlmIChkZWJ1ZylcbiAgICAgICAgICAgICAgICBcdGFsZXJ0KFwiVW5leHBlY3RlZCB2YWx1ZSAlZCFcXG5cIiwgdHlwZSk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cblxuICAgICAgICBpZih0eXBlPT0wKSB7XG4gICAgICAgICAgICB2YXIgYmxvY2tMZW4sIGNTdW07XG5cbiAgICAgICAgICAgIC8vIFN0b3JlZCBcbiAgICAgICAgICAgIGJ5dGVBbGlnbigpO1xuICAgICAgICAgICAgYmxvY2tMZW4gPSByZWFkQnl0ZSgpO1xuICAgICAgICAgICAgYmxvY2tMZW4gfD0gKHJlYWRCeXRlKCk8PDgpO1xuXG4gICAgICAgICAgICBjU3VtID0gcmVhZEJ5dGUoKTtcbiAgICAgICAgICAgIGNTdW0gfD0gKHJlYWRCeXRlKCk8PDgpO1xuXG4gICAgICAgICAgICBpZigoKGJsb2NrTGVuIF4gfmNTdW0pICYgMHhmZmZmKSkge1xuICAgICAgICAgICAgICAgIGRvY3VtZW50LndyaXRlKFwiQmxvY2tMZW4gY2hlY2tzdW0gbWlzbWF0Y2hcXG5cIik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB3aGlsZShibG9ja0xlbi0tKSB7XG4gICAgICAgICAgICAgICAgYyA9IHJlYWRCeXRlKCk7XG4gICAgICAgICAgICAgICAgYWRkQnVmZmVyKGMpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9IGVsc2UgaWYodHlwZT09MSkge1xuICAgICAgICAgICAgdmFyIGo7XG5cbiAgICAgICAgICAgIC8qIEZpeGVkIEh1ZmZtYW4gdGFibGVzIC0tIGZpeGVkIGRlY29kZSByb3V0aW5lICovXG4gICAgICAgICAgICB3aGlsZSgxKSB7XG4gICAgICAgICAgICAvKlxuICAgICAgICAgICAgICAgIDI1NiAgICAwMDAwMDAwICAgICAgICAwXG4gICAgICAgICAgICAgICAgOiAgIDogICAgIDpcbiAgICAgICAgICAgICAgICAyNzkgICAgMDAxMDExMSAgICAgICAgMjNcbiAgICAgICAgICAgICAgICAwICAgMDAxMTAwMDAgICAgNDhcbiAgICAgICAgICAgICAgICA6ICAgIDogICAgICA6XG4gICAgICAgICAgICAgICAgMTQzICAgIDEwMTExMTExICAgIDE5MVxuICAgICAgICAgICAgICAgIDI4MCAxMTAwMDAwMCAgICAxOTJcbiAgICAgICAgICAgICAgICA6ICAgIDogICAgICA6XG4gICAgICAgICAgICAgICAgMjg3IDExMDAwMTExICAgIDE5OVxuICAgICAgICAgICAgICAgIDE0NCAgICAxMTAwMTAwMDAgICAgNDAwXG4gICAgICAgICAgICAgICAgOiAgICA6ICAgICAgIDpcbiAgICAgICAgICAgICAgICAyNTUgICAgMTExMTExMTExICAgIDUxMVxuICAgIFxuICAgICAgICAgICAgICAgIE5vdGUgdGhlIGJpdCBvcmRlciFcbiAgICAgICAgICAgICAgICAqL1xuXG4gICAgICAgICAgICBqID0gKGJpdFJldmVyc2VbcmVhZEJpdHMoNyldPj4xKTtcbiAgICAgICAgICAgIGlmKGogPiAyMykge1xuICAgICAgICAgICAgICAgIGogPSAoajw8MSkgfCByZWFkQml0KCk7ICAgIC8qIDQ4Li4yNTUgKi9cblxuICAgICAgICAgICAgICAgIGlmKGogPiAxOTkpIHsgICAgLyogMjAwLi4yNTUgKi9cbiAgICAgICAgICAgICAgICAgICAgaiAtPSAxMjg7ICAgIC8qICA3Mi4uMTI3ICovXG4gICAgICAgICAgICAgICAgICAgIGogPSAoajw8MSkgfCByZWFkQml0KCk7ICAgICAgICAvKiAxNDQuLjI1NSA8PCAqL1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7ICAgICAgICAvKiAgNDguLjE5OSAqL1xuICAgICAgICAgICAgICAgICAgICBqIC09IDQ4OyAgICAvKiAgIDAuLjE1MSAqL1xuICAgICAgICAgICAgICAgICAgICBpZihqID4gMTQzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBqID0gaisxMzY7ICAgIC8qIDI4MC4uMjg3IDw8ICovXG4gICAgICAgICAgICAgICAgICAgICAgICAvKiAgIDAuLjE0MyA8PCAqL1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIHsgICAgLyogICAwLi4yMyAqL1xuICAgICAgICAgICAgICAgIGogKz0gMjU2OyAgICAvKiAyNTYuLjI3OSA8PCAqL1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYoaiA8IDI1Nikge1xuICAgICAgICAgICAgICAgIGFkZEJ1ZmZlcihqKTtcbiAgICAgICAgICAgICAgICAvL2RvY3VtZW50LndyaXRlKFwib3V0OlwiK1N0cmluZy5mcm9tQ2hhckNvZGUoaikpO1xuICAgICAgICAgICAgICAgIC8qZnByaW50ZihlcnJmcCwgXCJAJWQgJTAyeFxcblwiLCBTSVpFLCBqKTsqL1xuICAgICAgICAgICAgfSBlbHNlIGlmKGogPT0gMjU2KSB7XG4gICAgICAgICAgICAgICAgLyogRU9GICovXG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHZhciBsZW4sIGRpc3Q7XG5cbiAgICAgICAgICAgICAgICBqIC09IDI1NiArIDE7ICAgIC8qIGJ5dGVzICsgRU9GICovXG4gICAgICAgICAgICAgICAgbGVuID0gcmVhZEJpdHMoY3BsZXh0W2pdKSArIGNwbGVuc1tqXTtcblxuICAgICAgICAgICAgICAgIGogPSBiaXRSZXZlcnNlW3JlYWRCaXRzKDUpXT4+MztcbiAgICAgICAgICAgICAgICBpZihjcGRleHRbal0gPiA4KSB7XG4gICAgICAgICAgICAgICAgICAgIGRpc3QgPSByZWFkQml0cyg4KTtcbiAgICAgICAgICAgICAgICAgICAgZGlzdCB8PSAocmVhZEJpdHMoY3BkZXh0W2pdLTgpPDw4KTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBkaXN0ID0gcmVhZEJpdHMoY3BkZXh0W2pdKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZGlzdCArPSBjcGRpc3Rbal07XG5cbiAgICAgICAgICAgICAgICAvKmZwcmludGYoZXJyZnAsIFwiQCVkIChsJTAyeCxkJTA0eClcXG5cIiwgU0laRSwgbGVuLCBkaXN0KTsqL1xuICAgICAgICAgICAgICAgIGZvcihqPTA7ajxsZW47aisrKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBjID0gYnVmMzJrWyhiSWR4IC0gZGlzdCkgJiAweDdmZmZdO1xuICAgICAgICAgICAgICAgICAgICBhZGRCdWZmZXIoYyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSAvLyB3aGlsZVxuICAgICAgICB9IGVsc2UgaWYodHlwZT09Mikge1xuICAgICAgICAgICAgdmFyIGosIG4sIGxpdGVyYWxDb2RlcywgZGlzdENvZGVzLCBsZW5Db2RlcztcbiAgICAgICAgICAgIHZhciBsbCA9IG5ldyBBcnJheSgyODgrMzIpOyAgICAvLyBcInN0YXRpY1wiIGp1c3QgdG8gcHJlc2VydmUgc3RhY2tcbiAgICBcbiAgICAgICAgICAgIC8vIER5bmFtaWMgSHVmZm1hbiB0YWJsZXMgXG4gICAgXG4gICAgICAgICAgICBsaXRlcmFsQ29kZXMgPSAyNTcgKyByZWFkQml0cyg1KTtcbiAgICAgICAgICAgIGRpc3RDb2RlcyA9IDEgKyByZWFkQml0cyg1KTtcbiAgICAgICAgICAgIGxlbkNvZGVzID0gNCArIHJlYWRCaXRzKDQpO1xuICAgICAgICAgICAgLy9kb2N1bWVudC53cml0ZShcIjxicj5wYXJhbTogXCIrbGl0ZXJhbENvZGVzK1wiIFwiK2Rpc3RDb2RlcytcIiBcIitsZW5Db2RlcytcIjxicj5cIik7XG4gICAgICAgICAgICBmb3Ioaj0wOyBqPDE5OyBqKyspIHtcbiAgICAgICAgICAgICAgICBsbFtqXSA9IDA7XG4gICAgICAgICAgICB9XG4gICAgXG4gICAgICAgICAgICAvLyBHZXQgdGhlIGRlY29kZSB0cmVlIGNvZGUgbGVuZ3Roc1xuICAgIFxuICAgICAgICAgICAgLy9kb2N1bWVudC53cml0ZShcIjxicj5cIik7XG4gICAgICAgICAgICBmb3Ioaj0wOyBqPGxlbkNvZGVzOyBqKyspIHtcbiAgICAgICAgICAgICAgICBsbFtib3JkZXJbal1dID0gcmVhZEJpdHMoMyk7XG4gICAgICAgICAgICAgICAgLy9kb2N1bWVudC53cml0ZShsbFtib3JkZXJbal1dK1wiIFwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vZnByaW50ZihlcnJmcCwgXCJcXG5cIik7XG4gICAgICAgICAgICAvL2RvY3VtZW50LndyaXRlKCc8YnI+bGw6JytsbCk7XG4gICAgICAgICAgICBsZW4gPSBkaXN0YW5jZVRyZWUubGVuZ3RoO1xuICAgICAgICAgICAgZm9yIChpPTA7IGk8bGVuOyBpKyspXG4gICAgICAgICAgICAgICAgZGlzdGFuY2VUcmVlW2ldPW5ldyBIdWZOb2RlKCk7XG4gICAgICAgICAgICBpZihDcmVhdGVUcmVlKGRpc3RhbmNlVHJlZSwgMTksIGxsLCAwKSkge1xuICAgICAgICAgICAgICAgIGZsdXNoQnVmZmVyKCk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIDE7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoZGVidWcpe1xuICAgICAgICAgICAgXHRkb2N1bWVudC53cml0ZShcIjxicj5kaXN0YW5jZVRyZWVcIik7XG4gICAgICAgICAgICBcdGZvcih2YXIgYT0wO2E8ZGlzdGFuY2VUcmVlLmxlbmd0aDthKyspe1xuICAgICAgICAgICAgICAgIFx0ZG9jdW1lbnQud3JpdGUoXCI8YnI+XCIrZGlzdGFuY2VUcmVlW2FdLmIwK1wiIFwiK2Rpc3RhbmNlVHJlZVthXS5iMStcIiBcIitkaXN0YW5jZVRyZWVbYV0uanVtcCtcIiBcIitkaXN0YW5jZVRyZWVbYV0uanVtcHBvcyk7XG4gICAgICAgICAgICAgICAgXHQvKmlmIChkaXN0YW5jZVRyZWVbYV0uanVtcHBvcyE9LTEpXG4gICAgICAgICAgICAgICAgICAgIFx0ZG9jdW1lbnQud3JpdGUoXCIgXCIrZGlzdGFuY2VUcmVlW2FdLmp1bXAuYjArXCIgXCIrZGlzdGFuY2VUcmVlW2FdLmp1bXAuYjEpO1xuICAgICAgICAgICAgICAgIFx0Ki9cbiAgICAgICAgICAgIFx0fVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy9kb2N1bWVudC53cml0ZSgnPEJSPnRyZWUgY3JlYXRlZCcpO1xuICAgIFxuICAgICAgICAgICAgLy9yZWFkIGluIGxpdGVyYWwgYW5kIGRpc3RhbmNlIGNvZGUgbGVuZ3Roc1xuICAgICAgICAgICAgbiA9IGxpdGVyYWxDb2RlcyArIGRpc3RDb2RlcztcbiAgICAgICAgICAgIGkgPSAwO1xuICAgICAgICAgICAgdmFyIHo9LTE7XG4gICAgICAgICAgICBpZiAoZGVidWcpXG4gICAgICAgICAgICBcdGRvY3VtZW50LndyaXRlKFwiPGJyPm49XCIrbitcIiBiaXRzOiBcIitiaXRzK1wiPGJyPlwiKTtcbiAgICAgICAgICAgIHdoaWxlKGkgPCBuKSB7XG4gICAgICAgICAgICAgICAgeisrO1xuICAgICAgICAgICAgICAgIGogPSBEZWNvZGVWYWx1ZShkaXN0YW5jZVRyZWUpO1xuICAgICAgICAgICAgICAgIGlmIChkZWJ1ZylcbiAgICAgICAgICAgICAgICBcdGRvY3VtZW50LndyaXRlKFwiPGJyPlwiK3orXCIgaTpcIitpK1wiIGRlY29kZTogXCIraitcIiAgICBiaXRzIFwiK2JpdHMrXCI8YnI+XCIpO1xuICAgICAgICAgICAgICAgIGlmKGo8MTYpIHsgICAgLy8gbGVuZ3RoIG9mIGNvZGUgaW4gYml0cyAoMC4uMTUpXG4gICAgICAgICAgICAgICAgICAgICAgIGxsW2krK10gPSBqO1xuICAgICAgICAgICAgICAgIH0gZWxzZSBpZihqPT0xNikgeyAgICAvLyByZXBlYXQgbGFzdCBsZW5ndGggMyB0byA2IHRpbWVzIFxuICAgICAgICAgICAgICAgICAgICAgICB2YXIgbDtcbiAgICAgICAgICAgICAgICAgICAgaiA9IDMgKyByZWFkQml0cygyKTtcbiAgICAgICAgICAgICAgICAgICAgaWYoaStqID4gbikge1xuICAgICAgICAgICAgICAgICAgICAgICAgZmx1c2hCdWZmZXIoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiAxO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGwgPSBpID8gbGxbaS0xXSA6IDA7XG4gICAgICAgICAgICAgICAgICAgIHdoaWxlKGotLSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgbGxbaSsrXSA9IGw7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBpZihqPT0xNykgeyAgICAgICAgLy8gMyB0byAxMCB6ZXJvIGxlbmd0aCBjb2Rlc1xuICAgICAgICAgICAgICAgICAgICAgICAgaiA9IDMgKyByZWFkQml0cygzKTtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHsgICAgICAgIC8vIGogPT0gMTg6IDExIHRvIDEzOCB6ZXJvIGxlbmd0aCBjb2RlcyBcbiAgICAgICAgICAgICAgICAgICAgICAgIGogPSAxMSArIHJlYWRCaXRzKDcpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGlmKGkraiA+IG4pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGZsdXNoQnVmZmVyKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gMTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB3aGlsZShqLS0pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGxsW2krK10gPSAwO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLypmb3Ioaj0wOyBqPGxpdGVyYWxDb2RlcytkaXN0Q29kZXM7IGorKykge1xuICAgICAgICAgICAgICAgIC8vZnByaW50ZihlcnJmcCwgXCIlZCBcIiwgbGxbal0pO1xuICAgICAgICAgICAgICAgIGlmICgoaiY3KT09NylcbiAgICAgICAgICAgICAgICAgICAgZnByaW50ZihlcnJmcCwgXCJcXG5cIik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBmcHJpbnRmKGVycmZwLCBcIlxcblwiKTsqL1xuICAgICAgICAgICAgLy8gQ2FuIG92ZXJ3cml0ZSB0cmVlIGRlY29kZSB0cmVlIGFzIGl0IGlzIG5vdCB1c2VkIGFueW1vcmVcbiAgICAgICAgICAgIGxlbiA9IGxpdGVyYWxUcmVlLmxlbmd0aDtcbiAgICAgICAgICAgIGZvciAoaT0wOyBpPGxlbjsgaSsrKVxuICAgICAgICAgICAgICAgIGxpdGVyYWxUcmVlW2ldPW5ldyBIdWZOb2RlKCk7XG4gICAgICAgICAgICBpZihDcmVhdGVUcmVlKGxpdGVyYWxUcmVlLCBsaXRlcmFsQ29kZXMsIGxsLCAwKSkge1xuICAgICAgICAgICAgICAgIGZsdXNoQnVmZmVyKCk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIDE7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBsZW4gPSBsaXRlcmFsVHJlZS5sZW5ndGg7XG4gICAgICAgICAgICBmb3IgKGk9MDsgaTxsZW47IGkrKylcbiAgICAgICAgICAgICAgICBkaXN0YW5jZVRyZWVbaV09bmV3IEh1Zk5vZGUoKTtcbiAgICAgICAgICAgIHZhciBsbDIgPSBuZXcgQXJyYXkoKTtcbiAgICAgICAgICAgIGZvciAoaT1saXRlcmFsQ29kZXM7IGkgPGxsLmxlbmd0aDsgaSsrKXtcbiAgICAgICAgICAgICAgICBsbDJbaS1saXRlcmFsQ29kZXNdPWxsW2ldO1xuICAgICAgICAgICAgfSAgICBcbiAgICAgICAgICAgIGlmKENyZWF0ZVRyZWUoZGlzdGFuY2VUcmVlLCBkaXN0Q29kZXMsIGxsMiwgMCkpIHtcbiAgICAgICAgICAgICAgICBmbHVzaEJ1ZmZlcigpO1xuICAgICAgICAgICAgICAgIHJldHVybiAxO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGRlYnVnKVxuICAgICAgICAgICBcdFx0ZG9jdW1lbnQud3JpdGUoXCI8YnI+bGl0ZXJhbFRyZWVcIik7XG4gICAgICAgICAgICBvdXRlcjpcbiAgICAgICAgICAgIHdoaWxlKDEpIHtcbiAgICAgICAgICAgICAgICBqID0gRGVjb2RlVmFsdWUobGl0ZXJhbFRyZWUpO1xuICAgICAgICAgICAgICAgIGlmKGogPj0gMjU2KSB7ICAgICAgICAvLyBJbiBDNjQ6IGlmIGNhcnJ5IHNldFxuICAgICAgICAgICAgICAgICAgICB2YXIgbGVuLCBkaXN0O1xuICAgICAgICAgICAgICAgICAgICBqIC09IDI1NjtcbiAgICAgICAgICAgICAgICAgICAgaWYoaiA9PSAwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBFT0ZcbiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGotLTtcbiAgICAgICAgICAgICAgICAgICAgbGVuID0gcmVhZEJpdHMoY3BsZXh0W2pdKSArIGNwbGVuc1tqXTtcbiAgICBcbiAgICAgICAgICAgICAgICAgICAgaiA9IERlY29kZVZhbHVlKGRpc3RhbmNlVHJlZSk7XG4gICAgICAgICAgICAgICAgICAgIGlmKGNwZGV4dFtqXSA+IDgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGRpc3QgPSByZWFkQml0cyg4KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGRpc3QgfD0gKHJlYWRCaXRzKGNwZGV4dFtqXS04KTw8OCk7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBkaXN0ID0gcmVhZEJpdHMoY3BkZXh0W2pdKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBkaXN0ICs9IGNwZGlzdFtqXTtcbiAgICAgICAgICAgICAgICAgICAgd2hpbGUobGVuLS0pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmKGJJZHggLSBkaXN0IDwgMCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrIG91dGVyO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGMgPSBidWYzMmtbKGJJZHggLSBkaXN0KSAmIDB4N2ZmZl07XG4gICAgICAgICAgICAgICAgICAgICAgICBhZGRCdWZmZXIoYyk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBhZGRCdWZmZXIoaik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfSB3aGlsZSghbGFzdCk7XG4gICAgZmx1c2hCdWZmZXIoKTtcblxuICAgIGJ5dGVBbGlnbigpO1xuICAgIHJldHVybiAwO1xufTtcblxuSlhHLlV0aWwuVW56aXAucHJvdG90eXBlLnVuemlwRmlsZSA9IGZ1bmN0aW9uKG5hbWUpIHtcbiAgICB2YXIgaTtcblx0dGhpcy51bnppcCgpO1xuXHQvL2FsZXJ0KHVuemlwcGVkWzBdWzFdKTtcblx0Zm9yIChpPTA7aTx1bnppcHBlZC5sZW5ndGg7aSsrKXtcblx0XHRpZih1bnppcHBlZFtpXVsxXT09bmFtZSkge1xuXHRcdFx0cmV0dXJuIHVuemlwcGVkW2ldWzBdO1xuXHRcdH1cblx0fVxuXHRcbiAgfTtcblxuSlhHLlV0aWwuVW56aXAucHJvdG90eXBlLmRlZmxhdGUgPSBmdW5jdGlvbigpIHtcbiAgICBvdXRwdXRBcnIgPSBbXTtcbiAgICB2YXIgdG1wID0gW107XG4gICAgbW9kZVpJUCA9IGZhbHNlO1xuICAgIERlZmxhdGVMb29wKCk7XG4gICAgaWYgKGRlYnVnKVxuICAgICAgICBhbGVydChvdXRwdXRBcnIuam9pbignJykpO1xuICAgIHVuemlwcGVkW2ZpbGVzXSA9IG5ldyBBcnJheSgyKTtcbiAgICB1bnppcHBlZFtmaWxlc11bMF0gPSBvdXRwdXRBcnIuam9pbignJyk7XG4gICAgdW56aXBwZWRbZmlsZXNdWzFdID0gXCJERUZMQVRFXCI7XG4gICAgZmlsZXMrKztcbiAgICByZXR1cm4gdW56aXBwZWQ7XG59ICAgIFxuICAgIFxuSlhHLlV0aWwuVW56aXAucHJvdG90eXBlLnVuemlwID0gZnVuY3Rpb24oKSB7XG5cdC8vY29udmVydFRvQnl0ZUFycmF5KGlucHV0KTtcblx0aWYgKGRlYnVnKVxuXHRcdGFsZXJ0KGJBKTtcblx0Lypmb3IgKGk9MDtpPGJBLmxlbmd0aCo4O2krKyl7XG5cdFx0ZG9jdW1lbnQud3JpdGUocmVhZEJpdCgpKTtcblx0XHRpZiAoKGkrMSklOD09MClcblx0XHRcdGRvY3VtZW50LndyaXRlKFwiIFwiKTtcblx0fSovXG5cdC8qZm9yIChpPTA7aTxiQS5sZW5ndGg7aSsrKXtcblx0XHRkb2N1bWVudC53cml0ZShyZWFkQnl0ZSgpK1wiIFwiKTtcblx0XHRpZiAoKGkrMSklOD09MClcblx0XHRcdGRvY3VtZW50LndyaXRlKFwiIFwiKTtcblx0fVxuXHRmb3IgKGk9MDtpPGJBLmxlbmd0aDtpKyspe1xuXHRcdGRvY3VtZW50LndyaXRlKGJBW2ldK1wiIFwiKTtcblx0XHRpZiAoKGkrMSklMTY9PTApXG5cdFx0XHRkb2N1bWVudC53cml0ZShcIjxicj5cIik7XG5cdH1cdFxuXHQqL1xuXHQvL2FsZXJ0KGJBKTtcblx0bmV4dEZpbGUoKTtcblx0cmV0dXJuIHVuemlwcGVkO1xuICB9O1xuICAgIFxuIGZ1bmN0aW9uIG5leHRGaWxlKCl7XG4gXHRpZiAoZGVidWcpXG4gXHRcdGFsZXJ0KFwiTkVYVEZJTEVcIik7XG4gXHRvdXRwdXRBcnIgPSBbXTtcbiBcdHZhciB0bXAgPSBbXTtcbiBcdG1vZGVaSVAgPSBmYWxzZTtcblx0dG1wWzBdID0gcmVhZEJ5dGUoKTtcblx0dG1wWzFdID0gcmVhZEJ5dGUoKTtcblx0aWYgKGRlYnVnKVxuXHRcdGFsZXJ0KFwidHlwZTogXCIrdG1wWzBdK1wiIFwiK3RtcFsxXSk7XG5cdGlmICh0bXBbMF0gPT0gcGFyc2VJbnQoXCI3OFwiLDE2KSAmJiB0bXBbMV0gPT0gcGFyc2VJbnQoXCJkYVwiLDE2KSl7IC8vR1pJUFxuXHRcdGlmIChkZWJ1Zylcblx0XHRcdGFsZXJ0KFwiR0VPTkV4VC1HWklQXCIpO1xuXHRcdERlZmxhdGVMb29wKCk7XG5cdFx0aWYgKGRlYnVnKVxuXHRcdFx0YWxlcnQob3V0cHV0QXJyLmpvaW4oJycpKTtcblx0XHR1bnppcHBlZFtmaWxlc10gPSBuZXcgQXJyYXkoMik7XG4gICAgXHR1bnppcHBlZFtmaWxlc11bMF0gPSBvdXRwdXRBcnIuam9pbignJyk7XG4gICAgXHR1bnppcHBlZFtmaWxlc11bMV0gPSBcImdlb25leHQuZ3h0XCI7XG4gICAgXHRmaWxlcysrO1xuXHR9XG5cdGlmICh0bXBbMF0gPT0gcGFyc2VJbnQoXCI3OFwiLDE2KSAmJiB0bXBbMV0gPT0gcGFyc2VJbnQoXCI5Y1wiLDE2KSl7IC8vWkxJQlxuXHRcdGlmIChkZWJ1Zylcblx0XHRcdGFsZXJ0KFwiWkxJQlwiKTtcblx0XHREZWZsYXRlTG9vcCgpO1xuXHRcdGlmIChkZWJ1Zylcblx0XHRcdGFsZXJ0KG91dHB1dEFyci5qb2luKCcnKSk7XG5cdFx0dW56aXBwZWRbZmlsZXNdID0gbmV3IEFycmF5KDIpO1xuICAgIFx0dW56aXBwZWRbZmlsZXNdWzBdID0gb3V0cHV0QXJyLmpvaW4oJycpO1xuICAgIFx0dW56aXBwZWRbZmlsZXNdWzFdID0gXCJaTElCXCI7XG4gICAgXHRmaWxlcysrO1xuXHR9XG5cdGlmICh0bXBbMF0gPT0gcGFyc2VJbnQoXCIxZlwiLDE2KSAmJiB0bXBbMV0gPT0gcGFyc2VJbnQoXCI4YlwiLDE2KSl7IC8vR1pJUFxuXHRcdGlmIChkZWJ1Zylcblx0XHRcdGFsZXJ0KFwiR1pJUFwiKTtcblx0XHQvL0RlZmxhdGVMb29wKCk7XG5cdFx0c2tpcGRpcigpO1xuXHRcdGlmIChkZWJ1Zylcblx0XHRcdGFsZXJ0KG91dHB1dEFyci5qb2luKCcnKSk7XG5cdFx0dW56aXBwZWRbZmlsZXNdID0gbmV3IEFycmF5KDIpO1xuICAgIFx0dW56aXBwZWRbZmlsZXNdWzBdID0gb3V0cHV0QXJyLmpvaW4oJycpO1xuICAgIFx0dW56aXBwZWRbZmlsZXNdWzFdID0gXCJmaWxlXCI7XG4gICAgXHRmaWxlcysrO1xuXHR9XG5cdGlmICh0bXBbMF0gPT0gcGFyc2VJbnQoXCI1MFwiLDE2KSAmJiB0bXBbMV0gPT0gcGFyc2VJbnQoXCI0YlwiLDE2KSl7IC8vWklQXG5cdFx0bW9kZVpJUCA9IHRydWU7XG5cdFx0dG1wWzJdID0gcmVhZEJ5dGUoKTtcblx0XHR0bXBbM10gPSByZWFkQnl0ZSgpO1xuXHRcdGlmICh0bXBbMl0gPT0gcGFyc2VJbnQoXCIzXCIsMTYpICYmIHRtcFszXSA9PSBwYXJzZUludChcIjRcIiwxNikpe1xuXHRcdFx0Ly9NT0RFX1pJUFxuXHRcdFx0dG1wWzBdID0gcmVhZEJ5dGUoKTtcblx0XHRcdHRtcFsxXSA9IHJlYWRCeXRlKCk7XG5cdFx0XHRpZiAoZGVidWcpXG5cdFx0XHRcdGFsZXJ0KFwiWklQLVZlcnNpb246IFwiK3RtcFsxXStcIiBcIit0bXBbMF0vMTArXCIuXCIrdG1wWzBdJTEwKTtcblx0XHRcdFxuXHRcdFx0Z3BmbGFncyA9IHJlYWRCeXRlKCk7XG5cdFx0XHRncGZsYWdzIHw9IChyZWFkQnl0ZSgpPDw4KTtcblx0XHRcdGlmIChkZWJ1Zylcblx0XHRcdFx0YWxlcnQoXCJncGZsYWdzOiBcIitncGZsYWdzKTtcblx0XHRcdFxuXHRcdFx0dmFyIG1ldGhvZCA9IHJlYWRCeXRlKCk7XG5cdFx0XHRtZXRob2QgfD0gKHJlYWRCeXRlKCk8PDgpO1xuXHRcdFx0aWYgKGRlYnVnKVxuXHRcdFx0XHRhbGVydChcIm1ldGhvZDogXCIrbWV0aG9kKTtcblx0XHRcdFxuXHRcdFx0cmVhZEJ5dGUoKTtcblx0XHRcdHJlYWRCeXRlKCk7XG5cdFx0XHRyZWFkQnl0ZSgpO1xuXHRcdFx0cmVhZEJ5dGUoKTtcblx0XHRcdFxuXHRcdFx0dmFyIGNyYyA9IHJlYWRCeXRlKCk7XG5cdFx0XHRjcmMgfD0gKHJlYWRCeXRlKCk8PDgpO1xuXHRcdFx0Y3JjIHw9IChyZWFkQnl0ZSgpPDwxNik7XG5cdFx0XHRjcmMgfD0gKHJlYWRCeXRlKCk8PDI0KTtcblx0XHRcdFxuXHRcdFx0dmFyIGNvbXBTaXplID0gcmVhZEJ5dGUoKTtcblx0XHRcdGNvbXBTaXplIHw9IChyZWFkQnl0ZSgpPDw4KTtcblx0XHRcdGNvbXBTaXplIHw9IChyZWFkQnl0ZSgpPDwxNik7XG5cdFx0XHRjb21wU2l6ZSB8PSAocmVhZEJ5dGUoKTw8MjQpO1xuXHRcdFx0XG5cdFx0XHR2YXIgc2l6ZSA9IHJlYWRCeXRlKCk7XG5cdFx0XHRzaXplIHw9IChyZWFkQnl0ZSgpPDw4KTtcblx0XHRcdHNpemUgfD0gKHJlYWRCeXRlKCk8PDE2KTtcblx0XHRcdHNpemUgfD0gKHJlYWRCeXRlKCk8PDI0KTtcblx0XHRcdFxuXHRcdFx0aWYgKGRlYnVnKVxuXHRcdFx0XHRhbGVydChcImxvY2FsIENSQzogXCIrY3JjK1wiXFxubG9jYWwgU2l6ZTogXCIrc2l6ZStcIlxcbmxvY2FsIENvbXBTaXplOiBcIitjb21wU2l6ZSk7XG5cdFx0XHRcblx0XHRcdHZhciBmaWxlbGVuID0gcmVhZEJ5dGUoKTtcblx0XHRcdGZpbGVsZW4gfD0gKHJlYWRCeXRlKCk8PDgpO1xuXHRcdFx0XG5cdFx0XHR2YXIgZXh0cmFsZW4gPSByZWFkQnl0ZSgpO1xuXHRcdFx0ZXh0cmFsZW4gfD0gKHJlYWRCeXRlKCk8PDgpO1xuXHRcdFx0XG5cdFx0XHRpZiAoZGVidWcpXG5cdFx0XHRcdGFsZXJ0KFwiZmlsZWxlbiBcIitmaWxlbGVuKTtcblx0XHRcdGkgPSAwO1xuXHRcdFx0bmFtZUJ1ZiA9IFtdO1xuXHRcdFx0d2hpbGUgKGZpbGVsZW4tLSl7IFxuXHRcdFx0XHR2YXIgYyA9IHJlYWRCeXRlKCk7XG5cdFx0XHRcdGlmIChjID09IFwiL1wiIHwgYyA9PVwiOlwiKXtcblx0XHRcdFx0XHRpID0gMDtcblx0XHRcdFx0fSBlbHNlIGlmIChpIDwgTkFNRU1BWC0xKVxuXHRcdFx0XHRcdG5hbWVCdWZbaSsrXSA9IFN0cmluZy5mcm9tQ2hhckNvZGUoYyk7XG5cdFx0XHR9XG5cdFx0XHRpZiAoZGVidWcpXG5cdFx0XHRcdGFsZXJ0KFwibmFtZUJ1ZjogXCIrbmFtZUJ1Zik7XG5cdFx0XHRcblx0XHRcdC8vbmFtZUJ1ZltpXSA9IFwiXFwwXCI7XG5cdFx0XHRpZiAoIWZpbGVvdXQpXG5cdFx0XHRcdGZpbGVvdXQgPSBuYW1lQnVmO1xuXHRcdFx0XG5cdFx0XHR2YXIgaSA9IDA7XG5cdFx0XHR3aGlsZSAoaSA8IGV4dHJhbGVuKXtcblx0XHRcdFx0YyA9IHJlYWRCeXRlKCk7XG5cdFx0XHRcdGkrKztcblx0XHRcdH1cblx0XHRcdFx0XG5cdFx0XHRDUkMgPSAweGZmZmZmZmZmO1xuXHRcdFx0U0laRSA9IDA7XG5cdFx0XHRcblx0XHRcdGlmIChzaXplID0gMCAmJiBmaWxlT3V0LmNoYXJBdChmaWxlb3V0Lmxlbmd0aC0xKT09XCIvXCIpe1xuXHRcdFx0XHQvL3NraXBkaXJcblx0XHRcdFx0aWYgKGRlYnVnKVxuXHRcdFx0XHRcdGFsZXJ0KFwic2tpcGRpclwiKTtcblx0XHRcdH1cblx0XHRcdGlmIChtZXRob2QgPT0gOCl7XG5cdFx0XHRcdERlZmxhdGVMb29wKCk7XG5cdFx0XHRcdGlmIChkZWJ1Zylcblx0XHRcdFx0XHRhbGVydChvdXRwdXRBcnIuam9pbignJykpO1xuXHRcdFx0XHR1bnppcHBlZFtmaWxlc10gPSBuZXcgQXJyYXkoMik7XG5cdFx0XHRcdHVuemlwcGVkW2ZpbGVzXVswXSA9IG91dHB1dEFyci5qb2luKCcnKTtcbiAgICBcdFx0XHR1bnppcHBlZFtmaWxlc11bMV0gPSBuYW1lQnVmLmpvaW4oJycpO1xuICAgIFx0XHRcdGZpbGVzKys7XG5cdFx0XHRcdC8vcmV0dXJuIG91dHB1dEFyci5qb2luKCcnKTtcblx0XHRcdH1cblx0XHRcdHNraXBkaXIoKTtcblx0XHR9XG5cdH1cbiB9O1xuXHRcbmZ1bmN0aW9uIHNraXBkaXIoKXtcbiAgICB2YXIgY3JjLCBcbiAgICAgICAgdG1wID0gW10sXG4gICAgICAgIGNvbXBTaXplLCBzaXplLCBvcywgaSwgYztcbiAgICBcblx0aWYgKChncGZsYWdzICYgOCkpIHtcblx0XHR0bXBbMF0gPSByZWFkQnl0ZSgpO1xuXHRcdHRtcFsxXSA9IHJlYWRCeXRlKCk7XG5cdFx0dG1wWzJdID0gcmVhZEJ5dGUoKTtcblx0XHR0bXBbM10gPSByZWFkQnl0ZSgpO1xuXHRcdFxuXHRcdGlmICh0bXBbMF0gPT0gcGFyc2VJbnQoXCI1MFwiLDE2KSAmJiBcbiAgICAgICAgICAgIHRtcFsxXSA9PSBwYXJzZUludChcIjRiXCIsMTYpICYmIFxuICAgICAgICAgICAgdG1wWzJdID09IHBhcnNlSW50KFwiMDdcIiwxNikgJiYgXG4gICAgICAgICAgICB0bXBbM10gPT0gcGFyc2VJbnQoXCIwOFwiLDE2KSlcbiAgICAgICAge1xuICAgICAgICAgICAgY3JjID0gcmVhZEJ5dGUoKTtcbiAgICAgICAgICAgIGNyYyB8PSAocmVhZEJ5dGUoKTw8OCk7XG4gICAgICAgICAgICBjcmMgfD0gKHJlYWRCeXRlKCk8PDE2KTtcbiAgICAgICAgICAgIGNyYyB8PSAocmVhZEJ5dGUoKTw8MjQpO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRjcmMgPSB0bXBbMF0gfCAodG1wWzFdPDw4KSB8ICh0bXBbMl08PDE2KSB8ICh0bXBbM108PDI0KTtcblx0XHR9XG5cdFx0XG5cdFx0Y29tcFNpemUgPSByZWFkQnl0ZSgpO1xuXHRcdGNvbXBTaXplIHw9IChyZWFkQnl0ZSgpPDw4KTtcblx0XHRjb21wU2l6ZSB8PSAocmVhZEJ5dGUoKTw8MTYpO1xuXHRcdGNvbXBTaXplIHw9IChyZWFkQnl0ZSgpPDwyNCk7XG5cdFx0XG5cdFx0c2l6ZSA9IHJlYWRCeXRlKCk7XG5cdFx0c2l6ZSB8PSAocmVhZEJ5dGUoKTw8OCk7XG5cdFx0c2l6ZSB8PSAocmVhZEJ5dGUoKTw8MTYpO1xuXHRcdHNpemUgfD0gKHJlYWRCeXRlKCk8PDI0KTtcblx0XHRcblx0XHRpZiAoZGVidWcpXG5cdFx0XHRhbGVydChcIkNSQzpcIik7XG5cdH1cblxuXHRpZiAobW9kZVpJUClcblx0XHRuZXh0RmlsZSgpO1xuXHRcblx0dG1wWzBdID0gcmVhZEJ5dGUoKTtcblx0aWYgKHRtcFswXSAhPSA4KSB7XG5cdFx0aWYgKGRlYnVnKVxuXHRcdFx0YWxlcnQoXCJVbmtub3duIGNvbXByZXNzaW9uIG1ldGhvZCFcIik7XG4gICAgICAgIHJldHVybiAwO1x0XG5cdH1cblx0XG5cdGdwZmxhZ3MgPSByZWFkQnl0ZSgpO1xuXHRpZiAoZGVidWcpe1xuXHRcdGlmICgoZ3BmbGFncyAmIH4ocGFyc2VJbnQoXCIxZlwiLDE2KSkpKVxuXHRcdFx0YWxlcnQoXCJVbmtub3duIGZsYWdzIHNldCFcIik7XG5cdH1cblx0XG5cdHJlYWRCeXRlKCk7XG5cdHJlYWRCeXRlKCk7XG5cdHJlYWRCeXRlKCk7XG5cdHJlYWRCeXRlKCk7XG5cdFxuXHRyZWFkQnl0ZSgpO1xuXHRvcyA9IHJlYWRCeXRlKCk7XG5cdFxuXHRpZiAoKGdwZmxhZ3MgJiA0KSl7XG5cdFx0dG1wWzBdID0gcmVhZEJ5dGUoKTtcblx0XHR0bXBbMl0gPSByZWFkQnl0ZSgpO1xuXHRcdGxlbiA9IHRtcFswXSArIDI1Nip0bXBbMV07XG5cdFx0aWYgKGRlYnVnKVxuXHRcdFx0YWxlcnQoXCJFeHRyYSBmaWVsZCBzaXplOiBcIitsZW4pO1xuXHRcdGZvciAoaT0wO2k8bGVuO2krKylcblx0XHRcdHJlYWRCeXRlKCk7XG5cdH1cblx0XG5cdGlmICgoZ3BmbGFncyAmIDgpKXtcblx0XHRpPTA7XG5cdFx0bmFtZUJ1Zj1bXTtcblx0XHR3aGlsZSAoYz1yZWFkQnl0ZSgpKXtcblx0XHRcdGlmKGMgPT0gXCI3XCIgfHwgYyA9PSBcIjpcIilcblx0XHRcdFx0aT0wO1xuXHRcdFx0aWYgKGk8TkFNRU1BWC0xKVxuXHRcdFx0XHRuYW1lQnVmW2krK10gPSBjO1xuXHRcdH1cblx0XHQvL25hbWVCdWZbaV0gPSBcIlxcMFwiO1xuXHRcdGlmIChkZWJ1Zylcblx0XHRcdGFsZXJ0KFwib3JpZ2luYWwgZmlsZSBuYW1lOiBcIituYW1lQnVmKTtcblx0fVxuXHRcdFxuXHRpZiAoKGdwZmxhZ3MgJiAxNikpe1xuXHRcdHdoaWxlIChjPXJlYWRCeXRlKCkpe1xuXHRcdFx0Ly9GSUxFIENPTU1FTlRcblx0XHR9XG5cdH1cblx0XG5cdGlmICgoZ3BmbGFncyAmIDIpKXtcblx0XHRyZWFkQnl0ZSgpO1xuXHRcdHJlYWRCeXRlKCk7XG5cdH1cblx0XG5cdERlZmxhdGVMb29wKCk7XG5cdFxuXHRjcmMgPSByZWFkQnl0ZSgpO1xuXHRjcmMgfD0gKHJlYWRCeXRlKCk8PDgpO1xuXHRjcmMgfD0gKHJlYWRCeXRlKCk8PDE2KTtcblx0Y3JjIHw9IChyZWFkQnl0ZSgpPDwyNCk7XG5cdFxuXHRzaXplID0gcmVhZEJ5dGUoKTtcblx0c2l6ZSB8PSAocmVhZEJ5dGUoKTw8OCk7XG5cdHNpemUgfD0gKHJlYWRCeXRlKCk8PDE2KTtcblx0c2l6ZSB8PSAocmVhZEJ5dGUoKTw8MjQpO1xuXHRcblx0aWYgKG1vZGVaSVApXG5cdFx0bmV4dEZpbGUoKTtcblx0XG59O1xuXG59O1xuXG4vKipcbiogIEJhc2U2NCBlbmNvZGluZyAvIGRlY29kaW5nXG4qICB7QGxpbmsgaHR0cDovL3d3dy53ZWJ0b29sa2l0LmluZm8vfVxuKi9cbkpYRy5VdGlsLkJhc2U2NCA9IHtcblxuICAgIC8vIHByaXZhdGUgcHJvcGVydHlcbiAgICBfa2V5U3RyIDogXCJBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWmFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6MDEyMzQ1Njc4OSsvPVwiLFxuXG4gICAgLy8gcHVibGljIG1ldGhvZCBmb3IgZW5jb2RpbmdcbiAgICBlbmNvZGUgOiBmdW5jdGlvbiAoaW5wdXQpIHtcbiAgICAgICAgdmFyIG91dHB1dCA9IFtdLFxuICAgICAgICAgICAgY2hyMSwgY2hyMiwgY2hyMywgZW5jMSwgZW5jMiwgZW5jMywgZW5jNCxcbiAgICAgICAgICAgIGkgPSAwO1xuXG4gICAgICAgIGlucHV0ID0gSlhHLlV0aWwuQmFzZTY0Ll91dGY4X2VuY29kZShpbnB1dCk7XG5cbiAgICAgICAgd2hpbGUgKGkgPCBpbnB1dC5sZW5ndGgpIHtcblxuICAgICAgICAgICAgY2hyMSA9IGlucHV0LmNoYXJDb2RlQXQoaSsrKTtcbiAgICAgICAgICAgIGNocjIgPSBpbnB1dC5jaGFyQ29kZUF0KGkrKyk7XG4gICAgICAgICAgICBjaHIzID0gaW5wdXQuY2hhckNvZGVBdChpKyspO1xuXG4gICAgICAgICAgICBlbmMxID0gY2hyMSA+PiAyO1xuICAgICAgICAgICAgZW5jMiA9ICgoY2hyMSAmIDMpIDw8IDQpIHwgKGNocjIgPj4gNCk7XG4gICAgICAgICAgICBlbmMzID0gKChjaHIyICYgMTUpIDw8IDIpIHwgKGNocjMgPj4gNik7XG4gICAgICAgICAgICBlbmM0ID0gY2hyMyAmIDYzO1xuXG4gICAgICAgICAgICBpZiAoaXNOYU4oY2hyMikpIHtcbiAgICAgICAgICAgICAgICBlbmMzID0gZW5jNCA9IDY0O1xuICAgICAgICAgICAgfSBlbHNlIGlmIChpc05hTihjaHIzKSkge1xuICAgICAgICAgICAgICAgIGVuYzQgPSA2NDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgb3V0cHV0LnB1c2goW3RoaXMuX2tleVN0ci5jaGFyQXQoZW5jMSksXG4gICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5fa2V5U3RyLmNoYXJBdChlbmMyKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLl9rZXlTdHIuY2hhckF0KGVuYzMpLFxuICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuX2tleVN0ci5jaGFyQXQoZW5jNCldLmpvaW4oJycpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBvdXRwdXQuam9pbignJyk7XG4gICAgfSxcblxuICAgIC8vIHB1YmxpYyBtZXRob2QgZm9yIGRlY29kaW5nXG4gICAgZGVjb2RlIDogZnVuY3Rpb24gKGlucHV0LCB1dGY4KSB7XG4gICAgICAgIHZhciBvdXRwdXQgPSBbXSxcbiAgICAgICAgICAgIGNocjEsIGNocjIsIGNocjMsXG4gICAgICAgICAgICBlbmMxLCBlbmMyLCBlbmMzLCBlbmM0LFxuICAgICAgICAgICAgaSA9IDA7XG5cbiAgICAgICAgaW5wdXQgPSBpbnB1dC5yZXBsYWNlKC9bXkEtWmEtejAtOVxcK1xcL1xcPV0vZywgXCJcIik7XG5cbiAgICAgICAgd2hpbGUgKGkgPCBpbnB1dC5sZW5ndGgpIHtcblxuICAgICAgICAgICAgZW5jMSA9IHRoaXMuX2tleVN0ci5pbmRleE9mKGlucHV0LmNoYXJBdChpKyspKTtcbiAgICAgICAgICAgIGVuYzIgPSB0aGlzLl9rZXlTdHIuaW5kZXhPZihpbnB1dC5jaGFyQXQoaSsrKSk7XG4gICAgICAgICAgICBlbmMzID0gdGhpcy5fa2V5U3RyLmluZGV4T2YoaW5wdXQuY2hhckF0KGkrKykpO1xuICAgICAgICAgICAgZW5jNCA9IHRoaXMuX2tleVN0ci5pbmRleE9mKGlucHV0LmNoYXJBdChpKyspKTtcblxuICAgICAgICAgICAgY2hyMSA9IChlbmMxIDw8IDIpIHwgKGVuYzIgPj4gNCk7XG4gICAgICAgICAgICBjaHIyID0gKChlbmMyICYgMTUpIDw8IDQpIHwgKGVuYzMgPj4gMik7XG4gICAgICAgICAgICBjaHIzID0gKChlbmMzICYgMykgPDwgNikgfCBlbmM0O1xuXG4gICAgICAgICAgICBvdXRwdXQucHVzaChTdHJpbmcuZnJvbUNoYXJDb2RlKGNocjEpKTtcblxuICAgICAgICAgICAgaWYgKGVuYzMgIT0gNjQpIHtcbiAgICAgICAgICAgICAgICBvdXRwdXQucHVzaChTdHJpbmcuZnJvbUNoYXJDb2RlKGNocjIpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChlbmM0ICE9IDY0KSB7XG4gICAgICAgICAgICAgICAgb3V0cHV0LnB1c2goU3RyaW5nLmZyb21DaGFyQ29kZShjaHIzKSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgXG4gICAgICAgIG91dHB1dCA9IG91dHB1dC5qb2luKCcnKTsgXG4gICAgICAgIFxuICAgICAgICBpZiAodXRmOCkge1xuICAgICAgICAgICAgb3V0cHV0ID0gSlhHLlV0aWwuQmFzZTY0Ll91dGY4X2RlY29kZShvdXRwdXQpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBvdXRwdXQ7XG5cbiAgICB9LFxuXG4gICAgLy8gcHJpdmF0ZSBtZXRob2QgZm9yIFVURi04IGVuY29kaW5nXG4gICAgX3V0ZjhfZW5jb2RlIDogZnVuY3Rpb24gKHN0cmluZykge1xuICAgICAgICBzdHJpbmcgPSBzdHJpbmcucmVwbGFjZSgvXFxyXFxuL2csXCJcXG5cIik7XG4gICAgICAgIHZhciB1dGZ0ZXh0ID0gXCJcIjtcblxuICAgICAgICBmb3IgKHZhciBuID0gMDsgbiA8IHN0cmluZy5sZW5ndGg7IG4rKykge1xuXG4gICAgICAgICAgICB2YXIgYyA9IHN0cmluZy5jaGFyQ29kZUF0KG4pO1xuXG4gICAgICAgICAgICBpZiAoYyA8IDEyOCkge1xuICAgICAgICAgICAgICAgIHV0ZnRleHQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShjKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2UgaWYoKGMgPiAxMjcpICYmIChjIDwgMjA0OCkpIHtcbiAgICAgICAgICAgICAgICB1dGZ0ZXh0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoKGMgPj4gNikgfCAxOTIpO1xuICAgICAgICAgICAgICAgIHV0ZnRleHQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSgoYyAmIDYzKSB8IDEyOCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICB1dGZ0ZXh0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoKGMgPj4gMTIpIHwgMjI0KTtcbiAgICAgICAgICAgICAgICB1dGZ0ZXh0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoKChjID4+IDYpICYgNjMpIHwgMTI4KTtcbiAgICAgICAgICAgICAgICB1dGZ0ZXh0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoKGMgJiA2MykgfCAxMjgpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gdXRmdGV4dDtcbiAgICB9LFxuXG4gICAgLy8gcHJpdmF0ZSBtZXRob2QgZm9yIFVURi04IGRlY29kaW5nXG4gICAgX3V0ZjhfZGVjb2RlIDogZnVuY3Rpb24gKHV0ZnRleHQpIHtcbiAgICAgICAgdmFyIHN0cmluZyA9IFtdLFxuICAgICAgICAgICAgaSA9IDAsXG4gICAgICAgICAgICBjID0gMCwgYzIgPSAwLCBjMyA9IDA7XG5cbiAgICAgICAgd2hpbGUgKCBpIDwgdXRmdGV4dC5sZW5ndGggKSB7XG4gICAgICAgICAgICBjID0gdXRmdGV4dC5jaGFyQ29kZUF0KGkpO1xuICAgICAgICAgICAgaWYgKGMgPCAxMjgpIHtcbiAgICAgICAgICAgICAgICBzdHJpbmcucHVzaChTdHJpbmcuZnJvbUNoYXJDb2RlKGMpKTtcbiAgICAgICAgICAgICAgICBpKys7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIGlmKChjID4gMTkxKSAmJiAoYyA8IDIyNCkpIHtcbiAgICAgICAgICAgICAgICBjMiA9IHV0ZnRleHQuY2hhckNvZGVBdChpKzEpO1xuICAgICAgICAgICAgICAgIHN0cmluZy5wdXNoKFN0cmluZy5mcm9tQ2hhckNvZGUoKChjICYgMzEpIDw8IDYpIHwgKGMyICYgNjMpKSk7XG4gICAgICAgICAgICAgICAgaSArPSAyO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgYzIgPSB1dGZ0ZXh0LmNoYXJDb2RlQXQoaSsxKTtcbiAgICAgICAgICAgICAgICBjMyA9IHV0ZnRleHQuY2hhckNvZGVBdChpKzIpO1xuICAgICAgICAgICAgICAgIHN0cmluZy5wdXNoKFN0cmluZy5mcm9tQ2hhckNvZGUoKChjICYgMTUpIDw8IDEyKSB8ICgoYzIgJiA2MykgPDwgNikgfCAoYzMgJiA2MykpKTtcbiAgICAgICAgICAgICAgICBpICs9IDM7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHN0cmluZy5qb2luKCcnKTtcbiAgICB9LFxuICAgIFxuICAgIF9kZXN0cmlwOiBmdW5jdGlvbiAoc3RyaXBwZWQsIHdyYXApe1xuICAgICAgICB2YXIgbGluZXMgPSBbXSwgbGluZW5vLCBpLFxuICAgICAgICAgICAgZGVzdHJpcHBlZCA9IFtdO1xuICAgICAgICBcbiAgICAgICAgaWYgKHdyYXA9PW51bGwpIFxuICAgICAgICAgICAgd3JhcCA9IDc2O1xuICAgICAgICAgICAgXG4gICAgICAgIHN0cmlwcGVkLnJlcGxhY2UoLyAvZywgXCJcIik7XG4gICAgICAgIGxpbmVubyA9IHN0cmlwcGVkLmxlbmd0aCAvIHdyYXA7XG4gICAgICAgIGZvciAoaSA9IDA7IGkgPCBsaW5lbm87IGkrKylcbiAgICAgICAgICAgIGxpbmVzW2ldPXN0cmlwcGVkLnN1YnN0cihpICogd3JhcCwgd3JhcCk7XG4gICAgICAgIGlmIChsaW5lbm8gIT0gc3RyaXBwZWQubGVuZ3RoIC8gd3JhcClcbiAgICAgICAgICAgIGxpbmVzW2xpbmVzLmxlbmd0aF09c3RyaXBwZWQuc3Vic3RyKGxpbmVubyAqIHdyYXAsIHN0cmlwcGVkLmxlbmd0aC0obGluZW5vICogd3JhcCkpO1xuICAgICAgICAgICAgXG4gICAgICAgIGZvciAoaSA9IDA7IGkgPCBsaW5lcy5sZW5ndGg7IGkrKylcbiAgICAgICAgICAgIGRlc3RyaXBwZWQucHVzaChsaW5lc1tpXSk7XG4gICAgICAgIHJldHVybiBkZXN0cmlwcGVkLmpvaW4oJ1xcbicpO1xuICAgIH0sXG4gICAgXG4gICAgZGVjb2RlQXNBcnJheTogZnVuY3Rpb24gKGlucHV0KXtcbiAgICAgICAgdmFyIGRlYyA9IHRoaXMuZGVjb2RlKGlucHV0KSxcbiAgICAgICAgICAgIGFyID0gW10sIGk7XG4gICAgICAgIGZvciAoaT0wO2k8ZGVjLmxlbmd0aDtpKyspe1xuICAgICAgICAgICAgYXJbaV09ZGVjLmNoYXJDb2RlQXQoaSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGFyO1xuICAgIH0sXG4gICAgXG4gICAgZGVjb2RlR0VPTkV4VCA6IGZ1bmN0aW9uIChpbnB1dCkge1xuICAgICAgICByZXR1cm4gZGVjb2RlQXNBcnJheShkZXN0cmlwKGlucHV0KSxmYWxzZSk7XG4gICAgfVxufTtcblxuLyoqXG4gKiBAcHJpdmF0ZVxuICovXG5KWEcuVXRpbC5hc2NpaUNoYXJDb2RlQXQgPSBmdW5jdGlvbihzdHIsaSl7XG5cdHZhciBjID0gc3RyLmNoYXJDb2RlQXQoaSk7XG5cdGlmIChjPjI1NSl7XG4gICAgXHRzd2l0Y2ggKGMpIHtcblx0XHRcdGNhc2UgODM2NDogYz0xMjg7XG5cdCAgICBcdGJyZWFrO1xuXHQgICAgXHRjYXNlIDgyMTg6IGM9MTMwO1xuXHQgICAgXHRicmVhaztcblx0ICAgIFx0Y2FzZSA0MDI6IGM9MTMxO1xuXHQgICAgXHRicmVhaztcblx0ICAgIFx0Y2FzZSA4MjIyOiBjPTEzMjtcblx0ICAgIFx0YnJlYWs7XG5cdCAgICBcdGNhc2UgODIzMDogYz0xMzM7XG5cdCAgICBcdGJyZWFrO1xuXHQgICAgXHRjYXNlIDgyMjQ6IGM9MTM0O1xuXHQgICAgXHRicmVhaztcblx0ICAgIFx0Y2FzZSA4MjI1OiBjPTEzNTtcblx0ICAgIFx0YnJlYWs7XG5cdCAgICBcdGNhc2UgNzEwOiBjPTEzNjtcblx0ICAgIFx0YnJlYWs7XG5cdCAgICBcdGNhc2UgODI0MDogYz0xMzc7XG5cdCAgICBcdGJyZWFrO1xuXHQgICAgXHRjYXNlIDM1MjogYz0xMzg7XG5cdCAgICBcdGJyZWFrO1xuXHQgICAgXHRjYXNlIDgyNDk6IGM9MTM5O1xuXHQgICAgXHRicmVhaztcblx0ICAgIFx0Y2FzZSAzMzg6IGM9MTQwO1xuXHQgICAgXHRicmVhaztcblx0ICAgIFx0Y2FzZSAzODE6IGM9MTQyO1xuXHQgICAgXHRicmVhaztcblx0ICAgIFx0Y2FzZSA4MjE2OiBjPTE0NTtcblx0ICAgIFx0YnJlYWs7XG5cdCAgICBcdGNhc2UgODIxNzogYz0xNDY7XG5cdCAgICBcdGJyZWFrO1xuXHQgICAgXHRjYXNlIDgyMjA6IGM9MTQ3O1xuXHQgICAgXHRicmVhaztcblx0ICAgIFx0Y2FzZSA4MjIxOiBjPTE0ODtcblx0ICAgIFx0YnJlYWs7XG5cdCAgICBcdGNhc2UgODIyNjogYz0xNDk7XG5cdCAgICBcdGJyZWFrO1xuXHQgICAgXHRjYXNlIDgyMTE6IGM9MTUwO1xuXHQgICAgXHRicmVhaztcblx0ICAgIFx0Y2FzZSA4MjEyOiBjPTE1MTtcblx0ICAgIFx0YnJlYWs7XG5cdCAgICBcdGNhc2UgNzMyOiBjPTE1Mjtcblx0ICAgIFx0YnJlYWs7XG5cdCAgICBcdGNhc2UgODQ4MjogYz0xNTM7XG5cdCAgICBcdGJyZWFrO1xuXHQgICAgXHRjYXNlIDM1MzogYz0xNTQ7XG5cdCAgICBcdGJyZWFrO1xuXHQgICAgXHRjYXNlIDgyNTA6IGM9MTU1O1xuXHQgICAgXHRicmVhaztcblx0ICAgIFx0Y2FzZSAzMzk6IGM9MTU2O1xuXHQgICAgXHRicmVhaztcblx0ICAgIFx0Y2FzZSAzODI6IGM9MTU4O1xuXHQgICAgXHRicmVhaztcblx0ICAgIFx0Y2FzZSAzNzY6IGM9MTU5O1xuXHQgICAgXHRicmVhaztcblx0ICAgIFx0ZGVmYXVsdDpcblx0ICAgIFx0YnJlYWs7XG5cdCAgICB9XG5cdH1cblx0cmV0dXJuIGM7XG59O1xuXG4vKipcbiAqIERlY29kaW5nIHN0cmluZyBpbnRvIHV0Zi04XG4gKiBAcGFyYW0ge1N0cmluZ30gc3RyaW5nIHRvIGRlY29kZVxuICogQHJldHVybiB7U3RyaW5nfSB1dGY4IGRlY29kZWQgc3RyaW5nXG4gKi9cbkpYRy5VdGlsLnV0ZjhEZWNvZGUgPSBmdW5jdGlvbih1dGZ0ZXh0KSB7XG4gIHZhciBzdHJpbmcgPSBbXTtcbiAgdmFyIGkgPSAwO1xuICB2YXIgYyA9IDAsIGMxID0gMCwgYzIgPSAwLCBjMztcbiAgaWYgKCFKWEcuZXhpc3RzKHV0ZnRleHQpKSByZXR1cm4gJyc7XG4gIFxuICB3aGlsZSAoIGkgPCB1dGZ0ZXh0Lmxlbmd0aCApIHtcbiAgICBjID0gdXRmdGV4dC5jaGFyQ29kZUF0KGkpO1xuXG4gICAgaWYgKGMgPCAxMjgpIHtcbiAgICAgIHN0cmluZy5wdXNoKFN0cmluZy5mcm9tQ2hhckNvZGUoYykpO1xuICAgICAgaSsrO1xuICAgIH0gZWxzZSBpZigoYyA+IDE5MSkgJiYgKGMgPCAyMjQpKSB7XG4gICAgICBjMiA9IHV0ZnRleHQuY2hhckNvZGVBdChpKzEpO1xuICAgICAgc3RyaW5nLnB1c2goU3RyaW5nLmZyb21DaGFyQ29kZSgoKGMgJiAzMSkgPDwgNikgfCAoYzIgJiA2MykpKTtcbiAgICAgIGkgKz0gMjtcbiAgICB9IGVsc2Uge1xuICAgICAgYzIgPSB1dGZ0ZXh0LmNoYXJDb2RlQXQoaSsxKTtcbiAgICAgIGMzID0gdXRmdGV4dC5jaGFyQ29kZUF0KGkrMik7XG4gICAgICBzdHJpbmcucHVzaChTdHJpbmcuZnJvbUNoYXJDb2RlKCgoYyAmIDE1KSA8PCAxMikgfCAoKGMyICYgNjMpIDw8IDYpIHwgKGMzICYgNjMpKSk7XG4gICAgICBpICs9IDM7XG4gICAgfVxuICB9O1xuICByZXR1cm4gc3RyaW5nLmpvaW4oJycpO1xufTtcblxuLyoqXG4gKiBHZW5lcmF0ZSBhIHJhbmRvbSB1dWlkLlxuICogaHR0cDovL3d3dy5icm9vZmEuY29tXG4gKiBtYWlsdG86cm9iZXJ0QGJyb29mYS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgKGMpIDIwMTAgUm9iZXJ0IEtpZWZmZXJcbiAqIER1YWwgbGljZW5zZWQgdW5kZXIgdGhlIE1JVCBhbmQgR1BMIGxpY2Vuc2VzLlxuICpcbiAqIEVYQU1QTEVTOlxuICogICA+Pj4gTWF0aC51dWlkKClcbiAqICAgXCI5MjMyOUQzOS02RjVDLTQ1MjAtQUJGQy1BQUI2NDU0NEUxNzJcIlxuICovXG5KWEcuVXRpbC5nZW5VVUlEID0gZnVuY3Rpb24oKSB7XG4gICAgLy8gUHJpdmF0ZSBhcnJheSBvZiBjaGFycyB0byB1c2VcbiAgICB2YXIgY2hhcnMgPSAnMDEyMzQ1Njc4OUFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXonLnNwbGl0KCcnKSxcbiAgICAgICAgdXVpZCA9IG5ldyBBcnJheSgzNiksIHJuZD0wLCByO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCAzNjsgaSsrKSB7XG4gICAgICBpZiAoaT09OCB8fCBpPT0xMyB8fCAgaT09MTggfHwgaT09MjMpIHtcbiAgICAgICAgdXVpZFtpXSA9ICctJztcbiAgICAgIH0gZWxzZSBpZiAoaT09MTQpIHtcbiAgICAgICAgdXVpZFtpXSA9ICc0JztcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGlmIChybmQgPD0gMHgwMikgcm5kID0gMHgyMDAwMDAwICsgKE1hdGgucmFuZG9tKCkqMHgxMDAwMDAwKXwwO1xuICAgICAgICByID0gcm5kICYgMHhmO1xuICAgICAgICBybmQgPSBybmQgPj4gNDtcbiAgICAgICAgdXVpZFtpXSA9IGNoYXJzWyhpID09IDE5KSA/IChyICYgMHgzKSB8IDB4OCA6IHJdO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB1dWlkLmpvaW4oJycpO1xufTtcblxuXG5tb2R1bGUuZXhwb3J0cyA9IEpYRztcbiIsIihmdW5jdGlvbigpey8qKlxuICogQSBmYXN0IE1ENSBKYXZhU2NyaXB0IGltcGxlbWVudGF0aW9uXG4gKiBDb3B5cmlnaHQgKGMpIDIwMTIgSm9zZXBoIE15ZXJzXG4gKiBodHRwOi8vd3d3Lm15ZXJzZGFpbHkub3JnL2pvc2VwaC9qYXZhc2NyaXB0L21kNS10ZXh0Lmh0bWxcbiAqXG4gKiBQZXJtaXNzaW9uIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBhbmQgZGlzdHJpYnV0ZSB0aGlzIHNvZnR3YXJlXG4gKiBhbmQgaXRzIGRvY3VtZW50YXRpb24gZm9yIGFueSBwdXJwb3NlcyBhbmQgd2l0aG91dFxuICogZmVlIGlzIGhlcmVieSBncmFudGVkIHByb3ZpZGVkIHRoYXQgdGhpcyBjb3B5cmlnaHQgbm90aWNlXG4gKiBhcHBlYXJzIGluIGFsbCBjb3BpZXMuXG4gKlxuICogT2YgY291cnNlLCB0aGlzIHNvZnQgaXMgcHJvdmlkZWQgXCJhcyBpc1wiIHdpdGhvdXQgZXhwcmVzcyBvciBpbXBsaWVkXG4gKiB3YXJyYW50eSBvZiBhbnkga2luZC5cbiAqL1xuXG52YXIgdXRpbCA9IHJlcXVpcmUoJy4uLy4uL3V0aWwvdXRpbC5qcycpO1xuXG5mdW5jdGlvbiBNRDUoZW50cmVlKSB7XG5cdHZhciBoZXggPSBtZDUoZW50cmVlKTtcblx0dmFyIGJpbiA9IHV0aWwuaGV4MmJpbihoZXgpO1xuXHRyZXR1cm4gYmluO1xufVxuXG5mdW5jdGlvbiBtZDVjeWNsZSh4LCBrKSB7XG52YXIgYSA9IHhbMF0sIGIgPSB4WzFdLCBjID0geFsyXSwgZCA9IHhbM107XG5cbmEgPSBmZihhLCBiLCBjLCBkLCBrWzBdLCA3LCAtNjgwODc2OTM2KTtcbmQgPSBmZihkLCBhLCBiLCBjLCBrWzFdLCAxMiwgLTM4OTU2NDU4Nik7XG5jID0gZmYoYywgZCwgYSwgYiwga1syXSwgMTcsICA2MDYxMDU4MTkpO1xuYiA9IGZmKGIsIGMsIGQsIGEsIGtbM10sIDIyLCAtMTA0NDUyNTMzMCk7XG5hID0gZmYoYSwgYiwgYywgZCwga1s0XSwgNywgLTE3NjQxODg5Nyk7XG5kID0gZmYoZCwgYSwgYiwgYywga1s1XSwgMTIsICAxMjAwMDgwNDI2KTtcbmMgPSBmZihjLCBkLCBhLCBiLCBrWzZdLCAxNywgLTE0NzMyMzEzNDEpO1xuYiA9IGZmKGIsIGMsIGQsIGEsIGtbN10sIDIyLCAtNDU3MDU5ODMpO1xuYSA9IGZmKGEsIGIsIGMsIGQsIGtbOF0sIDcsICAxNzcwMDM1NDE2KTtcbmQgPSBmZihkLCBhLCBiLCBjLCBrWzldLCAxMiwgLTE5NTg0MTQ0MTcpO1xuYyA9IGZmKGMsIGQsIGEsIGIsIGtbMTBdLCAxNywgLTQyMDYzKTtcbmIgPSBmZihiLCBjLCBkLCBhLCBrWzExXSwgMjIsIC0xOTkwNDA0MTYyKTtcbmEgPSBmZihhLCBiLCBjLCBkLCBrWzEyXSwgNywgIDE4MDQ2MDM2ODIpO1xuZCA9IGZmKGQsIGEsIGIsIGMsIGtbMTNdLCAxMiwgLTQwMzQxMTAxKTtcbmMgPSBmZihjLCBkLCBhLCBiLCBrWzE0XSwgMTcsIC0xNTAyMDAyMjkwKTtcbmIgPSBmZihiLCBjLCBkLCBhLCBrWzE1XSwgMjIsICAxMjM2NTM1MzI5KTtcblxuYSA9IGdnKGEsIGIsIGMsIGQsIGtbMV0sIDUsIC0xNjU3OTY1MTApO1xuZCA9IGdnKGQsIGEsIGIsIGMsIGtbNl0sIDksIC0xMDY5NTAxNjMyKTtcbmMgPSBnZyhjLCBkLCBhLCBiLCBrWzExXSwgMTQsICA2NDM3MTc3MTMpO1xuYiA9IGdnKGIsIGMsIGQsIGEsIGtbMF0sIDIwLCAtMzczODk3MzAyKTtcbmEgPSBnZyhhLCBiLCBjLCBkLCBrWzVdLCA1LCAtNzAxNTU4NjkxKTtcbmQgPSBnZyhkLCBhLCBiLCBjLCBrWzEwXSwgOSwgIDM4MDE2MDgzKTtcbmMgPSBnZyhjLCBkLCBhLCBiLCBrWzE1XSwgMTQsIC02NjA0NzgzMzUpO1xuYiA9IGdnKGIsIGMsIGQsIGEsIGtbNF0sIDIwLCAtNDA1NTM3ODQ4KTtcbmEgPSBnZyhhLCBiLCBjLCBkLCBrWzldLCA1LCAgNTY4NDQ2NDM4KTtcbmQgPSBnZyhkLCBhLCBiLCBjLCBrWzE0XSwgOSwgLTEwMTk4MDM2OTApO1xuYyA9IGdnKGMsIGQsIGEsIGIsIGtbM10sIDE0LCAtMTg3MzYzOTYxKTtcbmIgPSBnZyhiLCBjLCBkLCBhLCBrWzhdLCAyMCwgIDExNjM1MzE1MDEpO1xuYSA9IGdnKGEsIGIsIGMsIGQsIGtbMTNdLCA1LCAtMTQ0NDY4MTQ2Nyk7XG5kID0gZ2coZCwgYSwgYiwgYywga1syXSwgOSwgLTUxNDAzNzg0KTtcbmMgPSBnZyhjLCBkLCBhLCBiLCBrWzddLCAxNCwgIDE3MzUzMjg0NzMpO1xuYiA9IGdnKGIsIGMsIGQsIGEsIGtbMTJdLCAyMCwgLTE5MjY2MDc3MzQpO1xuXG5hID0gaGgoYSwgYiwgYywgZCwga1s1XSwgNCwgLTM3ODU1OCk7XG5kID0gaGgoZCwgYSwgYiwgYywga1s4XSwgMTEsIC0yMDIyNTc0NDYzKTtcbmMgPSBoaChjLCBkLCBhLCBiLCBrWzExXSwgMTYsICAxODM5MDMwNTYyKTtcbmIgPSBoaChiLCBjLCBkLCBhLCBrWzE0XSwgMjMsIC0zNTMwOTU1Nik7XG5hID0gaGgoYSwgYiwgYywgZCwga1sxXSwgNCwgLTE1MzA5OTIwNjApO1xuZCA9IGhoKGQsIGEsIGIsIGMsIGtbNF0sIDExLCAgMTI3Mjg5MzM1Myk7XG5jID0gaGgoYywgZCwgYSwgYiwga1s3XSwgMTYsIC0xNTU0OTc2MzIpO1xuYiA9IGhoKGIsIGMsIGQsIGEsIGtbMTBdLCAyMywgLTEwOTQ3MzA2NDApO1xuYSA9IGhoKGEsIGIsIGMsIGQsIGtbMTNdLCA0LCAgNjgxMjc5MTc0KTtcbmQgPSBoaChkLCBhLCBiLCBjLCBrWzBdLCAxMSwgLTM1ODUzNzIyMik7XG5jID0gaGgoYywgZCwgYSwgYiwga1szXSwgMTYsIC03MjI1MjE5NzkpO1xuYiA9IGhoKGIsIGMsIGQsIGEsIGtbNl0sIDIzLCAgNzYwMjkxODkpO1xuYSA9IGhoKGEsIGIsIGMsIGQsIGtbOV0sIDQsIC02NDAzNjQ0ODcpO1xuZCA9IGhoKGQsIGEsIGIsIGMsIGtbMTJdLCAxMSwgLTQyMTgxNTgzNSk7XG5jID0gaGgoYywgZCwgYSwgYiwga1sxNV0sIDE2LCAgNTMwNzQyNTIwKTtcbmIgPSBoaChiLCBjLCBkLCBhLCBrWzJdLCAyMywgLTk5NTMzODY1MSk7XG5cbmEgPSBpaShhLCBiLCBjLCBkLCBrWzBdLCA2LCAtMTk4NjMwODQ0KTtcbmQgPSBpaShkLCBhLCBiLCBjLCBrWzddLCAxMCwgIDExMjY4OTE0MTUpO1xuYyA9IGlpKGMsIGQsIGEsIGIsIGtbMTRdLCAxNSwgLTE0MTYzNTQ5MDUpO1xuYiA9IGlpKGIsIGMsIGQsIGEsIGtbNV0sIDIxLCAtNTc0MzQwNTUpO1xuYSA9IGlpKGEsIGIsIGMsIGQsIGtbMTJdLCA2LCAgMTcwMDQ4NTU3MSk7XG5kID0gaWkoZCwgYSwgYiwgYywga1szXSwgMTAsIC0xODk0OTg2NjA2KTtcbmMgPSBpaShjLCBkLCBhLCBiLCBrWzEwXSwgMTUsIC0xMDUxNTIzKTtcbmIgPSBpaShiLCBjLCBkLCBhLCBrWzFdLCAyMSwgLTIwNTQ5MjI3OTkpO1xuYSA9IGlpKGEsIGIsIGMsIGQsIGtbOF0sIDYsICAxODczMzEzMzU5KTtcbmQgPSBpaShkLCBhLCBiLCBjLCBrWzE1XSwgMTAsIC0zMDYxMTc0NCk7XG5jID0gaWkoYywgZCwgYSwgYiwga1s2XSwgMTUsIC0xNTYwMTk4MzgwKTtcbmIgPSBpaShiLCBjLCBkLCBhLCBrWzEzXSwgMjEsICAxMzA5MTUxNjQ5KTtcbmEgPSBpaShhLCBiLCBjLCBkLCBrWzRdLCA2LCAtMTQ1NTIzMDcwKTtcbmQgPSBpaShkLCBhLCBiLCBjLCBrWzExXSwgMTAsIC0xMTIwMjEwMzc5KTtcbmMgPSBpaShjLCBkLCBhLCBiLCBrWzJdLCAxNSwgIDcxODc4NzI1OSk7XG5iID0gaWkoYiwgYywgZCwgYSwga1s5XSwgMjEsIC0zNDM0ODU1NTEpO1xuXG54WzBdID0gYWRkMzIoYSwgeFswXSk7XG54WzFdID0gYWRkMzIoYiwgeFsxXSk7XG54WzJdID0gYWRkMzIoYywgeFsyXSk7XG54WzNdID0gYWRkMzIoZCwgeFszXSk7XG5cbn1cblxuZnVuY3Rpb24gY21uKHEsIGEsIGIsIHgsIHMsIHQpIHtcbmEgPSBhZGQzMihhZGQzMihhLCBxKSwgYWRkMzIoeCwgdCkpO1xucmV0dXJuIGFkZDMyKChhIDw8IHMpIHwgKGEgPj4+ICgzMiAtIHMpKSwgYik7XG59XG5cbmZ1bmN0aW9uIGZmKGEsIGIsIGMsIGQsIHgsIHMsIHQpIHtcbnJldHVybiBjbW4oKGIgJiBjKSB8ICgofmIpICYgZCksIGEsIGIsIHgsIHMsIHQpO1xufVxuXG5mdW5jdGlvbiBnZyhhLCBiLCBjLCBkLCB4LCBzLCB0KSB7XG5yZXR1cm4gY21uKChiICYgZCkgfCAoYyAmICh+ZCkpLCBhLCBiLCB4LCBzLCB0KTtcbn1cblxuZnVuY3Rpb24gaGgoYSwgYiwgYywgZCwgeCwgcywgdCkge1xucmV0dXJuIGNtbihiIF4gYyBeIGQsIGEsIGIsIHgsIHMsIHQpO1xufVxuXG5mdW5jdGlvbiBpaShhLCBiLCBjLCBkLCB4LCBzLCB0KSB7XG5yZXR1cm4gY21uKGMgXiAoYiB8ICh+ZCkpLCBhLCBiLCB4LCBzLCB0KTtcbn1cblxuZnVuY3Rpb24gbWQ1MShzKSB7XG50eHQgPSAnJztcbnZhciBuID0gcy5sZW5ndGgsXG5zdGF0ZSA9IFsxNzMyNTg0MTkzLCAtMjcxNzMzODc5LCAtMTczMjU4NDE5NCwgMjcxNzMzODc4XSwgaTtcbmZvciAoaT02NDsgaTw9cy5sZW5ndGg7IGkrPTY0KSB7XG5tZDVjeWNsZShzdGF0ZSwgbWQ1YmxrKHMuc3Vic3RyaW5nKGktNjQsIGkpKSk7XG59XG5zID0gcy5zdWJzdHJpbmcoaS02NCk7XG52YXIgdGFpbCA9IFswLDAsMCwwLCAwLDAsMCwwLCAwLDAsMCwwLCAwLDAsMCwwXTtcbmZvciAoaT0wOyBpPHMubGVuZ3RoOyBpKyspXG50YWlsW2k+PjJdIHw9IHMuY2hhckNvZGVBdChpKSA8PCAoKGklNCkgPDwgMyk7XG50YWlsW2k+PjJdIHw9IDB4ODAgPDwgKChpJTQpIDw8IDMpO1xuaWYgKGkgPiA1NSkge1xubWQ1Y3ljbGUoc3RhdGUsIHRhaWwpO1xuZm9yIChpPTA7IGk8MTY7IGkrKykgdGFpbFtpXSA9IDA7XG59XG50YWlsWzE0XSA9IG4qODtcbm1kNWN5Y2xlKHN0YXRlLCB0YWlsKTtcbnJldHVybiBzdGF0ZTtcbn1cblxuLyogdGhlcmUgbmVlZHMgdG8gYmUgc3VwcG9ydCBmb3IgVW5pY29kZSBoZXJlLFxuICogdW5sZXNzIHdlIHByZXRlbmQgdGhhdCB3ZSBjYW4gcmVkZWZpbmUgdGhlIE1ELTVcbiAqIGFsZ29yaXRobSBmb3IgbXVsdGktYnl0ZSBjaGFyYWN0ZXJzIChwZXJoYXBzXG4gKiBieSBhZGRpbmcgZXZlcnkgZm91ciAxNi1iaXQgY2hhcmFjdGVycyBhbmRcbiAqIHNob3J0ZW5pbmcgdGhlIHN1bSB0byAzMiBiaXRzKS4gT3RoZXJ3aXNlXG4gKiBJIHN1Z2dlc3QgcGVyZm9ybWluZyBNRC01IGFzIGlmIGV2ZXJ5IGNoYXJhY3RlclxuICogd2FzIHR3byBieXRlcy0tZS5nLiwgMDA0MCAwMDI1ID0gQCUtLWJ1dCB0aGVuXG4gKiBob3cgd2lsbCBhbiBvcmRpbmFyeSBNRC01IHN1bSBiZSBtYXRjaGVkP1xuICogVGhlcmUgaXMgbm8gd2F5IHRvIHN0YW5kYXJkaXplIHRleHQgdG8gc29tZXRoaW5nXG4gKiBsaWtlIFVURi04IGJlZm9yZSB0cmFuc2Zvcm1hdGlvbjsgc3BlZWQgY29zdCBpc1xuICogdXR0ZXJseSBwcm9oaWJpdGl2ZS4gVGhlIEphdmFTY3JpcHQgc3RhbmRhcmRcbiAqIGl0c2VsZiBuZWVkcyB0byBsb29rIGF0IHRoaXM6IGl0IHNob3VsZCBzdGFydFxuICogcHJvdmlkaW5nIGFjY2VzcyB0byBzdHJpbmdzIGFzIHByZWZvcm1lZCBVVEYtOFxuICogOC1iaXQgdW5zaWduZWQgdmFsdWUgYXJyYXlzLlxuICovXG5mdW5jdGlvbiBtZDVibGsocykgeyAvKiBJIGZpZ3VyZWQgZ2xvYmFsIHdhcyBmYXN0ZXIuICAgKi9cbnZhciBtZDVibGtzID0gW10sIGk7IC8qIEFuZHkgS2luZyBzYWlkIGRvIGl0IHRoaXMgd2F5LiAqL1xuZm9yIChpPTA7IGk8NjQ7IGkrPTQpIHtcbm1kNWJsa3NbaT4+Ml0gPSBzLmNoYXJDb2RlQXQoaSlcbisgKHMuY2hhckNvZGVBdChpKzEpIDw8IDgpXG4rIChzLmNoYXJDb2RlQXQoaSsyKSA8PCAxNilcbisgKHMuY2hhckNvZGVBdChpKzMpIDw8IDI0KTtcbn1cbnJldHVybiBtZDVibGtzO1xufVxuXG52YXIgaGV4X2NociA9ICcwMTIzNDU2Nzg5YWJjZGVmJy5zcGxpdCgnJyk7XG5cbmZ1bmN0aW9uIHJoZXgobilcbntcbnZhciBzPScnLCBqPTA7XG5mb3IoOyBqPDQ7IGorKylcbnMgKz0gaGV4X2NoclsobiA+PiAoaiAqIDggKyA0KSkgJiAweDBGXVxuKyBoZXhfY2hyWyhuID4+IChqICogOCkpICYgMHgwRl07XG5yZXR1cm4gcztcbn1cblxuZnVuY3Rpb24gaGV4KHgpIHtcbmZvciAodmFyIGk9MDsgaTx4Lmxlbmd0aDsgaSsrKVxueFtpXSA9IHJoZXgoeFtpXSk7XG5yZXR1cm4geC5qb2luKCcnKTtcbn1cblxuZnVuY3Rpb24gbWQ1KHMpIHtcbnJldHVybiBoZXgobWQ1MShzKSk7XG59XG5cbi8qIHRoaXMgZnVuY3Rpb24gaXMgbXVjaCBmYXN0ZXIsXG5zbyBpZiBwb3NzaWJsZSB3ZSB1c2UgaXQuIFNvbWUgSUVzXG5hcmUgdGhlIG9ubHkgb25lcyBJIGtub3cgb2YgdGhhdFxubmVlZCB0aGUgaWRpb3RpYyBzZWNvbmQgZnVuY3Rpb24sXG5nZW5lcmF0ZWQgYnkgYW4gaWYgY2xhdXNlLiAgKi9cblxuZnVuY3Rpb24gYWRkMzIoYSwgYikge1xucmV0dXJuIChhICsgYikgJiAweEZGRkZGRkZGO1xufVxuXG5pZiAobWQ1KCdoZWxsbycpICE9ICc1ZDQxNDAyYWJjNGIyYTc2Yjk3MTlkOTExMDE3YzU5MicpIHtcbmZ1bmN0aW9uIGFkZDMyKHgsIHkpIHtcbnZhciBsc3cgPSAoeCAmIDB4RkZGRikgKyAoeSAmIDB4RkZGRiksXG5tc3cgPSAoeCA+PiAxNikgKyAoeSA+PiAxNikgKyAobHN3ID4+IDE2KTtcbnJldHVybiAobXN3IDw8IDE2KSB8IChsc3cgJiAweEZGRkYpO1xufVxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IE1ENVxuXG59KSgpIiwiLy8gR1BHNEJyb3dzZXJzIC0gQW4gT3BlblBHUCBpbXBsZW1lbnRhdGlvbiBpbiBqYXZhc2NyaXB0XG4vLyBDb3B5cmlnaHQgKEMpIDIwMTEgUmVjdXJpdHkgTGFicyBHbWJIXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3Jcbi8vIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlclxuLy8gdmVyc2lvbiAyLjEgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuLy8gYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2Zcbi8vIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUgR05VXG4vLyBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuLy8gXG4vLyBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFsb25nIHdpdGggdGhpcyBsaWJyYXJ5OyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlXG4vLyBGb3VuZGF0aW9uLCBJbmMuLCA1MSBGcmFua2xpbiBTdHJlZXQsIEZpZnRoIEZsb29yLCBCb3N0b24sIE1BICAwMjExMC0xMzAxICBVU0FcblxudmFyIGVudW1zID0gcmVxdWlyZSgnLi4vZW51bXMuanMnKSxcblx0dXRpbCA9IHJlcXVpcmUoJy4uL3V0aWwnKTtcblxuXG5tb2R1bGUuZXhwb3J0cyA9IHtcblx0cmVhZFNpbXBsZUxlbmd0aDogZnVuY3Rpb24oYnl0ZXMpIHtcblx0XHR2YXIgbGVuID0gMCxcblx0XHRcdG9mZnNldCxcblx0XHRcdHR5cGUgPSBieXRlc1swXS5jaGFyQ29kZUF0KCk7XG5cblxuXHRcdGlmICh0eXBlIDwgMTkyKSB7XG5cdFx0XHRsZW4gPSBieXRlc1swXS5jaGFyQ29kZUF0KCk7XG5cdFx0XHRvZmZzZXQgPSAxO1xuXHRcdH0gZWxzZSBpZiAodHlwZSA8IDI1NSkge1xuXHRcdFx0bGVuID0gKChieXRlc1swXS5jaGFyQ29kZUF0KCkgLSAxOTIpIDw8IDgpICsgKGJ5dGVzWzFdLmNoYXJDb2RlQXQoKSkgKyAxOTI7XG5cdFx0XHRvZmZzZXQgPSAyO1xuXHRcdH0gZWxzZSBpZiAodHlwZSA9PSAyNTUpIHtcblx0XHRcdGxlbiA9IHV0aWwucmVhZE51bWJlcihieXRlcy5zdWJzdHIoMSwgNCkpO1xuXHRcdFx0b2Zmc2V0ID0gNTtcblx0XHR9XG5cblx0XHRyZXR1cm4geyBsZW46IGxlbiwgb2Zmc2V0OiBvZmZzZXQgfTtcblx0fSxcblxuXHQvKipcblx0ICogRW5jb2RlcyBhIGdpdmVuIGludGVnZXIgb2YgbGVuZ3RoIHRvIHRoZSBvcGVucGdwIGxlbmd0aCBzcGVjaWZpZXIgdG8gYVxuXHQgKiBzdHJpbmdcblx0ICogXG5cdCAqIEBwYXJhbSB7SW50ZWdlcn0gbGVuZ3RoIFRoZSBsZW5ndGggdG8gZW5jb2RlXG5cdCAqIEByZXR1cm4ge1N0cmluZ30gU3RyaW5nIHdpdGggb3BlbnBncCBsZW5ndGggcmVwcmVzZW50YXRpb25cblx0ICovXG5cdHdyaXRlU2ltcGxlTGVuZ3RoOiBmdW5jdGlvbihsZW5ndGgpIHtcblx0XHR2YXIgcmVzdWx0ID0gXCJcIjtcblx0XHRpZiAobGVuZ3RoIDwgMTkyKSB7XG5cdFx0XHRyZXN1bHQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShsZW5ndGgpO1xuXHRcdH0gZWxzZSBpZiAobGVuZ3RoID4gMTkxICYmIGxlbmd0aCA8IDgzODQpIHtcblx0XHRcdC8qXG5cdFx0XHQgKiBsZXQgYSA9ICh0b3RhbCBkYXRhIHBhY2tldCBsZW5ndGgpIC0gMTkyIGxldCBiYyA9IHR3byBvY3RldFxuXHRcdFx0ICogcmVwcmVzZW50YXRpb24gb2YgYSBsZXQgZCA9IGIgKyAxOTJcblx0XHRcdCAqL1xuXHRcdFx0cmVzdWx0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoKChsZW5ndGggLSAxOTIpID4+IDgpICsgMTkyKTtcblx0XHRcdHJlc3VsdCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKChsZW5ndGggLSAxOTIpICYgMHhGRik7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHJlc3VsdCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKDI1NSk7XG5cdFx0XHRyZXN1bHQgKz0gdXRpbC53cml0ZU51bWJlcihsZW5ndGgsIDQpO1xuXHRcdH1cblx0XHRyZXR1cm4gcmVzdWx0O1xuXHR9LFxuXG5cdC8qKlxuXHQgKiBXcml0ZXMgYSBwYWNrZXQgaGVhZGVyIHZlcnNpb24gNCB3aXRoIHRoZSBnaXZlbiB0YWdfdHlwZSBhbmQgbGVuZ3RoIHRvIGFcblx0ICogc3RyaW5nXG5cdCAqIFxuXHQgKiBAcGFyYW0ge0ludGVnZXJ9IHRhZ190eXBlIFRhZyB0eXBlXG5cdCAqIEBwYXJhbSB7SW50ZWdlcn0gbGVuZ3RoIExlbmd0aCBvZiB0aGUgcGF5bG9hZFxuXHQgKiBAcmV0dXJuIHtTdHJpbmd9IFN0cmluZyBvZiB0aGUgaGVhZGVyXG5cdCAqL1xuXHR3cml0ZUhlYWRlcjogZnVuY3Rpb24odGFnX3R5cGUsIGxlbmd0aCkge1xuXHRcdC8qIHdlJ3JlIG9ubHkgZ2VuZXJhdGluZyB2NCBwYWNrZXQgaGVhZGVycyBoZXJlICovXG5cdFx0dmFyIHJlc3VsdCA9IFwiXCI7XG5cdFx0cmVzdWx0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoMHhDMCB8IHRhZ190eXBlKTtcblx0XHRyZXN1bHQgKz0gdGhpcy53cml0ZVNpbXBsZUxlbmd0aChsZW5ndGgpO1xuXHRcdHJldHVybiByZXN1bHQ7XG5cdH0sXG5cblx0LyoqXG5cdCAqIFdyaXRlcyBhIHBhY2tldCBoZWFkZXIgVmVyc2lvbiAzIHdpdGggdGhlIGdpdmVuIHRhZ190eXBlIGFuZCBsZW5ndGggdG8gYVxuXHQgKiBzdHJpbmdcblx0ICogXG5cdCAqIEBwYXJhbSB7SW50ZWdlcn0gdGFnX3R5cGUgVGFnIHR5cGVcblx0ICogQHBhcmFtIHtJbnRlZ2VyfSBsZW5ndGggTGVuZ3RoIG9mIHRoZSBwYXlsb2FkXG5cdCAqIEByZXR1cm4ge1N0cmluZ30gU3RyaW5nIG9mIHRoZSBoZWFkZXJcblx0ICovXG5cdHdyaXRlT2xkSGVhZGVyOiBmdW5jdGlvbih0YWdfdHlwZSwgbGVuZ3RoKSB7XG5cdFx0dmFyIHJlc3VsdCA9IFwiXCI7XG5cdFx0aWYgKGxlbmd0aCA8IDI1Nikge1xuXHRcdFx0cmVzdWx0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoMHg4MCB8ICh0YWdfdHlwZSA8PCAyKSk7XG5cdFx0XHRyZXN1bHQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShsZW5ndGgpO1xuXHRcdH0gZWxzZSBpZiAobGVuZ3RoIDwgNjU1MzYpIHtcblx0XHRcdHJlc3VsdCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKDB4ODAgfCAodGFnX3R5cGUgPDwgMikgfCAxKTtcblx0XHRcdHJlc3VsdCArPSB1dGlsLndyaXRlTnVtYmVyKGxlbmd0aCwgMik7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHJlc3VsdCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKDB4ODAgfCAodGFnX3R5cGUgPDwgMikgfCAyKTtcblx0XHRcdHJlc3VsdCArPSB1dGlsLndyaXRlTnVtYmVyKGxlbmd0aCwgNCk7XG5cdFx0fVxuXHRcdHJldHVybiByZXN1bHQ7XG5cdH0sXG5cblx0LyoqXG5cdCAqIEdlbmVyaWMgc3RhdGljIFBhY2tldCBQYXJzZXIgZnVuY3Rpb25cblx0ICogXG5cdCAqIEBwYXJhbSB7U3RyaW5nfSBpbnB1dCBJbnB1dCBzdHJlYW0gYXMgc3RyaW5nXG5cdCAqIEBwYXJhbSB7aW50ZWdlcn0gcG9zaXRpb24gUG9zaXRpb24gdG8gc3RhcnQgcGFyc2luZ1xuXHQgKiBAcGFyYW0ge2ludGVnZXJ9IGxlbiBMZW5ndGggb2YgdGhlIGlucHV0IGZyb20gcG9zaXRpb24gb25cblx0ICogQHJldHVybiB7T2JqZWN0fSBSZXR1cm5zIGEgcGFyc2VkIG9wZW5wZ3BfcGFja2V0XG5cdCAqL1xuXHRyZWFkOiBmdW5jdGlvbihpbnB1dCwgcG9zaXRpb24sIGxlbikge1xuXHRcdC8vIHNvbWUgc2FuaXR5IGNoZWNrc1xuXHRcdGlmIChpbnB1dCA9PSBudWxsIHx8IGlucHV0Lmxlbmd0aCA8PSBwb3NpdGlvblxuXHRcdFx0XHR8fCBpbnB1dC5zdWJzdHJpbmcocG9zaXRpb24pLmxlbmd0aCA8IDJcblx0XHRcdFx0fHwgKGlucHV0W3Bvc2l0aW9uXS5jaGFyQ29kZUF0KCkgJiAweDgwKSA9PSAwKSB7XG5cdFx0XHR1dGlsXG5cdFx0XHRcdFx0LnByaW50X2Vycm9yKFwiRXJyb3IgZHVyaW5nIHBhcnNpbmcuIFRoaXMgbWVzc2FnZSAvIGtleSBpcyBwcm9iYWJseSBub3QgY29udGFpbmluZyBhIHZhbGlkIE9wZW5QR1AgZm9ybWF0LlwiKTtcblx0XHRcdHJldHVybiBudWxsO1xuXHRcdH1cblx0XHR2YXIgbXlwb3MgPSBwb3NpdGlvbjtcblx0XHR2YXIgdGFnID0gLTE7XG5cdFx0dmFyIGZvcm1hdCA9IC0xO1xuXHRcdHZhciBwYWNrZXRfbGVuZ3RoO1xuXG5cdFx0Zm9ybWF0ID0gMDsgLy8gMCA9IG9sZCBmb3JtYXQ7IDEgPSBuZXcgZm9ybWF0XG5cdFx0aWYgKChpbnB1dFtteXBvc10uY2hhckNvZGVBdCgpICYgMHg0MCkgIT0gMCkge1xuXHRcdFx0Zm9ybWF0ID0gMTtcblx0XHR9XG5cblx0XHR2YXIgcGFja2V0X2xlbmd0aF90eXBlO1xuXHRcdGlmIChmb3JtYXQpIHtcblx0XHRcdC8vIG5ldyBmb3JtYXQgaGVhZGVyXG5cdFx0XHR0YWcgPSBpbnB1dFtteXBvc10uY2hhckNvZGVBdCgpICYgMHgzRjsgLy8gYml0IDUtMFxuXHRcdH0gZWxzZSB7XG5cdFx0XHQvLyBvbGQgZm9ybWF0IGhlYWRlclxuXHRcdFx0dGFnID0gKGlucHV0W215cG9zXS5jaGFyQ29kZUF0KCkgJiAweDNGKSA+PiAyOyAvLyBiaXQgNS0yXG5cdFx0XHRwYWNrZXRfbGVuZ3RoX3R5cGUgPSBpbnB1dFtteXBvc10uY2hhckNvZGVBdCgpICYgMHgwMzsgLy8gYml0IDEtMFxuXHRcdH1cblxuXHRcdC8vIGhlYWRlciBvY3RldCBwYXJzaW5nIGRvbmVcblx0XHRteXBvcysrO1xuXG5cdFx0Ly8gcGFyc2VkIGxlbmd0aCBmcm9tIGxlbmd0aCBmaWVsZFxuXHRcdHZhciBib2R5ZGF0YSA9IG51bGw7XG5cblx0XHQvLyB1c2VkIGZvciBwYXJ0aWFsIGJvZHkgbGVuZ3Roc1xuXHRcdHZhciByZWFsX3BhY2tldF9sZW5ndGggPSAtMTtcblx0XHRpZiAoIWZvcm1hdCkge1xuXHRcdFx0Ly8gNC4yLjEuIE9sZCBGb3JtYXQgUGFja2V0IExlbmd0aHNcblx0XHRcdHN3aXRjaCAocGFja2V0X2xlbmd0aF90eXBlKSB7XG5cdFx0XHRjYXNlIDA6IC8vIFRoZSBwYWNrZXQgaGFzIGEgb25lLW9jdGV0IGxlbmd0aC4gVGhlIGhlYWRlciBpcyAyIG9jdGV0c1xuXHRcdFx0XHQvLyBsb25nLlxuXHRcdFx0XHRwYWNrZXRfbGVuZ3RoID0gaW5wdXRbbXlwb3MrK10uY2hhckNvZGVBdCgpO1xuXHRcdFx0XHRicmVhaztcblx0XHRcdGNhc2UgMTogLy8gVGhlIHBhY2tldCBoYXMgYSB0d28tb2N0ZXQgbGVuZ3RoLiBUaGUgaGVhZGVyIGlzIDMgb2N0ZXRzXG5cdFx0XHRcdC8vIGxvbmcuXG5cdFx0XHRcdHBhY2tldF9sZW5ndGggPSAoaW5wdXRbbXlwb3MrK10uY2hhckNvZGVBdCgpIDw8IDgpXG5cdFx0XHRcdFx0XHR8IGlucHV0W215cG9zKytdLmNoYXJDb2RlQXQoKTtcblx0XHRcdFx0YnJlYWs7XG5cdFx0XHRjYXNlIDI6IC8vIFRoZSBwYWNrZXQgaGFzIGEgZm91ci1vY3RldCBsZW5ndGguIFRoZSBoZWFkZXIgaXMgNVxuXHRcdFx0XHQvLyBvY3RldHMgbG9uZy5cblx0XHRcdFx0cGFja2V0X2xlbmd0aCA9IChpbnB1dFtteXBvcysrXS5jaGFyQ29kZUF0KCkgPDwgMjQpXG5cdFx0XHRcdFx0XHR8IChpbnB1dFtteXBvcysrXS5jaGFyQ29kZUF0KCkgPDwgMTYpXG5cdFx0XHRcdFx0XHR8IChpbnB1dFtteXBvcysrXS5jaGFyQ29kZUF0KCkgPDwgOClcblx0XHRcdFx0XHRcdHwgaW5wdXRbbXlwb3MrK10uY2hhckNvZGVBdCgpO1xuXHRcdFx0XHRicmVhaztcblx0XHRcdGRlZmF1bHQ6XG5cdFx0XHRcdC8vIDMgLSBUaGUgcGFja2V0IGlzIG9mIGluZGV0ZXJtaW5hdGUgbGVuZ3RoLiBUaGUgaGVhZGVyIGlzIDFcblx0XHRcdFx0Ly8gb2N0ZXQgbG9uZywgYW5kIHRoZSBpbXBsZW1lbnRhdGlvbiBtdXN0IGRldGVybWluZSBob3cgbG9uZ1xuXHRcdFx0XHQvLyB0aGUgcGFja2V0IGlzLiBJZiB0aGUgcGFja2V0IGlzIGluIGEgZmlsZSwgdGhpcyBtZWFucyB0aGF0XG5cdFx0XHRcdC8vIHRoZSBwYWNrZXQgZXh0ZW5kcyB1bnRpbCB0aGUgZW5kIG9mIHRoZSBmaWxlLiBJbiBnZW5lcmFsLCBcblx0XHRcdFx0Ly8gYW4gaW1wbGVtZW50YXRpb24gU0hPVUxEIE5PVCB1c2UgaW5kZXRlcm1pbmF0ZS1sZW5ndGggXG5cdFx0XHRcdC8vIHBhY2tldHMgZXhjZXB0IHdoZXJlIHRoZSBlbmQgb2YgdGhlIGRhdGEgd2lsbCBiZSBjbGVhciBcblx0XHRcdFx0Ly8gZnJvbSB0aGUgY29udGV4dCwgYW5kIGV2ZW4gdGhlbiBpdCBpcyBiZXR0ZXIgdG8gdXNlIGEgXG5cdFx0XHRcdC8vIGRlZmluaXRlIGxlbmd0aCwgb3IgYSBuZXcgZm9ybWF0IGhlYWRlci4gVGhlIG5ldyBmb3JtYXQgXG5cdFx0XHRcdC8vIGhlYWRlcnMgZGVzY3JpYmVkIGJlbG93IGhhdmUgYSBtZWNoYW5pc20gZm9yIHByZWNpc2VseVxuXHRcdFx0XHQvLyBlbmNvZGluZyBkYXRhIG9mIGluZGV0ZXJtaW5hdGUgbGVuZ3RoLlxuXHRcdFx0XHRwYWNrZXRfbGVuZ3RoID0gbGVuO1xuXHRcdFx0XHRicmVhaztcblx0XHRcdH1cblxuXHRcdH0gZWxzZSAvLyA0LjIuMi4gTmV3IEZvcm1hdCBQYWNrZXQgTGVuZ3Roc1xuXHRcdHtcblxuXHRcdFx0Ly8gNC4yLjIuMS4gT25lLU9jdGV0IExlbmd0aHNcblx0XHRcdGlmIChpbnB1dFtteXBvc10uY2hhckNvZGVBdCgpIDwgMTkyKSB7XG5cdFx0XHRcdHBhY2tldF9sZW5ndGggPSBpbnB1dFtteXBvcysrXS5jaGFyQ29kZUF0KCk7XG5cdFx0XHRcdHV0aWwucHJpbnRfZGVidWcoXCIxIGJ5dGUgbGVuZ3RoOlwiICsgcGFja2V0X2xlbmd0aCk7XG5cdFx0XHRcdC8vIDQuMi4yLjIuIFR3by1PY3RldCBMZW5ndGhzXG5cdFx0XHR9IGVsc2UgaWYgKGlucHV0W215cG9zXS5jaGFyQ29kZUF0KCkgPj0gMTkyXG5cdFx0XHRcdFx0JiYgaW5wdXRbbXlwb3NdLmNoYXJDb2RlQXQoKSA8IDIyNCkge1xuXHRcdFx0XHRwYWNrZXRfbGVuZ3RoID0gKChpbnB1dFtteXBvcysrXS5jaGFyQ29kZUF0KCkgLSAxOTIpIDw8IDgpXG5cdFx0XHRcdFx0XHQrIChpbnB1dFtteXBvcysrXS5jaGFyQ29kZUF0KCkpICsgMTkyO1xuXHRcdFx0XHR1dGlsLnByaW50X2RlYnVnKFwiMiBieXRlIGxlbmd0aDpcIiArIHBhY2tldF9sZW5ndGgpO1xuXHRcdFx0XHQvLyA0LjIuMi40LiBQYXJ0aWFsIEJvZHkgTGVuZ3Roc1xuXHRcdFx0fSBlbHNlIGlmIChpbnB1dFtteXBvc10uY2hhckNvZGVBdCgpID4gMjIzXG5cdFx0XHRcdFx0JiYgaW5wdXRbbXlwb3NdLmNoYXJDb2RlQXQoKSA8IDI1NSkge1xuXHRcdFx0XHRwYWNrZXRfbGVuZ3RoID0gMSA8PCAoaW5wdXRbbXlwb3MrK10uY2hhckNvZGVBdCgpICYgMHgxRik7XG5cdFx0XHRcdHV0aWwucHJpbnRfZGVidWcoXCI0IGJ5dGUgbGVuZ3RoOlwiICsgcGFja2V0X2xlbmd0aCk7XG5cdFx0XHRcdC8vIEVFRUssIHdlJ3JlIHJlYWRpbmcgdGhlIGZ1bGwgZGF0YSBoZXJlLi4uXG5cdFx0XHRcdHZhciBteXBvczIgPSBteXBvcyArIHBhY2tldF9sZW5ndGg7XG5cdFx0XHRcdGJvZHlkYXRhID0gaW5wdXQuc3Vic3RyaW5nKG15cG9zLCBteXBvcyArIHBhY2tldF9sZW5ndGgpO1xuXHRcdFx0XHR3aGlsZSAodHJ1ZSkge1xuXHRcdFx0XHRcdGlmIChpbnB1dFtteXBvczJdLmNoYXJDb2RlQXQoKSA8IDE5Mikge1xuXHRcdFx0XHRcdFx0dmFyIHRtcGxlbiA9IGlucHV0W215cG9zMisrXS5jaGFyQ29kZUF0KCk7XG5cdFx0XHRcdFx0XHRwYWNrZXRfbGVuZ3RoICs9IHRtcGxlbjtcblx0XHRcdFx0XHRcdGJvZHlkYXRhICs9IGlucHV0LnN1YnN0cmluZyhteXBvczIsIG15cG9zMiArIHRtcGxlbik7XG5cdFx0XHRcdFx0XHRteXBvczIgKz0gdG1wbGVuO1xuXHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdFx0fSBlbHNlIGlmIChpbnB1dFtteXBvczJdLmNoYXJDb2RlQXQoKSA+PSAxOTJcblx0XHRcdFx0XHRcdFx0JiYgaW5wdXRbbXlwb3MyXS5jaGFyQ29kZUF0KCkgPCAyMjQpIHtcblx0XHRcdFx0XHRcdHZhciB0bXBsZW4gPSAoKGlucHV0W215cG9zMisrXS5jaGFyQ29kZUF0KCkgLSAxOTIpIDw8IDgpXG5cdFx0XHRcdFx0XHRcdFx0KyAoaW5wdXRbbXlwb3MyKytdLmNoYXJDb2RlQXQoKSkgKyAxOTI7XG5cdFx0XHRcdFx0XHRwYWNrZXRfbGVuZ3RoICs9IHRtcGxlbjtcblx0XHRcdFx0XHRcdGJvZHlkYXRhICs9IGlucHV0LnN1YnN0cmluZyhteXBvczIsIG15cG9zMiArIHRtcGxlbik7XG5cdFx0XHRcdFx0XHRteXBvczIgKz0gdG1wbGVuO1xuXHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdFx0fSBlbHNlIGlmIChpbnB1dFtteXBvczJdLmNoYXJDb2RlQXQoKSA+IDIyM1xuXHRcdFx0XHRcdFx0XHQmJiBpbnB1dFtteXBvczJdLmNoYXJDb2RlQXQoKSA8IDI1NSkge1xuXHRcdFx0XHRcdFx0dmFyIHRtcGxlbiA9IDEgPDwgKGlucHV0W215cG9zMisrXS5jaGFyQ29kZUF0KCkgJiAweDFGKTtcblx0XHRcdFx0XHRcdHBhY2tldF9sZW5ndGggKz0gdG1wbGVuO1xuXHRcdFx0XHRcdFx0Ym9keWRhdGEgKz0gaW5wdXQuc3Vic3RyaW5nKG15cG9zMiwgbXlwb3MyICsgdG1wbGVuKTtcblx0XHRcdFx0XHRcdG15cG9zMiArPSB0bXBsZW47XG5cdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdG15cG9zMisrO1xuXHRcdFx0XHRcdFx0dmFyIHRtcGxlbiA9IChpbnB1dFtteXBvczIrK10uY2hhckNvZGVBdCgpIDw8IDI0KVxuXHRcdFx0XHRcdFx0XHRcdHwgKGlucHV0W215cG9zMisrXS5jaGFyQ29kZUF0KCkgPDwgMTYpXG5cdFx0XHRcdFx0XHRcdFx0fCAoaW5wdXRbbXlwb3MyKytdLmNoYXJDb2RlQXQoKSA8PCA4KVxuXHRcdFx0XHRcdFx0XHRcdHwgaW5wdXRbbXlwb3MyKytdLmNoYXJDb2RlQXQoKTtcblx0XHRcdFx0XHRcdGJvZHlkYXRhICs9IGlucHV0LnN1YnN0cmluZyhteXBvczIsIG15cG9zMiArIHRtcGxlbik7XG5cdFx0XHRcdFx0XHRwYWNrZXRfbGVuZ3RoICs9IHRtcGxlbjtcblx0XHRcdFx0XHRcdG15cG9zMiArPSB0bXBsZW47XG5cdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdFx0cmVhbF9wYWNrZXRfbGVuZ3RoID0gbXlwb3MyO1xuXHRcdFx0XHQvLyA0LjIuMi4zLiBGaXZlLU9jdGV0IExlbmd0aHNcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdG15cG9zKys7XG5cdFx0XHRcdHBhY2tldF9sZW5ndGggPSAoaW5wdXRbbXlwb3MrK10uY2hhckNvZGVBdCgpIDw8IDI0KVxuXHRcdFx0XHRcdFx0fCAoaW5wdXRbbXlwb3MrK10uY2hhckNvZGVBdCgpIDw8IDE2KVxuXHRcdFx0XHRcdFx0fCAoaW5wdXRbbXlwb3MrK10uY2hhckNvZGVBdCgpIDw8IDgpXG5cdFx0XHRcdFx0XHR8IGlucHV0W215cG9zKytdLmNoYXJDb2RlQXQoKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHQvLyBpZiB0aGVyZSB3YXMnbnQgYSBwYXJ0aWFsIGJvZHkgbGVuZ3RoOiB1c2UgdGhlIHNwZWNpZmllZFxuXHRcdC8vIHBhY2tldF9sZW5ndGhcblx0XHRpZiAocmVhbF9wYWNrZXRfbGVuZ3RoID09IC0xKSB7XG5cdFx0XHRyZWFsX3BhY2tldF9sZW5ndGggPSBwYWNrZXRfbGVuZ3RoO1xuXHRcdH1cblxuXHRcdGlmIChib2R5ZGF0YSA9PSBudWxsKSB7XG5cdFx0XHRib2R5ZGF0YSA9IGlucHV0LnN1YnN0cmluZyhteXBvcywgbXlwb3MgKyByZWFsX3BhY2tldF9sZW5ndGgpO1xuXHRcdH1cblxuXHRcdHJldHVybiB7IFxuXHRcdFx0dGFnOiB0YWcsXG5cdFx0XHRwYWNrZXQ6IGJvZHlkYXRhLFxuXHRcdFx0b2Zmc2V0OiBteXBvcyArIHJlYWxfcGFja2V0X2xlbmd0aFxuXHRcdH07XG5cdH1cbn1cblxuIiwiLy8gR1BHNEJyb3dzZXJzIC0gQW4gT3BlblBHUCBpbXBsZW1lbnRhdGlvbiBpbiBqYXZhc2NyaXB0XG4vLyBDb3B5cmlnaHQgKEMpIDIwMTEgUmVjdXJpdHkgTGFicyBHbWJIXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3Jcbi8vIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlclxuLy8gdmVyc2lvbiAyLjEgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuLy8gYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2Zcbi8vIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUgR05VXG4vLyBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuLy8gXG4vLyBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFsb25nIHdpdGggdGhpcyBsaWJyYXJ5OyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlXG4vLyBGb3VuZGF0aW9uLCBJbmMuLCA1MSBGcmFua2xpbiBTdHJlZXQsIEZpZnRoIEZsb29yLCBCb3N0b24sIE1BICAwMjExMC0xMzAxICBVU0FcblxudmFyIHV0aWwgPSByZXF1aXJlKCcuLi91dGlsJyksXG5cdGNyeXB0byA9IHJlcXVpcmUoJy4uL2NyeXB0bycpO1xuXG4vKipcbiAqIEBjbGFzc1xuICogQGNsYXNzZGVzYyBJbXBsZW1lbnRhdGlvbiBvZiB0aGUgU3ltLiBFbmNyeXB0ZWQgSW50ZWdyaXR5IFByb3RlY3RlZCBEYXRhIFxuICogUGFja2V0IChUYWcgMTgpXG4gKiBcbiAqIFJGQzQ4ODAgNS4xMzogVGhlIFN5bW1ldHJpY2FsbHkgRW5jcnlwdGVkIEludGVncml0eSBQcm90ZWN0ZWQgRGF0YSBwYWNrZXQgaXNcbiAqIGEgdmFyaWFudCBvZiB0aGUgU3ltbWV0cmljYWxseSBFbmNyeXB0ZWQgRGF0YSBwYWNrZXQuIEl0IGlzIGEgbmV3IGZlYXR1cmVcbiAqIGNyZWF0ZWQgZm9yIE9wZW5QR1AgdGhhdCBhZGRyZXNzZXMgdGhlIHByb2JsZW0gb2YgZGV0ZWN0aW5nIGEgbW9kaWZpY2F0aW9uIHRvXG4gKiBlbmNyeXB0ZWQgZGF0YS4gSXQgaXMgdXNlZCBpbiBjb21iaW5hdGlvbiB3aXRoIGEgTW9kaWZpY2F0aW9uIERldGVjdGlvbiBDb2RlXG4gKiBwYWNrZXQuXG4gKi9cblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiBwYWNrZXRfc3ltX2VuY3J5cHRlZF9pbnRlZ3JpdHlfcHJvdGVjdGVkKCkge1xuXHQvKiogVGhlIGVuY3J5cHRlZCBwYXlsb2FkLiAqL1xuXHR0aGlzLmVuY3J5cHRlZCA9IG51bGw7IC8vIHN0cmluZ1xuXHQvKiogQHR5cGUge0Jvb2xlYW59XG5cdCAqIElmIGFmdGVyIGRlY3J5cHRpbmcgdGhlIHBhY2tldCB0aGlzIGlzIHNldCB0byB0cnVlLFxuXHQgKiBhIG1vZGlmaWNhdGlvbiBoYXMgYmVlbiBkZXRlY3RlZCBhbmQgdGh1cyB0aGUgY29udGVudHNcblx0ICogc2hvdWxkIGJlIGRpc2NhcmRlZC5cblx0ICovXG5cdHRoaXMubW9kaWZpY2F0aW9uID0gZmFsc2U7XG5cdHRoaXMucGFja2V0cztcblxuXG5cdHRoaXMucmVhZCA9IGZ1bmN0aW9uKGJ5dGVzKSB7XG5cdFx0Ly8gLSBBIG9uZS1vY3RldCB2ZXJzaW9uIG51bWJlci4gVGhlIG9ubHkgY3VycmVudGx5IGRlZmluZWQgdmFsdWUgaXNcblx0XHQvLyAxLlxuXHRcdHZhciB2ZXJzaW9uID0gYnl0ZXNbMF0uY2hhckNvZGVBdCgpO1xuXG5cdFx0aWYgKHZlcnNpb24gIT0gMSkge1xuXHRcdFx0dGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIHBhY2tldCB2ZXJzaW9uLicpO1xuXHRcdH1cblxuXHRcdC8vIC0gRW5jcnlwdGVkIGRhdGEsIHRoZSBvdXRwdXQgb2YgdGhlIHNlbGVjdGVkIHN5bW1ldHJpYy1rZXkgY2lwaGVyXG5cdFx0Ly8gICBvcGVyYXRpbmcgaW4gQ2lwaGVyIEZlZWRiYWNrIG1vZGUgd2l0aCBzaGlmdCBhbW91bnQgZXF1YWwgdG8gdGhlXG5cdFx0Ly8gICBibG9jayBzaXplIG9mIHRoZSBjaXBoZXIgKENGQi1uIHdoZXJlIG4gaXMgdGhlIGJsb2NrIHNpemUpLlxuXHRcdHRoaXMuZW5jcnlwdGVkID0gYnl0ZXMuc3Vic3RyKDEpO1xuXHR9XG5cblx0dGhpcy53cml0ZSA9IGZ1bmN0aW9uKCkge1xuXHRcdFxuXHRcdHJldHVybiBTdHJpbmcuZnJvbUNoYXJDb2RlKDEpIC8vIFZlcnNpb25cblx0XHRcdCsgdGhpcy5lbmNyeXB0ZWQ7XG5cdH1cblxuXHR0aGlzLmVuY3J5cHQgPSBmdW5jdGlvbihzZXNzaW9uS2V5QWxnb3JpdGhtLCBrZXkpIHtcblx0XHR2YXIgYnl0ZXMgPSB0aGlzLnBhY2tldHMud3JpdGUoKVxuXHRcdFxuXHRcdHZhciBwcmVmaXhyYW5kb20gPSBjcnlwdG8uZ2V0UHJlZml4UmFuZG9tKHNlc3Npb25LZXlBbGdvcml0aG0pO1xuXHRcdHZhciBwcmVmaXggPSBwcmVmaXhyYW5kb21cblx0XHRcdFx0KyBwcmVmaXhyYW5kb20uY2hhckF0KHByZWZpeHJhbmRvbS5sZW5ndGggLSAyKVxuXHRcdFx0XHQrIHByZWZpeHJhbmRvbS5jaGFyQXQocHJlZml4cmFuZG9tLmxlbmd0aCAtIDEpXG5cblx0XHR2YXIgdG9oYXNoID0gYnl0ZXM7XG5cblxuXHRcdC8vIE1vZGlmaWNhdGlvbiBkZXRlY3Rpb24gY29kZSBwYWNrZXQuXG5cdFx0dG9oYXNoICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoMHhEMyk7XG5cdFx0dG9oYXNoICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoMHgxNCk7XG5cblxuXHRcdHRvaGFzaCArPSBjcnlwdG8uaGFzaC5zaGExKHByZWZpeCArIHRvaGFzaCk7XG5cblxuXHRcdHRoaXMuZW5jcnlwdGVkID0gY3J5cHRvLnN5bW1ldHJpYy5lbmNyeXB0KHByZWZpeHJhbmRvbSxcblx0XHRcdFx0c2Vzc2lvbktleUFsZ29yaXRobSwga2V5LCB0b2hhc2gsIGZhbHNlKS5zdWJzdHJpbmcoMCxcblx0XHRcdFx0cHJlZml4Lmxlbmd0aCArIHRvaGFzaC5sZW5ndGgpO1xuXHR9XG5cblx0LyoqXG5cdCAqIERlY3J5cHRzIHRoZSBlbmNyeXB0ZWQgZGF0YSBjb250YWluZWQgaW4gdGhpcyBvYmplY3QgcmVhZF9wYWNrZXQgbXVzdFxuXHQgKiBoYXZlIGJlZW4gY2FsbGVkIGJlZm9yZVxuXHQgKiBcblx0ICogQHBhcmFtIHtJbnRlZ2VyfSBzZXNzaW9uS2V5QWxnb3JpdGhtXG5cdCAqICAgICAgICAgICAgVGhlIHNlbGVjdGVkIHN5bW1ldHJpYyBlbmNyeXB0aW9uIGFsZ29yaXRobSB0byBiZSB1c2VkXG5cdCAqIEBwYXJhbSB7U3RyaW5nfSBrZXkgVGhlIGtleSBvZiBjaXBoZXIgYmxvY2tzaXplIGxlbmd0aCB0byBiZSB1c2VkXG5cdCAqIEByZXR1cm4ge1N0cmluZ30gVGhlIGRlY3J5cHRlZCBkYXRhIG9mIHRoaXMgcGFja2V0XG5cdCAqL1xuXHR0aGlzLmRlY3J5cHQgPSBmdW5jdGlvbihzZXNzaW9uS2V5QWxnb3JpdGhtLCBrZXkpIHtcblx0XHR2YXIgZGVjcnlwdGVkID0gY3J5cHRvLnN5bW1ldHJpYy5kZWNyeXB0KFxuXHRcdFx0XHRzZXNzaW9uS2V5QWxnb3JpdGhtLCBrZXksIHRoaXMuZW5jcnlwdGVkLCBmYWxzZSk7XG5cblxuXHRcdC8vIHRoZXJlIG11c3QgYmUgYSBtb2RpZmljYXRpb24gZGV0ZWN0aW9uIGNvZGUgcGFja2V0IGFzIHRoZVxuXHRcdC8vIGxhc3QgcGFja2V0IGFuZCBldmVyeXRoaW5nIGdldHMgaGFzaGVkIGV4Y2VwdCB0aGUgaGFzaCBpdHNlbGZcblx0XHR0aGlzLmhhc2ggPSBjcnlwdG8uaGFzaC5zaGExKFxuXHRcdFx0Y3J5cHRvLk1EQ1N5c3RlbUJ5dGVzKHNlc3Npb25LZXlBbGdvcml0aG0sIGtleSwgdGhpcy5lbmNyeXB0ZWQpXG5cdFx0XHQrIGRlY3J5cHRlZC5zdWJzdHJpbmcoMCwgZGVjcnlwdGVkLmxlbmd0aCAtIDIwKSk7XG5cblxuXHRcdHZhciBtZGMgPSBkZWNyeXB0ZWQuc3Vic3RyKGRlY3J5cHRlZC5sZW5ndGggLSAyMCwgMjApO1xuXG5cdFx0aWYodGhpcy5oYXNoICE9IG1kYykge1xuXHRcdFx0dGhyb3cgbmV3IEVycm9yKCdNb2RpZmljYXRpb24gZGV0ZWN0ZWQuJyk7XG5cdFx0fVxuXHRcdGVsc2Vcblx0XHRcdHRoaXMucGFja2V0cy5yZWFkKGRlY3J5cHRlZC5zdWJzdHIoMCwgZGVjcnlwdGVkLmxlbmd0aCAtIDIyKSk7XG5cdH1cbn07XG4iLCIvLyBHUEc0QnJvd3NlcnMgLSBBbiBPcGVuUEdQIGltcGxlbWVudGF0aW9uIGluIGphdmFzY3JpcHRcbi8vIENvcHlyaWdodCAoQykgMjAxMSBSZWN1cml0eSBMYWJzIEdtYkhcbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vclxuLy8gbW9kaWZ5IGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyXG4vLyB2ZXJzaW9uIDIuMSBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4vLyBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuLy8gTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZSBHTlVcbi8vIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG4vLyBcbi8vIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYWxvbmcgd2l0aCB0aGlzIGxpYnJhcnk7IGlmIG5vdCwgd3JpdGUgdG8gdGhlIEZyZWUgU29mdHdhcmVcbi8vIEZvdW5kYXRpb24sIEluYy4sIDUxIEZyYW5rbGluIFN0cmVldCwgRmlmdGggRmxvb3IsIEJvc3RvbiwgTUEgIDAyMTEwLTEzMDEgIFVTQVxuXG52YXIgdHlwZV9rZXlpZCA9IHJlcXVpcmUoJy4uL3R5cGUva2V5aWQuanMnKSxcblx0dXRpbCA9IHJlcXVpcmUoJy4uL3V0aWwnKSxcblx0dHlwZV9tcGkgPSByZXF1aXJlKCcuLi90eXBlL21waS5qcycpLFxuXHRlbnVtcyA9IHJlcXVpcmUoJy4uL2VudW1zLmpzJyksXG5cdGNyeXB0byA9IHJlcXVpcmUoJy4uL2NyeXB0bycpO1xuXHRcblxuLyoqXG4gKiBAY2xhc3NcbiAqIEBjbGFzc2Rlc2MgUHVibGljLUtleSBFbmNyeXB0ZWQgU2Vzc2lvbiBLZXkgUGFja2V0cyAoVGFnIDEpXG4gKiBcbiAqIFJGQzQ4ODAgNS4xOiBBIFB1YmxpYy1LZXkgRW5jcnlwdGVkIFNlc3Npb24gS2V5IHBhY2tldCBob2xkcyB0aGUgc2Vzc2lvbiBrZXlcbiAqIHVzZWQgdG8gZW5jcnlwdCBhIG1lc3NhZ2UuIFplcm8gb3IgbW9yZSBQdWJsaWMtS2V5IEVuY3J5cHRlZCBTZXNzaW9uIEtleVxuICogcGFja2V0cyBhbmQvb3IgU3ltbWV0cmljLUtleSBFbmNyeXB0ZWQgU2Vzc2lvbiBLZXkgcGFja2V0cyBtYXkgcHJlY2VkZSBhXG4gKiBTeW1tZXRyaWNhbGx5IEVuY3J5cHRlZCBEYXRhIFBhY2tldCwgd2hpY2ggaG9sZHMgYW4gZW5jcnlwdGVkIG1lc3NhZ2UuIFRoZVxuICogbWVzc2FnZSBpcyBlbmNyeXB0ZWQgd2l0aCB0aGUgc2Vzc2lvbiBrZXksIGFuZCB0aGUgc2Vzc2lvbiBrZXkgaXMgaXRzZWxmXG4gKiBlbmNyeXB0ZWQgYW5kIHN0b3JlZCBpbiB0aGUgRW5jcnlwdGVkIFNlc3Npb24gS2V5IHBhY2tldChzKS4gVGhlXG4gKiBTeW1tZXRyaWNhbGx5IEVuY3J5cHRlZCBEYXRhIFBhY2tldCBpcyBwcmVjZWRlZCBieSBvbmUgUHVibGljLUtleSBFbmNyeXB0ZWRcbiAqIFNlc3Npb24gS2V5IHBhY2tldCBmb3IgZWFjaCBPcGVuUEdQIGtleSB0byB3aGljaCB0aGUgbWVzc2FnZSBpcyBlbmNyeXB0ZWQuXG4gKiBUaGUgcmVjaXBpZW50IG9mIHRoZSBtZXNzYWdlIGZpbmRzIGEgc2Vzc2lvbiBrZXkgdGhhdCBpcyBlbmNyeXB0ZWQgdG8gdGhlaXJcbiAqIHB1YmxpYyBrZXksIGRlY3J5cHRzIHRoZSBzZXNzaW9uIGtleSwgYW5kIHRoZW4gdXNlcyB0aGUgc2Vzc2lvbiBrZXkgdG9cbiAqIGRlY3J5cHQgdGhlIG1lc3NhZ2UuXG4gKi9cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gcGFja2V0X3B1YmxpY19rZXlfZW5jcnlwdGVkX3Nlc3Npb25fa2V5KCkge1xuXHR0aGlzLnZlcnNpb24gPSAzO1xuXG5cdHRoaXMucHVibGljS2V5SWQgPSBuZXcgdHlwZV9rZXlpZCgpO1xuXHR0aGlzLnB1YmxpY0tleUFsZ29yaXRobSA9ICdyc2FfZW5jcnlwdCc7XG5cblx0dGhpcy5zZXNzaW9uS2V5ID0gbnVsbDtcblx0dGhpcy5zZXNzaW9uS2V5QWxnb3JpdGhtID0gJ2FlczI1Nic7XG5cblx0LyoqIEB0eXBlIHtvcGVucGdwX3R5cGVfbXBpW119ICovXG5cdHRoaXMuZW5jcnlwdGVkID0gW107XG5cblx0LyoqXG5cdCAqIFBhcnNpbmcgZnVuY3Rpb24gZm9yIGEgcHVibGlja2V5IGVuY3J5cHRlZCBzZXNzaW9uIGtleSBwYWNrZXQgKHRhZyAxKS5cblx0ICogXG5cdCAqIEBwYXJhbSB7U3RyaW5nfSBpbnB1dCBQYXlsb2FkIG9mIGEgdGFnIDEgcGFja2V0XG5cdCAqIEBwYXJhbSB7SW50ZWdlcn0gcG9zaXRpb24gUG9zaXRpb24gdG8gc3RhcnQgcmVhZGluZyBmcm9tIHRoZSBpbnB1dCBzdHJpbmdcblx0ICogQHBhcmFtIHtJbnRlZ2VyfSBsZW4gTGVuZ3RoIG9mIHRoZSBwYWNrZXQgb3IgdGhlIHJlbWFpbmluZyBsZW5ndGggb2Zcblx0ICogICAgICAgICAgICBpbnB1dCBhdCBwb3NpdGlvblxuXHQgKiBAcmV0dXJuIHtvcGVucGdwX3BhY2tldF9lbmNyeXB0ZWRkYXRhfSBPYmplY3QgcmVwcmVzZW50YXRpb25cblx0ICovXG5cdHRoaXMucmVhZCA9IGZ1bmN0aW9uKGJ5dGVzKSB7XG5cblx0XHR0aGlzLnZlcnNpb24gPSBieXRlc1swXS5jaGFyQ29kZUF0KCk7XG5cdFx0dGhpcy5wdWJsaWNLZXlJZC5yZWFkKGJ5dGVzLnN1YnN0cigxKSk7XG5cdFx0dGhpcy5wdWJsaWNLZXlBbGdvcml0aG0gPSBlbnVtcy5yZWFkKGVudW1zLnB1YmxpY0tleSwgYnl0ZXNbOV0uY2hhckNvZGVBdCgpKTtcblxuXHRcdHZhciBpID0gMTA7XG5cblx0XHR2YXIgaW50ZWdlckNvdW50ID0gKGZ1bmN0aW9uKGFsZ28pIHtcblx0XHRcdHN3aXRjaCAoYWxnbykge1xuXHRcdFx0Y2FzZSAncnNhX2VuY3J5cHQnOlxuXHRcdFx0Y2FzZSAncnNhX2VuY3J5cHRfc2lnbic6XG5cdFx0XHRcdHJldHVybiAxO1xuXG5cdFx0XHRjYXNlICdlbGdhbWFsJzpcblx0XHRcdFx0cmV0dXJuIDI7XG5cblx0XHRcdGRlZmF1bHQ6XG5cdFx0XHRcdHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgYWxnb3JpdGhtLlwiKTtcblx0XHRcdH1cblx0XHR9KSh0aGlzLnB1YmxpY0tleUFsZ29yaXRobSk7XG5cblx0XHR0aGlzLmVuY3J5cHRlZCA9IFtdO1xuXG5cdFx0Zm9yKHZhciBqID0gMDsgaiA8IGludGVnZXJDb3VudDsgaisrKSB7XG5cdFx0XHR2YXIgbXBpID0gbmV3IHR5cGVfbXBpKCk7XG5cdFx0XHRpICs9IG1waS5yZWFkKGJ5dGVzLnN1YnN0cihpKSk7XG5cdFx0XHR0aGlzLmVuY3J5cHRlZC5wdXNoKG1waSk7XG5cdFx0fVxuXHR9XG5cblx0LyoqXG5cdCAqIENyZWF0ZSBhIHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiBhIHRhZyAxIHBhY2tldFxuXHQgKiBcblx0ICogQHBhcmFtIHtTdHJpbmd9IHB1YmxpY0tleUlkXG5cdCAqICAgICAgICAgICAgIFRoZSBwdWJsaWMga2V5IGlkIGNvcnJlc3BvbmRpbmcgdG8gcHVibGljTVBJcyBrZXkgYXMgc3RyaW5nXG5cdCAqIEBwYXJhbSB7b3BlbnBncF90eXBlX21waVtdfSBwdWJsaWNNUElzXG5cdCAqICAgICAgICAgICAgTXVsdGlwcmVjaXNpb24gaW50ZWdlciBvYmplY3RzIGRlc2NyaWJpbmcgdGhlIHB1YmxpYyBrZXlcblx0ICogQHBhcmFtIHtJbnRlZ2VyfSBwdWJhbGdvXG5cdCAqICAgICAgICAgICAgVGhlIGNvcnJlc3BvbmRpbmcgcHVibGljIGtleSBhbGdvcml0aG0gLy8gU2VlIFJGQzQ4ODAgOS4xXG5cdCAqIEBwYXJhbSB7SW50ZWdlcn0gc3ltbWFsZ29cblx0ICogICAgICAgICAgICBUaGUgc3ltbWV0cmljIGNpcGhlciBhbGdvcml0aG0gdXNlZCB0byBlbmNyeXB0IHRoZSBkYXRhIFxuXHQgKiAgICAgICAgICAgIHdpdGhpbiBhbiBlbmNyeXB0ZWRkYXRhcGFja2V0IG9yIGVuY3J5cHRlZGludGVncml0eS1cblx0ICogICAgICAgICAgICBwcm90ZWN0ZWRkYXRhcGFja2V0IFxuXHQgKiAgICAgICAgICAgIGZvbGxvd2luZyB0aGlzIHBhY2tldCAvL1NlZSBSRkM0ODgwIDkuMlxuXHQgKiBAcGFyYW0ge1N0cmluZ30gc2Vzc2lvbmtleVxuXHQgKiAgICAgICAgICAgIEEgc3RyaW5nIG9mIHJhbmRvbWJ5dGVzIHJlcHJlc2VudGluZyB0aGUgc2Vzc2lvbiBrZXlcblx0ICogQHJldHVybiB7U3RyaW5nfSBUaGUgc3RyaW5nIHJlcHJlc2VudGF0aW9uXG5cdCAqL1xuXHR0aGlzLndyaXRlID0gZnVuY3Rpb24oKSB7XG5cblx0XHR2YXIgcmVzdWx0ID0gU3RyaW5nLmZyb21DaGFyQ29kZSh0aGlzLnZlcnNpb24pO1xuXHRcdHJlc3VsdCArPSB0aGlzLnB1YmxpY0tleUlkLndyaXRlKCk7XG5cdFx0cmVzdWx0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoXG5cdFx0XHRlbnVtcy53cml0ZShlbnVtcy5wdWJsaWNLZXksIHRoaXMucHVibGljS2V5QWxnb3JpdGhtKSk7XG5cblx0XHRmb3IgKCB2YXIgaSA9IDA7IGkgPCB0aGlzLmVuY3J5cHRlZC5sZW5ndGg7IGkrKykge1xuXHRcdFx0cmVzdWx0ICs9IHRoaXMuZW5jcnlwdGVkW2ldLndyaXRlKClcblx0XHR9XG5cblx0XHRyZXR1cm4gcmVzdWx0O1xuXHR9XG5cblx0dGhpcy5lbmNyeXB0ID0gZnVuY3Rpb24oa2V5KSB7XG5cdFx0dmFyIGRhdGEgPSBTdHJpbmcuZnJvbUNoYXJDb2RlKFxuXHRcdFx0ZW51bXMud3JpdGUoZW51bXMuc3ltbWV0cmljLCB0aGlzLnNlc3Npb25LZXlBbGdvcml0aG0pKTtcblxuXHRcdGRhdGEgKz0gdGhpcy5zZXNzaW9uS2V5O1xuXHRcdHZhciBjaGVja3N1bSA9IHV0aWwuY2FsY19jaGVja3N1bSh0aGlzLnNlc3Npb25LZXkpO1xuXHRcdGRhdGEgKz0gdXRpbC53cml0ZU51bWJlcihjaGVja3N1bSwgMik7XG5cblx0XHR2YXIgbXBpID0gbmV3IHR5cGVfbXBpKCk7XG5cdFx0bXBpLmZyb21CeXRlcyhjcnlwdG8ucGtjczEuZW1lLmVuY29kZShcblx0XHRcdGRhdGEsXG5cdFx0XHRrZXkubXBpWzBdLmJ5dGVMZW5ndGgoKSkpO1xuXG5cdFx0dGhpcy5lbmNyeXB0ZWQgPSBjcnlwdG8ucHVibGljS2V5RW5jcnlwdChcblx0XHRcdHRoaXMucHVibGljS2V5QWxnb3JpdGhtLCBcblx0XHRcdGtleS5tcGksXG5cdFx0XHRtcGkpO1xuXHR9XG5cblx0LyoqXG5cdCAqIERlY3J5cHRzIHRoZSBzZXNzaW9uIGtleSAob25seSBmb3IgcHVibGljIGtleSBlbmNyeXB0ZWQgc2Vzc2lvbiBrZXlcblx0ICogcGFja2V0cyAodGFnIDEpXG5cdCAqIFxuXHQgKiBAcGFyYW0ge29wZW5wZ3BfbXNnX21lc3NhZ2V9IG1zZ1xuXHQgKiAgICAgICAgICAgIFRoZSBtZXNzYWdlIG9iamVjdCAod2l0aCBtZW1iZXIgZW5jcnlwdGVkRGF0YVxuXHQgKiBAcGFyYW0ge29wZW5wZ3BfbXNnX3ByaXZhdGVrZXl9IGtleVxuXHQgKiAgICAgICAgICAgIFByaXZhdGUga2V5IHdpdGggc2VjTVBJcyB1bmxvY2tlZFxuXHQgKiBAcmV0dXJuIHtTdHJpbmd9IFRoZSB1bmVuY3J5cHRlZCBzZXNzaW9uIGtleVxuXHQgKi9cblx0dGhpcy5kZWNyeXB0ID0gZnVuY3Rpb24oa2V5KSB7XG5cdFx0dmFyIHJlc3VsdCA9IGNyeXB0by5wdWJsaWNLZXlEZWNyeXB0KFxuXHRcdFx0XHR0aGlzLnB1YmxpY0tleUFsZ29yaXRobSxcblx0XHRcdFx0a2V5Lm1waSxcblx0XHRcdFx0dGhpcy5lbmNyeXB0ZWQpLnRvQnl0ZXMoKTtcblxuXHRcdHZhciBjaGVja3N1bSA9IHV0aWwucmVhZE51bWJlcihyZXN1bHQuc3Vic3RyKHJlc3VsdC5sZW5ndGggLSAyKSk7XG5cblx0XHR2YXIgZGVjb2RlZCA9IGNyeXB0by5wa2NzMS5lbWUuZGVjb2RlKFxuXHRcdFx0cmVzdWx0LFxuXHRcdFx0a2V5Lm1waVswXS5ieXRlTGVuZ3RoKCkpO1xuXG5cdFx0dmFyIGtleSA9IGRlY29kZWQuc3Vic3RyaW5nKDEsIGRlY29kZWQubGVuZ3RoIC0gMik7XG5cblx0XHRpZihjaGVja3N1bSAhPSB1dGlsLmNhbGNfY2hlY2tzdW0oa2V5KSkge1xuXHRcdFx0dGhyb3cgbmV3IEVycm9yKCdDaGVja3N1bSBtaXNtYXRjaCcpO1xuXHRcdH1cblx0XHRlbHNlIHtcblx0XHRcdHRoaXMuc2Vzc2lvbktleSA9IGtleTtcblx0XHRcdHRoaXMuc2Vzc2lvbktleUFsZ29yaXRobSA9IFxuXHRcdFx0XHRlbnVtcy5yZWFkKGVudW1zLnN5bW1ldHJpYywgZGVjb2RlZC5jaGFyQ29kZUF0KDApKTtcblx0XHR9XG5cdH1cbn07XG5cbiIsIi8vIEdQRzRCcm93c2VycyAtIEFuIE9wZW5QR1AgaW1wbGVtZW50YXRpb24gaW4gamF2YXNjcmlwdFxuLy8gQ29weXJpZ2h0IChDKSAyMDExIFJlY3VyaXR5IExhYnMgR21iSFxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yXG4vLyBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uOyBlaXRoZXJcbi8vIHZlcnNpb24gMi4xIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbi8vIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4vLyBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlIEdOVVxuLy8gTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cbi8vIFxuLy8gWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhbG9uZyB3aXRoIHRoaXMgbGlicmFyeTsgaWYgbm90LCB3cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZVxuLy8gRm91bmRhdGlvbiwgSW5jLiwgNTEgRnJhbmtsaW4gU3RyZWV0LCBGaWZ0aCBGbG9vciwgQm9zdG9uLCBNQSAgMDIxMTAtMTMwMSAgVVNBXG5cbnZhciB0eXBlX3MyayA9IHJlcXVpcmUoJy4uL3R5cGUvczJrLmpzJyksXG5cdGVudW1zID0gcmVxdWlyZSgnLi4vZW51bXMuanMnKSxcblx0Y3J5cHRvID0gcmVxdWlyZSgnLi4vY3J5cHRvJyk7XG5cbi8qKlxuICogQGNsYXNzXG4gKiBAY2xhc3NkZXNjIFB1YmxpYy1LZXkgRW5jcnlwdGVkIFNlc3Npb24gS2V5IFBhY2tldHMgKFRhZyAxKVxuICogXG4gKiBSRkM0ODgwIDUuMTogQSBQdWJsaWMtS2V5IEVuY3J5cHRlZCBTZXNzaW9uIEtleSBwYWNrZXQgaG9sZHMgdGhlIHNlc3Npb24ga2V5XG4gKiB1c2VkIHRvIGVuY3J5cHQgYSBtZXNzYWdlLiBaZXJvIG9yIG1vcmUgUHVibGljLUtleSBFbmNyeXB0ZWQgU2Vzc2lvbiBLZXlcbiAqIHBhY2tldHMgYW5kL29yIFN5bW1ldHJpYy1LZXkgRW5jcnlwdGVkIFNlc3Npb24gS2V5IHBhY2tldHMgbWF5IHByZWNlZGUgYVxuICogU3ltbWV0cmljYWxseSBFbmNyeXB0ZWQgRGF0YSBQYWNrZXQsIHdoaWNoIGhvbGRzIGFuIGVuY3J5cHRlZCBtZXNzYWdlLiBUaGVcbiAqIG1lc3NhZ2UgaXMgZW5jcnlwdGVkIHdpdGggdGhlIHNlc3Npb24ga2V5LCBhbmQgdGhlIHNlc3Npb24ga2V5IGlzIGl0c2VsZlxuICogZW5jcnlwdGVkIGFuZCBzdG9yZWQgaW4gdGhlIEVuY3J5cHRlZCBTZXNzaW9uIEtleSBwYWNrZXQocykuIFRoZVxuICogU3ltbWV0cmljYWxseSBFbmNyeXB0ZWQgRGF0YSBQYWNrZXQgaXMgcHJlY2VkZWQgYnkgb25lIFB1YmxpYy1LZXkgRW5jcnlwdGVkXG4gKiBTZXNzaW9uIEtleSBwYWNrZXQgZm9yIGVhY2ggT3BlblBHUCBrZXkgdG8gd2hpY2ggdGhlIG1lc3NhZ2UgaXMgZW5jcnlwdGVkLlxuICogVGhlIHJlY2lwaWVudCBvZiB0aGUgbWVzc2FnZSBmaW5kcyBhIHNlc3Npb24ga2V5IHRoYXQgaXMgZW5jcnlwdGVkIHRvIHRoZWlyXG4gKiBwdWJsaWMga2V5LCBkZWNyeXB0cyB0aGUgc2Vzc2lvbiBrZXksIGFuZCB0aGVuIHVzZXMgdGhlIHNlc3Npb24ga2V5IHRvXG4gKiBkZWNyeXB0IHRoZSBtZXNzYWdlLlxuICovXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIHBhY2tldF9zeW1fZW5jcnlwdGVkX3Nlc3Npb25fa2V5KCkge1xuXHR0aGlzLnRhZyA9IDM7XG5cdHRoaXMuc2Vzc2lvbktleUVuY3J5cHRpb25BbGdvcml0aG0gPSBudWxsO1xuXHR0aGlzLnNlc3Npb25LZXlBbGdvcml0aG0gPSAnYWVzMjU2Jztcblx0dGhpcy5lbmNyeXB0ZWQgPSBudWxsO1xuXHR0aGlzLnMyayA9IG5ldyB0eXBlX3MyaygpO1xuXG5cdC8qKlxuXHQgKiBQYXJzaW5nIGZ1bmN0aW9uIGZvciBhIHN5bW1ldHJpYyBlbmNyeXB0ZWQgc2Vzc2lvbiBrZXkgcGFja2V0ICh0YWcgMykuXG5cdCAqIFxuXHQgKiBAcGFyYW0ge1N0cmluZ30gaW5wdXQgUGF5bG9hZCBvZiBhIHRhZyAxIHBhY2tldFxuXHQgKiBAcGFyYW0ge0ludGVnZXJ9IHBvc2l0aW9uIFBvc2l0aW9uIHRvIHN0YXJ0IHJlYWRpbmcgZnJvbSB0aGUgaW5wdXQgc3RyaW5nXG5cdCAqIEBwYXJhbSB7SW50ZWdlcn0gbGVuXG5cdCAqICAgICAgICAgICAgTGVuZ3RoIG9mIHRoZSBwYWNrZXQgb3IgdGhlIHJlbWFpbmluZyBsZW5ndGggb2Zcblx0ICogICAgICAgICAgICBpbnB1dCBhdCBwb3NpdGlvblxuXHQgKiBAcmV0dXJuIHtvcGVucGdwX3BhY2tldF9lbmNyeXB0ZWRkYXRhfSBPYmplY3QgcmVwcmVzZW50YXRpb25cblx0ICovXG5cdHRoaXMucmVhZCA9IGZ1bmN0aW9uKGJ5dGVzKSB7XG5cdFx0Ly8gQSBvbmUtb2N0ZXQgdmVyc2lvbiBudW1iZXIuIFRoZSBvbmx5IGN1cnJlbnRseSBkZWZpbmVkIHZlcnNpb24gaXMgNC5cblx0XHR0aGlzLnZlcnNpb24gPSBieXRlc1swXS5jaGFyQ29kZUF0KCk7XG5cblx0XHQvLyBBIG9uZS1vY3RldCBudW1iZXIgZGVzY3JpYmluZyB0aGUgc3ltbWV0cmljIGFsZ29yaXRobSB1c2VkLlxuXHRcdHZhciBhbGdvID0gZW51bXMucmVhZChlbnVtcy5zeW1tZXRyaWMsIGJ5dGVzWzFdLmNoYXJDb2RlQXQoKSk7XG5cblx0XHQvLyBBIHN0cmluZy10by1rZXkgKFMySykgc3BlY2lmaWVyLCBsZW5ndGggYXMgZGVmaW5lZCBhYm92ZS5cblx0XHR2YXIgczJrbGVuZ3RoID0gdGhpcy5zMmsucmVhZChieXRlcy5zdWJzdHIoMikpO1xuXG5cdFx0Ly8gT3B0aW9uYWxseSwgdGhlIGVuY3J5cHRlZCBzZXNzaW9uIGtleSBpdHNlbGYsIHdoaWNoIGlzIGRlY3J5cHRlZFxuXHRcdC8vIHdpdGggdGhlIHN0cmluZy10by1rZXkgb2JqZWN0LlxuXHRcdHZhciBkb25lID0gczJrbGVuZ3RoICsgMjtcblxuXHRcdGlmKGRvbmUgPCBieXRlcy5sZW5ndGgpIHtcblx0XHRcdHRoaXMuZW5jcnlwdGVkID0gYnl0ZXMuc3Vic3RyKGRvbmUpO1xuXHRcdFx0dGhpcy5zZXNzaW9uS2V5RW5jcnlwdGlvbkFsZ29yaXRobSA9IGFsZ29cblx0XHR9XG5cdFx0ZWxzZVxuXHRcdFx0dGhpcy5zZXNzaW9uS2V5QWxnb3JpdGhtID0gYWxnbztcblx0fVxuXG5cdHRoaXMud3JpdGUgPSBmdW5jdGlvbigpIHtcblx0XHR2YXIgYWxnbyA9IHRoaXMuZW5jcnlwdGVkID09IG51bGwgPyBcblx0XHRcdHRoaXMuc2Vzc2lvbktleUFsZ29yaXRobSA6XG5cdFx0XHR0aGlzLnNlc3Npb25LZXlFbmNyeXB0aW9uQWxnb3JpdGhtO1xuXG5cdFx0dmFyIGJ5dGVzID0gU3RyaW5nLmZyb21DaGFyQ29kZSh0aGlzLnZlcnNpb24pICtcblx0XHRcdFN0cmluZy5mcm9tQ2hhckNvZGUoZW51bXMud3JpdGUoZW51bXMuc3ltbWV0cmljLCBhbGdvKSkgK1xuXHRcdFx0dGhpcy5zMmsud3JpdGUoKTtcblxuXHRcdGlmKHRoaXMuZW5jcnlwdGVkICE9IG51bGwpXG5cdFx0XHRieXRlcyArPSB0aGlzLmVuY3J5cHRlZDtcblx0XHRyZXR1cm4gYnl0ZXM7XG5cdH1cblxuXHQvKipcblx0ICogRGVjcnlwdHMgdGhlIHNlc3Npb24ga2V5IChvbmx5IGZvciBwdWJsaWMga2V5IGVuY3J5cHRlZCBzZXNzaW9uIGtleVxuXHQgKiBwYWNrZXRzICh0YWcgMSlcblx0ICogXG5cdCAqIEBwYXJhbSB7b3BlbnBncF9tc2dfbWVzc2FnZX0gbXNnXG5cdCAqICAgICAgICAgICAgVGhlIG1lc3NhZ2Ugb2JqZWN0ICh3aXRoIG1lbWJlciBlbmNyeXB0ZWREYXRhXG5cdCAqIEBwYXJhbSB7b3BlbnBncF9tc2dfcHJpdmF0ZWtleX0ga2V5XG5cdCAqICAgICAgICAgICAgUHJpdmF0ZSBrZXkgd2l0aCBzZWNNUElzIHVubG9ja2VkXG5cdCAqIEByZXR1cm4ge1N0cmluZ30gVGhlIHVuZW5jcnlwdGVkIHNlc3Npb24ga2V5XG5cdCAqL1xuXHR0aGlzLmRlY3J5cHQgPSBmdW5jdGlvbihwYXNzcGhyYXNlKSB7XG5cdFx0dmFyIGFsZ28gPSB0aGlzLnNlc3Npb25LZXlFbmNyeXB0aW9uQWxnb3JpdGhtICE9IG51bGwgP1xuXHRcdFx0dGhpcy5zZXNzaW9uS2V5RW5jcnlwdGlvbkFsZ29yaXRobSA6XG5cdFx0XHR0aGlzLnNlc3Npb25LZXlBbGdvcml0aG07XG5cblxuXHRcdHZhciBsZW5ndGggPSBjcnlwdG8uZ2V0S2V5TGVuZ3RoKGFsZ28pO1xuXHRcdHZhciBrZXkgPSB0aGlzLnMyay5wcm9kdWNlX2tleShwYXNzcGhyYXNlLCBsZW5ndGgpO1xuXG5cdFx0aWYodGhpcy5lbmNyeXB0ZWQgPT0gbnVsbCkge1xuXHRcdFx0dGhpcy5zZXNzaW9uS2V5ID0ga2V5O1xuXG5cdFx0fSBlbHNlIHtcblx0XHRcdHZhciBkZWNyeXB0ZWQgPSBjcnlwdG8uc3ltbWV0cmljLmRlY3J5cHQoXG5cdFx0XHRcdHRoaXMuc2Vzc2lvbktleUVuY3J5cHRpb25BbGdvcml0aG0sIGtleSwgdGhpcy5lbmNyeXB0ZWQsIHRydWUpO1xuXG5cdFx0XHR0aGlzLnNlc3Npb25LZXlBbGdvcml0aG0gPSBlbnVtcy5yZWFkKGVudW1zLnN5bW1ldHJpYyxcblx0XHRcdFx0ZGVjcnlwdGVkWzBdLmtleUNvZGVBdCgpKTtcblxuXHRcdFx0dGhpcy5zZXNzaW9uS2V5ID0gZGVjcnlwdGVkLnN1YnN0cigxKTtcblx0XHR9XG5cdH1cblxuXHR0aGlzLmVuY3J5cHQgPSBmdW5jdGlvbihwYXNzcGhyYXNlKSB7XG5cdFx0dmFyIGxlbmd0aCA9IGNyeXB0by5nZXRLZXlMZW5ndGgodGhpcy5zZXNzaW9uS2V5RW5jcnlwdGlvbkFsZ29yaXRobSk7XG5cdFx0dmFyIGtleSA9IHRoaXMuczJrLnByb2R1Y2Vfa2V5KHBhc3NwaHJhc2UsIGxlbmd0aCk7XG5cblx0XHR2YXIgcHJpdmF0ZV9rZXkgPSBTdHJpbmcuZnJvbUNoYXJDb2RlKFxuXHRcdFx0ZW51bXMud3JpdGUoZW51bXMuc3ltbWV0cmljLCB0aGlzLnNlc3Npb25LZXlBbGdvcml0aG0pKSArXG5cblx0XHRcdGNyeXB0by5nZXRSYW5kb21CeXRlcyhcblx0XHRcdFx0Y3J5cHRvLmdldEtleUxlbmd0aCh0aGlzLnNlc3Npb25LZXlBbGdvcml0aG0pKTtcblxuXHRcdHRoaXMuZW5jcnlwdGVkID0gY3J5cHRvLnN5bW1ldHJpYy5lbmNyeXB0KFxuXHRcdFx0XHRjcnlwdG8uZ2V0UHJlZml4UmFuZG9tKHRoaXMuc2Vzc2lvbktleUVuY3J5cHRpb25BbGdvcml0aG0pLCBcblx0XHRcdFx0dGhpcy5zZXNzaW9uS2V5RW5jcnlwdGlvbkFsZ29yaXRobSwga2V5LCBwcml2YXRlX2tleSwgdHJ1ZSk7XG5cdH1cbn07XG5cbiIsIi8vIEdQRzRCcm93c2VycyAtIEFuIE9wZW5QR1AgaW1wbGVtZW50YXRpb24gaW4gamF2YXNjcmlwdFxuLy8gQ29weXJpZ2h0IChDKSAyMDExIFJlY3VyaXR5IExhYnMgR21iSFxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yXG4vLyBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uOyBlaXRoZXJcbi8vIHZlcnNpb24gMi4xIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbi8vIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4vLyBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlIEdOVVxuLy8gTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cbi8vIFxuLy8gWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhbG9uZyB3aXRoIHRoaXMgbGlicmFyeTsgaWYgbm90LCB3cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZVxuLy8gRm91bmRhdGlvbiwgSW5jLiwgNTEgRnJhbmtsaW4gU3RyZWV0LCBGaWZ0aCBGbG9vciwgQm9zdG9uLCBNQSAgMDIxMTAtMTMwMSAgVVNBXG5cbnZhciB1dGlsID0gcmVxdWlyZSgnLi4vdXRpbCcpLFxuXHRlbnVtcyA9IHJlcXVpcmUoJy4uL2VudW1zLmpzJyk7XG5cbi8qKlxuICogQGNsYXNzXG4gKiBAY2xhc3NkZXNjIEltcGxlbWVudGF0aW9uIG9mIHRoZSBMaXRlcmFsIERhdGEgUGFja2V0IChUYWcgMTEpXG4gKiBcbiAqIFJGQzQ4ODAgNS45OiBBIExpdGVyYWwgRGF0YSBwYWNrZXQgY29udGFpbnMgdGhlIGJvZHkgb2YgYSBtZXNzYWdlOyBkYXRhIHRoYXRcbiAqIGlzIG5vdCB0byBiZSBmdXJ0aGVyIGludGVycHJldGVkLlxuICovXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIHBhY2tldF9saXRlcmFsKCkge1xuXHR0aGlzLmZvcm1hdCA9ICd1dGY4Jztcblx0dGhpcy5kYXRhID0gJyc7XG5cdHRoaXMuZGF0ZSA9IG5ldyBEYXRlKCk7XG5cblx0XG5cdC8qKlxuXHQgKiBTZXQgdGhlIHBhY2tldCBkYXRhIHRvIGEgamF2YXNjcmlwdCBuYXRpdmUgc3RyaW5nIG9yIGEgc3F1ZW5jZSBvZiBcblx0ICogYnl0ZXMuIENvbnZlcnNpb24gdG8gYSBwcm9wZXIgdXRmOCBlbmNvZGluZyB0YWtlcyBwbGFjZSB3aGVuIHRoZSBcblx0ICogcGFja2V0IGlzIHdyaXR0ZW4uXG5cdCAqIEBwYXJhbSB7U3RyaW5nfSBzdHIgQW55IG5hdGl2ZSBqYXZhc2NyaXB0IHN0cmluZ1xuXHQgKiBAcGFyYW0ge29wZW5wZ3BfcGFja2V0X2xpdGVyYWxkYXRhLmZvcm1hdH0gZm9ybWF0IFxuXHQgKi9cblx0dGhpcy5zZXQgPSBmdW5jdGlvbihzdHIsIGZvcm1hdCkge1xuXHRcdHRoaXMuZm9ybWF0ID0gZm9ybWF0O1xuXHRcdHRoaXMuZGF0YSA9IHN0cjtcblx0fVxuXG5cdC8qKlxuXHQgKiBTZXQgdGhlIHBhY2tldCBkYXRhIHRvIHZhbHVlIHJlcHJlc2VudGVkIGJ5IHRoZSBwcm92aWRlZCBzdHJpbmdcblx0ICogb2YgYnl0ZXMgdG9nZXRoZXIgd2l0aCB0aGUgYXBwcm9wcmlhdGUgY29udmVyc2lvbiBmb3JtYXQuXG5cdCAqIEBwYXJhbSB7U3RyaW5nfSBieXRlcyBUaGUgc3RyaW5nIG9mIGJ5dGVzXG5cdCAqIEBwYXJhbSB7b3BlbnBncF9wYWNrZXRfbGl0ZXJhbGRhdGEuZm9ybWF0fSBmb3JtYXRcblx0ICovXG5cdHRoaXMuc2V0Qnl0ZXMgPSBmdW5jdGlvbihieXRlcywgZm9ybWF0KSB7XG5cdFx0dGhpcy5mb3JtYXQgPSBmb3JtYXQ7XG5cblx0XHRpZihmb3JtYXQgPT0gJ3V0ZjgnKVxuXHRcdFx0Ynl0ZXMgPSB1dGlsLmRlY29kZV91dGY4KGJ5dGVzKTtcblxuXHRcdHRoaXMuZGF0YSA9IGJ5dGVzO1xuXHR9XG5cblx0LyoqXG5cdCAqIEdldCB0aGUgYnl0ZSBzZXF1ZW5jZSByZXByZXNlbnRpbmcgdGhlIGxpdGVyYWwgcGFja2V0IGRhdGFcblx0ICogQHJldHVybnMge1N0cmluZ30gQSBzZXF1ZW5jZSBvZiBieXRlc1xuXHQgKi9cblx0dGhpcy5nZXRCeXRlcyA9IGZ1bmN0aW9uKCkge1xuXHRcdGlmKHRoaXMuZm9ybWF0ID09ICd1dGY4Jylcblx0XHRcdHJldHVybiB1dGlsLmVuY29kZV91dGY4KHRoaXMuZGF0YSk7XG5cdFx0ZWxzZVxuXHRcdFx0cmV0dXJuIHRoaXMuZGF0YTtcblx0fVxuXHRcblx0XG5cblx0LyoqXG5cdCAqIFBhcnNpbmcgZnVuY3Rpb24gZm9yIGEgbGl0ZXJhbCBkYXRhIHBhY2tldCAodGFnIDExKS5cblx0ICogXG5cdCAqIEBwYXJhbSB7U3RyaW5nfSBpbnB1dCBQYXlsb2FkIG9mIGEgdGFnIDExIHBhY2tldFxuXHQgKiBAcGFyYW0ge0ludGVnZXJ9IHBvc2l0aW9uXG5cdCAqICAgICAgICAgICAgUG9zaXRpb24gdG8gc3RhcnQgcmVhZGluZyBmcm9tIHRoZSBpbnB1dCBzdHJpbmdcblx0ICogQHBhcmFtIHtJbnRlZ2VyfSBsZW5cblx0ICogICAgICAgICAgICBMZW5ndGggb2YgdGhlIHBhY2tldCBvciB0aGUgcmVtYWluaW5nIGxlbmd0aCBvZlxuXHQgKiAgICAgICAgICAgIGlucHV0IGF0IHBvc2l0aW9uXG5cdCAqIEByZXR1cm4ge29wZW5wZ3BfcGFja2V0X2VuY3J5cHRlZGRhdGF9IG9iamVjdCByZXByZXNlbnRhdGlvblxuXHQgKi9cblx0dGhpcy5yZWFkID0gZnVuY3Rpb24oYnl0ZXMpIHtcblx0XHQvLyAtIEEgb25lLW9jdGV0IGZpZWxkIHRoYXQgZGVzY3JpYmVzIGhvdyB0aGUgZGF0YSBpcyBmb3JtYXR0ZWQuXG5cblx0XHR2YXIgZm9ybWF0ID0gZW51bXMucmVhZChlbnVtcy5saXRlcmFsLCBieXRlc1swXS5jaGFyQ29kZUF0KCkpO1xuXG5cdFx0dmFyIGZpbGVuYW1lX2xlbiA9IGJ5dGVzLmNoYXJDb2RlQXQoMSk7XG5cdFx0dGhpcy5maWxlbmFtZSA9IHV0aWwuZGVjb2RlX3V0ZjgoYnl0ZXMuc3Vic3RyKDIsIGZpbGVuYW1lX2xlbikpO1xuXG5cdFx0dGhpcy5kYXRlID0gdXRpbC5yZWFkRGF0ZShieXRlcy5zdWJzdHIoMlxuXHRcdFx0XHQrIGZpbGVuYW1lX2xlbiwgNCkpO1xuXG5cdFx0dmFyIGRhdGEgPSBieXRlcy5zdWJzdHJpbmcoNiArIGZpbGVuYW1lX2xlbik7XG5cdFxuXHRcdHRoaXMuc2V0Qnl0ZXMoZGF0YSwgZm9ybWF0KTtcblx0fVxuXG5cdC8qKlxuXHQgKiBDcmVhdGVzIGEgc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBwYWNrZXRcblx0ICogXG5cdCAqIEBwYXJhbSB7U3RyaW5nfSBkYXRhIFRoZSBkYXRhIHRvIGJlIGluc2VydGVkIGFzIGJvZHlcblx0ICogQHJldHVybiB7U3RyaW5nfSBzdHJpbmctcmVwcmVzZW50YXRpb24gb2YgdGhlIHBhY2tldFxuXHQgKi9cblx0dGhpcy53cml0ZSA9IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBmaWxlbmFtZSA9IHV0aWwuZW5jb2RlX3V0ZjgoXCJtc2cudHh0XCIpO1xuXG5cdFx0dmFyIGRhdGEgPSB0aGlzLmdldEJ5dGVzKCk7XG5cblx0XHR2YXIgcmVzdWx0ID0gJyc7XG5cdFx0cmVzdWx0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoZW51bXMud3JpdGUoZW51bXMubGl0ZXJhbCwgdGhpcy5mb3JtYXQpKTtcblx0XHRyZXN1bHQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShmaWxlbmFtZS5sZW5ndGgpO1xuXHRcdHJlc3VsdCArPSBmaWxlbmFtZTtcblx0XHRyZXN1bHQgKz0gdXRpbC53cml0ZURhdGUodGhpcy5kYXRlKTtcblx0XHRyZXN1bHQgKz0gZGF0YTtcblx0XHRyZXR1cm4gcmVzdWx0O1xuXHR9XG59XG4iLCIvLyBHUEc0QnJvd3NlcnMgLSBBbiBPcGVuUEdQIGltcGxlbWVudGF0aW9uIGluIGphdmFzY3JpcHRcbi8vIENvcHlyaWdodCAoQykgMjAxMSBSZWN1cml0eSBMYWJzIEdtYkhcbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vclxuLy8gbW9kaWZ5IGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyXG4vLyB2ZXJzaW9uIDIuMSBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4vLyBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuLy8gTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZSBHTlVcbi8vIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG4vLyBcbi8vIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYWxvbmcgd2l0aCB0aGlzIGxpYnJhcnk7IGlmIG5vdCwgd3JpdGUgdG8gdGhlIEZyZWUgU29mdHdhcmVcbi8vIEZvdW5kYXRpb24sIEluYy4sIDUxIEZyYW5rbGluIFN0cmVldCwgRmlmdGggRmxvb3IsIEJvc3RvbiwgTUEgIDAyMTEwLTEzMDEgIFVTQVxuXG52YXIgdXRpbCA9IHJlcXVpcmUoJy4uL3V0aWwnKSxcblx0dHlwZV9tcGkgPSByZXF1aXJlKCcuLi90eXBlL21waS5qcycpLFxuXHRlbnVtcyA9IHJlcXVpcmUoJy4uL2VudW1zLmpzJyksXG5cdGNyeXB0byA9IHJlcXVpcmUoJy4uL2NyeXB0bycpO1xuXG4vKipcbiAqIEBjbGFzc1xuICogQGNsYXNzZGVzYyBJbXBsZW1lbnRhdGlvbiBvZiB0aGUgS2V5IE1hdGVyaWFsIFBhY2tldCAoVGFnIDUsNiw3LDE0KVxuICogICBcbiAqIFJGQzQ0ODAgNS41OlxuICogQSBrZXkgbWF0ZXJpYWwgcGFja2V0IGNvbnRhaW5zIGFsbCB0aGUgaW5mb3JtYXRpb24gYWJvdXQgYSBwdWJsaWMgb3JcbiAqIHByaXZhdGUga2V5LiAgVGhlcmUgYXJlIGZvdXIgdmFyaWFudHMgb2YgdGhpcyBwYWNrZXQgdHlwZSwgYW5kIHR3b1xuICogbWFqb3IgdmVyc2lvbnMuICBDb25zZXF1ZW50bHksIHRoaXMgc2VjdGlvbiBpcyBjb21wbGV4LlxuICovXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIHBhY2tldF9wdWJsaWNfa2V5KCkge1xuXHQvKiogS2V5IGNyZWF0aW9uIGRhdGUuXG5cdCAqIEB0eXBlIHtEYXRlfSAqL1xuXHR0aGlzLmNyZWF0ZWQgPSBuZXcgRGF0ZSgpO1xuXHQvKiogQSBsaXN0IG9mIG11bHRpcHJlY2lzaW9uIGludGVnZXJzXG5cdCAqIEB0eXBlIHtvcGVucGdwX3R5cGVfbXBpfSAqL1xuXHR0aGlzLm1waSA9IFtdO1xuXHQvKiogUHVibGljIGtleSBhbGdvcml0aG1cblx0ICogQHR5cGUge29wZW5wZ3AucHVibGlja2V5fSAqL1xuXHR0aGlzLmFsZ29yaXRobSA9ICdyc2Ffc2lnbic7XG5cblxuXHQvKipcblx0ICogSW50ZXJuYWwgUGFyc2VyIGZvciBwdWJsaWMga2V5cyBhcyBzcGVjaWZpZWQgaW4gUkZDIDQ4ODAgc2VjdGlvbiBcblx0ICogNS41LjIgUHVibGljLUtleSBQYWNrZXQgRm9ybWF0c1xuXHQgKiBjYWxsZWQgYnkgcmVhZF90YWcmbHQ7bnVtJmd0O1xuXHQgKiBAcGFyYW0ge1N0cmluZ30gaW5wdXQgSW5wdXQgc3RyaW5nIHRvIHJlYWQgdGhlIHBhY2tldCBmcm9tXG5cdCAqIEBwYXJhbSB7SW50ZWdlcn0gcG9zaXRpb24gU3RhcnQgcG9zaXRpb24gZm9yIHRoZSBwYXJzZXJcblx0ICogQHBhcmFtIHtJbnRlZ2VyfSBsZW4gTGVuZ3RoIG9mIHRoZSBwYWNrZXQgb3IgcmVtYWluaW5nIGxlbmd0aCBvZiBpbnB1dFxuXHQgKiBAcmV0dXJuIHtPYmplY3R9IFRoaXMgb2JqZWN0IHdpdGggYXR0cmlidXRlcyBzZXQgYnkgdGhlIHBhcnNlclxuXHQgKi8gIFxuXHR0aGlzLnJlYWRQdWJsaWNLZXkgPSB0aGlzLnJlYWQgPSBmdW5jdGlvbihieXRlcykge1xuXHRcdC8vIEEgb25lLW9jdGV0IHZlcnNpb24gbnVtYmVyICgzIG9yIDQpLlxuXHRcdHZhciB2ZXJzaW9uID0gYnl0ZXNbMF0uY2hhckNvZGVBdCgpO1xuXG5cdFx0aWYgKHZlcnNpb24gPT0gNCkge1xuXHRcdFx0Ly8gLSBBIGZvdXItb2N0ZXQgbnVtYmVyIGRlbm90aW5nIHRoZSB0aW1lIHRoYXQgdGhlIGtleSB3YXMgY3JlYXRlZC5cblx0XHRcdHRoaXMuY3JlYXRlZCA9IHV0aWwucmVhZERhdGUoYnl0ZXMuc3Vic3RyKDEsIDQpKTtcblx0XHRcdFxuXHRcdFx0Ly8gLSBBIG9uZS1vY3RldCBudW1iZXIgZGVub3RpbmcgdGhlIHB1YmxpYy1rZXkgYWxnb3JpdGhtIG9mIHRoaXMga2V5LlxuXHRcdFx0dGhpcy5hbGdvcml0aG0gPSBlbnVtcy5yZWFkKGVudW1zLnB1YmxpY0tleSwgYnl0ZXNbNV0uY2hhckNvZGVBdCgpKTtcblxuXHRcdFx0dmFyIG1waWNvdW50ID0gY3J5cHRvLmdldFB1YmxpY01waUNvdW50KHRoaXMuYWxnb3JpdGhtKTtcblx0XHRcdHRoaXMubXBpID0gW107XG5cblx0XHRcdHZhciBibXBpID0gYnl0ZXMuc3Vic3RyKDYpO1xuXHRcdFx0dmFyIHAgPSAwO1xuXG5cdFx0XHRmb3IgKHZhciBpID0gMDsgXG5cdFx0XHRcdGkgPCBtcGljb3VudCAmJiBwIDwgYm1waS5sZW5ndGg7IFxuXHRcdFx0XHRpKyspIHtcblxuXHRcdFx0XHR0aGlzLm1waVtpXSA9IG5ldyB0eXBlX21waSgpO1xuXG5cdFx0XHRcdHAgKz0gdGhpcy5tcGlbaV0ucmVhZChibXBpLnN1YnN0cihwKSlcblxuXHRcdFx0XHRpZihwID4gYm1waS5sZW5ndGgpXG5cdFx0XHRcdFx0dXRpbC5wcmludF9lcnJvcihcIm9wZW5wZ3AucGFja2V0LmtleW1hdGVyaWFsLmpzXFxuXCJcblx0XHRcdFx0XHRcdCsnZXJyb3IgcmVhZGluZyBNUEkgQDonK3ApO1xuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gcCArIDY7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHRocm93IG5ldyBFcnJvcignVmVyc2lvbiAnICsgdmVyc2lvbiArICcgb2YgdGhlIGtleSBwYWNrZXQgaXMgdW5zdXBwb3J0ZWQuJyk7XG5cdFx0fVxuXHR9XG5cblx0LypcbiAgICAgKiBTYW1lIGFzIHdyaXRlX3ByaXZhdGVfa2V5LCBidXQgaGFzIGxlc3MgaW5mb3JtYXRpb24gYmVjYXVzZSBvZiBcblx0ICogcHVibGljIGtleS5cbiAgICAgKiBAcGFyYW0ge0ludGVnZXJ9IGtleVR5cGUgRm9sbG93cyB0aGUgT3BlblBHUCBhbGdvcml0aG0gc3RhbmRhcmQsIFxuXHQgKiBJRSAxIGNvcnJlc3BvbmRzIHRvIFJTQS5cbiAgICAgKiBAcGFyYW0ge1JTQS5rZXlPYmplY3R9IGtleVxuICAgICAqIEBwYXJhbSB0aW1lUGFja2V0XG4gICAgICogQHJldHVybiB7T2JqZWN0fSB7Ym9keTogW3N0cmluZ11PcGVuUEdQIHBhY2tldCBib2R5IGNvbnRlbnRzLCBcblx0ICogaGVhZGVyOiBbc3RyaW5nXSBPcGVuUEdQIHBhY2tldCBoZWFkZXIsIHN0cmluZzogW3N0cmluZ10gaGVhZGVyK2JvZHl9XG4gICAgICovXG4gICAgdGhpcy53cml0ZVB1YmxpY0tleSA9IHRoaXMud3JpdGUgPSBmdW5jdGlvbigpIHtcblx0XHQvLyBWZXJzaW9uXG5cdFx0dmFyIHJlc3VsdCA9IFN0cmluZy5mcm9tQ2hhckNvZGUoNCk7XG4gICAgICAgIHJlc3VsdCArPSB1dGlsLndyaXRlRGF0ZSh0aGlzLmNyZWF0ZWQpO1xuXHRcdHJlc3VsdCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGVudW1zLndyaXRlKGVudW1zLnB1YmxpY0tleSwgdGhpcy5hbGdvcml0aG0pKTtcblxuXHRcdHZhciBtcGljb3VudCA9IGNyeXB0by5nZXRQdWJsaWNNcGlDb3VudCh0aGlzLmFsZ29yaXRobSk7XG5cblx0XHRmb3IodmFyIGkgPSAwOyBpIDwgbXBpY291bnQ7IGkrKykge1xuXHRcdFx0cmVzdWx0ICs9IHRoaXMubXBpW2ldLndyaXRlKCk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHJlc3VsdDtcblx0fVxuXG5cdC8vIFdyaXRlIGFuIG9sZCB2ZXJzaW9uIHBhY2tldCAtIGl0J3MgdXNlZCBieSBzb21lIG9mIHRoZSBpbnRlcm5hbCByb3V0aW5lcy5cblx0dGhpcy53cml0ZU9sZCA9IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBieXRlcyA9IHRoaXMud3JpdGVQdWJsaWNLZXkoKTtcblxuXHRcdHJldHVybiBTdHJpbmcuZnJvbUNoYXJDb2RlKDB4OTkpICtcblx0XHRcdHV0aWwud3JpdGVOdW1iZXIoYnl0ZXMubGVuZ3RoLCAyKSArXG5cdFx0XHRieXRlcztcblx0fVxuXG5cdC8qKlxuXHQgKiBDYWxjdWxhdGVzIHRoZSBrZXkgaWQgb2YgdGhlIGtleSBcblx0ICogQHJldHVybiB7U3RyaW5nfSBBIDggYnl0ZSBrZXkgaWRcblx0ICovXG5cdHRoaXMuZ2V0S2V5SWQgPSBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gdGhpcy5nZXRGaW5nZXJwcmludCgpLnN1YnN0cigxMiwgOCk7XG5cdH1cblx0XG5cdC8qKlxuXHQgKiBDYWxjdWxhdGVzIHRoZSBmaW5nZXJwcmludCBvZiB0aGUga2V5XG5cdCAqIEByZXR1cm4ge1N0cmluZ30gQSBzdHJpbmcgY29udGFpbmluZyB0aGUgZmluZ2VycHJpbnRcblx0ICovXG5cdHRoaXMuZ2V0RmluZ2VycHJpbnQgPSBmdW5jdGlvbigpIHtcblx0XHR2YXIgdG9IYXNoID0gdGhpcy53cml0ZU9sZCgpO1xuXHRcdHJldHVybiBjcnlwdG8uaGFzaC5zaGExKHRvSGFzaCwgdG9IYXNoLmxlbmd0aCk7XG5cdH1cblxufVxuIiwiLy8gR1BHNEJyb3dzZXJzIC0gQW4gT3BlblBHUCBpbXBsZW1lbnRhdGlvbiBpbiBqYXZhc2NyaXB0XG4vLyBDb3B5cmlnaHQgKEMpIDIwMTEgUmVjdXJpdHkgTGFicyBHbWJIXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3Jcbi8vIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlclxuLy8gdmVyc2lvbiAyLjEgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuLy8gYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2Zcbi8vIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUgR05VXG4vLyBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuLy8gXG4vLyBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFsb25nIHdpdGggdGhpcyBsaWJyYXJ5OyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlXG4vLyBGb3VuZGF0aW9uLCBJbmMuLCA1MSBGcmFua2xpbiBTdHJlZXQsIEZpZnRoIEZsb29yLCBCb3N0b24sIE1BICAwMjExMC0xMzAxICBVU0FcblxudmFyIGNyeXB0byA9IHJlcXVpcmUoJy4uL2NyeXB0bycpO1xuXG4vKipcbiAqIEBjbGFzc1xuICogQGNsYXNzZGVzYyBJbXBsZW1lbnRhdGlvbiBvZiB0aGUgU3ltbWV0cmljYWxseSBFbmNyeXB0ZWQgRGF0YSBQYWNrZXQgKFRhZyA5KVxuICogXG4gKiBSRkM0ODgwIDUuNzogVGhlIFN5bW1ldHJpY2FsbHkgRW5jcnlwdGVkIERhdGEgcGFja2V0IGNvbnRhaW5zIGRhdGEgZW5jcnlwdGVkXG4gKiB3aXRoIGEgc3ltbWV0cmljLWtleSBhbGdvcml0aG0uIFdoZW4gaXQgaGFzIGJlZW4gZGVjcnlwdGVkLCBpdCBjb250YWlucyBvdGhlclxuICogcGFja2V0cyAodXN1YWxseSBhIGxpdGVyYWwgZGF0YSBwYWNrZXQgb3IgY29tcHJlc3NlZCBkYXRhIHBhY2tldCwgYnV0IGluXG4gKiB0aGVvcnkgb3RoZXIgU3ltbWV0cmljYWxseSBFbmNyeXB0ZWQgRGF0YSBwYWNrZXRzIG9yIHNlcXVlbmNlcyBvZiBwYWNrZXRzXG4gKiB0aGF0IGZvcm0gd2hvbGUgT3BlblBHUCBtZXNzYWdlcykuXG4gKi9cblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiBwYWNrZXRfc3ltbWV0cmljYWxseV9lbmNyeXB0ZWQoKSB7XG5cdHRoaXMuZW5jcnlwdGVkID0gbnVsbDtcblx0LyoqIERlY3J5cHRlZCBwYWNrZXRzIGNvbnRhaW5lZCB3aXRoaW4uIFxuXHQgKiBAdHlwZSB7b3BlbnBncF9wYWNrZXRsaXN0fSAqL1xuXHR0aGlzLnBhY2tldHM7XG5cblx0XG5cblx0dGhpcy5yZWFkID0gZnVuY3Rpb24oYnl0ZXMpIHtcblx0XHR0aGlzLmVuY3J5cHRlZCA9IGJ5dGVzO1xuXHR9XG5cblx0dGhpcy53cml0ZSA9IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiB0aGlzLmVuY3J5cHRlZDtcblx0fVxuXG5cdC8qKlxuXHQgKiBTeW1tZXRyaWNhbGx5IGRlY3J5cHQgdGhlIHBhY2tldCBkYXRhXG5cdCAqIFxuXHQgKiBAcGFyYW0ge0ludGVnZXJ9IHNlc3Npb25LZXlBbGdvcml0aG1cblx0ICogICAgICAgICAgICAgU3ltbWV0cmljIGtleSBhbGdvcml0aG0gdG8gdXNlIC8vIFNlZSBSRkM0ODgwIDkuMlxuXHQgKiBAcGFyYW0ge1N0cmluZ30ga2V5XG5cdCAqICAgICAgICAgICAgIEtleSBhcyBzdHJpbmcgd2l0aCB0aGUgY29ycmVzcG9uZGluZyBsZW5ndGggdG8gdGhlXG5cdCAqICAgICAgICAgICAgYWxnb3JpdGhtXG5cdCAqIEByZXR1cm4gVGhlIGRlY3J5cHRlZCBkYXRhO1xuXHQgKi9cblx0dGhpcy5kZWNyeXB0ID0gZnVuY3Rpb24oc2Vzc2lvbktleUFsZ29yaXRobSwga2V5KSB7XG5cdFx0dmFyIGRlY3J5cHRlZCA9IGNyeXB0by5zeW1tZXRyaWMuZGVjcnlwdChcblx0XHRcdFx0c2Vzc2lvbktleUFsZ29yaXRobSwga2V5LCB0aGlzLmVuY3J5cHRlZCwgdHJ1ZSk7XG5cblx0XHR0aGlzLnBhY2tldHMucmVhZChkZWNyeXB0ZWQpO1xuXHR9XG5cblx0dGhpcy5lbmNyeXB0ID0gZnVuY3Rpb24oYWxnbywga2V5KSB7XG5cdFx0dmFyIGRhdGEgPSB0aGlzLnBhY2tldHMud3JpdGUoKTtcblxuXHRcdHRoaXMuZW5jcnlwdGVkID0gY3J5cHRvLnN5bW1ldHJpYy5lbmNyeXB0KFxuXHRcdFx0XHRjcnlwdG8uZ2V0UHJlZml4UmFuZG9tKGFsZ28pLCBhbGdvLCBrZXksIGRhdGEsIHRydWUpO1xuXHR9XG59O1xuIiwiLy8gR1BHNEJyb3dzZXJzIC0gQW4gT3BlblBHUCBpbXBsZW1lbnRhdGlvbiBpbiBqYXZhc2NyaXB0XG4vLyBDb3B5cmlnaHQgKEMpIDIwMTEgUmVjdXJpdHkgTGFicyBHbWJIXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3Jcbi8vIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlclxuLy8gdmVyc2lvbiAyLjEgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuLy8gYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2Zcbi8vIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUgR05VXG4vLyBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuLy8gXG4vLyBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFsb25nIHdpdGggdGhpcyBsaWJyYXJ5OyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlXG4vLyBGb3VuZGF0aW9uLCBJbmMuLCA1MSBGcmFua2xpbiBTdHJlZXQsIEZpZnRoIEZsb29yLCBCb3N0b24sIE1BICAwMjExMC0xMzAxICBVU0FcblxudmFyIHB1YmxpY0tleSA9IHJlcXVpcmUoJy4vcHVibGljX2tleS5qcycpLFxuXHRlbnVtcyA9IHJlcXVpcmUoJy4uL2VudW1zLmpzJyksXG5cdHV0aWwgPSByZXF1aXJlKCcuLi91dGlsJyksXG5cdGNyeXB0byA9IHJlcXVpcmUoJy4uL2NyeXB0bycpLFxuXHR0eXBlX21waSA9IHJlcXVpcmUoJy4uL3R5cGUvbXBpLmpzJyksXG5cdHR5cGVfczJrID0gcmVxdWlyZSgnLi4vdHlwZS9zMmsuanMnKTtcblxuLyoqXG4gKiBAY2xhc3NcbiAqIEBjbGFzc2Rlc2MgSW1wbGVtZW50YXRpb24gb2YgdGhlIEtleSBNYXRlcmlhbCBQYWNrZXQgKFRhZyA1LDYsNywxNClcbiAqICAgXG4gKiBSRkM0NDgwIDUuNTpcbiAqIEEga2V5IG1hdGVyaWFsIHBhY2tldCBjb250YWlucyBhbGwgdGhlIGluZm9ybWF0aW9uIGFib3V0IGEgcHVibGljIG9yXG4gKiBwcml2YXRlIGtleS4gIFRoZXJlIGFyZSBmb3VyIHZhcmlhbnRzIG9mIHRoaXMgcGFja2V0IHR5cGUsIGFuZCB0d29cbiAqIG1ham9yIHZlcnNpb25zLiAgQ29uc2VxdWVudGx5LCB0aGlzIHNlY3Rpb24gaXMgY29tcGxleC5cbiAqL1xuZnVuY3Rpb24gcGFja2V0X3NlY3JldF9rZXkoKSB7XG5cdHB1YmxpY0tleS5jYWxsKHRoaXMpO1xuXG5cdHRoaXMuZW5jcnlwdGVkID0gbnVsbDtcblxuXG5cdGZ1bmN0aW9uIGdldF9oYXNoX2xlbihoYXNoKSB7XG5cdFx0aWYoaGFzaCA9PSAnc2hhMScpXG5cdFx0XHRyZXR1cm4gMjA7XG5cdFx0ZWxzZVxuXHRcdFx0cmV0dXJuIDI7XG5cdH1cblxuXHRmdW5jdGlvbiBnZXRfaGFzaF9mbihoYXNoKSB7XG5cdFx0aWYoaGFzaCA9PSAnc2hhMScpXG5cdFx0XHRyZXR1cm4gY3J5cHRvLmhhc2guc2hhMTtcblx0XHRlbHNlXG5cdFx0XHRyZXR1cm4gZnVuY3Rpb24oYykge1xuXHRcdFx0XHRcdHJldHVybiB1dGlsLndyaXRlTnVtYmVyKHV0aWwuY2FsY19jaGVja3N1bShjKSwgMik7XG5cdFx0XHRcdH1cblx0fVxuXG5cdC8vIEhlbHBlciBmdW5jdGlvblxuXHRmdW5jdGlvbiBwYXJzZV9jbGVhcnRleHRfbXBpKGhhc2hfYWxnb3JpdGhtLCBjbGVhcnRleHQsIGFsZ29yaXRobSkge1xuXHRcdHZhciBoYXNobGVuID0gZ2V0X2hhc2hfbGVuKGhhc2hfYWxnb3JpdGhtKSxcblx0XHRcdGhhc2hmbiA9IGdldF9oYXNoX2ZuKGhhc2hfYWxnb3JpdGhtKTtcblxuXHRcdHZhciBoYXNodGV4dCA9IGNsZWFydGV4dC5zdWJzdHIoY2xlYXJ0ZXh0Lmxlbmd0aCAtIGhhc2hsZW4pO1xuXHRcdGNsZWFydGV4dCA9IGNsZWFydGV4dC5zdWJzdHIoMCwgY2xlYXJ0ZXh0Lmxlbmd0aCAtIGhhc2hsZW4pO1xuXG5cdFx0dmFyIGhhc2ggPSBoYXNoZm4oY2xlYXJ0ZXh0KTtcblxuXHRcdGlmKGhhc2ggIT0gaGFzaHRleHQpXG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoXCJIYXNoIG1pc21hdGNoLlwiKTtcblxuXHRcdHZhciBtcGlzID0gY3J5cHRvLmdldFByaXZhdGVNcGlDb3VudChhbGdvcml0aG0pO1xuXG5cdFx0dmFyIGogPSAwO1xuXHRcdHZhciBtcGkgPSBbXTtcblxuXHRcdGZvcih2YXIgaSA9IDA7IGkgPCBtcGlzICYmIGogPCBjbGVhcnRleHQubGVuZ3RoOyBpKyspIHtcblx0XHRcdG1waVtpXSA9IG5ldyB0eXBlX21waSgpO1xuXHRcdFx0aiArPSBtcGlbaV0ucmVhZChjbGVhcnRleHQuc3Vic3RyKGopKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gbXBpO1xuXHR9XG5cblx0ZnVuY3Rpb24gd3JpdGVfY2xlYXJ0ZXh0X21waShoYXNoX2FsZ29yaXRobSwgYWxnb3JpdGhtLCBtcGkpIHtcblx0XHR2YXIgYnl0ZXM9ICcnO1xuXHRcdHZhciBkaXNjYXJkID0gY3J5cHRvLmdldFB1YmxpY01waUNvdW50KGFsZ29yaXRobSk7XG5cblx0XHRmb3IodmFyIGkgPSBkaXNjYXJkOyBpIDwgbXBpLmxlbmd0aDsgaSsrKSB7XG5cdFx0XHRieXRlcyArPSBtcGlbaV0ud3JpdGUoKTtcblx0XHR9XG5cblxuXHRcdGJ5dGVzICs9IGdldF9oYXNoX2ZuKGhhc2hfYWxnb3JpdGhtKShieXRlcyk7XG5cdFx0XG5cdFx0cmV0dXJuIGJ5dGVzO1xuXHR9XG5cdFx0XG5cblx0Ly8gNS41LjMuICBTZWNyZXQtS2V5IFBhY2tldCBGb3JtYXRzXG5cdFxuXHQvKipcblx0ICogSW50ZXJuYWwgcGFyc2VyIGZvciBwcml2YXRlIGtleXMgYXMgc3BlY2lmaWVkIGluIFJGQyA0ODgwIHNlY3Rpb24gNS41LjNcblx0ICogQHBhcmFtIHtTdHJpbmd9IGJ5dGVzIElucHV0IHN0cmluZyB0byByZWFkIHRoZSBwYWNrZXQgZnJvbVxuXHQgKiBAcGFyYW0ge0ludGVnZXJ9IHBvc2l0aW9uIFN0YXJ0IHBvc2l0aW9uIGZvciB0aGUgcGFyc2VyXG5cdCAqIEBwYXJhbSB7SW50ZWdlcn0gbGVuIExlbmd0aCBvZiB0aGUgcGFja2V0IG9yIHJlbWFpbmluZyBsZW5ndGggb2YgYnl0ZXNcblx0ICogQHJldHVybiB7T2JqZWN0fSBUaGlzIG9iamVjdCB3aXRoIGF0dHJpYnV0ZXMgc2V0IGJ5IHRoZSBwYXJzZXJcblx0ICovXG5cdHRoaXMucmVhZCA9IGZ1bmN0aW9uKGJ5dGVzKSB7XG5cdCAgICAvLyAtIEEgUHVibGljLUtleSBvciBQdWJsaWMtU3Via2V5IHBhY2tldCwgYXMgZGVzY3JpYmVkIGFib3ZlLlxuXHRcdHZhciBsZW4gPSB0aGlzLnJlYWRQdWJsaWNLZXkoYnl0ZXMpO1xuXG5cdCAgICBieXRlcyA9IGJ5dGVzLnN1YnN0cihsZW4pO1xuXG5cdFx0XG5cdCAgICAvLyAtIE9uZSBvY3RldCBpbmRpY2F0aW5nIHN0cmluZy10by1rZXkgdXNhZ2UgY29udmVudGlvbnMuICBaZXJvXG5cdCAgICAvLyAgIGluZGljYXRlcyB0aGF0IHRoZSBzZWNyZXQta2V5IGRhdGEgaXMgbm90IGVuY3J5cHRlZC4gIDI1NSBvciAyNTRcblx0ICAgIC8vICAgaW5kaWNhdGVzIHRoYXQgYSBzdHJpbmctdG8ta2V5IHNwZWNpZmllciBpcyBiZWluZyBnaXZlbi4gIEFueVxuXHQgICAgLy8gICBvdGhlciB2YWx1ZSBpcyBhIHN5bW1ldHJpYy1rZXkgZW5jcnlwdGlvbiBhbGdvcml0aG0gaWRlbnRpZmllci5cblx0ICAgIHZhciBpc0VuY3J5cHRlZCA9IGJ5dGVzWzBdLmNoYXJDb2RlQXQoKTtcblxuXHRcdGlmKGlzRW5jcnlwdGVkKSB7XG5cdFx0XHR0aGlzLmVuY3J5cHRlZCA9IGJ5dGVzO1xuXHRcdH0gZWxzZSB7XG5cdFxuXHRcdFx0Ly8gLSBQbGFpbiBvciBlbmNyeXB0ZWQgbXVsdGlwcmVjaXNpb24gaW50ZWdlcnMgY29tcHJpc2luZyB0aGUgc2VjcmV0XG5cdFx0XHQvLyAgIGtleSBkYXRhLiAgVGhlc2UgYWxnb3JpdGhtLXNwZWNpZmljIGZpZWxkcyBhcmUgYXMgZGVzY3JpYmVkXG5cdFx0XHQvLyAgIGJlbG93LlxuXG5cdFx0XHR0aGlzLm1waSA9IHRoaXMubXBpLmNvbmNhdChwYXJzZV9jbGVhcnRleHRfbXBpKCdtb2QnLCBieXRlcy5zdWJzdHIoMSksXG5cdFx0XHRcdHRoaXMuYWxnb3JpdGhtKSk7XG5cdFx0fSAgICBcblxuXHR9XG5cdFxuXHQvKlxuICAgICAqIENyZWF0ZXMgYW4gT3BlblBHUCBrZXkgcGFja2V0IGZvciB0aGUgZ2l2ZW4ga2V5LiBtdWNoIFxuXHQgKiBUT0RPIGluIHJlZ2FyZHMgdG8gczJrLCBzdWJrZXlzLlxuICAgICAqIEBwYXJhbSB7SW50ZWdlcn0ga2V5VHlwZSBGb2xsb3dzIHRoZSBPcGVuUEdQIGFsZ29yaXRobSBzdGFuZGFyZCwgXG5cdCAqIElFIDEgY29ycmVzcG9uZHMgdG8gUlNBLlxuICAgICAqIEBwYXJhbSB7UlNBLmtleU9iamVjdH0ga2V5XG4gICAgICogQHBhcmFtIHBhc3NwaHJhc2VcbiAgICAgKiBAcGFyYW0gczJrSGFzaFxuICAgICAqIEBwYXJhbSBzeW1tZXRyaWNFbmNyeXB0aW9uQWxnb3JpdGhtXG4gICAgICogQHBhcmFtIHRpbWVQYWNrZXRcbiAgICAgKiBAcmV0dXJuIHtPYmplY3R9IHtib2R5OiBbc3RyaW5nXU9wZW5QR1AgcGFja2V0IGJvZHkgY29udGVudHMsIFxuXHRcdGhlYWRlcjogW3N0cmluZ10gT3BlblBHUCBwYWNrZXQgaGVhZGVyLCBzdHJpbmc6IFtzdHJpbmddIGhlYWRlcitib2R5fVxuICAgICAqL1xuICAgIHRoaXMud3JpdGUgPSBmdW5jdGlvbigpIHtcblx0XHR2YXIgYnl0ZXMgPSB0aGlzLndyaXRlUHVibGljS2V5KCk7XG5cblx0XHRpZighdGhpcy5lbmNyeXB0ZWQpIHtcblx0XHRcdGJ5dGVzICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoMCk7XG5cdFx0XHRcblx0XHRcdGJ5dGVzICs9IHdyaXRlX2NsZWFydGV4dF9tcGkoJ21vZCcsIHRoaXMuYWxnb3JpdGhtLCB0aGlzLm1waSk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdGJ5dGVzICs9IHRoaXMuZW5jcnlwdGVkO1xuXHRcdH1cblxuXHRcdHJldHVybiBieXRlcztcblx0fVxuXHRcdFx0XG5cblxuXG5cdC8qKiBFbmNyeXB0IHRoZSBwYXlsb2FkLiBCeSBkZWZhdWx0LCB3ZSB1c2UgYWVzMjU2IGFuZCBpdGVyYXRlZCwgc2FsdGVkIHN0cmluZ1xuXHQgKiB0byBrZXkgc3BlY2lmaWVyXG5cdCAqIEBwYXJhbSB7U3RyaW5nfSBwYXNzcGhyYXNlXG5cdCAqL1xuICAgIHRoaXMuZW5jcnlwdCA9IGZ1bmN0aW9uKHBhc3NwaHJhc2UpIHtcblxuXHRcdHZhciBzMmsgPSBuZXcgdHlwZV9zMmsoKSxcblx0XHRcdHN5bW1ldHJpYyA9ICdhZXMyNTYnLFxuXHRcdFx0Y2xlYXJ0ZXh0ID0gd3JpdGVfY2xlYXJ0ZXh0X21waSgnc2hhMScsIHRoaXMuYWxnb3JpdGhtLCB0aGlzLm1waSksXG5cdFx0XHRrZXkgPSBwcm9kdWNlRW5jcnlwdGlvbktleShzMmssIHBhc3NwaHJhc2UsIHN5bW1ldHJpYyksXG5cdFx0XHRibG9ja0xlbiA9IGNyeXB0by5nZXRCbG9ja0xlbmd0aChzeW1tZXRyaWMpLFxuXHRcdFx0aXYgPSBjcnlwdG8ucmFuZG9tLmdldFJhbmRvbUJ5dGVzKGJsb2NrTGVuKTtcblxuXG5cdFx0dGhpcy5lbmNyeXB0ZWQgPSAnJztcblx0XHR0aGlzLmVuY3J5cHRlZCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKDI1NCk7XG5cdFx0dGhpcy5lbmNyeXB0ZWQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShlbnVtcy53cml0ZShlbnVtcy5zeW1tZXRyaWMsIHN5bW1ldHJpYykpO1xuXHRcdHRoaXMuZW5jcnlwdGVkICs9IHMyay53cml0ZSgpO1xuXHRcdHRoaXMuZW5jcnlwdGVkICs9IGl2O1xuXG5cblx0XHR2YXIgZm47XG5cblx0XHRzd2l0Y2goc3ltbWV0cmljKSB7XG5cdFx0Y2FzZSAnY2FzdDUnOlxuXHRcdFx0Zm4gPSBjcnlwdG8uY2lwaGVyLmNhc3Q1O1xuXHRcdFx0YnJlYWs7XG5cdFx0Y2FzZSAnYWVzMTI4Jzpcblx0XHRjYXNlICdhZXMxOTInOlxuXHRcdGNhc2UgJ2FlczI1Nic6XG4gICAgXHRcdHZhciBmbiA9IGZ1bmN0aW9uKGJsb2NrLGtleSkge1xuICAgIFx0XHQgICAgXHRyZXR1cm4gY3J5cHRvLmNpcGhlci5hZXMuZW5jcnlwdCh1dGlsLnN0cjJiaW4oYmxvY2spLGtleSk7XG4gICAgXHRcdFx0fVxuXG5cdFx0XHRrZXkgPSBuZXcgY3J5cHRvLmNpcGhlci5hZXMua2V5RXhwYW5zaW9uKGtleSk7XG5cdFx0XHRicmVhaztcblxuXHRcdGRlZmF1bHQ6XG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoXCJVbnN1cHBvcnRlZCBzeW1tZXRyaWMgZW5jcnlwdGlvbiBhbGdvcml0aG0uXCIpO1xuXHRcdH1cblxuXHRcdGNvbnNvbGUubG9nKGNsZWFydGV4dCk7XG5cblx0XHR0aGlzLmVuY3J5cHRlZCArPSBjcnlwdG8uY2ZiLm5vcm1hbEVuY3J5cHQoZm4sIGl2Lmxlbmd0aCwga2V5LCBjbGVhcnRleHQsIGl2KTtcbiAgICB9XG5cblx0ZnVuY3Rpb24gcHJvZHVjZUVuY3J5cHRpb25LZXkoczJrLCBwYXNzcGhyYXNlLCBhbGdvcml0aG0pIHtcblx0XHRyZXR1cm4gczJrLnByb2R1Y2Vfa2V5KHBhc3NwaHJhc2UsXG5cdFx0XHRjcnlwdG8uZ2V0S2V5TGVuZ3RoKGFsZ29yaXRobSkpO1xuXHR9XG5cblx0LyoqXG5cdCAqIERlY3J5cHRzIHRoZSBwcml2YXRlIGtleSBNUElzIHdoaWNoIGFyZSBuZWVkZWQgdG8gdXNlIHRoZSBrZXkuXG5cdCAqIG9wZW5wZ3BfcGFja2V0X2tleW1hdGVyaWFsLmhhc1VuZW5jcnlwdGVkU2VjcmV0S2V5RGF0YSBzaG91bGQgYmUgXG5cdCAqIGZhbHNlIG90aGVyd2lzZVxuXHQgKiBhIGNhbGwgdG8gdGhpcyBmdW5jdGlvbiBpcyBub3QgbmVlZGVkXG5cdCAqIFxuXHQgKiBAcGFyYW0ge1N0cmluZ30gc3RyX3Bhc3NwaHJhc2UgVGhlIHBhc3NwaHJhc2UgZm9yIHRoaXMgcHJpdmF0ZSBrZXkgXG5cdCAqIGFzIHN0cmluZ1xuXHQgKiBAcmV0dXJuIHtCb29sZWFufSBUcnVlIGlmIHRoZSBwYXNzcGhyYXNlIHdhcyBjb3JyZWN0OyBmYWxzZSBpZiBub3Rcblx0ICovXG5cdHRoaXMuZGVjcnlwdCA9IGZ1bmN0aW9uKHBhc3NwaHJhc2UpIHtcblx0XHRpZiAoIXRoaXMuZW5jcnlwdGVkKVxuXHRcdFx0cmV0dXJuO1xuXG5cdFx0dmFyIGkgPSAwLFxuXHRcdFx0c3ltbWV0cmljLFxuXHRcdFx0a2V5O1xuXG5cdFx0dmFyIHMya191c2FnZSA9IHRoaXMuZW5jcnlwdGVkW2krK10uY2hhckNvZGVBdCgpO1xuXG5cdCAgICAvLyAtIFtPcHRpb25hbF0gSWYgc3RyaW5nLXRvLWtleSB1c2FnZSBvY3RldCB3YXMgMjU1IG9yIDI1NCwgYSBvbmUtXG5cdCAgICAvLyAgIG9jdGV0IHN5bW1ldHJpYyBlbmNyeXB0aW9uIGFsZ29yaXRobS5cblx0ICAgIGlmIChzMmtfdXNhZ2UgPT0gMjU1IHx8IHMya191c2FnZSA9PSAyNTQpIHtcblx0ICAgIFx0c3ltbWV0cmljID0gdGhpcy5lbmNyeXB0ZWRbaSsrXS5jaGFyQ29kZUF0KCk7XG5cdFx0XHRzeW1tZXRyaWMgPSBlbnVtcy5yZWFkKGVudW1zLnN5bW1ldHJpYywgc3ltbWV0cmljKTtcblx0ICAgICBcblx0XHRcdC8vIC0gW09wdGlvbmFsXSBJZiBzdHJpbmctdG8ta2V5IHVzYWdlIG9jdGV0IHdhcyAyNTUgb3IgMjU0LCBhXG5cdFx0XHQvLyAgIHN0cmluZy10by1rZXkgc3BlY2lmaWVyLiAgVGhlIGxlbmd0aCBvZiB0aGUgc3RyaW5nLXRvLWtleVxuXHRcdFx0Ly8gICBzcGVjaWZpZXIgaXMgaW1wbGllZCBieSBpdHMgdHlwZSwgYXMgZGVzY3JpYmVkIGFib3ZlLlxuXHQgICAgXHR2YXIgczJrID0gbmV3IHR5cGVfczJrKCk7XG5cdCAgICBcdGkgKz0gczJrLnJlYWQodGhpcy5lbmNyeXB0ZWQuc3Vic3RyKGkpKTtcblxuXHRcdFx0a2V5ID0gcHJvZHVjZUVuY3J5cHRpb25LZXkoczJrLCBwYXNzcGhyYXNlLCBzeW1tZXRyaWMpO1xuXHQgICAgfSBlbHNlIHtcblx0XHRcdHN5bW1ldHJpYyA9IHMya191c2FnZTtcblx0XHRcdHN5bW1ldHJpYyA9IGVudW1zLnJlYWQoZW51bXMuc3ltbWV0cmljLCBzeW1tZXRyaWMpO1xuXHRcdFx0a2V5ID0gY3J5cHRvLmhhc2gubWQ1KHBhc3NwaHJhc2UpO1xuXHRcdH1cblxuXHQgICAgXG5cdCAgICAvLyAtIFtPcHRpb25hbF0gSWYgc2VjcmV0IGRhdGEgaXMgZW5jcnlwdGVkIChzdHJpbmctdG8ta2V5IHVzYWdlIG9jdGV0XG5cdCAgICAvLyAgIG5vdCB6ZXJvKSwgYW4gSW5pdGlhbCBWZWN0b3IgKElWKSBvZiB0aGUgc2FtZSBsZW5ndGggYXMgdGhlXG5cdCAgICAvLyAgIGNpcGhlcidzIGJsb2NrIHNpemUuXG5cdFx0dmFyIGl2ID0gdGhpcy5lbmNyeXB0ZWQuc3Vic3RyKGksIFxuXHRcdFx0Y3J5cHRvLmdldEJsb2NrTGVuZ3RoKHN5bW1ldHJpYykpO1xuXG5cdFx0aSArPSBpdi5sZW5ndGg7XG5cblx0XHR2YXIgY2xlYXJ0ZXh0LFxuXHRcdFx0Y2lwaGVydGV4dCA9IHRoaXMuZW5jcnlwdGVkLnN1YnN0cihpKTtcblxuICAgIFx0c3dpdGNoIChzeW1tZXRyaWMpIHtcblx0ICAgIGNhc2UgICdpZGVhJzogLy8gLSBJREVBIFtJREVBXVxuXHRcdFx0dGhyb3cgbmV3IEVycm9yKFwiSURFQSBpcyBub3QgaW1wbGVtZW50ZWQuXCIpO1xuXHQgICAgXHRyZXR1cm4gZmFsc2U7XG4gICAgXHRjYXNlICAnZGVzJzogLy8gLSBUcmlwbGVERVMgKERFUy1FREUsIFtTQ0hORUlFUl0gW0hBQ10gLSAxNjggYml0IGtleSBkZXJpdmVkIGZyb20gMTkyKVxuICAgIFx0XHRjbGVhcnRleHQgPSBjcnlwdG8uY2ZiLm5vcm1hbF9kZWNyeXB0KGZ1bmN0aW9uKGJsb2NrLCBrZXkpIHtcbiAgICBcdFx0XHRyZXR1cm4gY3J5cHRvLmNpcGhlci5kZXMoa2V5LCBibG9jaywxLG51bGwsMCk7XG4gICAgXHRcdH0sIGl2Lmxlbmd0aCwga2V5LCBjaXBoZXJ0ZXh0LCBpdik7XG4gICAgXHRcdGJyZWFrO1xuICAgIFx0Y2FzZSAgJ2Nhc3Q1JzogLy8gLSBDQVNUNSAoMTI4IGJpdCBrZXksIGFzIHBlciBbUkZDMjE0NF0pXG4gICAgXHRcdGNsZWFydGV4dCA9IGNyeXB0by5jZmIubm9ybWFsRGVjcnlwdChcblx0XHRcdFx0ZnVuY3Rpb24oYmxvY2ssIGtleSkge1xuXHRcdFx0XHRcdHZhciBjYXN0NSA9IG5ldyBjcnlwdG8uY2lwaGVyLmNhc3Q1LmNhc3RDbGFzcygpO1xuXHRcdFx0XHRcdGNhc3Q1LnNldEtleShrZXkpO1xuXHRcdFx0XHRcdHJldHVybiBjYXN0NS5lbmNyeXB0KHV0aWwuc3RyMmJpbihibG9jaykpOyBcblx0XHRcdFx0fVxuXHRcdFx0LCBpdi5sZW5ndGgsIFxuXHRcdFx0dXRpbC5zdHIyYmluKGtleS5zdWJzdHJpbmcoMCwxNikpLCBjaXBoZXJ0ZXh0LCBpdik7XG4gICAgXHRcdGJyZWFrO1xuXHQgICAgY2FzZSAgJ2Jsb3dmaXNoJzogLy8gLSBCbG93ZmlzaCAoMTI4IGJpdCBrZXksIDE2IHJvdW5kcykgW0JMT1dGSVNIXVxuXHQgICAgXHRjbGVhcnRleHQgPSBub3JtYWxfY2ZiX2RlY3J5cHQoZnVuY3Rpb24oYmxvY2ssIGtleSkge1xuICAgIFx0XHRcdHZhciBibG93ZmlzaCA9IG5ldyBCbG93ZmlzaChrZXkpO1xuICAgICAgICBcdFx0cmV0dXJuIGJsb3dmaXNoLmVuY3J5cHQoYmxvY2spOyBcbiAgICBcdFx0fSwgaXYubGVuZ3RoLCBrZXksIGNpcGhlcnRleHQsIGl2KTtcbiAgICBcdFx0YnJlYWs7XG5cdCAgICBjYXNlICAnYWVzMTI4JzogLy8gLSBBRVMgd2l0aCAxMjgtYml0IGtleSBbQUVTXVxuICAgIFx0Y2FzZSAgJ2FlczE5Mic6IC8vIC0gQUVTIHdpdGggMTkyLWJpdCBrZXlcbiAgICBcdGNhc2UgICdhZXMyNTYnOiAvLyAtIEFFUyB3aXRoIDI1Ni1iaXQga2V5XG4gICAgXHRcdGNsZWFydGV4dCA9IGNyeXB0by5jZmIubm9ybWFsRGVjcnlwdChmdW5jdGlvbihibG9jayxrZXkpe1xuICAgIFx0XHQgICAgXHRyZXR1cm4gY3J5cHRvLmNpcGhlci5hZXMuZW5jcnlwdCh1dGlsLnN0cjJiaW4oYmxvY2spLGtleSk7XG4gICAgXHRcdFx0fSxcbiAgICBcdFx0XHRpdi5sZW5ndGgsIG5ldyBjcnlwdG8uY2lwaGVyLmFlcy5rZXlFeHBhbnNpb24oa2V5KSwgXG5cdFx0XHRcdFx0Y2lwaGVydGV4dCwgaXYpO1xuXHQgICAgXHRicmVhaztcbiAgICBcdGNhc2UgJ3R3b2Zpc2gnOiAvLyAtIFR3b2Zpc2ggd2l0aCAyNTYtYml0IGtleSBbVFdPRklTSF1cblx0XHRcdHRocm93IG5ldyBFcnJvcihcIlR3b2Zpc2ggaXMgbm90IGltcGxlbWVudGVkLlwiKTtcblx0ICAgIFx0cmV0dXJuIGZhbHNlO1xuICAgIFx0ZGVmYXVsdDpcblx0XHRcdHRocm93IG5ldyBFcnJvcihcIlVua25vd24gc3ltbWV0cmljIGFsZ29yaXRobS5cIik7XG4gICAgXHRcdHJldHVybiBmYWxzZTtcbiAgICBcdH1cbiBcblx0XHR2YXIgaGFzaCA9IHMya191c2FnZSA9PSAyNTQgP1xuXHRcdFx0J3NoYTEnIDpcblx0XHRcdCdtb2QnO1xuXG4gICBcdFxuXHRcdHRoaXMubXBpID0gdGhpcy5tcGkuY29uY2F0KHBhcnNlX2NsZWFydGV4dF9tcGkoaGFzaCwgY2xlYXJ0ZXh0LFxuXHRcdFx0dGhpcy5hbGdvcml0aG0pKTtcblx0fVxuXHRcbn1cblxucGFja2V0X3NlY3JldF9rZXkucHJvdG90eXBlID0gbmV3IHB1YmxpY0tleTtcblxubW9kdWxlLmV4cG9ydHMgPSBwYWNrZXRfc2VjcmV0X2tleTtcbiIsIi8vIEdQRzRCcm93c2VycyAtIEFuIE9wZW5QR1AgaW1wbGVtZW50YXRpb24gaW4gamF2YXNjcmlwdFxuLy8gQ29weXJpZ2h0IChDKSAyMDExIFJlY3VyaXR5IExhYnMgR21iSFxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZnJlZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yXG4vLyBtb2RpZnkgaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFzIHB1Ymxpc2hlZCBieSB0aGUgRnJlZSBTb2Z0d2FyZSBGb3VuZGF0aW9uOyBlaXRoZXJcbi8vIHZlcnNpb24gMi4xIG9mIHRoZSBMaWNlbnNlLCBvciAoYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuLy8gXG4vLyBUaGlzIGxpYnJhcnkgaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbi8vIGJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG4vLyBNRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlIEdOVVxuLy8gTGVzc2VyIEdlbmVyYWwgUHVibGljIExpY2Vuc2UgZm9yIG1vcmUgZGV0YWlscy5cbi8vIFxuLy8gWW91IHNob3VsZCBoYXZlIHJlY2VpdmVkIGEgY29weSBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhbG9uZyB3aXRoIHRoaXMgbGlicmFyeTsgaWYgbm90LCB3cml0ZSB0byB0aGUgRnJlZSBTb2Z0d2FyZVxuLy8gRm91bmRhdGlvbiwgSW5jLiwgNTEgRnJhbmtsaW4gU3RyZWV0LCBGaWZ0aCBGbG9vciwgQm9zdG9uLCBNQSAgMDIxMTAtMTMwMSAgVVNBXG5cbnZhciB1dGlsID0gcmVxdWlyZSgnLi4vdXRpbCcpO1xuXG4vKipcbiAqIEBjbGFzc1xuICogQGNsYXNzZGVzYyBJbXBsZW1lbnRhdGlvbiBvZiB0aGUgVXNlciBJRCBQYWNrZXQgKFRhZyAxMylcbiAqIEEgVXNlciBJRCBwYWNrZXQgY29uc2lzdHMgb2YgVVRGLTggdGV4dCB0aGF0IGlzIGludGVuZGVkIHRvIHJlcHJlc2VudFxuICogdGhlIG5hbWUgYW5kIGVtYWlsIGFkZHJlc3Mgb2YgdGhlIGtleSBob2xkZXIuICBCeSBjb252ZW50aW9uLCBpdFxuICogaW5jbHVkZXMgYW4gUkZDIDI4MjIgW1JGQzI4MjJdIG1haWwgbmFtZS1hZGRyLCBidXQgdGhlcmUgYXJlIG5vXG4gKiByZXN0cmljdGlvbnMgb24gaXRzIGNvbnRlbnQuICBUaGUgcGFja2V0IGxlbmd0aCBpbiB0aGUgaGVhZGVyXG4gKiBzcGVjaWZpZXMgdGhlIGxlbmd0aCBvZiB0aGUgVXNlciBJRC4gXG4gKi9cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gcGFja2V0X3VzZXJpZCgpIHtcblx0LyoqIEB0eXBlIHtTdHJpbmd9IEEgc3RyaW5nIGNvbnRhaW5pbmcgdGhlIHVzZXIgaWQuIFVzdWFsbHkgaW4gdGhlIGZvcm1cblx0ICogSm9obiBEb2UgPGpvaG5AZXhhbXBsZS5jb20+IFxuXHQgKi9cblx0dGhpcy51c2VyaWQgPSAnJztcblx0XG5cdFxuXHQvKipcblx0ICogUGFyc2luZyBmdW5jdGlvbiBmb3IgYSB1c2VyIGlkIHBhY2tldCAodGFnIDEzKS5cblx0ICogQHBhcmFtIHtTdHJpbmd9IGlucHV0IHBheWxvYWQgb2YgYSB0YWcgMTMgcGFja2V0XG5cdCAqIEBwYXJhbSB7SW50ZWdlcn0gcG9zaXRpb24gcG9zaXRpb24gdG8gc3RhcnQgcmVhZGluZyBmcm9tIHRoZSBpbnB1dCBzdHJpbmdcblx0ICogQHBhcmFtIHtJbnRlZ2VyfSBsZW4gbGVuZ3RoIG9mIHRoZSBwYWNrZXQgb3IgdGhlIHJlbWFpbmluZyBsZW5ndGggb2YgaW5wdXQgXG5cdCAqIGF0IHBvc2l0aW9uXG5cdCAqIEByZXR1cm4ge29wZW5wZ3BfcGFja2V0X2VuY3J5cHRlZGRhdGF9IG9iamVjdCByZXByZXNlbnRhdGlvblxuXHQgKi9cblx0dGhpcy5yZWFkID0gZnVuY3Rpb24oYnl0ZXMpIHtcblx0XHR0aGlzLnVzZXJpZCA9IHV0aWwuZGVjb2RlX3V0ZjgoYnl0ZXMpO1xuXHR9XG5cblx0LyoqXG5cdCAqIENyZWF0ZXMgYSBzdHJpbmcgcmVwcmVzZW50YXRpb24gb2YgdGhlIHVzZXIgaWQgcGFja2V0XG5cdCAqIEBwYXJhbSB7U3RyaW5nfSB1c2VyX2lkIHRoZSB1c2VyIGlkIGFzIHN0cmluZyAoXCJKb2huIERvZSA8am9obi5kb2VAbWFpbC51c1wiKVxuXHQgKiBAcmV0dXJuIHtTdHJpbmd9IHN0cmluZyByZXByZXNlbnRhdGlvblxuXHQgKi9cblx0dGhpcy53cml0ZSA9IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiB1dGlsLmVuY29kZV91dGY4KHRoaXMudXNlcmlkKTtcblx0fVxufVxuIiwiLy8gR1BHNEJyb3dzZXJzIC0gQW4gT3BlblBHUCBpbXBsZW1lbnRhdGlvbiBpbiBqYXZhc2NyaXB0XG4vLyBDb3B5cmlnaHQgKEMpIDIwMTEgUmVjdXJpdHkgTGFicyBHbWJIXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJlZGlzdHJpYnV0ZSBpdCBhbmQvb3Jcbi8vIG1vZGlmeSBpdCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYXMgcHVibGlzaGVkIGJ5IHRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb247IGVpdGhlclxuLy8gdmVyc2lvbiAyLjEgb2YgdGhlIExpY2Vuc2UsIG9yIChhdCB5b3VyIG9wdGlvbikgYW55IGxhdGVyIHZlcnNpb24uXG4vLyBcbi8vIFRoaXMgbGlicmFyeSBpcyBkaXN0cmlidXRlZCBpbiB0aGUgaG9wZSB0aGF0IGl0IHdpbGwgYmUgdXNlZnVsLFxuLy8gYnV0IFdJVEhPVVQgQU5ZIFdBUlJBTlRZOyB3aXRob3V0IGV2ZW4gdGhlIGltcGxpZWQgd2FycmFudHkgb2Zcbi8vIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUgR05VXG4vLyBMZXNzZXIgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuLy8gXG4vLyBZb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgTGVzc2VyIEdlbmVyYWwgUHVibGljXG4vLyBMaWNlbnNlIGFsb25nIHdpdGggdGhpcyBsaWJyYXJ5OyBpZiBub3QsIHdyaXRlIHRvIHRoZSBGcmVlIFNvZnR3YXJlXG4vLyBGb3VuZGF0aW9uLCBJbmMuLCA1MSBGcmFua2xpbiBTdHJlZXQsIEZpZnRoIEZsb29yLCBCb3N0b24sIE1BICAwMjExMC0xMzAxICBVU0FcblxudmFyIHV0aWwgPSByZXF1aXJlKCcuLi91dGlsJyksXG5cdHBhY2tldCA9IHJlcXVpcmUoJy4vcGFja2V0LmpzJyksXG5cdGVudW1zID0gcmVxdWlyZSgnLi4vZW51bXMuanMnKSxcblx0Y3J5cHRvID0gcmVxdWlyZSgnLi4vY3J5cHRvJyksXG5cdHR5cGVfbXBpID0gcmVxdWlyZSgnLi4vdHlwZS9tcGkuanMnKTtcblxuLyoqXG4gKiBAY2xhc3NcbiAqIEBjbGFzc2Rlc2MgSW1wbGVtZW50YXRpb24gb2YgdGhlIFNpZ25hdHVyZSBQYWNrZXQgKFRhZyAyKVxuICogXG4gKiBSRkM0NDgwIDUuMjpcbiAqIEEgU2lnbmF0dXJlIHBhY2tldCBkZXNjcmliZXMgYSBiaW5kaW5nIGJldHdlZW4gc29tZSBwdWJsaWMga2V5IGFuZFxuICogc29tZSBkYXRhLiAgVGhlIG1vc3QgY29tbW9uIHNpZ25hdHVyZXMgYXJlIGEgc2lnbmF0dXJlIG9mIGEgZmlsZSBvciBhXG4gKiBibG9jayBvZiB0ZXh0LCBhbmQgYSBzaWduYXR1cmUgdGhhdCBpcyBhIGNlcnRpZmljYXRpb24gb2YgYSBVc2VyIElELlxuICovXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIHBhY2tldF9zaWduYXR1cmUoKSB7XG5cblx0dGhpcy5zaWduYXR1cmVUeXBlID0gbnVsbDtcblx0dGhpcy5oYXNoQWxnb3JpdGhtID0gbnVsbDtcblx0dGhpcy5wdWJsaWNLZXlBbGdvcml0aG0gPSBudWxsOyBcblxuXHR0aGlzLnNpZ25hdHVyZURhdGEgPSBudWxsO1xuXHR0aGlzLnNpZ25lZEhhc2hWYWx1ZSA9IG51bGw7XG5cdHRoaXMubXBpID0gbnVsbDtcblxuXHR0aGlzLmNyZWF0ZWQgPSBudWxsO1xuXHR0aGlzLnNpZ25hdHVyZUV4cGlyYXRpb25UaW1lID0gbnVsbDtcblx0dGhpcy5zaWduYXR1cmVOZXZlckV4cGlyZXMgPSBudWxsO1xuXHR0aGlzLmV4cG9ydGFibGUgPSBudWxsO1xuXHR0aGlzLnRydXN0TGV2ZWwgPSBudWxsO1xuXHR0aGlzLnRydXN0QW1vdW50ID0gbnVsbDtcblx0dGhpcy5yZWd1bGFyRXhwcmVzc2lvbiA9IG51bGw7XG5cdHRoaXMucmV2b2NhYmxlID0gbnVsbDtcblx0dGhpcy5rZXlFeHBpcmF0aW9uVGltZSA9IG51bGw7XG5cdHRoaXMua2V5TmV2ZXJFeHBpcmVzID0gbnVsbDtcblx0dGhpcy5wcmVmZXJyZWRTeW1tZXRyaWNBbGdvcml0aG1zID0gbnVsbDtcblx0dGhpcy5yZXZvY2F0aW9uS2V5Q2xhc3MgPSBudWxsO1xuXHR0aGlzLnJldm9jYXRpb25LZXlBbGdvcml0aG0gPSBudWxsO1xuXHR0aGlzLnJldm9jYXRpb25LZXlGaW5nZXJwcmludCA9IG51bGw7XG5cdHRoaXMuaXNzdWVyS2V5SWQgPSBudWxsO1xuXHR0aGlzLm5vdGF0aW9uID0ge307XG5cdHRoaXMucHJlZmVycmVkSGFzaEFsZ29yaXRobXMgPSBudWxsO1xuXHR0aGlzLnByZWZlcnJlZENvbXByZXNzaW9uQWxnb3JpdGhtcyA9IG51bGw7XG5cdHRoaXMua2V5U2VydmVyUHJlZmVyZW5jZXMgPSBudWxsO1xuXHR0aGlzLnByZWZlcnJlZEtleVNlcnZlciA9IG51bGw7XG5cdHRoaXMuaXNQcmltYXJ5VXNlcklEID0gbnVsbDtcblx0dGhpcy5wb2xpY3lVUkkgPSBudWxsO1xuXHR0aGlzLmtleUZsYWdzID0gbnVsbDtcblx0dGhpcy5zaWduZXJzVXNlcklkID0gbnVsbDtcblx0dGhpcy5yZWFzb25Gb3JSZXZvY2F0aW9uRmxhZyA9IG51bGw7XG5cdHRoaXMucmVhc29uRm9yUmV2b2NhdGlvblN0cmluZyA9IG51bGw7XG5cdHRoaXMuc2lnbmF0dXJlVGFyZ2V0UHVibGljS2V5QWxnb3JpdGhtID0gbnVsbDtcblx0dGhpcy5zaWduYXR1cmVUYXJnZXRIYXNoQWxnb3JpdGhtID0gbnVsbDtcblx0dGhpcy5zaWduYXR1cmVUYXJnZXRIYXNoID0gbnVsbDtcblx0dGhpcy5lbWJlZGRlZFNpZ25hdHVyZSA9IG51bGw7XG5cblx0dGhpcy52ZXJpZmllZCA9IGZhbHNlO1xuXHRcblxuXHQvKipcblx0ICogcGFyc2luZyBmdW5jdGlvbiBmb3IgYSBzaWduYXR1cmUgcGFja2V0ICh0YWcgMikuXG5cdCAqIEBwYXJhbSB7U3RyaW5nfSBieXRlcyBwYXlsb2FkIG9mIGEgdGFnIDIgcGFja2V0XG5cdCAqIEBwYXJhbSB7SW50ZWdlcn0gcG9zaXRpb24gcG9zaXRpb24gdG8gc3RhcnQgcmVhZGluZyBmcm9tIHRoZSBieXRlcyBzdHJpbmdcblx0ICogQHBhcmFtIHtJbnRlZ2VyfSBsZW4gbGVuZ3RoIG9mIHRoZSBwYWNrZXQgb3IgdGhlIHJlbWFpbmluZyBsZW5ndGggb2YgYnl0ZXMgYXQgcG9zaXRpb25cblx0ICogQHJldHVybiB7b3BlbnBncF9wYWNrZXRfZW5jcnlwdGVkZGF0YX0gb2JqZWN0IHJlcHJlc2VudGF0aW9uXG5cdCAqL1xuXHR0aGlzLnJlYWQgPSBmdW5jdGlvbihieXRlcykge1xuXHRcdHZhciBpID0gMDtcblxuXHRcdHZhciB2ZXJzaW9uID0gYnl0ZXNbaSsrXS5jaGFyQ29kZUF0KCk7XG5cdFx0Ly8gc3dpdGNoIG9uIHZlcnNpb24gKDMgYW5kIDQpXG5cdFx0c3dpdGNoICh2ZXJzaW9uKSB7XG5cdFx0Y2FzZSAzOlxuXHRcdFx0Ly8gT25lLW9jdGV0IGxlbmd0aCBvZiBmb2xsb3dpbmcgaGFzaGVkIG1hdGVyaWFsLiBNVVNUIGJlIDUuXG5cdFx0XHRpZiAoYnl0ZXNbaSsrXS5jaGFyQ29kZUF0KCkgIT0gNSlcblx0XHRcdFx0dXRpbC5wcmludF9kZWJ1ZyhcIm9wZW5wZ3AucGFja2V0LnNpZ25hdHVyZS5qc1xcblwiK1xuXHRcdFx0XHRcdCdpbnZhbGlkIE9uZS1vY3RldCBsZW5ndGggb2YgZm9sbG93aW5nIGhhc2hlZCBtYXRlcmlhbC4nICtcblx0XHRcdFx0XHQnTVVTVCBiZSA1LiBAOicrKGktMSkpO1xuXG5cdFx0XHR2YXIgc2lncG9zID0gaTtcblx0XHRcdC8vIE9uZS1vY3RldCBzaWduYXR1cmUgdHlwZS5cblx0XHRcdHRoaXMuc2lnbmF0dXJlVHlwZSA9IGJ5dGVzW2krK10uY2hhckNvZGVBdCgpO1xuXG5cdFx0XHQvLyBGb3VyLW9jdGV0IGNyZWF0aW9uIHRpbWUuXG5cdFx0XHR0aGlzLmNyZWF0ZWQgPSB1dGlsLnJlYWREYXRlKGJ5dGVzLnN1YnN0cihpLCA0KSk7XG5cdFx0XHRpICs9IDQ7XG5cdFx0XHRcblx0XHRcdC8vIHN0b3JpbmcgZGF0YSBhcHBlbmRlZCB0byBkYXRhIHdoaWNoIGdldHMgdmVyaWZpZWRcblx0XHRcdHRoaXMuc2lnbmF0dXJlRGF0YSA9IGJ5dGVzLnN1YnN0cmluZyhwb3NpdGlvbiwgaSk7XG5cdFx0XHRcblx0XHRcdC8vIEVpZ2h0LW9jdGV0IEtleSBJRCBvZiBzaWduZXIuXG5cdFx0XHR0aGlzLmlzc3VlcktleUlkID0gYnl0ZXMuc3Vic3RyaW5nKGksIGkgKzgpO1xuXHRcdFx0aSArPSA4O1xuXG5cdFx0XHQvLyBPbmUtb2N0ZXQgcHVibGljLWtleSBhbGdvcml0aG0uXG5cdFx0XHR0aGlzLnB1YmxpY0tleUFsZ29yaXRobSA9IGJ5dGVzW2krK10uY2hhckNvZGVBdCgpO1xuXG5cdFx0XHQvLyBPbmUtb2N0ZXQgaGFzaCBhbGdvcml0aG0uXG5cdFx0XHR0aGlzLmhhc2hBbGdvcml0aG0gPSBieXRlc1tpKytdLmNoYXJDb2RlQXQoKTtcblx0XHRicmVhaztcblx0XHRjYXNlIDQ6XG5cdFx0XHR0aGlzLnNpZ25hdHVyZVR5cGUgPSBieXRlc1tpKytdLmNoYXJDb2RlQXQoKTtcblx0XHRcdHRoaXMucHVibGljS2V5QWxnb3JpdGhtID0gYnl0ZXNbaSsrXS5jaGFyQ29kZUF0KCk7XG5cdFx0XHR0aGlzLmhhc2hBbGdvcml0aG0gPSBieXRlc1tpKytdLmNoYXJDb2RlQXQoKTtcblxuXG5cdFx0XHRmdW5jdGlvbiBzdWJwYWNrZXRzKGJ5dGVzLCBzaWduZWQpIHtcblx0XHRcdFx0Ly8gVHdvLW9jdGV0IHNjYWxhciBvY3RldCBjb3VudCBmb3IgZm9sbG93aW5nIGhhc2hlZCBzdWJwYWNrZXRcblx0XHRcdFx0Ly8gZGF0YS5cblx0XHRcdFx0dmFyIHN1YnBhY2tldF9sZW5ndGggPSB1dGlsLnJlYWROdW1iZXIoXG5cdFx0XHRcdFx0Ynl0ZXMuc3Vic3RyKDAsIDIpKTtcblxuXHRcdFx0XHR2YXIgaSA9IDI7XG5cblx0XHRcdFx0Ly8gSGFzaGVkIHN1YnBhY2tldCBkYXRhIHNldCAoemVybyBvciBtb3JlIHN1YnBhY2tldHMpXG5cdFx0XHRcdHZhciBzdWJwYWNrZWRfcmVhZCA9IDA7XG5cdFx0XHRcdHdoaWxlIChpIDwgMiArIHN1YnBhY2tldF9sZW5ndGgpIHtcblxuXHRcdFx0XHRcdHZhciBsZW4gPSBwYWNrZXQucmVhZFNpbXBsZUxlbmd0aChieXRlcy5zdWJzdHIoaSkpO1xuXHRcdFx0XHRcdGkgKz0gbGVuLm9mZnNldDtcblxuXHRcdFx0XHRcdC8vIFNpbmNlIGl0IGlzIHRyaXZpYWwgdG8gYWRkIGRhdGEgdG8gdGhlIHVuaGFzaGVkIHBvcnRpb24gb2YgXG5cdFx0XHRcdFx0Ly8gdGhlIHBhY2tldCB3ZSBzaW1wbHkgaWdub3JlIGFsbCB1bmF1dGhlbnRpY2F0ZWQgZGF0YS5cblx0XHRcdFx0XHRpZihzaWduZWQpXG5cdFx0XHRcdFx0XHR0aGlzLnJlYWRfc3ViX3BhY2tldChieXRlcy5zdWJzdHIoaSwgbGVuLmxlbikpO1xuXG5cdFx0XHRcdFx0aSArPSBsZW4ubGVuO1xuXHRcdFx0XHR9XG5cdFx0XHRcdFxuXHRcdFx0XHRyZXR1cm4gaTtcblx0XHRcdH1cblx0XHRcdFxuXHRcdFx0aSArPSBzdWJwYWNrZXRzLmNhbGwodGhpcywgYnl0ZXMuc3Vic3RyKGkpLCB0cnVlKTtcblxuXHRcdFx0Ly8gQSBWNCBzaWduYXR1cmUgaGFzaGVzIHRoZSBwYWNrZXQgYm9keVxuXHRcdFx0Ly8gc3RhcnRpbmcgZnJvbSBpdHMgZmlyc3QgZmllbGQsIHRoZSB2ZXJzaW9uIG51bWJlciwgdGhyb3VnaCB0aGUgZW5kXG5cdFx0XHQvLyBvZiB0aGUgaGFzaGVkIHN1YnBhY2tldCBkYXRhLiAgVGh1cywgdGhlIGZpZWxkcyBoYXNoZWQgYXJlIHRoZVxuXHRcdFx0Ly8gc2lnbmF0dXJlIHZlcnNpb24sIHRoZSBzaWduYXR1cmUgdHlwZSwgdGhlIHB1YmxpYy1rZXkgYWxnb3JpdGhtLCB0aGVcblx0XHRcdC8vIGhhc2ggYWxnb3JpdGhtLCB0aGUgaGFzaGVkIHN1YnBhY2tldCBsZW5ndGgsIGFuZCB0aGUgaGFzaGVkXG5cdFx0XHQvLyBzdWJwYWNrZXQgYm9keS5cblx0XHRcdHRoaXMuc2lnbmF0dXJlRGF0YSA9IGJ5dGVzLnN1YnN0cigwLCBpKTtcblxuXHRcdFx0aSArPSBzdWJwYWNrZXRzLmNhbGwodGhpcywgYnl0ZXMuc3Vic3RyKGkpLCBmYWxzZSk7XG5cblx0XHRcdGJyZWFrO1xuXHRcdGRlZmF1bHQ6XG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoJ1ZlcnNpb24gJyArIHZlcnNpb24gKyAnIG9mIHRoZSBzaWduYXR1cmUgaXMgdW5zdXBwb3J0ZWQuJyk7XG5cdFx0XHRicmVhaztcblx0XHR9XG5cblx0XHQvLyBUd28tb2N0ZXQgZmllbGQgaG9sZGluZyBsZWZ0IDE2IGJpdHMgb2Ygc2lnbmVkIGhhc2ggdmFsdWUuXG5cdFx0dGhpcy5zaWduZWRIYXNoVmFsdWUgPSBieXRlcy5zdWJzdHIoaSwgMik7XG5cdFx0aSArPSAyO1xuXG5cdFx0dGhpcy5zaWduYXR1cmUgPSBieXRlcy5zdWJzdHIoaSk7XG5cdH1cblxuXHR0aGlzLndyaXRlID0gZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIHRoaXMuc2lnbmF0dXJlRGF0YSArIFxuXHRcdFx0dXRpbC53cml0ZU51bWJlcigwLCAyKSArIC8vIE51bWJlciBvZiB1bnNpZ25lZCBzdWJwYWNrZXRzLlxuXHRcdFx0dGhpcy5zaWduZWRIYXNoVmFsdWUgK1xuXHRcdFx0dGhpcy5zaWduYXR1cmU7XG5cdH1cblxuXHQvKipcblx0ICogU2lnbnMgcHJvdmlkZWQgZGF0YS4gVGhpcyBuZWVkcyB0byBiZSBkb25lIHByaW9yIHRvIHNlcmlhbGl6YXRpb24uXG5cdCAqIEBwYXJhbSB7T2JqZWN0fSBkYXRhIENvbnRhaW5zIHBhY2tldHMgdG8gYmUgc2lnbmVkLlxuXHQgKiBAcGFyYW0ge29wZW5wZ3BfbXNnX3ByaXZhdGVrZXl9IHByaXZhdGVrZXkgcHJpdmF0ZSBrZXkgdXNlZCB0byBzaWduIHRoZSBtZXNzYWdlLiBcblx0ICovXG5cdHRoaXMuc2lnbiA9IGZ1bmN0aW9uKGtleSwgZGF0YSkge1xuXHRcdHZhciBzaWduYXR1cmVUeXBlID0gZW51bXMud3JpdGUoZW51bXMuc2lnbmF0dXJlLCB0aGlzLnNpZ25hdHVyZVR5cGUpLFxuXHRcdFx0cHVibGljS2V5QWxnb3JpdGhtID0gZW51bXMud3JpdGUoZW51bXMucHVibGljS2V5LCB0aGlzLnB1YmxpY0tleUFsZ29yaXRobSksXG5cdFx0XHRoYXNoQWxnb3JpdGhtID0gZW51bXMud3JpdGUoZW51bXMuaGFzaCwgdGhpcy5oYXNoQWxnb3JpdGhtKTtcblxuXHRcdHZhciByZXN1bHQgPSBTdHJpbmcuZnJvbUNoYXJDb2RlKDQpOyBcblx0XHRyZXN1bHQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShzaWduYXR1cmVUeXBlKTtcblx0XHRyZXN1bHQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShwdWJsaWNLZXlBbGdvcml0aG0pO1xuXHRcdHJlc3VsdCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGhhc2hBbGdvcml0aG0pO1xuXG5cblx0XHQvLyBBZGQgc3VicGFja2V0cyBoZXJlXG5cdFx0cmVzdWx0ICs9IHV0aWwud3JpdGVOdW1iZXIoMCwgMik7XG5cblxuXHRcdHRoaXMuc2lnbmF0dXJlRGF0YSA9IHJlc3VsdDtcblxuXHRcdHZhciB0cmFpbGVyID0gdGhpcy5jYWxjdWxhdGVUcmFpbGVyKCk7XG5cdFx0XG5cdFx0dmFyIHRvSGFzaCA9IHRoaXMudG9TaWduKHNpZ25hdHVyZVR5cGUsIGRhdGEpICsgXG5cdFx0XHR0aGlzLnNpZ25hdHVyZURhdGEgKyB0cmFpbGVyO1xuXG5cdFx0dmFyIGhhc2ggPSBjcnlwdG8uaGFzaC5kaWdlc3QoaGFzaEFsZ29yaXRobSwgdG9IYXNoKTtcblx0XHRcblx0XHR0aGlzLnNpZ25lZEhhc2hWYWx1ZSA9IGhhc2guc3Vic3RyKDAsIDIpO1xuXG5cblx0XHR0aGlzLnNpZ25hdHVyZSA9IGNyeXB0by5zaWduYXR1cmUuc2lnbihoYXNoQWxnb3JpdGhtLCBcblx0XHRcdHB1YmxpY0tleUFsZ29yaXRobSwga2V5Lm1waSwgdG9IYXNoKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBjcmVhdGVzIGEgc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIGEgc3ViIHNpZ25hdHVyZSBwYWNrZXQgKFNlZSBSRkMgNDg4MCA1LjIuMy4xKVxuXHQgKiBAcGFyYW0ge0ludGVnZXJ9IHR5cGUgc3VicGFja2V0IHNpZ25hdHVyZSB0eXBlLiBTaWduYXR1cmUgdHlwZXMgYXMgZGVzY3JpYmVkIFxuXHQgKiBpbiBSRkM0ODgwIFNlY3Rpb24gNS4yLjMuMlxuXHQgKiBAcGFyYW0ge1N0cmluZ30gZGF0YSBkYXRhIHRvIGJlIGluY2x1ZGVkXG5cdCAqIEByZXR1cm4ge1N0cmluZ30gYSBzdHJpbmctcmVwcmVzZW50YXRpb24gb2YgYSBzdWIgc2lnbmF0dXJlIHBhY2tldCAoU2VlIFJGQyA0ODgwIDUuMi4zLjEpXG5cdCAqL1xuXHRmdW5jdGlvbiB3cml0ZV9zdWJfcGFja2V0KHR5cGUsIGRhdGEpIHtcblx0XHR2YXIgcmVzdWx0ID0gXCJcIjtcblx0XHRyZXN1bHQgKz0gcGFja2V0LndyaXRlU2ltcGxlTGVuZ3RoKGRhdGEubGVuZ3RoKzEpO1xuXHRcdHJlc3VsdCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKHR5cGUpO1xuXHRcdHJlc3VsdCArPSBkYXRhO1xuXHRcdHJldHVybiByZXN1bHQ7XG5cdH1cblx0XG5cdC8vIFY0IHNpZ25hdHVyZSBzdWIgcGFja2V0c1xuXHRcblx0dGhpcy5yZWFkX3N1Yl9wYWNrZXQgPSBmdW5jdGlvbihieXRlcykge1xuXHRcdHZhciBteXBvcyA9IDA7XG5cblx0XHRmdW5jdGlvbiByZWFkX2FycmF5KHByb3AsIGJ5dGVzKSB7XG5cdFx0XHR0aGlzW3Byb3BdID0gW107XG5cblx0XHRcdGZvciAodmFyIGkgPSAwOyBpIDwgYnl0ZXMubGVuZ3RoOyBpKyspIHtcblx0XHRcdFx0dGhpc1twcm9wXS5wdXNoKGJ5dGVzW2ldLmNoYXJDb2RlQXQoKSk7XG5cdFx0XHR9XG5cdFx0fVxuXHRcdFxuXHRcdC8vIFRoZSBsZWZ0d29zdCBiaXQgZGVub3RlcyBhIFwiY3JpdGljYWxcIiBwYWNrZXQsIGJ1dCB3ZSBpZ25vcmUgaXQuXG5cdFx0dmFyIHR5cGUgPSBieXRlc1tteXBvcysrXS5jaGFyQ29kZUF0KCkgJiAweDdGO1xuXG5cdFx0Ly8gc3VicGFja2V0IHR5cGVcblx0XHRzd2l0Y2ggKHR5cGUpIHtcblx0XHRjYXNlIDI6IC8vIFNpZ25hdHVyZSBDcmVhdGlvbiBUaW1lXG5cdFx0XHR0aGlzLmNyZWF0ZWQgPSB1dGlsLnJlYWREYXRlKGJ5dGVzLnN1YnN0cihteXBvcykpO1xuXHRcdFx0YnJlYWs7XG5cdFx0Y2FzZSAzOiAvLyBTaWduYXR1cmUgRXhwaXJhdGlvbiBUaW1lXG5cdFx0XHR2YXIgdGltZSA9IHV0aWwucmVhZERhdGUoYnl0ZXMuc3Vic3RyKG15cG9zKSk7XG5cblx0XHRcdHRoaXMuc2lnbmF0dXJlTmV2ZXJFeHBpcmVzID0gdGltZS5nZXRUaW1lKCkgPT0gMDtcblx0XHRcdHRoaXMuc2lnbmF0dXJlRXhwaXJhdGlvblRpbWUgPSB0aW1lO1xuXHRcdFx0XG5cdFx0XHRicmVhaztcblx0XHRjYXNlIDQ6IC8vIEV4cG9ydGFibGUgQ2VydGlmaWNhdGlvblxuXHRcdFx0dGhpcy5leHBvcnRhYmxlID0gYnl0ZXNbbXlwb3MrK10uY2hhckNvZGVBdCgpID09IDE7XG5cdFx0XHRicmVhaztcblx0XHRjYXNlIDU6IC8vIFRydXN0IFNpZ25hdHVyZVxuXHRcdFx0dGhpcy50cnVzdExldmVsID0gYnl0ZXNbbXlwb3MrK10uY2hhckNvZGVBdCgpO1xuXHRcdFx0dGhpcy50cnVzdEFtb3VudCA9IGJ5dGVzW215cG9zKytdLmNoYXJDb2RlQXQoKTtcblx0XHRcdGJyZWFrO1xuXHRcdGNhc2UgNjogLy8gUmVndWxhciBFeHByZXNzaW9uXG5cdFx0XHR0aGlzLnJlZ3VsYXJFeHByZXNzaW9uID0gYnl0ZXMuc3Vic3RyKG15cG9zKTtcblx0XHRcdGJyZWFrO1xuXHRcdGNhc2UgNzogLy8gUmV2b2NhYmxlXG5cdFx0XHR0aGlzLnJldm9jYWJsZSA9IGJ5dGVzW215cG9zKytdLmNoYXJDb2RlQXQoKSA9PSAxO1xuXHRcdFx0YnJlYWs7XG5cdFx0Y2FzZSA5OiAvLyBLZXkgRXhwaXJhdGlvbiBUaW1lXG5cdFx0XHR2YXIgdGltZSA9IHV0aWwucmVhZERhdGUoYnl0ZXMuc3Vic3RyKG15cG9zKSk7XG5cblx0XHRcdHRoaXMua2V5RXhwaXJhdGlvblRpbWUgPSB0aW1lO1xuXHRcdFx0dGhpcy5rZXlOZXZlckV4cGlyZXMgPSB0aW1lLmdldFRpbWUoKSA9PSAwO1xuXG5cdFx0XHRicmVhaztcblx0XHRjYXNlIDExOiAvLyBQcmVmZXJyZWQgU3ltbWV0cmljIEFsZ29yaXRobXNcblx0XHRcdHRoaXMucHJlZmVycmVkU3ltbWV0cmljQWxnb3JpdGhtcyA9IFtdO1xuXG5cdFx0XHR3aGlsZShteXBvcyAhPSBieXRlcy5sZW5ndGgpIHtcblx0XHRcdFx0dGhpcy5wcmVmZXJyZWRTeW1tZXRyaWNBbGdvcml0aG1zLnB1c2goYnl0ZXNbbXlwb3MrK10uY2hhckNvZGVBdCgpKTtcblx0XHRcdH1cblxuXHRcdFx0YnJlYWs7XG5cdFx0Y2FzZSAxMjogLy8gUmV2b2NhdGlvbiBLZXlcblx0XHRcdC8vICgxIG9jdGV0IG9mIGNsYXNzLCAxIG9jdGV0IG9mIHB1YmxpYy1rZXkgYWxnb3JpdGhtIElELCAyMFxuXHRcdFx0Ly8gb2N0ZXRzIG9mXG5cdFx0XHQvLyBmaW5nZXJwcmludClcblx0XHRcdHRoaXMucmV2b2NhdGlvbktleUNsYXNzID0gYnl0ZXNbbXlwb3MrK10uY2hhckNvZGVBdCgpO1xuXHRcdFx0dGhpcy5yZXZvY2F0aW9uS2V5QWxnb3JpdGhtID0gYnl0ZXNbbXlwb3MrK10uY2hhckNvZGVBdCgpO1xuXHRcdFx0dGhpcy5yZXZvY2F0aW9uS2V5RmluZ2VycHJpbnQgPSBieXRlcy5zdWJzdHIobXlwb3MsIDIwKTtcblx0XHRcdGJyZWFrO1xuXG5cdFx0Y2FzZSAxNjogLy8gSXNzdWVyXG5cdFx0XHR0aGlzLmlzc3VlcktleUlkID0gYnl0ZXMuc3Vic3RyKG15cG9zLCA4KTtcblx0XHRcdGJyZWFrO1xuXG5cdFx0Y2FzZSAyMDogLy8gTm90YXRpb24gRGF0YVxuXHRcdFx0Ly8gV2UgZG9uJ3Qga25vdyBob3cgdG8gaGFuZGxlIGFueXRoaW5nIGJ1dCBhIHRleHQgZmxhZ2dlZCBkYXRhLlxuXHRcdFx0aWYoYnl0ZXNbbXlwb3NdLmNoYXJDb2RlQXQoKSA9PSAweDgwKSB7XG5cblx0XHRcdFx0Ly8gV2UgZXh0cmFjdCBrZXkvdmFsdWUgdHVwbGUgZnJvbSB0aGUgYnl0ZSBzdHJlYW0uXG5cdFx0XHRcdG15cG9zICs9IDQ7XG5cdFx0XHRcdHZhciBtID0gdXRpbC53cml0ZU51bWJlcihieXRlcy5zdWJzdHIobXlwb3MsIDIpKTtcblx0XHRcdFx0bXlwb3MgKz0gMlxuXHRcdFx0XHR2YXIgbiA9IHV0aWwud3JpdGVOdW1iZXIoYnl0ZXMuc3Vic3RyKG15cG9zLCAyKSk7XG5cdFx0XHRcdG15cG9zICs9IDJcblxuXHRcdFx0XHR2YXIgbmFtZSA9IGJ5dGVzLnN1YnN0cihteXBvcywgbSksXG5cdFx0XHRcdFx0dmFsdWUgPSBieXRlcy5zdWJzdHIobXlwb3MgKyBtLCBuKTtcblxuXHRcdFx0XHR0aGlzLm5vdGF0aW9uW25hbWVdID0gdmFsdWU7XG5cdFx0XHR9XG5cdFx0XHRlbHNlIHRocm93IG5ldyBFcnJvcihcIlVuc3VwcG9ydGVkIG5vdGF0aW9uIGZsYWcuXCIpO1xuXHRcdFx0YnJlYWs7XG5cdFx0Y2FzZSAyMTogLy8gUHJlZmVycmVkIEhhc2ggQWxnb3JpdGhtc1xuXHRcdFx0cmVhZF9hcnJheS5jYWxsKHRoaXMsICdwcmVmZXJyZWRIYXNoQWxnb3JpdGhtcycsIGJ5dGVzLnN1YnN0cihteXBvcykpO1xuXHRcdFx0YnJlYWs7XG5cdFx0Y2FzZSAyMjogLy8gUHJlZmVycmVkIENvbXByZXNzaW9uIEFsZ29yaXRobXNcblx0XHRcdHJlYWRfYXJyYXkuY2FsbCh0aGlzLCAncHJlZmVycmVkQ29tcHJlc3Npb25BbGdvcml0aG1zICcsIGJ5dGVzLnN1YnN0cihteXBvcykpO1xuXHRcdFx0YnJlYWs7XG5cdFx0Y2FzZSAyMzogLy8gS2V5IFNlcnZlciBQcmVmZXJlbmNlc1xuXHRcdFx0cmVhZF9hcnJheS5jYWxsKHRoaXMsICdrZXlTZXJ2ZXJQcmVmZXJlbmNlc3MnLCBieXRlcy5zdWJzdHIobXlwb3MpKTtcblx0XHRcdGJyZWFrO1xuXHRcdGNhc2UgMjQ6IC8vIFByZWZlcnJlZCBLZXkgU2VydmVyXG5cdFx0XHR0aGlzLnByZWZlcnJlZEtleVNlcnZlciA9IGJ5dGVzLnN1YnN0cihteXBvcyk7XG5cdFx0XHRicmVhaztcblx0XHRjYXNlIDI1OiAvLyBQcmltYXJ5IFVzZXIgSURcblx0XHRcdHRoaXMuaXNQcmltYXJ5VXNlcklEID0gYnl0ZXNbbXlwb3MrK10gIT0gMDtcblx0XHRcdGJyZWFrO1xuXHRcdGNhc2UgMjY6IC8vIFBvbGljeSBVUklcblx0XHRcdHRoaXMucG9saWN5VVJJID0gYnl0ZXMuc3Vic3RyKG15cG9zKTtcblx0XHRcdGJyZWFrO1xuXHRcdGNhc2UgMjc6IC8vIEtleSBGbGFnc1xuXHRcdFx0cmVhZF9hcnJheS5jYWxsKHRoaXMsICdrZXlGbGFncycsIGJ5dGVzLnN1YnN0cihteXBvcykpO1xuXHRcdFx0YnJlYWs7XG5cdFx0Y2FzZSAyODogLy8gU2lnbmVyJ3MgVXNlciBJRFxuXHRcdFx0dGhpcy5zaWduZXJzVXNlcklkICs9IGJ5dGVzLnN1YnN0cihteXBvcyk7XG5cdFx0XHRicmVhaztcblx0XHRjYXNlIDI5OiAvLyBSZWFzb24gZm9yIFJldm9jYXRpb25cblx0XHRcdHRoaXMucmVhc29uRm9yUmV2b2NhdGlvbkZsYWcgPSBieXRlc1tteXBvcysrXS5jaGFyQ29kZUF0KCk7XG5cdFx0XHR0aGlzLnJlYXNvbkZvclJldm9jYXRpb25TdHJpbmcgPSBieXRlcy5zdWJzdHIobXlwb3MpO1xuXHRcdFx0YnJlYWs7XG5cdFx0Y2FzZSAzMDogLy8gRmVhdHVyZXNcblx0XHRcdHJlYWRfYXJyYXkuY2FsbCh0aGlzLCAnZmVhdHVyZXMnLCBieXRlcy5zdWJzdHIobXlwb3MpKTtcblx0XHRcdGJyZWFrO1xuXHRcdGNhc2UgMzE6IC8vIFNpZ25hdHVyZSBUYXJnZXRcblx0XHRcdC8vICgxIG9jdGV0IHB1YmxpYy1rZXkgYWxnb3JpdGhtLCAxIG9jdGV0IGhhc2ggYWxnb3JpdGhtLCBOIG9jdGV0cyBoYXNoKVxuXHRcdFx0dGhpcy5zaWduYXR1cmVUYXJnZXRQdWJsaWNLZXlBbGdvcml0aG0gPSBieXRlc1tteXBvcysrXS5jaGFyQ29kZUF0KCk7XG5cdFx0XHR0aGlzLnNpZ25hdHVyZVRhcmdldEhhc2hBbGdvcml0aG0gPSBieXRlc1tteXBvcysrXS5jaGFyQ29kZUF0KCk7XG5cblx0XHRcdHZhciBsZW4gPSBjcnlwdG8uZ2V0SGFzaEJ5dGVMZW5ndGgodGhpcy5zaWduYXR1cmVUYXJnZXRIYXNoQWxnb3JpdGhtKTtcblxuXHRcdFx0dGhpcy5zaWduYXR1cmVUYXJnZXRIYXNoID0gYnl0ZXMuc3Vic3RyKG15cG9zLCBsZW4pO1xuXHRcdFx0YnJlYWs7XG5cdFx0Y2FzZSAzMjogLy8gRW1iZWRkZWQgU2lnbmF0dXJlXG5cdFx0XHR0aGlzLmVtYmVkZGVkU2lnbmF0dXJlID0gbmV3IHBhY2tldF9zaWduYXR1cmUoKTtcblx0XHRcdHRoaXMuZW1iZWRkZWRTaWduYXR1cmUucmVhZChieXRlcy5zdWJzdHIobXlwb3MpKTtcblx0XHRcdGJyZWFrO1xuXHRcdGRlZmF1bHQ6XG5cdFx0XHR1dGlsLnByaW50X2Vycm9yKFwib3BlbnBncC5wYWNrZXQuc2lnbmF0dXJlLmpzXFxuXCIrXG5cdFx0XHRcdCd1bmtub3duIHNpZ25hdHVyZSBzdWJwYWNrZXQgdHlwZSAnK3R5cGUrXCIgQDpcIitteXBvcytcblx0XHRcdFx0XCIgc3VicGxlbjpcIitzdWJwbGVuK1wiIGxlbjpcIitsZW4pO1xuXHRcdFx0YnJlYWs7XG5cdFx0fVxuXHR9O1xuXG5cdC8vIFByb2R1Y2VzIGRhdGEgdG8gcHJvZHVjZSBzaWduYXR1cmUgb25cblx0dGhpcy50b1NpZ24gPSBmdW5jdGlvbih0eXBlLCBkYXRhKSB7XG5cdFx0dmFyIHQgPSBlbnVtcy5zaWduYXR1cmVcblxuXHRcdHN3aXRjaCh0eXBlKSB7XG5cdFx0Y2FzZSB0LmJpbmFyeTpcblx0XHRcdHJldHVybiBkYXRhLmxpdGVyYWwuZ2V0Qnl0ZXMoKTtcblxuXHRcdGNhc2UgdC50ZXh0OlxuXHRcdFx0cmV0dXJuIHRoaXMudG9TaWduKHQuYmluYXJ5LCBkYXRhKVxuXHRcdFx0XHQucmVwbGFjZSgvXFxyXFxuL2csICdcXG4nKVxuXHRcdFx0XHQucmVwbGFjZSgvXFxuL2csICdcXHJcXG4nKTtcblx0XHRcdFx0XG5cdFx0Y2FzZSB0LnN0YW5kYWxvbmU6XG5cdFx0XHRyZXR1cm4gJydcblxuXHRcdGNhc2UgdC5jZXJ0X2dlbmVyaWM6XG5cdFx0Y2FzZSB0LmNlcnRfcGVyc29uYTpcblx0XHRjYXNlIHQuY2VydF9jYXN1YWw6XG5cdFx0Y2FzZSB0LmNlcnRfcG9zaXRpdmU6XG5cdFx0Y2FzZSB0LmNlcnRfcmV2b2NhdGlvbjpcblx0XHR7XG5cdFx0XHR2YXIgcGFja2V0LCB0YWc7XG5cblx0XHRcdGlmKGRhdGEudXNlcmlkICE9IHVuZGVmaW5lZCkge1xuXHRcdFx0XHR0YWcgPSAweEI0O1xuXHRcdFx0XHRwYWNrZXQgPSBkYXRhLnVzZXJpZDtcblx0XHRcdH1cblx0XHRcdGVsc2UgaWYoZGF0YS51c2VyYXR0cmlidXRlICE9IHVuZGVmaW5lZCkge1xuXHRcdFx0XHR0YWcgPSAweEQxXG5cdFx0XHRcdHBhY2tldCA9IGRhdGEudXNlcmF0dHJpYnV0ZTtcblx0XHRcdH1cblx0XHRcdGVsc2UgdGhyb3cgbmV3IEVycm9yKCdFaXRoZXIgYSB1c2VyaWQgb3IgdXNlcmF0dHJpYnV0ZSBwYWNrZXQgbmVlZHMgdG8gYmUgJyArXG5cdFx0XHRcdCdzdXBwbGllZCBmb3IgY2VydGlmaWNhdGlvbi4nKTtcblxuXG5cdFx0XHR2YXIgYnl0ZXMgPSBwYWNrZXQud3JpdGUoKTtcblxuXHRcdFx0XG5cdFx0XHRyZXR1cm4gdGhpcy50b1NpZ24odC5rZXksIGRhdGEpICtcblx0XHRcdFx0U3RyaW5nLmZyb21DaGFyQ29kZSh0YWcpICtcblx0XHRcdFx0dXRpbC53cml0ZU51bWJlcihieXRlcy5sZW5ndGgsIDQpICtcblx0XHRcdFx0Ynl0ZXM7XG5cdFx0fVxuXHRcdGNhc2UgdC5zdWJrZXlfYmluZGluZzpcblx0XHRjYXNlIHQua2V5X2JpbmRpbmc6XG5cdFx0e1xuXHRcdFx0cmV0dXJuIHRoaXMudG9TaWduKHQua2V5LCBkYXRhKSArIHRoaXMudG9TaWduKHQua2V5LCB7IGtleTogZGF0YS5iaW5kIH0pO1xuXHRcdH1cblx0XHRjYXNlIHQua2V5OlxuXHRcdHtcblx0XHRcdGlmKGRhdGEua2V5ID09IHVuZGVmaW5lZClcblx0XHRcdFx0dGhyb3cgbmV3IEVycm9yKCdLZXkgcGFja2V0IGlzIHJlcXVpcmVkIGZvciB0aGlzIHNpZ3RhdHVyZS4nKTtcblx0XHRcdFxuXHRcdFx0cmV0dXJuIGRhdGEua2V5LndyaXRlT2xkKCk7XG5cdFx0fVxuXHRcdGNhc2UgdC5rZXlfcmV2b2NhdGlvbjpcblx0XHRjYXNlIHQuc3Via2V5X3Jldm9jYXRpb246XG5cdFx0XHRyZXR1cm4gdGhpcy50b1NpZ24odC5rZXksIGRhdGEpO1xuXHRcdGNhc2UgdC50aW1lc3RhbXA6XG5cdFx0XHRyZXR1cm4gJyc7XG5cdFx0Y2FzZSB0LnRocmlkX3BhcnR5OlxuXHRcdFx0dGhyb3cgbmV3IEVycm9yKCdOb3QgaW1wbGVtZW50ZWQnKTtcblx0XHRcdGJyZWFrO1xuXHRcdGRlZmF1bHQ6XG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoJ1Vua25vd24gc2lnbmF0dXJlIHR5cGUuJylcblx0XHR9XG5cdH1cblxuXHRcblx0dGhpcy5jYWxjdWxhdGVUcmFpbGVyID0gZnVuY3Rpb24oKSB7XG5cdFx0Ly8gY2FsY3VsYXRpbmcgdGhlIHRyYWlsZXJcblx0XHR2YXIgdHJhaWxlciA9ICcnO1xuXHRcdHRyYWlsZXIgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSg0KTsgLy8gVmVyc2lvblxuXHRcdHRyYWlsZXIgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSgweEZGKTtcblx0XHR0cmFpbGVyICs9IHV0aWwud3JpdGVOdW1iZXIodGhpcy5zaWduYXR1cmVEYXRhLmxlbmd0aCwgNCk7XG5cdFx0cmV0dXJuIHRyYWlsZXJcblx0fVxuXG5cblx0LyoqXG5cdCAqIHZlcmlmeXMgdGhlIHNpZ25hdHVyZSBwYWNrZXQuIE5vdGU6IG5vdCBzaWduYXR1cmUgdHlwZXMgYXJlIGltcGxlbWVudGVkXG5cdCAqIEBwYXJhbSB7U3RyaW5nfSBkYXRhIGRhdGEgd2hpY2ggb24gdGhlIHNpZ25hdHVyZSBhcHBsaWVzXG5cdCAqIEBwYXJhbSB7b3BlbnBncF9tc2dfcHJpdmF0ZWtleX0ga2V5IHRoZSBwdWJsaWMga2V5IHRvIHZlcmlmeSB0aGUgc2lnbmF0dXJlXG5cdCAqIEByZXR1cm4ge2Jvb2xlYW59IFRydWUgaWYgbWVzc2FnZSBpcyB2ZXJpZmllZCwgZWxzZSBmYWxzZS5cblx0ICovXG5cdHRoaXMudmVyaWZ5ID0gZnVuY3Rpb24oa2V5LCBkYXRhKSB7XG5cdFx0dmFyIHNpZ25hdHVyZVR5cGUgPSBlbnVtcy53cml0ZShlbnVtcy5zaWduYXR1cmUsIHRoaXMuc2lnbmF0dXJlVHlwZSksXG5cdFx0XHRwdWJsaWNLZXlBbGdvcml0aG0gPSBlbnVtcy53cml0ZShlbnVtcy5wdWJsaWNLZXksIHRoaXMucHVibGljS2V5QWxnb3JpdGhtKSxcblx0XHRcdGhhc2hBbGdvcml0aG0gPSBlbnVtcy53cml0ZShlbnVtcy5oYXNoLCB0aGlzLmhhc2hBbGdvcml0aG0pO1xuXG5cdFx0dmFyIGJ5dGVzID0gdGhpcy50b1NpZ24oc2lnbmF0dXJlVHlwZSwgZGF0YSksXG5cdFx0XHR0cmFpbGVyID0gdGhpcy5jYWxjdWxhdGVUcmFpbGVyKCk7XG5cblxuXHRcdHZhciBtcGljb3VudCA9IDA7XG5cdFx0Ly8gQWxnb3JpdGhtLVNwZWNpZmljIEZpZWxkcyBmb3IgUlNBIHNpZ25hdHVyZXM6XG5cdFx0Ly8gXHQgICAgLSBtdWx0aXByZWNpc2lvbiBudW1iZXIgKE1QSSkgb2YgUlNBIHNpZ25hdHVyZSB2YWx1ZSBtKipkIG1vZCBuLlxuXHRcdGlmIChwdWJsaWNLZXlBbGdvcml0aG0gPiAwICYmIHB1YmxpY0tleUFsZ29yaXRobSA8IDQpXG5cdFx0XHRtcGljb3VudCA9IDE7XG5cdFx0Ly8gICAgQWxnb3JpdGhtLVNwZWNpZmljIEZpZWxkcyBmb3IgRFNBIHNpZ25hdHVyZXM6XG5cdFx0Ly8gICAgICAtIE1QSSBvZiBEU0EgdmFsdWUgci5cblx0XHQvLyAgICAgIC0gTVBJIG9mIERTQSB2YWx1ZSBzLlxuXHRcdGVsc2UgaWYgKHB1YmxpY0tleUFsZ29yaXRobSA9PSAxNylcblx0XHRcdG1waWNvdW50ID0gMjtcblx0XHRcblx0XHR2YXIgbXBpID0gW10sIGkgPSAwO1xuXHRcdGZvciAodmFyIGogPSAwOyBqIDwgbXBpY291bnQ7IGorKykge1xuXHRcdFx0bXBpW2pdID0gbmV3IHR5cGVfbXBpKCk7XG5cdFx0XHRpICs9IG1waVtqXS5yZWFkKHRoaXMuc2lnbmF0dXJlLnN1YnN0cihpKSk7XG5cdFx0fVxuXG5cdFx0dGhpcy52ZXJpZmllZCA9IGNyeXB0by5zaWduYXR1cmUudmVyaWZ5KHB1YmxpY0tleUFsZ29yaXRobSwgXG5cdFx0XHRoYXNoQWxnb3JpdGhtLCBtcGksIGtleS5tcGksIFxuXHRcdFx0Ynl0ZXMgKyB0aGlzLnNpZ25hdHVyZURhdGEgKyB0cmFpbGVyKTtcblxuXHRcdHJldHVybiB0aGlzLnZlcmlmaWVkO1xuXHR9XG59XG5cbiIsIlxuLyogUmlqbmRhZWwgKEFFUykgRW5jcnlwdGlvblxuICogQ29weXJpZ2h0IDIwMDUgSGVyYmVydCBIYW5ld2lua2VsLCB3d3cuaGFuZVdJTi5kZVxuICogdmVyc2lvbiAxLjEsIGNoZWNrIHd3dy5oYW5lV0lOLmRlIGZvciB0aGUgbGF0ZXN0IHZlcnNpb25cblxuICogVGhpcyBzb2Z0d2FyZSBpcyBwcm92aWRlZCBhcy1pcywgd2l0aG91dCBleHByZXNzIG9yIGltcGxpZWQgd2FycmFudHkuICBcbiAqIFBlcm1pc3Npb24gdG8gdXNlLCBjb3B5LCBtb2RpZnksIGRpc3RyaWJ1dGUgb3Igc2VsbCB0aGlzIHNvZnR3YXJlLCB3aXRoIG9yXG4gKiB3aXRob3V0IGZlZSwgZm9yIGFueSBwdXJwb3NlIGFuZCBieSBhbnkgaW5kaXZpZHVhbCBvciBvcmdhbml6YXRpb24sIGlzIGhlcmVieVxuICogZ3JhbnRlZCwgcHJvdmlkZWQgdGhhdCB0aGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcyBwYXJhZ3JhcGggYXBwZWFyIFxuICogaW4gYWxsIGNvcGllcy4gRGlzdHJpYnV0aW9uIGFzIGEgcGFydCBvZiBhbiBhcHBsaWNhdGlvbiBvciBiaW5hcnkgbXVzdFxuICogaW5jbHVkZSB0aGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBpbiB0aGUgZG9jdW1lbnRhdGlvbiBhbmQvb3Igb3RoZXJcbiAqIG1hdGVyaWFscyBwcm92aWRlZCB3aXRoIHRoZSBhcHBsaWNhdGlvbiBvciBkaXN0cmlidXRpb24uXG4gKi9cblxudmFyIHV0aWwgPSByZXF1aXJlKCcuLi8uLi91dGlsJyk7XG5cbi8vIFRoZSByb3VuZCBjb25zdGFudHMgdXNlZCBpbiBzdWJrZXkgZXhwYW5zaW9uXG52YXIgUmNvbiA9IFsgXG4weDAxLCAweDAyLCAweDA0LCAweDA4LCAweDEwLCAweDIwLCAweDQwLCAweDgwLCAweDFiLCAweDM2LCAweDZjLCAweGQ4LCBcbjB4YWIsIDB4NGQsIDB4OWEsIDB4MmYsIDB4NWUsIDB4YmMsIDB4NjMsIDB4YzYsIDB4OTcsIDB4MzUsIDB4NmEsIDB4ZDQsIFxuMHhiMywgMHg3ZCwgMHhmYSwgMHhlZiwgMHhjNSwgMHg5MSBdO1xuXG4vLyBQcmVjb21wdXRlZCBsb29rdXAgdGFibGUgZm9yIHRoZSBTQm94XG52YXIgUyA9IFtcbiA5OSwgMTI0LCAxMTksIDEyMywgMjQyLCAxMDcsIDExMSwgMTk3LCAgNDgsICAgMSwgMTAzLCAgNDMsIDI1NCwgMjE1LCAxNzEsIFxuMTE4LCAyMDIsIDEzMCwgMjAxLCAxMjUsIDI1MCwgIDg5LCAgNzEsIDI0MCwgMTczLCAyMTIsIDE2MiwgMTc1LCAxNTYsIDE2NCwgXG4xMTQsIDE5MiwgMTgzLCAyNTMsIDE0NywgIDM4LCAgNTQsICA2MywgMjQ3LCAyMDQsICA1MiwgMTY1LCAyMjksIDI0MSwgMTEzLCBcbjIxNiwgIDQ5LCAgMjEsICAgNCwgMTk5LCAgMzUsIDE5NSwgIDI0LCAxNTAsICAgNSwgMTU0LCAgIDcsICAxOCwgMTI4LCAyMjYsIFxuMjM1LCAgMzksIDE3OCwgMTE3LCAgIDksIDEzMSwgIDQ0LCAgMjYsICAyNywgMTEwLCAgOTAsIDE2MCwgIDgyLCAgNTksIDIxNCwgXG4xNzksICA0MSwgMjI3LCAgNDcsIDEzMiwgIDgzLCAyMDksICAgMCwgMjM3LCAgMzIsIDI1MiwgMTc3LCAgOTEsIDEwNiwgMjAzLCBcbjE5MCwgIDU3LCAgNzQsICA3NiwgIDg4LCAyMDcsIDIwOCwgMjM5LCAxNzAsIDI1MSwgIDY3LCAgNzcsICA1MSwgMTMzLCAgNjksIFxuMjQ5LCAgIDIsIDEyNywgIDgwLCAgNjAsIDE1OSwgMTY4LCAgODEsIDE2MywgIDY0LCAxNDMsIDE0NiwgMTU3LCAgNTYsIDI0NSwgXG4xODgsIDE4MiwgMjE4LCAgMzMsICAxNiwgMjU1LCAyNDMsIDIxMCwgMjA1LCAgMTIsICAxOSwgMjM2LCAgOTUsIDE1MSwgIDY4LCAgXG4yMywgIDE5NiwgMTY3LCAxMjYsICA2MSwgMTAwLCAgOTMsICAyNSwgMTE1LCAgOTYsIDEyOSwgIDc5LCAyMjAsICAzNCwgIDQyLCBcbjE0NCwgMTM2LCAgNzAsIDIzOCwgMTg0LCAgMjAsIDIyMiwgIDk0LCAgMTEsIDIxOSwgMjI0LCAgNTAsICA1OCwgIDEwLCAgNzMsXG4gIDYsICAzNiwgIDkyLCAxOTQsIDIxMSwgMTcyLCAgOTgsIDE0NSwgMTQ5LCAyMjgsIDEyMSwgMjMxLCAyMDAsICA1NSwgMTA5LCBcbjE0MSwgMjEzLCAgNzgsIDE2OSwgMTA4LCAgODYsIDI0NCwgMjM0LCAxMDEsIDEyMiwgMTc0LCAgIDgsIDE4NiwgMTIwLCAgMzcsICBcbiA0NiwgIDI4LCAxNjYsIDE4MCwgMTk4LCAyMzIsIDIyMSwgMTE2LCAgMzEsICA3NSwgMTg5LCAxMzksIDEzOCwgMTEyLCAgNjIsIFxuMTgxLCAxMDIsICA3MiwgICAzLCAyNDYsICAxNCwgIDk3LCAgNTMsICA4NywgMTg1LCAxMzQsIDE5MywgIDI5LCAxNTgsIDIyNSxcbjI0OCwgMTUyLCAgMTcsIDEwNSwgMjE3LCAxNDIsIDE0OCwgMTU1LCAgMzAsIDEzNSwgMjMzLCAyMDYsICA4NSwgIDQwLCAyMjMsXG4xNDAsIDE2MSwgMTM3LCAgMTMsIDE5MSwgMjMwLCAgNjYsIDEwNCwgIDY1LCAxNTMsICA0NSwgIDE1LCAxNzYsICA4NCwgMTg3LCAgXG4gMjIgXTtcblxudmFyIFQxID0gW1xuMHhhNTYzNjNjNiwgMHg4NDdjN2NmOCwgMHg5OTc3NzdlZSwgMHg4ZDdiN2JmNixcbjB4MGRmMmYyZmYsIDB4YmQ2YjZiZDYsIDB4YjE2ZjZmZGUsIDB4NTRjNWM1OTEsXG4weDUwMzAzMDYwLCAweDAzMDEwMTAyLCAweGE5Njc2N2NlLCAweDdkMmIyYjU2LFxuMHgxOWZlZmVlNywgMHg2MmQ3ZDdiNSwgMHhlNmFiYWI0ZCwgMHg5YTc2NzZlYyxcbjB4NDVjYWNhOGYsIDB4OWQ4MjgyMWYsIDB4NDBjOWM5ODksIDB4ODc3ZDdkZmEsXG4weDE1ZmFmYWVmLCAweGViNTk1OWIyLCAweGM5NDc0NzhlLCAweDBiZjBmMGZiLFxuMHhlY2FkYWQ0MSwgMHg2N2Q0ZDRiMywgMHhmZGEyYTI1ZiwgMHhlYWFmYWY0NSxcbjB4YmY5YzljMjMsIDB4ZjdhNGE0NTMsIDB4OTY3MjcyZTQsIDB4NWJjMGMwOWIsXG4weGMyYjdiNzc1LCAweDFjZmRmZGUxLCAweGFlOTM5MzNkLCAweDZhMjYyNjRjLFxuMHg1YTM2MzY2YywgMHg0MTNmM2Y3ZSwgMHgwMmY3ZjdmNSwgMHg0ZmNjY2M4MyxcbjB4NWMzNDM0NjgsIDB4ZjRhNWE1NTEsIDB4MzRlNWU1ZDEsIDB4MDhmMWYxZjksXG4weDkzNzE3MWUyLCAweDczZDhkOGFiLCAweDUzMzEzMTYyLCAweDNmMTUxNTJhLFxuMHgwYzA0MDQwOCwgMHg1MmM3Yzc5NSwgMHg2NTIzMjM0NiwgMHg1ZWMzYzM5ZCxcbjB4MjgxODE4MzAsIDB4YTE5Njk2MzcsIDB4MGYwNTA1MGEsIDB4YjU5YTlhMmYsXG4weDA5MDcwNzBlLCAweDM2MTIxMjI0LCAweDliODA4MDFiLCAweDNkZTJlMmRmLFxuMHgyNmViZWJjZCwgMHg2OTI3Mjc0ZSwgMHhjZGIyYjI3ZiwgMHg5Zjc1NzVlYSxcbjB4MWIwOTA5MTIsIDB4OWU4MzgzMWQsIDB4NzQyYzJjNTgsIDB4MmUxYTFhMzQsXG4weDJkMWIxYjM2LCAweGIyNmU2ZWRjLCAweGVlNWE1YWI0LCAweGZiYTBhMDViLFxuMHhmNjUyNTJhNCwgMHg0ZDNiM2I3NiwgMHg2MWQ2ZDZiNywgMHhjZWIzYjM3ZCxcbjB4N2IyOTI5NTIsIDB4M2VlM2UzZGQsIDB4NzEyZjJmNWUsIDB4OTc4NDg0MTMsXG4weGY1NTM1M2E2LCAweDY4ZDFkMWI5LCAweDAwMDAwMDAwLCAweDJjZWRlZGMxLFxuMHg2MDIwMjA0MCwgMHgxZmZjZmNlMywgMHhjOGIxYjE3OSwgMHhlZDViNWJiNixcbjB4YmU2YTZhZDQsIDB4NDZjYmNiOGQsIDB4ZDliZWJlNjcsIDB4NGIzOTM5NzIsXG4weGRlNGE0YTk0LCAweGQ0NGM0Yzk4LCAweGU4NTg1OGIwLCAweDRhY2ZjZjg1LFxuMHg2YmQwZDBiYiwgMHgyYWVmZWZjNSwgMHhlNWFhYWE0ZiwgMHgxNmZiZmJlZCxcbjB4YzU0MzQzODYsIDB4ZDc0ZDRkOWEsIDB4NTUzMzMzNjYsIDB4OTQ4NTg1MTEsXG4weGNmNDU0NThhLCAweDEwZjlmOWU5LCAweDA2MDIwMjA0LCAweDgxN2Y3ZmZlLFxuMHhmMDUwNTBhMCwgMHg0NDNjM2M3OCwgMHhiYTlmOWYyNSwgMHhlM2E4YTg0YixcbjB4ZjM1MTUxYTIsIDB4ZmVhM2EzNWQsIDB4YzA0MDQwODAsIDB4OGE4ZjhmMDUsXG4weGFkOTI5MjNmLCAweGJjOWQ5ZDIxLCAweDQ4MzgzODcwLCAweDA0ZjVmNWYxLFxuMHhkZmJjYmM2MywgMHhjMWI2YjY3NywgMHg3NWRhZGFhZiwgMHg2MzIxMjE0MixcbjB4MzAxMDEwMjAsIDB4MWFmZmZmZTUsIDB4MGVmM2YzZmQsIDB4NmRkMmQyYmYsXG4weDRjY2RjZDgxLCAweDE0MGMwYzE4LCAweDM1MTMxMzI2LCAweDJmZWNlY2MzLFxuMHhlMTVmNWZiZSwgMHhhMjk3OTczNSwgMHhjYzQ0NDQ4OCwgMHgzOTE3MTcyZSxcbjB4NTdjNGM0OTMsIDB4ZjJhN2E3NTUsIDB4ODI3ZTdlZmMsIDB4NDczZDNkN2EsXG4weGFjNjQ2NGM4LCAweGU3NWQ1ZGJhLCAweDJiMTkxOTMyLCAweDk1NzM3M2U2LFxuMHhhMDYwNjBjMCwgMHg5ODgxODExOSwgMHhkMTRmNGY5ZSwgMHg3ZmRjZGNhMyxcbjB4NjYyMjIyNDQsIDB4N2UyYTJhNTQsIDB4YWI5MDkwM2IsIDB4ODM4ODg4MGIsXG4weGNhNDY0NjhjLCAweDI5ZWVlZWM3LCAweGQzYjhiODZiLCAweDNjMTQxNDI4LFxuMHg3OWRlZGVhNywgMHhlMjVlNWViYywgMHgxZDBiMGIxNiwgMHg3NmRiZGJhZCxcbjB4M2JlMGUwZGIsIDB4NTYzMjMyNjQsIDB4NGUzYTNhNzQsIDB4MWUwYTBhMTQsXG4weGRiNDk0OTkyLCAweDBhMDYwNjBjLCAweDZjMjQyNDQ4LCAweGU0NWM1Y2I4LFxuMHg1ZGMyYzI5ZiwgMHg2ZWQzZDNiZCwgMHhlZmFjYWM0MywgMHhhNjYyNjJjNCxcbjB4YTg5MTkxMzksIDB4YTQ5NTk1MzEsIDB4MzdlNGU0ZDMsIDB4OGI3OTc5ZjIsXG4weDMyZTdlN2Q1LCAweDQzYzhjODhiLCAweDU5MzczNzZlLCAweGI3NmQ2ZGRhLFxuMHg4YzhkOGQwMSwgMHg2NGQ1ZDViMSwgMHhkMjRlNGU5YywgMHhlMGE5YTk0OSxcbjB4YjQ2YzZjZDgsIDB4ZmE1NjU2YWMsIDB4MDdmNGY0ZjMsIDB4MjVlYWVhY2YsXG4weGFmNjU2NWNhLCAweDhlN2E3YWY0LCAweGU5YWVhZTQ3LCAweDE4MDgwODEwLFxuMHhkNWJhYmE2ZiwgMHg4ODc4NzhmMCwgMHg2ZjI1MjU0YSwgMHg3MjJlMmU1YyxcbjB4MjQxYzFjMzgsIDB4ZjFhNmE2NTcsIDB4YzdiNGI0NzMsIDB4NTFjNmM2OTcsXG4weDIzZThlOGNiLCAweDdjZGRkZGExLCAweDljNzQ3NGU4LCAweDIxMWYxZjNlLFxuMHhkZDRiNGI5NiwgMHhkY2JkYmQ2MSwgMHg4NjhiOGIwZCwgMHg4NThhOGEwZixcbjB4OTA3MDcwZTAsIDB4NDIzZTNlN2MsIDB4YzRiNWI1NzEsIDB4YWE2NjY2Y2MsXG4weGQ4NDg0ODkwLCAweDA1MDMwMzA2LCAweDAxZjZmNmY3LCAweDEyMGUwZTFjLFxuMHhhMzYxNjFjMiwgMHg1ZjM1MzU2YSwgMHhmOTU3NTdhZSwgMHhkMGI5Yjk2OSxcbjB4OTE4Njg2MTcsIDB4NThjMWMxOTksIDB4MjcxZDFkM2EsIDB4Yjk5ZTllMjcsXG4weDM4ZTFlMWQ5LCAweDEzZjhmOGViLCAweGIzOTg5ODJiLCAweDMzMTExMTIyLFxuMHhiYjY5NjlkMiwgMHg3MGQ5ZDlhOSwgMHg4OThlOGUwNywgMHhhNzk0OTQzMyxcbjB4YjY5YjliMmQsIDB4MjIxZTFlM2MsIDB4OTI4Nzg3MTUsIDB4MjBlOWU5YzksXG4weDQ5Y2VjZTg3LCAweGZmNTU1NWFhLCAweDc4MjgyODUwLCAweDdhZGZkZmE1LFxuMHg4ZjhjOGMwMywgMHhmOGExYTE1OSwgMHg4MDg5ODkwOSwgMHgxNzBkMGQxYSxcbjB4ZGFiZmJmNjUsIDB4MzFlNmU2ZDcsIDB4YzY0MjQyODQsIDB4Yjg2ODY4ZDAsXG4weGMzNDE0MTgyLCAweGIwOTk5OTI5LCAweDc3MmQyZDVhLCAweDExMGYwZjFlLFxuMHhjYmIwYjA3YiwgMHhmYzU0NTRhOCwgMHhkNmJiYmI2ZCwgMHgzYTE2MTYyYyBdO1xuXG52YXIgVDIgPSBbXG4weDYzNjNjNmE1LCAweDdjN2NmODg0LCAweDc3NzdlZTk5LCAweDdiN2JmNjhkLFxuMHhmMmYyZmYwZCwgMHg2YjZiZDZiZCwgMHg2ZjZmZGViMSwgMHhjNWM1OTE1NCxcbjB4MzAzMDYwNTAsIDB4MDEwMTAyMDMsIDB4Njc2N2NlYTksIDB4MmIyYjU2N2QsXG4weGZlZmVlNzE5LCAweGQ3ZDdiNTYyLCAweGFiYWI0ZGU2LCAweDc2NzZlYzlhLFxuMHhjYWNhOGY0NSwgMHg4MjgyMWY5ZCwgMHhjOWM5ODk0MCwgMHg3ZDdkZmE4NyxcbjB4ZmFmYWVmMTUsIDB4NTk1OWIyZWIsIDB4NDc0NzhlYzksIDB4ZjBmMGZiMGIsXG4weGFkYWQ0MWVjLCAweGQ0ZDRiMzY3LCAweGEyYTI1ZmZkLCAweGFmYWY0NWVhLFxuMHg5YzljMjNiZiwgMHhhNGE0NTNmNywgMHg3MjcyZTQ5NiwgMHhjMGMwOWI1YixcbjB4YjdiNzc1YzIsIDB4ZmRmZGUxMWMsIDB4OTM5MzNkYWUsIDB4MjYyNjRjNmEsXG4weDM2MzY2YzVhLCAweDNmM2Y3ZTQxLCAweGY3ZjdmNTAyLCAweGNjY2M4MzRmLFxuMHgzNDM0Njg1YywgMHhhNWE1NTFmNCwgMHhlNWU1ZDEzNCwgMHhmMWYxZjkwOCxcbjB4NzE3MWUyOTMsIDB4ZDhkOGFiNzMsIDB4MzEzMTYyNTMsIDB4MTUxNTJhM2YsXG4weDA0MDQwODBjLCAweGM3Yzc5NTUyLCAweDIzMjM0NjY1LCAweGMzYzM5ZDVlLFxuMHgxODE4MzAyOCwgMHg5Njk2MzdhMSwgMHgwNTA1MGEwZiwgMHg5YTlhMmZiNSxcbjB4MDcwNzBlMDksIDB4MTIxMjI0MzYsIDB4ODA4MDFiOWIsIDB4ZTJlMmRmM2QsXG4weGViZWJjZDI2LCAweDI3Mjc0ZTY5LCAweGIyYjI3ZmNkLCAweDc1NzVlYTlmLFxuMHgwOTA5MTIxYiwgMHg4MzgzMWQ5ZSwgMHgyYzJjNTg3NCwgMHgxYTFhMzQyZSxcbjB4MWIxYjM2MmQsIDB4NmU2ZWRjYjIsIDB4NWE1YWI0ZWUsIDB4YTBhMDViZmIsXG4weDUyNTJhNGY2LCAweDNiM2I3NjRkLCAweGQ2ZDZiNzYxLCAweGIzYjM3ZGNlLFxuMHgyOTI5NTI3YiwgMHhlM2UzZGQzZSwgMHgyZjJmNWU3MSwgMHg4NDg0MTM5NyxcbjB4NTM1M2E2ZjUsIDB4ZDFkMWI5NjgsIDB4MDAwMDAwMDAsIDB4ZWRlZGMxMmMsXG4weDIwMjA0MDYwLCAweGZjZmNlMzFmLCAweGIxYjE3OWM4LCAweDViNWJiNmVkLFxuMHg2YTZhZDRiZSwgMHhjYmNiOGQ0NiwgMHhiZWJlNjdkOSwgMHgzOTM5NzI0YixcbjB4NGE0YTk0ZGUsIDB4NGM0Yzk4ZDQsIDB4NTg1OGIwZTgsIDB4Y2ZjZjg1NGEsXG4weGQwZDBiYjZiLCAweGVmZWZjNTJhLCAweGFhYWE0ZmU1LCAweGZiZmJlZDE2LFxuMHg0MzQzODZjNSwgMHg0ZDRkOWFkNywgMHgzMzMzNjY1NSwgMHg4NTg1MTE5NCxcbjB4NDU0NThhY2YsIDB4ZjlmOWU5MTAsIDB4MDIwMjA0MDYsIDB4N2Y3ZmZlODEsXG4weDUwNTBhMGYwLCAweDNjM2M3ODQ0LCAweDlmOWYyNWJhLCAweGE4YTg0YmUzLFxuMHg1MTUxYTJmMywgMHhhM2EzNWRmZSwgMHg0MDQwODBjMCwgMHg4ZjhmMDU4YSxcbjB4OTI5MjNmYWQsIDB4OWQ5ZDIxYmMsIDB4MzgzODcwNDgsIDB4ZjVmNWYxMDQsXG4weGJjYmM2M2RmLCAweGI2YjY3N2MxLCAweGRhZGFhZjc1LCAweDIxMjE0MjYzLFxuMHgxMDEwMjAzMCwgMHhmZmZmZTUxYSwgMHhmM2YzZmQwZSwgMHhkMmQyYmY2ZCxcbjB4Y2RjZDgxNGMsIDB4MGMwYzE4MTQsIDB4MTMxMzI2MzUsIDB4ZWNlY2MzMmYsXG4weDVmNWZiZWUxLCAweDk3OTczNWEyLCAweDQ0NDQ4OGNjLCAweDE3MTcyZTM5LFxuMHhjNGM0OTM1NywgMHhhN2E3NTVmMiwgMHg3ZTdlZmM4MiwgMHgzZDNkN2E0NyxcbjB4NjQ2NGM4YWMsIDB4NWQ1ZGJhZTcsIDB4MTkxOTMyMmIsIDB4NzM3M2U2OTUsXG4weDYwNjBjMGEwLCAweDgxODExOTk4LCAweDRmNGY5ZWQxLCAweGRjZGNhMzdmLFxuMHgyMjIyNDQ2NiwgMHgyYTJhNTQ3ZSwgMHg5MDkwM2JhYiwgMHg4ODg4MGI4MyxcbjB4NDY0NjhjY2EsIDB4ZWVlZWM3MjksIDB4YjhiODZiZDMsIDB4MTQxNDI4M2MsXG4weGRlZGVhNzc5LCAweDVlNWViY2UyLCAweDBiMGIxNjFkLCAweGRiZGJhZDc2LFxuMHhlMGUwZGIzYiwgMHgzMjMyNjQ1NiwgMHgzYTNhNzQ0ZSwgMHgwYTBhMTQxZSxcbjB4NDk0OTkyZGIsIDB4MDYwNjBjMGEsIDB4MjQyNDQ4NmMsIDB4NWM1Y2I4ZTQsXG4weGMyYzI5ZjVkLCAweGQzZDNiZDZlLCAweGFjYWM0M2VmLCAweDYyNjJjNGE2LFxuMHg5MTkxMzlhOCwgMHg5NTk1MzFhNCwgMHhlNGU0ZDMzNywgMHg3OTc5ZjI4YixcbjB4ZTdlN2Q1MzIsIDB4YzhjODhiNDMsIDB4MzczNzZlNTksIDB4NmQ2ZGRhYjcsXG4weDhkOGQwMThjLCAweGQ1ZDViMTY0LCAweDRlNGU5Y2QyLCAweGE5YTk0OWUwLFxuMHg2YzZjZDhiNCwgMHg1NjU2YWNmYSwgMHhmNGY0ZjMwNywgMHhlYWVhY2YyNSxcbjB4NjU2NWNhYWYsIDB4N2E3YWY0OGUsIDB4YWVhZTQ3ZTksIDB4MDgwODEwMTgsXG4weGJhYmE2ZmQ1LCAweDc4NzhmMDg4LCAweDI1MjU0YTZmLCAweDJlMmU1YzcyLFxuMHgxYzFjMzgyNCwgMHhhNmE2NTdmMSwgMHhiNGI0NzNjNywgMHhjNmM2OTc1MSxcbjB4ZThlOGNiMjMsIDB4ZGRkZGExN2MsIDB4NzQ3NGU4OWMsIDB4MWYxZjNlMjEsXG4weDRiNGI5NmRkLCAweGJkYmQ2MWRjLCAweDhiOGIwZDg2LCAweDhhOGEwZjg1LFxuMHg3MDcwZTA5MCwgMHgzZTNlN2M0MiwgMHhiNWI1NzFjNCwgMHg2NjY2Y2NhYSxcbjB4NDg0ODkwZDgsIDB4MDMwMzA2MDUsIDB4ZjZmNmY3MDEsIDB4MGUwZTFjMTIsXG4weDYxNjFjMmEzLCAweDM1MzU2YTVmLCAweDU3NTdhZWY5LCAweGI5Yjk2OWQwLFxuMHg4Njg2MTc5MSwgMHhjMWMxOTk1OCwgMHgxZDFkM2EyNywgMHg5ZTllMjdiOSxcbjB4ZTFlMWQ5MzgsIDB4ZjhmOGViMTMsIDB4OTg5ODJiYjMsIDB4MTExMTIyMzMsXG4weDY5NjlkMmJiLCAweGQ5ZDlhOTcwLCAweDhlOGUwNzg5LCAweDk0OTQzM2E3LFxuMHg5YjliMmRiNiwgMHgxZTFlM2MyMiwgMHg4Nzg3MTU5MiwgMHhlOWU5YzkyMCxcbjB4Y2VjZTg3NDksIDB4NTU1NWFhZmYsIDB4MjgyODUwNzgsIDB4ZGZkZmE1N2EsXG4weDhjOGMwMzhmLCAweGExYTE1OWY4LCAweDg5ODkwOTgwLCAweDBkMGQxYTE3LFxuMHhiZmJmNjVkYSwgMHhlNmU2ZDczMSwgMHg0MjQyODRjNiwgMHg2ODY4ZDBiOCxcbjB4NDE0MTgyYzMsIDB4OTk5OTI5YjAsIDB4MmQyZDVhNzcsIDB4MGYwZjFlMTEsXG4weGIwYjA3YmNiLCAweDU0NTRhOGZjLCAweGJiYmI2ZGQ2LCAweDE2MTYyYzNhIF07XG5cbnZhciBUMyA9IFtcbjB4NjNjNmE1NjMsIDB4N2NmODg0N2MsIDB4NzdlZTk5NzcsIDB4N2JmNjhkN2IsXG4weGYyZmYwZGYyLCAweDZiZDZiZDZiLCAweDZmZGViMTZmLCAweGM1OTE1NGM1LFxuMHgzMDYwNTAzMCwgMHgwMTAyMDMwMSwgMHg2N2NlYTk2NywgMHgyYjU2N2QyYixcbjB4ZmVlNzE5ZmUsIDB4ZDdiNTYyZDcsIDB4YWI0ZGU2YWIsIDB4NzZlYzlhNzYsXG4weGNhOGY0NWNhLCAweDgyMWY5ZDgyLCAweGM5ODk0MGM5LCAweDdkZmE4NzdkLFxuMHhmYWVmMTVmYSwgMHg1OWIyZWI1OSwgMHg0NzhlYzk0NywgMHhmMGZiMGJmMCxcbjB4YWQ0MWVjYWQsIDB4ZDRiMzY3ZDQsIDB4YTI1ZmZkYTIsIDB4YWY0NWVhYWYsXG4weDljMjNiZjljLCAweGE0NTNmN2E0LCAweDcyZTQ5NjcyLCAweGMwOWI1YmMwLFxuMHhiNzc1YzJiNywgMHhmZGUxMWNmZCwgMHg5MzNkYWU5MywgMHgyNjRjNmEyNixcbjB4MzY2YzVhMzYsIDB4M2Y3ZTQxM2YsIDB4ZjdmNTAyZjcsIDB4Y2M4MzRmY2MsXG4weDM0Njg1YzM0LCAweGE1NTFmNGE1LCAweGU1ZDEzNGU1LCAweGYxZjkwOGYxLFxuMHg3MWUyOTM3MSwgMHhkOGFiNzNkOCwgMHgzMTYyNTMzMSwgMHgxNTJhM2YxNSxcbjB4MDQwODBjMDQsIDB4Yzc5NTUyYzcsIDB4MjM0NjY1MjMsIDB4YzM5ZDVlYzMsXG4weDE4MzAyODE4LCAweDk2MzdhMTk2LCAweDA1MGEwZjA1LCAweDlhMmZiNTlhLFxuMHgwNzBlMDkwNywgMHgxMjI0MzYxMiwgMHg4MDFiOWI4MCwgMHhlMmRmM2RlMixcbjB4ZWJjZDI2ZWIsIDB4Mjc0ZTY5MjcsIDB4YjI3ZmNkYjIsIDB4NzVlYTlmNzUsXG4weDA5MTIxYjA5LCAweDgzMWQ5ZTgzLCAweDJjNTg3NDJjLCAweDFhMzQyZTFhLFxuMHgxYjM2MmQxYiwgMHg2ZWRjYjI2ZSwgMHg1YWI0ZWU1YSwgMHhhMDViZmJhMCxcbjB4NTJhNGY2NTIsIDB4M2I3NjRkM2IsIDB4ZDZiNzYxZDYsIDB4YjM3ZGNlYjMsXG4weDI5NTI3YjI5LCAweGUzZGQzZWUzLCAweDJmNWU3MTJmLCAweDg0MTM5Nzg0LFxuMHg1M2E2ZjU1MywgMHhkMWI5NjhkMSwgMHgwMDAwMDAwMCwgMHhlZGMxMmNlZCxcbjB4MjA0MDYwMjAsIDB4ZmNlMzFmZmMsIDB4YjE3OWM4YjEsIDB4NWJiNmVkNWIsXG4weDZhZDRiZTZhLCAweGNiOGQ0NmNiLCAweGJlNjdkOWJlLCAweDM5NzI0YjM5LFxuMHg0YTk0ZGU0YSwgMHg0Yzk4ZDQ0YywgMHg1OGIwZTg1OCwgMHhjZjg1NGFjZixcbjB4ZDBiYjZiZDAsIDB4ZWZjNTJhZWYsIDB4YWE0ZmU1YWEsIDB4ZmJlZDE2ZmIsXG4weDQzODZjNTQzLCAweDRkOWFkNzRkLCAweDMzNjY1NTMzLCAweDg1MTE5NDg1LFxuMHg0NThhY2Y0NSwgMHhmOWU5MTBmOSwgMHgwMjA0MDYwMiwgMHg3ZmZlODE3ZixcbjB4NTBhMGYwNTAsIDB4M2M3ODQ0M2MsIDB4OWYyNWJhOWYsIDB4YTg0YmUzYTgsXG4weDUxYTJmMzUxLCAweGEzNWRmZWEzLCAweDQwODBjMDQwLCAweDhmMDU4YThmLFxuMHg5MjNmYWQ5MiwgMHg5ZDIxYmM5ZCwgMHgzODcwNDgzOCwgMHhmNWYxMDRmNSxcbjB4YmM2M2RmYmMsIDB4YjY3N2MxYjYsIDB4ZGFhZjc1ZGEsIDB4MjE0MjYzMjEsXG4weDEwMjAzMDEwLCAweGZmZTUxYWZmLCAweGYzZmQwZWYzLCAweGQyYmY2ZGQyLFxuMHhjZDgxNGNjZCwgMHgwYzE4MTQwYywgMHgxMzI2MzUxMywgMHhlY2MzMmZlYyxcbjB4NWZiZWUxNWYsIDB4OTczNWEyOTcsIDB4NDQ4OGNjNDQsIDB4MTcyZTM5MTcsXG4weGM0OTM1N2M0LCAweGE3NTVmMmE3LCAweDdlZmM4MjdlLCAweDNkN2E0NzNkLFxuMHg2NGM4YWM2NCwgMHg1ZGJhZTc1ZCwgMHgxOTMyMmIxOSwgMHg3M2U2OTU3MyxcbjB4NjBjMGEwNjAsIDB4ODExOTk4ODEsIDB4NGY5ZWQxNGYsIDB4ZGNhMzdmZGMsXG4weDIyNDQ2NjIyLCAweDJhNTQ3ZTJhLCAweDkwM2JhYjkwLCAweDg4MGI4Mzg4LFxuMHg0NjhjY2E0NiwgMHhlZWM3MjllZSwgMHhiODZiZDNiOCwgMHgxNDI4M2MxNCxcbjB4ZGVhNzc5ZGUsIDB4NWViY2UyNWUsIDB4MGIxNjFkMGIsIDB4ZGJhZDc2ZGIsXG4weGUwZGIzYmUwLCAweDMyNjQ1NjMyLCAweDNhNzQ0ZTNhLCAweDBhMTQxZTBhLFxuMHg0OTkyZGI0OSwgMHgwNjBjMGEwNiwgMHgyNDQ4NmMyNCwgMHg1Y2I4ZTQ1YyxcbjB4YzI5ZjVkYzIsIDB4ZDNiZDZlZDMsIDB4YWM0M2VmYWMsIDB4NjJjNGE2NjIsXG4weDkxMzlhODkxLCAweDk1MzFhNDk1LCAweGU0ZDMzN2U0LCAweDc5ZjI4Yjc5LFxuMHhlN2Q1MzJlNywgMHhjODhiNDNjOCwgMHgzNzZlNTkzNywgMHg2ZGRhYjc2ZCxcbjB4OGQwMThjOGQsIDB4ZDViMTY0ZDUsIDB4NGU5Y2QyNGUsIDB4YTk0OWUwYTksXG4weDZjZDhiNDZjLCAweDU2YWNmYTU2LCAweGY0ZjMwN2Y0LCAweGVhY2YyNWVhLFxuMHg2NWNhYWY2NSwgMHg3YWY0OGU3YSwgMHhhZTQ3ZTlhZSwgMHgwODEwMTgwOCxcbjB4YmE2ZmQ1YmEsIDB4NzhmMDg4NzgsIDB4MjU0YTZmMjUsIDB4MmU1YzcyMmUsXG4weDFjMzgyNDFjLCAweGE2NTdmMWE2LCAweGI0NzNjN2I0LCAweGM2OTc1MWM2LFxuMHhlOGNiMjNlOCwgMHhkZGExN2NkZCwgMHg3NGU4OWM3NCwgMHgxZjNlMjExZixcbjB4NGI5NmRkNGIsIDB4YmQ2MWRjYmQsIDB4OGIwZDg2OGIsIDB4OGEwZjg1OGEsXG4weDcwZTA5MDcwLCAweDNlN2M0MjNlLCAweGI1NzFjNGI1LCAweDY2Y2NhYTY2LFxuMHg0ODkwZDg0OCwgMHgwMzA2MDUwMywgMHhmNmY3MDFmNiwgMHgwZTFjMTIwZSxcbjB4NjFjMmEzNjEsIDB4MzU2YTVmMzUsIDB4NTdhZWY5NTcsIDB4Yjk2OWQwYjksXG4weDg2MTc5MTg2LCAweGMxOTk1OGMxLCAweDFkM2EyNzFkLCAweDllMjdiOTllLFxuMHhlMWQ5MzhlMSwgMHhmOGViMTNmOCwgMHg5ODJiYjM5OCwgMHgxMTIyMzMxMSxcbjB4NjlkMmJiNjksIDB4ZDlhOTcwZDksIDB4OGUwNzg5OGUsIDB4OTQzM2E3OTQsXG4weDliMmRiNjliLCAweDFlM2MyMjFlLCAweDg3MTU5Mjg3LCAweGU5YzkyMGU5LFxuMHhjZTg3NDljZSwgMHg1NWFhZmY1NSwgMHgyODUwNzgyOCwgMHhkZmE1N2FkZixcbjB4OGMwMzhmOGMsIDB4YTE1OWY4YTEsIDB4ODkwOTgwODksIDB4MGQxYTE3MGQsXG4weGJmNjVkYWJmLCAweGU2ZDczMWU2LCAweDQyODRjNjQyLCAweDY4ZDBiODY4LFxuMHg0MTgyYzM0MSwgMHg5OTI5YjA5OSwgMHgyZDVhNzcyZCwgMHgwZjFlMTEwZixcbjB4YjA3YmNiYjAsIDB4NTRhOGZjNTQsIDB4YmI2ZGQ2YmIsIDB4MTYyYzNhMTYgXTtcblxudmFyIFQ0ID0gW1xuMHhjNmE1NjM2MywgMHhmODg0N2M3YywgMHhlZTk5Nzc3NywgMHhmNjhkN2I3YixcbjB4ZmYwZGYyZjIsIDB4ZDZiZDZiNmIsIDB4ZGViMTZmNmYsIDB4OTE1NGM1YzUsXG4weDYwNTAzMDMwLCAweDAyMDMwMTAxLCAweGNlYTk2NzY3LCAweDU2N2QyYjJiLFxuMHhlNzE5ZmVmZSwgMHhiNTYyZDdkNywgMHg0ZGU2YWJhYiwgMHhlYzlhNzY3NixcbjB4OGY0NWNhY2EsIDB4MWY5ZDgyODIsIDB4ODk0MGM5YzksIDB4ZmE4NzdkN2QsXG4weGVmMTVmYWZhLCAweGIyZWI1OTU5LCAweDhlYzk0NzQ3LCAweGZiMGJmMGYwLFxuMHg0MWVjYWRhZCwgMHhiMzY3ZDRkNCwgMHg1ZmZkYTJhMiwgMHg0NWVhYWZhZixcbjB4MjNiZjljOWMsIDB4NTNmN2E0YTQsIDB4ZTQ5NjcyNzIsIDB4OWI1YmMwYzAsXG4weDc1YzJiN2I3LCAweGUxMWNmZGZkLCAweDNkYWU5MzkzLCAweDRjNmEyNjI2LFxuMHg2YzVhMzYzNiwgMHg3ZTQxM2YzZiwgMHhmNTAyZjdmNywgMHg4MzRmY2NjYyxcbjB4Njg1YzM0MzQsIDB4NTFmNGE1YTUsIDB4ZDEzNGU1ZTUsIDB4ZjkwOGYxZjEsXG4weGUyOTM3MTcxLCAweGFiNzNkOGQ4LCAweDYyNTMzMTMxLCAweDJhM2YxNTE1LFxuMHgwODBjMDQwNCwgMHg5NTUyYzdjNywgMHg0NjY1MjMyMywgMHg5ZDVlYzNjMyxcbjB4MzAyODE4MTgsIDB4MzdhMTk2OTYsIDB4MGEwZjA1MDUsIDB4MmZiNTlhOWEsXG4weDBlMDkwNzA3LCAweDI0MzYxMjEyLCAweDFiOWI4MDgwLCAweGRmM2RlMmUyLFxuMHhjZDI2ZWJlYiwgMHg0ZTY5MjcyNywgMHg3ZmNkYjJiMiwgMHhlYTlmNzU3NSxcbjB4MTIxYjA5MDksIDB4MWQ5ZTgzODMsIDB4NTg3NDJjMmMsIDB4MzQyZTFhMWEsXG4weDM2MmQxYjFiLCAweGRjYjI2ZTZlLCAweGI0ZWU1YTVhLCAweDViZmJhMGEwLFxuMHhhNGY2NTI1MiwgMHg3NjRkM2IzYiwgMHhiNzYxZDZkNiwgMHg3ZGNlYjNiMyxcbjB4NTI3YjI5MjksIDB4ZGQzZWUzZTMsIDB4NWU3MTJmMmYsIDB4MTM5Nzg0ODQsXG4weGE2ZjU1MzUzLCAweGI5NjhkMWQxLCAweDAwMDAwMDAwLCAweGMxMmNlZGVkLFxuMHg0MDYwMjAyMCwgMHhlMzFmZmNmYywgMHg3OWM4YjFiMSwgMHhiNmVkNWI1YixcbjB4ZDRiZTZhNmEsIDB4OGQ0NmNiY2IsIDB4NjdkOWJlYmUsIDB4NzI0YjM5MzksXG4weDk0ZGU0YTRhLCAweDk4ZDQ0YzRjLCAweGIwZTg1ODU4LCAweDg1NGFjZmNmLFxuMHhiYjZiZDBkMCwgMHhjNTJhZWZlZiwgMHg0ZmU1YWFhYSwgMHhlZDE2ZmJmYixcbjB4ODZjNTQzNDMsIDB4OWFkNzRkNGQsIDB4NjY1NTMzMzMsIDB4MTE5NDg1ODUsXG4weDhhY2Y0NTQ1LCAweGU5MTBmOWY5LCAweDA0MDYwMjAyLCAweGZlODE3ZjdmLFxuMHhhMGYwNTA1MCwgMHg3ODQ0M2MzYywgMHgyNWJhOWY5ZiwgMHg0YmUzYThhOCxcbjB4YTJmMzUxNTEsIDB4NWRmZWEzYTMsIDB4ODBjMDQwNDAsIDB4MDU4YThmOGYsXG4weDNmYWQ5MjkyLCAweDIxYmM5ZDlkLCAweDcwNDgzODM4LCAweGYxMDRmNWY1LFxuMHg2M2RmYmNiYywgMHg3N2MxYjZiNiwgMHhhZjc1ZGFkYSwgMHg0MjYzMjEyMSxcbjB4MjAzMDEwMTAsIDB4ZTUxYWZmZmYsIDB4ZmQwZWYzZjMsIDB4YmY2ZGQyZDIsXG4weDgxNGNjZGNkLCAweDE4MTQwYzBjLCAweDI2MzUxMzEzLCAweGMzMmZlY2VjLFxuMHhiZWUxNWY1ZiwgMHgzNWEyOTc5NywgMHg4OGNjNDQ0NCwgMHgyZTM5MTcxNyxcbjB4OTM1N2M0YzQsIDB4NTVmMmE3YTcsIDB4ZmM4MjdlN2UsIDB4N2E0NzNkM2QsXG4weGM4YWM2NDY0LCAweGJhZTc1ZDVkLCAweDMyMmIxOTE5LCAweGU2OTU3MzczLFxuMHhjMGEwNjA2MCwgMHgxOTk4ODE4MSwgMHg5ZWQxNGY0ZiwgMHhhMzdmZGNkYyxcbjB4NDQ2NjIyMjIsIDB4NTQ3ZTJhMmEsIDB4M2JhYjkwOTAsIDB4MGI4Mzg4ODgsXG4weDhjY2E0NjQ2LCAweGM3MjllZWVlLCAweDZiZDNiOGI4LCAweDI4M2MxNDE0LFxuMHhhNzc5ZGVkZSwgMHhiY2UyNWU1ZSwgMHgxNjFkMGIwYiwgMHhhZDc2ZGJkYixcbjB4ZGIzYmUwZTAsIDB4NjQ1NjMyMzIsIDB4NzQ0ZTNhM2EsIDB4MTQxZTBhMGEsXG4weDkyZGI0OTQ5LCAweDBjMGEwNjA2LCAweDQ4NmMyNDI0LCAweGI4ZTQ1YzVjLFxuMHg5ZjVkYzJjMiwgMHhiZDZlZDNkMywgMHg0M2VmYWNhYywgMHhjNGE2NjI2MixcbjB4MzlhODkxOTEsIDB4MzFhNDk1OTUsIDB4ZDMzN2U0ZTQsIDB4ZjI4Yjc5NzksXG4weGQ1MzJlN2U3LCAweDhiNDNjOGM4LCAweDZlNTkzNzM3LCAweGRhYjc2ZDZkLFxuMHgwMThjOGQ4ZCwgMHhiMTY0ZDVkNSwgMHg5Y2QyNGU0ZSwgMHg0OWUwYTlhOSxcbjB4ZDhiNDZjNmMsIDB4YWNmYTU2NTYsIDB4ZjMwN2Y0ZjQsIDB4Y2YyNWVhZWEsXG4weGNhYWY2NTY1LCAweGY0OGU3YTdhLCAweDQ3ZTlhZWFlLCAweDEwMTgwODA4LFxuMHg2ZmQ1YmFiYSwgMHhmMDg4Nzg3OCwgMHg0YTZmMjUyNSwgMHg1YzcyMmUyZSxcbjB4MzgyNDFjMWMsIDB4NTdmMWE2YTYsIDB4NzNjN2I0YjQsIDB4OTc1MWM2YzYsXG4weGNiMjNlOGU4LCAweGExN2NkZGRkLCAweGU4OWM3NDc0LCAweDNlMjExZjFmLFxuMHg5NmRkNGI0YiwgMHg2MWRjYmRiZCwgMHgwZDg2OGI4YiwgMHgwZjg1OGE4YSxcbjB4ZTA5MDcwNzAsIDB4N2M0MjNlM2UsIDB4NzFjNGI1YjUsIDB4Y2NhYTY2NjYsXG4weDkwZDg0ODQ4LCAweDA2MDUwMzAzLCAweGY3MDFmNmY2LCAweDFjMTIwZTBlLFxuMHhjMmEzNjE2MSwgMHg2YTVmMzUzNSwgMHhhZWY5NTc1NywgMHg2OWQwYjliOSxcbjB4MTc5MTg2ODYsIDB4OTk1OGMxYzEsIDB4M2EyNzFkMWQsIDB4MjdiOTllOWUsXG4weGQ5MzhlMWUxLCAweGViMTNmOGY4LCAweDJiYjM5ODk4LCAweDIyMzMxMTExLFxuMHhkMmJiNjk2OSwgMHhhOTcwZDlkOSwgMHgwNzg5OGU4ZSwgMHgzM2E3OTQ5NCxcbjB4MmRiNjliOWIsIDB4M2MyMjFlMWUsIDB4MTU5Mjg3ODcsIDB4YzkyMGU5ZTksXG4weDg3NDljZWNlLCAweGFhZmY1NTU1LCAweDUwNzgyODI4LCAweGE1N2FkZmRmLFxuMHgwMzhmOGM4YywgMHg1OWY4YTFhMSwgMHgwOTgwODk4OSwgMHgxYTE3MGQwZCxcbjB4NjVkYWJmYmYsIDB4ZDczMWU2ZTYsIDB4ODRjNjQyNDIsIDB4ZDBiODY4NjgsXG4weDgyYzM0MTQxLCAweDI5YjA5OTk5LCAweDVhNzcyZDJkLCAweDFlMTEwZjBmLFxuMHg3YmNiYjBiMCwgMHhhOGZjNTQ1NCwgMHg2ZGQ2YmJiYiwgMHgyYzNhMTYxNiBdO1xuXG5mdW5jdGlvbiBCMCh4KSB7IHJldHVybiAoeCYyNTUpOyB9XG5mdW5jdGlvbiBCMSh4KSB7IHJldHVybiAoKHg+PjgpJjI1NSk7IH1cbmZ1bmN0aW9uIEIyKHgpIHsgcmV0dXJuICgoeD4+MTYpJjI1NSk7IH1cbmZ1bmN0aW9uIEIzKHgpIHsgcmV0dXJuICgoeD4+MjQpJjI1NSk7IH1cblxuZnVuY3Rpb24gRjEoeDAsIHgxLCB4MiwgeDMpXG57XG4gIHJldHVybiBCMShUMVt4MCYyNTVdKSB8IChCMShUMVsoeDE+PjgpJjI1NV0pPDw4KVxuICAgICAgfCAoQjEoVDFbKHgyPj4xNikmMjU1XSk8PDE2KSB8IChCMShUMVt4Mz4+PjI0XSk8PDI0KTtcbn1cblxuZnVuY3Rpb24gcGFja0J5dGVzKG9jdGV0cylcbntcbiAgdmFyIGksIGo7XG4gIHZhciBsZW49b2N0ZXRzLmxlbmd0aDtcbiAgdmFyIGI9bmV3IEFycmF5KGxlbi80KTtcblxuICBpZiAoIW9jdGV0cyB8fCBsZW4gJSA0KSByZXR1cm47XG5cbiAgZm9yIChpPTAsIGo9MDsgajxsZW47IGorPSA0KVxuICAgICBiW2krK10gPSBvY3RldHNbal0gfCAob2N0ZXRzW2orMV08PDgpIHwgKG9jdGV0c1tqKzJdPDwxNikgfCAob2N0ZXRzW2orM108PDI0KTtcblxuICByZXR1cm4gYjsgIFxufVxuXG5mdW5jdGlvbiB1bnBhY2tCeXRlcyhwYWNrZWQpXG57XG4gIHZhciBqO1xuICB2YXIgaT0wLCBsID0gcGFja2VkLmxlbmd0aDtcbiAgdmFyIHIgPSBuZXcgQXJyYXkobCo0KTtcblxuICBmb3IgKGo9MDsgajxsOyBqKyspXG4gIHtcbiAgICByW2krK10gPSBCMChwYWNrZWRbal0pO1xuICAgIHJbaSsrXSA9IEIxKHBhY2tlZFtqXSk7XG4gICAgcltpKytdID0gQjIocGFja2VkW2pdKTtcbiAgICByW2krK10gPSBCMyhwYWNrZWRbal0pO1xuICB9XG4gIHJldHVybiByO1xufVxuXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxudmFyIG1heGtjPTg7XG52YXIgbWF4cms9MTQ7XG5cbmZ1bmN0aW9uIGtleUV4cGFuc2lvbihrZXkpXG57XG4gIHZhciBrYywgaSwgaiwgciwgdDtcbiAgdmFyIHJvdW5kcztcbiAgdmFyIGtleVNjaGVkPW5ldyBBcnJheShtYXhyaysxKTtcbiAgdmFyIGtleWxlbj1rZXkubGVuZ3RoO1xuICB2YXIgaz1uZXcgQXJyYXkobWF4a2MpO1xuICB2YXIgdGs9bmV3IEFycmF5KG1heGtjKTtcbiAgdmFyIHJjb25wb2ludGVyPTA7XG5cbiAgaWYoa2V5bGVuPT0xNilcbiAge1xuICAgcm91bmRzPTEwO1xuICAga2M9NDtcbiAgfVxuICBlbHNlIGlmKGtleWxlbj09MjQpXG4gIHtcbiAgIHJvdW5kcz0xMjtcbiAgIGtjPTY7XG4gIH1cbiAgZWxzZSBpZihrZXlsZW49PTMyKVxuICB7XG4gICByb3VuZHM9MTQ7XG4gICBrYz04O1xuICB9XG4gIGVsc2VcbiAge1xuXHR1dGlsLnByaW50X2Vycm9yKCdhZXMuanM6IEludmFsaWQga2V5LWxlbmd0aCBmb3IgQUVTIGtleTonK2tleWxlbik7XG4gICByZXR1cm47XG4gIH1cblxuICBmb3IoaT0wOyBpPG1heHJrKzE7IGkrKykga2V5U2NoZWRbaV09bmV3IEFycmF5KDQpO1xuXG4gIGZvcihpPTAsaj0wOyBqPGtleWxlbjsgaisrLGkrPTQpXG4gICAga1tqXSA9IGtleS5jaGFyQ29kZUF0KGkpIHwgKGtleS5jaGFyQ29kZUF0KGkrMSk8PDgpXG4gICAgICAgICAgICAgICAgICAgICB8IChrZXkuY2hhckNvZGVBdChpKzIpPDwxNikgfCAoa2V5LmNoYXJDb2RlQXQoaSszKTw8MjQpO1xuXG4gIGZvcihqPWtjLTE7IGo+PTA7IGotLSkgdGtbal0gPSBrW2pdO1xuXG4gIHI9MDtcbiAgdD0wO1xuICBmb3Ioaj0wOyAoajxrYykmJihyPHJvdW5kcysxKTsgKVxuICB7XG4gICAgZm9yKDsgKGo8a2MpJiYodDw0KTsgaisrLHQrKylcbiAgICB7XG4gICAgICBrZXlTY2hlZFtyXVt0XT10a1tqXTtcbiAgICB9XG4gICAgaWYodD09NClcbiAgICB7XG4gICAgICByKys7XG4gICAgICB0PTA7XG4gICAgfVxuICB9XG5cbiAgd2hpbGUocjxyb3VuZHMrMSlcbiAge1xuICAgIHZhciB0ZW1wID0gdGtba2MtMV07XG5cbiAgICB0a1swXSBePSBTW0IxKHRlbXApXSB8IChTW0IyKHRlbXApXTw8OCkgfCAoU1tCMyh0ZW1wKV08PDE2KSB8IChTW0IwKHRlbXApXTw8MjQpO1xuICAgIHRrWzBdIF49IFJjb25bcmNvbnBvaW50ZXIrK107XG5cbiAgICBpZihrYyAhPSA4KVxuICAgIHtcbiAgICAgIGZvcihqPTE7IGo8a2M7IGorKykgdGtbal0gXj0gdGtbai0xXTtcbiAgICB9XG4gICAgZWxzZVxuICAgIHtcbiAgICAgIGZvcihqPTE7IGo8a2MvMjsgaisrKSB0a1tqXSBePSB0a1tqLTFdO1xuIFxuICAgICAgdGVtcCA9IHRrW2tjLzItMV07XG4gICAgICB0a1trYy8yXSBePSBTW0IwKHRlbXApXSB8IChTW0IxKHRlbXApXTw8OCkgfCAoU1tCMih0ZW1wKV08PDE2KSB8IChTW0IzKHRlbXApXTw8MjQpO1xuXG4gICAgICBmb3Ioaj1rYy8yKzE7IGo8a2M7IGorKykgdGtbal0gXj0gdGtbai0xXTtcbiAgICB9XG5cbiAgICBmb3Ioaj0wOyAoajxrYykmJihyPHJvdW5kcysxKTsgKVxuICAgIHtcbiAgICAgIGZvcig7IChqPGtjKSYmKHQ8NCk7IGorKyx0KyspXG4gICAgICB7XG4gICAgICAgIGtleVNjaGVkW3JdW3RdPXRrW2pdO1xuICAgICAgfVxuICAgICAgaWYodD09NClcbiAgICAgIHtcbiAgICAgICAgcisrO1xuICAgICAgICB0PTA7XG4gICAgICB9XG4gICAgfVxuICB9XG4gIHRoaXMucm91bmRzID0gcm91bmRzO1xuICB0aGlzLnJrID0ga2V5U2NoZWQ7XG4gIHJldHVybiB0aGlzO1xufVxuXG5mdW5jdGlvbiBBRVNlbmNyeXB0KGJsb2NrLCBjdHgpXG57XG4gIHZhciByO1xuICB2YXIgdDAsdDEsdDIsdDM7XG5cbiAgdmFyIGIgPSBwYWNrQnl0ZXMoYmxvY2spO1xuICB2YXIgcm91bmRzID0gY3R4LnJvdW5kcztcbiAgdmFyIGIwID0gYlswXTtcbiAgdmFyIGIxID0gYlsxXTtcbiAgdmFyIGIyID0gYlsyXTtcbiAgdmFyIGIzID0gYlszXTtcblxuICBmb3Iocj0wOyByPHJvdW5kcy0xOyByKyspXG4gIHtcbiAgICB0MCA9IGIwIF4gY3R4LnJrW3JdWzBdO1xuICAgIHQxID0gYjEgXiBjdHgucmtbcl1bMV07XG4gICAgdDIgPSBiMiBeIGN0eC5ya1tyXVsyXTtcbiAgICB0MyA9IGIzIF4gY3R4LnJrW3JdWzNdO1xuXG4gICAgYjAgPSBUMVt0MCYyNTVdIF4gVDJbKHQxPj44KSYyNTVdIF4gVDNbKHQyPj4xNikmMjU1XSBeIFQ0W3QzPj4+MjRdO1xuICAgIGIxID0gVDFbdDEmMjU1XSBeIFQyWyh0Mj4+OCkmMjU1XSBeIFQzWyh0Mz4+MTYpJjI1NV0gXiBUNFt0MD4+PjI0XTtcbiAgICBiMiA9IFQxW3QyJjI1NV0gXiBUMlsodDM+PjgpJjI1NV0gXiBUM1sodDA+PjE2KSYyNTVdIF4gVDRbdDE+Pj4yNF07XG4gICAgYjMgPSBUMVt0MyYyNTVdIF4gVDJbKHQwPj44KSYyNTVdIF4gVDNbKHQxPj4xNikmMjU1XSBeIFQ0W3QyPj4+MjRdO1xuICB9XG5cbiAgLy8gbGFzdCByb3VuZCBpcyBzcGVjaWFsXG4gIHIgPSByb3VuZHMtMTtcblxuICB0MCA9IGIwIF4gY3R4LnJrW3JdWzBdO1xuICB0MSA9IGIxIF4gY3R4LnJrW3JdWzFdO1xuICB0MiA9IGIyIF4gY3R4LnJrW3JdWzJdO1xuICB0MyA9IGIzIF4gY3R4LnJrW3JdWzNdO1xuXG4gIGJbMF0gPSBGMSh0MCwgdDEsIHQyLCB0MykgXiBjdHgucmtbcm91bmRzXVswXTtcbiAgYlsxXSA9IEYxKHQxLCB0MiwgdDMsIHQwKSBeIGN0eC5ya1tyb3VuZHNdWzFdO1xuICBiWzJdID0gRjEodDIsIHQzLCB0MCwgdDEpIF4gY3R4LnJrW3JvdW5kc11bMl07XG4gIGJbM10gPSBGMSh0MywgdDAsIHQxLCB0MikgXiBjdHgucmtbcm91bmRzXVszXTtcblxuICByZXR1cm4gdW5wYWNrQnl0ZXMoYik7XG59XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuXHRlbmNyeXB0OiBBRVNlbmNyeXB0LFxuXHRrZXlFeHBhbnNpb246IGtleUV4cGFuc2lvblxufVxuIiwiLy9QYXVsIFRlcm8sIEp1bHkgMjAwMVxuLy9odHRwOi8vd3d3LnRlcm8uY28udWsvZGVzL1xuLy9cbi8vT3B0aW1pc2VkIGZvciBwZXJmb3JtYW5jZSB3aXRoIGxhcmdlIGJsb2NrcyBieSBNaWNoYWVsIEhheXdvcnRoLCBOb3ZlbWJlciAyMDAxXG4vL2h0dHA6Ly93d3cubmV0ZGVhbGluZy5jb21cbi8vXG4vLyBNb2RpZmllZCBieSBSZWN1cml0eSBMYWJzIEdtYkhcblxuLy9USElTIFNPRlRXQVJFIElTIFBST1ZJREVEIFwiQVMgSVNcIiBBTkRcbi8vQU5ZIEVYUFJFU1MgT1IgSU1QTElFRCBXQVJSQU5USUVTLCBJTkNMVURJTkcsIEJVVCBOT1QgTElNSVRFRCBUTywgVEhFXG4vL0lNUExJRUQgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFkgQU5EIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFXG4vL0FSRSBESVNDTEFJTUVELiAgSU4gTk8gRVZFTlQgU0hBTEwgVEhFIEFVVEhPUiBPUiBDT05UUklCVVRPUlMgQkUgTElBQkxFXG4vL0ZPUiBBTlkgRElSRUNULCBJTkRJUkVDVCwgSU5DSURFTlRBTCwgU1BFQ0lBTCwgRVhFTVBMQVJZLCBPUiBDT05TRVFVRU5USUFMXG4vL0RBTUFHRVMgKElOQ0xVRElORywgQlVUIE5PVCBMSU1JVEVEIFRPLCBQUk9DVVJFTUVOVCBPRiBTVUJTVElUVVRFIEdPT0RTXG4vL09SIFNFUlZJQ0VTOyBMT1NTIE9GIFVTRSwgREFUQSwgT1IgUFJPRklUUzsgT1IgQlVTSU5FU1MgSU5URVJSVVBUSU9OKVxuLy9IT1dFVkVSIENBVVNFRCBBTkQgT04gQU5ZIFRIRU9SWSBPRiBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQ09OVFJBQ1QsIFNUUklDVFxuLy9MSUFCSUxJVFksIE9SIFRPUlQgKElOQ0xVRElORyBORUdMSUdFTkNFIE9SIE9USEVSV0lTRSkgQVJJU0lORyBJTiBBTlkgV0FZXG4vL09VVCBPRiBUSEUgVVNFIE9GIFRISVMgU09GVFdBUkUsIEVWRU4gSUYgQURWSVNFRCBPRiBUSEUgUE9TU0lCSUxJVFkgT0Zcbi8vU1VDSCBEQU1BR0UuXG5cbi8vZGVzXG4vL3RoaXMgdGFrZXMgdGhlIGtleSwgdGhlIG1lc3NhZ2UsIGFuZCB3aGV0aGVyIHRvIGVuY3J5cHQgb3IgZGVjcnlwdFxuXG52YXIgdXRpbCA9IHJlcXVpcmUoJy4uLy4uL3V0aWwnKTtcblxuLy8gYWRkZWQgYnkgUmVjdXJpdHkgTGFic1xuZnVuY3Rpb24gZGVzZWRlKGJsb2NrLGtleSkge1xuXHR2YXIga2V5MSA9IGtleS5zdWJzdHJpbmcoMCw4KTtcblx0dmFyIGtleTIgPSBrZXkuc3Vic3RyaW5nKDgsMTYpO1xuXHR2YXIga2V5MyA9IGtleS5zdWJzdHJpbmcoMTYsMjQpO1xuXHRyZXR1cm4gdXRpbC5zdHIyYmluKGRlcyhkZXNfY3JlYXRlS2V5cyhrZXkzKSxkZXMoZGVzX2NyZWF0ZUtleXMoa2V5MiksZGVzKGRlc19jcmVhdGVLZXlzKGtleTEpLHV0aWwuYmluMnN0cihibG9jayksIHRydWUsIDAsbnVsbCxudWxsKSwgZmFsc2UsIDAsbnVsbCxudWxsKSwgdHJ1ZSwgMCxudWxsLG51bGwpKTtcbn1cblxuXG5mdW5jdGlvbiBkZXMgKGtleXMsIG1lc3NhZ2UsIGVuY3J5cHQsIG1vZGUsIGl2LCBwYWRkaW5nKSB7XG4gIC8vZGVjbGFyaW5nIHRoaXMgbG9jYWxseSBzcGVlZHMgdGhpbmdzIHVwIGEgYml0XG4gIHZhciBzcGZ1bmN0aW9uMSA9IG5ldyBBcnJheSAoMHgxMDEwNDAwLDAsMHgxMDAwMCwweDEwMTA0MDQsMHgxMDEwMDA0LDB4MTA0MDQsMHg0LDB4MTAwMDAsMHg0MDAsMHgxMDEwNDAwLDB4MTAxMDQwNCwweDQwMCwweDEwMDA0MDQsMHgxMDEwMDA0LDB4MTAwMDAwMCwweDQsMHg0MDQsMHgxMDAwNDAwLDB4MTAwMDQwMCwweDEwNDAwLDB4MTA0MDAsMHgxMDEwMDAwLDB4MTAxMDAwMCwweDEwMDA0MDQsMHgxMDAwNCwweDEwMDAwMDQsMHgxMDAwMDA0LDB4MTAwMDQsMCwweDQwNCwweDEwNDA0LDB4MTAwMDAwMCwweDEwMDAwLDB4MTAxMDQwNCwweDQsMHgxMDEwMDAwLDB4MTAxMDQwMCwweDEwMDAwMDAsMHgxMDAwMDAwLDB4NDAwLDB4MTAxMDAwNCwweDEwMDAwLDB4MTA0MDAsMHgxMDAwMDA0LDB4NDAwLDB4NCwweDEwMDA0MDQsMHgxMDQwNCwweDEwMTA0MDQsMHgxMDAwNCwweDEwMTAwMDAsMHgxMDAwNDA0LDB4MTAwMDAwNCwweDQwNCwweDEwNDA0LDB4MTAxMDQwMCwweDQwNCwweDEwMDA0MDAsMHgxMDAwNDAwLDAsMHgxMDAwNCwweDEwNDAwLDAsMHgxMDEwMDA0KTtcbiAgdmFyIHNwZnVuY3Rpb24yID0gbmV3IEFycmF5ICgtMHg3ZmVmN2ZlMCwtMHg3ZmZmODAwMCwweDgwMDAsMHgxMDgwMjAsMHgxMDAwMDAsMHgyMCwtMHg3ZmVmZmZlMCwtMHg3ZmZmN2ZlMCwtMHg3ZmZmZmZlMCwtMHg3ZmVmN2ZlMCwtMHg3ZmVmODAwMCwtMHg4MDAwMDAwMCwtMHg3ZmZmODAwMCwweDEwMDAwMCwweDIwLC0weDdmZWZmZmUwLDB4MTA4MDAwLDB4MTAwMDIwLC0weDdmZmY3ZmUwLDAsLTB4ODAwMDAwMDAsMHg4MDAwLDB4MTA4MDIwLC0weDdmZjAwMDAwLDB4MTAwMDIwLC0weDdmZmZmZmUwLDAsMHgxMDgwMDAsMHg4MDIwLC0weDdmZWY4MDAwLC0weDdmZjAwMDAwLDB4ODAyMCwwLDB4MTA4MDIwLC0weDdmZWZmZmUwLDB4MTAwMDAwLC0weDdmZmY3ZmUwLC0weDdmZjAwMDAwLC0weDdmZWY4MDAwLDB4ODAwMCwtMHg3ZmYwMDAwMCwtMHg3ZmZmODAwMCwweDIwLC0weDdmZWY3ZmUwLDB4MTA4MDIwLDB4MjAsMHg4MDAwLC0weDgwMDAwMDAwLDB4ODAyMCwtMHg3ZmVmODAwMCwweDEwMDAwMCwtMHg3ZmZmZmZlMCwweDEwMDAyMCwtMHg3ZmZmN2ZlMCwtMHg3ZmZmZmZlMCwweDEwMDAyMCwweDEwODAwMCwwLC0weDdmZmY4MDAwLDB4ODAyMCwtMHg4MDAwMDAwMCwtMHg3ZmVmZmZlMCwtMHg3ZmVmN2ZlMCwweDEwODAwMCk7XG4gIHZhciBzcGZ1bmN0aW9uMyA9IG5ldyBBcnJheSAoMHgyMDgsMHg4MDIwMjAwLDAsMHg4MDIwMDA4LDB4ODAwMDIwMCwwLDB4MjAyMDgsMHg4MDAwMjAwLDB4MjAwMDgsMHg4MDAwMDA4LDB4ODAwMDAwOCwweDIwMDAwLDB4ODAyMDIwOCwweDIwMDA4LDB4ODAyMDAwMCwweDIwOCwweDgwMDAwMDAsMHg4LDB4ODAyMDIwMCwweDIwMCwweDIwMjAwLDB4ODAyMDAwMCwweDgwMjAwMDgsMHgyMDIwOCwweDgwMDAyMDgsMHgyMDIwMCwweDIwMDAwLDB4ODAwMDIwOCwweDgsMHg4MDIwMjA4LDB4MjAwLDB4ODAwMDAwMCwweDgwMjAyMDAsMHg4MDAwMDAwLDB4MjAwMDgsMHgyMDgsMHgyMDAwMCwweDgwMjAyMDAsMHg4MDAwMjAwLDAsMHgyMDAsMHgyMDAwOCwweDgwMjAyMDgsMHg4MDAwMjAwLDB4ODAwMDAwOCwweDIwMCwwLDB4ODAyMDAwOCwweDgwMDAyMDgsMHgyMDAwMCwweDgwMDAwMDAsMHg4MDIwMjA4LDB4OCwweDIwMjA4LDB4MjAyMDAsMHg4MDAwMDA4LDB4ODAyMDAwMCwweDgwMDAyMDgsMHgyMDgsMHg4MDIwMDAwLDB4MjAyMDgsMHg4LDB4ODAyMDAwOCwweDIwMjAwKTtcbiAgdmFyIHNwZnVuY3Rpb240ID0gbmV3IEFycmF5ICgweDgwMjAwMSwweDIwODEsMHgyMDgxLDB4ODAsMHg4MDIwODAsMHg4MDAwODEsMHg4MDAwMDEsMHgyMDAxLDAsMHg4MDIwMDAsMHg4MDIwMDAsMHg4MDIwODEsMHg4MSwwLDB4ODAwMDgwLDB4ODAwMDAxLDB4MSwweDIwMDAsMHg4MDAwMDAsMHg4MDIwMDEsMHg4MCwweDgwMDAwMCwweDIwMDEsMHgyMDgwLDB4ODAwMDgxLDB4MSwweDIwODAsMHg4MDAwODAsMHgyMDAwLDB4ODAyMDgwLDB4ODAyMDgxLDB4ODEsMHg4MDAwODAsMHg4MDAwMDEsMHg4MDIwMDAsMHg4MDIwODEsMHg4MSwwLDAsMHg4MDIwMDAsMHgyMDgwLDB4ODAwMDgwLDB4ODAwMDgxLDB4MSwweDgwMjAwMSwweDIwODEsMHgyMDgxLDB4ODAsMHg4MDIwODEsMHg4MSwweDEsMHgyMDAwLDB4ODAwMDAxLDB4MjAwMSwweDgwMjA4MCwweDgwMDA4MSwweDIwMDEsMHgyMDgwLDB4ODAwMDAwLDB4ODAyMDAxLDB4ODAsMHg4MDAwMDAsMHgyMDAwLDB4ODAyMDgwKTtcbiAgdmFyIHNwZnVuY3Rpb241ID0gbmV3IEFycmF5ICgweDEwMCwweDIwODAxMDAsMHgyMDgwMDAwLDB4NDIwMDAxMDAsMHg4MDAwMCwweDEwMCwweDQwMDAwMDAwLDB4MjA4MDAwMCwweDQwMDgwMTAwLDB4ODAwMDAsMHgyMDAwMTAwLDB4NDAwODAxMDAsMHg0MjAwMDEwMCwweDQyMDgwMDAwLDB4ODAxMDAsMHg0MDAwMDAwMCwweDIwMDAwMDAsMHg0MDA4MDAwMCwweDQwMDgwMDAwLDAsMHg0MDAwMDEwMCwweDQyMDgwMTAwLDB4NDIwODAxMDAsMHgyMDAwMTAwLDB4NDIwODAwMDAsMHg0MDAwMDEwMCwwLDB4NDIwMDAwMDAsMHgyMDgwMTAwLDB4MjAwMDAwMCwweDQyMDAwMDAwLDB4ODAxMDAsMHg4MDAwMCwweDQyMDAwMTAwLDB4MTAwLDB4MjAwMDAwMCwweDQwMDAwMDAwLDB4MjA4MDAwMCwweDQyMDAwMTAwLDB4NDAwODAxMDAsMHgyMDAwMTAwLDB4NDAwMDAwMDAsMHg0MjA4MDAwMCwweDIwODAxMDAsMHg0MDA4MDEwMCwweDEwMCwweDIwMDAwMDAsMHg0MjA4MDAwMCwweDQyMDgwMTAwLDB4ODAxMDAsMHg0MjAwMDAwMCwweDQyMDgwMTAwLDB4MjA4MDAwMCwwLDB4NDAwODAwMDAsMHg0MjAwMDAwMCwweDgwMTAwLDB4MjAwMDEwMCwweDQwMDAwMTAwLDB4ODAwMDAsMCwweDQwMDgwMDAwLDB4MjA4MDEwMCwweDQwMDAwMTAwKTtcbiAgdmFyIHNwZnVuY3Rpb242ID0gbmV3IEFycmF5ICgweDIwMDAwMDEwLDB4MjA0MDAwMDAsMHg0MDAwLDB4MjA0MDQwMTAsMHgyMDQwMDAwMCwweDEwLDB4MjA0MDQwMTAsMHg0MDAwMDAsMHgyMDAwNDAwMCwweDQwNDAxMCwweDQwMDAwMCwweDIwMDAwMDEwLDB4NDAwMDEwLDB4MjAwMDQwMDAsMHgyMDAwMDAwMCwweDQwMTAsMCwweDQwMDAxMCwweDIwMDA0MDEwLDB4NDAwMCwweDQwNDAwMCwweDIwMDA0MDEwLDB4MTAsMHgyMDQwMDAxMCwweDIwNDAwMDEwLDAsMHg0MDQwMTAsMHgyMDQwNDAwMCwweDQwMTAsMHg0MDQwMDAsMHgyMDQwNDAwMCwweDIwMDAwMDAwLDB4MjAwMDQwMDAsMHgxMCwweDIwNDAwMDEwLDB4NDA0MDAwLDB4MjA0MDQwMTAsMHg0MDAwMDAsMHg0MDEwLDB4MjAwMDAwMTAsMHg0MDAwMDAsMHgyMDAwNDAwMCwweDIwMDAwMDAwLDB4NDAxMCwweDIwMDAwMDEwLDB4MjA0MDQwMTAsMHg0MDQwMDAsMHgyMDQwMDAwMCwweDQwNDAxMCwweDIwNDA0MDAwLDAsMHgyMDQwMDAxMCwweDEwLDB4NDAwMCwweDIwNDAwMDAwLDB4NDA0MDEwLDB4NDAwMCwweDQwMDAxMCwweDIwMDA0MDEwLDAsMHgyMDQwNDAwMCwweDIwMDAwMDAwLDB4NDAwMDEwLDB4MjAwMDQwMTApO1xuICB2YXIgc3BmdW5jdGlvbjcgPSBuZXcgQXJyYXkgKDB4MjAwMDAwLDB4NDIwMDAwMiwweDQwMDA4MDIsMCwweDgwMCwweDQwMDA4MDIsMHgyMDA4MDIsMHg0MjAwODAwLDB4NDIwMDgwMiwweDIwMDAwMCwwLDB4NDAwMDAwMiwweDIsMHg0MDAwMDAwLDB4NDIwMDAwMiwweDgwMiwweDQwMDA4MDAsMHgyMDA4MDIsMHgyMDAwMDIsMHg0MDAwODAwLDB4NDAwMDAwMiwweDQyMDAwMDAsMHg0MjAwODAwLDB4MjAwMDAyLDB4NDIwMDAwMCwweDgwMCwweDgwMiwweDQyMDA4MDIsMHgyMDA4MDAsMHgyLDB4NDAwMDAwMCwweDIwMDgwMCwweDQwMDAwMDAsMHgyMDA4MDAsMHgyMDAwMDAsMHg0MDAwODAyLDB4NDAwMDgwMiwweDQyMDAwMDIsMHg0MjAwMDAyLDB4MiwweDIwMDAwMiwweDQwMDAwMDAsMHg0MDAwODAwLDB4MjAwMDAwLDB4NDIwMDgwMCwweDgwMiwweDIwMDgwMiwweDQyMDA4MDAsMHg4MDIsMHg0MDAwMDAyLDB4NDIwMDgwMiwweDQyMDAwMDAsMHgyMDA4MDAsMCwweDIsMHg0MjAwODAyLDAsMHgyMDA4MDIsMHg0MjAwMDAwLDB4ODAwLDB4NDAwMDAwMiwweDQwMDA4MDAsMHg4MDAsMHgyMDAwMDIpO1xuICB2YXIgc3BmdW5jdGlvbjggPSBuZXcgQXJyYXkgKDB4MTAwMDEwNDAsMHgxMDAwLDB4NDAwMDAsMHgxMDA0MTA0MCwweDEwMDAwMDAwLDB4MTAwMDEwNDAsMHg0MCwweDEwMDAwMDAwLDB4NDAwNDAsMHgxMDA0MDAwMCwweDEwMDQxMDQwLDB4NDEwMDAsMHgxMDA0MTAwMCwweDQxMDQwLDB4MTAwMCwweDQwLDB4MTAwNDAwMDAsMHgxMDAwMDA0MCwweDEwMDAxMDAwLDB4MTA0MCwweDQxMDAwLDB4NDAwNDAsMHgxMDA0MDA0MCwweDEwMDQxMDAwLDB4MTA0MCwwLDAsMHgxMDA0MDA0MCwweDEwMDAwMDQwLDB4MTAwMDEwMDAsMHg0MTA0MCwweDQwMDAwLDB4NDEwNDAsMHg0MDAwMCwweDEwMDQxMDAwLDB4MTAwMCwweDQwLDB4MTAwNDAwNDAsMHgxMDAwLDB4NDEwNDAsMHgxMDAwMTAwMCwweDQwLDB4MTAwMDAwNDAsMHgxMDA0MDAwMCwweDEwMDQwMDQwLDB4MTAwMDAwMDAsMHg0MDAwMCwweDEwMDAxMDQwLDAsMHgxMDA0MTA0MCwweDQwMDQwLDB4MTAwMDAwNDAsMHgxMDA0MDAwMCwweDEwMDAxMDAwLDB4MTAwMDEwNDAsMCwweDEwMDQxMDQwLDB4NDEwMDAsMHg0MTAwMCwweDEwNDAsMHgxMDQwLDB4NDAwNDAsMHgxMDAwMDAwMCwweDEwMDQxMDAwKTtcblxuICAvL2NyZWF0ZSB0aGUgMTYgb3IgNDggc3Via2V5cyB3ZSB3aWxsIG5lZWRcbiAgdmFyIG09MCwgaSwgaiwgdGVtcCwgdGVtcDIsIHJpZ2h0MSwgcmlnaHQyLCBsZWZ0LCByaWdodCwgbG9vcGluZztcbiAgdmFyIGNiY2xlZnQsIGNiY2xlZnQyLCBjYmNyaWdodCwgY2JjcmlnaHQyXG4gIHZhciBlbmRsb29wLCBsb29waW5jO1xuICB2YXIgbGVuID0gbWVzc2FnZS5sZW5ndGg7XG4gIHZhciBjaHVuayA9IDA7XG4gIC8vc2V0IHVwIHRoZSBsb29wcyBmb3Igc2luZ2xlIGFuZCB0cmlwbGUgZGVzXG4gIHZhciBpdGVyYXRpb25zID0ga2V5cy5sZW5ndGggPT0gMzIgPyAzIDogOTsgLy9zaW5nbGUgb3IgdHJpcGxlIGRlc1xuICBpZiAoaXRlcmF0aW9ucyA9PSAzKSB7bG9vcGluZyA9IGVuY3J5cHQgPyBuZXcgQXJyYXkgKDAsIDMyLCAyKSA6IG5ldyBBcnJheSAoMzAsIC0yLCAtMik7fVxuICBlbHNlIHtsb29waW5nID0gZW5jcnlwdCA/IG5ldyBBcnJheSAoMCwgMzIsIDIsIDYyLCAzMCwgLTIsIDY0LCA5NiwgMikgOiBuZXcgQXJyYXkgKDk0LCA2MiwgLTIsIDMyLCA2NCwgMiwgMzAsIC0yLCAtMik7fVxuXG4gIC8vcGFkIHRoZSBtZXNzYWdlIGRlcGVuZGluZyBvbiB0aGUgcGFkZGluZyBwYXJhbWV0ZXJcbiAgaWYgKHBhZGRpbmcgPT0gMikgbWVzc2FnZSArPSBcIiAgICAgICAgXCI7IC8vcGFkIHRoZSBtZXNzYWdlIHdpdGggc3BhY2VzXG4gIGVsc2UgaWYgKHBhZGRpbmcgPT0gMSkge3RlbXAgPSA4LShsZW4lOCk7IG1lc3NhZ2UgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSAodGVtcCx0ZW1wLHRlbXAsdGVtcCx0ZW1wLHRlbXAsdGVtcCx0ZW1wKTsgaWYgKHRlbXA9PTgpIGxlbis9ODt9IC8vUEtDUzcgcGFkZGluZ1xuICBlbHNlIGlmICghcGFkZGluZykgbWVzc2FnZSArPSBcIlxcMFxcMFxcMFxcMFxcMFxcMFxcMFxcMFwiOyAvL3BhZCB0aGUgbWVzc2FnZSBvdXQgd2l0aCBudWxsIGJ5dGVzXG5cbiAgLy9zdG9yZSB0aGUgcmVzdWx0IGhlcmVcbiAgcmVzdWx0ID0gXCJcIjtcbiAgdGVtcHJlc3VsdCA9IFwiXCI7XG5cbiAgaWYgKG1vZGUgPT0gMSkgeyAvL0NCQyBtb2RlXG4gICAgY2JjbGVmdCA9IChpdi5jaGFyQ29kZUF0KG0rKykgPDwgMjQpIHwgKGl2LmNoYXJDb2RlQXQobSsrKSA8PCAxNikgfCAoaXYuY2hhckNvZGVBdChtKyspIDw8IDgpIHwgaXYuY2hhckNvZGVBdChtKyspO1xuICAgIGNiY3JpZ2h0ID0gKGl2LmNoYXJDb2RlQXQobSsrKSA8PCAyNCkgfCAoaXYuY2hhckNvZGVBdChtKyspIDw8IDE2KSB8IChpdi5jaGFyQ29kZUF0KG0rKykgPDwgOCkgfCBpdi5jaGFyQ29kZUF0KG0rKyk7XG4gICAgbT0wO1xuICB9XG5cbiAgLy9sb29wIHRocm91Z2ggZWFjaCA2NCBiaXQgY2h1bmsgb2YgdGhlIG1lc3NhZ2VcbiAgd2hpbGUgKG0gPCBsZW4pIHtcbiAgICBsZWZ0ID0gKG1lc3NhZ2UuY2hhckNvZGVBdChtKyspIDw8IDI0KSB8IChtZXNzYWdlLmNoYXJDb2RlQXQobSsrKSA8PCAxNikgfCAobWVzc2FnZS5jaGFyQ29kZUF0KG0rKykgPDwgOCkgfCBtZXNzYWdlLmNoYXJDb2RlQXQobSsrKTtcbiAgICByaWdodCA9IChtZXNzYWdlLmNoYXJDb2RlQXQobSsrKSA8PCAyNCkgfCAobWVzc2FnZS5jaGFyQ29kZUF0KG0rKykgPDwgMTYpIHwgKG1lc3NhZ2UuY2hhckNvZGVBdChtKyspIDw8IDgpIHwgbWVzc2FnZS5jaGFyQ29kZUF0KG0rKyk7XG5cbiAgICAvL2ZvciBDaXBoZXIgQmxvY2sgQ2hhaW5pbmcgbW9kZSwgeG9yIHRoZSBtZXNzYWdlIHdpdGggdGhlIHByZXZpb3VzIHJlc3VsdFxuICAgIGlmIChtb2RlID09IDEpIHtpZiAoZW5jcnlwdCkge2xlZnQgXj0gY2JjbGVmdDsgcmlnaHQgXj0gY2JjcmlnaHQ7fSBlbHNlIHtjYmNsZWZ0MiA9IGNiY2xlZnQ7IGNiY3JpZ2h0MiA9IGNiY3JpZ2h0OyBjYmNsZWZ0ID0gbGVmdDsgY2JjcmlnaHQgPSByaWdodDt9fVxuXG4gICAgLy9maXJzdCBlYWNoIDY0IGJ1dCBjaHVuayBvZiB0aGUgbWVzc2FnZSBtdXN0IGJlIHBlcm11dGVkIGFjY29yZGluZyB0byBJUFxuICAgIHRlbXAgPSAoKGxlZnQgPj4+IDQpIF4gcmlnaHQpICYgMHgwZjBmMGYwZjsgcmlnaHQgXj0gdGVtcDsgbGVmdCBePSAodGVtcCA8PCA0KTtcbiAgICB0ZW1wID0gKChsZWZ0ID4+PiAxNikgXiByaWdodCkgJiAweDAwMDBmZmZmOyByaWdodCBePSB0ZW1wOyBsZWZ0IF49ICh0ZW1wIDw8IDE2KTtcbiAgICB0ZW1wID0gKChyaWdodCA+Pj4gMikgXiBsZWZ0KSAmIDB4MzMzMzMzMzM7IGxlZnQgXj0gdGVtcDsgcmlnaHQgXj0gKHRlbXAgPDwgMik7XG4gICAgdGVtcCA9ICgocmlnaHQgPj4+IDgpIF4gbGVmdCkgJiAweDAwZmYwMGZmOyBsZWZ0IF49IHRlbXA7IHJpZ2h0IF49ICh0ZW1wIDw8IDgpO1xuICAgIHRlbXAgPSAoKGxlZnQgPj4+IDEpIF4gcmlnaHQpICYgMHg1NTU1NTU1NTsgcmlnaHQgXj0gdGVtcDsgbGVmdCBePSAodGVtcCA8PCAxKTtcblxuICAgIGxlZnQgPSAoKGxlZnQgPDwgMSkgfCAobGVmdCA+Pj4gMzEpKTsgXG4gICAgcmlnaHQgPSAoKHJpZ2h0IDw8IDEpIHwgKHJpZ2h0ID4+PiAzMSkpOyBcblxuICAgIC8vZG8gdGhpcyBlaXRoZXIgMSBvciAzIHRpbWVzIGZvciBlYWNoIGNodW5rIG9mIHRoZSBtZXNzYWdlXG4gICAgZm9yIChqPTA7IGo8aXRlcmF0aW9uczsgais9Mykge1xuICAgICAgZW5kbG9vcCA9IGxvb3BpbmdbaisxXTtcbiAgICAgIGxvb3BpbmMgPSBsb29waW5nW2orMl07XG4gICAgICAvL25vdyBnbyB0aHJvdWdoIGFuZCBwZXJmb3JtIHRoZSBlbmNyeXB0aW9uIG9yIGRlY3J5cHRpb24gIFxuICAgICAgZm9yIChpPWxvb3Bpbmdbal07IGkhPWVuZGxvb3A7IGkrPWxvb3BpbmMpIHsgLy9mb3IgZWZmaWNpZW5jeVxuICAgICAgICByaWdodDEgPSByaWdodCBeIGtleXNbaV07IFxuICAgICAgICByaWdodDIgPSAoKHJpZ2h0ID4+PiA0KSB8IChyaWdodCA8PCAyOCkpIF4ga2V5c1tpKzFdO1xuICAgICAgICAvL3RoZSByZXN1bHQgaXMgYXR0YWluZWQgYnkgcGFzc2luZyB0aGVzZSBieXRlcyB0aHJvdWdoIHRoZSBTIHNlbGVjdGlvbiBmdW5jdGlvbnNcbiAgICAgICAgdGVtcCA9IGxlZnQ7XG4gICAgICAgIGxlZnQgPSByaWdodDtcbiAgICAgICAgcmlnaHQgPSB0ZW1wIF4gKHNwZnVuY3Rpb24yWyhyaWdodDEgPj4+IDI0KSAmIDB4M2ZdIHwgc3BmdW5jdGlvbjRbKHJpZ2h0MSA+Pj4gMTYpICYgMHgzZl1cbiAgICAgICAgICAgICAgfCBzcGZ1bmN0aW9uNlsocmlnaHQxID4+PiAgOCkgJiAweDNmXSB8IHNwZnVuY3Rpb244W3JpZ2h0MSAmIDB4M2ZdXG4gICAgICAgICAgICAgIHwgc3BmdW5jdGlvbjFbKHJpZ2h0MiA+Pj4gMjQpICYgMHgzZl0gfCBzcGZ1bmN0aW9uM1socmlnaHQyID4+PiAxNikgJiAweDNmXVxuICAgICAgICAgICAgICB8IHNwZnVuY3Rpb241WyhyaWdodDIgPj4+ICA4KSAmIDB4M2ZdIHwgc3BmdW5jdGlvbjdbcmlnaHQyICYgMHgzZl0pO1xuICAgICAgfVxuICAgICAgdGVtcCA9IGxlZnQ7IGxlZnQgPSByaWdodDsgcmlnaHQgPSB0ZW1wOyAvL3VucmV2ZXJzZSBsZWZ0IGFuZCByaWdodFxuICAgIH0gLy9mb3IgZWl0aGVyIDEgb3IgMyBpdGVyYXRpb25zXG5cbiAgICAvL21vdmUgdGhlbiBlYWNoIG9uZSBiaXQgdG8gdGhlIHJpZ2h0XG4gICAgbGVmdCA9ICgobGVmdCA+Pj4gMSkgfCAobGVmdCA8PCAzMSkpOyBcbiAgICByaWdodCA9ICgocmlnaHQgPj4+IDEpIHwgKHJpZ2h0IDw8IDMxKSk7IFxuXG4gICAgLy9ub3cgcGVyZm9ybSBJUC0xLCB3aGljaCBpcyBJUCBpbiB0aGUgb3Bwb3NpdGUgZGlyZWN0aW9uXG4gICAgdGVtcCA9ICgobGVmdCA+Pj4gMSkgXiByaWdodCkgJiAweDU1NTU1NTU1OyByaWdodCBePSB0ZW1wOyBsZWZ0IF49ICh0ZW1wIDw8IDEpO1xuICAgIHRlbXAgPSAoKHJpZ2h0ID4+PiA4KSBeIGxlZnQpICYgMHgwMGZmMDBmZjsgbGVmdCBePSB0ZW1wOyByaWdodCBePSAodGVtcCA8PCA4KTtcbiAgICB0ZW1wID0gKChyaWdodCA+Pj4gMikgXiBsZWZ0KSAmIDB4MzMzMzMzMzM7IGxlZnQgXj0gdGVtcDsgcmlnaHQgXj0gKHRlbXAgPDwgMik7XG4gICAgdGVtcCA9ICgobGVmdCA+Pj4gMTYpIF4gcmlnaHQpICYgMHgwMDAwZmZmZjsgcmlnaHQgXj0gdGVtcDsgbGVmdCBePSAodGVtcCA8PCAxNik7XG4gICAgdGVtcCA9ICgobGVmdCA+Pj4gNCkgXiByaWdodCkgJiAweDBmMGYwZjBmOyByaWdodCBePSB0ZW1wOyBsZWZ0IF49ICh0ZW1wIDw8IDQpO1xuXG4gICAgLy9mb3IgQ2lwaGVyIEJsb2NrIENoYWluaW5nIG1vZGUsIHhvciB0aGUgbWVzc2FnZSB3aXRoIHRoZSBwcmV2aW91cyByZXN1bHRcbiAgICBpZiAobW9kZSA9PSAxKSB7aWYgKGVuY3J5cHQpIHtjYmNsZWZ0ID0gbGVmdDsgY2JjcmlnaHQgPSByaWdodDt9IGVsc2Uge2xlZnQgXj0gY2JjbGVmdDI7IHJpZ2h0IF49IGNiY3JpZ2h0Mjt9fVxuICAgIHRlbXByZXN1bHQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSAoKGxlZnQ+Pj4yNCksICgobGVmdD4+PjE2KSAmIDB4ZmYpLCAoKGxlZnQ+Pj44KSAmIDB4ZmYpLCAobGVmdCAmIDB4ZmYpLCAocmlnaHQ+Pj4yNCksICgocmlnaHQ+Pj4xNikgJiAweGZmKSwgKChyaWdodD4+PjgpICYgMHhmZiksIChyaWdodCAmIDB4ZmYpKTtcblxuICAgIGNodW5rICs9IDg7XG4gICAgaWYgKGNodW5rID09IDUxMikge3Jlc3VsdCArPSB0ZW1wcmVzdWx0OyB0ZW1wcmVzdWx0ID0gXCJcIjsgY2h1bmsgPSAwO31cbiAgfSAvL2ZvciBldmVyeSA4IGNoYXJhY3RlcnMsIG9yIDY0IGJpdHMgaW4gdGhlIG1lc3NhZ2VcblxuICAvL3JldHVybiB0aGUgcmVzdWx0IGFzIGFuIGFycmF5XG4gIHJlc3VsdCArPSB0ZW1wcmVzdWx0O1xuICByZXN1bHQgPSByZXN1bHQucmVwbGFjZSgvXFwwKiQvZywgXCJcIik7XG4gIHJldHVybiByZXN1bHQ7XG59IC8vZW5kIG9mIGRlc1xuXG5cblxuLy9kZXNfY3JlYXRlS2V5c1xuLy90aGlzIHRha2VzIGFzIGlucHV0IGEgNjQgYml0IGtleSAoZXZlbiB0aG91Z2ggb25seSA1NiBiaXRzIGFyZSB1c2VkKVxuLy9hcyBhbiBhcnJheSBvZiAyIGludGVnZXJzLCBhbmQgcmV0dXJucyAxNiA0OCBiaXQga2V5c1xuZnVuY3Rpb24gZGVzX2NyZWF0ZUtleXMgKGtleSkge1xuICAvL2RlY2xhcmluZyB0aGlzIGxvY2FsbHkgc3BlZWRzIHRoaW5ncyB1cCBhIGJpdFxuICBwYzJieXRlczAgID0gbmV3IEFycmF5ICgwLDB4NCwweDIwMDAwMDAwLDB4MjAwMDAwMDQsMHgxMDAwMCwweDEwMDA0LDB4MjAwMTAwMDAsMHgyMDAxMDAwNCwweDIwMCwweDIwNCwweDIwMDAwMjAwLDB4MjAwMDAyMDQsMHgxMDIwMCwweDEwMjA0LDB4MjAwMTAyMDAsMHgyMDAxMDIwNCk7XG4gIHBjMmJ5dGVzMSAgPSBuZXcgQXJyYXkgKDAsMHgxLDB4MTAwMDAwLDB4MTAwMDAxLDB4NDAwMDAwMCwweDQwMDAwMDEsMHg0MTAwMDAwLDB4NDEwMDAwMSwweDEwMCwweDEwMSwweDEwMDEwMCwweDEwMDEwMSwweDQwMDAxMDAsMHg0MDAwMTAxLDB4NDEwMDEwMCwweDQxMDAxMDEpO1xuICBwYzJieXRlczIgID0gbmV3IEFycmF5ICgwLDB4OCwweDgwMCwweDgwOCwweDEwMDAwMDAsMHgxMDAwMDA4LDB4MTAwMDgwMCwweDEwMDA4MDgsMCwweDgsMHg4MDAsMHg4MDgsMHgxMDAwMDAwLDB4MTAwMDAwOCwweDEwMDA4MDAsMHgxMDAwODA4KTtcbiAgcGMyYnl0ZXMzICA9IG5ldyBBcnJheSAoMCwweDIwMDAwMCwweDgwMDAwMDAsMHg4MjAwMDAwLDB4MjAwMCwweDIwMjAwMCwweDgwMDIwMDAsMHg4MjAyMDAwLDB4MjAwMDAsMHgyMjAwMDAsMHg4MDIwMDAwLDB4ODIyMDAwMCwweDIyMDAwLDB4MjIyMDAwLDB4ODAyMjAwMCwweDgyMjIwMDApO1xuICBwYzJieXRlczQgID0gbmV3IEFycmF5ICgwLDB4NDAwMDAsMHgxMCwweDQwMDEwLDAsMHg0MDAwMCwweDEwLDB4NDAwMTAsMHgxMDAwLDB4NDEwMDAsMHgxMDEwLDB4NDEwMTAsMHgxMDAwLDB4NDEwMDAsMHgxMDEwLDB4NDEwMTApO1xuICBwYzJieXRlczUgID0gbmV3IEFycmF5ICgwLDB4NDAwLDB4MjAsMHg0MjAsMCwweDQwMCwweDIwLDB4NDIwLDB4MjAwMDAwMCwweDIwMDA0MDAsMHgyMDAwMDIwLDB4MjAwMDQyMCwweDIwMDAwMDAsMHgyMDAwNDAwLDB4MjAwMDAyMCwweDIwMDA0MjApO1xuICBwYzJieXRlczYgID0gbmV3IEFycmF5ICgwLDB4MTAwMDAwMDAsMHg4MDAwMCwweDEwMDgwMDAwLDB4MiwweDEwMDAwMDAyLDB4ODAwMDIsMHgxMDA4MDAwMiwwLDB4MTAwMDAwMDAsMHg4MDAwMCwweDEwMDgwMDAwLDB4MiwweDEwMDAwMDAyLDB4ODAwMDIsMHgxMDA4MDAwMik7XG4gIHBjMmJ5dGVzNyAgPSBuZXcgQXJyYXkgKDAsMHgxMDAwMCwweDgwMCwweDEwODAwLDB4MjAwMDAwMDAsMHgyMDAxMDAwMCwweDIwMDAwODAwLDB4MjAwMTA4MDAsMHgyMDAwMCwweDMwMDAwLDB4MjA4MDAsMHgzMDgwMCwweDIwMDIwMDAwLDB4MjAwMzAwMDAsMHgyMDAyMDgwMCwweDIwMDMwODAwKTtcbiAgcGMyYnl0ZXM4ICA9IG5ldyBBcnJheSAoMCwweDQwMDAwLDAsMHg0MDAwMCwweDIsMHg0MDAwMiwweDIsMHg0MDAwMiwweDIwMDAwMDAsMHgyMDQwMDAwLDB4MjAwMDAwMCwweDIwNDAwMDAsMHgyMDAwMDAyLDB4MjA0MDAwMiwweDIwMDAwMDIsMHgyMDQwMDAyKTtcbiAgcGMyYnl0ZXM5ICA9IG5ldyBBcnJheSAoMCwweDEwMDAwMDAwLDB4OCwweDEwMDAwMDA4LDAsMHgxMDAwMDAwMCwweDgsMHgxMDAwMDAwOCwweDQwMCwweDEwMDAwNDAwLDB4NDA4LDB4MTAwMDA0MDgsMHg0MDAsMHgxMDAwMDQwMCwweDQwOCwweDEwMDAwNDA4KTtcbiAgcGMyYnl0ZXMxMCA9IG5ldyBBcnJheSAoMCwweDIwLDAsMHgyMCwweDEwMDAwMCwweDEwMDAyMCwweDEwMDAwMCwweDEwMDAyMCwweDIwMDAsMHgyMDIwLDB4MjAwMCwweDIwMjAsMHgxMDIwMDAsMHgxMDIwMjAsMHgxMDIwMDAsMHgxMDIwMjApO1xuICBwYzJieXRlczExID0gbmV3IEFycmF5ICgwLDB4MTAwMDAwMCwweDIwMCwweDEwMDAyMDAsMHgyMDAwMDAsMHgxMjAwMDAwLDB4MjAwMjAwLDB4MTIwMDIwMCwweDQwMDAwMDAsMHg1MDAwMDAwLDB4NDAwMDIwMCwweDUwMDAyMDAsMHg0MjAwMDAwLDB4NTIwMDAwMCwweDQyMDAyMDAsMHg1MjAwMjAwKTtcbiAgcGMyYnl0ZXMxMiA9IG5ldyBBcnJheSAoMCwweDEwMDAsMHg4MDAwMDAwLDB4ODAwMTAwMCwweDgwMDAwLDB4ODEwMDAsMHg4MDgwMDAwLDB4ODA4MTAwMCwweDEwLDB4MTAxMCwweDgwMDAwMTAsMHg4MDAxMDEwLDB4ODAwMTAsMHg4MTAxMCwweDgwODAwMTAsMHg4MDgxMDEwKTtcbiAgcGMyYnl0ZXMxMyA9IG5ldyBBcnJheSAoMCwweDQsMHgxMDAsMHgxMDQsMCwweDQsMHgxMDAsMHgxMDQsMHgxLDB4NSwweDEwMSwweDEwNSwweDEsMHg1LDB4MTAxLDB4MTA1KTtcblxuICAvL2hvdyBtYW55IGl0ZXJhdGlvbnMgKDEgZm9yIGRlcywgMyBmb3IgdHJpcGxlIGRlcylcbiAgdmFyIGl0ZXJhdGlvbnMgPSBrZXkubGVuZ3RoID4gOCA/IDMgOiAxOyAvL2NoYW5nZWQgYnkgUGF1bCAxNi82LzIwMDcgdG8gdXNlIFRyaXBsZSBERVMgZm9yIDkrIGJ5dGUga2V5c1xuICAvL3N0b3JlcyB0aGUgcmV0dXJuIGtleXNcbiAgdmFyIGtleXMgPSBuZXcgQXJyYXkgKDMyICogaXRlcmF0aW9ucyk7XG4gIC8vbm93IGRlZmluZSB0aGUgbGVmdCBzaGlmdHMgd2hpY2ggbmVlZCB0byBiZSBkb25lXG4gIHZhciBzaGlmdHMgPSBuZXcgQXJyYXkgKDAsIDAsIDEsIDEsIDEsIDEsIDEsIDEsIDAsIDEsIDEsIDEsIDEsIDEsIDEsIDApO1xuICAvL290aGVyIHZhcmlhYmxlc1xuICB2YXIgbGVmdHRlbXAsIHJpZ2h0dGVtcCwgbT0wLCBuPTAsIHRlbXA7XG5cbiAgZm9yICh2YXIgaj0wOyBqPGl0ZXJhdGlvbnM7IGorKykgeyAvL2VpdGhlciAxIG9yIDMgaXRlcmF0aW9uc1xuICAgIGxlZnQgPSAoa2V5LmNoYXJDb2RlQXQobSsrKSA8PCAyNCkgfCAoa2V5LmNoYXJDb2RlQXQobSsrKSA8PCAxNikgfCAoa2V5LmNoYXJDb2RlQXQobSsrKSA8PCA4KSB8IGtleS5jaGFyQ29kZUF0KG0rKyk7XG4gICAgcmlnaHQgPSAoa2V5LmNoYXJDb2RlQXQobSsrKSA8PCAyNCkgfCAoa2V5LmNoYXJDb2RlQXQobSsrKSA8PCAxNikgfCAoa2V5LmNoYXJDb2RlQXQobSsrKSA8PCA4KSB8IGtleS5jaGFyQ29kZUF0KG0rKyk7XG5cbiAgICB0ZW1wID0gKChsZWZ0ID4+PiA0KSBeIHJpZ2h0KSAmIDB4MGYwZjBmMGY7IHJpZ2h0IF49IHRlbXA7IGxlZnQgXj0gKHRlbXAgPDwgNCk7XG4gICAgdGVtcCA9ICgocmlnaHQgPj4+IC0xNikgXiBsZWZ0KSAmIDB4MDAwMGZmZmY7IGxlZnQgXj0gdGVtcDsgcmlnaHQgXj0gKHRlbXAgPDwgLTE2KTtcbiAgICB0ZW1wID0gKChsZWZ0ID4+PiAyKSBeIHJpZ2h0KSAmIDB4MzMzMzMzMzM7IHJpZ2h0IF49IHRlbXA7IGxlZnQgXj0gKHRlbXAgPDwgMik7XG4gICAgdGVtcCA9ICgocmlnaHQgPj4+IC0xNikgXiBsZWZ0KSAmIDB4MDAwMGZmZmY7IGxlZnQgXj0gdGVtcDsgcmlnaHQgXj0gKHRlbXAgPDwgLTE2KTtcbiAgICB0ZW1wID0gKChsZWZ0ID4+PiAxKSBeIHJpZ2h0KSAmIDB4NTU1NTU1NTU7IHJpZ2h0IF49IHRlbXA7IGxlZnQgXj0gKHRlbXAgPDwgMSk7XG4gICAgdGVtcCA9ICgocmlnaHQgPj4+IDgpIF4gbGVmdCkgJiAweDAwZmYwMGZmOyBsZWZ0IF49IHRlbXA7IHJpZ2h0IF49ICh0ZW1wIDw8IDgpO1xuICAgIHRlbXAgPSAoKGxlZnQgPj4+IDEpIF4gcmlnaHQpICYgMHg1NTU1NTU1NTsgcmlnaHQgXj0gdGVtcDsgbGVmdCBePSAodGVtcCA8PCAxKTtcblxuICAgIC8vdGhlIHJpZ2h0IHNpZGUgbmVlZHMgdG8gYmUgc2hpZnRlZCBhbmQgdG8gZ2V0IHRoZSBsYXN0IGZvdXIgYml0cyBvZiB0aGUgbGVmdCBzaWRlXG4gICAgdGVtcCA9IChsZWZ0IDw8IDgpIHwgKChyaWdodCA+Pj4gMjApICYgMHgwMDAwMDBmMCk7XG4gICAgLy9sZWZ0IG5lZWRzIHRvIGJlIHB1dCB1cHNpZGUgZG93blxuICAgIGxlZnQgPSAocmlnaHQgPDwgMjQpIHwgKChyaWdodCA8PCA4KSAmIDB4ZmYwMDAwKSB8ICgocmlnaHQgPj4+IDgpICYgMHhmZjAwKSB8ICgocmlnaHQgPj4+IDI0KSAmIDB4ZjApO1xuICAgIHJpZ2h0ID0gdGVtcDtcblxuICAgIC8vbm93IGdvIHRocm91Z2ggYW5kIHBlcmZvcm0gdGhlc2Ugc2hpZnRzIG9uIHRoZSBsZWZ0IGFuZCByaWdodCBrZXlzXG4gICAgZm9yIChpPTA7IGkgPCBzaGlmdHMubGVuZ3RoOyBpKyspIHtcbiAgICAgIC8vc2hpZnQgdGhlIGtleXMgZWl0aGVyIG9uZSBvciB0d28gYml0cyB0byB0aGUgbGVmdFxuICAgICAgaWYgKHNoaWZ0c1tpXSkge2xlZnQgPSAobGVmdCA8PCAyKSB8IChsZWZ0ID4+PiAyNik7IHJpZ2h0ID0gKHJpZ2h0IDw8IDIpIHwgKHJpZ2h0ID4+PiAyNik7fVxuICAgICAgZWxzZSB7bGVmdCA9IChsZWZ0IDw8IDEpIHwgKGxlZnQgPj4+IDI3KTsgcmlnaHQgPSAocmlnaHQgPDwgMSkgfCAocmlnaHQgPj4+IDI3KTt9XG4gICAgICBsZWZ0ICY9IC0weGY7IHJpZ2h0ICY9IC0weGY7XG5cbiAgICAgIC8vbm93IGFwcGx5IFBDLTIsIGluIHN1Y2ggYSB3YXkgdGhhdCBFIGlzIGVhc2llciB3aGVuIGVuY3J5cHRpbmcgb3IgZGVjcnlwdGluZ1xuICAgICAgLy90aGlzIGNvbnZlcnNpb24gd2lsbCBsb29rIGxpa2UgUEMtMiBleGNlcHQgb25seSB0aGUgbGFzdCA2IGJpdHMgb2YgZWFjaCBieXRlIGFyZSB1c2VkXG4gICAgICAvL3JhdGhlciB0aGFuIDQ4IGNvbnNlY3V0aXZlIGJpdHMgYW5kIHRoZSBvcmRlciBvZiBsaW5lcyB3aWxsIGJlIGFjY29yZGluZyB0byBcbiAgICAgIC8vaG93IHRoZSBTIHNlbGVjdGlvbiBmdW5jdGlvbnMgd2lsbCBiZSBhcHBsaWVkOiBTMiwgUzQsIFM2LCBTOCwgUzEsIFMzLCBTNSwgUzdcbiAgICAgIGxlZnR0ZW1wID0gcGMyYnl0ZXMwW2xlZnQgPj4+IDI4XSB8IHBjMmJ5dGVzMVsobGVmdCA+Pj4gMjQpICYgMHhmXVxuICAgICAgICAgICAgICB8IHBjMmJ5dGVzMlsobGVmdCA+Pj4gMjApICYgMHhmXSB8IHBjMmJ5dGVzM1sobGVmdCA+Pj4gMTYpICYgMHhmXVxuICAgICAgICAgICAgICB8IHBjMmJ5dGVzNFsobGVmdCA+Pj4gMTIpICYgMHhmXSB8IHBjMmJ5dGVzNVsobGVmdCA+Pj4gOCkgJiAweGZdXG4gICAgICAgICAgICAgIHwgcGMyYnl0ZXM2WyhsZWZ0ID4+PiA0KSAmIDB4Zl07XG4gICAgICByaWdodHRlbXAgPSBwYzJieXRlczdbcmlnaHQgPj4+IDI4XSB8IHBjMmJ5dGVzOFsocmlnaHQgPj4+IDI0KSAmIDB4Zl1cbiAgICAgICAgICAgICAgICB8IHBjMmJ5dGVzOVsocmlnaHQgPj4+IDIwKSAmIDB4Zl0gfCBwYzJieXRlczEwWyhyaWdodCA+Pj4gMTYpICYgMHhmXVxuICAgICAgICAgICAgICAgIHwgcGMyYnl0ZXMxMVsocmlnaHQgPj4+IDEyKSAmIDB4Zl0gfCBwYzJieXRlczEyWyhyaWdodCA+Pj4gOCkgJiAweGZdXG4gICAgICAgICAgICAgICAgfCBwYzJieXRlczEzWyhyaWdodCA+Pj4gNCkgJiAweGZdO1xuICAgICAgdGVtcCA9ICgocmlnaHR0ZW1wID4+PiAxNikgXiBsZWZ0dGVtcCkgJiAweDAwMDBmZmZmOyBcbiAgICAgIGtleXNbbisrXSA9IGxlZnR0ZW1wIF4gdGVtcDsga2V5c1tuKytdID0gcmlnaHR0ZW1wIF4gKHRlbXAgPDwgMTYpO1xuICAgIH1cbiAgfSAvL2ZvciBlYWNoIGl0ZXJhdGlvbnNcbiAgLy9yZXR1cm4gdGhlIGtleXMgd2UndmUgY3JlYXRlZFxuICByZXR1cm4ga2V5cztcbn0gLy9lbmQgb2YgZGVzX2NyZWF0ZUtleXNcblxuXG5tb2R1bGUuZXhwb3J0cyA9IGRlc2VkZTtcbiIsIlxyXG4vLyBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhIEJTRC1zdHlsZVxyXG4vLyBsaWNlbnNlIHRoYXQgY2FuIGJlIGZvdW5kIGluIHRoZSBMSUNFTlNFIGZpbGUuXHJcblxyXG4vLyBDb3B5cmlnaHQgMjAxMCBwamFjb2JzQHhlZWtyLmNvbSAuIEFsbCByaWdodHMgcmVzZXJ2ZWQuXHJcblxyXG4vLyBNb2RpZmllZCBieSBSZWN1cml0eSBMYWJzIEdtYkhcclxuXHJcbi8vIGZpeGVkL21vZGlmaWVkIGJ5IEhlcmJlcnQgSGFuZXdpbmtlbCwgd3d3LmhhbmVXSU4uZGVcclxuLy8gY2hlY2sgd3d3LmhhbmVXSU4uZGUgZm9yIHRoZSBsYXRlc3QgdmVyc2lvblxyXG5cclxuLy8gY2FzdDUuanMgaXMgYSBKYXZhc2NyaXB0IGltcGxlbWVudGF0aW9uIG9mIENBU1QtMTI4LCBhcyBkZWZpbmVkIGluIFJGQyAyMTQ0LlxyXG4vLyBDQVNULTEyOCBpcyBhIGNvbW1vbiBPcGVuUEdQIGNpcGhlci5cclxuXHJcblxyXG4vLyBDQVNUNSBjb25zdHJ1Y3RvclxyXG5cclxudmFyIHV0aWwgPSByZXF1aXJlKCcuLi8uLi91dGlsJyk7XHJcblxyXG5mdW5jdGlvbiBjYXN0NV9lbmNyeXB0KGJsb2NrLCBrZXkpIHtcclxuXHR2YXIgY2FzdDUgPSBuZXcgb3BlbnBncF9zeW1lbmNfY2FzdDUoKTtcclxuXHRjYXN0NS5zZXRLZXkodXRpbC5zdHIyYmluKGtleSkpO1xyXG5cdHJldHVybiBjYXN0NS5lbmNyeXB0KGJsb2NrKTtcclxufVxyXG5cclxuZnVuY3Rpb24gb3BlbnBncF9zeW1lbmNfY2FzdDUoKSB7XHJcblx0dGhpcy5CbG9ja1NpemU9IDg7XHJcblx0dGhpcy5LZXlTaXplID0gMTY7XHJcblxyXG5cdHRoaXMuc2V0S2V5ID0gZnVuY3Rpb24gKGtleSkge1xyXG5cdFx0IHRoaXMubWFza2luZyA9IG5ldyBBcnJheSgxNik7XHJcblx0XHQgdGhpcy5yb3RhdGUgPSBuZXcgQXJyYXkoMTYpO1xyXG5cclxuXHRcdCB0aGlzLnJlc2V0KCk7XHJcblxyXG5cdFx0IGlmIChrZXkubGVuZ3RoID09IHRoaXMuS2V5U2l6ZSlcclxuXHRcdCB7XHJcblx0XHQgICB0aGlzLmtleVNjaGVkdWxlKGtleSk7XHJcblx0XHQgfVxyXG5cdFx0IGVsc2VcclxuXHRcdCB7XHJcblx0XHQgICB1dGlsLnByaW50X2Vycm9yKCdjYXN0NS5qczogQ0FTVC0xMjg6IGtleXMgbXVzdCBiZSAxNiBieXRlcycpO1xyXG5cdFx0ICAgcmV0dXJuIGZhbHNlO1xyXG5cdFx0IH1cclxuXHRcdCByZXR1cm4gdHJ1ZTtcclxuXHR9O1xyXG5cdFxyXG5cdHRoaXMucmVzZXQgPSBmdW5jdGlvbigpIHtcclxuXHRcdCBmb3IgKHZhciBpID0gMDsgaSA8IDE2OyBpKyspXHJcblx0XHQge1xyXG5cdFx0ICB0aGlzLm1hc2tpbmdbaV0gPSAwO1xyXG5cdFx0ICB0aGlzLnJvdGF0ZVtpXSA9IDA7XHJcblx0XHQgfVxyXG5cdH07XHJcblxyXG5cdHRoaXMuZ2V0QmxvY2tTaXplID0gZnVuY3Rpb24oKSB7XHJcblx0XHQgcmV0dXJuIEJsb2NrU2l6ZTtcclxuXHR9O1xyXG5cclxuXHR0aGlzLmVuY3J5cHQgPSBmdW5jdGlvbihzcmMpIHtcclxuXHRcdCB2YXIgZHN0ID0gbmV3IEFycmF5KHNyYy5sZW5ndGgpO1xyXG5cclxuXHRcdCBmb3IodmFyIGkgPSAwOyBpIDwgc3JjLmxlbmd0aDsgaSs9OClcclxuXHRcdCB7XHJcblx0XHQgIHZhciBsID0gc3JjW2ldPDwyNCB8IHNyY1tpKzFdPDwxNiB8IHNyY1tpKzJdPDw4IHwgc3JjW2krM107XHJcblx0XHQgIHZhciByID0gc3JjW2krNF08PDI0IHwgc3JjW2krNV08PDE2IHwgc3JjW2krNl08PDggfCBzcmNbaSs3XTtcclxuXHRcdCAgdmFyIHQ7XHJcblxyXG5cdFx0ICB0ID0gcjsgciA9IGxeZjEociwgdGhpcy5tYXNraW5nWzBdLCB0aGlzLnJvdGF0ZVswXSk7IGwgPSB0O1xyXG5cdFx0ICB0ID0gcjsgciA9IGxeZjIociwgdGhpcy5tYXNraW5nWzFdLCB0aGlzLnJvdGF0ZVsxXSk7IGwgPSB0O1xyXG5cdFx0ICB0ID0gcjsgciA9IGxeZjMociwgdGhpcy5tYXNraW5nWzJdLCB0aGlzLnJvdGF0ZVsyXSk7IGwgPSB0O1xyXG5cdFx0ICB0ID0gcjsgciA9IGxeZjEociwgdGhpcy5tYXNraW5nWzNdLCB0aGlzLnJvdGF0ZVszXSk7IGwgPSB0O1xyXG5cclxuXHRcdCAgdCA9IHI7IHIgPSBsXmYyKHIsIHRoaXMubWFza2luZ1s0XSwgdGhpcy5yb3RhdGVbNF0pOyBsID0gdDtcclxuXHRcdCAgdCA9IHI7IHIgPSBsXmYzKHIsIHRoaXMubWFza2luZ1s1XSwgdGhpcy5yb3RhdGVbNV0pOyBsID0gdDtcclxuXHRcdCAgdCA9IHI7IHIgPSBsXmYxKHIsIHRoaXMubWFza2luZ1s2XSwgdGhpcy5yb3RhdGVbNl0pOyBsID0gdDtcclxuXHRcdCAgdCA9IHI7IHIgPSBsXmYyKHIsIHRoaXMubWFza2luZ1s3XSwgdGhpcy5yb3RhdGVbN10pOyBsID0gdDtcclxuXHJcblx0XHQgIHQgPSByOyByID0gbF5mMyhyLCB0aGlzLm1hc2tpbmdbOF0sIHRoaXMucm90YXRlWzhdKTsgbCA9IHQ7XHJcblx0XHQgIHQgPSByOyByID0gbF5mMShyLCB0aGlzLm1hc2tpbmdbOV0sIHRoaXMucm90YXRlWzldKTsgbCA9IHQ7XHJcblx0XHQgIHQgPSByOyByID0gbF5mMihyLCB0aGlzLm1hc2tpbmdbMTBdLCB0aGlzLnJvdGF0ZVsxMF0pOyBsID0gdDtcclxuXHRcdCAgdCA9IHI7IHIgPSBsXmYzKHIsIHRoaXMubWFza2luZ1sxMV0sIHRoaXMucm90YXRlWzExXSk7IGwgPSB0O1xyXG5cclxuXHRcdCAgdCA9IHI7IHIgPSBsXmYxKHIsIHRoaXMubWFza2luZ1sxMl0sIHRoaXMucm90YXRlWzEyXSk7IGwgPSB0O1xyXG5cdFx0ICB0ID0gcjsgciA9IGxeZjIociwgdGhpcy5tYXNraW5nWzEzXSwgdGhpcy5yb3RhdGVbMTNdKTsgbCA9IHQ7XHJcblx0XHQgIHQgPSByOyByID0gbF5mMyhyLCB0aGlzLm1hc2tpbmdbMTRdLCB0aGlzLnJvdGF0ZVsxNF0pOyBsID0gdDtcclxuXHRcdCAgdCA9IHI7IHIgPSBsXmYxKHIsIHRoaXMubWFza2luZ1sxNV0sIHRoaXMucm90YXRlWzE1XSk7IGwgPSB0O1xyXG5cclxuXHRcdCAgZHN0W2ldICAgPSAociA+Pj4gMjQpJjI1NTtcclxuXHRcdCAgZHN0W2krMV0gPSAociA+Pj4gMTYpJjI1NTtcclxuXHRcdCAgZHN0W2krMl0gPSAociA+Pj4gOCkmMjU1O1xyXG5cdFx0ICBkc3RbaSszXSA9IHImMjU1O1xyXG5cdFx0ICBkc3RbaSs0XSA9IChsID4+PiAyNCkmMjU1O1xyXG5cdFx0ICBkc3RbaSs1XSA9IChsID4+PiAxNikmMjU1O1xyXG5cdFx0ICBkc3RbaSs2XSA9IChsID4+PiA4KSYyNTU7XHJcblx0XHQgIGRzdFtpKzddID0gbCYyNTU7XHJcblx0XHQgfVxyXG5cclxuXHRcdCByZXR1cm4gZHN0O1xyXG5cdH07XHJcblx0XHJcblx0dGhpcy5kZWNyeXB0ID0gZnVuY3Rpb24oc3JjKSB7XHJcblx0XHQgdmFyIGRzdCA9IG5ldyBBcnJheShzcmMubGVuZ3RoKTtcclxuXHJcblx0XHQgZm9yKHZhciBpID0gMDsgaSA8IHNyYy5sZW5ndGg7IGkrPTgpXHJcblx0XHQge1xyXG5cdFx0ICB2YXIgbCA9IHNyY1tpXTw8MjQgfCBzcmNbaSsxXTw8MTYgfCBzcmNbaSsyXTw8OCB8IHNyY1tpKzNdO1xyXG5cdFx0ICB2YXIgciA9IHNyY1tpKzRdPDwyNCB8IHNyY1tpKzVdPDwxNiB8IHNyY1tpKzZdPDw4IHwgc3JjW2krN107XHJcblx0XHQgIHZhciB0O1xyXG5cclxuXHRcdCAgdCA9IHI7IHIgPSBsXmYxKHIsIHRoaXMubWFza2luZ1sxNV0sIHRoaXMucm90YXRlWzE1XSk7IGwgPSB0O1xyXG5cdFx0ICB0ID0gcjsgciA9IGxeZjMociwgdGhpcy5tYXNraW5nWzE0XSwgdGhpcy5yb3RhdGVbMTRdKTsgbCA9IHQ7XHJcblx0XHQgIHQgPSByOyByID0gbF5mMihyLCB0aGlzLm1hc2tpbmdbMTNdLCB0aGlzLnJvdGF0ZVsxM10pOyBsID0gdDtcclxuXHRcdCAgdCA9IHI7IHIgPSBsXmYxKHIsIHRoaXMubWFza2luZ1sxMl0sIHRoaXMucm90YXRlWzEyXSk7IGwgPSB0O1xyXG5cclxuXHRcdCAgdCA9IHI7IHIgPSBsXmYzKHIsIHRoaXMubWFza2luZ1sxMV0sIHRoaXMucm90YXRlWzExXSk7IGwgPSB0O1xyXG5cdFx0ICB0ID0gcjsgciA9IGxeZjIociwgdGhpcy5tYXNraW5nWzEwXSwgdGhpcy5yb3RhdGVbMTBdKTsgbCA9IHQ7XHJcblx0XHQgIHQgPSByOyByID0gbF5mMShyLCB0aGlzLm1hc2tpbmdbOV0sIHRoaXMucm90YXRlWzldKTsgbCA9IHQ7XHJcblx0XHQgIHQgPSByOyByID0gbF5mMyhyLCB0aGlzLm1hc2tpbmdbOF0sIHRoaXMucm90YXRlWzhdKTsgbCA9IHQ7XHJcblxyXG5cdFx0ICB0ID0gcjsgciA9IGxeZjIociwgdGhpcy5tYXNraW5nWzddLCB0aGlzLnJvdGF0ZVs3XSk7IGwgPSB0O1xyXG5cdFx0ICB0ID0gcjsgciA9IGxeZjEociwgdGhpcy5tYXNraW5nWzZdLCB0aGlzLnJvdGF0ZVs2XSk7IGwgPSB0O1xyXG5cdFx0ICB0ID0gcjsgciA9IGxeZjMociwgdGhpcy5tYXNraW5nWzVdLCB0aGlzLnJvdGF0ZVs1XSk7IGwgPSB0O1xyXG5cdFx0ICB0ID0gcjsgciA9IGxeZjIociwgdGhpcy5tYXNraW5nWzRdLCB0aGlzLnJvdGF0ZVs0XSk7IGwgPSB0O1xyXG5cclxuXHRcdCAgdCA9IHI7IHIgPSBsXmYxKHIsIHRoaXMubWFza2luZ1szXSwgdGhpcy5yb3RhdGVbM10pOyBsID0gdDtcclxuXHRcdCAgdCA9IHI7IHIgPSBsXmYzKHIsIHRoaXMubWFza2luZ1syXSwgdGhpcy5yb3RhdGVbMl0pOyBsID0gdDtcclxuXHRcdCAgdCA9IHI7IHIgPSBsXmYyKHIsIHRoaXMubWFza2luZ1sxXSwgdGhpcy5yb3RhdGVbMV0pOyBsID0gdDtcclxuXHRcdCAgdCA9IHI7IHIgPSBsXmYxKHIsIHRoaXMubWFza2luZ1swXSwgdGhpcy5yb3RhdGVbMF0pOyBsID0gdDtcclxuXHJcblx0XHQgIGRzdFtpXSAgID0gKHIgPj4+IDI0KSYyNTU7XHJcblx0XHQgIGRzdFtpKzFdID0gKHIgPj4+IDE2KSYyNTU7XHJcblx0XHQgIGRzdFtpKzJdID0gKHIgPj4+IDgpJjI1NTtcclxuXHRcdCAgZHN0W2krM10gPSByJjI1NTtcclxuXHRcdCAgZHN0W2krNF0gPSAobCA+Pj4gMjQpJjI1NTtcclxuXHRcdCAgZHN0W2krNV0gPSAobCA+PiAxNikmMjU1O1xyXG5cdFx0ICBkc3RbaSs2XSA9IChsID4+IDgpJjI1NTtcclxuXHRcdCAgZHN0W2krN10gPSBsJjI1NTtcclxuXHRcdCB9XHJcblxyXG5cdFx0IHJldHVybiBkc3Q7XHJcblx0XHR9O1xyXG5cdFx0dmFyIHNjaGVkdWxlQSA9IG5ldyBBcnJheSg0KTtcclxuXHJcblx0XHRzY2hlZHVsZUFbMF0gPSBuZXcgQXJyYXkoNCk7XHJcblx0XHRzY2hlZHVsZUFbMF1bMF0gPSBuZXcgQXJyYXkoNCwgMCwgMHhkLCAweGYsIDB4YywgMHhlLCAweDgpO1xyXG5cdFx0c2NoZWR1bGVBWzBdWzFdID0gbmV3IEFycmF5KDUsIDIsIDE2ICsgMCwgMTYgKyAyLCAxNiArIDEsIDE2ICsgMywgMHhhKTtcclxuXHRcdHNjaGVkdWxlQVswXVsyXSA9IG5ldyBBcnJheSg2LCAzLCAxNiArIDcsIDE2ICsgNiwgMTYgKyA1LCAxNiArIDQsIDkpO1xyXG5cdFx0c2NoZWR1bGVBWzBdWzNdID0gbmV3IEFycmF5KDcsIDEsIDE2ICsgMHhhLCAxNiArIDksIDE2ICsgMHhiLCAxNiArIDgsIDB4Yik7XHJcblxyXG5cdFx0c2NoZWR1bGVBWzFdID0gbmV3IEFycmF5KDQpO1xyXG5cdFx0c2NoZWR1bGVBWzFdWzBdID0gbmV3IEFycmF5KDAsIDYsIDE2ICsgNSwgMTYgKyA3LCAxNiArIDQsIDE2ICsgNiwgMTYgKyAwKTtcclxuXHRcdHNjaGVkdWxlQVsxXVsxXSA9IG5ldyBBcnJheSgxLCA0LCAwLCAyLCAxLCAzLCAxNiArIDIpO1xyXG5cdFx0c2NoZWR1bGVBWzFdWzJdID0gbmV3IEFycmF5KDIsIDUsIDcsIDYsIDUsIDQsIDE2ICsgMSk7XHJcblx0XHRzY2hlZHVsZUFbMV1bM10gPSBuZXcgQXJyYXkoMywgNywgMHhhLCA5LCAweGIsIDgsIDE2ICsgMyk7XHJcblxyXG5cdFx0c2NoZWR1bGVBWzJdID0gbmV3IEFycmF5KDQpO1xyXG5cdFx0c2NoZWR1bGVBWzJdWzBdID0gbmV3IEFycmF5KDQsIDAsIDB4ZCwgMHhmLCAweGMsIDB4ZSwgOCk7XHJcblx0XHRzY2hlZHVsZUFbMl1bMV0gPSBuZXcgQXJyYXkoNSwgMiwgMTYgKyAwLCAxNiArIDIsIDE2ICsgMSwgMTYgKyAzLCAweGEpO1xyXG5cdFx0c2NoZWR1bGVBWzJdWzJdID0gbmV3IEFycmF5KDYsIDMsIDE2ICsgNywgMTYgKyA2LCAxNiArIDUsIDE2ICsgNCwgOSk7XHJcblx0XHRzY2hlZHVsZUFbMl1bM10gPSBuZXcgQXJyYXkoNywgMSwgMTYgKyAweGEsIDE2ICsgOSwgMTYgKyAweGIsIDE2ICsgOCwgMHhiKTtcclxuXHJcblxyXG5cdFx0c2NoZWR1bGVBWzNdID0gbmV3IEFycmF5KDQpO1xyXG5cdFx0c2NoZWR1bGVBWzNdWzBdID0gbmV3IEFycmF5KDAsIDYsIDE2ICsgNSwgMTYgKyA3LCAxNiArIDQsIDE2ICsgNiwgMTYgKyAwKTtcclxuXHRcdHNjaGVkdWxlQVszXVsxXSA9IG5ldyBBcnJheSgxLCA0LCAwLCAyLCAxLCAzLCAxNiArIDIpO1xyXG5cdFx0c2NoZWR1bGVBWzNdWzJdID0gbmV3IEFycmF5KDIsIDUsIDcsIDYsIDUsIDQsIDE2ICsgMSk7XHJcblx0XHRzY2hlZHVsZUFbM11bM10gPSBuZXcgQXJyYXkoMywgNywgMHhhLCA5LCAweGIsIDgsIDE2ICsgMyk7XHJcblxyXG5cdFx0dmFyIHNjaGVkdWxlQiA9IG5ldyBBcnJheSg0KTtcclxuXHJcblx0XHRzY2hlZHVsZUJbMF0gPSBuZXcgQXJyYXkoNCk7XHJcblx0XHRzY2hlZHVsZUJbMF1bMF0gPSBuZXcgQXJyYXkoMTYgKyA4LCAxNiArIDksIDE2ICsgNywgMTYgKyA2LCAxNiArIDIpO1xyXG5cdFx0c2NoZWR1bGVCWzBdWzFdID0gbmV3IEFycmF5KDE2ICsgMHhhLCAxNiArIDB4YiwgMTYgKyA1LCAxNiArIDQsIDE2ICsgNik7XHJcblx0XHRzY2hlZHVsZUJbMF1bMl0gPSBuZXcgQXJyYXkoMTYgKyAweGMsIDE2ICsgMHhkLCAxNiArIDMsIDE2ICsgMiwgMTYgKyA5KTtcclxuXHRcdHNjaGVkdWxlQlswXVszXSA9IG5ldyBBcnJheSgxNiArIDB4ZSwgMTYgKyAweGYsIDE2ICsgMSwgMTYgKyAwLCAxNiArIDB4Yyk7XHJcblxyXG5cdFx0c2NoZWR1bGVCWzFdID0gbmV3IEFycmF5KDQpO1xyXG5cdFx0c2NoZWR1bGVCWzFdWzBdID0gbmV3IEFycmF5KDMsIDIsIDB4YywgMHhkLCA4KTtcclxuXHRcdHNjaGVkdWxlQlsxXVsxXSA9IG5ldyBBcnJheSgxLCAwLCAweGUsIDB4ZiwgMHhkKTtcclxuXHRcdHNjaGVkdWxlQlsxXVsyXSA9IG5ldyBBcnJheSg3LCA2LCA4LCA5LCAzKTtcclxuXHRcdHNjaGVkdWxlQlsxXVszXSA9IG5ldyBBcnJheSg1LCA0LCAweGEsIDB4YiwgNyk7XHJcblxyXG5cclxuXHRcdHNjaGVkdWxlQlsyXSA9IG5ldyBBcnJheSg0KTtcclxuXHRcdHNjaGVkdWxlQlsyXVswXSA9IG5ldyBBcnJheSgxNiArIDMsIDE2ICsgMiwgMTYgKyAweGMsIDE2ICsgMHhkLCAxNiArIDkpO1xyXG5cdFx0c2NoZWR1bGVCWzJdWzFdID0gbmV3IEFycmF5KDE2ICsgMSwgMTYgKyAwLCAxNiArIDB4ZSwgMTYgKyAweGYsIDE2ICsgMHhjKTtcclxuXHRcdHNjaGVkdWxlQlsyXVsyXSA9IG5ldyBBcnJheSgxNiArIDcsIDE2ICsgNiwgMTYgKyA4LCAxNiArIDksIDE2ICsgMik7XHJcblx0XHRzY2hlZHVsZUJbMl1bM10gPSBuZXcgQXJyYXkoMTYgKyA1LCAxNiArIDQsIDE2ICsgMHhhLCAxNiArIDB4YiwgMTYgKyA2KTtcclxuXHJcblxyXG5cdFx0c2NoZWR1bGVCWzNdID0gbmV3IEFycmF5KDQpO1xyXG5cdFx0c2NoZWR1bGVCWzNdWzBdID0gbmV3IEFycmF5KDgsIDksIDcsIDYsIDMpO1xyXG5cdFx0c2NoZWR1bGVCWzNdWzFdID0gbmV3IEFycmF5KDB4YSwgMHhiLCA1LCA0LCA3KTtcclxuXHRcdHNjaGVkdWxlQlszXVsyXSA9IG5ldyBBcnJheSgweGMsIDB4ZCwgMywgMiwgOCk7XHJcblx0XHRzY2hlZHVsZUJbM11bM10gPSBuZXcgQXJyYXkoMHhlLCAweGYsIDEsIDAsIDB4ZCk7XHJcblxyXG5cdFx0Ly8gY2hhbmdlZCAnaW4nIHRvICdpbm4nIChpbiBqYXZhc2NyaXB0ICdpbicgaXMgYSByZXNlcnZlZCB3b3JkKVxyXG5cdFx0dGhpcy5rZXlTY2hlZHVsZSA9IGZ1bmN0aW9uKGlubilcclxuXHRcdHtcclxuXHRcdCB2YXIgdCA9IG5ldyBBcnJheSg4KTtcclxuXHRcdCB2YXIgayA9IG5ldyBBcnJheSgzMik7XHJcblxyXG5cdFx0IGZvciAodmFyIGkgPSAwOyBpIDwgNDsgaSsrKVxyXG5cdFx0IHtcclxuXHRcdCAgdmFyIGogPSBpICogNDtcclxuXHRcdCAgdFtpXSA9IGlubltqXTw8MjQgfCBpbm5baisxXTw8MTYgfCBpbm5baisyXTw8OCB8IGlubltqKzNdO1xyXG5cdFx0IH1cclxuXHJcblx0XHQgdmFyIHggPSBbNiwgNywgNCwgNV07XHJcblx0XHQgdmFyIGtpID0gMDtcclxuXHJcblx0XHQgZm9yICh2YXIgaGFsZiA9IDA7IGhhbGYgPCAyOyBoYWxmKyspXHJcblx0XHQge1xyXG5cdFx0ICBmb3IgKHZhciByb3VuZCA9IDA7IHJvdW5kIDwgNDsgcm91bmQrKylcclxuXHRcdCAge1xyXG5cdFx0ICAgZm9yICh2YXIgaiA9IDA7IGogPCA0OyBqKyspXHJcblx0XHQgICB7XHJcblx0XHQgICAgdmFyIGEgPSBzY2hlZHVsZUFbcm91bmRdW2pdO1xyXG5cdFx0ICAgIHZhciB3ID0gdFthWzFdXTtcclxuXHJcblx0XHQgICAgdyBePSBzQm94WzRdWyh0W2FbMl0+Pj4yXT4+PigyNC04KihhWzJdJjMpKSkmMHhmZl07XHJcblx0XHQgICAgdyBePSBzQm94WzVdWyh0W2FbM10+Pj4yXT4+PigyNC04KihhWzNdJjMpKSkmMHhmZl07XHJcblx0XHQgICAgdyBePSBzQm94WzZdWyh0W2FbNF0+Pj4yXT4+PigyNC04KihhWzRdJjMpKSkmMHhmZl07XHJcblx0XHQgICAgdyBePSBzQm94WzddWyh0W2FbNV0+Pj4yXT4+PigyNC04KihhWzVdJjMpKSkmMHhmZl07XHJcblx0XHQgICAgdyBePSBzQm94W3hbal1dWyh0W2FbNl0+Pj4yXT4+PigyNC04KihhWzZdJjMpKSkmMHhmZl07XHJcblx0XHQgICAgdFthWzBdXSA9IHc7XHJcblx0XHQgICB9XHJcblxyXG5cdFx0ICAgZm9yICh2YXIgaiA9IDA7IGogPCA0OyBqKyspXHJcblx0XHQgICB7XHJcblx0XHQgICAgdmFyIGIgPSBzY2hlZHVsZUJbcm91bmRdW2pdO1xyXG5cdFx0ICAgIHZhciB3ID0gc0JveFs0XVsodFtiWzBdPj4+Ml0+Pj4oMjQtOCooYlswXSYzKSkpJjB4ZmZdO1xyXG5cclxuXHRcdCAgICB3IF49IHNCb3hbNV1bKHRbYlsxXT4+PjJdPj4+KDI0LTgqKGJbMV0mMykpKSYweGZmXTtcclxuXHRcdCAgICB3IF49IHNCb3hbNl1bKHRbYlsyXT4+PjJdPj4+KDI0LTgqKGJbMl0mMykpKSYweGZmXTtcclxuXHRcdCAgICB3IF49IHNCb3hbN11bKHRbYlszXT4+PjJdPj4+KDI0LTgqKGJbM10mMykpKSYweGZmXTtcclxuXHRcdCAgICB3IF49IHNCb3hbNCtqXVsodFtiWzRdPj4+Ml0+Pj4oMjQtOCooYls0XSYzKSkpJjB4ZmZdO1xyXG5cdFx0ICAgIGtba2ldID0gdztcclxuXHRcdCAgICBraSsrO1xyXG5cdFx0ICAgfVxyXG5cdFx0ICB9XHJcblx0XHQgfVxyXG5cclxuXHRcdCBmb3IgKHZhciBpID0gMDsgaSA8IDE2OyBpKyspXHJcblx0XHQge1xyXG5cdFx0ICB0aGlzLm1hc2tpbmdbaV0gPSBrW2ldO1xyXG5cdFx0ICB0aGlzLnJvdGF0ZVtpXSAgPSBrWzE2K2ldICYgMHgxZjtcclxuXHRcdCB9XHJcblx0XHR9O1xyXG5cclxuXHRcdC8vIFRoZXNlIGFyZSB0aGUgdGhyZWUgJ2YnIGZ1bmN0aW9ucy4gU2VlIFJGQyAyMTQ0LCBzZWN0aW9uIDIuMi5cclxuXHJcblx0XHRmdW5jdGlvbiBmMShkLCBtLCByKVxyXG5cdFx0e1xyXG5cdFx0IHZhciB0ID0gbSArIGQ7XHJcblx0XHQgdmFyIEkgPSAodCA8PCByKSB8ICh0ID4+PiAoMzIgLSByKSk7XHJcblx0XHQgcmV0dXJuICgoc0JveFswXVtJPj4+MjRdIF4gc0JveFsxXVsoST4+PjE2KSYyNTVdKSAtIHNCb3hbMl1bKEk+Pj44KSYyNTVdKSArIHNCb3hbM11bSSYyNTVdO1xyXG5cdFx0fVxyXG5cclxuXHRcdGZ1bmN0aW9uIGYyKGQsIG0sIHIpXHJcblx0XHR7XHJcblx0XHQgdmFyIHQgPSBtIF4gZDtcclxuXHRcdCB2YXIgSSA9ICh0IDw8IHIpIHwgKHQgPj4+ICgzMiAtIHIpKTtcclxuXHRcdCByZXR1cm4gKChzQm94WzBdW0k+Pj4yNF0gLSBzQm94WzFdWyhJPj4+MTYpJjI1NV0pICsgc0JveFsyXVsoST4+PjgpJjI1NV0pIF4gc0JveFszXVtJJjI1NV07XHJcblx0XHR9XHJcblxyXG5cdFx0ZnVuY3Rpb24gZjMoZCwgbSwgcilcclxuXHRcdHtcclxuXHRcdCB2YXIgdCA9IG0gLSBkO1xyXG5cdFx0IHZhciBJID0gKHQgPDwgcikgfCAodCA+Pj4gKDMyIC0gcikpO1xyXG5cdFx0IHJldHVybiAoKHNCb3hbMF1bST4+PjI0XSArIHNCb3hbMV1bKEk+Pj4xNikmMjU1XSkgXiBzQm94WzJdWyhJPj4+OCkmMjU1XSkgLSBzQm94WzNdW0kmMjU1XTtcclxuXHRcdH1cclxuXHJcblx0XHR2YXIgc0JveCA9IG5ldyBBcnJheSg4KTtcclxuXHRcdHNCb3hbMF0gPSBuZXcgQXJyYXkoXHJcblx0XHQgIDB4MzBmYjQwZDQsIDB4OWZhMGZmMGIsIDB4NmJlY2NkMmYsIDB4M2YyNThjN2EsIDB4MWUyMTNmMmYsIDB4OWMwMDRkZDMsIDB4NjAwM2U1NDAsIDB4Y2Y5ZmM5NDksXHJcblx0XHQgIDB4YmZkNGFmMjcsIDB4ODhiYmJkYjUsIDB4ZTIwMzQwOTAsIDB4OThkMDk2NzUsIDB4NmU2M2EwZTAsIDB4MTVjMzYxZDIsIDB4YzJlNzY2MWQsIDB4MjJkNGZmOGUsXHJcblx0XHQgIDB4Mjg2ODNiNmYsIDB4YzA3ZmQwNTksIDB4ZmYyMzc5YzgsIDB4Nzc1ZjUwZTIsIDB4NDNjMzQwZDMsIDB4ZGYyZjg2NTYsIDB4ODg3Y2E0MWEsIDB4YTJkMmJkMmQsXHJcblx0XHQgIDB4YTFjOWUwZDYsIDB4MzQ2YzQ4MTksIDB4NjFiNzZkODcsIDB4MjI1NDBmMmYsIDB4MmFiZTMyZTEsIDB4YWE1NDE2NmIsIDB4MjI1NjhlM2EsIDB4YTJkMzQxZDAsXHJcblx0XHQgIDB4NjZkYjQwYzgsIDB4YTc4NDM5MmYsIDB4MDA0ZGZmMmYsIDB4MmRiOWQyZGUsIDB4OTc5NDNmYWMsIDB4NGE5N2MxZDgsIDB4NTI3NjQ0YjcsIDB4YjVmNDM3YTcsXHJcblx0XHQgIDB4YjgyY2JhZWYsIDB4ZDc1MWQxNTksIDB4NmZmN2YwZWQsIDB4NWEwOTdhMWYsIDB4ODI3YjY4ZDAsIDB4OTBlY2Y1MmUsIDB4MjJiMGMwNTQsIDB4YmM4ZTU5MzUsXHJcblx0XHQgIDB4NGI2ZDJmN2YsIDB4NTBiYjY0YTIsIDB4ZDI2NjQ5MTAsIDB4YmVlNTgxMmQsIDB4YjczMzIyOTAsIDB4ZTkzYjE1OWYsIDB4YjQ4ZWU0MTEsIDB4NGJmZjM0NWQsXHJcblx0XHQgIDB4ZmQ0NWMyNDAsIDB4YWQzMTk3M2YsIDB4YzRmNmQwMmUsIDB4NTVmYzgxNjUsIDB4ZDViMWNhYWQsIDB4YTFhYzJkYWUsIDB4YTJkNGI3NmQsIDB4YzE5YjBjNTAsXHJcblx0XHQgIDB4ODgyMjQwZjIsIDB4MGM2ZTRmMzgsIDB4YTRlNGJmZDcsIDB4NGY1YmEyNzIsIDB4NTY0YzFkMmYsIDB4YzU5YzUzMTksIDB4Yjk0OWUzNTQsIDB4YjA0NjY5ZmUsXHJcblx0XHQgIDB4YjFiNmFiOGEsIDB4YzcxMzU4ZGQsIDB4NjM4NWM1NDUsIDB4MTEwZjkzNWQsIDB4NTc1MzhhZDUsIDB4NmEzOTA0OTMsIDB4ZTYzZDM3ZTAsIDB4MmE1NGY2YjMsXHJcblx0XHQgIDB4M2E3ODdkNWYsIDB4NjI3NmEwYjUsIDB4MTlhNmZjZGYsIDB4N2E0MjIwNmEsIDB4MjlmOWQ0ZDUsIDB4ZjYxYjE4OTEsIDB4YmI3MjI3NWUsIDB4YWE1MDgxNjcsXHJcblx0XHQgIDB4Mzg5MDEwOTEsIDB4YzZiNTA1ZWIsIDB4ODRjN2NiOGMsIDB4MmFkNzVhMGYsIDB4ODc0YTE0MjcsIDB4YTJkMTkzNmIsIDB4MmFkMjg2YWYsIDB4YWE1NmQyOTEsXHJcblx0XHQgIDB4ZDc4OTQzNjAsIDB4NDI1Yzc1MGQsIDB4OTNiMzllMjYsIDB4MTg3MTg0YzksIDB4NmMwMGIzMmQsIDB4NzNlMmJiMTQsIDB4YTBiZWJjM2MsIDB4NTQ2MjM3NzksXHJcblx0XHQgIDB4NjQ0NTllYWIsIDB4M2YzMjhiODIsIDB4NzcxOGNmODIsIDB4NTlhMmNlYTYsIDB4MDRlZTAwMmUsIDB4ODlmZTc4ZTYsIDB4M2ZhYjA5NTAsIDB4MzI1ZmY2YzIsXHJcblx0XHQgIDB4ODEzODNmMDUsIDB4Njk2M2M1YzgsIDB4NzZjYjVhZDYsIDB4ZDQ5OTc0YzksIDB4Y2ExODBkY2YsIDB4MzgwNzgyZDUsIDB4YzdmYTVjZjYsIDB4OGFjMzE1MTEsXHJcblx0XHQgIDB4MzVlNzllMTMsIDB4NDdkYTkxZDAsIDB4ZjQwZjkwODYsIDB4YTdlMjQxOWUsIDB4MzEzNjYyNDEsIDB4MDUxZWY0OTUsIDB4YWE1NzNiMDQsIDB4NGE4MDVkOGQsXHJcblx0XHQgIDB4NTQ4MzAwZDAsIDB4MDAzMjJhM2MsIDB4YmY2NGNkZGYsIDB4YmE1N2E2OGUsIDB4NzVjNjM3MmIsIDB4NTBhZmQzNDEsIDB4YTdjMTMyNzUsIDB4OTE1YTBiZjUsXHJcblx0XHQgIDB4NmI1NGJmYWIsIDB4MmIwYjE0MjYsIDB4YWI0Y2M5ZDcsIDB4NDQ5Y2NkODIsIDB4ZjdmYmYyNjUsIDB4YWI4NWM1ZjMsIDB4MWI1NWRiOTQsIDB4YWFkNGUzMjQsXHJcblx0XHQgIDB4Y2ZhNGJkM2YsIDB4MmRlYWEzZTIsIDB4OWUyMDRkMDIsIDB4YzhiZDI1YWMsIDB4ZWFkZjU1YjMsIDB4ZDViZDllOTgsIDB4ZTMxMjMxYjIsIDB4MmFkNWFkNmMsXHJcblx0XHQgIDB4OTU0MzI5ZGUsIDB4YWRiZTQ1MjgsIDB4ZDg3MTBmNjksIDB4YWE1MWM5MGYsIDB4YWE3ODZiZjYsIDB4MjI1MTNmMWUsIDB4YWE1MWE3OWIsIDB4MmFkMzQ0Y2MsXHJcblx0XHQgIDB4N2I1YTQxZjAsIDB4ZDM3Y2ZiYWQsIDB4MWIwNjk1MDUsIDB4NDFlY2U0OTEsIDB4YjRjMzMyZTYsIDB4MDMyMjY4ZDQsIDB4Yzk2MDBhY2MsIDB4Y2UzODdlNmQsXHJcblx0XHQgIDB4YmY2YmIxNmMsIDB4NmE3MGZiNzgsIDB4MGQwM2Q5YzksIDB4ZDRkZjM5ZGUsIDB4ZTAxMDYzZGEsIDB4NDczNmY0NjQsIDB4NWFkMzI4ZDgsIDB4YjM0N2NjOTYsXHJcblx0XHQgIDB4NzViYjBmYzMsIDB4OTg1MTFiZmIsIDB4NGZmYmNjMzUsIDB4YjU4YmNmNmEsIDB4ZTExZjBhYmMsIDB4YmZjNWZlNGEsIDB4YTcwYWVjMTAsIDB4YWMzOTU3MGEsXHJcblx0XHQgIDB4M2YwNDQ0MmYsIDB4NjE4OGIxNTMsIDB4ZTAzOTdhMmUsIDB4NTcyN2NiNzksIDB4OWNlYjQxOGYsIDB4MWNhY2Q2OGQsIDB4MmFkMzdjOTYsIDB4MDE3NWNiOWQsXHJcblx0XHQgIDB4YzY5ZGZmMDksIDB4Yzc1YjY1ZjAsIDB4ZDlkYjQwZDgsIDB4ZWMwZTc3NzksIDB4NDc0NGVhZDQsIDB4YjExYzMyNzQsIDB4ZGQyNGNiOWUsIDB4N2UxYzU0YmQsXHJcblx0XHQgIDB4ZjAxMTQ0ZjksIDB4ZDIyNDBlYjEsIDB4OTY3NWIzZmQsIDB4YTNhYzM3NTUsIDB4ZDQ3YzI3YWYsIDB4NTFjODVmNGQsIDB4NTY5MDc1OTYsIDB4YTViYjE1ZTYsXHJcblx0XHQgIDB4NTgwMzA0ZjAsIDB4Y2EwNDJjZjEsIDB4MDExYTM3ZWEsIDB4OGRiZmFhZGIsIDB4MzViYTNlNGEsIDB4MzUyNmZmYTAsIDB4YzM3YjRkMDksIDB4YmMzMDZlZDksXHJcblx0XHQgIDB4OThhNTI2NjYsIDB4NTY0OGY3MjUsIDB4ZmY1ZTU2OWQsIDB4MGNlZDYzZDAsIDB4N2M2M2IyY2YsIDB4NzAwYjQ1ZTEsIDB4ZDVlYTUwZjEsIDB4ODVhOTI4NzIsXHJcblx0XHQgIDB4YWYxZmJkYTcsIDB4ZDQyMzQ4NzAsIDB4YTc4NzBiZjMsIDB4MmQzYjRkNzksIDB4NDJlMDQxOTgsIDB4MGNkMGVkZTcsIDB4MjY0NzBkYjgsIDB4Zjg4MTgxNGMsXHJcblx0XHQgIDB4NDc0ZDZhZDcsIDB4N2MwYzVlNWMsIDB4ZDEyMzE5NTksIDB4MzgxYjcyOTgsIDB4ZjVkMmY0ZGIsIDB4YWI4Mzg2NTMsIDB4NmUyZjFlMjMsIDB4ODM3MTljOWUsXHJcblx0XHQgIDB4YmQ5MWUwNDYsIDB4OWE1NjQ1NmUsIDB4ZGMzOTIwMGMsIDB4MjBjOGM1NzEsIDB4OTYyYmRhMWMsIDB4ZTFlNjk2ZmYsIDB4YjE0MWFiMDgsIDB4N2NjYTg5YjksXHJcblx0XHQgIDB4MWE2OWU3ODMsIDB4MDJjYzQ4NDMsIDB4YTJmN2M1NzksIDB4NDI5ZWY0N2QsIDB4NDI3YjE2OWMsIDB4NWFjOWYwNDksIDB4ZGQ4ZjBmMDAsIDB4NWM4MTY1YmYpO1xyXG5cclxuXHRcdHNCb3hbMV0gPSBuZXcgQXJyYXkoXHJcblx0XHQgIDB4MWYyMDEwOTQsIDB4ZWYwYmE3NWIsIDB4NjllM2NmN2UsIDB4MzkzZjQzODAsIDB4ZmU2MWNmN2EsIDB4ZWVjNTIwN2EsIDB4NTU4ODljOTQsIDB4NzJmYzA2NTEsXHJcblx0XHQgIDB4YWRhN2VmNzksIDB4NGUxZDcyMzUsIDB4ZDU1YTYzY2UsIDB4ZGUwNDM2YmEsIDB4OTljNDMwZWYsIDB4NWYwYzA3OTQsIDB4MThkY2RiN2QsIDB4YTFkNmVmZjMsXHJcblx0XHQgIDB4YTBiNTJmN2IsIDB4NTllODM2MDUsIDB4ZWUxNWIwOTQsIDB4ZTlmZmQ5MDksIDB4ZGM0NDAwODYsIDB4ZWY5NDQ0NTksIDB4YmE4M2NjYjMsIDB4ZTBjM2NkZmIsXHJcblx0XHQgIDB4ZDFkYTQxODEsIDB4M2IwOTJhYjEsIDB4Zjk5N2YxYzEsIDB4YTVlNmNmN2IsIDB4MDE0MjBkZGIsIDB4ZTRlN2VmNWIsIDB4MjVhMWZmNDEsIDB4ZTE4MGY4MDYsXHJcblx0XHQgIDB4MWZjNDEwODAsIDB4MTc5YmVlN2EsIDB4ZDM3YWM2YTksIDB4ZmU1ODMwYTQsIDB4OThkZThiN2YsIDB4NzdlODNmNGUsIDB4Nzk5MjkyNjksIDB4MjRmYTlmN2IsXHJcblx0XHQgIDB4ZTExM2M4NWIsIDB4YWNjNDAwODMsIDB4ZDc1MDM1MjUsIDB4ZjdlYTYxNWYsIDB4NjIxNDMxNTQsIDB4MGQ1NTRiNjMsIDB4NWQ2ODExMjEsIDB4Yzg2NmMzNTksXHJcblx0XHQgIDB4M2Q2M2NmNzMsIDB4Y2VlMjM0YzAsIDB4ZDRkODdlODcsIDB4NWM2NzJiMjEsIDB4MDcxZjYxODEsIDB4MzlmNzYyN2YsIDB4MzYxZTMwODQsIDB4ZTRlYjU3M2IsXHJcblx0XHQgIDB4NjAyZjY0YTQsIDB4ZDYzYWNkOWMsIDB4MWJiYzQ2MzUsIDB4OWU4MTAzMmQsIDB4MjcwMWY1MGMsIDB4OTk4NDdhYjQsIDB4YTBlM2RmNzksIDB4YmE2Y2YzOGMsXHJcblx0XHQgIDB4MTA4NDMwOTQsIDB4MjUzN2E5NWUsIDB4ZjQ2ZjZmZmUsIDB4YTFmZjNiMWYsIDB4MjA4Y2ZiNmEsIDB4OGY0NThjNzQsIDB4ZDllMGEyMjcsIDB4NGVjNzNhMzQsXHJcblx0XHQgIDB4ZmM4ODRmNjksIDB4M2U0ZGU4ZGYsIDB4ZWYwZTAwODgsIDB4MzU1OTY0OGQsIDB4OGE0NTM4OGMsIDB4MWQ4MDQzNjYsIDB4NzIxZDliZmQsIDB4YTU4Njg0YmIsXHJcblx0XHQgIDB4ZTgyNTYzMzMsIDB4ODQ0ZTgyMTIsIDB4MTI4ZDgwOTgsIDB4ZmVkMzNmYjQsIDB4Y2UyODBhZTEsIDB4MjdlMTliYTUsIDB4ZDVhNmMyNTIsIDB4ZTQ5NzU0YmQsXHJcblx0XHQgIDB4YzVkNjU1ZGQsIDB4ZWI2NjcwNjQsIDB4Nzc4NDBiNGQsIDB4YTFiNmE4MDEsIDB4ODRkYjI2YTksIDB4ZTBiNTY3MTQsIDB4MjFmMDQzYjcsIDB4ZTVkMDU4NjAsXHJcblx0XHQgIDB4NTRmMDMwODQsIDB4MDY2ZmY0NzIsIDB4YTMxYWExNTMsIDB4ZGFkYzQ3NTUsIDB4YjU2MjVkYmYsIDB4Njg1NjFiZTYsIDB4ODNjYTZiOTQsIDB4MmQ2ZWQyM2IsXHJcblx0XHQgIDB4ZWNjZjAxZGIsIDB4YTZkM2QwYmEsIDB4YjY4MDNkNWMsIDB4YWY3N2E3MDksIDB4MzNiNGEzNGMsIDB4Mzk3YmM4ZDYsIDB4NWVlMjJiOTUsIDB4NWYwZTUzMDQsXHJcblx0XHQgIDB4ODFlZDZmNjEsIDB4MjBlNzQzNjQsIDB4YjQ1ZTEzNzgsIDB4ZGUxODYzOWIsIDB4ODgxY2ExMjIsIDB4Yjk2NzI2ZDEsIDB4ODA0OWE3ZTgsIDB4MjJiN2RhN2IsXHJcblx0XHQgIDB4NWU1NTJkMjUsIDB4NTI3MmQyMzcsIDB4NzlkMjk1MWMsIDB4YzYwZDg5NGMsIDB4NDg4Y2I0MDIsIDB4MWJhNGZlNWIsIDB4YTRiMDlmNmIsIDB4MWNhODE1Y2YsXHJcblx0XHQgIDB4YTIwYzMwMDUsIDB4ODg3MWRmNjMsIDB4YjlkZTJmY2IsIDB4MGNjNmM5ZTksIDB4MGJlZWZmNTMsIDB4ZTMyMTQ1MTcsIDB4YjQ1NDI4MzUsIDB4OWY2MzI5M2MsXHJcblx0XHQgIDB4ZWU0MWU3MjksIDB4NmUxZDJkN2MsIDB4NTAwNDUyODYsIDB4MWU2Njg1ZjMsIDB4ZjMzNDAxYzYsIDB4MzBhMjJjOTUsIDB4MzFhNzA4NTAsIDB4NjA5MzBmMTMsXHJcblx0XHQgIDB4NzNmOTg0MTcsIDB4YTEyNjk4NTksIDB4ZWM2NDVjNDQsIDB4NTJjODc3YTksIDB4Y2RmZjMzYTYsIDB4YTAyYjE3NDEsIDB4N2NiYWQ5YTIsIDB4MjE4MDAzNmYsXHJcblx0XHQgIDB4NTBkOTljMDgsIDB4Y2IzZjQ4NjEsIDB4YzI2YmQ3NjUsIDB4NjRhM2Y2YWIsIDB4ODAzNDI2NzYsIDB4MjVhNzVlN2IsIDB4ZTRlNmQxZmMsIDB4MjBjNzEwZTYsXHJcblx0XHQgIDB4Y2RmMGI2ODAsIDB4MTc4NDRkM2IsIDB4MzFlZWY4NGQsIDB4N2UwODI0ZTQsIDB4MmNjYjQ5ZWIsIDB4ODQ2YTNiYWUsIDB4OGZmNzc4ODgsIDB4ZWU1ZDYwZjYsXHJcblx0XHQgIDB4N2FmNzU2NzMsIDB4MmZkZDVjZGIsIDB4YTExNjMxYzEsIDB4MzBmNjZmNDMsIDB4YjNmYWVjNTQsIDB4MTU3ZmQ3ZmEsIDB4ZWY4NTc5Y2MsIDB4ZDE1MmRlNTgsXHJcblx0XHQgIDB4ZGIyZmZkNWUsIDB4OGYzMmNlMTksIDB4MzA2YWY5N2EsIDB4MDJmMDNlZjgsIDB4OTkzMTlhZDUsIDB4YzI0MmZhMGYsIDB4YTdlM2ViYjAsIDB4YzY4ZTQ5MDYsXHJcblx0XHQgIDB4YjhkYTIzMGMsIDB4ODA4MjMwMjgsIDB4ZGNkZWYzYzgsIDB4ZDM1ZmIxNzEsIDB4MDg4YTFiYzgsIDB4YmVjMGM1NjAsIDB4NjFhM2M5ZTgsIDB4YmNhOGY1NGQsXHJcblx0XHQgIDB4YzcyZmVmZmEsIDB4MjI4MjJlOTksIDB4ODJjNTcwYjQsIDB4ZDhkOTRlODksIDB4OGIxYzM0YmMsIDB4MzAxZTE2ZTYsIDB4MjczYmU5NzksIDB4YjBmZmVhYTYsXHJcblx0XHQgIDB4NjFkOWI4YzYsIDB4MDBiMjQ4NjksIDB4YjdmZmNlM2YsIDB4MDhkYzI4M2IsIDB4NDNkYWY2NWEsIDB4ZjdlMTk3OTgsIDB4NzYxOWI3MmYsIDB4OGYxYzliYTQsXHJcblx0XHQgIDB4ZGM4NjM3YTAsIDB4MTZhN2QzYjEsIDB4OWZjMzkzYjcsIDB4YTcxMzZlZWIsIDB4YzZiY2M2M2UsIDB4MWE1MTM3NDIsIDB4ZWY2ODI4YmMsIDB4NTIwMzY1ZDYsXHJcblx0XHQgIDB4MmQ2YTc3YWIsIDB4MzUyN2VkNGIsIDB4ODIxZmQyMTYsIDB4MDk1YzZlMmUsIDB4ZGI5MmYyZmIsIDB4NWVlYTI5Y2IsIDB4MTQ1ODkyZjUsIDB4OTE1ODRmN2YsXHJcblx0XHQgIDB4NTQ4MzY5N2IsIDB4MjY2N2E4Y2MsIDB4ODUxOTYwNDgsIDB4OGM0YmFjZWEsIDB4ODMzODYwZDQsIDB4MGQyM2UwZjksIDB4NmMzODdlOGEsIDB4MGFlNmQyNDksXHJcblx0XHQgIDB4YjI4NDYwMGMsIDB4ZDgzNTczMWQsIDB4ZGNiMWM2NDcsIDB4YWM0YzU2ZWEsIDB4M2ViZDgxYjMsIDB4MjMwZWFiYjAsIDB4NjQzOGJjODcsIDB4ZjBiNWIxZmEsXHJcblx0XHQgIDB4OGY1ZWEyYjMsIDB4ZmMxODQ2NDIsIDB4MGEwMzZiN2EsIDB4NGZiMDg5YmQsIDB4NjQ5ZGE1ODksIDB4YTM0NTQxNWUsIDB4NWMwMzgzMjMsIDB4M2U1ZDNiYjksXHJcblx0XHQgIDB4NDNkNzk1NzIsIDB4N2U2ZGQwN2MsIDB4MDZkZmRmMWUsIDB4NmM2Y2M0ZWYsIDB4NzE2MGE1MzksIDB4NzNiZmJlNzAsIDB4ODM4Nzc2MDUsIDB4NDUyM2VjZjEpO1xyXG5cclxuXHRcdHNCb3hbMl0gPSBuZXcgQXJyYXkoXHJcblx0XHQgIDB4OGRlZmMyNDAsIDB4MjVmYTVkOWYsIDB4ZWI5MDNkYmYsIDB4ZTgxMGM5MDcsIDB4NDc2MDdmZmYsIDB4MzY5ZmU0NGIsIDB4OGMxZmM2NDQsIDB4YWVjZWNhOTAsXHJcblx0XHQgIDB4YmViMWY5YmYsIDB4ZWVmYmNhZWEsIDB4ZThjZjE5NTAsIDB4NTFkZjA3YWUsIDB4OTIwZTg4MDYsIDB4ZjBhZDA1NDgsIDB4ZTEzYzhkODMsIDB4OTI3MDEwZDUsXHJcblx0XHQgIDB4MTExMDdkOWYsIDB4MDc2NDdkYjksIDB4YjJlM2U0ZDQsIDB4M2Q0ZjI4NWUsIDB4YjlhZmE4MjAsIDB4ZmFkZTgyZTAsIDB4YTA2NzI2OGIsIDB4ODI3Mjc5MmUsXHJcblx0XHQgIDB4NTUzZmIyYzAsIDB4NDg5YWUyMmIsIDB4ZDRlZjk3OTQsIDB4MTI1ZTNmYmMsIDB4MjFmZmZjZWUsIDB4ODI1YjFiZmQsIDB4OTI1NWM1ZWQsIDB4MTI1N2EyNDAsXHJcblx0XHQgIDB4NGUxYTgzMDIsIDB4YmFlMDdmZmYsIDB4NTI4MjQ2ZTcsIDB4OGU1NzE0MGUsIDB4MzM3M2Y3YmYsIDB4OGM5ZjgxODgsIDB4YTZmYzRlZTgsIDB4Yzk4MmI1YTUsXHJcblx0XHQgIDB4YThjMDFkYjcsIDB4NTc5ZmMyNjQsIDB4NjcwOTRmMzEsIDB4ZjJiZDNmNWYsIDB4NDBmZmY3YzEsIDB4MWZiNzhkZmMsIDB4OGU2YmQyYzEsIDB4NDM3YmU1OWIsXHJcblx0XHQgIDB4OTliMDNkYmYsIDB4YjVkYmM2NGIsIDB4NjM4ZGMwZTYsIDB4NTU4MTlkOTksIDB4YTE5N2M4MWMsIDB4NGEwMTJkNmUsIDB4YzU4ODRhMjgsIDB4Y2NjMzZmNzEsXHJcblx0XHQgIDB4Yjg0M2MyMTMsIDB4NmMwNzQzZjEsIDB4ODMwOTg5M2MsIDB4MGZlZGRkNWYsIDB4MmY3ZmU4NTAsIDB4ZDdjMDdmN2UsIDB4MDI1MDdmYmYsIDB4NWFmYjlhMDQsXHJcblx0XHQgIDB4YTc0N2QyZDAsIDB4MTY1MTE5MmUsIDB4YWY3MGJmM2UsIDB4NThjMzEzODAsIDB4NWY5ODMwMmUsIDB4NzI3Y2MzYzQsIDB4MGEwZmI0MDIsIDB4MGY3ZmVmODIsXHJcblx0XHQgIDB4OGM5NmZkYWQsIDB4NWQyYzJhYWUsIDB4OGVlOTlhNDksIDB4NTBkYTg4YjgsIDB4ODQyN2Y0YTAsIDB4MWVhYzU3OTAsIDB4Nzk2ZmI0NDksIDB4ODI1MmRjMTUsXHJcblx0XHQgIDB4ZWZiZDdkOWIsIDB4YTY3MjU5N2QsIDB4YWRhODQwZDgsIDB4NDVmNTQ1MDQsIDB4ZmE1ZDc0MDMsIDB4ZTgzZWMzMDUsIDB4NGY5MTc1MWEsIDB4OTI1NjY5YzIsXHJcblx0XHQgIDB4MjNlZmU5NDEsIDB4YTkwM2YxMmUsIDB4NjAyNzBkZjIsIDB4MDI3NmU0YjYsIDB4OTRmZDY1NzQsIDB4OTI3OTg1YjIsIDB4ODI3NmRiY2IsIDB4MDI3NzgxNzYsXHJcblx0XHQgIDB4ZjhhZjkxOGQsIDB4NGU0OGY3OWUsIDB4OGY2MTZkZGYsIDB4ZTI5ZDg0MGUsIDB4ODQyZjdkODMsIDB4MzQwY2U1YzgsIDB4OTZiYmI2ODIsIDB4OTNiNGIxNDgsXHJcblx0XHQgIDB4ZWYzMDNjYWIsIDB4OTg0ZmFmMjgsIDB4Nzc5ZmFmOWIsIDB4OTJkYzU2MGQsIDB4MjI0ZDFlMjAsIDB4ODQzN2FhODgsIDB4N2QyOWRjOTYsIDB4Mjc1NmQzZGMsXHJcblx0XHQgIDB4OGI5MDdjZWUsIDB4YjUxZmQyNDAsIDB4ZTdjMDdjZTMsIDB4ZTU2NmI0YTEsIDB4YzNlOTYxNWUsIDB4M2NmODIwOWQsIDB4NjA5NGQxZTMsIDB4Y2Q5Y2EzNDEsXHJcblx0XHQgIDB4NWM3NjQ2MGUsIDB4MDBlYTk4M2IsIDB4ZDRkNjc4ODEsIDB4ZmQ0NzU3MmMsIDB4Zjc2Y2VkZDksIDB4YmRhODIyOWMsIDB4MTI3ZGFkYWEsIDB4NDM4YTA3NGUsXHJcblx0XHQgIDB4MWY5N2MwOTAsIDB4MDgxYmRiOGEsIDB4OTNhMDdlYmUsIDB4YjkzOGNhMTUsIDB4OTdiMDNjZmYsIDB4M2RjMmMwZjgsIDB4OGQxYWIyZWMsIDB4NjQzODBlNTEsXHJcblx0XHQgIDB4NjhjYzdiZmIsIDB4ZDkwZjI3ODgsIDB4MTI0OTAxODEsIDB4NWRlNWZmZDQsIDB4ZGQ3ZWY4NmEsIDB4NzZhMmUyMTQsIDB4YjlhNDAzNjgsIDB4OTI1ZDk1OGYsXHJcblx0XHQgIDB4NGIzOWZmZmEsIDB4YmEzOWFlZTksIDB4YTRmZmQzMGIsIDB4ZmFmNzkzM2IsIDB4NmQ0OTg2MjMsIDB4MTkzY2JjZmEsIDB4Mjc2Mjc1NDUsIDB4ODI1Y2Y0N2EsXHJcblx0XHQgIDB4NjFiZDhiYTAsIDB4ZDExZTQyZDEsIDB4Y2VhZDA0ZjQsIDB4MTI3ZWEzOTIsIDB4MTA0MjhkYjcsIDB4ODI3MmE5NzIsIDB4OTI3MGM0YTgsIDB4MTI3ZGU1MGIsXHJcblx0XHQgIDB4Mjg1YmExYzgsIDB4M2M2MmY0NGYsIDB4MzVjMGVhYTUsIDB4ZTgwNWQyMzEsIDB4NDI4OTI5ZmIsIDB4YjRmY2RmODIsIDB4NGZiNjZhNTMsIDB4MGU3ZGMxNWIsXHJcblx0XHQgIDB4MWYwODFmYWIsIDB4MTA4NjE4YWUsIDB4ZmNmZDA4NmQsIDB4ZjlmZjI4ODksIDB4Njk0YmNjMTEsIDB4MjM2YTVjYWUsIDB4MTJkZWNhNGQsIDB4MmMzZjhjYzUsXHJcblx0XHQgIDB4ZDJkMDJkZmUsIDB4ZjhlZjU4OTYsIDB4ZTRjZjUyZGEsIDB4OTUxNTViNjcsIDB4NDk0YTQ4OGMsIDB4YjliNmE4MGMsIDB4NWM4ZjgyYmMsIDB4ODlkMzZiNDUsXHJcblx0XHQgIDB4M2E2MDk0MzcsIDB4ZWMwMGM5YTksIDB4NDQ3MTUyNTMsIDB4MGE4NzRiNDksIDB4ZDc3M2JjNDAsIDB4N2MzNDY3MWMsIDB4MDI3MTdlZjYsIDB4NGZlYjU1MzYsXHJcblx0XHQgIDB4YTJkMDJmZmYsIDB4ZDJiZjYwYzQsIDB4ZDQzZjAzYzAsIDB4NTBiNGVmNmQsIDB4MDc0NzhjZDEsIDB4MDA2ZTE4ODgsIDB4YTJlNTNmNTUsIDB4YjllNmQ0YmMsXHJcblx0XHQgIDB4YTIwNDgwMTYsIDB4OTc1NzM4MzMsIDB4ZDcyMDdkNjcsIDB4ZGUwZjhmM2QsIDB4NzJmODdiMzMsIDB4YWJjYzRmMzMsIDB4NzY4OGM1NWQsIDB4N2IwMGE2YjAsXHJcblx0XHQgIDB4OTQ3YjAwMDEsIDB4NTcwMDc1ZDIsIDB4ZjliYjg4ZjgsIDB4ODk0MjAxOWUsIDB4NDI2NGE1ZmYsIDB4ODU2MzAyZTAsIDB4NzJkYmQ5MmIsIDB4ZWU5NzFiNjksXHJcblx0XHQgIDB4NmVhMjJmZGUsIDB4NWYwOGFlMmIsIDB4YWY3YTYxNmQsIDB4ZTVjOTg3NjcsIDB4Y2YxZmViZDIsIDB4NjFlZmM4YzIsIDB4ZjFhYzI1NzEsIDB4Y2M4MjM5YzIsXHJcblx0XHQgIDB4NjcyMTRjYjgsIDB4YjFlNTgzZDEsIDB4YjdkYzNlNjIsIDB4N2YxMGJkY2UsIDB4ZjkwYTVjMzgsIDB4MGZmMDQ0M2QsIDB4NjA2ZTZkYzYsIDB4NjA1NDNhNDksXHJcblx0XHQgIDB4NTcyN2MxNDgsIDB4MmJlOThhMWQsIDB4OGFiNDE3MzgsIDB4MjBlMWJlMjQsIDB4YWY5NmRhMGYsIDB4Njg0NTg0MjUsIDB4OTk4MzNiZTUsIDB4NjAwZDQ1N2QsXHJcblx0XHQgIDB4MjgyZjkzNTAsIDB4ODMzNGIzNjIsIDB4ZDkxZDExMjAsIDB4MmI2ZDhkYTAsIDB4NjQyYjFlMzEsIDB4OWMzMDVhMDAsIDB4NTJiY2U2ODgsIDB4MWIwMzU4OGEsXHJcblx0XHQgIDB4ZjdiYWVmZDUsIDB4NDE0MmVkOWMsIDB4YTQzMTVjMTEsIDB4ODMzMjNlYzUsIDB4ZGZlZjQ2MzYsIDB4YTEzM2M1MDEsIDB4ZTlkMzUzMWMsIDB4ZWUzNTM3ODMpO1xyXG5cclxuXHRcdHNCb3hbM10gPSBuZXcgQXJyYXkoXHJcblx0XHQgIDB4OWRiMzA0MjAsIDB4MWZiNmU5ZGUsIDB4YTdiZTdiZWYsIDB4ZDI3M2EyOTgsIDB4NGE0ZjdiZGIsIDB4NjRhZDhjNTcsIDB4ODU1MTA0NDMsIDB4ZmEwMjBlZDEsXHJcblx0XHQgIDB4N2UyODdhZmYsIDB4ZTYwZmI2NjMsIDB4MDk1ZjM1YTEsIDB4NzllYmYxMjAsIDB4ZmQwNTlkNDMsIDB4NjQ5N2I3YjEsIDB4ZjM2NDFmNjMsIDB4MjQxZTRhZGYsXHJcblx0XHQgIDB4MjgxNDdmNWYsIDB4NGZhMmI4Y2QsIDB4Yzk0MzAwNDAsIDB4MGNjMzIyMjAsIDB4ZmRkMzBiMzAsIDB4YzBhNTM3NGYsIDB4MWQyZDAwZDksIDB4MjQxNDdiMTUsXHJcblx0XHQgIDB4ZWU0ZDExMWEsIDB4MGZjYTUxNjcsIDB4NzFmZjkwNGMsIDB4MmQxOTVmZmUsIDB4MWEwNTY0NWYsIDB4MGMxM2ZlZmUsIDB4MDgxYjA4Y2EsIDB4MDUxNzAxMjEsXHJcblx0XHQgIDB4ODA1MzAxMDAsIDB4ZTgzZTVlZmUsIDB4YWM5YWY0ZjgsIDB4N2ZlNzI3MDEsIDB4ZDJiOGVlNWYsIDB4MDZkZjQyNjEsIDB4YmI5ZTliOGEsIDB4NzI5M2VhMjUsXHJcblx0XHQgIDB4Y2U4NGZmZGYsIDB4ZjU3MTg4MDEsIDB4M2RkNjRiMDQsIDB4YTI2ZjI2M2IsIDB4N2VkNDg0MDAsIDB4NTQ3ZWViZTYsIDB4NDQ2ZDRjYTAsIDB4NmNmM2Q2ZjUsXHJcblx0XHQgIDB4MjY0OWFiZGYsIDB4YWVhMGM3ZjUsIDB4MzYzMzhjYzEsIDB4NTAzZjdlOTMsIDB4ZDM3NzIwNjEsIDB4MTFiNjM4ZTEsIDB4NzI1MDBlMDMsIDB4ZjgwZWIyYmIsXHJcblx0XHQgIDB4YWJlMDUwMmUsIDB4ZWM4ZDc3ZGUsIDB4NTc5NzFlODEsIDB4ZTE0ZjY3NDYsIDB4YzkzMzU0MDAsIDB4NjkyMDMxOGYsIDB4MDgxZGJiOTksIDB4ZmZjMzA0YTUsXHJcblx0XHQgIDB4NGQzNTE4MDUsIDB4N2YzZDVjZTMsIDB4YTZjODY2YzYsIDB4NWQ1YmNjYTksIDB4ZGFlYzZmZWEsIDB4OWY5MjZmOTEsIDB4OWY0NjIyMmYsIDB4Mzk5MTQ2N2QsXHJcblx0XHQgIDB4YTViZjZkOGUsIDB4MTE0M2M0NGYsIDB4NDM5NTgzMDIsIDB4ZDAyMTRlZWIsIDB4MDIyMDgzYjgsIDB4M2ZiNjE4MGMsIDB4MThmODkzMWUsIDB4MjgxNjU4ZTYsXHJcblx0XHQgIDB4MjY0ODZlM2UsIDB4OGJkNzhhNzAsIDB4NzQ3N2U0YzEsIDB4YjUwNmUwN2MsIDB4ZjMyZDBhMjUsIDB4NzkwOThiMDIsIDB4ZTRlYWJiODEsIDB4MjgxMjNiMjMsXHJcblx0XHQgIDB4NjlkZWFkMzgsIDB4MTU3NGNhMTYsIDB4ZGY4NzFiNjIsIDB4MjExYzQwYjcsIDB4YTUxYTllZjksIDB4MDAxNDM3N2IsIDB4MDQxZThhYzgsIDB4MDkxMTQwMDMsXHJcblx0XHQgIDB4YmQ1OWU0ZDIsIDB4ZTNkMTU2ZDUsIDB4NGZlODc2ZDUsIDB4MmY5MWEzNDAsIDB4NTU3YmU4ZGUsIDB4MDBlYWU0YTcsIDB4MGNlNWMyZWMsIDB4NGRiNGJiYTYsXHJcblx0XHQgIDB4ZTc1NmJkZmYsIDB4ZGQzMzY5YWMsIDB4ZWMxN2IwMzUsIDB4MDY1NzIzMjcsIDB4OTlhZmM4YjAsIDB4NTZjOGMzOTEsIDB4NmI2NTgxMWMsIDB4NWUxNDYxMTksXHJcblx0XHQgIDB4NmU4NWNiNzUsIDB4YmUwN2MwMDIsIDB4YzIzMjU1NzcsIDB4ODkzZmY0ZWMsIDB4NWJiZmM5MmQsIDB4ZDBlYzNiMjUsIDB4Yjc4MDFhYjcsIDB4OGQ2ZDNiMjQsXHJcblx0XHQgIDB4MjBjNzYzZWYsIDB4YzM2NmE1ZmMsIDB4OWMzODI4ODAsIDB4MGFjZTMyMDUsIDB4YWFjOTU0OGEsIDB4ZWNhMWQ3YzcsIDB4MDQxYWZhMzIsIDB4MWQxNjYyNWEsXHJcblx0XHQgIDB4NjcwMTkwMmMsIDB4OWI3NTdhNTQsIDB4MzFkNDc3ZjcsIDB4OTEyNmIwMzEsIDB4MzZjYzZmZGIsIDB4YzcwYjhiNDYsIDB4ZDllNjZhNDgsIDB4NTZlNTVhNzksXHJcblx0XHQgIDB4MDI2YTRjZWIsIDB4NTI0MzdlZmYsIDB4MmY4Zjc2YjQsIDB4MGRmOTgwYTUsIDB4ODY3NGNkZTMsIDB4ZWRkYTA0ZWIsIDB4MTdhOWJlMDQsIDB4MmMxOGY0ZGYsXHJcblx0XHQgIDB4Yjc3NDdmOWQsIDB4YWIyYWY3YjQsIDB4ZWZjMzRkMjAsIDB4MmUwOTZiN2MsIDB4MTc0MWEyNTQsIDB4ZTViNmEwMzUsIDB4MjEzZDQyZjYsIDB4MmMxYzdjMjYsXHJcblx0XHQgIDB4NjFjMmY1MGYsIDB4NjU1MmRhZjksIDB4ZDJjMjMxZjgsIDB4MjUxMzBmNjksIDB4ZDgxNjdmYTIsIDB4MDQxOGYyYzgsIDB4MDAxYTk2YTYsIDB4MGQxNTI2YWIsXHJcblx0XHQgIDB4NjMzMTVjMjEsIDB4NWUwYTcyZWMsIDB4NDliYWZlZmQsIDB4MTg3OTA4ZDksIDB4OGQwZGJkODYsIDB4MzExMTcwYTcsIDB4M2U5YjY0MGMsIDB4Y2MzZTEwZDcsXHJcblx0XHQgIDB4ZDVjYWQzYjYsIDB4MGNhZWMzODgsIDB4ZjczMDAxZTEsIDB4NmM3MjhhZmYsIDB4NzFlYWUyYTEsIDB4MWY5YWYzNmUsIDB4Y2ZjYmQxMmYsIDB4YzFkZTg0MTcsXHJcblx0XHQgIDB4YWMwN2JlNmIsIDB4Y2I0NGExZDgsIDB4OGI5YjBmNTYsIDB4MDEzOTg4YzMsIDB4YjFjNTJmY2EsIDB4YjRiZTMxY2QsIDB4ZDg3ODI4MDYsIDB4MTJhM2E0ZTIsXHJcblx0XHQgIDB4NmY3ZGU1MzIsIDB4NThmZDdlYjYsIDB4ZDAxZWU5MDAsIDB4MjRhZGZmYzIsIDB4ZjQ5OTBmYzUsIDB4OTcxMWFhYzUsIDB4MDAxZDdiOTUsIDB4ODJlNWU3ZDIsXHJcblx0XHQgIDB4MTA5ODczZjYsIDB4MDA2MTMwOTYsIDB4YzMyZDk1MjEsIDB4YWRhMTIxZmYsIDB4Mjk5MDg0MTUsIDB4N2ZiYjk3N2YsIDB4YWY5ZWIzZGIsIDB4MjljOWVkMmEsXHJcblx0XHQgIDB4NWNlMmE0NjUsIDB4YTczMGYzMmMsIDB4ZDBhYTNmZTgsIDB4OGE1Y2MwOTEsIDB4ZDQ5ZTJjZTcsIDB4MGNlNDU0YTksIDB4ZDYwYWNkODYsIDB4MDE1ZjE5MTksXHJcblx0XHQgIDB4NzcwNzkxMDMsIDB4ZGVhMDNhZjYsIDB4NzhhODU2NWUsIDB4ZGVlMzU2ZGYsIDB4MjFmMDVjYmUsIDB4OGI3NWUzODcsIDB4YjNjNTA2NTEsIDB4YjhhNWMzZWYsXHJcblx0XHQgIDB4ZDhlZWI2ZDIsIDB4ZTUyM2JlNzcsIDB4YzIxNTQ1MjksIDB4MmY2OWVmZGYsIDB4YWZlNjdhZmIsIDB4ZjQ3MGM0YjIsIDB4ZjNlMGViNWIsIDB4ZDZjYzk4NzYsXHJcblx0XHQgIDB4MzllNDQ2MGMsIDB4MWZkYTg1MzgsIDB4MTk4NzgzMmYsIDB4Y2EwMDczNjcsIDB4YTk5MTQ0ZjgsIDB4Mjk2YjI5OWUsIDB4NDkyZmMyOTUsIDB4OTI2NmJlYWIsXHJcblx0XHQgIDB4YjU2NzZlNjksIDB4OWJkM2RkZGEsIDB4ZGY3ZTA1MmYsIDB4ZGIyNTcwMWMsIDB4MWI1ZTUxZWUsIDB4ZjY1MzI0ZTYsIDB4NmFmY2UzNmMsIDB4MDMxNmNjMDQsXHJcblx0XHQgIDB4ODY0NDIxM2UsIDB4YjdkYzU5ZDAsIDB4Nzk2NTI5MWYsIDB4Y2NkNmZkNDMsIDB4NDE4MjM5NzksIDB4OTMyYmNkZjYsIDB4YjY1N2MzNGQsIDB4NGVkZmQyODIsXHJcblx0XHQgIDB4N2FlNTI5MGMsIDB4M2NiOTUzNmIsIDB4ODUxZTIwZmUsIDB4OTgzMzU1N2UsIDB4MTNlY2YwYjAsIDB4ZDNmZmIzNzIsIDB4M2Y4NWM1YzEsIDB4MGFlZjdlZDIpO1xyXG5cclxuXHRcdHNCb3hbNF0gPSBuZXcgQXJyYXkoXHJcblx0XHQgIDB4N2VjOTBjMDQsIDB4MmM2ZTc0YjksIDB4OWIwZTY2ZGYsIDB4YTYzMzc5MTEsIDB4Yjg2YTdmZmYsIDB4MWRkMzU4ZjUsIDB4NDRkZDlkNDQsIDB4MTczMTE2N2YsXHJcblx0XHQgIDB4MDhmYmYxZmEsIDB4ZTdmNTExY2MsIDB4ZDIwNTFiMDAsIDB4NzM1YWJhMDAsIDB4MmFiNzIyZDgsIDB4Mzg2MzgxY2IsIDB4YWNmNjI0M2EsIDB4NjliZWZkN2EsXHJcblx0XHQgIDB4ZTZhMmU3N2YsIDB4ZjBjNzIwY2QsIDB4YzQ0OTQ4MTYsIDB4Y2NmNWMxODAsIDB4Mzg4NTE2NDAsIDB4MTViMGE4NDgsIDB4ZTY4YjE4Y2IsIDB4NGNhYWRlZmYsXHJcblx0XHQgIDB4NWY0ODBhMDEsIDB4MDQxMmIyYWEsIDB4MjU5ODE0ZmMsIDB4NDFkMGVmZTIsIDB4NGU0MGI0OGQsIDB4MjQ4ZWI2ZmIsIDB4OGRiYTFjZmUsIDB4NDFhOTliMDIsXHJcblx0XHQgIDB4MWE1NTBhMDQsIDB4YmE4ZjY1Y2IsIDB4NzI1MWY0ZTcsIDB4OTVhNTE3MjUsIDB4YzEwNmVjZDcsIDB4OTdhNTk4MGEsIDB4YzUzOWI5YWEsIDB4NGQ3OWZlNmEsXHJcblx0XHQgIDB4ZjJmM2Y3NjMsIDB4NjhhZjgwNDAsIDB4ZWQwYzllNTYsIDB4MTFiNDk1OGIsIDB4ZTFlYjVhODgsIDB4ODcwOWU2YjAsIDB4ZDdlMDcxNTYsIDB4NGUyOWZlYTcsXHJcblx0XHQgIDB4NjM2NmU1MmQsIDB4MDJkMWMwMDAsIDB4YzRhYzhlMDUsIDB4OTM3N2Y1NzEsIDB4MGMwNTM3MmEsIDB4NTc4NTM1ZjIsIDB4MjI2MWJlMDIsIDB4ZDY0MmEwYzksXHJcblx0XHQgIDB4ZGYxM2EyODAsIDB4NzRiNTViZDIsIDB4NjgyMTk5YzAsIDB4ZDQyMWU1ZWMsIDB4NTNmYjNjZTgsIDB4YzhhZGVkYjMsIDB4MjhhODdmYzksIDB4M2Q5NTk5ODEsXHJcblx0XHQgIDB4NWMxZmY5MDAsIDB4ZmUzOGQzOTksIDB4MGM0ZWZmMGIsIDB4MDYyNDA3ZWEsIDB4YWEyZjRmYjEsIDB4NGZiOTY5NzYsIDB4OTBjNzk1MDUsIDB4YjBhOGE3NzQsXHJcblx0XHQgIDB4ZWY1NWExZmYsIDB4ZTU5Y2EyYzIsIDB4YTZiNjJkMjcsIDB4ZTY2YTQyNjMsIDB4ZGY2NTAwMWYsIDB4MGVjNTA5NjYsIDB4ZGZkZDU1YmMsIDB4MjlkZTA2NTUsXHJcblx0XHQgIDB4OTExZTczOWEsIDB4MTdhZjg5NzUsIDB4MzJjNzkxMWMsIDB4ODlmODk0NjgsIDB4MGQwMWU5ODAsIDB4NTI0NzU1ZjQsIDB4MDNiNjNjYzksIDB4MGNjODQ0YjIsXHJcblx0XHQgIDB4YmNmM2YwYWEsIDB4ODdhYzM2ZTksIDB4ZTUzYTc0MjYsIDB4MDFiM2Q4MmIsIDB4MWE5ZTc0NDksIDB4NjRlZTJkN2UsIDB4Y2RkYmIxZGEsIDB4MDFjOTQ5MTAsXHJcblx0XHQgIDB4Yjg2OGJmODAsIDB4MGQyNmYzZmQsIDB4OTM0MmVkZTcsIDB4MDRhNWMyODQsIDB4NjM2NzM3YjYsIDB4NTBmNWI2MTYsIDB4ZjI0NzY2ZTMsIDB4OGVjYTM2YzEsXHJcblx0XHQgIDB4MTM2ZTA1ZGIsIDB4ZmVmMTgzOTEsIDB4ZmI4ODdhMzcsIDB4ZDZlN2Y3ZDQsIDB4YzdmYjdkYzksIDB4MzA2M2ZjZGYsIDB4YjZmNTg5ZGUsIDB4ZWMyOTQxZGEsXHJcblx0XHQgIDB4MjZlNDY2OTUsIDB4Yjc1NjY0MTksIDB4ZjY1NGVmYzUsIDB4ZDA4ZDU4YjcsIDB4NDg5MjU0MDEsIDB4YzFiYWNiN2YsIDB4ZTVmZjU1MGYsIDB4YjYwODMwNDksXHJcblx0XHQgIDB4NWJiNWQwZTgsIDB4ODdkNzJlNWEsIDB4YWI2YTZlZTEsIDB4MjIzYTY2Y2UsIDB4YzYyYmYzY2QsIDB4OWUwODg1ZjksIDB4NjhjYjNlNDcsIDB4MDg2YzAxMGYsXHJcblx0XHQgIDB4YTIxZGU4MjAsIDB4ZDE4YjY5ZGUsIDB4ZjNmNjU3NzcsIDB4ZmEwMmMzZjYsIDB4NDA3ZWRhYzMsIDB4Y2JiM2Q1NTAsIDB4MTc5MzA4NGQsIDB4YjBkNzBlYmEsXHJcblx0XHQgIDB4MGFiMzc4ZDUsIDB4ZDk1MWZiMGMsIDB4ZGVkN2RhNTYsIDB4NDEyNGJiZTQsIDB4OTRjYTBiNTYsIDB4MGY1NzU1ZDEsIDB4ZTBlMWU1NmUsIDB4NjE4NGI1YmUsXHJcblx0XHQgIDB4NTgwYTI0OWYsIDB4OTRmNzRiYzAsIDB4ZTMyNzg4OGUsIDB4OWY3YjU1NjEsIDB4YzNkYzAyODAsIDB4MDU2ODc3MTUsIDB4NjQ2YzZiZDcsIDB4NDQ5MDRkYjMsXHJcblx0XHQgIDB4NjZiNGYwYTMsIDB4YzBmMTY0OGEsIDB4Njk3ZWQ1YWYsIDB4NDllOTJmZjYsIDB4MzA5ZTM3NGYsIDB4MmNiNjM1NmEsIDB4ODU4MDg1NzMsIDB4NDk5MWY4NDAsXHJcblx0XHQgIDB4NzZmMGFlMDIsIDB4MDgzYmU4NGQsIDB4Mjg0MjFjOWEsIDB4NDQ0ODk0MDYsIDB4NzM2ZTRjYjgsIDB4YzEwOTI5MTAsIDB4OGJjOTVmYzYsIDB4N2Q4NjljZjQsXHJcblx0XHQgIDB4MTM0ZjYxNmYsIDB4MmU3NzExOGQsIDB4YjMxYjJiZTEsIDB4YWE5MGI0NzIsIDB4M2NhNWQ3MTcsIDB4N2QxNjFiYmEsIDB4OWNhZDkwMTAsIDB4YWY0NjJiYTIsXHJcblx0XHQgIDB4OWZlNDU5ZDIsIDB4NDVkMzQ1NTksIDB4ZDlmMmRhMTMsIDB4ZGJjNjU0ODcsIDB4ZjNlNGY5NGUsIDB4MTc2ZDQ4NmYsIDB4MDk3YzEzZWEsIDB4NjMxZGE1YzcsXHJcblx0XHQgIDB4NDQ1ZjczODIsIDB4MTc1NjgzZjQsIDB4Y2RjNjZhOTcsIDB4NzBiZTAyODgsIDB4YjNjZGNmNzIsIDB4NmU1ZGQyZjMsIDB4MjA5MzYwNzksIDB4NDU5YjgwYTUsXHJcblx0XHQgIDB4YmU2MGUyZGIsIDB4YTljMjMxMDEsIDB4ZWJhNTMxNWMsIDB4MjI0ZTQyZjIsIDB4MWM1YzE1NzIsIDB4ZjY3MjFiMmMsIDB4MWFkMmZmZjMsIDB4OGMyNTQwNGUsXHJcblx0XHQgIDB4MzI0ZWQ3MmYsIDB4NDA2N2I3ZmQsIDB4MDUyMzEzOGUsIDB4NWNhM2JjNzgsIDB4ZGMwZmQ2NmUsIDB4NzU5MjIyODMsIDB4Nzg0ZDZiMTcsIDB4NThlYmIxNmUsXHJcblx0XHQgIDB4NDQwOTRmODUsIDB4M2Y0ODFkODcsIDB4ZmNmZWFlN2IsIDB4NzdiNWZmNzYsIDB4OGMyMzAyYmYsIDB4YWFmNDc1NTYsIDB4NWY0NmIwMmEsIDB4MmIwOTI4MDEsXHJcblx0XHQgIDB4M2QzOGY1ZjcsIDB4MGNhODFmMzYsIDB4NTJhZjRhOGEsIDB4NjZkNWU3YzAsIDB4ZGYzYjA4NzQsIDB4OTUwNTUxMTAsIDB4MWI1YWQ3YTgsIDB4ZjYxZWQ1YWQsXHJcblx0XHQgIDB4NmNmNmU0NzksIDB4MjA3NTgxODQsIDB4ZDBjZWZhNjUsIDB4ODhmN2JlNTgsIDB4NGEwNDY4MjYsIDB4MGZmNmY4ZjMsIDB4YTA5YzdmNzAsIDB4NTM0NmFiYTAsXHJcblx0XHQgIDB4NWNlOTZjMjgsIDB4ZTE3NmVkYTMsIDB4NmJhYzMwN2YsIDB4Mzc2ODI5ZDIsIDB4ODUzNjBmYTksIDB4MTdlM2ZlMmEsIDB4MjRiNzk3NjcsIDB4ZjVhOTZiMjAsXHJcblx0XHQgIDB4ZDZjZDI1OTUsIDB4NjhmZjFlYmYsIDB4NzU1NTQ0MmMsIDB4ZjE5ZjA2YmUsIDB4ZjllMDY1OWEsIDB4ZWViOTQ5MWQsIDB4MzQwMTA3MTgsIDB4YmIzMGNhYjgsXHJcblx0XHQgIDB4ZTgyMmZlMTUsIDB4ODg1NzA5ODMsIDB4NzUwZTYyNDksIDB4ZGE2MjdlNTUsIDB4NWU3NmZmYTgsIDB4YjE1MzQ1NDYsIDB4NmQ0N2RlMDgsIDB4ZWZlOWU3ZDQpO1xyXG5cclxuXHRcdHNCb3hbNV0gPSBuZXcgQXJyYXkoXHJcblx0XHQgIDB4ZjZmYThmOWQsIDB4MmNhYzZjZTEsIDB4NGNhMzQ4NjcsIDB4ZTIzMzdmN2MsIDB4OTVkYjA4ZTcsIDB4MDE2ODQzYjQsIDB4ZWNlZDVjYmMsIDB4MzI1NTUzYWMsXHJcblx0XHQgIDB4YmY5ZjA5NjAsIDB4ZGZhMWUyZWQsIDB4ODNmMDU3OWQsIDB4NjNlZDg2YjksIDB4MWFiNmE2YjgsIDB4ZGU1ZWJlMzksIDB4ZjM4ZmY3MzIsIDB4ODk4OWIxMzgsXHJcblx0XHQgIDB4MzNmMTQ5NjEsIDB4YzAxOTM3YmQsIDB4ZjUwNmM2ZGEsIDB4ZTQ2MjVlN2UsIDB4YTMwOGVhOTksIDB4NGUyM2UzM2MsIDB4NzljYmQ3Y2MsIDB4NDhhMTQzNjcsXHJcblx0XHQgIDB4YTMxNDk2MTksIDB4ZmVjOTRiZDUsIDB4YTExNDE3NGEsIDB4ZWFhMDE4NjYsIDB4YTA4NGRiMmQsIDB4MDlhODQ4NmYsIDB4YTg4ODYxNGEsIDB4MjkwMGFmOTgsXHJcblx0XHQgIDB4MDE2NjU5OTEsIDB4ZTE5OTI4NjMsIDB4YzhmMzBjNjAsIDB4MmU3OGVmM2MsIDB4ZDBkNTE5MzIsIDB4Y2YwZmVjMTQsIDB4ZjdjYTA3ZDIsIDB4ZDBhODIwNzIsXHJcblx0XHQgIDB4ZmQ0MTE5N2UsIDB4OTMwNWE2YjAsIDB4ZTg2YmUzZGEsIDB4NzRiZWQzY2QsIDB4MzcyZGE1M2MsIDB4NGM3ZjQ0NDgsIDB4ZGFiNWQ0NDAsIDB4NmRiYTBlYzMsXHJcblx0XHQgIDB4MDgzOTE5YTcsIDB4OWZiYWVlZDksIDB4NDlkYmNmYjAsIDB4NGU2NzBjNTMsIDB4NWMzZDljMDEsIDB4NjRiZGI5NDEsIDB4MmMwZTYzNmEsIDB4YmE3ZGQ5Y2QsXHJcblx0XHQgIDB4ZWE2ZjczODgsIDB4ZTcwYmM3NjIsIDB4MzVmMjlhZGIsIDB4NWM0Y2RkOGQsIDB4ZjBkNDhkOGMsIDB4Yjg4MTUzZTIsIDB4MDhhMTk4NjYsIDB4MWFlMmVhYzgsXHJcblx0XHQgIDB4Mjg0Y2FmODksIDB4YWE5MjgyMjMsIDB4OTMzNGJlNTMsIDB4M2IzYTIxYmYsIDB4MTY0MzRiZTMsIDB4OWFlYTM5MDYsIDB4ZWZlOGMzNmUsIDB4Zjg5MGNkZDksXHJcblx0XHQgIDB4ODAyMjZkYWUsIDB4YzM0MGE0YTMsIDB4ZGY3ZTljMDksIDB4YTY5NGE4MDcsIDB4NWI3YzVlY2MsIDB4MjIxZGIzYTYsIDB4OWE2OWEwMmYsIDB4Njg4MThhNTQsXHJcblx0XHQgIDB4Y2ViMjI5NmYsIDB4NTNjMDg0M2EsIDB4ZmU4OTM2NTUsIDB4MjViZmU2OGEsIDB4YjQ2MjhhYmMsIDB4Y2YyMjJlYmYsIDB4MjVhYzZmNDgsIDB4YTlhOTkzODcsXHJcblx0XHQgIDB4NTNiZGRiNjUsIDB4ZTc2ZmZiZTcsIDB4ZTk2N2ZkNzgsIDB4MGJhOTM1NjMsIDB4OGUzNDJiYzEsIDB4ZThhMTFiZTksIDB4NDk4MDc0MGQsIDB4YzgwODdkZmMsXHJcblx0XHQgIDB4OGRlNGJmOTksIDB4YTExMTAxYTAsIDB4N2ZkMzc5NzUsIDB4ZGE1YTI2YzAsIDB4ZTgxZjk5NGYsIDB4OTUyOGNkODksIDB4ZmQzMzlmZWQsIDB4Yjg3ODM0YmYsXHJcblx0XHQgIDB4NWYwNDQ1NmQsIDB4MjIyNTg2OTgsIDB4YzljNGM4M2IsIDB4MmRjMTU2YmUsIDB4NGY2MjhkYWEsIDB4NTdmNTVlYzUsIDB4ZTIyMjBhYmUsIDB4ZDI5MTZlYmYsXHJcblx0XHQgIDB4NGVjNzViOTUsIDB4MjRmMmMzYzAsIDB4NDJkMTVkOTksIDB4Y2QwZDdmYTAsIDB4N2I2ZTI3ZmYsIDB4YThkYzhhZjAsIDB4NzM0NWMxMDYsIDB4ZjQxZTIzMmYsXHJcblx0XHQgIDB4MzUxNjIzODYsIDB4ZTZlYTg5MjYsIDB4MzMzM2IwOTQsIDB4MTU3ZWM2ZjIsIDB4MzcyYjc0YWYsIDB4NjkyNTczZTQsIDB4ZTlhOWQ4NDgsIDB4ZjMxNjAyODksXHJcblx0XHQgIDB4M2E2MmVmMWQsIDB4YTc4N2UyMzgsIDB4ZjNhNWY2NzYsIDB4NzQzNjQ4NTMsIDB4MjA5NTEwNjMsIDB4NDU3NjY5OGQsIDB4YjZmYWQ0MDcsIDB4NTkyYWY5NTAsXHJcblx0XHQgIDB4MzZmNzM1MjMsIDB4NGNmYjZlODcsIDB4N2RhNGNlYzAsIDB4NmMxNTJkYWEsIDB4Y2IwMzk2YTgsIDB4YzUwZGZlNWQsIDB4ZmNkNzA3YWIsIDB4MDkyMWM0MmYsXHJcblx0XHQgIDB4ODlkZmYwYmIsIDB4NWZlMmJlNzgsIDB4NDQ4ZjRmMzMsIDB4NzU0NjEzYzksIDB4MmIwNWQwOGQsIDB4NDhiOWQ1ODUsIDB4ZGMwNDk0NDEsIDB4YzgwOThmOWIsXHJcblx0XHQgIDB4N2RlZGU3ODYsIDB4YzM5YTMzNzMsIDB4NDI0MTAwMDUsIDB4NmEwOTE3NTEsIDB4MGVmM2M4YTYsIDB4ODkwMDcyZDYsIDB4MjgyMDc2ODIsIDB4YTlhOWY3YmUsXHJcblx0XHQgIDB4YmYzMjY3OWQsIDB4ZDQ1YjViNzUsIDB4YjM1M2ZkMDAsIDB4Y2JiMGUzNTgsIDB4ODMwZjIyMGEsIDB4MWY4ZmIyMTQsIDB4ZDM3MmNmMDgsIDB4Y2MzYzRhMTMsXHJcblx0XHQgIDB4OGNmNjMxNjYsIDB4MDYxYzg3YmUsIDB4ODhjOThmODgsIDB4NjA2MmUzOTcsIDB4NDdjZjhlN2EsIDB4YjZjODUyODMsIDB4M2NjMmFjZmIsIDB4M2ZjMDY5NzYsXHJcblx0XHQgIDB4NGU4ZjAyNTIsIDB4NjRkODMxNGQsIDB4ZGEzODcwZTMsIDB4MWU2NjU0NTksIDB4YzEwOTA4ZjAsIDB4NTEzMDIxYTUsIDB4NmM1YjY4YjcsIDB4ODIyZjhhYTAsXHJcblx0XHQgIDB4MzAwN2NkM2UsIDB4NzQ3MTllZWYsIDB4ZGM4NzI2ODEsIDB4MDczMzQwZDQsIDB4N2U0MzJmZDksIDB4MGM1ZWMyNDEsIDB4ODgwOTI4NmMsIDB4ZjU5MmQ4OTEsXHJcblx0XHQgIDB4MDhhOTMwZjYsIDB4OTU3ZWYzMDUsIDB4YjdmYmZmYmQsIDB4YzI2NmU5NmYsIDB4NmZlNGFjOTgsIDB4YjE3M2VjYzAsIDB4YmM2MGI0MmEsIDB4OTUzNDk4ZGEsXHJcblx0XHQgIDB4ZmJhMWFlMTIsIDB4MmQ0YmQ3MzYsIDB4MGYyNWZhYWIsIDB4YTRmM2ZjZWIsIDB4ZTI5NjkxMjMsIDB4MjU3ZjBjM2QsIDB4OTM0OGFmNDksIDB4MzYxNDAwYmMsXHJcblx0XHQgIDB4ZTg4MTZmNGEsIDB4MzgxNGYyMDAsIDB4YTNmOTQwNDMsIDB4OWM3YTU0YzIsIDB4YmM3MDRmNTcsIDB4ZGE0MWU3ZjksIDB4YzI1YWQzM2EsIDB4NTRmNGEwODQsXHJcblx0XHQgIDB4YjE3ZjU1MDUsIDB4NTkzNTdjYmUsIDB4ZWRiZDE1YzgsIDB4N2Y5N2M1YWIsIDB4YmE1YWM3YjUsIDB4YjZmNmRlYWYsIDB4M2E0NzljM2EsIDB4NTMwMmRhMjUsXHJcblx0XHQgIDB4NjUzZDdlNmEsIDB4NTQyNjhkNDksIDB4NTFhNDc3ZWEsIDB4NTAxN2Q1NWIsIDB4ZDdkMjVkODgsIDB4NDQxMzZjNzYsIDB4MDQwNGE4YzgsIDB4YjhlNWExMjEsXHJcblx0XHQgIDB4YjgxYTkyOGEsIDB4NjBlZDU4NjksIDB4OTdjNTViOTYsIDB4ZWFlYzk5MWIsIDB4Mjk5MzU5MTMsIDB4MDFmZGI3ZjEsIDB4MDg4ZThkZmEsIDB4OWFiNmY2ZjUsXHJcblx0XHQgIDB4M2I0Y2JmOWYsIDB4NGE1ZGUzYWIsIDB4ZTYwNTFkMzUsIDB4YTBlMWQ4NTUsIDB4ZDM2YjRjZjEsIDB4ZjU0NGVkZWIsIDB4YjBlOTM1MjQsIDB4YmViYjhmYmQsXHJcblx0XHQgIDB4YTJkNzYyY2YsIDB4NDljOTJmNTQsIDB4MzhiNWYzMzEsIDB4NzEyOGE0NTQsIDB4NDgzOTI5MDUsIDB4YTY1YjFkYjgsIDB4ODUxYzk3YmQsIDB4ZDY3NWNmMmYpO1xyXG5cclxuXHRcdHNCb3hbNl0gPSBuZXcgQXJyYXkoXHJcblx0XHQgIDB4ODVlMDQwMTksIDB4MzMyYmY1NjcsIDB4NjYyZGJmZmYsIDB4Y2ZjNjU2OTMsIDB4MmE4ZDdmNmYsIDB4YWI5YmM5MTIsIDB4ZGU2MDA4YTEsIDB4MjAyOGRhMWYsXHJcblx0XHQgIDB4MDIyN2JjZTcsIDB4NGQ2NDI5MTYsIDB4MThmYWMzMDAsIDB4NTBmMThiODIsIDB4MmNiMmNiMTEsIDB4YjIzMmU3NWMsIDB4NGIzNjk1ZjIsIDB4YjI4NzA3ZGUsXHJcblx0XHQgIDB4YTA1ZmJjZjYsIDB4Y2Q0MTgxZTksIDB4ZTE1MDIxMGMsIDB4ZTI0ZWYxYmQsIDB4YjE2OGMzODEsIDB4ZmRlNGU3ODksIDB4NWM3OWIwZDgsIDB4MWU4YmZkNDMsXHJcblx0XHQgIDB4NGQ0OTUwMDEsIDB4MzhiZTQzNDEsIDB4OTEzY2VlMWQsIDB4OTJhNzljM2YsIDB4MDg5NzY2YmUsIDB4YmFlZWFkZjQsIDB4MTI4NmJlY2YsIDB4YjZlYWNiMTksXHJcblx0XHQgIDB4MjY2MGMyMDAsIDB4NzU2NWJkZTQsIDB4NjQyNDFmN2EsIDB4ODI0OGRjYTksIDB4YzNiM2FkNjYsIDB4MjgxMzYwODYsIDB4MGJkOGRmYTgsIDB4MzU2ZDFjZjIsXHJcblx0XHQgIDB4MTA3Nzg5YmUsIDB4YjNiMmU5Y2UsIDB4MDUwMmFhOGYsIDB4MGJjMDM1MWUsIDB4MTY2YmY1MmEsIDB4ZWIxMmZmODIsIDB4ZTM0ODY5MTEsIDB4ZDM0ZDc1MTYsXHJcblx0XHQgIDB4NGU3YjNhZmYsIDB4NWY0MzY3MWIsIDB4OWNmNmUwMzcsIDB4NDk4MWFjODMsIDB4MzM0MjY2Y2UsIDB4OGM5MzQxYjcsIDB4ZDBkODU0YzAsIDB4Y2IzYTZjODgsXHJcblx0XHQgIDB4NDdiYzI4MjksIDB4NDcyNWJhMzcsIDB4YTY2YWQyMmIsIDB4N2FkNjFmMWUsIDB4MGM1Y2JhZmEsIDB4NDQzN2YxMDcsIDB4YjZlNzk5NjIsIDB4NDJkMmQ4MTYsXHJcblx0XHQgIDB4MGE5NjEyODgsIDB4ZTFhNWMwNmUsIDB4MTM3NDllNjcsIDB4NzJmYzA4MWEsIDB4YjFkMTM5ZjcsIDB4Zjk1ODM3NDUsIDB4Y2YxOWRmNTgsIDB4YmVjM2Y3NTYsXHJcblx0XHQgIDB4YzA2ZWJhMzAsIDB4MDcyMTFiMjQsIDB4NDVjMjg4MjksIDB4Yzk1ZTMxN2YsIDB4YmM4ZWM1MTEsIDB4MzhiYzQ2ZTksIDB4YzZlNmZhMTQsIDB4YmFlODU4NGEsXHJcblx0XHQgIDB4YWQ0ZWJjNDYsIDB4NDY4ZjUwOGIsIDB4NzgyOTQzNWYsIDB4ZjEyNDE4M2IsIDB4ODIxZGJhOWYsIDB4YWZmNjBmZjQsIDB4ZWEyYzRlNmQsIDB4MTZlMzkyNjQsXHJcblx0XHQgIDB4OTI1NDRhOGIsIDB4MDA5YjRmYzMsIDB4YWJhNjhjZWQsIDB4OWFjOTZmNzgsIDB4MDZhNWI3OWEsIDB4YjI4NTZlNmUsIDB4MWFlYzNjYTksIDB4YmU4Mzg2ODgsXHJcblx0XHQgIDB4MGUwODA0ZTksIDB4NTVmMWJlNTYsIDB4ZTdlNTM2M2IsIDB4YjNhMWYyNWQsIDB4ZjdkZWJiODUsIDB4NjFmZTAzM2MsIDB4MTY3NDYyMzMsIDB4M2MwMzRjMjgsXHJcblx0XHQgIDB4ZGE2ZDBjNzQsIDB4NzlhYWM1NmMsIDB4M2NlNGUxYWQsIDB4NTFmMGM4MDIsIDB4OThmOGYzNWEsIDB4MTYyNmE0OWYsIDB4ZWVkODJiMjksIDB4MWQzODJmZTMsXHJcblx0XHQgIDB4MGM0ZmI5OWEsIDB4YmIzMjU3NzgsIDB4M2VjNmQ5N2IsIDB4NmU3N2E2YTksIDB4Y2I2NThiNWMsIDB4ZDQ1MjMwYzcsIDB4MmJkMTQwOGIsIDB4NjBjMDNlYjcsXHJcblx0XHQgIDB4YjkwNjhkNzgsIDB4YTMzNzU0ZjQsIDB4ZjQzMGM4N2QsIDB4YzhhNzEzMDIsIDB4Yjk2ZDhjMzIsIDB4ZWJkNGU3YmUsIDB4YmU4YjlkMmQsIDB4Nzk3OWZiMDYsXHJcblx0XHQgIDB4ZTcyMjUzMDgsIDB4OGI3NWNmNzcsIDB4MTFlZjhkYTQsIDB4ZTA4M2M4NTgsIDB4OGQ2Yjc4NmYsIDB4NWE2MzE3YTYsIDB4ZmE1Y2Y3YTAsIDB4NWRkYTAwMzMsXHJcblx0XHQgIDB4ZjI4ZWJmYjAsIDB4ZjViOWMzMTAsIDB4YTBlYWMyODAsIDB4MDhiOTc2N2EsIDB4YTNkOWQyYjAsIDB4NzlkMzQyMTcsIDB4MDIxYTcxOGQsIDB4OWFjNjMzNmEsXHJcblx0XHQgIDB4MjcxMWZkNjAsIDB4NDM4MDUwZTMsIDB4MDY5OTA4YTgsIDB4M2Q3ZmVkYzQsIDB4ODI2ZDJiZWYsIDB4NGVlYjg0NzYsIDB4NDg4ZGNmMjUsIDB4MzZjOWQ1NjYsXHJcblx0XHQgIDB4MjhlNzRlNDEsIDB4YzI2MTBhY2EsIDB4M2Q0OWE5Y2YsIDB4YmFlM2I5ZGYsIDB4YjY1ZjhkZTYsIDB4OTJhZWFmNjQsIDB4M2FjN2Q1ZTYsIDB4OWVhODA1MDksXHJcblx0XHQgIDB4ZjIyYjAxN2QsIDB4YTQxNzNmNzAsIDB4ZGQxZTE2YzMsIDB4MTVlMGQ3ZjksIDB4NTBiMWI4ODcsIDB4MmI5ZjRmZDUsIDB4NjI1YWJhODIsIDB4NmEwMTc5NjIsXHJcblx0XHQgIDB4MmVjMDFiOWMsIDB4MTU0ODhhYTksIDB4ZDcxNmU3NDAsIDB4NDAwNTVhMmMsIDB4OTNkMjlhMjIsIDB4ZTMyZGJmOWEsIDB4MDU4NzQ1YjksIDB4MzQ1M2RjMWUsXHJcblx0XHQgIDB4ZDY5OTI5NmUsIDB4NDk2Y2ZmNmYsIDB4MWM5ZjQ5ODYsIDB4ZGZlMmVkMDcsIDB4Yjg3MjQyZDEsIDB4MTlkZTdlYWUsIDB4MDUzZTU2MWEsIDB4MTVhZDZmOGMsXHJcblx0XHQgIDB4NjY2MjZjMWMsIDB4NzE1NGMyNGMsIDB4ZWEwODJiMmEsIDB4OTNlYjI5MzksIDB4MTdkY2IwZjAsIDB4NThkNGYyYWUsIDB4OWVhMjk0ZmIsIDB4NTJjZjU2NGMsXHJcblx0XHQgIDB4OTg4M2ZlNjYsIDB4MmVjNDA1ODEsIDB4NzYzOTUzYzMsIDB4MDFkNjY5MmUsIDB4ZDNhMGMxMDgsIDB4YTFlNzE2MGUsIDB4ZTRmMmRmYTYsIDB4NjkzZWQyODUsXHJcblx0XHQgIDB4NzQ5MDQ2OTgsIDB4NGMyYjBlZGQsIDB4NGY3NTc2NTYsIDB4NWQzOTMzNzgsIDB4YTEzMjIzNGYsIDB4M2QzMjFjNWQsIDB4YzNmNWUxOTQsIDB4NGIyNjkzMDEsXHJcblx0XHQgIDB4Yzc5ZjAyMmYsIDB4M2M5OTdlN2UsIDB4NWU0Zjk1MDQsIDB4M2ZmYWZiYmQsIDB4NzZmN2FkMGUsIDB4Mjk2NjkzZjQsIDB4M2QxZmNlNmYsIDB4YzYxZTQ1YmUsXHJcblx0XHQgIDB4ZDNiNWFiMzQsIDB4ZjcyYmY5YjcsIDB4MWIwNDM0YzAsIDB4NGU3MmI1NjcsIDB4NTU5MmEzM2QsIDB4YjUyMjkzMDEsIDB4Y2ZkMmE4N2YsIDB4NjBhZWI3NjcsXHJcblx0XHQgIDB4MTgxNDM4NmIsIDB4MzBiY2MzM2QsIDB4MzhhMGMwN2QsIDB4ZmQxNjA2ZjIsIDB4YzM2MzUxOWIsIDB4NTg5ZGQzOTAsIDB4NTQ3OWY4ZTYsIDB4MWNiOGQ2NDcsXHJcblx0XHQgIDB4OTdmZDYxYTksIDB4ZWE3NzU5ZjQsIDB4MmQ1NzUzOWQsIDB4NTY5YTU4Y2YsIDB4ZTg0ZTYzYWQsIDB4NDYyZTFiNzgsIDB4NjU4MGY4N2UsIDB4ZjM4MTc5MTQsXHJcblx0XHQgIDB4OTFkYTU1ZjQsIDB4NDBhMjMwZjMsIDB4ZDE5ODhmMzUsIDB4YjZlMzE4ZDIsIDB4M2ZmYTUwYmMsIDB4M2Q0MGYwMjEsIDB4YzNjMGJkYWUsIDB4NDk1OGMyNGMsXHJcblx0XHQgIDB4NTE4ZjM2YjIsIDB4ODRiMWQzNzAsIDB4MGZlZGNlODMsIDB4ODc4ZGRhZGEsIDB4ZjJhMjc5YzcsIDB4OTRlMDFiZTgsIDB4OTA3MTZmNGIsIDB4OTU0YjhhYTMpO1xyXG5cclxuXHRcdHNCb3hbN10gPSBuZXcgQXJyYXkoXHJcblx0XHQgIDB4ZTIxNjMwMGQsIDB4YmJkZGZmZmMsIDB4YTdlYmRhYmQsIDB4MzU2NDgwOTUsIDB4Nzc4OWY4YjcsIDB4ZTZjMTEyMWIsIDB4MGUyNDE2MDAsIDB4MDUyY2U4YjUsXHJcblx0XHQgIDB4MTFhOWNmYjAsIDB4ZTU5NTJmMTEsIDB4ZWNlNzk5MGEsIDB4OTM4NmQxNzQsIDB4MmE0MjkzMWMsIDB4NzZlMzgxMTEsIDB4YjEyZGVmM2EsIDB4MzdkZGRkZmMsXHJcblx0XHQgIDB4ZGU5YWRlYjEsIDB4MGEwY2MzMmMsIDB4YmUxOTcwMjksIDB4ODRhMDA5NDAsIDB4YmIyNDNhMGYsIDB4YjRkMTM3Y2YsIDB4YjQ0ZTc5ZjAsIDB4MDQ5ZWVkZmQsXHJcblx0XHQgIDB4MGIxNWExNWQsIDB4NDgwZDMxNjgsIDB4OGJiYmRlNWEsIDB4NjY5ZGVkNDIsIDB4YzdlY2U4MzEsIDB4M2Y4Zjk1ZTcsIDB4NzJkZjE5MWIsIDB4NzU4MDMzMGQsXHJcblx0XHQgIDB4OTQwNzQyNTEsIDB4NWM3ZGNkZmEsIDB4YWJiZTZkNjMsIDB4YWE0MDIxNjQsIDB4YjMwMWQ0MGEsIDB4MDJlN2QxY2EsIDB4NTM1NzFkYWUsIDB4N2EzMTgyYTIsXHJcblx0XHQgIDB4MTJhOGRkZWMsIDB4ZmRhYTMzNWQsIDB4MTc2ZjQzZTgsIDB4NzFmYjQ2ZDQsIDB4MzgxMjkwMjIsIDB4Y2U5NDlhZDQsIDB4Yjg0NzY5YWQsIDB4OTY1YmQ4NjIsXHJcblx0XHQgIDB4ODJmM2QwNTUsIDB4NjZmYjk3NjcsIDB4MTViODBiNGUsIDB4MWQ1YjQ3YTAsIDB4NGNmZGUwNmYsIDB4YzI4ZWM0YjgsIDB4NTdlODcyNmUsIDB4NjQ3YTc4ZmMsXHJcblx0XHQgIDB4OTk4NjVkNDQsIDB4NjA4YmQ1OTMsIDB4NmMyMDBlMDMsIDB4MzlkYzVmZjYsIDB4NWQwYjAwYTMsIDB4YWU2M2FmZjIsIDB4N2U4YmQ2MzIsIDB4NzAxMDhjMGMsXHJcblx0XHQgIDB4YmJkMzUwNDksIDB4Mjk5OGRmMDQsIDB4OTgwY2Y0MmEsIDB4OWI2ZGY0OTEsIDB4OWU3ZWRkNTMsIDB4MDY5MTg1NDgsIDB4NThjYjdlMDcsIDB4M2I3NGVmMmUsXHJcblx0XHQgIDB4NTIyZmZmYjEsIDB4ZDI0NzA4Y2MsIDB4MWM3ZTI3Y2QsIDB4YTRlYjIxNWIsIDB4M2NmMWQyZTIsIDB4MTliNDdhMzgsIDB4NDI0Zjc2MTgsIDB4MzU4NTYwMzksXHJcblx0XHQgIDB4OWQxN2RlZTcsIDB4MjdlYjM1ZTYsIDB4YzlhZmY2N2IsIDB4MzZiYWY1YjgsIDB4MDljNDY3Y2QsIDB4YzE4OTEwYjEsIDB4ZTExZGJmN2IsIDB4MDZjZDFhZjgsXHJcblx0XHQgIDB4NzE3MGM2MDgsIDB4MmQ1ZTMzNTQsIDB4ZDRkZTQ5NWEsIDB4NjRjNmQwMDYsIDB4YmNjMGM2MmMsIDB4M2RkMDBkYjMsIDB4NzA4ZjhmMzQsIDB4NzdkNTFiNDIsXHJcblx0XHQgIDB4MjY0ZjYyMGYsIDB4MjRiOGQyYmYsIDB4MTVjMWI3OWUsIDB4NDZhNTI1NjQsIDB4ZjhkN2U1NGUsIDB4M2UzNzgxNjAsIDB4Nzg5NWNkYTUsIDB4ODU5YzE1YTUsXHJcblx0XHQgIDB4ZTY0NTk3ODgsIDB4YzM3YmM3NWYsIDB4ZGIwN2JhMGMsIDB4MDY3NmEzYWIsIDB4N2YyMjliMWUsIDB4MzE4NDJlN2IsIDB4MjQyNTlmZDcsIDB4ZjhiZWY0NzIsXHJcblx0XHQgIDB4ODM1ZmZjYjgsIDB4NmRmNGMxZjIsIDB4OTZmNWIxOTUsIDB4ZmQwYWYwZmMsIDB4YjBmZTEzNGMsIDB4ZTI1MDZkM2QsIDB4NGY5YjEyZWEsIDB4ZjIxNWYyMjUsXHJcblx0XHQgIDB4YTIyMzczNmYsIDB4OWZiNGM0MjgsIDB4MjVkMDQ5NzksIDB4MzRjNzEzZjgsIDB4YzQ2MTgxODcsIDB4ZWE3YTZlOTgsIDB4N2NkMTZlZmMsIDB4MTQzNjg3NmMsXHJcblx0XHQgIDB4ZjE1NDQxMDcsIDB4YmVkZWVlMTQsIDB4NTZlOWFmMjcsIDB4YTA0YWE0NDEsIDB4M2NmN2M4OTksIDB4OTJlY2JhZTYsIDB4ZGQ2NzAxNmQsIDB4MTUxNjgyZWIsXHJcblx0XHQgIDB4YTg0MmVlZGYsIDB4ZmRiYTYwYjQsIDB4ZjE5MDdiNzUsIDB4MjBlMzAzMGYsIDB4MjRkOGMyOWUsIDB4ZTEzOTY3M2IsIDB4ZWZhNjNmYjgsIDB4NzE4NzMwNTQsXHJcblx0XHQgIDB4YjZmMmNmM2IsIDB4OWYzMjY0NDIsIDB4Y2IxNWE0Y2MsIDB4YjAxYTQ1MDQsIDB4ZjFlNDdkOGQsIDB4ODQ0YTFiZTUsIDB4YmFlN2RmZGMsIDB4NDJjYmRhNzAsXHJcblx0XHQgIDB4Y2Q3ZGFlMGEsIDB4NTdlODViN2EsIDB4ZDUzZjVhZjYsIDB4MjBjZjRkOGMsIDB4Y2VhNGQ0MjgsIDB4NzlkMTMwYTQsIDB4MzQ4NmViZmIsIDB4MzNkM2NkZGMsXHJcblx0XHQgIDB4Nzc4NTNiNTMsIDB4MzdlZmZjYjUsIDB4YzUwNjg3NzgsIDB4ZTU4MGIzZTYsIDB4NGU2OGI4ZjQsIDB4YzVjOGIzN2UsIDB4MGQ4MDllYTIsIDB4Mzk4ZmViN2MsXHJcblx0XHQgIDB4MTMyYTRmOTQsIDB4NDNiNzk1MGUsIDB4MmZlZTdkMWMsIDB4MjIzNjEzYmQsIDB4ZGQwNmNhYTIsIDB4MzdkZjkzMmIsIDB4YzQyNDgyODksIDB4YWNmM2ViYzMsXHJcblx0XHQgIDB4NTcxNWY2YjcsIDB4ZWYzNDc4ZGQsIDB4ZjI2NzYxNmYsIDB4YzE0OGNiZTQsIDB4OTA1MjgxNWUsIDB4NWU0MTBmYWIsIDB4YjQ4YTI0NjUsIDB4MmVkYTdmYTQsXHJcblx0XHQgIDB4ZTg3YjQwZTQsIDB4ZTk4ZWEwODQsIDB4NTg4OWU5ZTEsIDB4ZWZkMzkwZmMsIDB4ZGQwN2QzNWIsIDB4ZGI0ODU2OTQsIDB4MzhkN2U1YjIsIDB4NTc3MjAxMDEsXHJcblx0XHQgIDB4NzMwZWRlYmMsIDB4NWI2NDMxMTMsIDB4OTQ5MTdlNGYsIDB4NTAzYzJmYmEsIDB4NjQ2ZjEyODIsIDB4NzUyM2QyNGEsIDB4ZTA3Nzk2OTUsIDB4ZjljMTdhOGYsXHJcblx0XHQgIDB4N2E1YjIxMjEsIDB4ZDE4N2I4OTYsIDB4MjkyNjNhNGQsIDB4YmE1MTBjZGYsIDB4ODFmNDdjOWYsIDB4YWQxMTYzZWQsIDB4ZWE3YjU5NjUsIDB4MWEwMDcyNmUsXHJcblx0XHQgIDB4MTE0MDMwOTIsIDB4MDBkYTZkNzcsIDB4NGEwY2RkNjEsIDB4YWQxZjQ2MDMsIDB4NjA1YmRmYjAsIDB4OWVlZGMzNjQsIDB4MjJlYmU2YTgsIDB4Y2VlN2QyOGEsXHJcblx0XHQgIDB4YTBlNzM2YTAsIDB4NTU2NGE2YjksIDB4MTA4NTMyMDksIDB4YzdlYjhmMzcsIDB4MmRlNzA1Y2EsIDB4ODk1MTU3MGYsIDB4ZGYwOTgyMmIsIDB4YmQ2OTFhNmMsXHJcblx0XHQgIDB4YWExMmU0ZjIsIDB4ODc0NTFjMGYsIDB4ZTBmNmEyN2EsIDB4M2FkYTQ4MTksIDB4NGNmMTc2NGYsIDB4MGQ3NzFjMmIsIDB4NjdjZGIxNTYsIDB4MzUwZDgzODQsXHJcblx0XHQgIDB4NTkzOGZhMGYsIDB4NDIzOTllZjMsIDB4MzY5OTdiMDcsIDB4MGU4NDA5M2QsIDB4NGFhOTNlNjEsIDB4ODM2MGQ4N2IsIDB4MWZhOThiMGMsIDB4MTE0OTM4MmMsXHJcblx0XHQgIDB4ZTk3NjI1YTUsIDB4MDYxNGQxYjcsIDB4MGUyNTI0NGIsIDB4MGM3NjgzNDcsIDB4NTg5ZThkODIsIDB4MGQyMDU5ZDEsIDB4YTQ2NmJiMWUsIDB4ZjhkYTBhODIsXHJcblx0XHQgIDB4MDRmMTkxMzAsIDB4YmE2ZTRlYzAsIDB4OTkyNjUxNjQsIDB4MWVlNzIzMGQsIDB4NTBiMmFkODAsIDB4ZWFlZTY4MDEsIDB4OGRiMmEyODMsIDB4ZWE4YmY1OWUpO1xyXG5cclxufTtcclxuXHJcblxyXG5tb2R1bGUuZXhwb3J0cyA9IGNhc3Q1X2VuY3J5cHQ7XHJcbm1vZHVsZS5leHBvcnRzLmNhc3RDbGFzcyA9IG9wZW5wZ3Bfc3ltZW5jX2Nhc3Q1O1xyXG4iLCIvKiBNb2RpZmllZCBieSBSZWN1cml0eSBMYWJzIEdtYkggXG4gKiBcbiAqIENpcGhlci5qc1xuICogQSBibG9jay1jaXBoZXIgYWxnb3JpdGhtIGltcGxlbWVudGF0aW9uIG9uIEphdmFTY3JpcHRcbiAqIFNlZSBDaXBoZXIucmVhZG1lLnR4dCBmb3IgZnVydGhlciBpbmZvcm1hdGlvbi5cbiAqXG4gKiBDb3B5cmlnaHQoYykgMjAwOSBBdHN1c2hpIE9rYSBbIGh0dHA6Ly9va2EubnUvIF1cbiAqIFRoaXMgc2NyaXB0IGZpbGUgaXMgZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExHUExcbiAqXG4gKiBBQ0tOT1dMRURHTUVOVFxuICpcbiAqICAgICBUaGUgbWFpbiBzdWJyb3V0aW5lcyBhcmUgd3JpdHRlbiBieSBNaWNoaWVsIHZhbiBFdmVyZGluZ2VuLlxuICogXG4gKiAgICAgTWljaGllbCB2YW4gRXZlcmRpbmdlblxuICogICAgIGh0dHA6Ly9ob21lLnZlcnNhdGVsLm5sL01BdmFuRXZlcmRpbmdlbi9pbmRleC5odG1sXG4gKiBcbiAqICAgICBBbGwgcmlnaHRzIGZvciB0aGVzZSByb3V0aW5lcyBhcmUgcmVzZXJ2ZWQgdG8gTWljaGllbCB2YW4gRXZlcmRpbmdlbi5cbiAqXG4gKi9cblxudmFyIHV0aWwgPSByZXF1aXJlKCcuLi8uLi91dGlsJyk7XG5cbi8vIGFkZGVkIGJ5IFJlY3VyaXR5IExhYnNcbmZ1bmN0aW9uIFRGZW5jcnlwdChibG9jaywga2V5KSB7XG5cdHZhciBibG9ja19jb3B5ID0gW10uY29uY2F0KGJsb2NrKTtcblx0dmFyIHRmID0gY3JlYXRlVHdvZmlzaCgpO1xuXHR0Zi5vcGVuKHV0aWwuc3RyMmJpbihrZXkpLDApO1xuXHR2YXIgcmVzdWx0ID0gdGYuZW5jcnlwdChibG9ja19jb3B5LCAwKTtcblx0dGYuY2xvc2UoKTtcblx0cmV0dXJuIHJlc3VsdDtcbn1cblxuLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vXG4vL01hdGhcbi8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vL1xuXG52YXIgTUFYSU5UID0gMHhGRkZGRkZGRjtcblxuZnVuY3Rpb24gcm90YihiLG4peyByZXR1cm4gKCBiPDxuIHwgYj4+PiggOC1uKSApICYgMHhGRjsgfVxuZnVuY3Rpb24gcm90dyh3LG4peyByZXR1cm4gKCB3PDxuIHwgdz4+PigzMi1uKSApICYgTUFYSU5UOyB9XG5mdW5jdGlvbiBnZXRXKGEsaSl7IHJldHVybiBhW2ldfGFbaSsxXTw8OHxhW2krMl08PDE2fGFbaSszXTw8MjQ7IH1cbmZ1bmN0aW9uIHNldFcoYSxpLHcpeyBhLnNwbGljZShpLDQsdyYweEZGLCh3Pj4+OCkmMHhGRiwodz4+PjE2KSYweEZGLCh3Pj4+MjQpJjB4RkYpOyB9XG5mdW5jdGlvbiBzZXRXSW52KGEsaSx3KXsgYS5zcGxpY2UoaSw0LCh3Pj4+MjQpJjB4RkYsKHc+Pj4xNikmMHhGRiwodz4+PjgpJjB4RkYsdyYweEZGKTsgfVxuZnVuY3Rpb24gZ2V0Qih4LG4peyByZXR1cm4gKHg+Pj4obio4KSkmMHhGRjsgfVxuXG5mdW5jdGlvbiBnZXROckJpdHMoaSl7IHZhciBuPTA7IHdoaWxlIChpPjApeyBuKys7IGk+Pj49MTsgfSByZXR1cm4gbjsgfVxuZnVuY3Rpb24gZ2V0TWFzayhuKXsgcmV0dXJuICgxPDxuKS0xOyB9XG5cbi8vYWRkZWQgMjAwOC8xMS8xMyBYWFggTVVTVCBVU0UgT05FLVdBWSBIQVNIIEZVTkNUSU9OIEZPUiBTRUNVUklUWSBSRUFTT05cbmZ1bmN0aW9uIHJhbmRCeXRlKCkge1xuIHJldHVybiBNYXRoLmZsb29yKCBNYXRoLnJhbmRvbSgpICogMjU2ICk7XG59XG4vLyAvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vXG4vLyBUd29maXNoXG4vLyAvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vXG5cbmZ1bmN0aW9uIGNyZWF0ZVR3b2Zpc2goKSB7XG5cdC8vXG5cdHZhciBrZXlCeXRlcyA9IG51bGw7XG5cdHZhciBkYXRhQnl0ZXMgPSBudWxsO1xuXHR2YXIgZGF0YU9mZnNldCA9IC0xO1xuXHQvLyB2YXIgZGF0YUxlbmd0aCA9IC0xO1xuXHR2YXIgYWxnb3JpdGhtTmFtZSA9IG51bGw7XG5cdC8vIHZhciBpZHgyID0gLTE7XG5cdC8vXG5cblx0YWxnb3JpdGhtTmFtZSA9IFwidHdvZmlzaFwiO1xuXG5cdHZhciB0ZnNLZXkgPSBbXTtcblx0dmFyIHRmc00gPSBbIFtdLCBbXSwgW10sIFtdIF07XG5cblx0ZnVuY3Rpb24gdGZzSW5pdChrZXkpIHtcblx0XHRrZXlCeXRlcyA9IGtleTtcblx0XHR2YXIgaSwgYSwgYiwgYywgZCwgbWVLZXkgPSBbXSwgbW9LZXkgPSBbXSwgaW5LZXkgPSBbXTtcblx0XHR2YXIga0xlbjtcblx0XHR2YXIgc0tleSA9IFtdO1xuXHRcdHZhciBmMDEsIGY1YiwgZmVmO1xuXG5cdFx0dmFyIHEwID0gWyBbIDgsIDEsIDcsIDEzLCA2LCAxNSwgMywgMiwgMCwgMTEsIDUsIDksIDE0LCAxMiwgMTAsIDQgXSxcblx0XHRcdFx0WyAyLCA4LCAxMSwgMTMsIDE1LCA3LCA2LCAxNCwgMywgMSwgOSwgNCwgMCwgMTAsIDEyLCA1IF0gXTtcblx0XHR2YXIgcTEgPSBbIFsgMTQsIDEyLCAxMSwgOCwgMSwgMiwgMywgNSwgMTUsIDQsIDEwLCA2LCA3LCAwLCA5LCAxMyBdLFxuXHRcdFx0XHRbIDEsIDE0LCAyLCAxMSwgNCwgMTIsIDMsIDcsIDYsIDEzLCAxMCwgNSwgMTUsIDksIDAsIDggXSBdO1xuXHRcdHZhciBxMiA9IFsgWyAxMSwgMTAsIDUsIDE0LCA2LCAxMywgOSwgMCwgMTIsIDgsIDE1LCAzLCAyLCA0LCA3LCAxIF0sXG5cdFx0XHRcdFsgNCwgMTIsIDcsIDUsIDEsIDYsIDksIDEwLCAwLCAxNCwgMTMsIDgsIDIsIDExLCAzLCAxNSBdIF07XG5cdFx0dmFyIHEzID0gWyBbIDEzLCA3LCAxNSwgNCwgMSwgMiwgNiwgMTQsIDksIDExLCAzLCAwLCA4LCA1LCAxMiwgMTAgXSxcblx0XHRcdFx0WyAxMSwgOSwgNSwgMSwgMTIsIDMsIDEzLCAxNCwgNiwgNCwgNywgMTUsIDIsIDAsIDgsIDEwIF0gXTtcblx0XHR2YXIgcm9yNCA9IFsgMCwgOCwgMSwgOSwgMiwgMTAsIDMsIDExLCA0LCAxMiwgNSwgMTMsIDYsIDE0LCA3LCAxNSBdO1xuXHRcdHZhciBhc2h4ID0gWyAwLCA5LCAyLCAxMSwgNCwgMTMsIDYsIDE1LCA4LCAxLCAxMCwgMywgMTIsIDUsIDE0LCA3IF07XG5cdFx0dmFyIHEgPSBbIFtdLCBbXSBdO1xuXHRcdHZhciBtID0gWyBbXSwgW10sIFtdLCBbXSBdO1xuXG5cdFx0ZnVuY3Rpb24gZmZtNWIoeCkge1xuXHRcdFx0cmV0dXJuIHggXiAoeCA+PiAyKSBeIFsgMCwgOTAsIDE4MCwgMjM4IF1beCAmIDNdO1xuXHRcdH1cblx0XHRmdW5jdGlvbiBmZm1FZih4KSB7XG5cdFx0XHRyZXR1cm4geCBeICh4ID4+IDEpIF4gKHggPj4gMikgXiBbIDAsIDIzOCwgMTgwLCA5MCBdW3ggJiAzXTtcblx0XHR9XG5cblx0XHRmdW5jdGlvbiBtZHNSZW0ocCwgcSkge1xuXHRcdFx0dmFyIGksIHQsIHU7XG5cdFx0XHRmb3IgKGkgPSAwOyBpIDwgODsgaSsrKSB7XG5cdFx0XHRcdHQgPSBxID4+PiAyNDtcblx0XHRcdFx0cSA9ICgocSA8PCA4KSAmIE1BWElOVCkgfCBwID4+PiAyNDtcblx0XHRcdFx0cCA9IChwIDw8IDgpICYgTUFYSU5UO1xuXHRcdFx0XHR1ID0gdCA8PCAxO1xuXHRcdFx0XHRpZiAodCAmIDEyOCkge1xuXHRcdFx0XHRcdHUgXj0gMzMzO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHEgXj0gdCBeICh1IDw8IDE2KTtcblx0XHRcdFx0dSBePSB0ID4+PiAxO1xuXHRcdFx0XHRpZiAodCAmIDEpIHtcblx0XHRcdFx0XHR1IF49IDE2Njtcblx0XHRcdFx0fVxuXHRcdFx0XHRxIF49IHUgPDwgMjQgfCB1IDw8IDg7XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gcTtcblx0XHR9XG5cblx0XHRmdW5jdGlvbiBxcChuLCB4KSB7XG5cdFx0XHR2YXIgYSwgYiwgYywgZDtcblx0XHRcdGEgPSB4ID4+IDQ7XG5cdFx0XHRiID0geCAmIDE1O1xuXHRcdFx0YyA9IHEwW25dW2EgXiBiXTtcblx0XHRcdGQgPSBxMVtuXVtyb3I0W2JdIF4gYXNoeFthXV07XG5cdFx0XHRyZXR1cm4gcTNbbl1bcm9yNFtkXSBeIGFzaHhbY11dIDw8IDQgfCBxMltuXVtjIF4gZF07XG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gaEZ1bih4LCBrZXkpIHtcblx0XHRcdHZhciBhID0gZ2V0Qih4LCAwKSwgYiA9IGdldEIoeCwgMSksIGMgPSBnZXRCKHgsIDIpLCBkID0gZ2V0Qih4LCAzKTtcblx0XHRcdHN3aXRjaCAoa0xlbikge1xuXHRcdFx0Y2FzZSA0OlxuXHRcdFx0XHRhID0gcVsxXVthXSBeIGdldEIoa2V5WzNdLCAwKTtcblx0XHRcdFx0YiA9IHFbMF1bYl0gXiBnZXRCKGtleVszXSwgMSk7XG5cdFx0XHRcdGMgPSBxWzBdW2NdIF4gZ2V0QihrZXlbM10sIDIpO1xuXHRcdFx0XHRkID0gcVsxXVtkXSBeIGdldEIoa2V5WzNdLCAzKTtcblx0XHRcdGNhc2UgMzpcblx0XHRcdFx0YSA9IHFbMV1bYV0gXiBnZXRCKGtleVsyXSwgMCk7XG5cdFx0XHRcdGIgPSBxWzFdW2JdIF4gZ2V0QihrZXlbMl0sIDEpO1xuXHRcdFx0XHRjID0gcVswXVtjXSBeIGdldEIoa2V5WzJdLCAyKTtcblx0XHRcdFx0ZCA9IHFbMF1bZF0gXiBnZXRCKGtleVsyXSwgMyk7XG5cdFx0XHRjYXNlIDI6XG5cdFx0XHRcdGEgPSBxWzBdW3FbMF1bYV0gXiBnZXRCKGtleVsxXSwgMCldIF4gZ2V0QihrZXlbMF0sIDApO1xuXHRcdFx0XHRiID0gcVswXVtxWzFdW2JdIF4gZ2V0QihrZXlbMV0sIDEpXSBeIGdldEIoa2V5WzBdLCAxKTtcblx0XHRcdFx0YyA9IHFbMV1bcVswXVtjXSBeIGdldEIoa2V5WzFdLCAyKV0gXiBnZXRCKGtleVswXSwgMik7XG5cdFx0XHRcdGQgPSBxWzFdW3FbMV1bZF0gXiBnZXRCKGtleVsxXSwgMyldIF4gZ2V0QihrZXlbMF0sIDMpO1xuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIG1bMF1bYV0gXiBtWzFdW2JdIF4gbVsyXVtjXSBeIG1bM11bZF07XG5cdFx0fVxuXG5cdFx0a2V5Qnl0ZXMgPSBrZXlCeXRlcy5zbGljZSgwLCAzMik7XG5cdFx0aSA9IGtleUJ5dGVzLmxlbmd0aDtcblx0XHR3aGlsZSAoaSAhPSAxNiAmJiBpICE9IDI0ICYmIGkgIT0gMzIpXG5cdFx0XHRrZXlCeXRlc1tpKytdID0gMDtcblxuXHRcdGZvciAoaSA9IDA7IGkgPCBrZXlCeXRlcy5sZW5ndGg7IGkgKz0gNCkge1xuXHRcdFx0aW5LZXlbaSA+PiAyXSA9IGdldFcoa2V5Qnl0ZXMsIGkpO1xuXHRcdH1cblx0XHRmb3IgKGkgPSAwOyBpIDwgMjU2OyBpKyspIHtcblx0XHRcdHFbMF1baV0gPSBxcCgwLCBpKTtcblx0XHRcdHFbMV1baV0gPSBxcCgxLCBpKTtcblx0XHR9XG5cdFx0Zm9yIChpID0gMDsgaSA8IDI1NjsgaSsrKSB7XG5cdFx0XHRmMDEgPSBxWzFdW2ldO1xuXHRcdFx0ZjViID0gZmZtNWIoZjAxKTtcblx0XHRcdGZlZiA9IGZmbUVmKGYwMSk7XG5cdFx0XHRtWzBdW2ldID0gZjAxICsgKGY1YiA8PCA4KSArIChmZWYgPDwgMTYpICsgKGZlZiA8PCAyNCk7XG5cdFx0XHRtWzJdW2ldID0gZjViICsgKGZlZiA8PCA4KSArIChmMDEgPDwgMTYpICsgKGZlZiA8PCAyNCk7XG5cdFx0XHRmMDEgPSBxWzBdW2ldO1xuXHRcdFx0ZjViID0gZmZtNWIoZjAxKTtcblx0XHRcdGZlZiA9IGZmbUVmKGYwMSk7XG5cdFx0XHRtWzFdW2ldID0gZmVmICsgKGZlZiA8PCA4KSArIChmNWIgPDwgMTYpICsgKGYwMSA8PCAyNCk7XG5cdFx0XHRtWzNdW2ldID0gZjViICsgKGYwMSA8PCA4KSArIChmZWYgPDwgMTYpICsgKGY1YiA8PCAyNCk7XG5cdFx0fVxuXG5cdFx0a0xlbiA9IGluS2V5Lmxlbmd0aCAvIDI7XG5cdFx0Zm9yIChpID0gMDsgaSA8IGtMZW47IGkrKykge1xuXHRcdFx0YSA9IGluS2V5W2kgKyBpXTtcblx0XHRcdG1lS2V5W2ldID0gYTtcblx0XHRcdGIgPSBpbktleVtpICsgaSArIDFdO1xuXHRcdFx0bW9LZXlbaV0gPSBiO1xuXHRcdFx0c0tleVtrTGVuIC0gaSAtIDFdID0gbWRzUmVtKGEsIGIpO1xuXHRcdH1cblx0XHRmb3IgKGkgPSAwOyBpIDwgNDA7IGkgKz0gMikge1xuXHRcdFx0YSA9IDB4MTAxMDEwMSAqIGk7XG5cdFx0XHRiID0gYSArIDB4MTAxMDEwMTtcblx0XHRcdGEgPSBoRnVuKGEsIG1lS2V5KTtcblx0XHRcdGIgPSByb3R3KGhGdW4oYiwgbW9LZXkpLCA4KTtcblx0XHRcdHRmc0tleVtpXSA9IChhICsgYikgJiBNQVhJTlQ7XG5cdFx0XHR0ZnNLZXlbaSArIDFdID0gcm90dyhhICsgMiAqIGIsIDkpO1xuXHRcdH1cblx0XHRmb3IgKGkgPSAwOyBpIDwgMjU2OyBpKyspIHtcblx0XHRcdGEgPSBiID0gYyA9IGQgPSBpO1xuXHRcdFx0c3dpdGNoIChrTGVuKSB7XG5cdFx0XHRjYXNlIDQ6XG5cdFx0XHRcdGEgPSBxWzFdW2FdIF4gZ2V0QihzS2V5WzNdLCAwKTtcblx0XHRcdFx0YiA9IHFbMF1bYl0gXiBnZXRCKHNLZXlbM10sIDEpO1xuXHRcdFx0XHRjID0gcVswXVtjXSBeIGdldEIoc0tleVszXSwgMik7XG5cdFx0XHRcdGQgPSBxWzFdW2RdIF4gZ2V0QihzS2V5WzNdLCAzKTtcblx0XHRcdGNhc2UgMzpcblx0XHRcdFx0YSA9IHFbMV1bYV0gXiBnZXRCKHNLZXlbMl0sIDApO1xuXHRcdFx0XHRiID0gcVsxXVtiXSBeIGdldEIoc0tleVsyXSwgMSk7XG5cdFx0XHRcdGMgPSBxWzBdW2NdIF4gZ2V0QihzS2V5WzJdLCAyKTtcblx0XHRcdFx0ZCA9IHFbMF1bZF0gXiBnZXRCKHNLZXlbMl0sIDMpO1xuXHRcdFx0Y2FzZSAyOlxuXHRcdFx0XHR0ZnNNWzBdW2ldID0gbVswXVtxWzBdW3FbMF1bYV0gXiBnZXRCKHNLZXlbMV0sIDApXVxuXHRcdFx0XHRcdFx0XiBnZXRCKHNLZXlbMF0sIDApXTtcblx0XHRcdFx0dGZzTVsxXVtpXSA9IG1bMV1bcVswXVtxWzFdW2JdIF4gZ2V0QihzS2V5WzFdLCAxKV1cblx0XHRcdFx0XHRcdF4gZ2V0QihzS2V5WzBdLCAxKV07XG5cdFx0XHRcdHRmc01bMl1baV0gPSBtWzJdW3FbMV1bcVswXVtjXSBeIGdldEIoc0tleVsxXSwgMildXG5cdFx0XHRcdFx0XHReIGdldEIoc0tleVswXSwgMildO1xuXHRcdFx0XHR0ZnNNWzNdW2ldID0gbVszXVtxWzFdW3FbMV1bZF0gXiBnZXRCKHNLZXlbMV0sIDMpXVxuXHRcdFx0XHRcdFx0XiBnZXRCKHNLZXlbMF0sIDMpXTtcblx0XHRcdH1cblx0XHR9XG5cdH1cblxuXHRmdW5jdGlvbiB0ZnNHMCh4KSB7XG5cdFx0cmV0dXJuIHRmc01bMF1bZ2V0Qih4LCAwKV0gXiB0ZnNNWzFdW2dldEIoeCwgMSldIF4gdGZzTVsyXVtnZXRCKHgsIDIpXVxuXHRcdFx0XHReIHRmc01bM11bZ2V0Qih4LCAzKV07XG5cdH1cblx0ZnVuY3Rpb24gdGZzRzEoeCkge1xuXHRcdHJldHVybiB0ZnNNWzBdW2dldEIoeCwgMyldIF4gdGZzTVsxXVtnZXRCKHgsIDApXSBeIHRmc01bMl1bZ2V0Qih4LCAxKV1cblx0XHRcdFx0XiB0ZnNNWzNdW2dldEIoeCwgMildO1xuXHR9XG5cblx0ZnVuY3Rpb24gdGZzRnJuZChyLCBibGspIHtcblx0XHR2YXIgYSA9IHRmc0cwKGJsa1swXSk7XG5cdFx0dmFyIGIgPSB0ZnNHMShibGtbMV0pO1xuXHRcdGJsa1syXSA9IHJvdHcoYmxrWzJdIF4gKGEgKyBiICsgdGZzS2V5WzQgKiByICsgOF0pICYgTUFYSU5ULCAzMSk7XG5cdFx0YmxrWzNdID0gcm90dyhibGtbM10sIDEpIF4gKGEgKyAyICogYiArIHRmc0tleVs0ICogciArIDldKSAmIE1BWElOVDtcblx0XHRhID0gdGZzRzAoYmxrWzJdKTtcblx0XHRiID0gdGZzRzEoYmxrWzNdKTtcblx0XHRibGtbMF0gPSByb3R3KGJsa1swXSBeIChhICsgYiArIHRmc0tleVs0ICogciArIDEwXSkgJiBNQVhJTlQsIDMxKTtcblx0XHRibGtbMV0gPSByb3R3KGJsa1sxXSwgMSkgXiAoYSArIDIgKiBiICsgdGZzS2V5WzQgKiByICsgMTFdKSAmIE1BWElOVDtcblx0fVxuXG5cdGZ1bmN0aW9uIHRmc0lybmQoaSwgYmxrKSB7XG5cdFx0dmFyIGEgPSB0ZnNHMChibGtbMF0pO1xuXHRcdHZhciBiID0gdGZzRzEoYmxrWzFdKTtcblx0XHRibGtbMl0gPSByb3R3KGJsa1syXSwgMSkgXiAoYSArIGIgKyB0ZnNLZXlbNCAqIGkgKyAxMF0pICYgTUFYSU5UO1xuXHRcdGJsa1szXSA9IHJvdHcoYmxrWzNdIF4gKGEgKyAyICogYiArIHRmc0tleVs0ICogaSArIDExXSkgJiBNQVhJTlQsIDMxKTtcblx0XHRhID0gdGZzRzAoYmxrWzJdKTtcblx0XHRiID0gdGZzRzEoYmxrWzNdKTtcblx0XHRibGtbMF0gPSByb3R3KGJsa1swXSwgMSkgXiAoYSArIGIgKyB0ZnNLZXlbNCAqIGkgKyA4XSkgJiBNQVhJTlQ7XG5cdFx0YmxrWzFdID0gcm90dyhibGtbMV0gXiAoYSArIDIgKiBiICsgdGZzS2V5WzQgKiBpICsgOV0pICYgTUFYSU5ULCAzMSk7XG5cdH1cblxuXHRmdW5jdGlvbiB0ZnNDbG9zZSgpIHtcblx0XHR0ZnNLZXkgPSBbXTtcblx0XHR0ZnNNID0gWyBbXSwgW10sIFtdLCBbXSBdO1xuXHR9XG5cblx0ZnVuY3Rpb24gdGZzRW5jcnlwdChkYXRhLCBvZmZzZXQpIHtcblx0XHRkYXRhQnl0ZXMgPSBkYXRhO1xuXHRcdGRhdGFPZmZzZXQgPSBvZmZzZXQ7XG5cdFx0dmFyIGJsayA9IFsgZ2V0VyhkYXRhQnl0ZXMsIGRhdGFPZmZzZXQpIF4gdGZzS2V5WzBdLFxuXHRcdFx0XHRnZXRXKGRhdGFCeXRlcywgZGF0YU9mZnNldCArIDQpIF4gdGZzS2V5WzFdLFxuXHRcdFx0XHRnZXRXKGRhdGFCeXRlcywgZGF0YU9mZnNldCArIDgpIF4gdGZzS2V5WzJdLFxuXHRcdFx0XHRnZXRXKGRhdGFCeXRlcywgZGF0YU9mZnNldCArIDEyKSBeIHRmc0tleVszXSBdO1xuXHRcdGZvciAoIHZhciBqID0gMDsgaiA8IDg7IGorKykge1xuXHRcdFx0dGZzRnJuZChqLCBibGspO1xuXHRcdH1cblx0XHRzZXRXKGRhdGFCeXRlcywgZGF0YU9mZnNldCwgYmxrWzJdIF4gdGZzS2V5WzRdKTtcblx0XHRzZXRXKGRhdGFCeXRlcywgZGF0YU9mZnNldCArIDQsIGJsa1szXSBeIHRmc0tleVs1XSk7XG5cdFx0c2V0VyhkYXRhQnl0ZXMsIGRhdGFPZmZzZXQgKyA4LCBibGtbMF0gXiB0ZnNLZXlbNl0pO1xuXHRcdHNldFcoZGF0YUJ5dGVzLCBkYXRhT2Zmc2V0ICsgMTIsIGJsa1sxXSBeIHRmc0tleVs3XSk7XG5cdFx0ZGF0YU9mZnNldCArPSAxNjtcblx0XHRyZXR1cm4gZGF0YUJ5dGVzO1xuXHR9XG5cblx0ZnVuY3Rpb24gdGZzRGVjcnlwdChkYXRhLCBvZmZzZXQpIHtcblx0XHRkYXRhQnl0ZXMgPSBkYXRhO1xuXHRcdGRhdGFPZmZzZXQgPSBvZmZzZXQ7XG5cdFx0dmFyIGJsayA9IFsgZ2V0VyhkYXRhQnl0ZXMsIGRhdGFPZmZzZXQpIF4gdGZzS2V5WzRdLFxuXHRcdFx0XHRnZXRXKGRhdGFCeXRlcywgZGF0YU9mZnNldCArIDQpIF4gdGZzS2V5WzVdLFxuXHRcdFx0XHRnZXRXKGRhdGFCeXRlcywgZGF0YU9mZnNldCArIDgpIF4gdGZzS2V5WzZdLFxuXHRcdFx0XHRnZXRXKGRhdGFCeXRlcywgZGF0YU9mZnNldCArIDEyKSBeIHRmc0tleVs3XSBdO1xuXHRcdGZvciAoIHZhciBqID0gNzsgaiA+PSAwOyBqLS0pIHtcblx0XHRcdHRmc0lybmQoaiwgYmxrKTtcblx0XHR9XG5cdFx0c2V0VyhkYXRhQnl0ZXMsIGRhdGFPZmZzZXQsIGJsa1syXSBeIHRmc0tleVswXSk7XG5cdFx0c2V0VyhkYXRhQnl0ZXMsIGRhdGFPZmZzZXQgKyA0LCBibGtbM10gXiB0ZnNLZXlbMV0pO1xuXHRcdHNldFcoZGF0YUJ5dGVzLCBkYXRhT2Zmc2V0ICsgOCwgYmxrWzBdIF4gdGZzS2V5WzJdKTtcblx0XHRzZXRXKGRhdGFCeXRlcywgZGF0YU9mZnNldCArIDEyLCBibGtbMV0gXiB0ZnNLZXlbM10pO1xuXHRcdGRhdGFPZmZzZXQgKz0gMTY7XG5cdH1cblx0XG5cdC8vIGFkZGVkIGJ5IFJlY3VyaXR5IExhYnNcblx0ZnVuY3Rpb24gdGZzRmluYWwoKSB7XG5cdFx0cmV0dXJuIGRhdGFCeXRlcztcblx0fVxuXG5cdHJldHVybiB7XG5cdFx0bmFtZSA6IFwidHdvZmlzaFwiLFxuXHRcdGJsb2Nrc2l6ZSA6IDEyOCAvIDgsXG5cdFx0b3BlbiA6IHRmc0luaXQsXG5cdFx0Y2xvc2UgOiB0ZnNDbG9zZSxcblx0XHRlbmNyeXB0IDogdGZzRW5jcnlwdCxcblx0XHRkZWNyeXB0IDogdGZzRGVjcnlwdCxcblx0XHQvLyBhZGRlZCBieSBSZWN1cml0eSBMYWJzXG5cdFx0ZmluYWxpemU6IHRmc0ZpbmFsXG5cdH07XG59XG5cbm1vZHVsZS5leHBvcnRzID0gVEZlbmNyeXB0O1xuIiwiLyogTW9kaWZpZWQgYnkgUmVjdXJpdHkgTGFicyBHbWJIIFxuICogXG4gKiBPcmlnaW5hbGx5IHdyaXR0ZW4gYnkgbmtsZWluIHNvZnR3YXJlIChua2xlaW4uY29tKVxuICovXG5cbi8qIFxuICogSmF2YXNjcmlwdCBpbXBsZW1lbnRhdGlvbiBiYXNlZCBvbiBCcnVjZSBTY2huZWllcidzIHJlZmVyZW5jZSBpbXBsZW1lbnRhdGlvbi5cbiAqXG4gKlxuICogVGhlIGNvbnN0cnVjdG9yIGRvZXNuJ3QgZG8gbXVjaCBvZiBhbnl0aGluZy4gIEl0J3MganVzdCBoZXJlXG4gKiBzbyB3ZSBjYW4gc3RhcnQgZGVmaW5pbmcgcHJvcGVydGllcyBhbmQgbWV0aG9kcyBhbmQgc3VjaC5cbiAqL1xuZnVuY3Rpb24gQmxvd2Zpc2goKSB7XG59O1xuXG4vKlxuICogRGVjbGFyZSB0aGUgYmxvY2sgc2l6ZSBzbyB0aGF0IHByb3RvY29scyBrbm93IHdoYXQgc2l6ZVxuICogSW5pdGlhbGl6YXRpb24gVmVjdG9yIChJVikgdGhleSB3aWxsIG5lZWQuXG4gKi9cbkJsb3dmaXNoLnByb3RvdHlwZS5CTE9DS1NJWkUgPSA4O1xuXG4vKlxuICogVGhlc2UgYXJlIHRoZSBkZWZhdWx0IFNCT1hFUy5cbiAqL1xuQmxvd2Zpc2gucHJvdG90eXBlLlNCT1hFUyA9IFtcbiAgICBbXG5cdDB4ZDEzMTBiYTYsIDB4OThkZmI1YWMsIDB4MmZmZDcyZGIsIDB4ZDAxYWRmYjcsIDB4YjhlMWFmZWQsIDB4NmEyNjdlOTYsXG5cdDB4YmE3YzkwNDUsIDB4ZjEyYzdmOTksIDB4MjRhMTk5NDcsIDB4YjM5MTZjZjcsIDB4MDgwMWYyZTIsIDB4ODU4ZWZjMTYsXG5cdDB4NjM2OTIwZDgsIDB4NzE1NzRlNjksIDB4YTQ1OGZlYTMsIDB4ZjQ5MzNkN2UsIDB4MGQ5NTc0OGYsIDB4NzI4ZWI2NTgsXG5cdDB4NzE4YmNkNTgsIDB4ODIxNTRhZWUsIDB4N2I1NGE0MWQsIDB4YzI1YTU5YjUsIDB4OWMzMGQ1MzksIDB4MmFmMjYwMTMsXG5cdDB4YzVkMWIwMjMsIDB4Mjg2MDg1ZjAsIDB4Y2E0MTc5MTgsIDB4YjhkYjM4ZWYsIDB4OGU3OWRjYjAsIDB4NjAzYTE4MGUsXG5cdDB4NmM5ZTBlOGIsIDB4YjAxZThhM2UsIDB4ZDcxNTc3YzEsIDB4YmQzMTRiMjcsIDB4NzhhZjJmZGEsIDB4NTU2MDVjNjAsXG5cdDB4ZTY1NTI1ZjMsIDB4YWE1NWFiOTQsIDB4NTc0ODk4NjIsIDB4NjNlODE0NDAsIDB4NTVjYTM5NmEsIDB4MmFhYjEwYjYsXG5cdDB4YjRjYzVjMzQsIDB4MTE0MWU4Y2UsIDB4YTE1NDg2YWYsIDB4N2M3MmU5OTMsIDB4YjNlZTE0MTEsIDB4NjM2ZmJjMmEsXG5cdDB4MmJhOWM1NWQsIDB4NzQxODMxZjYsIDB4Y2U1YzNlMTYsIDB4OWI4NzkzMWUsIDB4YWZkNmJhMzMsIDB4NmMyNGNmNWMsXG5cdDB4N2EzMjUzODEsIDB4Mjg5NTg2NzcsIDB4M2I4ZjQ4OTgsIDB4NmI0YmI5YWYsIDB4YzRiZmU4MWIsIDB4NjYyODIxOTMsXG5cdDB4NjFkODA5Y2MsIDB4ZmIyMWE5OTEsIDB4NDg3Y2FjNjAsIDB4NWRlYzgwMzIsIDB4ZWY4NDVkNWQsIDB4ZTk4NTc1YjEsXG5cdDB4ZGMyNjIzMDIsIDB4ZWI2NTFiODgsIDB4MjM4OTNlODEsIDB4ZDM5NmFjYzUsIDB4MGY2ZDZmZjMsIDB4ODNmNDQyMzksXG5cdDB4MmUwYjQ0ODIsIDB4YTQ4NDIwMDQsIDB4NjljOGYwNGEsIDB4OWUxZjliNWUsIDB4MjFjNjY4NDIsIDB4ZjZlOTZjOWEsXG5cdDB4NjcwYzljNjEsIDB4YWJkMzg4ZjAsIDB4NmE1MWEwZDIsIDB4ZDg1NDJmNjgsIDB4OTYwZmE3MjgsIDB4YWI1MTMzYTMsXG5cdDB4NmVlZjBiNmMsIDB4MTM3YTNiZTQsIDB4YmEzYmYwNTAsIDB4N2VmYjJhOTgsIDB4YTFmMTY1MWQsIDB4MzlhZjAxNzYsXG5cdDB4NjZjYTU5M2UsIDB4ODI0MzBlODgsIDB4OGNlZTg2MTksIDB4NDU2ZjlmYjQsIDB4N2Q4NGE1YzMsIDB4M2I4YjVlYmUsXG5cdDB4ZTA2Zjc1ZDgsIDB4ODVjMTIwNzMsIDB4NDAxYTQ0OWYsIDB4NTZjMTZhYTYsIDB4NGVkM2FhNjIsIDB4MzYzZjc3MDYsXG5cdDB4MWJmZWRmNzIsIDB4NDI5YjAyM2QsIDB4MzdkMGQ3MjQsIDB4ZDAwYTEyNDgsIDB4ZGIwZmVhZDMsIDB4NDlmMWMwOWIsXG5cdDB4MDc1MzcyYzksIDB4ODA5OTFiN2IsIDB4MjVkNDc5ZDgsIDB4ZjZlOGRlZjcsIDB4ZTNmZTUwMWEsIDB4YjY3OTRjM2IsXG5cdDB4OTc2Y2UwYmQsIDB4MDRjMDA2YmEsIDB4YzFhOTRmYjYsIDB4NDA5ZjYwYzQsIDB4NWU1YzllYzIsIDB4MTk2YTI0NjMsXG5cdDB4NjhmYjZmYWYsIDB4M2U2YzUzYjUsIDB4MTMzOWIyZWIsIDB4M2I1MmVjNmYsIDB4NmRmYzUxMWYsIDB4OWIzMDk1MmMsXG5cdDB4Y2M4MTQ1NDQsIDB4YWY1ZWJkMDksIDB4YmVlM2QwMDQsIDB4ZGUzMzRhZmQsIDB4NjYwZjI4MDcsIDB4MTkyZTRiYjMsXG5cdDB4YzBjYmE4NTcsIDB4NDVjODc0MGYsIDB4ZDIwYjVmMzksIDB4YjlkM2ZiZGIsIDB4NTU3OWMwYmQsIDB4MWE2MDMyMGEsXG5cdDB4ZDZhMTAwYzYsIDB4NDAyYzcyNzksIDB4Njc5ZjI1ZmUsIDB4ZmIxZmEzY2MsIDB4OGVhNWU5ZjgsIDB4ZGIzMjIyZjgsXG5cdDB4M2M3NTE2ZGYsIDB4ZmQ2MTZiMTUsIDB4MmY1MDFlYzgsIDB4YWQwNTUyYWIsIDB4MzIzZGI1ZmEsIDB4ZmQyMzg3NjAsXG5cdDB4NTMzMTdiNDgsIDB4M2UwMGRmODIsIDB4OWU1YzU3YmIsIDB4Y2E2ZjhjYTAsIDB4MWE4NzU2MmUsIDB4ZGYxNzY5ZGIsXG5cdDB4ZDU0MmE4ZjYsIDB4Mjg3ZWZmYzMsIDB4YWM2NzMyYzYsIDB4OGM0ZjU1NzMsIDB4Njk1YjI3YjAsIDB4YmJjYTU4YzgsXG5cdDB4ZTFmZmEzNWQsIDB4YjhmMDExYTAsIDB4MTBmYTNkOTgsIDB4ZmQyMTgzYjgsIDB4NGFmY2I1NmMsIDB4MmRkMWQzNWIsXG5cdDB4OWE1M2U0NzksIDB4YjZmODQ1NjUsIDB4ZDI4ZTQ5YmMsIDB4NGJmYjk3OTAsIDB4ZTFkZGYyZGEsIDB4YTRjYjdlMzMsXG5cdDB4NjJmYjEzNDEsIDB4Y2VlNGM2ZTgsIDB4ZWYyMGNhZGEsIDB4MzY3NzRjMDEsIDB4ZDA3ZTllZmUsIDB4MmJmMTFmYjQsXG5cdDB4OTVkYmRhNGQsIDB4YWU5MDkxOTgsIDB4ZWFhZDhlNzEsIDB4NmI5M2Q1YTAsIDB4ZDA4ZWQxZDAsIDB4YWZjNzI1ZTAsXG5cdDB4OGUzYzViMmYsIDB4OGU3NTk0YjcsIDB4OGZmNmUyZmIsIDB4ZjIxMjJiNjQsIDB4ODg4OGI4MTIsIDB4OTAwZGYwMWMsXG5cdDB4NGZhZDVlYTAsIDB4Njg4ZmMzMWMsIDB4ZDFjZmYxOTEsIDB4YjNhOGMxYWQsIDB4MmYyZjIyMTgsIDB4YmUwZTE3NzcsXG5cdDB4ZWE3NTJkZmUsIDB4OGIwMjFmYTEsIDB4ZTVhMGNjMGYsIDB4YjU2Zjc0ZTgsIDB4MThhY2YzZDYsIDB4Y2U4OWUyOTksXG5cdDB4YjRhODRmZTAsIDB4ZmQxM2UwYjcsIDB4N2NjNDNiODEsIDB4ZDJhZGE4ZDksIDB4MTY1ZmEyNjYsIDB4ODA5NTc3MDUsXG5cdDB4OTNjYzczMTQsIDB4MjExYTE0NzcsIDB4ZTZhZDIwNjUsIDB4NzdiNWZhODYsIDB4Yzc1NDQyZjUsIDB4ZmI5ZDM1Y2YsXG5cdDB4ZWJjZGFmMGMsIDB4N2IzZTg5YTAsIDB4ZDY0MTFiZDMsIDB4YWUxZTdlNDksIDB4MDAyNTBlMmQsIDB4MjA3MWIzNWUsXG5cdDB4MjI2ODAwYmIsIDB4NTdiOGUwYWYsIDB4MjQ2NDM2OWIsIDB4ZjAwOWI5MWUsIDB4NTU2MzkxMWQsIDB4NTlkZmE2YWEsXG5cdDB4NzhjMTQzODksIDB4ZDk1YTUzN2YsIDB4MjA3ZDViYTIsIDB4MDJlNWI5YzUsIDB4ODMyNjAzNzYsIDB4NjI5NWNmYTksXG5cdDB4MTFjODE5NjgsIDB4NGU3MzRhNDEsIDB4YjM0NzJkY2EsIDB4N2IxNGE5NGEsIDB4MWI1MTAwNTIsIDB4OWE1MzI5MTUsXG5cdDB4ZDYwZjU3M2YsIDB4YmM5YmM2ZTQsIDB4MmI2MGE0NzYsIDB4ODFlNjc0MDAsIDB4MDhiYTZmYjUsIDB4NTcxYmU5MWYsXG5cdDB4ZjI5NmVjNmIsIDB4MmEwZGQ5MTUsIDB4YjY2MzY1MjEsIDB4ZTdiOWY5YjYsIDB4ZmYzNDA1MmUsIDB4YzU4NTU2NjQsXG5cdDB4NTNiMDJkNWQsIDB4YTk5ZjhmYTEsIDB4MDhiYTQ3OTksIDB4NmU4NTA3NmFcbiAgICBdLCBbXG5cdDB4NGI3YTcwZTksIDB4YjViMzI5NDQsIDB4ZGI3NTA5MmUsIDB4YzQxOTI2MjMsIDB4YWQ2ZWE2YjAsIDB4NDlhN2RmN2QsXG5cdDB4OWNlZTYwYjgsIDB4OGZlZGIyNjYsIDB4ZWNhYThjNzEsIDB4Njk5YTE3ZmYsIDB4NTY2NDUyNmMsIDB4YzJiMTllZTEsXG5cdDB4MTkzNjAyYTUsIDB4NzUwOTRjMjksIDB4YTA1OTEzNDAsIDB4ZTQxODNhM2UsIDB4M2Y1NDk4OWEsIDB4NWI0MjlkNjUsXG5cdDB4NmI4ZmU0ZDYsIDB4OTlmNzNmZDYsIDB4YTFkMjljMDcsIDB4ZWZlODMwZjUsIDB4NGQyZDM4ZTYsIDB4ZjAyNTVkYzEsXG5cdDB4NGNkZDIwODYsIDB4ODQ3MGViMjYsIDB4NjM4MmU5YzYsIDB4MDIxZWNjNWUsIDB4MDk2ODZiM2YsIDB4M2ViYWVmYzksXG5cdDB4M2M5NzE4MTQsIDB4NmI2YTcwYTEsIDB4Njg3ZjM1ODQsIDB4NTJhMGUyODYsIDB4Yjc5YzUzMDUsIDB4YWE1MDA3MzcsXG5cdDB4M2UwNzg0MWMsIDB4N2ZkZWFlNWMsIDB4OGU3ZDQ0ZWMsIDB4NTcxNmYyYjgsIDB4YjAzYWRhMzcsIDB4ZjA1MDBjMGQsXG5cdDB4ZjAxYzFmMDQsIDB4MDIwMGIzZmYsIDB4YWUwY2Y1MWEsIDB4M2NiNTc0YjIsIDB4MjU4MzdhNTgsIDB4ZGMwOTIxYmQsXG5cdDB4ZDE5MTEzZjksIDB4N2NhOTJmZjYsIDB4OTQzMjQ3NzMsIDB4MjJmNTQ3MDEsIDB4M2FlNWU1ODEsIDB4MzdjMmRhZGMsXG5cdDB4YzhiNTc2MzQsIDB4OWFmM2RkYTcsIDB4YTk0NDYxNDYsIDB4MGZkMDAzMGUsIDB4ZWNjOGM3M2UsIDB4YTQ3NTFlNDEsXG5cdDB4ZTIzOGNkOTksIDB4M2JlYTBlMmYsIDB4MzI4MGJiYTEsIDB4MTgzZWIzMzEsIDB4NGU1NDhiMzgsIDB4NGY2ZGI5MDgsXG5cdDB4NmY0MjBkMDMsIDB4ZjYwYTA0YmYsIDB4MmNiODEyOTAsIDB4MjQ5NzdjNzksIDB4NTY3OWIwNzIsIDB4YmNhZjg5YWYsXG5cdDB4ZGU5YTc3MWYsIDB4ZDk5MzA4MTAsIDB4YjM4YmFlMTIsIDB4ZGNjZjNmMmUsIDB4NTUxMjcyMWYsIDB4MmU2YjcxMjQsXG5cdDB4NTAxYWRkZTYsIDB4OWY4NGNkODcsIDB4N2E1ODQ3MTgsIDB4NzQwOGRhMTcsIDB4YmM5ZjlhYmMsIDB4ZTk0YjdkOGMsXG5cdDB4ZWM3YWVjM2EsIDB4ZGI4NTFkZmEsIDB4NjMwOTQzNjYsIDB4YzQ2NGMzZDIsIDB4ZWYxYzE4NDcsIDB4MzIxNWQ5MDgsXG5cdDB4ZGQ0MzNiMzcsIDB4MjRjMmJhMTYsIDB4MTJhMTRkNDMsIDB4MmE2NWM0NTEsIDB4NTA5NDAwMDIsIDB4MTMzYWU0ZGQsXG5cdDB4NzFkZmY4OWUsIDB4MTAzMTRlNTUsIDB4ODFhYzc3ZDYsIDB4NWYxMTE5OWIsIDB4MDQzNTU2ZjEsIDB4ZDdhM2M3NmIsXG5cdDB4M2MxMTE4M2IsIDB4NTkyNGE1MDksIDB4ZjI4ZmU2ZWQsIDB4OTdmMWZiZmEsIDB4OWViYWJmMmMsIDB4MWUxNTNjNmUsXG5cdDB4ODZlMzQ1NzAsIDB4ZWFlOTZmYjEsIDB4ODYwZTVlMGEsIDB4NWEzZTJhYjMsIDB4NzcxZmU3MWMsIDB4NGUzZDA2ZmEsXG5cdDB4Mjk2NWRjYjksIDB4OTllNzFkMGYsIDB4ODAzZTg5ZDYsIDB4NTI2NmM4MjUsIDB4MmU0Y2M5NzgsIDB4OWMxMGIzNmEsXG5cdDB4YzYxNTBlYmEsIDB4OTRlMmVhNzgsIDB4YTVmYzNjNTMsIDB4MWUwYTJkZjQsIDB4ZjJmNzRlYTcsIDB4MzYxZDJiM2QsXG5cdDB4MTkzOTI2MGYsIDB4MTljMjc5NjAsIDB4NTIyM2E3MDgsIDB4ZjcxMzEyYjYsIDB4ZWJhZGZlNmUsIDB4ZWFjMzFmNjYsXG5cdDB4ZTNiYzQ1OTUsIDB4YTY3YmM4ODMsIDB4YjE3ZjM3ZDEsIDB4MDE4Y2ZmMjgsIDB4YzMzMmRkZWYsIDB4YmU2YzVhYTUsXG5cdDB4NjU1ODIxODUsIDB4NjhhYjk4MDIsIDB4ZWVjZWE1MGYsIDB4ZGIyZjk1M2IsIDB4MmFlZjdkYWQsIDB4NWI2ZTJmODQsXG5cdDB4MTUyMWI2MjgsIDB4MjkwNzYxNzAsIDB4ZWNkZDQ3NzUsIDB4NjE5ZjE1MTAsIDB4MTNjY2E4MzAsIDB4ZWI2MWJkOTYsXG5cdDB4MDMzNGZlMWUsIDB4YWEwMzYzY2YsIDB4YjU3MzVjOTAsIDB4NGM3MGEyMzksIDB4ZDU5ZTllMGIsIDB4Y2JhYWRlMTQsXG5cdDB4ZWVjYzg2YmMsIDB4NjA2MjJjYTcsIDB4OWNhYjVjYWIsIDB4YjJmMzg0NmUsIDB4NjQ4YjFlYWYsIDB4MTliZGYwY2EsXG5cdDB4YTAyMzY5YjksIDB4NjU1YWJiNTAsIDB4NDA2ODVhMzIsIDB4M2MyYWI0YjMsIDB4MzE5ZWU5ZDUsIDB4YzAyMWI4ZjcsXG5cdDB4OWI1NDBiMTksIDB4ODc1ZmEwOTksIDB4OTVmNzk5N2UsIDB4NjIzZDdkYTgsIDB4ZjgzNzg4OWEsIDB4OTdlMzJkNzcsXG5cdDB4MTFlZDkzNWYsIDB4MTY2ODEyODEsIDB4MGUzNTg4MjksIDB4YzdlNjFmZDYsIDB4OTZkZWRmYTEsIDB4Nzg1OGJhOTksXG5cdDB4NTdmNTg0YTUsIDB4MWIyMjcyNjMsIDB4OWI4M2MzZmYsIDB4MWFjMjQ2OTYsIDB4Y2RiMzBhZWIsIDB4NTMyZTMwNTQsXG5cdDB4OGZkOTQ4ZTQsIDB4NmRiYzMxMjgsIDB4NThlYmYyZWYsIDB4MzRjNmZmZWEsIDB4ZmUyOGVkNjEsIDB4ZWU3YzNjNzMsXG5cdDB4NWQ0YTE0ZDksIDB4ZTg2NGI3ZTMsIDB4NDIxMDVkMTQsIDB4MjAzZTEzZTAsIDB4NDVlZWUyYjYsIDB4YTNhYWFiZWEsXG5cdDB4ZGI2YzRmMTUsIDB4ZmFjYjRmZDAsIDB4Yzc0MmY0NDIsIDB4ZWY2YWJiYjUsIDB4NjU0ZjNiMWQsIDB4NDFjZDIxMDUsXG5cdDB4ZDgxZTc5OWUsIDB4ODY4NTRkYzcsIDB4ZTQ0YjQ3NmEsIDB4M2Q4MTYyNTAsIDB4Y2Y2MmExZjIsIDB4NWI4ZDI2NDYsXG5cdDB4ZmM4ODgzYTAsIDB4YzFjN2I2YTMsIDB4N2YxNTI0YzMsIDB4NjljYjc0OTIsIDB4NDc4NDhhMGIsIDB4NTY5MmIyODUsXG5cdDB4MDk1YmJmMDAsIDB4YWQxOTQ4OWQsIDB4MTQ2MmIxNzQsIDB4MjM4MjBlMDAsIDB4NTg0MjhkMmEsIDB4MGM1NWY1ZWEsXG5cdDB4MWRhZGY0M2UsIDB4MjMzZjcwNjEsIDB4MzM3MmYwOTIsIDB4OGQ5MzdlNDEsIDB4ZDY1ZmVjZjEsIDB4NmMyMjNiZGIsXG5cdDB4N2NkZTM3NTksIDB4Y2JlZTc0NjAsIDB4NDA4NWYyYTcsIDB4Y2U3NzMyNmUsIDB4YTYwNzgwODQsIDB4MTlmODUwOWUsXG5cdDB4ZThlZmQ4NTUsIDB4NjFkOTk3MzUsIDB4YTk2OWE3YWEsIDB4YzUwYzA2YzIsIDB4NWEwNGFiZmMsIDB4ODAwYmNhZGMsXG5cdDB4OWU0NDdhMmUsIDB4YzM0NTM0ODQsIDB4ZmRkNTY3MDUsIDB4MGUxZTllYzksIDB4ZGI3M2RiZDMsIDB4MTA1NTg4Y2QsXG5cdDB4Njc1ZmRhNzksIDB4ZTM2NzQzNDAsIDB4YzVjNDM0NjUsIDB4NzEzZTM4ZDgsIDB4M2QyOGY4OWUsIDB4ZjE2ZGZmMjAsXG5cdDB4MTUzZTIxZTcsIDB4OGZiMDNkNGEsIDB4ZTZlMzlmMmIsIDB4ZGI4M2FkZjdcbiAgICBdLCBbXG5cdDB4ZTkzZDVhNjgsIDB4OTQ4MTQwZjcsIDB4ZjY0YzI2MWMsIDB4OTQ2OTI5MzQsIDB4NDExNTIwZjcsIDB4NzYwMmQ0ZjcsXG5cdDB4YmNmNDZiMmUsIDB4ZDRhMjAwNjgsIDB4ZDQwODI0NzEsIDB4MzMyMGY0NmEsIDB4NDNiN2Q0YjcsIDB4NTAwMDYxYWYsXG5cdDB4MWUzOWY2MmUsIDB4OTcyNDQ1NDYsIDB4MTQyMTRmNzQsIDB4YmY4Yjg4NDAsIDB4NGQ5NWZjMWQsIDB4OTZiNTkxYWYsXG5cdDB4NzBmNGRkZDMsIDB4NjZhMDJmNDUsIDB4YmZiYzA5ZWMsIDB4MDNiZDk3ODUsIDB4N2ZhYzZkZDAsIDB4MzFjYjg1MDQsXG5cdDB4OTZlYjI3YjMsIDB4NTVmZDM5NDEsIDB4ZGEyNTQ3ZTYsIDB4YWJjYTBhOWEsIDB4Mjg1MDc4MjUsIDB4NTMwNDI5ZjQsXG5cdDB4MGEyYzg2ZGEsIDB4ZTliNjZkZmIsIDB4NjhkYzE0NjIsIDB4ZDc0ODY5MDAsIDB4NjgwZWMwYTQsIDB4MjdhMThkZWUsXG5cdDB4NGYzZmZlYTIsIDB4ZTg4N2FkOGMsIDB4YjU4Y2UwMDYsIDB4N2FmNGQ2YjYsIDB4YWFjZTFlN2MsIDB4ZDMzNzVmZWMsXG5cdDB4Y2U3OGEzOTksIDB4NDA2YjJhNDIsIDB4MjBmZTllMzUsIDB4ZDlmMzg1YjksIDB4ZWUzOWQ3YWIsIDB4M2IxMjRlOGIsXG5cdDB4MWRjOWZhZjcsIDB4NGI2ZDE4NTYsIDB4MjZhMzY2MzEsIDB4ZWFlMzk3YjIsIDB4M2E2ZWZhNzQsIDB4ZGQ1YjQzMzIsXG5cdDB4Njg0MWU3ZjcsIDB4Y2E3ODIwZmIsIDB4ZmIwYWY1NGUsIDB4ZDhmZWIzOTcsIDB4NDU0MDU2YWMsIDB4YmE0ODk1MjcsXG5cdDB4NTU1MzNhM2EsIDB4MjA4MzhkODcsIDB4ZmU2YmE5YjcsIDB4ZDA5Njk1NGIsIDB4NTVhODY3YmMsIDB4YTExNTlhNTgsXG5cdDB4Y2NhOTI5NjMsIDB4OTllMWRiMzMsIDB4YTYyYTRhNTYsIDB4M2YzMTI1ZjksIDB4NWVmNDdlMWMsIDB4OTAyOTMxN2MsXG5cdDB4ZmRmOGU4MDIsIDB4MDQyNzJmNzAsIDB4ODBiYjE1NWMsIDB4MDUyODJjZTMsIDB4OTVjMTE1NDgsIDB4ZTRjNjZkMjIsXG5cdDB4NDhjMTEzM2YsIDB4YzcwZjg2ZGMsIDB4MDdmOWM5ZWUsIDB4NDEwNDFmMGYsIDB4NDA0Nzc5YTQsIDB4NWQ4ODZlMTcsXG5cdDB4MzI1ZjUxZWIsIDB4ZDU5YmMwZDEsIDB4ZjJiY2MxOGYsIDB4NDExMTM1NjQsIDB4MjU3Yjc4MzQsIDB4NjAyYTljNjAsXG5cdDB4ZGZmOGU4YTMsIDB4MWY2MzZjMWIsIDB4MGUxMmI0YzIsIDB4MDJlMTMyOWUsIDB4YWY2NjRmZDEsIDB4Y2FkMTgxMTUsXG5cdDB4NmIyMzk1ZTAsIDB4MzMzZTkyZTEsIDB4M2IyNDBiNjIsIDB4ZWViZWI5MjIsIDB4ODViMmEyMGUsIDB4ZTZiYTBkOTksXG5cdDB4ZGU3MjBjOGMsIDB4MmRhMmY3MjgsIDB4ZDAxMjc4NDUsIDB4OTViNzk0ZmQsIDB4NjQ3ZDA4NjIsIDB4ZTdjY2Y1ZjAsXG5cdDB4NTQ0OWEzNmYsIDB4ODc3ZDQ4ZmEsIDB4YzM5ZGZkMjcsIDB4ZjMzZThkMWUsIDB4MGE0NzYzNDEsIDB4OTkyZWZmNzQsXG5cdDB4M2E2ZjZlYWIsIDB4ZjRmOGZkMzcsIDB4YTgxMmRjNjAsIDB4YTFlYmRkZjgsIDB4OTkxYmUxNGMsIDB4ZGI2ZTZiMGQsXG5cdDB4YzY3YjU1MTAsIDB4NmQ2NzJjMzcsIDB4Mjc2NWQ0M2IsIDB4ZGNkMGU4MDQsIDB4ZjEyOTBkYzcsIDB4Y2MwMGZmYTMsXG5cdDB4YjUzOTBmOTIsIDB4NjkwZmVkMGIsIDB4NjY3YjlmZmIsIDB4Y2VkYjdkOWMsIDB4YTA5MWNmMGIsIDB4ZDkxNTVlYTMsXG5cdDB4YmIxMzJmODgsIDB4NTE1YmFkMjQsIDB4N2I5NDc5YmYsIDB4NzYzYmQ2ZWIsIDB4MzczOTJlYjMsIDB4Y2MxMTU5NzksXG5cdDB4ODAyNmUyOTcsIDB4ZjQyZTMxMmQsIDB4Njg0MmFkYTcsIDB4YzY2YTJiM2IsIDB4MTI3NTRjY2MsIDB4NzgyZWYxMWMsXG5cdDB4NmExMjQyMzcsIDB4Yjc5MjUxZTcsIDB4MDZhMWJiZTYsIDB4NGJmYjYzNTAsIDB4MWE2YjEwMTgsIDB4MTFjYWVkZmEsXG5cdDB4M2QyNWJkZDgsIDB4ZTJlMWMzYzksIDB4NDQ0MjE2NTksIDB4MGExMjEzODYsIDB4ZDkwY2VjNmUsIDB4ZDVhYmVhMmEsXG5cdDB4NjRhZjY3NGUsIDB4ZGE4NmE4NWYsIDB4YmViZmU5ODgsIDB4NjRlNGMzZmUsIDB4OWRiYzgwNTcsIDB4ZjBmN2MwODYsXG5cdDB4NjA3ODdiZjgsIDB4NjAwMzYwNGQsIDB4ZDFmZDgzNDYsIDB4ZjYzODFmYjAsIDB4Nzc0NWFlMDQsIDB4ZDczNmZjY2MsXG5cdDB4ODM0MjZiMzMsIDB4ZjAxZWFiNzEsIDB4YjA4MDQxODcsIDB4M2MwMDVlNWYsIDB4NzdhMDU3YmUsIDB4YmRlOGFlMjQsXG5cdDB4NTU0NjQyOTksIDB4YmY1ODJlNjEsIDB4NGU1OGY0OGYsIDB4ZjJkZGZkYTIsIDB4ZjQ3NGVmMzgsIDB4ODc4OWJkYzIsXG5cdDB4NTM2NmY5YzMsIDB4YzhiMzhlNzQsIDB4YjQ3NWYyNTUsIDB4NDZmY2Q5YjksIDB4N2FlYjI2NjEsIDB4OGIxZGRmODQsXG5cdDB4ODQ2YTBlNzksIDB4OTE1Zjk1ZTIsIDB4NDY2ZTU5OGUsIDB4MjBiNDU3NzAsIDB4OGNkNTU1OTEsIDB4YzkwMmRlNGMsXG5cdDB4YjkwYmFjZTEsIDB4YmI4MjA1ZDAsIDB4MTFhODYyNDgsIDB4NzU3NGE5OWUsIDB4Yjc3ZjE5YjYsIDB4ZTBhOWRjMDksXG5cdDB4NjYyZDA5YTEsIDB4YzQzMjQ2MzMsIDB4ZTg1YTFmMDIsIDB4MDlmMGJlOGMsIDB4NGE5OWEwMjUsIDB4MWQ2ZWZlMTAsXG5cdDB4MWFiOTNkMWQsIDB4MGJhNWE0ZGYsIDB4YTE4NmYyMGYsIDB4Mjg2OGYxNjksIDB4ZGNiN2RhODMsIDB4NTczOTA2ZmUsXG5cdDB4YTFlMmNlOWIsIDB4NGZjZDdmNTIsIDB4NTAxMTVlMDEsIDB4YTcwNjgzZmEsIDB4YTAwMmI1YzQsIDB4MGRlNmQwMjcsXG5cdDB4OWFmODhjMjcsIDB4NzczZjg2NDEsIDB4YzM2MDRjMDYsIDB4NjFhODA2YjUsIDB4ZjAxNzdhMjgsIDB4YzBmNTg2ZTAsXG5cdDB4MDA2MDU4YWEsIDB4MzBkYzdkNjIsIDB4MTFlNjllZDcsIDB4MjMzOGVhNjMsIDB4NTNjMmRkOTQsIDB4YzJjMjE2MzQsXG5cdDB4YmJjYmVlNTYsIDB4OTBiY2I2ZGUsIDB4ZWJmYzdkYTEsIDB4Y2U1OTFkNzYsIDB4NmYwNWU0MDksIDB4NGI3YzAxODgsXG5cdDB4Mzk3MjBhM2QsIDB4N2M5MjdjMjQsIDB4ODZlMzcyNWYsIDB4NzI0ZDlkYjksIDB4MWFjMTViYjQsIDB4ZDM5ZWI4ZmMsXG5cdDB4ZWQ1NDU1NzgsIDB4MDhmY2E1YjUsIDB4ZDgzZDdjZDMsIDB4NGRhZDBmYzQsIDB4MWU1MGVmNWUsIDB4YjE2MWU2ZjgsXG5cdDB4YTI4NTE0ZDksIDB4NmM1MTEzM2MsIDB4NmZkNWM3ZTcsIDB4NTZlMTRlYzQsIDB4MzYyYWJmY2UsIDB4ZGRjNmM4MzcsXG5cdDB4ZDc5YTMyMzQsIDB4OTI2MzgyMTIsIDB4NjcwZWZhOGUsIDB4NDA2MDAwZTBcbiAgICBdLCBbXG5cdDB4M2EzOWNlMzcsIDB4ZDNmYWY1Y2YsIDB4YWJjMjc3MzcsIDB4NWFjNTJkMWIsIDB4NWNiMDY3OWUsIDB4NGZhMzM3NDIsXG5cdDB4ZDM4MjI3NDAsIDB4OTliYzliYmUsIDB4ZDUxMThlOWQsIDB4YmYwZjczMTUsIDB4ZDYyZDFjN2UsIDB4YzcwMGM0N2IsXG5cdDB4Yjc4YzFiNmIsIDB4MjFhMTkwNDUsIDB4YjI2ZWIxYmUsIDB4NmEzNjZlYjQsIDB4NTc0OGFiMmYsIDB4YmM5NDZlNzksXG5cdDB4YzZhMzc2ZDIsIDB4NjU0OWMyYzgsIDB4NTMwZmY4ZWUsIDB4NDY4ZGRlN2QsIDB4ZDU3MzBhMWQsIDB4NGNkMDRkYzYsXG5cdDB4MjkzOWJiZGIsIDB4YTliYTQ2NTAsIDB4YWM5NTI2ZTgsIDB4YmU1ZWUzMDQsIDB4YTFmYWQ1ZjAsIDB4NmEyZDUxOWEsXG5cdDB4NjNlZjhjZTIsIDB4OWE4NmVlMjIsIDB4YzA4OWMyYjgsIDB4NDMyNDJlZjYsIDB4YTUxZTAzYWEsIDB4OWNmMmQwYTQsXG5cdDB4ODNjMDYxYmEsIDB4OWJlOTZhNGQsIDB4OGZlNTE1NTAsIDB4YmE2NDViZDYsIDB4MjgyNmEyZjksIDB4YTczYTNhZTEsXG5cdDB4NGJhOTk1ODYsIDB4ZWY1NTYyZTksIDB4YzcyZmVmZDMsIDB4Zjc1MmY3ZGEsIDB4M2YwNDZmNjksIDB4NzdmYTBhNTksXG5cdDB4ODBlNGE5MTUsIDB4ODdiMDg2MDEsIDB4OWIwOWU2YWQsIDB4M2IzZWU1OTMsIDB4ZTk5MGZkNWEsIDB4OWUzNGQ3OTcsXG5cdDB4MmNmMGI3ZDksIDB4MDIyYjhiNTEsIDB4OTZkNWFjM2EsIDB4MDE3ZGE2N2QsIDB4ZDFjZjNlZDYsIDB4N2M3ZDJkMjgsXG5cdDB4MWY5ZjI1Y2YsIDB4YWRmMmI4OWIsIDB4NWFkNmI0NzIsIDB4NWE4OGY1NGMsIDB4ZTAyOWFjNzEsIDB4ZTAxOWE1ZTYsXG5cdDB4NDdiMGFjZmQsIDB4ZWQ5M2ZhOWIsIDB4ZThkM2M0OGQsIDB4MjgzYjU3Y2MsIDB4ZjhkNTY2MjksIDB4NzkxMzJlMjgsXG5cdDB4Nzg1ZjAxOTEsIDB4ZWQ3NTYwNTUsIDB4Zjc5NjBlNDQsIDB4ZTNkMzVlOGMsIDB4MTUwNTZkZDQsIDB4ODhmNDZkYmEsXG5cdDB4MDNhMTYxMjUsIDB4MDU2NGYwYmQsIDB4YzNlYjllMTUsIDB4M2M5MDU3YTIsIDB4OTcyNzFhZWMsIDB4YTkzYTA3MmEsXG5cdDB4MWIzZjZkOWIsIDB4MWU2MzIxZjUsIDB4ZjU5YzY2ZmIsIDB4MjZkY2YzMTksIDB4NzUzM2Q5MjgsIDB4YjE1NWZkZjUsXG5cdDB4MDM1NjM0ODIsIDB4OGFiYTNjYmIsIDB4Mjg1MTc3MTEsIDB4YzIwYWQ5ZjgsIDB4YWJjYzUxNjcsIDB4Y2NhZDkyNWYsXG5cdDB4NGRlODE3NTEsIDB4MzgzMGRjOGUsIDB4Mzc5ZDU4NjIsIDB4OTMyMGY5OTEsIDB4ZWE3YTkwYzIsIDB4ZmIzZTdiY2UsXG5cdDB4NTEyMWNlNjQsIDB4Nzc0ZmJlMzIsIDB4YThiNmUzN2UsIDB4YzMyOTNkNDYsIDB4NDhkZTUzNjksIDB4NjQxM2U2ODAsXG5cdDB4YTJhZTA4MTAsIDB4ZGQ2ZGIyMjQsIDB4Njk4NTJkZmQsIDB4MDkwNzIxNjYsIDB4YjM5YTQ2MGEsIDB4NjQ0NWMwZGQsXG5cdDB4NTg2Y2RlY2YsIDB4MWMyMGM4YWUsIDB4NWJiZWY3ZGQsIDB4MWI1ODhkNDAsIDB4Y2NkMjAxN2YsIDB4NmJiNGUzYmIsXG5cdDB4ZGRhMjZhN2UsIDB4M2E1OWZmNDUsIDB4M2UzNTBhNDQsIDB4YmNiNGNkZDUsIDB4NzJlYWNlYTgsIDB4ZmE2NDg0YmIsXG5cdDB4OGQ2NjEyYWUsIDB4YmYzYzZmNDcsIDB4ZDI5YmU0NjMsIDB4NTQyZjVkOWUsIDB4YWVjMjc3MWIsIDB4ZjY0ZTYzNzAsXG5cdDB4NzQwZTBkOGQsIDB4ZTc1YjEzNTcsIDB4Zjg3MjE2NzEsIDB4YWY1MzdkNWQsIDB4NDA0MGNiMDgsIDB4NGViNGUyY2MsXG5cdDB4MzRkMjQ2NmEsIDB4MDExNWFmODQsIDB4ZTFiMDA0MjgsIDB4OTU5ODNhMWQsIDB4MDZiODlmYjQsIDB4Y2U2ZWEwNDgsXG5cdDB4NmYzZjNiODIsIDB4MzUyMGFiODIsIDB4MDExYTFkNGIsIDB4Mjc3MjI3ZjgsIDB4NjExNTYwYjEsIDB4ZTc5MzNmZGMsXG5cdDB4YmIzYTc5MmIsIDB4MzQ0NTI1YmQsIDB4YTA4ODM5ZTEsIDB4NTFjZTc5NGIsIDB4MmYzMmM5YjcsIDB4YTAxZmJhYzksXG5cdDB4ZTAxY2M4N2UsIDB4YmNjN2QxZjYsIDB4Y2YwMTExYzMsIDB4YTFlOGFhYzcsIDB4MWE5MDg3NDksIDB4ZDQ0ZmJkOWEsXG5cdDB4ZDBkYWRlY2IsIDB4ZDUwYWRhMzgsIDB4MDMzOWMzMmEsIDB4YzY5MTM2NjcsIDB4OGRmOTMxN2MsIDB4ZTBiMTJiNGYsXG5cdDB4Zjc5ZTU5YjcsIDB4NDNmNWJiM2EsIDB4ZjJkNTE5ZmYsIDB4MjdkOTQ1OWMsIDB4YmY5NzIyMmMsIDB4MTVlNmZjMmEsXG5cdDB4MGY5MWZjNzEsIDB4OWI5NDE1MjUsIDB4ZmFlNTkzNjEsIDB4Y2ViNjljZWIsIDB4YzJhODY0NTksIDB4MTJiYWE4ZDEsXG5cdDB4YjZjMTA3NWUsIDB4ZTMwNTZhMGMsIDB4MTBkMjUwNjUsIDB4Y2IwM2E0NDIsIDB4ZTBlYzZlMGUsIDB4MTY5OGRiM2IsXG5cdDB4NGM5OGEwYmUsIDB4MzI3OGU5NjQsIDB4OWYxZjk1MzIsIDB4ZTBkMzkyZGYsIDB4ZDNhMDM0MmIsIDB4ODk3MWYyMWUsXG5cdDB4MWIwYTc0NDEsIDB4NGJhMzM0OGMsIDB4YzViZTcxMjAsIDB4YzM3NjMyZDgsIDB4ZGYzNTlmOGQsIDB4OWI5OTJmMmUsXG5cdDB4ZTYwYjZmNDcsIDB4MGZlM2YxMWQsIDB4ZTU0Y2RhNTQsIDB4MWVkYWQ4OTEsIDB4Y2U2Mjc5Y2YsIDB4Y2QzZTdlNmYsXG5cdDB4MTYxOGIxNjYsIDB4ZmQyYzFkMDUsIDB4ODQ4ZmQyYzUsIDB4ZjZmYjIyOTksIDB4ZjUyM2YzNTcsIDB4YTYzMjc2MjMsXG5cdDB4OTNhODM1MzEsIDB4NTZjY2NkMDIsIDB4YWNmMDgxNjIsIDB4NWE3NWViYjUsIDB4NmUxNjM2OTcsIDB4ODhkMjczY2MsXG5cdDB4ZGU5NjYyOTIsIDB4ODFiOTQ5ZDAsIDB4NGM1MDkwMWIsIDB4NzFjNjU2MTQsIDB4ZTZjNmM3YmQsIDB4MzI3YTE0MGEsXG5cdDB4NDVlMWQwMDYsIDB4YzNmMjdiOWEsIDB4YzlhYTUzZmQsIDB4NjJhODBmMDAsIDB4YmIyNWJmZTIsIDB4MzViZGQyZjYsXG5cdDB4NzExMjY5MDUsIDB4YjIwNDAyMjIsIDB4YjZjYmNmN2MsIDB4Y2Q3NjljMmIsIDB4NTMxMTNlYzAsIDB4MTY0MGUzZDMsXG5cdDB4MzhhYmJkNjAsIDB4MjU0N2FkZjAsIDB4YmEzODIwOWMsIDB4Zjc0NmNlNzYsIDB4NzdhZmExYzUsIDB4MjA3NTYwNjAsXG5cdDB4ODVjYmZlNGUsIDB4OGFlODhkZDgsIDB4N2FhYWY5YjAsIDB4NGNmOWFhN2UsIDB4MTk0OGMyNWMsIDB4MDJmYjhhOGMsXG5cdDB4MDFjMzZhZTQsIDB4ZDZlYmUxZjksIDB4OTBkNGY4NjksIDB4YTY1Y2RlYTAsIDB4M2YwOTI1MmQsIDB4YzIwOGU2OWYsXG5cdDB4Yjc0ZTYxMzIsIDB4Y2U3N2UyNWIsIDB4NTc4ZmRmZTMsIDB4M2FjMzcyZTZcbiAgICBdXG5dO1xuXG4vLypcbi8vKiBUaGlzIGlzIHRoZSBkZWZhdWx0IFBBUlJBWVxuLy8qXG5CbG93ZmlzaC5wcm90b3R5cGUuUEFSUkFZID0gW1xuICAgIDB4MjQzZjZhODgsIDB4ODVhMzA4ZDMsIDB4MTMxOThhMmUsIDB4MDM3MDczNDQsIDB4YTQwOTM4MjIsIDB4Mjk5ZjMxZDAsXG4gICAgMHgwODJlZmE5OCwgMHhlYzRlNmM4OSwgMHg0NTI4MjFlNiwgMHgzOGQwMTM3NywgMHhiZTU0NjZjZiwgMHgzNGU5MGM2YyxcbiAgICAweGMwYWMyOWI3LCAweGM5N2M1MGRkLCAweDNmODRkNWI1LCAweGI1NDcwOTE3LCAweDkyMTZkNWQ5LCAweDg5NzlmYjFiXG5dO1xuXG4vLypcbi8vKiBUaGlzIGlzIHRoZSBudW1iZXIgb2Ygcm91bmRzIHRoZSBjaXBoZXIgd2lsbCBnb1xuLy8qXG5CbG93ZmlzaC5wcm90b3R5cGUuTk4gPSAxNjtcblxuLy8qXG4vLyogVGhpcyBmdW5jdGlvbiBpcyBuZWVkZWQgdG8gZ2V0IHJpZCBvZiBwcm9ibGVtc1xuLy8qIHdpdGggdGhlIGhpZ2gtYml0IGdldHRpbmcgc2V0LiAgSWYgd2UgZG9uJ3QgZG9cbi8vKiB0aGlzLCB0aGVuIHNvbWV0aW1lcyAoIGFhICYgMHgwMEZGRkZGRkZGICkgaXMgbm90XG4vLyogZXF1YWwgdG8gKCBiYiAmIDB4MDBGRkZGRkZGRiApIGV2ZW4gd2hlbiB0aGV5XG4vLyogYWdyZWUgYml0LWZvci1iaXQgZm9yIHRoZSBmaXJzdCAzMiBiaXRzLlxuLy8qXG5CbG93ZmlzaC5wcm90b3R5cGUuX2NsZWFuID0gZnVuY3Rpb24oIHh4ICkge1xuICAgIGlmICggeHggPCAwICkge1xuXHR2YXIgeXkgPSB4eCAmIDB4N0ZGRkZGRkY7XG5cdHh4ID0geXkgKyAweDgwMDAwMDAwO1xuICAgIH1cbiAgICByZXR1cm4geHg7XG59O1xuXG4vLypcbi8vKiBUaGlzIGlzIHRoZSBtaXhpbmcgZnVuY3Rpb24gdGhhdCB1c2VzIHRoZSBzYm94ZXNcbi8vKlxuQmxvd2Zpc2gucHJvdG90eXBlLl9GID0gZnVuY3Rpb24gKCB4eCApIHtcbiAgICB2YXIgYWE7XG4gICAgdmFyIGJiO1xuICAgIHZhciBjYztcbiAgICB2YXIgZGQ7XG4gICAgdmFyIHl5O1xuXG4gICAgZGQgPSB4eCAmIDB4MDBGRjtcbiAgICB4eCA+Pj49IDg7XG4gICAgY2MgPSB4eCAmIDB4MDBGRjtcbiAgICB4eCA+Pj49IDg7XG4gICAgYmIgPSB4eCAmIDB4MDBGRjtcbiAgICB4eCA+Pj49IDg7XG4gICAgYWEgPSB4eCAmIDB4MDBGRjtcblxuICAgIHl5ID0gdGhpcy5zYm94ZXNbIDAgXVsgYWEgXSArIHRoaXMuc2JveGVzWyAxIF1bIGJiIF07XG4gICAgeXkgPSB5eSBeIHRoaXMuc2JveGVzWyAyIF1bIGNjIF07XG4gICAgeXkgPSB5eSArIHRoaXMuc2JveGVzWyAzIF1bIGRkIF07XG5cbiAgICByZXR1cm4geXk7XG59O1xuXG4vLypcbi8vKiBUaGlzIG1ldGhvZCB0YWtlcyBhbiBhcnJheSB3aXRoIHR3byB2YWx1ZXMsIGxlZnQgYW5kIHJpZ2h0XG4vLyogYW5kIGRvZXMgTk4gcm91bmRzIG9mIEJsb3dmaXNoIG9uIHRoZW0uXG4vLypcbkJsb3dmaXNoLnByb3RvdHlwZS5fZW5jcnlwdF9ibG9jayA9IGZ1bmN0aW9uICggdmFscyApIHtcbiAgICB2YXIgZGF0YUwgPSB2YWxzWyAwIF07XG4gICAgdmFyIGRhdGFSID0gdmFsc1sgMSBdO1xuXG4gICAgdmFyIGlpO1xuXG4gICAgZm9yICggaWk9MDsgaWkgPCB0aGlzLk5OOyArK2lpICkge1xuXHRkYXRhTCA9IGRhdGFMIF4gdGhpcy5wYXJyYXlbIGlpIF07XG5cdGRhdGFSID0gdGhpcy5fRiggZGF0YUwgKSBeIGRhdGFSO1xuXG5cdHZhciB0bXAgPSBkYXRhTDtcblx0ZGF0YUwgPSBkYXRhUjtcblx0ZGF0YVIgPSB0bXA7XG4gICAgfVxuXG4gICAgZGF0YUwgPSBkYXRhTCBeIHRoaXMucGFycmF5WyB0aGlzLk5OICsgMCBdO1xuICAgIGRhdGFSID0gZGF0YVIgXiB0aGlzLnBhcnJheVsgdGhpcy5OTiArIDEgXTtcblxuICAgIHZhbHNbIDAgXSA9IHRoaXMuX2NsZWFuKCBkYXRhUiApO1xuICAgIHZhbHNbIDEgXSA9IHRoaXMuX2NsZWFuKCBkYXRhTCApO1xufTtcblxuLy8qXG4vLyogVGhpcyBtZXRob2QgdGFrZXMgYSB2ZWN0b3Igb2YgbnVtYmVycyBhbmQgdHVybnMgdGhlbVxuLy8qIGludG8gbG9uZyB3b3JkcyBzbyB0aGF0IHRoZXkgY2FuIGJlIHByb2Nlc3NlZCBieSB0aGVcbi8vKiByZWFsIGFsZ29yaXRobS5cbi8vKlxuLy8qIE1heWJlIEkgc2hvdWxkIG1ha2UgdGhlIHJlYWwgYWxnb3JpdGhtIGFib3ZlIHRha2UgYSB2ZWN0b3Jcbi8vKiBpbnN0ZWFkLiAgVGhhdCB3aWxsIGludm9sdmUgbW9yZSBsb29waW5nLCBidXQgaXQgd29uJ3QgcmVxdWlyZVxuLy8qIHRoZSBGKCkgbWV0aG9kIHRvIGRlY29uc3RydWN0IHRoZSB2ZWN0b3IuXG4vLypcbkJsb3dmaXNoLnByb3RvdHlwZS5lbmNyeXB0X2Jsb2NrID0gZnVuY3Rpb24gKCB2ZWN0b3IgKSB7XG4gICAgdmFyIGlpO1xuICAgIHZhciB2YWxzID0gWyAwLCAwIF07XG4gICAgdmFyIG9mZiAgPSB0aGlzLkJMT0NLU0laRS8yO1xuICAgIGZvciAoIGlpID0gMDsgaWkgPCB0aGlzLkJMT0NLU0laRS8yOyArK2lpICkge1xuXHR2YWxzWzBdID0gKCB2YWxzWzBdIDw8IDggKSB8ICggdmVjdG9yWyBpaSArIDAgICBdICYgMHgwMEZGICk7XG5cdHZhbHNbMV0gPSAoIHZhbHNbMV0gPDwgOCApIHwgKCB2ZWN0b3JbIGlpICsgb2ZmIF0gJiAweDAwRkYgKTtcbiAgICB9XG5cbiAgICB0aGlzLl9lbmNyeXB0X2Jsb2NrKCB2YWxzICk7XG5cbiAgICB2YXIgcmV0ID0gWyBdO1xuICAgIGZvciAoIGlpID0gMDsgaWkgPCB0aGlzLkJMT0NLU0laRS8yOyArK2lpICkge1xuXHRyZXRbIGlpICsgMCAgIF0gPSAoIHZhbHNbIDAgXSA+Pj4gKDI0IC0gOCooaWkpKSAmIDB4MDBGRiApO1xuXHRyZXRbIGlpICsgb2ZmIF0gPSAoIHZhbHNbIDEgXSA+Pj4gKDI0IC0gOCooaWkpKSAmIDB4MDBGRiApO1xuXHQvLyB2YWxzWyAwIF0gPSAoIHZhbHNbIDAgXSA+Pj4gOCApO1xuXHQvLyB2YWxzWyAxIF0gPSAoIHZhbHNbIDEgXSA+Pj4gOCApO1xuICAgIH1cblxuICAgIHJldHVybiByZXQ7XG59O1xuXG4vLypcbi8vKiBUaGlzIG1ldGhvZCB0YWtlcyBhbiBhcnJheSB3aXRoIHR3byB2YWx1ZXMsIGxlZnQgYW5kIHJpZ2h0XG4vLyogYW5kIHVuZG9lcyBOTiByb3VuZHMgb2YgQmxvd2Zpc2ggb24gdGhlbS5cbi8vKlxuQmxvd2Zpc2gucHJvdG90eXBlLl9kZWNyeXB0X2Jsb2NrID0gZnVuY3Rpb24gKCB2YWxzICkge1xuICAgIHZhciBkYXRhTCA9IHZhbHNbIDAgXTtcbiAgICB2YXIgZGF0YVIgPSB2YWxzWyAxIF07XG5cbiAgICB2YXIgaWk7XG5cbiAgICBmb3IgKCBpaT10aGlzLk5OKzE7IGlpID4gMTsgLS1paSApIHtcblx0ZGF0YUwgPSBkYXRhTCBeIHRoaXMucGFycmF5WyBpaSBdO1xuXHRkYXRhUiA9IHRoaXMuX0YoIGRhdGFMICkgXiBkYXRhUjtcblxuXHR2YXIgdG1wID0gZGF0YUw7XG5cdGRhdGFMID0gZGF0YVI7XG5cdGRhdGFSID0gdG1wO1xuICAgIH1cblxuICAgIGRhdGFMID0gZGF0YUwgXiB0aGlzLnBhcnJheVsgMSBdO1xuICAgIGRhdGFSID0gZGF0YVIgXiB0aGlzLnBhcnJheVsgMCBdO1xuXG4gICAgdmFsc1sgMCBdID0gdGhpcy5fY2xlYW4oIGRhdGFSICk7XG4gICAgdmFsc1sgMSBdID0gdGhpcy5fY2xlYW4oIGRhdGFMICk7XG59O1xuXG4vLypcbi8vKiBUaGlzIG1ldGhvZCB0YWtlcyBhIGtleSBhcnJheSBhbmQgaW5pdGlhbGl6ZXMgdGhlXG4vLyogc2JveGVzIGFuZCBwYXJyYXkgZm9yIHRoaXMgZW5jcnlwdGlvbi5cbi8vKlxuQmxvd2Zpc2gucHJvdG90eXBlLmluaXQgPSBmdW5jdGlvbiAoIGtleSApIHtcbiAgICB2YXIgaWk7XG4gICAgdmFyIGpqID0gMDtcblxuICAgIHRoaXMucGFycmF5ID0gW107XG4gICAgZm9yICggaWk9MDsgaWkgPCB0aGlzLk5OICsgMjsgKytpaSApIHtcblx0dmFyIGRhdGEgPSAweDAwMDAwMDAwO1xuXHR2YXIga2s7XG5cdGZvciAoIGtrPTA7IGtrIDwgNDsgKytrayApIHtcblx0ICAgIGRhdGEgPSAoIGRhdGEgPDwgOCApIHwgKCBrZXlbIGpqIF0gJiAweDAwRkYgKTtcblx0ICAgIGlmICggKytqaiA+PSBrZXkubGVuZ3RoICkge1xuXHRcdGpqID0gMDtcblx0ICAgIH1cblx0fVxuXHR0aGlzLnBhcnJheVsgaWkgXSA9IHRoaXMuUEFSUkFZWyBpaSBdIF4gZGF0YTtcbiAgICB9XG5cbiAgICB0aGlzLnNib3hlcyA9IFtdO1xuICAgIGZvciAoIGlpPTA7IGlpIDwgNDsgKytpaSApIHtcblx0dGhpcy5zYm94ZXNbIGlpIF0gPSBbXTtcblx0Zm9yICggamo9MDsgamogPCAyNTY7ICsramogKSB7XG5cdCAgICB0aGlzLnNib3hlc1sgaWkgXVsgamogXSA9IHRoaXMuU0JPWEVTWyBpaSBdWyBqaiBdO1xuXHR9XG4gICAgfVxuXG4gICAgdmFyIHZhbHMgPSBbIDB4MDAwMDAwMDAsIDB4MDAwMDAwMDAgXTtcblxuICAgIGZvciAoIGlpPTA7IGlpIDwgdGhpcy5OTisyOyBpaSArPSAyICkge1xuXHR0aGlzLl9lbmNyeXB0X2Jsb2NrKCB2YWxzICk7XG5cdHRoaXMucGFycmF5WyBpaSArIDAgXSA9IHZhbHNbIDAgXTtcblx0dGhpcy5wYXJyYXlbIGlpICsgMSBdID0gdmFsc1sgMSBdO1xuICAgIH1cblxuICAgIGZvciAoIGlpPTA7IGlpIDwgNDsgKytpaSApIHtcblx0Zm9yICggamo9MDsgamogPCAyNTY7IGpqICs9IDIgKSB7XG5cdCAgICB0aGlzLl9lbmNyeXB0X2Jsb2NrKCB2YWxzICk7XG5cdCAgICB0aGlzLnNib3hlc1sgaWkgXVsgamogKyAwIF0gPSB2YWxzWyAwIF07XG5cdCAgICB0aGlzLnNib3hlc1sgaWkgXVsgamogKyAxIF0gPSB2YWxzWyAxIF07XG5cdH1cbiAgICB9XG59O1xuXG52YXIgdXRpbCA9IHJlcXVpcmUoJy4uLy4uL3V0aWwnKTtcblxuLy8gYWRkZWQgYnkgUmVjdXJpdHkgTGFic1xuZnVuY3Rpb24gQkZlbmNyeXB0KGJsb2NrLGtleSkge1xuXHR2YXIgYmYgPSBuZXcgQmxvd2Zpc2goKTtcblx0YmYuaW5pdCh1dGlsLnN0cjJiaW4oa2V5KSk7XG5cdHJldHVybiBiZi5lbmNyeXB0X2Jsb2NrKGJsb2NrKTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBCRmVuY3J5cHQ7XG4iLCIvLyBHUEc0QnJvd3NlcnMgLSBBbiBPcGVuUEdQIGltcGxlbWVudGF0aW9uIGluIGphdmFzY3JpcHRcbi8vIENvcHlyaWdodCAoQykgMjAxMSBSZWN1cml0eSBMYWJzIEdtYkhcbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vclxuLy8gbW9kaWZ5IGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyXG4vLyB2ZXJzaW9uIDIuMSBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4vLyBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuLy8gTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZSBHTlVcbi8vIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG4vLyBcbi8vIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYWxvbmcgd2l0aCB0aGlzIGxpYnJhcnk7IGlmIG5vdCwgd3JpdGUgdG8gdGhlIEZyZWUgU29mdHdhcmVcbi8vIEZvdW5kYXRpb24sIEluYy4sIDUxIEZyYW5rbGluIFN0cmVldCwgRmlmdGggRmxvb3IsIEJvc3RvbiwgTUEgIDAyMTEwLTEzMDEgIFVTQVxuLy9cbi8vIFJTQSBpbXBsZW1lbnRhdGlvblxuXG52YXIgQmlnSW50ZWdlciA9IHJlcXVpcmUoJy4vanNibi5qcycpLFxuXHR1dGlsID0gcmVxdWlyZSgnLi4vLi4vdXRpbCcpLFxuXHRyYW5kb20gPSByZXF1aXJlKCcuLi9yYW5kb20uanMnKTtcblxuZnVuY3Rpb24gU2VjdXJlUmFuZG9tKCl7XG4gICAgZnVuY3Rpb24gbmV4dEJ5dGVzKGJ5dGVBcnJheSl7XG4gICAgICAgIGZvcih2YXIgbiA9IDA7IG4gPCBieXRlQXJyYXkubGVuZ3RoO24rKyl7XG4gICAgICAgICAgICBieXRlQXJyYXlbbl0gPSByYW5kb20uZ2V0U2VjdXJlUmFuZG9tT2N0ZXQoKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICB0aGlzLm5leHRCeXRlcyA9IG5leHRCeXRlcztcbn1cblxuZnVuY3Rpb24gUlNBKCkge1xuXHQvKipcblx0ICogVGhpcyBmdW5jdGlvbiB1c2VzIGpzYm4gQmlnIE51bSBsaWJyYXJ5IHRvIGRlY3J5cHQgUlNBXG5cdCAqIEBwYXJhbSBtXG5cdCAqICAgICAgICAgICAgbWVzc2FnZVxuXHQgKiBAcGFyYW0gZFxuXHQgKiAgICAgICAgICAgIFJTQSBkIGFzIEJpZ0ludGVnZXJcblx0ICogQHBhcmFtIHBcblx0ICogICAgICAgICAgICBSU0EgcCBhcyBCaWdJbnRlZ2VyXG5cdCAqIEBwYXJhbSBxXG5cdCAqICAgICAgICAgICAgUlNBIHEgYXMgQmlnSW50ZWdlclxuXHQgKiBAcGFyYW0gdVxuXHQgKiAgICAgICAgICAgIFJTQSB1IGFzIEJpZ0ludGVnZXJcblx0ICogQHJldHVybiB7QmlnSW50ZWdlcn0gVGhlIGRlY3J5cHRlZCB2YWx1ZSBvZiB0aGUgbWVzc2FnZVxuXHQgKi9cblx0ZnVuY3Rpb24gZGVjcnlwdChtLCBkLCBwLCBxLCB1KSB7XG5cdFx0dmFyIHhwID0gbS5tb2QocCkubW9kUG93KGQubW9kKHAuc3VidHJhY3QoQmlnSW50ZWdlci5PTkUpKSwgcCk7XG5cdFx0dmFyIHhxID0gbS5tb2QocSkubW9kUG93KGQubW9kKHEuc3VidHJhY3QoQmlnSW50ZWdlci5PTkUpKSwgcSk7XG5cdFx0dXRpbC5wcmludF9kZWJ1ZyhcInJzYS5qcyBkZWNyeXB0XFxueHBuOlwiK3V0aWwuaGV4c3RyZHVtcCh4cC50b01QSSgpKStcIlxcbnhxbjpcIit1dGlsLmhleHN0cmR1bXAoeHEudG9NUEkoKSkpO1xuXG5cdFx0dmFyIHQgPSB4cS5zdWJ0cmFjdCh4cCk7XG5cdFx0aWYgKHRbMF0gPT0gMCkge1xuXHRcdFx0dCA9IHhwLnN1YnRyYWN0KHhxKTtcblx0XHRcdHQgPSB0Lm11bHRpcGx5KHUpLm1vZChxKTtcblx0XHRcdHQgPSBxLnN1YnRyYWN0KHQpO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHR0ID0gdC5tdWx0aXBseSh1KS5tb2QocSk7XG5cdFx0fVxuXHRcdHJldHVybiB0Lm11bHRpcGx5KHApLmFkZCh4cCk7XG5cdH1cblx0XG5cdC8qKlxuXHQgKiBlbmNyeXB0IG1lc3NhZ2Vcblx0ICogQHBhcmFtIG0gbWVzc2FnZSBhcyBCaWdJbnRlZ2VyXG5cdCAqIEBwYXJhbSBlIHB1YmxpYyBNUEkgcGFydCBhcyBCaWdJbnRlZ2VyXG5cdCAqIEBwYXJhbSBuIHB1YmxpYyBNUEkgcGFydCBhcyBCaWdJbnRlZ2VyXG5cdCAqIEByZXR1cm4gQmlnSW50ZWdlclxuXHQgKi9cblx0ZnVuY3Rpb24gZW5jcnlwdChtLGUsbikge1xuXHRcdHJldHVybiBtLm1vZFBvd0ludChlLCBuKTtcblx0fVxuXHRcblx0LyogU2lnbiBhbmQgVmVyaWZ5ICovXG5cdGZ1bmN0aW9uIHNpZ24obSxkLG4pIHtcblx0XHRyZXR1cm4gbS5tb2RQb3coZCwgbik7XG5cdH1cblx0XHRcblx0ZnVuY3Rpb24gdmVyaWZ5KHgsZSxuKSB7XG5cdFx0cmV0dXJuIHgubW9kUG93SW50KGUsIG4pO1xuXHR9XG5cdFxuXHQvLyBcImVtcHR5XCIgUlNBIGtleSBjb25zdHJ1Y3RvclxuICAgIGZ1bmN0aW9uIGtleU9iamVjdCgpIHtcbiAgICAgICAgdGhpcy5uID0gbnVsbDtcbiAgICAgICAgdGhpcy5lID0gMDtcbiAgICAgICAgdGhpcy5lZSA9IG51bGw7XG4gICAgICAgIHRoaXMuZCA9IG51bGw7XG4gICAgICAgIHRoaXMucCA9IG51bGw7XG4gICAgICAgIHRoaXMucSA9IG51bGw7XG4gICAgICAgIHRoaXMuZG1wMSA9IG51bGw7XG4gICAgICAgIHRoaXMuZG1xMSA9IG51bGw7XG4gICAgICAgIHRoaXMudSA9IG51bGw7XG4gICAgfVxuXHRcblx0Ly8gR2VuZXJhdGUgYSBuZXcgcmFuZG9tIHByaXZhdGUga2V5IEIgYml0cyBsb25nLCB1c2luZyBwdWJsaWMgZXhwdCBFXG4gICAgZnVuY3Rpb24gZ2VuZXJhdGUoQixFKSB7XG4gICAgICAgIHZhciBrZXkgPSBuZXcga2V5T2JqZWN0KCk7XG4gICAgICAgIHZhciBybmcgPSBuZXcgU2VjdXJlUmFuZG9tKCk7XG4gICAgICAgIHZhciBxcyA9IEI+PjE7XG4gICAgICAgIGtleS5lID0gcGFyc2VJbnQoRSwxNik7XG4gICAgICAgIGtleS5lZSA9IG5ldyBCaWdJbnRlZ2VyKEUsMTYpO1xuICAgICAgICBmb3IoOzspIHtcbiAgICAgICAgICAgIGZvcig7Oykge1xuICAgICAgICAgICAgICAgIGtleS5wID0gbmV3IEJpZ0ludGVnZXIoQi1xcywxLHJuZyk7XG4gICAgICAgICAgICAgICAgaWYoa2V5LnAuc3VidHJhY3QoQmlnSW50ZWdlci5PTkUpLmdjZChrZXkuZWUpLmNvbXBhcmVUbyhCaWdJbnRlZ2VyLk9ORSkgPT0gMCAmJiBrZXkucC5pc1Byb2JhYmxlUHJpbWUoMTApKSBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGZvcig7Oykge1xuICAgICAgICAgICAgICAgIGtleS5xID0gbmV3IEJpZ0ludGVnZXIocXMsMSxybmcpO1xuICAgICAgICAgICAgICAgIGlmKGtleS5xLnN1YnRyYWN0KEJpZ0ludGVnZXIuT05FKS5nY2Qoa2V5LmVlKS5jb21wYXJlVG8oQmlnSW50ZWdlci5PTkUpID09IDAgJiYga2V5LnEuaXNQcm9iYWJsZVByaW1lKDEwKSkgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZihrZXkucC5jb21wYXJlVG8oa2V5LnEpIDw9IDApIHtcbiAgICAgICAgICAgICAgICB2YXIgdCA9IGtleS5wO1xuICAgICAgICAgICAgICAgIGtleS5wID0ga2V5LnE7XG4gICAgICAgICAgICAgICAga2V5LnEgPSB0O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIHAxID0ga2V5LnAuc3VidHJhY3QoQmlnSW50ZWdlci5PTkUpO1xuICAgICAgICAgICAgdmFyIHExID0ga2V5LnEuc3VidHJhY3QoQmlnSW50ZWdlci5PTkUpO1xuICAgICAgICAgICAgdmFyIHBoaSA9IHAxLm11bHRpcGx5KHExKTtcbiAgICAgICAgICAgIGlmKHBoaS5nY2Qoa2V5LmVlKS5jb21wYXJlVG8oQmlnSW50ZWdlci5PTkUpID09IDApIHtcbiAgICAgICAgICAgICAgICBrZXkubiA9IGtleS5wLm11bHRpcGx5KGtleS5xKTtcbiAgICAgICAgICAgICAgICBrZXkuZCA9IGtleS5lZS5tb2RJbnZlcnNlKHBoaSk7XG4gICAgICAgICAgICAgICAga2V5LmRtcDEgPSBrZXkuZC5tb2QocDEpO1xuICAgICAgICAgICAgICAgIGtleS5kbXExID0ga2V5LmQubW9kKHExKTtcbiAgICAgICAgICAgICAgICBrZXkudSA9IGtleS5wLm1vZEludmVyc2Uoa2V5LnEpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBrZXk7XG4gICAgfVxuXHRcdFxuXHR0aGlzLmVuY3J5cHQgPSBlbmNyeXB0O1xuXHR0aGlzLmRlY3J5cHQgPSBkZWNyeXB0O1xuXHR0aGlzLnZlcmlmeSA9IHZlcmlmeTtcblx0dGhpcy5zaWduID0gc2lnbjtcblx0dGhpcy5nZW5lcmF0ZSA9IGdlbmVyYXRlO1xuXHR0aGlzLmtleU9iamVjdCA9IGtleU9iamVjdDtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBSU0E7XG4iLCIvLyBHUEc0QnJvd3NlcnMgLSBBbiBPcGVuUEdQIGltcGxlbWVudGF0aW9uIGluIGphdmFzY3JpcHRcbi8vIENvcHlyaWdodCAoQykgMjAxMSBSZWN1cml0eSBMYWJzIEdtYkhcbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGZyZWUgc29mdHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vclxuLy8gbW9kaWZ5IGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIExlc3NlciBHZW5lcmFsIFB1YmxpY1xuLy8gTGljZW5zZSBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsgZWl0aGVyXG4vLyB2ZXJzaW9uIDIuMSBvZiB0aGUgTGljZW5zZSwgb3IgKGF0IHlvdXIgb3B0aW9uKSBhbnkgbGF0ZXIgdmVyc2lvbi5cbi8vIFxuLy8gVGhpcyBsaWJyYXJ5IGlzIGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIHRoYXQgaXQgd2lsbCBiZSB1c2VmdWwsXG4vLyBidXQgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJyYW50eSBvZlxuLy8gTUVSQ0hBTlRBQklMSVRZIG9yIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLiAgU2VlIHRoZSBHTlVcbi8vIExlc3NlciBHZW5lcmFsIFB1YmxpYyBMaWNlbnNlIGZvciBtb3JlIGRldGFpbHMuXG4vLyBcbi8vIFlvdSBzaG91bGQgaGF2ZSByZWNlaXZlZCBhIGNvcHkgb2YgdGhlIEdOVSBMZXNzZXIgR2VuZXJhbCBQdWJsaWNcbi8vIExpY2Vuc2UgYWxvbmcgd2l0aCB0aGlzIGxpYnJhcnk7IGlmIG5vdCwgd3JpdGUgdG8gdGhlIEZyZWUgU29mdHdhcmVcbi8vIEZvdW5kYXRpb24sIEluYy4sIDUxIEZyYW5rbGluIFN0cmVldCwgRmlmdGggRmxvb3IsIEJvc3RvbiwgTUEgIDAyMTEwLTEzMDEgIFVTQVxuLy9cbi8vIEVsR2FtYWwgaW1wbGVtZW50YXRpb25cblxudmFyIEJpZ0ludGVnZXIgPSByZXF1aXJlKCcuL2pzYm4uanMnKSxcblx0dXRpbCA9IHJlcXVpcmUoJy4uLy4uL3V0aWwnKTtcblxuZnVuY3Rpb24gRWxnYW1hbCgpIHtcblx0XG5cdGZ1bmN0aW9uIGVuY3J5cHQobSxnLHAseSkge1xuXHRcdC8vICBjaG9vc2UgayBpbiB7MiwuLi4scC0yfVxuXHRcdHZhciB0d28gPSBCaWdJbnRlZ2VyLk9ORS5hZGQoQmlnSW50ZWdlci5PTkUpO1xuXHRcdHZhciBwTWludXMyID0gcC5zdWJ0cmFjdCh0d28pO1xuXHRcdHZhciBrID0gb3BlbnBncF9jcnlwdG9fZ2V0UmFuZG9tQmlnSW50ZWdlckluUmFuZ2UodHdvLCBwTWludXMyKTtcblx0XHR2YXIgayA9IGsubW9kKHBNaW51czIpLmFkZChCaWdJbnRlZ2VyLk9ORSk7XG5cdFx0dmFyIGMgPSBuZXcgQXJyYXkoKTtcblx0XHRjWzBdID0gZy5tb2RQb3coaywgcCk7XG5cdFx0Y1sxXSA9IHkubW9kUG93KGssIHApLm11bHRpcGx5KG0pLm1vZChwKS50b01QSSgpO1xuXHRcdGNbMF0gPSBjWzBdLnRvTVBJKCk7XG5cdFx0cmV0dXJuIGM7XG5cdH1cblx0XG5cdGZ1bmN0aW9uIGRlY3J5cHQoYzEsYzIscCx4KSB7XG5cdFx0dXRpbC5wcmludF9kZWJ1ZyhcIkVsZ2FtYWwgRGVjcnlwdDpcXG5jMTpcIit1dGlsLmhleHN0cmR1bXAoYzEudG9NUEkoKSkrXCJcXG5cIitcblx0XHRcdCAgXCJjMjpcIit1dGlsLmhleHN0cmR1bXAoYzIudG9NUEkoKSkrXCJcXG5cIitcblx0XHRcdCAgXCJwOlwiK3V0aWwuaGV4c3RyZHVtcChwLnRvTVBJKCkpK1wiXFxuXCIrXG5cdFx0XHQgIFwieDpcIit1dGlsLmhleHN0cmR1bXAoeC50b01QSSgpKSk7XG5cdFx0cmV0dXJuIChjMS5tb2RQb3coeCwgcCkubW9kSW52ZXJzZShwKSkubXVsdGlwbHkoYzIpLm1vZChwKTtcblx0XHQvL3ZhciBjID0gYzEucG93KHgpLm1vZEludmVyc2UocCk7IC8vIGMwXi1hIG1vZCBwXG5cdCAgICAvL3JldHVybiBjLm11bHRpcGx5KGMyKS5tb2QocCk7XG5cdH1cblx0XG5cdC8vIHNpZ25pbmcgYW5kIHNpZ25hdHVyZSB2ZXJpZmljYXRpb24gdXNpbmcgRWxnYW1hbCBpcyBub3QgcmVxdWlyZWQgYnkgT3BlblBHUC5cblx0dGhpcy5lbmNyeXB0ID0gZW5jcnlwdDtcblx0dGhpcy5kZWNyeXB0ID0gZGVjcnlwdDtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBFbGdhbWFsO1xuIl19
|
||
; |