UNPKG

vosk-browser

Version:

Kaldi in-browser speech recognition based on a WASM build of the Vosk library

542 lines (440 loc) 5.8 MB
(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