UNPKG

@tomo-inc/ledger-bitcoin-babylon

Version:

Ledger Hardware Wallet Babylon Application Client

269 lines 23.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ClientCommandInterpreter = exports.GetMoreElementsCommand = exports.GetMerkleLeafIndexCommand = exports.GetMerkleLeafProofCommand = exports.GetPreimageCommand = exports.YieldCommand = void 0; const bitcoinjs_lib_1 = require("bitcoinjs-lib"); const buffertools_1 = require("./buffertools"); const merkle_1 = require("./merkle"); const varint_1 = require("./varint"); var ClientCommandCode; (function (ClientCommandCode) { ClientCommandCode[ClientCommandCode["YIELD"] = 16] = "YIELD"; ClientCommandCode[ClientCommandCode["GET_PREIMAGE"] = 64] = "GET_PREIMAGE"; ClientCommandCode[ClientCommandCode["GET_MERKLE_LEAF_PROOF"] = 65] = "GET_MERKLE_LEAF_PROOF"; ClientCommandCode[ClientCommandCode["GET_MERKLE_LEAF_INDEX"] = 66] = "GET_MERKLE_LEAF_INDEX"; ClientCommandCode[ClientCommandCode["GET_MORE_ELEMENTS"] = 160] = "GET_MORE_ELEMENTS"; })(ClientCommandCode || (ClientCommandCode = {})); class ClientCommand { } class YieldCommand extends ClientCommand { constructor(results, progressCallback) { super(); this.progressCallback = progressCallback; this.code = ClientCommandCode.YIELD; this.results = results; } execute(request) { this.results.push(Buffer.from(request.subarray(1))); if (this.progressCallback) { this.progressCallback(); } return Buffer.from(''); } } exports.YieldCommand = YieldCommand; class GetPreimageCommand extends ClientCommand { constructor(known_preimages, queue) { super(); this.code = ClientCommandCode.GET_PREIMAGE; this.known_preimages = known_preimages; this.queue = queue; } execute(request) { const req = Buffer.from(request.subarray(1)); // we expect no more data to read if (req.length != 1 + 32) { throw new Error('Invalid request, unexpected trailing data'); } if (req[0] != 0) { throw new Error('Unsupported request, the first byte should be 0'); } // read the hash const hash = Buffer.alloc(32); for (let i = 0; i < 32; i++) { hash[i] = req[1 + i]; } const req_hash_hex = hash.toString('hex'); const known_preimage = this.known_preimages.get(req_hash_hex); if (known_preimage != undefined) { const preimage_len_varint = (0, varint_1.createVarint)(known_preimage.length); // We can send at most 255 - len(preimage_len_out) - 1 bytes in a single message; // the rest will be stored in the queue for GET_MORE_ELEMENTS const max_payload_size = 255 - preimage_len_varint.length - 1; const payload_size = Math.min(max_payload_size, known_preimage.length); if (payload_size < known_preimage.length) { for (let i = payload_size; i < known_preimage.length; i++) { this.queue.push(Buffer.from([known_preimage[i]])); } } return Buffer.concat([ preimage_len_varint, Buffer.from([payload_size]), Buffer.from(known_preimage.subarray(0, payload_size)), ]); } throw Error(`Requested unknown preimage for: ${req_hash_hex}`); } } exports.GetPreimageCommand = GetPreimageCommand; class GetMerkleLeafProofCommand extends ClientCommand { constructor(known_trees, queue) { super(); this.code = ClientCommandCode.GET_MERKLE_LEAF_PROOF; this.known_trees = known_trees; this.queue = queue; } execute(request) { const req = Buffer.from(request.subarray(1)); if (req.length < 32 + 1 + 1) { throw new Error('Invalid request, expected at least 34 bytes'); } const reqBuf = new buffertools_1.BufferReader(req); const hash = reqBuf.readSlice(32); const hash_hex = hash.toString('hex'); let tree_size; let leaf_index; try { tree_size = (0, varint_1.sanitizeBigintToNumber)(reqBuf.readVarInt()); leaf_index = (0, varint_1.sanitizeBigintToNumber)(reqBuf.readVarInt()); } catch (e) { throw new Error("Invalid request, couldn't parse tree_size or leaf_index"); } const mt = this.known_trees.get(hash_hex); if (!mt) { throw Error(`Requested Merkle leaf proof for unknown tree: ${hash_hex}`); } if (leaf_index >= tree_size || mt.size() != tree_size) { throw Error('Invalid index or tree size.'); } if (this.queue.length != 0) { throw Error('This command should not execute when the queue is not empty.'); } const proof = mt.getProof(leaf_index); const n_response_elements = Math.min(Math.floor((255 - 32 - 1 - 1) / 32), proof.length); const n_leftover_elements = proof.length - n_response_elements; // Add to the queue any proof elements that do not fit the response if (n_leftover_elements > 0) { this.queue.push(...proof.slice(-n_leftover_elements)); } return Buffer.concat([ mt.getLeafHash(leaf_index), Buffer.from([proof.length]), Buffer.from([n_response_elements]), ...proof.slice(0, n_response_elements), ]); } } exports.GetMerkleLeafProofCommand = GetMerkleLeafProofCommand; class GetMerkleLeafIndexCommand extends ClientCommand { constructor(known_trees) { super(); this.code = ClientCommandCode.GET_MERKLE_LEAF_INDEX; this.known_trees = known_trees; } execute(request) { const req = Buffer.from(request.subarray(1)); if (req.length != 32 + 32) { throw new Error('Invalid request, unexpected trailing data'); } // read the root hash const root_hash = Buffer.alloc(32); for (let i = 0; i < 32; i++) { root_hash[i] = req.readUInt8(i); } const root_hash_hex = root_hash.toString('hex'); // read the leaf hash const leef_hash = Buffer.alloc(32); for (let i = 0; i < 32; i++) { leef_hash[i] = req.readUInt8(32 + i); } const leef_hash_hex = leef_hash.toString('hex'); const mt = this.known_trees.get(root_hash_hex); if (!mt) { throw Error(`Requested Merkle leaf index for unknown root: ${root_hash_hex}`); } let leaf_index = 0; let found = 0; for (let i = 0; i < mt.size(); i++) { if (mt.getLeafHash(i).toString('hex') == leef_hash_hex) { found = 1; leaf_index = i; break; } } return Buffer.concat([Buffer.from([found]), (0, varint_1.createVarint)(leaf_index)]); } } exports.GetMerkleLeafIndexCommand = GetMerkleLeafIndexCommand; class GetMoreElementsCommand extends ClientCommand { constructor(queue) { super(); this.code = ClientCommandCode.GET_MORE_ELEMENTS; this.queue = queue; } execute(request) { if (request.length != 1) { throw new Error('Invalid request, unexpected trailing data'); } if (this.queue.length === 0) { throw new Error('No elements to get'); } // all elements should have the same length const element_len = this.queue[0].length; if (this.queue.some((el) => el.length != element_len)) { throw new Error('The queue contains elements with different byte length, which is not expected'); } const max_elements = Math.floor(253 / element_len); const n_returned_elements = Math.min(max_elements, this.queue.length); const returned_elements = this.queue.splice(0, n_returned_elements); return Buffer.concat([ Buffer.from([n_returned_elements]), Buffer.from([element_len]), ...returned_elements, ]); } } exports.GetMoreElementsCommand = GetMoreElementsCommand; /** * This class will dispatch a client command coming from the hardware device to * the appropriate client command implementation. Those client commands * typically requests data from a merkle tree or merkelized maps. * * A ClientCommandInterpreter is prepared by adding the merkle trees and * merkelized maps it should be able to serve to the hardware device. This class * doesn't know anything about the semantics of the data it holds, it just * serves merkle data. It doesn't even know in what context it is being * executed, ie SignPsbt, getWalletAddress, etc. * * If the command yelds results to the client, as signPsbt does, the yielded * data will be accessible after the command completed by calling getYielded(), * which will return the yields in the same order as they came in. */ class ClientCommandInterpreter { constructor(progressCallback) { this.roots = new Map(); this.preimages = new Map(); this.yielded = []; this.queue = []; this.commands = new Map(); const commands = [ new YieldCommand(this.yielded, progressCallback), new GetPreimageCommand(this.preimages, this.queue), new GetMerkleLeafIndexCommand(this.roots), new GetMerkleLeafProofCommand(this.roots, this.queue), new GetMoreElementsCommand(this.queue), ]; for (const cmd of commands) { if (this.commands.has(cmd.code)) { throw new Error(`Multiple commands with code ${cmd.code}`); } this.commands.set(cmd.code, cmd); } } getYielded() { return this.yielded; } addKnownPreimage(preimage) { this.preimages.set(bitcoinjs_lib_1.crypto.sha256(preimage).toString('hex'), preimage); } addKnownList(elements) { for (const el of elements) { const preimage = Buffer.concat([Buffer.from([0]), el]); this.addKnownPreimage(preimage); } const mt = new merkle_1.Merkle(elements.map((el) => (0, merkle_1.hashLeaf)(el))); this.roots.set(mt.getRoot().toString('hex'), mt); } addKnownMapping(mm) { this.addKnownList(mm.keys); this.addKnownList(mm.values); } addKnownWalletPolicy(wp) { this.addKnownPreimage(wp.serialize()); this.addKnownList(wp.keys.map((k) => Buffer.from(k, 'ascii'))); this.addKnownPreimage(Buffer.from(wp.descriptorTemplate)); } execute(request) { if (request.length == 0) { throw new Error('Unexpected empty command'); } const cmdCode = request[0]; const cmd = this.commands.get(cmdCode); if (!cmd) { throw new Error(`Unexpected command code ${cmdCode}`); } return cmd.execute(request); } } exports.ClientCommandInterpreter = ClientCommandInterpreter; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpZW50Q29tbWFuZHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGliL2NsaWVudENvbW1hbmRzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLGlEQUF1QztBQUV2QywrQ0FBNkM7QUFDN0MscUNBQTRDO0FBRzVDLHFDQUFnRTtBQUVoRSxJQUFLLGlCQU1KO0FBTkQsV0FBSyxpQkFBaUI7SUFDcEIsNERBQVksQ0FBQTtJQUNaLDBFQUFtQixDQUFBO0lBQ25CLDRGQUE0QixDQUFBO0lBQzVCLDRGQUE0QixDQUFBO0lBQzVCLHFGQUF3QixDQUFBO0FBQzFCLENBQUMsRUFOSSxpQkFBaUIsS0FBakIsaUJBQWlCLFFBTXJCO0FBRUQsTUFBZSxhQUFhO0NBRzNCO0FBRUQsTUFBYSxZQUFhLFNBQVEsYUFBYTtJQUs3QyxZQUNFLE9BQWlCLEVBQ0EsZ0JBQTZCO1FBRTlDLEtBQUssRUFBRSxDQUFDO1FBRlMscUJBQWdCLEdBQWhCLGdCQUFnQixDQUFhO1FBSnZDLFNBQUksR0FBRyxpQkFBaUIsQ0FBQyxLQUFLLENBQUM7UUFPdEMsSUFBSSxDQUFDLE9BQU8sR0FBRyxPQUFPLENBQUM7SUFDekIsQ0FBQztJQUVELE9BQU8sQ0FBQyxPQUFlO1FBQ3JCLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDcEQsSUFBSSxJQUFJLENBQUMsZ0JBQWdCLEVBQUU7WUFDekIsSUFBSSxDQUFDLGdCQUFnQixFQUFFLENBQUM7U0FDekI7UUFDRCxPQUFPLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDekIsQ0FBQztDQUNGO0FBcEJELG9DQW9CQztBQUVELE1BQWEsa0JBQW1CLFNBQVEsYUFBYTtJQU1uRCxZQUFZLGVBQTRDLEVBQUUsS0FBZTtRQUN2RSxLQUFLLEVBQUUsQ0FBQztRQUhELFNBQUksR0FBRyxpQkFBaUIsQ0FBQyxZQUFZLENBQUM7UUFJN0MsSUFBSSxDQUFDLGVBQWUsR0FBRyxlQUFlLENBQUM7UUFDdkMsSUFBSSxDQUFDLEtBQUssR0FBRyxLQUFLLENBQUM7SUFDckIsQ0FBQztJQUVELE9BQU8sQ0FBQyxPQUFlO1FBQ3JCLE1BQU0sR0FBRyxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBRTdDLGlDQUFpQztRQUNqQyxJQUFJLEdBQUcsQ0FBQyxNQUFNLElBQUksQ0FBQyxHQUFHLEVBQUUsRUFBRTtZQUN4QixNQUFNLElBQUksS0FBSyxDQUFDLDJDQUEyQyxDQUFDLENBQUM7U0FDOUQ7UUFFRCxJQUFJLEdBQUcsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEVBQUU7WUFDZixNQUFNLElBQUksS0FBSyxDQUFDLGlEQUFpRCxDQUFDLENBQUM7U0FDcEU7UUFFRCxnQkFBZ0I7UUFDaEIsTUFBTSxJQUFJLEdBQUcsTUFBTSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUM5QixLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsRUFBRSxFQUFFO1lBQzNCLElBQUksQ0FBQyxDQUFDLENBQUMsR0FBRyxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO1NBQ3RCO1FBQ0QsTUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUUxQyxNQUFNLGNBQWMsR0FBRyxJQUFJLENBQUMsZUFBZSxDQUFDLEdBQUcsQ0FBQyxZQUFZLENBQUMsQ0FBQztRQUM5RCxJQUFJLGNBQWMsSUFBSSxTQUFTLEVBQUU7WUFDL0IsTUFBTSxtQkFBbUIsR0FBRyxJQUFBLHFCQUFZLEVBQUMsY0FBYyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBRWhFLGlGQUFpRjtZQUNqRiw2REFBNkQ7WUFDN0QsTUFBTSxnQkFBZ0IsR0FBRyxHQUFHLEdBQUcsbUJBQW1CLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQztZQUU5RCxNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLGdCQUFnQixFQUFFLGNBQWMsQ0FBQyxNQUFNLENBQUMsQ0FBQztZQUV2RSxJQUFJLFlBQVksR0FBRyxjQUFjLENBQUMsTUFBTSxFQUFFO2dCQUN4QyxLQUFLLElBQUksQ0FBQyxHQUFHLFlBQVksRUFBRSxDQUFDLEdBQUcsY0FBYyxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRTtvQkFDekQsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLGNBQWMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztpQkFDbkQ7YUFDRjtZQUVELE9BQU8sTUFBTSxDQUFDLE1BQU0sQ0FBQztnQkFDbkIsbUJBQW1CO2dCQUNuQixNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsWUFBWSxDQUFDLENBQUM7Z0JBQzNCLE1BQU0sQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLFFBQVEsQ0FBQyxDQUFDLEVBQUUsWUFBWSxDQUFDLENBQUM7YUFDdEQsQ0FBQyxDQUFDO1NBQ0o7UUFFRCxNQUFNLEtBQUssQ0FBQyxtQ0FBbUMsWUFBWSxFQUFFLENBQUMsQ0FBQztJQUNqRSxDQUFDO0NBQ0Y7QUF4REQsZ0RBd0RDO0FBRUQsTUFBYSx5QkFBMEIsU0FBUSxhQUFhO0lBTTFELFlBQVksV0FBd0MsRUFBRSxLQUFlO1FBQ25FLEtBQUssRUFBRSxDQUFDO1FBSEQsU0FBSSxHQUFHLGlCQUFpQixDQUFDLHFCQUFxQixDQUFDO1FBSXRELElBQUksQ0FBQyxXQUFXLEdBQUcsV0FBVyxDQUFDO1FBQy9CLElBQUksQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDO0lBQ3JCLENBQUM7SUFFRCxPQUFPLENBQUMsT0FBZTtRQUNyQixNQUFNLEdBQUcsR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUU3QyxJQUFJLEdBQUcsQ0FBQyxNQUFNLEdBQUcsRUFBRSxHQUFHLENBQUMsR0FBRyxDQUFDLEVBQUU7WUFDM0IsTUFBTSxJQUFJLEtBQUssQ0FBQyw2Q0FBNkMsQ0FBQyxDQUFDO1NBQ2hFO1FBRUQsTUFBTSxNQUFNLEdBQUcsSUFBSSwwQkFBWSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ3JDLE1BQU0sSUFBSSxHQUFHLE1BQU0sQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDbEMsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUV0QyxJQUFJLFNBQWlCLENBQUM7UUFDdEIsSUFBSSxVQUFrQixDQUFDO1FBQ3ZCLElBQUk7WUFDRixTQUFTLEdBQUcsSUFBQSwrQkFBc0IsRUFBQyxNQUFNLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQztZQUN4RCxVQUFVLEdBQUcsSUFBQSwrQkFBc0IsRUFBQyxNQUFNLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQztTQUMxRDtRQUFDLE9BQU8sQ0FBQyxFQUFFO1lBQ1YsTUFBTSxJQUFJLEtBQUssQ0FDYix5REFBeUQsQ0FDMUQsQ0FBQztTQUNIO1FBRUQsTUFBTSxFQUFFLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDMUMsSUFBSSxDQUFDLEVBQUUsRUFBRTtZQUNQLE1BQU0sS0FBSyxDQUFDLGlEQUFpRCxRQUFRLEVBQUUsQ0FBQyxDQUFDO1NBQzFFO1FBRUQsSUFBSSxVQUFVLElBQUksU0FBUyxJQUFJLEVBQUUsQ0FBQyxJQUFJLEVBQUUsSUFBSSxTQUFTLEVBQUU7WUFDckQsTUFBTSxLQUFLLENBQUMsNkJBQTZCLENBQUMsQ0FBQztTQUM1QztRQUVELElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLElBQUksQ0FBQyxFQUFFO1lBQzFCLE1BQU0sS0FBSyxDQUNULDhEQUE4RCxDQUMvRCxDQUFDO1NBQ0g7UUFFRCxNQUFNLEtBQUssR0FBRyxFQUFFLENBQUMsUUFBUSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBRXRDLE1BQU0sbUJBQW1CLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FDbEMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLEdBQUcsR0FBRyxFQUFFLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxFQUNuQyxLQUFLLENBQUMsTUFBTSxDQUNiLENBQUM7UUFDRixNQUFNLG1CQUFtQixHQUFHLEtBQUssQ0FBQyxNQUFNLEdBQUcsbUJBQW1CLENBQUM7UUFFL0QsbUVBQW1FO1FBQ25FLElBQUksbUJBQW1CLEdBQUcsQ0FBQyxFQUFFO1lBQzNCLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLEdBQUcsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDLG1CQUFtQixDQUFDLENBQUMsQ0FBQztTQUN2RDtRQUVELE9BQU8sTUFBTSxDQUFDLE1BQU0sQ0FBQztZQUNuQixFQUFFLENBQUMsV0FBVyxDQUFDLFVBQVUsQ0FBQztZQUMxQixNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQzNCLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO1lBQ2xDLEdBQUcsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsbUJBQW1CLENBQUM7U0FDdkMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztDQUNGO0FBckVELDhEQXFFQztBQUVELE1BQWEseUJBQTBCLFNBQVEsYUFBYTtJQUsxRCxZQUFZLFdBQXdDO1FBQ2xELEtBQUssRUFBRSxDQUFDO1FBSEQsU0FBSSxHQUFHLGlCQUFpQixDQUFDLHFCQUFxQixDQUFDO1FBSXRELElBQUksQ0FBQyxXQUFXLEdBQUcsV0FBVyxDQUFDO0lBQ2pDLENBQUM7SUFFRCxPQUFPLENBQUMsT0FBZTtRQUNyQixNQUFNLEdBQUcsR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUU3QyxJQUFJLEdBQUcsQ0FBQyxNQUFNLElBQUksRUFBRSxHQUFHLEVBQUUsRUFBRTtZQUN6QixNQUFNLElBQUksS0FBSyxDQUFDLDJDQUEyQyxDQUFDLENBQUM7U0FDOUQ7UUFFRCxxQkFBcUI7UUFDckIsTUFBTSxTQUFTLEdBQUcsTUFBTSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUNuQyxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsRUFBRSxFQUFFO1lBQzNCLFNBQVMsQ0FBQyxDQUFDLENBQUMsR0FBRyxHQUFHLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDO1NBQ2pDO1FBQ0QsTUFBTSxhQUFhLEdBQUcsU0FBUyxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUVoRCxxQkFBcUI7UUFDckIsTUFBTSxTQUFTLEdBQUcsTUFBTSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUNuQyxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsRUFBRSxFQUFFO1lBQzNCLFNBQVMsQ0FBQyxDQUFDLENBQUMsR0FBRyxHQUFHLENBQUMsU0FBUyxDQUFDLEVBQUUsR0FBRyxDQUFDLENBQUMsQ0FBQztTQUN0QztRQUNELE1BQU0sYUFBYSxHQUFHLFNBQVMsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUM7UUFFaEQsTUFBTSxFQUFFLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUMsYUFBYSxDQUFDLENBQUM7UUFDL0MsSUFBSSxDQUFDLEVBQUUsRUFBRTtZQUNQLE1BQU0sS0FBSyxDQUNULGlEQUFpRCxhQUFhLEVBQUUsQ0FDakUsQ0FBQztTQUNIO1FBRUQsSUFBSSxVQUFVLEdBQUcsQ0FBQyxDQUFDO1FBQ25CLElBQUksS0FBSyxHQUFHLENBQUMsQ0FBQztRQUNkLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxFQUFFLEVBQUU7WUFDbEMsSUFBSSxFQUFFLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsSUFBSSxhQUFhLEVBQUU7Z0JBQ3RELEtBQUssR0FBRyxDQUFDLENBQUM7Z0JBQ1YsVUFBVSxHQUFHLENBQUMsQ0FBQztnQkFDZixNQUFNO2FBQ1A7U0FDRjtRQUNELE9BQU8sTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLElBQUEscUJBQVksRUFBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDekUsQ0FBQztDQUNGO0FBakRELDhEQWlEQztBQUVELE1BQWEsc0JBQXVCLFNBQVEsYUFBYTtJQUt2RCxZQUFZLEtBQWU7UUFDekIsS0FBSyxFQUFFLENBQUM7UUFIRCxTQUFJLEdBQUcsaUJBQWlCLENBQUMsaUJBQWlCLENBQUM7UUFJbEQsSUFBSSxDQUFDLEtBQUssR0FBRyxLQUFLLENBQUM7SUFDckIsQ0FBQztJQUVELE9BQU8sQ0FBQyxPQUFlO1FBQ3JCLElBQUksT0FBTyxDQUFDLE1BQU0sSUFBSSxDQUFDLEVBQUU7WUFDdkIsTUFBTSxJQUFJLEtBQUssQ0FBQywyQ0FBMkMsQ0FBQyxDQUFDO1NBQzlEO1FBRUQsSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUU7WUFDM0IsTUFBTSxJQUFJLEtBQUssQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDO1NBQ3ZDO1FBRUQsMkNBQTJDO1FBQzNDLE1BQU0sV0FBVyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDO1FBQ3pDLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLEVBQUUsQ0FBQyxNQUFNLElBQUksV0FBVyxDQUFDLEVBQUU7WUFDckQsTUFBTSxJQUFJLEtBQUssQ0FDYiwrRUFBK0UsQ0FDaEYsQ0FBQztTQUNIO1FBRUQsTUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLEdBQUcsV0FBVyxDQUFDLENBQUM7UUFDbkQsTUFBTSxtQkFBbUIsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLFlBQVksRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBRXRFLE1BQU0saUJBQWlCLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxFQUFFLG1CQUFtQixDQUFDLENBQUM7UUFFcEUsT0FBTyxNQUFNLENBQUMsTUFBTSxDQUFDO1lBQ25CLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO1lBQ2xDLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyxXQUFXLENBQUMsQ0FBQztZQUMxQixHQUFHLGlCQUFpQjtTQUNyQixDQUFDLENBQUM7SUFDTCxDQUFDO0NBQ0Y7QUF0Q0Qsd0RBc0NDO0FBRUQ7Ozs7Ozs7Ozs7Ozs7O0dBY0c7QUFDSCxNQUFhLHdCQUF3QjtJQVVuQyxZQUFZLGdCQUE2QjtRQVR4QixVQUFLLEdBQXdCLElBQUksR0FBRyxFQUFFLENBQUM7UUFDdkMsY0FBUyxHQUF3QixJQUFJLEdBQUcsRUFBRSxDQUFDO1FBRXBELFlBQU8sR0FBYSxFQUFFLENBQUM7UUFFdkIsVUFBSyxHQUFhLEVBQUUsQ0FBQztRQUVaLGFBQVEsR0FBMEMsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQUczRSxNQUFNLFFBQVEsR0FBRztZQUNmLElBQUksWUFBWSxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsZ0JBQWdCLENBQUM7WUFDaEQsSUFBSSxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUM7WUFDbEQsSUFBSSx5QkFBeUIsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDO1lBQ3pDLElBQUkseUJBQXlCLENBQUMsSUFBSSxDQUFDLEtBQUssRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDO1lBQ3JELElBQUksc0JBQXNCLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQztTQUN2QyxDQUFDO1FBRUYsS0FBSyxNQUFNLEdBQUcsSUFBSSxRQUFRLEVBQUU7WUFDMUIsSUFBSSxJQUFJLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUU7Z0JBQy9CLE1BQU0sSUFBSSxLQUFLLENBQUMsK0JBQStCLEdBQUcsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDO2FBQzVEO1lBQ0QsSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRSxHQUFHLENBQUMsQ0FBQztTQUNsQztJQUNILENBQUM7SUFFRCxVQUFVO1FBQ1IsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDO0lBQ3RCLENBQUM7SUFFRCxnQkFBZ0IsQ0FBQyxRQUFnQjtRQUMvQixJQUFJLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxzQkFBTSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLEVBQUUsUUFBUSxDQUFDLENBQUM7SUFDeEUsQ0FBQztJQUVELFlBQVksQ0FBQyxRQUEyQjtRQUN0QyxLQUFLLE1BQU0sRUFBRSxJQUFJLFFBQVEsRUFBRTtZQUN6QixNQUFNLFFBQVEsR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQztZQUN2RCxJQUFJLENBQUMsZ0JBQWdCLENBQUMsUUFBUSxDQUFDLENBQUM7U0FDakM7UUFDRCxNQUFNLEVBQUUsR0FBRyxJQUFJLGVBQU0sQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxJQUFBLGlCQUFRLEVBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQzFELElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDbkQsQ0FBQztJQUVELGVBQWUsQ0FBQyxFQUFhO1FBQzNCLElBQUksQ0FBQyxZQUFZLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQzNCLElBQUksQ0FBQyxZQUFZLENBQUMsRUFBRSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQy9CLENBQUM7SUFFRCxvQkFBb0IsQ0FBQyxFQUFnQjtRQUNuQyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsRUFBRSxDQUFDLFNBQVMsRUFBRSxDQUFDLENBQUM7UUFDdEMsSUFBSSxDQUFDLFlBQVksQ0FDZixFQUFFLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLEVBQUUsT0FBTyxDQUFDLENBQUMsQ0FDNUMsQ0FBQztRQUNGLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDLENBQUM7SUFDNUQsQ0FBQztJQUVELE9BQU8sQ0FBQyxPQUFlO1FBQ3JCLElBQUksT0FBTyxDQUFDLE1BQU0sSUFBSSxDQUFDLEVBQUU7WUFDdkIsTUFBTSxJQUFJLEtBQUssQ0FBQywwQkFBMEIsQ0FBQyxDQUFDO1NBQzdDO1FBRUQsTUFBTSxPQUFPLEdBQUcsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQzNCLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ3ZDLElBQUksQ0FBQyxHQUFHLEVBQUU7WUFDUixNQUFNLElBQUksS0FBSyxDQUFDLDJCQUEyQixPQUFPLEVBQUUsQ0FBQyxDQUFDO1NBQ3ZEO1FBRUQsT0FBTyxHQUFHLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQzlCLENBQUM7Q0FDRjtBQXRFRCw0REFzRUMifQ==