vosk-browser
Version:
Kaldi in-browser speech recognition based on a WASM build of the Vosk library
542 lines (440 loc) • 5.8 MB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.Vosk = {}));
})(this, (function (exports) { 'use strict';
/******************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
function __awaiter(thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
}
// Unique ID creation requires a high quality random # generator. In the browser we therefore
// require the crypto API and do not support built-in fallback to lower quality random number
// generators (like Math.random()).
let getRandomValues;
const rnds8 = new Uint8Array(16);
function rng() {
// lazy load so that environments that need to polyfill have a chance to do so
if (!getRandomValues) {
// getRandomValues needs to be invoked in a context where "this" is a Crypto implementation.
getRandomValues = typeof crypto !== 'undefined' && crypto.getRandomValues && crypto.getRandomValues.bind(crypto);
if (!getRandomValues) {
throw new Error('crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported');
}
}
return getRandomValues(rnds8);
}
var REGEX = /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i;
function validate(uuid) {
return typeof uuid === 'string' && REGEX.test(uuid);
}
/**
* Convert array of 16 byte values to UUID string format of the form:
* XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
*/
const byteToHex = [];
for (let i = 0; i < 256; ++i) {
byteToHex.push((i + 0x100).toString(16).slice(1));
}
function unsafeStringify(arr, offset = 0) {
// Note: Be careful editing this code! It's been tuned for performance
// and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434
return (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + '-' + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + '-' + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + '-' + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + '-' + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase();
}
function parse(uuid) {
if (!validate(uuid)) {
throw TypeError('Invalid UUID');
}
let v;
const arr = new Uint8Array(16); // Parse ########-....-....-....-............
arr[0] = (v = parseInt(uuid.slice(0, 8), 16)) >>> 24;
arr[1] = v >>> 16 & 0xff;
arr[2] = v >>> 8 & 0xff;
arr[3] = v & 0xff; // Parse ........-####-....-....-............
arr[4] = (v = parseInt(uuid.slice(9, 13), 16)) >>> 8;
arr[5] = v & 0xff; // Parse ........-....-####-....-............
arr[6] = (v = parseInt(uuid.slice(14, 18), 16)) >>> 8;
arr[7] = v & 0xff; // Parse ........-....-....-####-............
arr[8] = (v = parseInt(uuid.slice(19, 23), 16)) >>> 8;
arr[9] = v & 0xff; // Parse ........-....-....-....-############
// (Use "/" to avoid 32-bit truncation when bit-shifting high-order bytes)
arr[10] = (v = parseInt(uuid.slice(24, 36), 16)) / 0x10000000000 & 0xff;
arr[11] = v / 0x100000000 & 0xff;
arr[12] = v >>> 24 & 0xff;
arr[13] = v >>> 16 & 0xff;
arr[14] = v >>> 8 & 0xff;
arr[15] = v & 0xff;
return arr;
}
function stringToBytes(str) {
str = unescape(encodeURIComponent(str)); // UTF8 escape
const bytes = [];
for (let i = 0; i < str.length; ++i) {
bytes.push(str.charCodeAt(i));
}
return bytes;
}
const DNS = '6ba7b810-9dad-11d1-80b4-00c04fd430c8';
const URL$1 = '6ba7b811-9dad-11d1-80b4-00c04fd430c8';
function v35(name, version, hashfunc) {
function generateUUID(value, namespace, buf, offset) {
var _namespace;
if (typeof value === 'string') {
value = stringToBytes(value);
}
if (typeof namespace === 'string') {
namespace = parse(namespace);
}
if (((_namespace = namespace) === null || _namespace === void 0 ? void 0 : _namespace.length) !== 16) {
throw TypeError('Namespace must be array-like (16 iterable integer values, 0-255)');
} // Compute hash of namespace and value, Per 4.3
// Future: Use spread syntax when supported on all platforms, e.g. `bytes =
// hashfunc([...namespace, ... value])`
let bytes = new Uint8Array(16 + value.length);
bytes.set(namespace);
bytes.set(value, namespace.length);
bytes = hashfunc(bytes);
bytes[6] = bytes[6] & 0x0f | version;
bytes[8] = bytes[8] & 0x3f | 0x80;
if (buf) {
offset = offset || 0;
for (let i = 0; i < 16; ++i) {
buf[offset + i] = bytes[i];
}
return buf;
}
return unsafeStringify(bytes);
} // Function#name is not settable on some platforms (#270)
try {
generateUUID.name = name; // eslint-disable-next-line no-empty
} catch (err) {} // For CommonJS default export support
generateUUID.DNS = DNS;
generateUUID.URL = URL$1;
return generateUUID;
}
/*
* Browser-compatible JavaScript MD5
*
* Modification of JavaScript MD5
* https://github.com/blueimp/JavaScript-MD5
*
* Copyright 2011, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
* https://opensource.org/licenses/MIT
*
* Based on
* A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
* Digest Algorithm, as defined in RFC 1321.
* Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
* Distributed under the BSD License
* See http://pajhome.org.uk/crypt/md5 for more info.
*/
function md5(bytes) {
if (typeof bytes === 'string') {
const msg = unescape(encodeURIComponent(bytes)); // UTF8 escape
bytes = new Uint8Array(msg.length);
for (let i = 0; i < msg.length; ++i) {
bytes[i] = msg.charCodeAt(i);
}
}
return md5ToHexEncodedArray(wordsToMd5(bytesToWords(bytes), bytes.length * 8));
}
/*
* Convert an array of little-endian words to an array of bytes
*/
function md5ToHexEncodedArray(input) {
const output = [];
const length32 = input.length * 32;
const hexTab = '0123456789abcdef';
for (let i = 0; i < length32; i += 8) {
const x = input[i >> 5] >>> i % 32 & 0xff;
const hex = parseInt(hexTab.charAt(x >>> 4 & 0x0f) + hexTab.charAt(x & 0x0f), 16);
output.push(hex);
}
return output;
}
/**
* Calculate output length with padding and bit length
*/
function getOutputLength(inputLength8) {
return (inputLength8 + 64 >>> 9 << 4) + 14 + 1;
}
/*
* Calculate the MD5 of an array of little-endian words, and a bit length.
*/
function wordsToMd5(x, len) {
/* append padding */
x[len >> 5] |= 0x80 << len % 32;
x[getOutputLength(len) - 1] = len;
let a = 1732584193;
let b = -271733879;
let c = -1732584194;
let d = 271733878;
for (let i = 0; i < x.length; i += 16) {
const olda = a;
const oldb = b;
const oldc = c;
const oldd = d;
a = md5ff(a, b, c, d, x[i], 7, -680876936);
d = md5ff(d, a, b, c, x[i + 1], 12, -389564586);
c = md5ff(c, d, a, b, x[i + 2], 17, 606105819);
b = md5ff(b, c, d, a, x[i + 3], 22, -1044525330);
a = md5ff(a, b, c, d, x[i + 4], 7, -176418897);
d = md5ff(d, a, b, c, x[i + 5], 12, 1200080426);
c = md5ff(c, d, a, b, x[i + 6], 17, -1473231341);
b = md5ff(b, c, d, a, x[i + 7], 22, -45705983);
a = md5ff(a, b, c, d, x[i + 8], 7, 1770035416);
d = md5ff(d, a, b, c, x[i + 9], 12, -1958414417);
c = md5ff(c, d, a, b, x[i + 10], 17, -42063);
b = md5ff(b, c, d, a, x[i + 11], 22, -1990404162);
a = md5ff(a, b, c, d, x[i + 12], 7, 1804603682);
d = md5ff(d, a, b, c, x[i + 13], 12, -40341101);
c = md5ff(c, d, a, b, x[i + 14], 17, -1502002290);
b = md5ff(b, c, d, a, x[i + 15], 22, 1236535329);
a = md5gg(a, b, c, d, x[i + 1], 5, -165796510);
d = md5gg(d, a, b, c, x[i + 6], 9, -1069501632);
c = md5gg(c, d, a, b, x[i + 11], 14, 643717713);
b = md5gg(b, c, d, a, x[i], 20, -373897302);
a = md5gg(a, b, c, d, x[i + 5], 5, -701558691);
d = md5gg(d, a, b, c, x[i + 10], 9, 38016083);
c = md5gg(c, d, a, b, x[i + 15], 14, -660478335);
b = md5gg(b, c, d, a, x[i + 4], 20, -405537848);
a = md5gg(a, b, c, d, x[i + 9], 5, 568446438);
d = md5gg(d, a, b, c, x[i + 14], 9, -1019803690);
c = md5gg(c, d, a, b, x[i + 3], 14, -187363961);
b = md5gg(b, c, d, a, x[i + 8], 20, 1163531501);
a = md5gg(a, b, c, d, x[i + 13], 5, -1444681467);
d = md5gg(d, a, b, c, x[i + 2], 9, -51403784);
c = md5gg(c, d, a, b, x[i + 7], 14, 1735328473);
b = md5gg(b, c, d, a, x[i + 12], 20, -1926607734);
a = md5hh(a, b, c, d, x[i + 5], 4, -378558);
d = md5hh(d, a, b, c, x[i + 8], 11, -2022574463);
c = md5hh(c, d, a, b, x[i + 11], 16, 1839030562);
b = md5hh(b, c, d, a, x[i + 14], 23, -35309556);
a = md5hh(a, b, c, d, x[i + 1], 4, -1530992060);
d = md5hh(d, a, b, c, x[i + 4], 11, 1272893353);
c = md5hh(c, d, a, b, x[i + 7], 16, -155497632);
b = md5hh(b, c, d, a, x[i + 10], 23, -1094730640);
a = md5hh(a, b, c, d, x[i + 13], 4, 681279174);
d = md5hh(d, a, b, c, x[i], 11, -358537222);
c = md5hh(c, d, a, b, x[i + 3], 16, -722521979);
b = md5hh(b, c, d, a, x[i + 6], 23, 76029189);
a = md5hh(a, b, c, d, x[i + 9], 4, -640364487);
d = md5hh(d, a, b, c, x[i + 12], 11, -421815835);
c = md5hh(c, d, a, b, x[i + 15], 16, 530742520);
b = md5hh(b, c, d, a, x[i + 2], 23, -995338651);
a = md5ii(a, b, c, d, x[i], 6, -198630844);
d = md5ii(d, a, b, c, x[i + 7], 10, 1126891415);
c = md5ii(c, d, a, b, x[i + 14], 15, -1416354905);
b = md5ii(b, c, d, a, x[i + 5], 21, -57434055);
a = md5ii(a, b, c, d, x[i + 12], 6, 1700485571);
d = md5ii(d, a, b, c, x[i + 3], 10, -1894986606);
c = md5ii(c, d, a, b, x[i + 10], 15, -1051523);
b = md5ii(b, c, d, a, x[i + 1], 21, -2054922799);
a = md5ii(a, b, c, d, x[i + 8], 6, 1873313359);
d = md5ii(d, a, b, c, x[i + 15], 10, -30611744);
c = md5ii(c, d, a, b, x[i + 6], 15, -1560198380);
b = md5ii(b, c, d, a, x[i + 13], 21, 1309151649);
a = md5ii(a, b, c, d, x[i + 4], 6, -145523070);
d = md5ii(d, a, b, c, x[i + 11], 10, -1120210379);
c = md5ii(c, d, a, b, x[i + 2], 15, 718787259);
b = md5ii(b, c, d, a, x[i + 9], 21, -343485551);
a = safeAdd(a, olda);
b = safeAdd(b, oldb);
c = safeAdd(c, oldc);
d = safeAdd(d, oldd);
}
return [a, b, c, d];
}
/*
* Convert an array bytes to an array of little-endian words
* Characters >255 have their high-byte silently ignored.
*/
function bytesToWords(input) {
if (input.length === 0) {
return [];
}
const length8 = input.length * 8;
const output = new Uint32Array(getOutputLength(length8));
for (let i = 0; i < length8; i += 8) {
output[i >> 5] |= (input[i / 8] & 0xff) << i % 32;
}
return output;
}
/*
* Add integers, wrapping at 2^32. This uses 16-bit operations internally
* to work around bugs in some JS interpreters.
*/
function safeAdd(x, y) {
const lsw = (x & 0xffff) + (y & 0xffff);
const msw = (x >> 16) + (y >> 16) + (lsw >> 16);
return msw << 16 | lsw & 0xffff;
}
/*
* Bitwise rotate a 32-bit number to the left.
*/
function bitRotateLeft(num, cnt) {
return num << cnt | num >>> 32 - cnt;
}
/*
* These functions implement the four basic operations the algorithm uses.
*/
function md5cmn(q, a, b, x, s, t) {
return safeAdd(bitRotateLeft(safeAdd(safeAdd(a, q), safeAdd(x, t)), s), b);
}
function md5ff(a, b, c, d, x, s, t) {
return md5cmn(b & c | ~b & d, a, b, x, s, t);
}
function md5gg(a, b, c, d, x, s, t) {
return md5cmn(b & d | c & ~d, a, b, x, s, t);
}
function md5hh(a, b, c, d, x, s, t) {
return md5cmn(b ^ c ^ d, a, b, x, s, t);
}
function md5ii(a, b, c, d, x, s, t) {
return md5cmn(c ^ (b | ~d), a, b, x, s, t);
}
v35('v3', 0x30, md5);
const randomUUID = typeof crypto !== 'undefined' && crypto.randomUUID && crypto.randomUUID.bind(crypto);
var native = {
randomUUID
};
function v4(options, buf, offset) {
if (native.randomUUID && !buf && !options) {
return native.randomUUID();
}
options = options || {};
const rnds = options.random || (options.rng || rng)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
rnds[6] = rnds[6] & 0x0f | 0x40;
rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided
if (buf) {
offset = offset || 0;
for (let i = 0; i < 16; ++i) {
buf[offset + i] = rnds[i];
}
return buf;
}
return unsafeStringify(rnds);
}
// Adapted from Chris Veness' SHA1 code at
// http://www.movable-type.co.uk/scripts/sha1.html
function f(s, x, y, z) {
switch (s) {
case 0:
return x & y ^ ~x & z;
case 1:
return x ^ y ^ z;
case 2:
return x & y ^ x & z ^ y & z;
case 3:
return x ^ y ^ z;
}
}
function ROTL(x, n) {
return x << n | x >>> 32 - n;
}
function sha1(bytes) {
const K = [0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6];
const H = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0];
if (typeof bytes === 'string') {
const msg = unescape(encodeURIComponent(bytes)); // UTF8 escape
bytes = [];
for (let i = 0; i < msg.length; ++i) {
bytes.push(msg.charCodeAt(i));
}
} else if (!Array.isArray(bytes)) {
// Convert Array-like to Array
bytes = Array.prototype.slice.call(bytes);
}
bytes.push(0x80);
const l = bytes.length / 4 + 2;
const N = Math.ceil(l / 16);
const M = new Array(N);
for (let i = 0; i < N; ++i) {
const arr = new Uint32Array(16);
for (let j = 0; j < 16; ++j) {
arr[j] = bytes[i * 64 + j * 4] << 24 | bytes[i * 64 + j * 4 + 1] << 16 | bytes[i * 64 + j * 4 + 2] << 8 | bytes[i * 64 + j * 4 + 3];
}
M[i] = arr;
}
M[N - 1][14] = (bytes.length - 1) * 8 / Math.pow(2, 32);
M[N - 1][14] = Math.floor(M[N - 1][14]);
M[N - 1][15] = (bytes.length - 1) * 8 & 0xffffffff;
for (let i = 0; i < N; ++i) {
const W = new Uint32Array(80);
for (let t = 0; t < 16; ++t) {
W[t] = M[i][t];
}
for (let t = 16; t < 80; ++t) {
W[t] = ROTL(W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16], 1);
}
let a = H[0];
let b = H[1];
let c = H[2];
let d = H[3];
let e = H[4];
for (let t = 0; t < 80; ++t) {
const s = Math.floor(t / 20);
const T = ROTL(a, 5) + f(s, b, c, d) + e + K[s] + W[t] >>> 0;
e = d;
d = c;
c = ROTL(b, 30) >>> 0;
b = a;
a = T;
}
H[0] = H[0] + a >>> 0;
H[1] = H[1] + b >>> 0;
H[2] = H[2] + c >>> 0;
H[3] = H[3] + d >>> 0;
H[4] = H[4] + e >>> 0;
}
return [H[0] >> 24 & 0xff, H[0] >> 16 & 0xff, H[0] >> 8 & 0xff, H[0] & 0xff, H[1] >> 24 & 0xff, H[1] >> 16 & 0xff, H[1] >> 8 & 0xff, H[1] & 0xff, H[2] >> 24 & 0xff, H[2] >> 16 & 0xff, H[2] >> 8 & 0xff, H[2] & 0xff, H[3] >> 24 & 0xff, H[3] >> 16 & 0xff, H[3] >> 8 & 0xff, H[3] & 0xff, H[4] >> 24 & 0xff, H[4] >> 16 & 0xff, H[4] >> 8 & 0xff, H[4] & 0xff];
}
v35('v5', 0x50, sha1);
function decodeBase64(base64, enableUnicode) {
var binaryString = atob(base64);
if (enableUnicode) {
var binaryView = new Uint8Array(binaryString.length);
for (var i = 0, n = binaryString.length; i < n; ++i) {
binaryView[i] = binaryString.charCodeAt(i);
}
return String.fromCharCode.apply(null, new Uint16Array(binaryView.buffer));
}
return binaryString;
}
function createURL(base64, sourcemapArg, enableUnicodeArg) {
var sourcemap = sourcemapArg === undefined ? null : sourcemapArg;
var enableUnicode = enableUnicodeArg === undefined ? false : enableUnicodeArg;
var source = decodeBase64(base64, enableUnicode);
var start = source.indexOf('\n', 10) + 1;
var body = source.substring(start) + (sourcemap ? '\/\/# sourceMappingURL=' + sourcemap : '');
var blob = new Blob([body], { type: 'application/javascript' });
return URL.createObjectURL(blob);
}
function createBase64WorkerFactory(base64, sourcemapArg, enableUnicodeArg) {
var url;
return function WorkerFactory(options) {
url = url || createURL(base64, sourcemapArg, enableUnicodeArg);
return new Worker(url, options);
};
}
var WorkerFactory = createBase64WorkerFactory('Lyogcm9sbHVwLXBsdWdpbi13ZWItd29ya2VyLWxvYWRlciAqLwp2YXIgd29ya2VyX2NvZGUgPSAoZnVuY3Rpb24gKGV4cG9ydHMpIHsKICAgICd1c2Ugc3RyaWN0JzsKCiAgICAvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqDQogICAgQ29weXJpZ2h0IChjKSBNaWNyb3NvZnQgQ29ycG9yYXRpb24uDQoNCiAgICBQZXJtaXNzaW9uIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBhbmQvb3IgZGlzdHJpYnV0ZSB0aGlzIHNvZnR3YXJlIGZvciBhbnkNCiAgICBwdXJwb3NlIHdpdGggb3Igd2l0aG91dCBmZWUgaXMgaGVyZWJ5IGdyYW50ZWQuDQoNCiAgICBUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgIkFTIElTIiBBTkQgVEhFIEFVVEhPUiBESVNDTEFJTVMgQUxMIFdBUlJBTlRJRVMgV0lUSA0KICAgIFJFR0FSRCBUTyBUSElTIFNPRlRXQVJFIElOQ0xVRElORyBBTEwgSU1QTElFRCBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWQ0KICAgIEFORCBGSVRORVNTLiBJTiBOTyBFVkVOVCBTSEFMTCBUSEUgQVVUSE9SIEJFIExJQUJMRSBGT1IgQU5ZIFNQRUNJQUwsIERJUkVDVCwNCiAgICBJTkRJUkVDVCwgT1IgQ09OU0VRVUVOVElBTCBEQU1BR0VTIE9SIEFOWSBEQU1BR0VTIFdIQVRTT0VWRVIgUkVTVUxUSU5HIEZST00NCiAgICBMT1NTIE9GIFVTRSwgREFUQSBPUiBQUk9GSVRTLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgTkVHTElHRU5DRSBPUg0KICAgIE9USEVSIFRPUlRJT1VTIEFDVElPTiwgQVJJU0lORyBPVVQgT0YgT1IgSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBVU0UgT1INCiAgICBQRVJGT1JNQU5DRSBPRiBUSElTIFNPRlRXQVJFLg0KICAgICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqICovDQoNCiAgICBmdW5jdGlvbiBfX2F3YWl0ZXIodGhpc0FyZywgX2FyZ3VtZW50cywgUCwgZ2VuZXJhdG9yKSB7DQogICAgICAgIGZ1bmN0aW9uIGFkb3B0KHZhbHVlKSB7IHJldHVybiB2YWx1ZSBpbnN0YW5jZW9mIFAgPyB2YWx1ZSA6IG5ldyBQKGZ1bmN0aW9uIChyZXNvbHZlKSB7IHJlc29sdmUodmFsdWUpOyB9KTsgfQ0KICAgICAgICByZXR1cm4gbmV3IChQIHx8IChQID0gUHJvbWlzZSkpKGZ1bmN0aW9uIChyZXNvbHZlLCByZWplY3QpIHsNCiAgICAgICAgICAgIGZ1bmN0aW9uIGZ1bGZpbGxlZCh2YWx1ZSkgeyB0cnkgeyBzdGVwKGdlbmVyYXRvci5uZXh0KHZhbHVlKSk7IH0gY2F0Y2ggKGUpIHsgcmVqZWN0KGUpOyB9IH0NCiAgICAgICAgICAgIGZ1bmN0aW9uIHJlamVjdGVkKHZhbHVlKSB7IHRyeSB7IHN0ZXAoZ2VuZXJhdG9yWyJ0aHJvdyJdKHZhbHVlKSk7IH0gY2F0Y2ggKGUpIHsgcmVqZWN0KGUpOyB9IH0NCiAgICAgICAgICAgIGZ1bmN0aW9uIHN0ZXAocmVzdWx0KSB7IHJlc3VsdC5kb25lID8gcmVzb2x2ZShyZXN1bHQudmFsdWUpIDogYWRvcHQocmVzdWx0LnZhbHVlKS50aGVuKGZ1bGZpbGxlZCwgcmVqZWN0ZWQpOyB9DQogICAgICAgICAgICBzdGVwKChnZW5lcmF0b3IgPSBnZW5lcmF0b3IuYXBwbHkodGhpc0FyZywgX2FyZ3VtZW50cyB8fCBbXSkpLm5leHQoKSk7DQogICAgICAgIH0pOw0KICAgIH0KCiAgICB2YXIgdm9za1dhc20gPSB7ZXhwb3J0czoge319OwoKICAgIChmdW5jdGlvbiAobW9kdWxlLCBleHBvcnRzKSB7CiAgICAJdmFyIExvYWRWb3NrID0gKGZ1bmN0aW9uKCkgewogICAgCSAgdmFyIF9zY3JpcHREaXIgPSB0eXBlb2YgZG9jdW1lbnQgIT09ICd1bmRlZmluZWQnICYmIGRvY3VtZW50LmN1cnJlbnRTY3JpcHQgPyBkb2N1bWVudC5jdXJyZW50U2NyaXB0LnNyYyA6IHVuZGVmaW5lZDsKICAgIAkgIAogICAgCSAgcmV0dXJuICgKICAgIAlmdW5jdGlvbihMb2FkVm9zaykgewogICAgCSAgTG9hZFZvc2sgPSBMb2FkVm9zayB8fCB7fTsKCiAgICAJdmFyIE1vZHVsZT10eXBlb2YgTG9hZFZvc2shPT0idW5kZWZpbmVkIj9Mb2FkVm9zazp7fTt2YXIgcmVhZHlQcm9taXNlUmVzb2x2ZSxyZWFkeVByb21pc2VSZWplY3Q7TW9kdWxlWyJyZWFkeSJdPW5ldyBQcm9taXNlKGZ1bmN0aW9uKHJlc29sdmUscmVqZWN0KXtyZWFkeVByb21pc2VSZXNvbHZlPXJlc29sdmU7cmVhZHlQcm9taXNlUmVqZWN0PXJlamVjdDt9KTt2YXIgTW9kdWxlPWZ1bmN0aW9uKE1vZHVsZSl7ZnVuY3Rpb24gZGV0ZXJtaW5lQ3VycmVudFNjcmlwdCgpe2lmKHR5cGVvZiBkb2N1bWVudCE9PSJ1bmRlZmluZWQiKXtyZXR1cm4gZG9jdW1lbnQuY3VycmVudFNjcmlwdC5zcmN9aWYodHlwZW9mIHNlbGYuQ1VSUkVOVF9TQ1JJUFQ9PT0ic3RyaW5nIil7cmV0dXJuIHNlbGYuQ1VSUkVOVF9TQ1JJUFR9cmV0dXJuIGxvY2F0aW9uLmhyZWZ9Y29uc3QgY3VycmVudFNjcmlwdD1kZXRlcm1pbmVDdXJyZW50U2NyaXB0KCk7ZnVuY3Rpb24gbG9jYXRlRmlsZShwYXRoLHByZWZpeCl7Y29uc3QgdXJsPW5ldyBVUkwocHJlZml4K3BhdGgsY3VycmVudFNjcmlwdCk7cmV0dXJuIHVybC50b1N0cmluZygpfXJldHVybiBPYmplY3QuYXNzaWduKE1vZHVsZSx7ImxvY2F0ZUZpbGUiOmxvY2F0ZUZpbGV9KX0oTW9kdWxlfHx7fSk7dmFyIG1vZHVsZU92ZXJyaWRlcz17fTt2YXIga2V5O2ZvcihrZXkgaW4gTW9kdWxlKXtpZihNb2R1bGUuaGFzT3duUHJvcGVydHkoa2V5KSl7bW9kdWxlT3ZlcnJpZGVzW2tleV09TW9kdWxlW2tleV07fX12YXIgdGhpc1Byb2dyYW09Ii4vdGhpcy5wcm9ncmFtIjt2YXIgcXVpdF89ZnVuY3Rpb24oc3RhdHVzLHRvVGhyb3cpe3Rocm93IHRvVGhyb3d9O3ZhciBFTlZJUk9OTUVOVF9JU19XT1JLRVI9dHJ1ZTt2YXIgc2NyaXB0RGlyZWN0b3J5PSIiO2Z1bmN0aW9uIGxvY2F0ZUZpbGUocGF0aCl7aWYoTW9kdWxlWyJsb2NhdGVGaWxlIl0pe3JldHVybiBNb2R1bGVbImxvY2F0ZUZpbGUiXShwYXRoLHNjcmlwdERpcmVjdG9yeSl9cmV0dXJuIHNjcmlwdERpcmVjdG9yeStwYXRofXZhciByZWFkXyxyZWFkQXN5bmMscmVhZEJpbmFyeTt7e3NjcmlwdERpcmVjdG9yeT1zZWxmLmxvY2F0aW9uLmhyZWY7fWlmKF9zY3JpcHREaXIpe3NjcmlwdERpcmVjdG9yeT1fc2NyaXB0RGlyO31pZihzY3JpcHREaXJlY3RvcnkuaW5kZXhPZigiYmxvYjoiKSE9PTApe3NjcmlwdERpcmVjdG9yeT1zY3JpcHREaXJlY3Rvcnkuc3Vic3RyKDAsc2NyaXB0RGlyZWN0b3J5Lmxhc3RJbmRleE9mKCIvIikrMSk7fWVsc2Uge3NjcmlwdERpcmVjdG9yeT0iIjt9e3JlYWRfPWZ1bmN0aW9uKHVybCl7dHJ5e3ZhciB4aHI9bmV3IFhNTEh0dHBSZXF1ZXN0O3hoci5vcGVuKCJHRVQiLHVybCxmYWxzZSk7eGhyLnNlbmQobnVsbCk7cmV0dXJuIHhoci5yZXNwb25zZVRleHR9Y2F0Y2goZXJyKXt2YXIgZGF0YT10cnlQYXJzZUFzRGF0YVVSSSh1cmwpO2lmKGRhdGEpe3JldHVybiBpbnRBcnJheVRvU3RyaW5nKGRhdGEpfXRocm93IGVycn19O3tyZWFkQmluYXJ5PWZ1bmN0aW9uKHVybCl7dHJ5e3ZhciB4aHI9bmV3IFhNTEh0dHBSZXF1ZXN0O3hoci5vcGVuKCJHRVQiLHVybCxmYWxzZSk7eGhyLnJlc3BvbnNlVHlwZT0iYXJyYXlidWZmZXIiO3hoci5zZW5kKG51bGwpO3JldHVybiBuZXcgVWludDhBcnJheSh4aHIucmVzcG9uc2UpfWNhdGNoKGVycil7dmFyIGRhdGE9dHJ5UGFyc2VBc0RhdGFVUkkodXJsKTtpZihkYXRhKXtyZXR1cm4gZGF0YX10aHJvdyBlcnJ9fTt9cmVhZEFzeW5jPWZ1bmN0aW9uKHVybCxvbmxvYWQsb25lcnJvcil7dmFyIHhocj1uZXcgWE1MSHR0cFJlcXVlc3Q7eGhyLm9wZW4oIkdFVCIsdXJsLHRydWUpO3hoci5yZXNwb25zZVR5cGU9ImFycmF5YnVmZmVyIjt4aHIub25sb2FkPWZ1bmN0aW9uKCl7aWYoeGhyLnN0YXR1cz09MjAwfHx4aHIuc3RhdHVzPT0wJiZ4aHIucmVzcG9uc2Upe29ubG9hZCh4aHIucmVzcG9uc2UpO3JldHVybn12YXIgZGF0YT10cnlQYXJzZUFzRGF0YVVSSSh1cmwpO2lmKGRhdGEpe29ubG9hZChkYXRhLmJ1ZmZlcik7cmV0dXJufW9uZXJyb3IoKTt9O3hoci5vbmVycm9yPW9uZXJyb3I7eGhyLnNlbmQobnVsbCk7fTt9fXZhciBvdXQ9TW9kdWxlWyJwcmludCJdfHxjb25zb2xlLmxvZy5iaW5kKGNvbnNvbGUpO3ZhciBlcnI9TW9kdWxlWyJwcmludEVyciJdfHxjb25zb2xlLndhcm4uYmluZChjb25zb2xlKTtmb3Ioa2V5IGluIG1vZHVsZU92ZXJyaWRlcyl7aWYobW9kdWxlT3ZlcnJpZGVzLmhhc093blByb3BlcnR5KGtleSkpe01vZHVsZVtrZXldPW1vZHVsZU92ZXJyaWRlc1trZXldO319bW9kdWxlT3ZlcnJpZGVzPW51bGw7aWYoTW9kdWxlWyJhcmd1bWVudHMiXSlNb2R1bGVbImFyZ3VtZW50cyJdO2lmKE1vZHVsZVsidGhpc1Byb2dyYW0iXSl0aGlzUHJvZ3JhbT1Nb2R1bGVbInRoaXNQcm9ncmFtIl07aWYoTW9kdWxlWyJxdWl0Il0pcXVpdF89TW9kdWxlWyJxdWl0Il07dmFyIHdhc21CaW5hcnk7aWYoTW9kdWxlWyJ3YXNtQmluYXJ5Il0pd2FzbUJpbmFyeT1Nb2R1bGVbIndhc21CaW5hcnkiXTt2YXIgbm9FeGl0UnVudGltZT1Nb2R1bGVbIm5vRXhpdFJ1bnRpbWUiXXx8dHJ1ZTtpZih0eXBlb2YgV2ViQXNzZW1ibHkhPT0ib2JqZWN0Iil7YWJvcnQoIm5vIG5hdGl2ZSB3YXNtIHN1cHBvcnQgZGV0ZWN0ZWQiKTt9dmFyIHdhc21NZW1vcnk7dmFyIEFCT1JUPWZhbHNlO2Z1bmN0aW9uIGFzc2VydChjb25kaXRpb24sdGV4dCl7aWYoIWNvbmRpdGlvbil7YWJvcnQoIkFzc2VydGlvbiBmYWlsZWQ6ICIrdGV4dCk7fX12YXIgVVRGOERlY29kZXI9dHlwZW9mIFRleHREZWNvZGVyIT09InVuZGVmaW5lZCI/bmV3IFRleHREZWNvZGVyKCJ1dGY4Iik6dW5kZWZpbmVkO2Z1bmN0aW9uIFVURjhBcnJheVRvU3RyaW5nKGhlYXAsaWR4LG1heEJ5dGVzVG9SZWFkKXt2YXIgZW5kSWR4PWlkeCttYXhCeXRlc1RvUmVhZDt2YXIgZW5kUHRyPWlkeDt3aGlsZShoZWFwW2VuZFB0cl0mJiEoZW5kUHRyPj1lbmRJZHgpKSsrZW5kUHRyO2lmKGVuZFB0ci1pZHg+MTYmJmhlYXAuc3ViYXJyYXkmJlVURjhEZWNvZGVyKXtyZXR1cm4gVVRGOERlY29kZXIuZGVjb2RlKGhlYXAuc3ViYXJyYXkoaWR4LGVuZFB0cikpfWVsc2Uge3ZhciBzdHI9IiI7d2hpbGUoaWR4PGVuZFB0cil7dmFyIHUwPWhlYXBbaWR4KytdO2lmKCEodTAmMTI4KSl7c3RyKz1TdHJpbmcuZnJvbUNoYXJDb2RlKHUwKTtjb250aW51ZX12YXIgdTE9aGVhcFtpZHgrK10mNjM7aWYoKHUwJjIyNCk9PTE5Mil7c3RyKz1TdHJpbmcuZnJvbUNoYXJDb2RlKCh1MCYzMSk8PDZ8dTEpO2NvbnRpbnVlfXZhciB1Mj1oZWFwW2lkeCsrXSY2MztpZigodTAmMjQwKT09MjI0KXt1MD0odTAmMTUpPDwxMnx1MTw8Nnx1Mjt9ZWxzZSB7dTA9KHUwJjcpPDwxOHx1MTw8MTJ8dTI8PDZ8aGVhcFtpZHgrK10mNjM7fWlmKHUwPDY1NTM2KXtzdHIrPVN0cmluZy5mcm9tQ2hhckNvZGUodTApO31lbHNlIHt2YXIgY2g9dTAtNjU1MzY7c3RyKz1TdHJpbmcuZnJvbUNoYXJDb2RlKDU1Mjk2fGNoPj4xMCw1NjMyMHxjaCYxMDIzKTt9fX1yZXR1cm4gc3RyfWZ1bmN0aW9uIFVURjhUb1N0cmluZyhwdHIsbWF4Qnl0ZXNUb1JlYWQpe3JldHVybiBwdHI/VVRGOEFycmF5VG9TdHJpbmcoSEVBUFU4LHB0cixtYXhCeXRlc1RvUmVhZCk6IiJ9ZnVuY3Rpb24gc3RyaW5nVG9VVEY4QXJyYXkoc3RyLGhlYXAsb3V0SWR4LG1heEJ5dGVzVG9Xcml0ZSl7aWYoIShtYXhCeXRlc1RvV3JpdGU+MCkpcmV0dXJuIDA7dmFyIHN0YXJ0SWR4PW91dElkeDt2YXIgZW5kSWR4PW91dElkeCttYXhCeXRlc1RvV3JpdGUtMTtmb3IodmFyIGk9MDtpPHN0ci5sZW5ndGg7KytpKXt2YXIgdT1zdHIuY2hhckNvZGVBdChpKTtpZih1Pj01NTI5NiYmdTw9NTczNDMpe3ZhciB1MT1zdHIuY2hhckNvZGVBdCgrK2kpO3U9NjU1MzYrKCh1JjEwMjMpPDwxMCl8dTEmMTAyMzt9aWYodTw9MTI3KXtpZihvdXRJZHg+PWVuZElkeClicmVhaztoZWFwW291dElkeCsrXT11O31lbHNlIGlmKHU8PTIwNDcpe2lmKG91dElkeCsxPj1lbmRJZHgpYnJlYWs7aGVhcFtvdXRJZHgrK109MTkyfHU+PjY7aGVhcFtvdXRJZHgrK109MTI4fHUmNjM7fWVsc2UgaWYodTw9NjU1MzUpe2lmKG91dElkeCsyPj1lbmRJZHgpYnJlYWs7aGVhcFtvdXRJZHgrK109MjI0fHU+PjEyO2hlYXBbb3V0SWR4KytdPTEyOHx1Pj42JjYzO2hlYXBbb3V0SWR4KytdPTEyOHx1JjYzO31lbHNlIHtpZihvdXRJZHgrMz49ZW5kSWR4KWJyZWFrO2hlYXBbb3V0SWR4KytdPTI0MHx1Pj4xODtoZWFwW291dElkeCsrXT0xMjh8dT4+MTImNjM7aGVhcFtvdXRJZHgrK109MTI4fHU+PjYmNjM7aGVhcFtvdXRJZHgrK109MTI4fHUmNjM7fX1oZWFwW291dElkeF09MDtyZXR1cm4gb3V0SWR4LXN0YXJ0SWR4fWZ1bmN0aW9uIHN0cmluZ1RvVVRGOChzdHIsb3V0UHRyLG1heEJ5dGVzVG9Xcml0ZSl7cmV0dXJuIHN0cmluZ1RvVVRGOEFycmF5KHN0cixIRUFQVTgsb3V0UHRyLG1heEJ5dGVzVG9Xcml0ZSl9ZnVuY3Rpb24gbGVuZ3RoQnl0ZXNVVEY4KHN0cil7dmFyIGxlbj0wO2Zvcih2YXIgaT0wO2k8c3RyLmxlbmd0aDsrK2kpe3ZhciB1PXN0ci5jaGFyQ29kZUF0KGkpO2lmKHU+PTU1Mjk2JiZ1PD01NzM0Myl1PTY1NTM2KygodSYxMDIzKTw8MTApfHN0ci5jaGFyQ29kZUF0KCsraSkmMTAyMztpZih1PD0xMjcpKytsZW47ZWxzZSBpZih1PD0yMDQ3KWxlbis9MjtlbHNlIGlmKHU8PTY1NTM1KWxlbis9MztlbHNlIGxlbis9NDt9cmV0dXJuIGxlbn12YXIgVVRGMTZEZWNvZGVyPXR5cGVvZiBUZXh0RGVjb2RlciE9PSJ1bmRlZmluZWQiP25ldyBUZXh0RGVjb2RlcigidXRmLTE2bGUiKTp1bmRlZmluZWQ7ZnVuY3Rpb24gVVRGMTZUb1N0cmluZyhwdHIsbWF4Qnl0ZXNUb1JlYWQpe3ZhciBlbmRQdHI9cHRyO3ZhciBpZHg9ZW5kUHRyPj4xO3ZhciBtYXhJZHg9aWR4K21heEJ5dGVzVG9SZWFkLzI7d2hpbGUoIShpZHg+PW1heElkeCkmJkhFQVBVMTZbaWR4XSkrK2lkeDtlbmRQdHI9aWR4PDwxO2lmKGVuZFB0ci1wdHI+MzImJlVURjE2RGVjb2Rlcil7cmV0dXJuIFVURjE2RGVjb2Rlci5kZWNvZGUoSEVBUFU4LnN1YmFycmF5KHB0cixlbmRQdHIpKX1lbHNlIHt2YXIgc3RyPSIiO2Zvcih2YXIgaT0wOyEoaT49bWF4Qnl0ZXNUb1JlYWQvMik7KytpKXt2YXIgY29kZVVuaXQ9SEVBUDE2W3B0citpKjI+PjFdO2lmKGNvZGVVbml0PT0wKWJyZWFrO3N0cis9U3RyaW5nLmZyb21DaGFyQ29kZShjb2RlVW5pdCk7fXJldHVybiBzdHJ9fWZ1bmN0aW9uIHN0cmluZ1RvVVRGMTYoc3RyLG91dFB0cixtYXhCeXRlc1RvV3JpdGUpe2lmKG1heEJ5dGVzVG9Xcml0ZT09PXVuZGVmaW5lZCl7bWF4Qnl0ZXNUb1dyaXRlPTIxNDc0ODM2NDc7fWlmKG1heEJ5dGVzVG9Xcml0ZTwyKXJldHVybiAwO21heEJ5dGVzVG9Xcml0ZS09Mjt2YXIgc3RhcnRQdHI9b3V0UHRyO3ZhciBudW1DaGFyc1RvV3JpdGU9bWF4Qnl0ZXNUb1dyaXRlPHN0ci5sZW5ndGgqMj9tYXhCeXRlc1RvV3JpdGUvMjpzdHIubGVuZ3RoO2Zvcih2YXIgaT0wO2k8bnVtQ2hhcnNUb1dyaXRlOysraSl7dmFyIGNvZGVVbml0PXN0ci5jaGFyQ29kZUF0KGkpO0hFQVAxNltvdXRQdHI+PjFdPWNvZGVVbml0O291dFB0cis9Mjt9SEVBUDE2W291dFB0cj4+MV09MDtyZXR1cm4gb3V0UHRyLXN0YXJ0UHRyfWZ1bmN0aW9uIGxlbmd0aEJ5dGVzVVRGMTYoc3RyKXtyZXR1cm4gc3RyLmxlbmd0aCoyfWZ1bmN0aW9uIFVURjMyVG9TdHJpbmcocHRyLG1heEJ5dGVzVG9SZWFkKXt2YXIgaT0wO3ZhciBzdHI9IiI7d2hpbGUoIShpPj1tYXhCeXRlc1RvUmVhZC80KSl7dmFyIHV0ZjMyPUhFQVAzMltwdHIraSo0Pj4yXTtpZih1dGYzMj09MClicmVhazsrK2k7aWYodXRmMzI+PTY1NTM2KXt2YXIgY2g9dXRmMzItNjU1MzY7c3RyKz1TdHJpbmcuZnJvbUNoYXJDb2RlKDU1Mjk2fGNoPj4xMCw1NjMyMHxjaCYxMDIzKTt9ZWxzZSB7c3RyKz1TdHJpbmcuZnJvbUNoYXJDb2RlKHV0ZjMyKTt9fXJldHVybiBzdHJ9ZnVuY3Rpb24gc3RyaW5nVG9VVEYzMihzdHIsb3V0UHRyLG1heEJ5dGVzVG9Xcml0ZSl7aWYobWF4Qnl0ZXNUb1dyaXRlPT09dW5kZWZpbmVkKXttYXhCeXRlc1RvV3JpdGU9MjE0NzQ4MzY0Nzt9aWYobWF4Qnl0ZXNUb1dyaXRlPDQpcmV0dXJuIDA7dmFyIHN0YXJ0UHRyPW91dFB0cjt2YXIgZW5kUHRyPXN0YXJ0UHRyK21heEJ5dGVzVG9Xcml0ZS00O2Zvcih2YXIgaT0wO2k8c3RyLmxlbmd0aDsrK2kpe3ZhciBjb2RlVW5pdD1zdHIuY2hhckNvZGVBdChpKTtpZihjb2RlVW5pdD49NTUyOTYmJmNvZGVVbml0PD01NzM0Myl7dmFyIHRyYWlsU3Vycm9nYXRlPXN0ci5jaGFyQ29kZUF0KCsraSk7Y29kZVVuaXQ9NjU1MzYrKChjb2RlVW5pdCYxMDIzKTw8MTApfHRyYWlsU3Vycm9nYXRlJjEwMjM7fUhFQVAzMltvdXRQdHI+PjJdPWNvZGVVbml0O291dFB0cis9NDtpZihvdXRQdHIrND5lbmRQdHIpYnJlYWt9SEVBUDMyW291dFB0cj4+Ml09MDtyZXR1cm4gb3V0UHRyLXN0YXJ0UHRyfWZ1bmN0aW9uIGxlbmd0aEJ5dGVzVVRGMzIoc3RyKXt2YXIgbGVuPTA7Zm9yKHZhciBpPTA7aTxzdHIubGVuZ3RoOysraSl7dmFyIGNvZGVVbml0PXN0ci5jaGFyQ29kZUF0KGkpO2lmKGNvZGVVbml0Pj01NTI5NiYmY29kZVVuaXQ8PTU3MzQzKSsraTtsZW4rPTQ7fXJldHVybiBsZW59ZnVuY3Rpb24gYWxsb2NhdGVVVEY4KHN0cil7dmFyIHNpemU9bGVuZ3RoQnl0ZXNVVEY4KHN0cikrMTt2YXIgcmV0PV9tYWxsb2Moc2l6ZSk7aWYocmV0KXN0cmluZ1RvVVRGOEFycmF5KHN0cixIRUFQOCxyZXQsc2l6ZSk7cmV0dXJuIHJldH1mdW5jdGlvbiB3cml0ZUFycmF5VG9NZW1vcnkoYXJyYXksYnVmZmVyKXtIRUFQOC5zZXQoYXJyYXksYnVmZmVyKTt9ZnVuY3Rpb24gd3JpdGVBc2NpaVRvTWVtb3J5KHN0cixidWZmZXIsZG9udEFkZE51bGwpe2Zvcih2YXIgaT0wO2k8c3RyLmxlbmd0aDsrK2kpe0hFQVA4W2J1ZmZlcisrPj4wXT1zdHIuY2hhckNvZGVBdChpKTt9aWYoIWRvbnRBZGROdWxsKUhFQVA4W2J1ZmZlcj4+MF09MDt9ZnVuY3Rpb24gYWxpZ25VcCh4LG11bHRpcGxlKXtpZih4JW11bHRpcGxlPjApe3grPW11bHRpcGxlLXglbXVsdGlwbGU7fXJldHVybiB4fXZhciBidWZmZXIsSEVBUDgsSEVBUFU4LEhFQVAxNixIRUFQVTE2LEhFQVAzMixIRUFQVTMyLEhFQVBGMzIsSEVBUEY2NDtmdW5jdGlvbiB1cGRhdGVHbG9iYWxCdWZmZXJBbmRWaWV3cyhidWYpe2J1ZmZlcj1idWY7TW9kdWxlWyJIRUFQOCJdPUhFQVA4PW5ldyBJbnQ4QXJyYXkoYnVmKTtNb2R1bGVbIkhFQVAxNiJdPUhFQVAxNj1uZXcgSW50MTZBcnJheShidWYpO01vZHVsZVsiSEVBUDMyIl09SEVBUDMyPW5ldyBJbnQzMkFycmF5KGJ1Zik7TW9kdWxlWyJIRUFQVTgiXT1IRUFQVTg9bmV3IFVpbnQ4QXJyYXkoYnVmKTtNb2R1bGVbIkhFQVBVMTYiXT1IRUFQVTE2PW5ldyBVaW50MTZBcnJheShidWYpO01vZHVsZVsiSEVBUFUzMiJdPUhFQVBVMzI9bmV3IFVpbnQzMkFycmF5KGJ1Zik7TW9kdWxlWyJIRUFQRjMyIl09SEVBUEYzMj1uZXcgRmxvYXQzMkFycmF5KGJ1Zik7TW9kdWxlWyJIRUFQRjY0Il09SEVBUEY2ND1uZXcgRmxvYXQ2NEFycmF5KGJ1Zik7fU1vZHVsZVsiSU5JVElBTF9NRU1PUlkiXXx8MTY3NzcyMTY7dmFyIHdhc21UYWJsZTt2YXIgX19BVFBSRVJVTl9fPVtdO3ZhciBfX0FUSU5JVF9fPVtdO3ZhciBfX0FUUE9TVFJVTl9fPVtdO3ZhciBydW50aW1lS2VlcGFsaXZlQ291bnRlcj0wO2Z1bmN0aW9uIGtlZXBSdW50aW1lQWxpdmUoKXtyZXR1cm4gbm9FeGl0UnVudGltZXx8cnVudGltZUtlZXBhbGl2ZUNvdW50ZXI+MH1mdW5jdGlvbiBwcmVSdW4oKXtpZihNb2R1bGVbInByZVJ1biJdKXtpZih0eXBlb2YgTW9kdWxlWyJwcmVSdW4iXT09ImZ1bmN0aW9uIilNb2R1bGVbInByZVJ1biJdPVtNb2R1bGVbInByZVJ1biJdXTt3aGlsZShNb2R1bGVbInByZVJ1biJdLmxlbmd0aCl7YWRkT25QcmVSdW4oTW9kdWxlWyJwcmVSdW4iXS5zaGlmdCgpKTt9fWNhbGxSdW50aW1lQ2FsbGJhY2tzKF9fQVRQUkVSVU5fXyk7fWZ1bmN0aW9uIGluaXRSdW50aW1lKCl7aWYoIU1vZHVsZVsibm9GU0luaXQiXSYmIUZTLmluaXQuaW5pdGlhbGl6ZWQpRlMuaW5pdCgpO0ZTLmlnbm9yZVBlcm1pc3Npb25zPWZhbHNlO2NhbGxSdW50aW1lQ2FsbGJhY2tzKF9fQVRJTklUX18pO31mdW5jdGlvbiBwb3N0UnVuKCl7aWYoTW9kdWxlWyJwb3N0UnVuIl0pe2lmKHR5cGVvZiBNb2R1bGVbInBvc3RSdW4iXT09ImZ1bmN0aW9uIilNb2R1bGVbInBvc3RSdW4iXT1bTW9kdWxlWyJwb3N0UnVuIl1dO3doaWxlKE1vZHVsZVsicG9zdFJ1biJdLmxlbmd0aCl7YWRkT25Qb3N0UnVuKE1vZHVsZVsicG9zdFJ1biJdLnNoaWZ0KCkpO319Y2FsbFJ1bnRpbWVDYWxsYmFja3MoX19BVFBPU1RSVU5fXyk7fWZ1bmN0aW9uIGFkZE9uUHJlUnVuKGNiKXtfX0FUUFJFUlVOX18udW5zaGlmdChjYik7fWZ1bmN0aW9uIGFkZE9uSW5pdChjYil7X19BVElOSVRfXy51bnNoaWZ0KGNiKTt9ZnVuY3Rpb24gYWRkT25Qb3N0UnVuKGNiKXtfX0FUUE9TVFJVTl9fLnVuc2hpZnQoY2IpO312YXIgcnVuRGVwZW5kZW5jaWVzPTA7dmFyIGRlcGVuZGVuY2llc0Z1bGZpbGxlZD1udWxsO2Z1bmN0aW9uIGdldFVuaXF1ZVJ1bkRlcGVuZGVuY3koaWQpe3JldHVybiBpZH1mdW5jdGlvbiBhZGRSdW5EZXBlbmRlbmN5KGlkKXtydW5EZXBlbmRlbmNpZXMrKztpZihNb2R1bGVbIm1vbml0b3JSdW5EZXBlbmRlbmNpZXMiXSl7TW9kdWxlWyJtb25pdG9yUnVuRGVwZW5kZW5jaWVzIl0ocnVuRGVwZW5kZW5jaWVzKTt9fWZ1bmN0aW9uIHJlbW92ZVJ1bkRlcGVuZGVuY3koaWQpe3J1bkRlcGVuZGVuY2llcy0tO2lmKE1vZHVsZVsibW9uaXRvclJ1bkRlcGVuZGVuY2llcyJdKXtNb2R1bGVbIm1vbml0b3JSdW5EZXBlbmRlbmNpZXMiXShydW5EZXBlbmRlbmNpZXMpO31pZihydW5EZXBlbmRlbmNpZXM9PTApe2lmKGRlcGVuZGVuY2llc0Z1bGZpbGxlZCl7dmFyIGNhbGxiYWNrPWRlcGVuZGVuY2llc0Z1bGZpbGxlZDtkZXBlbmRlbmNpZXNGdWxmaWxsZWQ9bnVsbDtjYWxsYmFjaygpO319fU1vZHVsZVsicHJlbG9hZGVkSW1hZ2VzIl09e307TW9kdWxlWyJwcmVsb2FkZWRBdWRpb3MiXT17fTtmdW5jdGlvbiBhYm9ydCh3aGF0KXt7aWYoTW9kdWxlWyJvbkFib3J0Il0pe01vZHVsZVsib25BYm9ydCJdKHdoYXQpO319d2hhdCs9IiI7ZXJyKHdoYXQpO0FCT1JUPXRydWU7d2hhdD0iYWJvcnQoIit3aGF0KyIpLiBCdWlsZCB3aXRoIC1zIEFTU0VSVElPTlM9MSBmb3IgbW9yZSBpbmZvLiI7dmFyIGU9bmV3IFdlYkFzc2VtYmx5LlJ1bnRpbWVFcnJvcih3aGF0KTtyZWFkeVByb21pc2VSZWplY3QoZSk7dGhyb3cgZX12YXIgZGF0YVVSSVByZWZpeD0iZGF0YTphcHBsaWNhdGlvbi9vY3RldC1zdHJlYW07YmFzZTY0LCI7ZnVuY3Rpb24gaXNEYXRhVVJJKGZpbGVuYW1lKXtyZXR1cm4gZmlsZW5hbWUuc3RhcnRzV2l0aChkYXRhVVJJUHJlZml4KX12YXIgd2FzbUJpbmFyeUZpbGU7d2FzbUJpbmFyeUZpbGU9ImRhdGE6YXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtO2Jhc2U2NCxBR0Z6YlFFQUFBQUI3UWlLQVdBQmZ3Ri9ZQUYvQUdBQ2YzOEJmMkFDZjM4QVlBTi9mMzhBWUFOL2YzOEJmMkFFZjM5L2Z3QmdBMzkrZndGK1lBUi9mMzkvQVg5Z0FuOS9BWDFnQlg5L2YzOS9BWDlnQVg4QmZtQUZmMzkvZjM4QVlBSi9mZ0YrWUFKL2ZRQmdDWDkvZjM5L2YzOS9md0JnQm45L2YzOS9md0YvWUFOL2ZuNEFZQU4vZlg4QVlBWi9mMzkvZjM4QVlBaC9mMzkvZjM5L2Z3Ri9ZQVYvZjM1L2Z3QmdDSDkvZjM5L2YzOS9BR0FBQVg5Z0EzOS9mUUJnQW45L0FYNWdCMzkvZjM5L2YzOEFZQUYvQVgxZ0EzOS9mZ0JnQjM5L2YzOS9mMzhCZjJBRWYzMS9md0JnQTM5L2Z3RjlZQUFBWUFOL2YzNEJmbUFDZjM4QmZHQUZmMzUrZm40QVlBTi9mSDhBWUExL2YzOS9mMzkvZjM5L2YzOS9BR0FGZjM5L2YzNEJmMkFFZjM5K2Z3RitZQUovZkFCZ0JIOS9mMzhCZm1BR2YzOS9mMzUvQUdBRmYzOS9mM3dCZjJBQmZBRjhZQUY5QVgxZ0JYOTlmMzk5QUdBRWYzOS9mUUJnQW45K0FHQUVmMzkvZmdGL1lBcC9mMzkvZjM5L2YzOS9BR0FMZjM5L2YzOS9mMzkvZjM4QVlBZC9mWDkvZjM5OUFHQUVmMzUrZndCZ0FuOStBWDlnREg5L2YzOS9mMzkvZjM5L2Z3Ri9ZQVIvZjMxL0FHQUtmMzkvZjM5L2YzOS9md0YvWUFOL2YzOEJmR0FFZlg5L2Z3QmdBbjEvQUdBSGYzOS9mMzkrZmdGL1lBWi9mMzkvZm40QmYyQUNmMzBCZjJBQmZ3RjhZQU4vZjN3QVlBNS9mMzkvZjM5L2YzOS9mMzkvZndCZ0JYOTlmMzkvQUdBQmZBRjlZQUo4ZkFGOFlBSjhmd0Y4WUFWL2YzOS9md0Y5WUFOL2ZuOEJmMkFDZm44QmYyQUVmbjkvZndGK1lBVi9mMzk5ZndCZ0JuOThmMzkvZndGL1lBTitmMzhCZm1BRWYzOStmZ0JnRDM5L2YzOS9mMzkvZjM5L2YzOS9md0JnQzM5L2YzOS9mMzkvZjM5L0FYOWdBMzk5ZndGL1lBSi9mQUYvWUFSL2ZYOTlBR0FDZlgwQmZXQUNmbjRCZjJBRGYzOS9BWDVnQW41K0FYNWdCSDUrZm40QmYyQUdmMzEvZjM5OUFHQUdmMzkvZlg5L0FYOWdCMzEvZjM5L2YzMEFZQU44Zkg4QmZHQURmMzUvQUdBS2YzOS9mWDkvZjM5L2Z3QmdESDkvZjM5OWYzOS9mMzEvZndCZ0JYOS9mMzkvQVh4Z0JIOThmMzhBWUFWL2YzMTlmUUYvWUFkL2ZIOS9mM3gvQUdBSmYzOS9mSDkvZjN4L0FHQUZmM3gvZjN3QVlBUi9mM3gvQUdBQ2YzMEJmV0FEZm41K0FYOWdBbjUrQVh4Z0JIOS9mMzRCZm1BSGYzOS9mMzkrZndCZ0IzOS9mMzkvZlgwQVlBVi9mMzkvZkFCZ0IzNS9mMzkvZjM4QVlBTitmMzhCZjJBRWYzOStmd0JnQlg5L2YzOTlBR0FIZjM5L2YzMS9md0JnQkg5K2YzOEJmMkFDZm40QmZXQUNmSDhCZjJBQ2ZYOEJmMkFDZlg4QmZXQUlmMzkvZjM5K2YzOEJmMkFFZjM5K2Z3Ri9ZQUorZndGK1lBNS9mMzkvZjM5OWYzOS9mMzEvZndCZ0JYOS9mM3g4QUdBTWYzOS9mMzkvZjM5L2YzOS9BR0FHZjM5L2ZYOS9BR0FGZjM5L2ZYMEFZQVIvZjM5L0FYMWdCSDkvZjM4QmZHQUVmM3gvZkFCZ0JIOS9mSDhCZjJBSGYzOS9mMzE5ZndCZ0MzOS9mMzkvZkg5L2YzOS9BR0FGZjM5OWYzOEFZQWwvZjM5L2YzOS9mMzhCZjJBRGYzOTlBWDlnQkg5L2ZYOEJmd0xQQkZ3QllRRmhBQWdCWVFGaUFBRUJZUUZqQUFZQllRRmtBQ0lCWVFGbEFBSUJZUUZtQUFRQllRRm5BQUFCWVFGb0FDQUJZUUZwQUFRQllRRnFBQVVCWVFGckFBd0JZUUZzQUJZQllRRnRBQUFCWVFGdUFBQUJZUUZ2QUF3QllRRndBQUVCWVFGeEFBQUJZUUZ5QUNVQllRRnpBQUVCWVFGMEFBWUJZUUYxQUJNQllRRjJBQ0lCWVFGM0FBWUJZUUY0QUFnQllRRjVBQUlCWVFGNkFBZ0JZUUZCQUFRQllRRkNBQUFCWVFGREFBZ0JZUUZFQUFVQllRRkZBQWdCWVFGR0FBSUJZUUZIQUFJQllRRklBQVFCWVFGSkFBTUJZUUZLQUJNQllRRkxBQm9CWVFGTUFBb0JZUUZOQUJvQllRRk9BQUVCWVFGUEFBVUJZUUZRQUFBQllRRlJBQW9CWVFGU0FBSUJZUUZUQUFJQllRRlVBQUlCWVFGVkFBSUJZUUZXQUJBQllRRlhBQUlCWVFGWUFCY0JZUUZaQUJjQllRRmFBQVVCWVFGZkFBVUJZUUVrQUFBQllRSmhZUUFBQVdFQ1ltRUFCUUZoQW1OaEFBSUJZUUprWVFBRkFXRUNaV0VBQWdGaEFtWmhBQWdCWVFKbllRQUFBV0VDYUdFQUJRRmhBbWxoQUFJQllRSnFZUUFJQVdFQ2EyRUFBZ0ZoQW14aEFBZ0JZUUp0WVFBSUFXRUNibUVBQWdGaEFtOWhBQUlCWVFKd1lRQUZBV0VDY1dFQUJRRmhBbkpoQUFBQllRSnpZUUFDQVdFQ2RHRUFBd0ZoQW5WaEFBd0JZUUoyWVFBREFXRUNkMkVBQ2dGaEFuaGhBQW9CWVFKNVlRQUFBV0VDZW1FQUFnRmhBa0ZoQUFBQllRSkNZUUFYQVdFQ1EyRUFCUUZoQWtSaEFBQUJZUUpGWVFBaUFXRUNSbUVBQWdGaEFrZGhBQmNCWVFKSVlRQUNBV0VDU1dFQUJBRmhBa3BoQUFFQllRSkxZUUFGQVdFQ1RHRUFDQU9zSWFBaEFRQUZCZ1VDQ2dZZ0JRRUJBUUVGQWdBREFBSUVBUU1CQVFJQ0RRUUZCUUlGQkFRRkJRTUFBQVEvQUFFQUVBUUVBd0lBQXdVQkJRVUNEQUlFTEFJYUF3UlNCUU1EQkFNZ0FRUUVBUUFBQWdFWUFqSUFEQU1EQXdBRENBQUNDZ1VGQXdNREF3TUFMU1VPQWdFQ0Z3UURBVE0wQkFBbE13TWVJd1VnQkNJTUJnSUZBZ1FBQVFNRURnQUZCQXdFRWdRREF3QUdBMU1ERGdZQ0JCa0FCQTRBQXc4RUFRTUNBQUFDQUFRRkFsUUNBZ0VCQkFRR0FBSURCZ1VEQUFBRUF3SUFCUVJBQWdRQUtBSUlBUU1qQUMwc0JCNEJCZ1FERGk0Q0FRSUFBd0FBQXdvR0FqVUNBZ0lEQXdRREF3SURBd0VCQVFBVEFnQUNCQU1QRHc0RENRTUNFQUFGREFjV0ZnUlZBeVFEQVFRSkN3SUNBZ1VqQUFVUUJBQUdHd0VEQmdNSkFVRUNBUUEyQlFBREFEY0RCaFpDQkFJQ0FnRUVCUmdEQXdRQkFnRU1CZ1lHQXdNREF3UUlBd0FEQXdNQkJBQWdBd2daQ0FCRER3TUVCQzRERWdNQkFnWURMeThFQWdKV01BSkVSRVVDVndNQ0FnSUNBZ01FQkFNQkJBNENBd0VHQWcwQ0FnUURDZ29JQUNnc0JRVURKQXdCQVFFQ0F3NFlBeUlDQVFNYkF5UWtCZ0FFQlFVREF3QUNCVVlCQkFJVUZCQUNBZ2dDQkVjSUNBVUJFd01RQkFRREFnTUFCZ0FEQXdVQ0FBRUFCZ0FBQUFNQUJnQUlGd01EQXdnQ0JBUU1Bd1VDR3hzQkJBRUZBUU1BQmpRT0F3TWVCQU1EQlFVRkFBSVREUU1BQlFVREFsZzFCUzFJQlFBREJRMENBQUlERHdJR0JSTUNCUUlDQVFJRUF3RTRBUklDQkFFR0Jnd0RPQUlDQUFNdkFRTURBQUFFQXhZRkJRVUNBd1E1QURrQUF3VUZBQ3dFU1FnQUFnQUFCUVVCQlFnQUFnTUJBUXdXUWdZSUFBTURCQVFCQkFJREFnVUREUXNCQWdVRkFBTURBd1VFQkNnREExa0ZFQVFEQlFNRkx3VUZCRm9HQlFNT0dBUUVXd1lEQmdNQUFBTUJDZ29DQUFRREFnQUJBUUlCQkFNTUFRQUFBd01EQXdRQ0FBUURBQWRjUlMwSUFnUmRCQWdHQkFJSUFnQUVEUWdEQTBrRkJBTmVYMkJoQXdBQVlnWUNCQUVDQWdVQ0JBQUFBQVFBQTBvR0JBUUJBUVVEQXdNa0FRRU9BelFDQUFNQkFBZ0lCUU1EQWc0QUFDZ2VHQUVEQmdFQUJBQURCUVVGQlFVRkJRVURBZ0lJQWdnQkF3UUVBUU1BQXcwRERBRURCUVFEQUFFQkJBRUJBUUVBQXd3Q0FnTURBZ01BQkFRQUFBQUFBQUFDQWdVQUFBTWFCUm9kSFFBQUFnQUFBZ1VBQWdVQUFnVUlCZ2dEQkFnSUFBQU5CUUFDQ0FFR0F3TURBQUFYQlFjaEJBSUZCbU5rT2dNaUJnWUJBQUlEQkFRQkJnRURBd3NDQVFZREJBTUNBQUlGQ0FNRUFnVUdBZ01PQWdRQUF3TUVEZ1FEQWdNRFpVRm1ad1FPQXg0TUJBSUVBZ05MQUFNRUF3SURReVFTQkFNREFnTURBd01EQ2dRREFBZ0dBUXdGQlFNREJBQUtBUU1BQXdNQkJRTUVCQWdHQXdJRkFBTUJBUUFEQXdNQUJBQUNBQUlCQUFNQUFnUUNBd0FBQUFBQUFnRUJBUUVCQVFFRkJRRVRCZ1FBQUFFREFBUUFBd2dCQXdNRkFnQURBd2tLQ0FvSUNnZ0FBQUFCQkFJQkFRRUFBZ0VBQ0FBRkNnRUFBd1UzREFVM0RDa0RBUU1YQXhjQUFTTm9hUUFHYWdJQ0FBSUVIUW9BQUFBSUFnVUNFQU1BQUFBRmF3VUNCeWtJQ2dZQ0FBQUNDQkF4Q0FVRkNBZ0hCUUlJQVFJQkFnSUlCQWdEQVFFTUdRZHNCaG9NQXdRTURBTUFBd01EQndNQ0V3SUVBd01LQkFFTUJFc2FGZ3dDQXdVR0JRTUVCQVFFQmdNQUJRTUVBd29JQkFBSUFRRUJBQUlJQUFrRENnZ0tDQVFCQXdBRUZ3d0RBdzRPQXdBQ0NnZ0RCQUFEQXdFR0F3RUJHam9BQVFNRUxnQnRDZ2dFQXlRRkVnUURBd01mQXdvSUJBTUVCQWdHQXdJQkNnZ0VCUUFEQVFvSUJBWURCQW9JQXdBRGJnTnZHUUViQWdNQ0czQUVCUU1BQXdFR0JnWkhBM0VGQVFFRUNnZ0VBQzRZQkFRREF3UUVCQU1LQ0FRRUFnb0VDZ1FEQXdvSEFnTURBd01EQXdNQklBd1dCUXdBRmdZTUZnRU1CZ01NRmd3V0FBd0VGZzBBREFRV0JBQURCUVVHQXdZR0F3TUJBZ1VEQkFBQUFBQUFBQUFNQWdNRUFnSUNBd0FxQndFSEEzSUFBRW9YS2dRREJFMEVCQVFCQUFBQUFBQUFBQVFCQVFBSkFBWUNCZ3dDRmdZQUJnWUNEQVlDQXdBRkZnVUdBdzBBQUFFTUJnRUFBQUFBQUFBQUJBRUJBQU1CQUFBQUFBQUFBQU1BQUFFRkFBQUFBd0FBQUFBQUFBUVdjMDRBSXdJQ0JnRUJBQU1EQkFNRUFBVURBd01CQkFFQUFRd1dCQU1FQkFRR0FBSUNBQUlCQWdFRUJBSUNBZzBCQVFFQkFRQXdBd0VBQUFBR0ZRVUJBQUFBQXdFREJBSUNGd0VDQkFBQUFnQUtBaFFDQUFJQUFnQUFBUUVBVHpKUE1nSUFBQU5RQXdJQUtnQUVBMUFEQXdNVERCTVREQk1UR2dVREdnSUFBaEFDQlFZNkh5a0lFQWdwQ0FRRUJDa0lBUUlGQTNRaklnSVpCalVqQWdNQ0JRQUNkVVlLZG5jS0FBc0xCUVlBQkJ4SUJBZ0NBZ0VCQVFFQkFTQURCUVFBQWdVQ0FBZ0lBQmNFQ0FnRGVBRUJBQU1FQ2dJRkFBQUFCUVVDQWdJQUFnaE9BQkFBZVFVRkNnTUNBQVVEQXdnRkJRVUNBZ0lDQlFnQ0FRQUZBUWdGQWdjRUFnSUZCQUVDQUJnQUVRSURBd01JQUFBQUJBUUlDZ01CQWdJQUFBRUJBd01BZWswSUFnSWxEek1hZXdrR2ZBOE1BQ1VsRmhZTWZSb2FDQVlNREF3RkFBd0NCQWNCQXdJR0FRQUNBQUVFQkFjSEJRRVREQVk3T3pzQ0FBQUJBQU1UREJvRFBINE1CaGNNQmdFQkF3SUVCUU1FS2d3Q0JRTURCZ1VHQXdJREJBY0lCQVVCQ0FNREF3RUJCQU1EQkFFREF3UUVCQU1EQWdJRUF3d1RBd01DQXdZR0F3TURBd01DQXdNRkJBUUVBd0lER2dRREF3TURBd1FEQmdRSUFBTURBd0lBQXdJQ0F3b0dBd1FEQkFRQUJBQUVBd1FBQUFJQ0FBSUVBQUFBQXdNQkF3RURBZzhEQXdNQUZ3RUVBQU1PQXdCL0F3UUlFZzRDSGdRZUJJQUJBd01FQXdRQUFBRURCZ1lEQXdNRGdRRS9LQUVFZ2dFRFFBTURBd01EQkFJQkhnTURHQU1EQkFFT0F3TUFBeDhNQ0FJQ0JBTURBd01EQXdNREJnTURCZ01CQW9NQkFnWUNBd0FBQUFBQUFBQUNoQUVDQlFNQUFRRUJDandDQXdNaUJBTUNBZ0lEQVFRREFnTUFBQUFBR3dRRkJnQUJDQUVBQVFFQ0JBQUJBd01hT0R3QUFBTUJEZ0VHQVFNQUFpb0RCUUVIQXdJSEF3SUVBUVFEQXdRRUF4NERDZ01DaFFFRGhnRWVBZ01FQVFNQkF3TURBd1FBQlFNQUFnZ0NBZ01EQkFBREFRWUFBZ0lLQWdNREJnSURCUUlNQ2dNRERBQUZBUVFEQUFNREF3TUdEQU1XQWdFQUJRTUFBUUFCQUFFQ0FnRUFCQVVEQUFFQUFRQUJBZ0lCQUFVREFBRUFBUUFCQWdJQkFBVURBQUVBQVFBQUFnRUNBZ0VBQlFNQUFRRUFBUUlDQVFBRkF3QUNBUUVBQVFJQ0FRQUZBd0FCQUFFQURRRUFBQUlEQWdFREFnUUJBQUFDQUFJQUFRQUVBQU1BQVFBQkFBTUNCQUVCQUFFQkFRQUVBd01BQUFRREF3UUJBd1FFQXdBUkJBTUNCUUlCQUFFREFRQUFBUUVCQUFRREF3QUFCQU1EQkFFREJBUURFUU1DQlFJQkFRQUJBQUFCQUFBQUFBQUJBQUVCQUFFQUJBTUNBZ0lDQkFFQkFBRUFBUUFFQXdJQ0FnSUpBUUFBQWdrREFBRUJBQWtCQXdBQkFRQUJBQUlEQWdFQUFBQUJBQUFCQUFBQkFBQUJBQUFBQUFFQUFBQUJBQUFBQUFFQUFBQUJBQUFCQUFBQUFRQUFBQUFCQUFBQUFRQUFBQUVBQUFBQUFRQUFBQUFCQUFBQUFRQUFBUUVBQVFrRkJnTUFPWWNCSFJBUUNBd0dBUVVLR2dnQ0V3b0NFeE1UREF3TUFBVUdCZ1lGQlFFREFBRUJBQUFnQUFZQkFBQUNCUU1DQlFNQ0FBQURBZ0FBQXdFQkJ3RUFBUUFCQUFFQUFRQUJBQUVHQVFNQUJoVUZBZ0FDQUFFVkFBSUNBQUVCQUFJQUF3d0ZBQUlGQVFVQUFRVUJBUUFCQUFFQUFRQUJBQUVBQVFBQkFBRUFBUUFCQUFFQUFRQUJBd0FEQXdNREF3TUFBQUlCQVFvVUZBb1VGQUFLQUFvVUZBRUtDZ1VJQlFJRkFnRUtCUWdGQWdVQ0NRZ0lDQVVCQVFFQkV4TVFBVDBRUFFBZEhSMGRBQjBkRkFFUUVCQVFFQlFBRUJBUUVCQUtBUmMrS3lZS0pnRUtDZ28rS3lZS0pnb0JDaEFRRUFBUUVCQVFCQkFRQXhBUUVBTVFFQkFBRUJBQUVBVUVBQVlLQlFZS0F3VUVCQUFFQUFVRkJBUUJBeGNYRndRWEJBTVJBUU1GQUFOTUFnY0ZCUVVDQUFFQUF3VWhBU0VEQUFJRk1Sa0ZCUVVGQlFVSUNBZ0lDQWdJQ0FnSUNBSUNBZ0lBQUFJQ0FBQUFDQUVDQlFJRkFBQUFDQUlDQVFNQUFBZ0NCUUVBQndBQ0JRSUFBUUFBQndBSUFBVUNCQUlDQUFBSUFnVUNBQUFJQWdVQ0FBQUlBZ1VDQWdJS0NnQUtDZ0FBQ0FJRkFnUURBQUFJQWdVREFnQUFDQUlDQUFNRUFBQUFBZ0lDQUFFQ0FnQW5CUUloQlFNQUFnMEFBQUFDQ0FBWkFnSUFBQVFFQWdFREFRUUJBUUlBQWdBRUFnRUNCQUlCQXhFQkFnRUZCUVVGQlFVRkFnVURBZ29kQlFBTEFBSUFBd0FaR1FBQkFqWUNNQmtjQXdNQkFRRUJBUUVCQVFBQkNBRUdCZ1lHQ1FnQkJnWUJBQUFBQlFFQUFBVUFBQVVCQUFBQUJRSUNBQUFHRlFVREFBRUJHd0VFQUFJQkJBQUNBQUVBQUFBQUFBTUJBQVVEQVFRRUFBTURBd0FKRGhJT0Nnb0dCQVFFRHdjSUF3TURBUUFBQUFBQUF3UUVBQW9LQmdRRUJBOFNEZ0VHQ0FNREFRQUFBd0VBQXdFRUJBQURBd01BQ1E0U0Rnb0tCZ1FFQkE4SUF3TUFBQVFCQUFBZkFnQUNBUU1BQVFBQkFRQUNBUUFBQVFFQUNBRUFBUUFCQUFJQkFnQUJBQWtBQkFBQUF3a0NCQWdFQUFRSkNRUUlBd1FBQXdrRUJBQUVBQVFEQkFBRUJBQUVBd1FBQkFBRUF3QUVDUUlBQkFNQUF3QURBQU9JQVFNUEFRQUFBd0FBQXdBREFBQUFBd0VBQXdBRUFRQURBQUVBQXdBQkFBRURBUUFEQUFFQUF3QUJBQU1BQUFNRUJBb0RBd0FFQkE4SUF3UUVDZ01FQUFRRUR3Z0RBd0FFQkFnREFRQURDUklPQUFRRUJBOElBeElPQVE4SUNnTUFBd01FQkFRRUR3Z0tVUW9HQkFRREJBUUVCQUFQQ0FZS0F3b0VCQkVFQkFNUENBb0VCQW9HQVFBREFBUUFBd0FBQUFNQkVnNEVBd1FHRHdnREF3OElBd1FFQXdFQUF3RUFBQU1DQVFBQUF3QUFBd0VBQUFNREF3TUpEZ0VTRGdRRUR3Z0RBd0FEQXdPSkFRQUpEZ0VTRGdRRUR3Z0RBd0FCQXdNUENBTURDUTRTRGdFQUF3UUVBQUFEQkFRUENBTUJBQUFEQXdBT0FBa0VCQVVQRWc0SUF3TUFBQUlCQUFBREFRQURBQUVBQUFBREFRQURBUUFBQXdZQkFBQURBUUFEQVFjQUFBTUFBQU1EQVFBQkF3RUFBd0VBQXdFQUFBTUJBQU1CQUFNQUFBTUFBQU1CQUFNQkFBQUFBd0VBQXdZQkFRQURBQUFEQUFNQUF3TUFBQU1BQXdBQUF3OElBd1FFQXdNQUF4TUpBd01BQVE0T0RoSU9BdzhFQVFRSUFBQUFBd1FFQXdnQUFRTUFCZ0FEQXdRRUJBUUFEd2dEQXdRRUFBOElBd01QQ0FZUENBZ0VCQUFEQkFRQUR3Z0RBUU1EQ1FNRERoSU9BQThJQXdRREJBRURFZ0VHQUFNRUF3UUJBd01BQXdrT0VnNEFCQVFQQ0FNUENBTURDUTRTRGdRRUF3TUVCQThJQUFNSkFBTVNBQVFFRHdRSUF3a0FFZ01EQkFRSkVnOElBd01BQVFRQUFRTURCQVFFRHdnRENRQURFZ01EQUFRRUR3UUlBd2tBQVFRU0JBWVBDQUFHRHdnU0RnRVBBd01EQkFRRUJBTUREd1lQQVFnRUJBOElBd1FFRHdnREFnTURBQVFFRHdnREFBTUFBd0FPR3dFT0RnTUJDZ1lCQXdRRUVnNERBQUVLQmdFQUFRQUJBQU1CQUFFQkFBZ0pBQUFCQUFBQ0FnQUJBUUFKQUFNQUFRQUFBUUFEQWdjSkFRQUFBUUlCQVFNQkFBQUJBd0lDQUFJRkFnQUNBQUlCQVFBQUd3SUFBQUVCQVFJQUFBRUFBQUlBQkFRRUJBUUVBUUFFQVFFU0JBQUNBQUVTQkFBQkFBSUFBUklFQUFJQUFSc0VBd0lBQUFRQkFBRVNCQnNDQUFFQUFRQUNBd0VDQlFFQUFRRUJBQU1FQkFNREFBQUVBd01FQVFBREJBUURBQkVZQXdFQ0FnVUNCd0VBQUFFQkFnRUFBQUlEQWdJQkFBUUFBd0VCQUFBRUFRQUNBQUVCQUFJRUNBTUZBZ0lKQVFBQ0NRUUVBUUFCQVFBQUFnSUJBZ0VDQUFFQUFnRUJBUUFFQVFBQkFRQUJBQUFDQWdFQUFnVUVCUUlKQUEwQkFBQUNBQU1DQWdFQUFRQUJBUUFFQXdVQ0FnSUNDUUFCQVFBQkFBQUNCQU1GQWdJQ0FBSUpBQUVBQUFNQ0FBSUFBUUlDQVFBRkF3QUJBQUVBQVFJQUJBY0JjQUdvR0tnWUJRY0JBWUFDZ0lBQ0Jna0Jmd0ZCZ1Bqa0Fnc0hvQUViQWsxaEFnQUNUbUVBdEFzQ1QyRUFqZ0VDVUdFQkFBSlJZUUJjQWxKaEFJRVhBbE5oQUpNWEFsUmhBSXNPQWxWaEFQOFdBbFpoQVA0V0FsZGhBUDBXQWxoaEFQWVVBbGxoQVBVVUFscGhBUFFVQWw5aEFQTVVBaVJoQVBJVUFtRmlBUEVVQW1KaUFQQVVBbU5pQU84VUFtUmlBTzBVQW1WaUFPd1VBbVppQU9zVUFtZGlBT29VQW1oaUFPa1VBbWxpQU9nVUFtcGlBT2NVQW10aUFPWVVDZEF3QVFCQkFRdW5HTDhRL1JqakZNWVZ2eERrQWVRQmpoVGVFK2dMOGhMN0liY2gvU0NvQStnTG1RTE5JS1FncUFQcEg4NGZ4QitvQTUwZndCN2lIWVVkb3h6RUc5c2FvQnFKR29BYXJ4bjhHT29ZdkJpQ0dNZ1htUmVGRitvV3ZoYnNDTzBJbWg2SEh1d2g2eUhxSWVraDZDR29BNWtDb0JXRkZjZ2h3Q0dZSVpBaGh5SGtBWWNCNlNEaElOZ2d6Q0RESU1JZ3dDQy9JTDRndlNDa0E3QWdveUNaQXNNUmxTRC9IL3dmK0IveEgrb2ZtUUxERWVnZjV4L0ZCS0lSeFFUZEg5VWYxQi9RSDg4ZnpSLzdFTWdmbVFMNkVQWVF4eC9HSDhrS3hSL0RINWtDeEFyQUNzSWZ3Ui9BSC9zUXZ4K1pBdm9ROWhDN0g3RWZxQitjSDVFZmh4LzlIdllleFFTS0dxb2Rod1dzRUtzUXFSQ29FUHNjOUFMZEhOUWN2Z1NYQXBZQ3lnV2hFUFlFeVFXRkhQRWI1aHZYRzg0YnVSdXVHNWtiamh2Nkd1OGE1QnJhR3RNYTBockxHc0FhdFJxc0dxTWFvaHIrQWZZRWh3R2VDcFVheEFYREJZMGFqQnFMR3NZQml4V3pCcklHeGdHWEFwWUN2UVdaQXVJQ3hnSEZCT1FCaHdHdkQ2MFA3Z09rQSswRHVBVzNCZUlDK3dtckZzWUJod1dzRUtzUXFSQ29FTVFaOUFLekJySUdsd0tXQXZZRXZRV1pBdUlDd3hQR0FZY0ZvQStjRDlzSG1BLzBDZlFDc3dheUJwY0NsZ0wyQkwwRm1RTGlBc1VFa1EvN0dQVVk0U0gwR1BNWThoaUhCZjBPOXc3MkR0c0g1Z24wQXRzWTF4aStCSmNDbGdMS0JlVU85Z1RKQmRRWTB4alpEc1lZMkE2MUdMRVkwUTZpR0prWWtSaVFHSWdZZ1JqNEYrOFh2UTY4RHQ4WDNCZldGLzRCaHdITENjNFh4QVhEQmNjWHd4ZThGOFlCc3dheUJzWUJsd0tXQXIwRm1RTGlBc1lCeFFUa0FZY0JrdzZQRHU0RHBBUHRBN2dGdHdYaUFvd09raGVRRjQ4WHZnU1hBcFlDeWdXaEVNa0ZpeGVHRjZFRmhCZndEWU1YZ2hlQUYvd1dwZ242RnFNSjhCYnBGdVlXNHhiZkZ0c1cyQmJURnM0Vy9nR0hBWllKeEJiRUJjTUZ2UmEyRnE4V3hnSEdBZVFCaHdHdkQ2MFA3Z09rQSswRHVBVzNCZUlDK3dtbUZxSVdxQTJXRnFNTm9RMmVEZVlKOUFMMkZaY0NsZ0xzRlpzTm1nMlBEYzRWeVJXT0NjVVZ3eFc4RmJjVnJoWFBBZjRNbXdMOUNQa0lrQlgvQmZFTS93V1BGWTRWb2hHTUZZUVYvZ0dIQWYwVTdoVHFBdGNFNVJUa0ZPSVVqZ1hoRktrRXhnSG1DT0FVM3hUZUZOMFVod0hjRklvSHhReUtCOXNVMmhUeEROZ1VpUWZaRklrSDF4VFdGTlVVMUJTSUI5TVVpQWZTRk5FVTBCVFBGSWNIemhTSEI4MFV6QlRMRkp3VWhRZktGSVVIeVJUSUZNUU14eFRsQ01ZVTVRakZGTVFVd3hUQ0ZPUUl3UlRrQ01BVXZ4UytGT1lUK3dXOUZQc0Z2QlM3Rk1FTTVSUGpDTG9VdVJTNEZMY1U1QlBpQ0xZVXRSUzBGTE1Vc2hUaENMRVVzQlN2Rks0VWt4UGdDSzBVckJTckZLb1VxQlRmQ0trVXB4U21GS1VVbXhTRUI4QU1oQWVrRktNVXhReWlGTGNNZ3dlM0RLRVVvQlMxREo4VXRBeTFETFFNbmhTZEZNQU1pZ2VKQjRnSGh3ZUZCNFFIbWhTWkZKZ1VoUVNYRkpZVWhBU1ZGSlFVendIZEEvMEkzQU9URkpJVS9nR0hBYVlNa1JUcUFxUU1rQlNQRko4TW5neU5GSXdVaXhUK0FZY0JsZ3lLRk9vQ3BBeUpGSWdVbnd5ZURJY1V4Z0hrQVljQnFBU0dGSWNCNUFHSEFZVVVwQVB1QSswRGhCU0RGSTRNZ2hTQkZJQVUveFBtQ2ZRQy9oT1hBcFlDL1JQOEUvc1QraFArQVljQitSUDRFK29DK3diR0FmY1Q5aE9NRE5JSWl3eUtETjhUOVJPT0RQUVQ4eFB5RS9FVDlBbjBBdkFUbHdLV0F1OFQ3aFB0RSt3VC9nR0hBZXNUNmhQcUF2c0d1QUxwRThRRnd3WG9FK2NUL3dYN0JlTUk0Z2poQ09BSTN3ampFOUVJd1F6UkNPSVQ0UlBnRThZQjNSUGNFNHdNMGdpTERJb00yeFBhRTlrVHZnU1hBcFlDeWdYL0M4a0YyQlBYRS80TDFoUE5DTlVUMUJQVEU5SVQwUlBRRTg4VHpoUE5FOHdUeXhQS0U4a1R5QlBIRThZVC9nR0hBY3NJeFJQRUU4WUJ4Z0hrQVljQjlndjFDKzREcEFQdEE3Z0Z0d1hpQXNvSXdoUEJFOGtLd0JPL0U1a0N4QXJBQ3I0VHZST0hCYUFQbkEvYkI1Z1A4Z3YwQXJ3VHV4TytCSmNDbGdMS0JmOEw5Z1RKQmJvVHVSTzRFN2NUdGhPMUU3UVRzeE95RTdFVHNCT3ZFNjRUclJPc0U2c1RxaE9wRTZnVHB4T21FLzRCaHdISENLVVR4QVhEQmFRVG94T2lFOFlCc3dheUJzWUJsd0tXQXIwRm1RTGlBc1lCeFFUa0FZY0I5Z3YxQys0RHBBUHRBN2dGdHdYaUFzb0lrUk9oRSs0TG9CUHNDK3NMNmd2eUMvUUNueE9YQXBZQ25oUHBDNTBUbkJQK0FZY0JteE9hRStvQyt3YVpFNWdUbHhPV0U1VVR4Z0h6QlpRVC93WDdCZU1JNGdqaENPQUkzd2pSQ01ZQmh3R29CSkFUaHdIa0FZY0JqeE9rQSs0RDdRT09FNDBUcUEyTUUrd0w2d3ZxQy9RSjlBS0xFNWNDbGdLS0Ura0xtZzNRQzRrVGlCT09DWWNUaGhPRkU0UVRneFBQQVlJVG13TFBDL2tJL3dXQkU0QVQvZ0dIQWY4Uy9oTHFBdGNFL1JMOEV2c1NqZ1hOQzhZQjVnajZFdmtTK0JLRkJPNEY5eEtFQktJRTloTFBBZDBEend2Y0EvVVM5QkwrQVljQnl3dnpFdW9DeWd2eEV2QVM3eEtPQmNnTDdoTHRFdXdTaFFUdUJlc1NoQVNpQk9vU3p3SGRBOXdENlJMb0V2NEJod0hHQytjUzZnTEtDK1lTNVJMa0VvNEZ6UXZqRXVJUzRSS0ZCTzRGNEJLRUJLSUUzeExQQWQwRDNBUEdBWWNCcUFUZUVvY0I1QUdIQWQwU3BBUHVBKzBEM0JMYkV2NEJod0hhRXRrUzZnTFhCTmdTMXhMV0VySUlzUWpWRXRRUzB4S0ZCSzhJMGhLRUJLSUUwUkxQQWQwRDNBUFFFczhTL2dHSEFjNFN6UkxxQXRjRXpCTExFc29TamdYSUM4a1N5QkxIRW9VRTdnWEdFb1FFb2dURkVzOEIzUVBjQThRU3d4TCtBWWNCd2hMQkV1b0Mxd1RBRXI4U3ZoS09CYjBTdkJLN0Vyb1NoUVR1QmJrU2hBU2lCTGdTendIZEE5d0R0eEsyRXY0Qmh3RzFFclFTNmdMWEJMTVNzaEt4RXJJSXNRaXdFcThTcmhLRkJLOEkraUdFQktJRStTSFBBZDBEM0FQNElmY2gvZ0dIQWZZaDlTSHFBdGNFOUNIeklmSWhzZ2l4Q1BFaDhDSHZJWVVFcndqdUlZUUVvZ1R0SWM4QjNRUGNBK2NoNVNIa0llTWg0aUhnSWQ4aHFndjBBdDRoM1NHK0JKY0NsZ0xjSWRzaDJpSFpJZGdoMXlIK0FZY0IxaUhWSWVZaDFDSFRJZEloMFNIUUljOGhxZ3YwQXM0aHpTRytCSmNDbGdMTUljc2hvQkxHQWNZQnlpSEpJZjRCaHdISEljWWh4Z0hHQWNVaHhDSERJY0lod1NHL0liNGh2U0c4SWRRRXV5RzZJYmtodUNHMkliVWh0Q0d6SWJJaHNTR09DWjBTc0NHdklhNGhyU0hQ