UNPKG

144 kBJavaScriptView Raw
1import { common, crypto, utils } from '@neo-one/client-common-esnext-esm';
2import { metrics } from '@neo-one/monitor-esnext-esm';
3import { Consensus } from '@neo-one/node-consensus-esnext-esm';
4import { createEndpoint, getEndpointConfig, MerkleTree, RegisterTransaction, TransactionType, } from '@neo-one/node-core-esnext-esm';
5import { finalize, labels, neverComplete, utils as commonUtils } from '@neo-one/utils-esnext-esm';
6import { ScalingBloem } from 'bloem';
7// tslint:disable-next-line:match-default-export-name
8import BloomFilter from 'bloom-filter';
9import fetch from 'cross-fetch';
10import { Address6 } from 'ip-address';
11import _ from 'lodash';
12import LRU from 'lru-cache';
13import { combineLatest, defer, of as _of } from 'rxjs';
14import { distinctUntilChanged, map, switchMap, take } from 'rxjs/operators';
15import { Command } from './Command';
16import { AlreadyConnectedError, NegotiationError } from './errors';
17import { Message, MessageTransform } from './Message';
18import { AddrPayload, GetBlocksPayload, HeadersPayload, InventoryType, InvPayload, MerkleBlockPayload, NetworkAddress, SERVICES, VersionPayload, } from './payload';
19const messageReceivedLabelNames = [labels.COMMAND_NAME];
20const messageReceivedLabels = Object.keys(Command).map((command) => ({
21 [labels.COMMAND_NAME]: command,
22}));
23const NEO_PROTOCOL_MESSAGES_RECEIVED_TOTAL = metrics.createCounter({
24 name: 'neo_protocol_messages_received_total',
25 labelNames: messageReceivedLabelNames,
26 labels: messageReceivedLabels,
27});
28const NEO_PROTOCOL_MESSAGES_FAILURES_TOTAL = metrics.createCounter({
29 name: 'neo_protocol_messages_failures_total',
30 labelNames: messageReceivedLabelNames,
31 labels: messageReceivedLabels,
32});
33const NEO_PROTOCOL_MEMPOOL_SIZE = metrics.createGauge({
34 name: 'neo_protocol_mempool_size',
35});
36const createPeerBloomFilter = ({ filter, k, tweak, }) => new BloomFilter({
37 vData: Buffer.from(filter),
38 nHashFuncs: k,
39 nTweak: tweak,
40});
41const createScalingBloomFilter = () => new ScalingBloem(0.05, {
42 initial_capacity: 100000,
43 scaling: 4,
44});
45const compareTransactionAndFees = (val1, val2) => {
46 const a = val1.networkFee.divn(val1.transaction.size);
47 const b = val2.networkFee.divn(val2.transaction.size);
48 if (a.lt(b)) {
49 return -1;
50 }
51 if (b.lt(a)) {
52 return 1;
53 }
54 return val1.transaction.hash.compare(val2.transaction.hash);
55};
56const MEM_POOL_SIZE = 5000;
57const GET_ADDR_PEER_COUNT = 200;
58const GET_BLOCKS_COUNT = 500;
59// Assume that we get 500 back, but if not, at least request every 10 seconds
60const GET_BLOCKS_BUFFER = GET_BLOCKS_COUNT / 3;
61const GET_BLOCKS_TIME_MS = 10000;
62const GET_BLOCKS_THROTTLE_MS = 1000;
63const TRIM_MEMPOOL_THROTTLE = 5000;
64const GET_BLOCKS_CLOSE_COUNT = 2;
65const UNHEALTHY_PEER_SECONDS = 300;
66const LOCAL_HOST_ADDRESSES = new Set(['', '0.0.0.0', 'localhost', '127.0.0.1', '::', '::1']);
67export class Node {
68 constructor({ monitor, blockchain, createNetwork, environment = {}, options$, }) {
69 this.mutableUnhealthyPeerSeconds = UNHEALTHY_PEER_SECONDS;
70 this.requestBlocks = _.debounce(() => {
71 const peer = this.mutableBestPeer;
72 const previousBlock = this.blockchain.previousBlock;
73 const block = previousBlock === undefined ? this.blockchain.currentBlock : previousBlock;
74 if (peer !== undefined && block.index < peer.data.startHeight) {
75 if (this.mutableGetBlocksRequestsCount > GET_BLOCKS_CLOSE_COUNT) {
76 this.mutableBestPeer = this.findBestPeer(peer);
77 this.network.blacklistAndClose(peer);
78 this.mutableGetBlocksRequestsCount = 0;
79 }
80 else if (this.shouldRequestBlocks()) {
81 if (this.mutableGetBlocksRequestsIndex === block.index) {
82 this.mutableGetBlocksRequestsCount += 1;
83 }
84 else {
85 this.mutableGetBlocksRequestsCount = 1;
86 this.mutableGetBlocksRequestsIndex = block.index;
87 }
88 this.mutableGetBlocksRequestTime = Date.now();
89 this.sendMessage(peer, this.createMessage({
90 command: Command.getblocks,
91 payload: new GetBlocksPayload({
92 hashStart: [block.hash],
93 }),
94 }));
95 }
96 this.requestBlocks();
97 }
98 }, GET_BLOCKS_THROTTLE_MS);
99 this.onRequestEndpoints = _.throttle(() => {
100 this.relay(this.createMessage({ command: Command.getaddr }));
101 // tslint:disable-next-line no-floating-promises
102 this.fetchEndpointsFromRPC();
103 }, 5000);
104 // tslint:disable-next-line no-unnecessary-type-annotation
105 this.trimMemPool = _.throttle(async (monitor) => {
106 const memPool = Object.values(this.mutableMemPool);
107 if (memPool.length > MEM_POOL_SIZE) {
108 await monitor.captureSpan(async () => {
109 const transactionAndFees = await Promise.all(memPool.map(async (transaction) => {
110 const networkFee = await transaction.getNetworkFee({
111 getOutput: this.blockchain.output.get,
112 governingToken: this.blockchain.settings.governingToken,
113 utilityToken: this.blockchain.settings.utilityToken,
114 fees: this.blockchain.settings.fees,
115 registerValidatorFee: this.blockchain.settings.registerValidatorFee,
116 });
117 return { transaction, networkFee };
118 }));
119 const hashesToRemove = _.take(
120 // tslint:disable-next-line no-array-mutation
121 transactionAndFees.slice().sort(compareTransactionAndFees), this.blockchain.settings.memPoolSize).map((transactionAndFee) => transactionAndFee.transaction.hashHex);
122 hashesToRemove.forEach((hash) => {
123 // tslint:disable-next-line no-dynamic-delete
124 delete this.mutableMemPool[hash];
125 });
126 NEO_PROTOCOL_MEMPOOL_SIZE.set(Object.keys(this.mutableMemPool).length);
127 }, {
128 name: 'neo_protocol_trim_mempool',
129 });
130 }
131 }, TRIM_MEMPOOL_THROTTLE);
132 this.negotiate = async (peer) => {
133 this.sendMessage(peer, this.createMessage({
134 command: Command.version,
135 payload: new VersionPayload({
136 protocolVersion: 0,
137 services: SERVICES.NODE_NETWORK,
138 timestamp: Math.round(Date.now() / 1000),
139 port: this.externalPort,
140 nonce: this.nonce,
141 userAgent: this.userAgent,
142 startHeight: this.blockchain.currentBlockIndex,
143 relay: true,
144 }),
145 }));
146 const message = await peer.receiveMessage(30000);
147 let versionPayload;
148 if (message.value.command === Command.version) {
149 versionPayload = message.value.payload;
150 }
151 else {
152 throw new NegotiationError(message);
153 }
154 this.checkVersion(peer, message, versionPayload);
155 const { host } = getEndpointConfig(peer.endpoint);
156 let address;
157 if (NetworkAddress.isValid(host)) {
158 address = new NetworkAddress({
159 host,
160 port: versionPayload.port,
161 timestamp: versionPayload.timestamp,
162 services: versionPayload.services,
163 });
164 }
165 this.sendMessage(peer, this.createMessage({ command: Command.verack }));
166 const nextMessage = await peer.receiveMessage(30000);
167 if (nextMessage.value.command !== Command.verack) {
168 throw new NegotiationError(nextMessage);
169 }
170 return {
171 data: {
172 nonce: versionPayload.nonce,
173 startHeight: versionPayload.startHeight,
174 mutableBloomFilter: undefined,
175 address,
176 },
177 relay: versionPayload.relay,
178 };
179 };
180 this.checkPeerHealth = (peer, prevHealth) => {
181 const checkTimeSeconds = commonUtils.nowSeconds();
182 const blockIndex = this.mutableBlockIndex[peer.endpoint];
183 // If first check -> healthy
184 if (prevHealth === undefined) {
185 return { healthy: true, checkTimeSeconds, blockIndex };
186 }
187 // If seen new block -> healthy + update check time
188 if (prevHealth.blockIndex !== undefined && blockIndex !== undefined && prevHealth.blockIndex < blockIndex) {
189 return { healthy: true, checkTimeSeconds, blockIndex };
190 }
191 // If not seen a block or a new block BUT it has NOT been a long
192 // time -> healthy
193 if (prevHealth.blockIndex === blockIndex &&
194 commonUtils.nowSeconds() - prevHealth.checkTimeSeconds < this.mutableUnhealthyPeerSeconds) {
195 return {
196 healthy: true,
197 checkTimeSeconds: prevHealth.checkTimeSeconds,
198 blockIndex: prevHealth.blockIndex,
199 };
200 }
201 return { healthy: false, checkTimeSeconds, blockIndex };
202 };
203 this.onEvent = (event) => {
204 if (event.event === 'PEER_CONNECT_SUCCESS') {
205 const { connectedPeer } = event;
206 if (this.mutableBestPeer === undefined ||
207 // Only change best peer at most every 100 blocks
208 this.mutableBestPeer.data.startHeight + 100 < connectedPeer.data.startHeight) {
209 this.mutableBestPeer = connectedPeer;
210 this.resetRequestBlocks();
211 this.requestBlocks();
212 }
213 }
214 else if (event.event === 'PEER_CLOSED' &&
215 this.mutableBestPeer !== undefined &&
216 this.mutableBestPeer.endpoint === event.peer.endpoint) {
217 this.mutableBestPeer = this.findBestPeer();
218 this.resetRequestBlocks();
219 this.requestBlocks();
220 }
221 };
222 this.blockchain = blockchain;
223 this.monitor = monitor.at('node_protocol');
224 this.network = createNetwork({
225 negotiate: this.negotiate,
226 checkPeerHealth: this.checkPeerHealth,
227 createMessageTransform: () => new MessageTransform(this.blockchain.deserializeWireContext),
228 onMessageReceived: (peer, message) => {
229 this.onMessageReceived(peer, message);
230 },
231 onRequestEndpoints: this.onRequestEndpoints.bind(this),
232 onEvent: this.onEvent,
233 });
234 this.options$ = options$;
235 const { externalPort = 0 } = environment;
236 this.externalPort = externalPort;
237 this.nonce = Math.floor(Math.random() * utils.UINT_MAX_NUMBER);
238 this.userAgent = `NEO:neo-one-js:1.0.0-preview`;
239 this.mutableMemPool = {};
240 this.mutableKnownBlockHashes = createScalingBloomFilter();
241 this.tempKnownBlockHashes = new Set();
242 this.mutableKnownTransactionHashes = createScalingBloomFilter();
243 this.tempKnownTransactionHashes = new Set();
244 this.mutableKnownHeaderHashes = createScalingBloomFilter();
245 this.tempKnownHeaderHashes = new Set();
246 this.mutableGetBlocksRequestsCount = 1;
247 this.consensusCache = LRU(10000);
248 this.mutableBlockIndex = {};
249 }
250 get consensus() {
251 return this.mutableConsensus;
252 }
253 get connectedPeers() {
254 return this.network.connectedPeers.map((peer) => peer.endpoint);
255 }
256 get memPool() {
257 return this.mutableMemPool;
258 }
259 async reset() {
260 this.mutableMemPool = {};
261 this.mutableKnownBlockHashes = createScalingBloomFilter();
262 this.tempKnownBlockHashes.clear();
263 this.mutableKnownTransactionHashes = createScalingBloomFilter();
264 this.tempKnownTransactionHashes.clear();
265 this.mutableKnownHeaderHashes = createScalingBloomFilter();
266 this.tempKnownHeaderHashes.clear();
267 this.mutableGetBlocksRequestsCount = 1;
268 this.consensusCache.reset();
269 this.mutableBlockIndex = {};
270 }
271 // tslint:disable-next-line no-any
272 start$() {
273 const network$ = defer(async () => {
274 this.network.start();
275 this.monitor.log({
276 name: 'neo_protocol_start',
277 message: 'Protocol started.',
278 level: 'verbose',
279 });
280 }).pipe(neverComplete(), finalize(() => {
281 this.network.stop();
282 this.monitor.log({
283 name: 'neo_protocol_stop',
284 message: 'Protocol stopped.',
285 level: 'verbose',
286 });
287 }));
288 const defaultOptions = {
289 enabled: false,
290 options: { privateKey: 'unused', privateNet: false },
291 };
292 const consensus$ = this.options$.pipe(map(({ consensus = defaultOptions }) => consensus.enabled), distinctUntilChanged(), switchMap((enabled) => {
293 if (enabled) {
294 const mutableConsensus = new Consensus({
295 monitor: this.monitor,
296 options$: this.options$.pipe(map(({ consensus = defaultOptions }) => consensus.options), distinctUntilChanged()),
297 node: this,
298 });
299 this.mutableConsensus = mutableConsensus;
300 return mutableConsensus.start$();
301 }
302 return _of(undefined);
303 }));
304 const options$ = this.options$.pipe(map(({ unhealthyPeerSeconds = UNHEALTHY_PEER_SECONDS }) => {
305 this.mutableUnhealthyPeerSeconds = unhealthyPeerSeconds;
306 }));
307 return combineLatest(network$, consensus$, options$);
308 }
309 async relayTransaction(transaction, { throwVerifyError = false, forceAdd = false, } = {
310 throwVerifyError: false,
311 forceAdd: false,
312 }) {
313 const result = {};
314 if (transaction.type === TransactionType.Miner ||
315 this.mutableMemPool[transaction.hashHex] !== undefined ||
316 this.tempKnownTransactionHashes.has(transaction.hashHex)) {
317 return result;
318 }
319 if (!this.mutableKnownTransactionHashes.has(transaction.hash)) {
320 this.tempKnownTransactionHashes.add(transaction.hashHex);
321 try {
322 const memPool = Object.values(this.mutableMemPool);
323 if (memPool.length > MEM_POOL_SIZE / 2 && !forceAdd) {
324 this.mutableKnownTransactionHashes.add(transaction.hash);
325 return result;
326 }
327 // tslint:disable-next-line prefer-immediate-return
328 const finalResult = await this.monitor
329 .withData({ [labels.NEO_TRANSACTION_HASH]: transaction.hashHex })
330 .captureSpanLog(async (span) => {
331 let foundTransaction;
332 try {
333 foundTransaction = await this.blockchain.transaction.tryGet({
334 hash: transaction.hash,
335 });
336 }
337 finally {
338 span.setLabels({
339 [labels.NEO_TRANSACTION_FOUND]: foundTransaction !== undefined,
340 });
341 }
342 let verifyResult;
343 if (foundTransaction === undefined) {
344 verifyResult = await this.blockchain.verifyTransaction({
345 monitor: span,
346 transaction,
347 memPool: Object.values(this.mutableMemPool),
348 });
349 const verified = verifyResult.verifications.every(({ failureMessage }) => failureMessage === undefined);
350 if (verified) {
351 this.mutableMemPool[transaction.hashHex] = transaction;
352 NEO_PROTOCOL_MEMPOOL_SIZE.inc();
353 if (this.mutableConsensus !== undefined) {
354 this.mutableConsensus.onTransactionReceived(transaction);
355 }
356 this.relayTransactionInternal(transaction);
357 await this.trimMemPool(span);
358 }
359 }
360 this.mutableKnownTransactionHashes.add(transaction.hash);
361 return { verifyResult };
362 }, {
363 name: 'neo_relay_transaction',
364 level: { log: 'verbose', span: 'info' },
365 trace: true,
366 });
367 // tslint:disable-next-line no-var-before-return
368 return finalResult;
369 }
370 catch (error) {
371 if (error.code === undefined ||
372 typeof error.code !== 'string' ||
373 !error.code.includes('VERIFY') ||
374 throwVerifyError) {
375 throw error;
376 }
377 }
378 finally {
379 this.tempKnownTransactionHashes.delete(transaction.hashHex);
380 }
381 }
382 return result;
383 }
384 async relayBlock(block, monitor) {
385 await this.persistBlock(block, monitor);
386 }
387 relayConsensusPayload(payload) {
388 const message = this.createMessage({
389 command: Command.inv,
390 payload: new InvPayload({
391 type: InventoryType.Consensus,
392 hashes: [payload.hash],
393 }),
394 });
395 this.consensusCache.set(payload.hashHex, payload);
396 this.relay(message);
397 }
398 syncMemPool() {
399 this.relay(this.createMessage({ command: Command.mempool }));
400 }
401 relay(message) {
402 this.network.relay(message.serializeWire());
403 }
404 relayTransactionInternal(transaction) {
405 const message = this.createMessage({
406 command: Command.inv,
407 payload: new InvPayload({
408 type: InventoryType.Transaction,
409 hashes: [transaction.hash],
410 }),
411 });
412 const messagePayload = message.serializeWire();
413 this.network.connectedPeers.forEach((peer) => {
414 if (peer.relay && this.testFilter(peer.data.mutableBloomFilter, transaction)) {
415 peer.write(messagePayload);
416 }
417 });
418 }
419 sendMessage(peer, message) {
420 peer.write(message.serializeWire());
421 }
422 findBestPeer(bestPeer) {
423 let peers = this.network.connectedPeers;
424 if (bestPeer !== undefined) {
425 peers = peers.filter((peer) => peer.endpoint !== bestPeer.endpoint);
426 }
427 const result = _.maxBy(peers, (peer) => peer.data.startHeight);
428 if (result === undefined) {
429 return undefined;
430 }
431 return _.shuffle(peers.filter((peer) => peer.data.startHeight === result.data.startHeight))[0];
432 }
433 resetRequestBlocks() {
434 this.mutableGetBlocksRequestsIndex = undefined;
435 this.mutableGetBlocksRequestsCount = 0;
436 }
437 shouldRequestBlocks() {
438 const block = this.blockchain.currentBlock;
439 const getBlocksRequestTime = this.mutableGetBlocksRequestTime;
440 return (this.mutableGetBlocksRequestsIndex === undefined ||
441 block.index - this.mutableGetBlocksRequestsIndex > GET_BLOCKS_BUFFER ||
442 getBlocksRequestTime === undefined ||
443 Date.now() - getBlocksRequestTime > GET_BLOCKS_TIME_MS);
444 }
445 checkVersion(peer, message, version) {
446 if (version.nonce === this.nonce) {
447 this.network.permanentlyBlacklist(peer.endpoint);
448 throw new NegotiationError(message, 'Nonce equals my nonce.');
449 }
450 const connectedPeer = this.network.connectedPeers.find((otherPeer) => version.nonce === otherPeer.data.nonce);
451 if (connectedPeer !== undefined) {
452 throw new AlreadyConnectedError('Already connected to nonce.');
453 }
454 }
455 ready() {
456 const peer = this.mutableBestPeer;
457 const block = this.blockchain.currentBlock;
458 return peer !== undefined && block.index >= peer.data.startHeight;
459 }
460 async fetchEndpointsFromRPC() {
461 try {
462 await this.doFetchEndpointsFromRPC();
463 }
464 catch {
465 // ignore, logged deeper in the stack
466 }
467 }
468 async doFetchEndpointsFromRPC() {
469 const { rpcURLs = [] } = await this.options$.pipe(take(1)).toPromise();
470 await Promise.all(rpcURLs.map(async (rpcURL) => this.fetchEndpointsFromRPCURL(rpcURL)));
471 }
472 async fetchEndpointsFromRPCURL(rpcURL) {
473 try {
474 const response = await fetch(rpcURL, {
475 method: 'POST',
476 headers: {
477 'Content-Type': 'application/json',
478 },
479 body: JSON.stringify({
480 jsonrpc: '2.0',
481 id: 1,
482 method: 'getpeers',
483 params: [],
484 }),
485 });
486 if (!response.ok) {
487 throw new Error(`Failed to fetch peers from ${rpcURL}: ${response.status} ${response.statusText}`);
488 }
489 const result = await response.json();
490 if (typeof result === 'object' &&
491 result.error !== undefined &&
492 typeof result.error === 'object' &&
493 typeof result.error.code === 'number' &&
494 typeof result.error.message === 'string') {
495 throw new Error(result.error);
496 }
497 const connected = result.result.connected;
498 connected
499 .map((peer) => {
500 const { address, port } = peer;
501 const host = new Address6(address);
502 const canonicalForm = host.canonicalForm();
503 return { host: canonicalForm == undefined ? '' : canonicalForm, port };
504 })
505 .filter((endpoint) => !LOCAL_HOST_ADDRESSES.has(endpoint.host))
506 .map((endpoint) => createEndpoint({
507 type: 'tcp',
508 host: endpoint.host,
509 port: endpoint.port,
510 }))
511 .forEach((endpoint) => this.network.addEndpoint(endpoint));
512 }
513 catch (error) {
514 this.monitor.withData({ [this.monitor.labels.HTTP_URL]: rpcURL }).logError({
515 name: 'neo_protocol_fetch_endpoints_error',
516 message: `Failed to fetch endpoints from ${rpcURL}`,
517 error,
518 });
519 }
520 }
521 onMessageReceived(peer, message) {
522 this.monitor
523 .withLabels({ [labels.COMMAND_NAME]: message.value.command })
524 .withData({ [this.monitor.labels.PEER_ADDRESS]: peer.endpoint })
525 .captureLog(async (monitor) => {
526 switch (message.value.command) {
527 case Command.addr:
528 this.onAddrMessageReceived(monitor, message.value.payload);
529 break;
530 case Command.block:
531 await this.onBlockMessageReceived(monitor, peer, message.value.payload);
532 break;
533 case Command.consensus:
534 await this.onConsensusMessageReceived(monitor, message.value.payload);
535 break;
536 case Command.filteradd:
537 this.onFilterAddMessageReceived(monitor, peer, message.value.payload);
538 break;
539 case Command.filterclear:
540 this.onFilterClearMessageReceived(monitor, peer);
541 break;
542 case Command.filterload:
543 this.onFilterLoadMessageReceived(monitor, peer, message.value.payload);
544 break;
545 case Command.getaddr:
546 this.onGetAddrMessageReceived(monitor, peer);
547 break;
548 case Command.getblocks:
549 await this.onGetBlocksMessageReceived(monitor, peer, message.value.payload);
550 break;
551 case Command.getdata:
552 await this.onGetDataMessageReceived(monitor, peer, message.value.payload);
553 break;
554 case Command.getheaders:
555 await this.onGetHeadersMessageReceived(monitor, peer, message.value.payload);
556 break;
557 case Command.headers:
558 await this.onHeadersMessageReceived(monitor, peer, message.value.payload);
559 break;
560 case Command.inv:
561 this.onInvMessageReceived(monitor, peer, message.value.payload);
562 break;
563 case Command.mempool:
564 this.onMemPoolMessageReceived(monitor, peer);
565 break;
566 case Command.tx:
567 await this.onTransactionReceived(monitor, message.value.payload);
568 break;
569 case Command.verack:
570 this.onVerackMessageReceived(monitor, peer);
571 break;
572 case Command.version:
573 this.onVersionMessageReceived(monitor, peer);
574 break;
575 case Command.alert:
576 break;
577 case Command.merkleblock:
578 break;
579 case Command.notfound:
580 break;
581 case Command.ping:
582 break;
583 case Command.pong:
584 break;
585 case Command.reject:
586 break;
587 default:
588 commonUtils.assertNever(message.value);
589 }
590 }, {
591 name: 'neo_protocol_message_received',
592 level: 'debug',
593 message: `Received ${message.value.command} from ${peer.endpoint}`,
594 metric: NEO_PROTOCOL_MESSAGES_RECEIVED_TOTAL,
595 error: {
596 metric: NEO_PROTOCOL_MESSAGES_FAILURES_TOTAL,
597 message: `Failed to process message ${message.value.command} from ${peer.endpoint}`,
598 },
599 })
600 .catch(() => {
601 // do nothing
602 });
603 }
604 onAddrMessageReceived(_monitor, addr) {
605 addr.addresses
606 .filter((address) => !LOCAL_HOST_ADDRESSES.has(address.host))
607 .map((address) => createEndpoint({
608 type: 'tcp',
609 host: address.host,
610 port: address.port,
611 }))
612 .forEach((endpoint) => this.network.addEndpoint(endpoint));
613 }
614 async onBlockMessageReceived(monitor, peer, block) {
615 const blockIndex = this.mutableBlockIndex[peer.endpoint];
616 this.mutableBlockIndex[peer.endpoint] = Math.max(block.index, blockIndex === undefined ? 0 : blockIndex);
617 await this.relayBlock(block, monitor);
618 }
619 async persistBlock(block, monitor = this.monitor) {
620 if (this.blockchain.currentBlockIndex > block.index || this.tempKnownBlockHashes.has(block.hashHex)) {
621 return;
622 }
623 if (!this.mutableKnownBlockHashes.has(block.hash)) {
624 this.tempKnownBlockHashes.add(block.hashHex);
625 try {
626 const foundBlock = await this.blockchain.block.tryGet({
627 hashOrIndex: block.hash,
628 });
629 if (foundBlock === undefined) {
630 await monitor.withData({ [labels.NEO_BLOCK_INDEX]: block.index }).captureSpanLog(async (span) => {
631 await this.blockchain.persistBlock({ monitor: span, block });
632 if (this.mutableConsensus !== undefined) {
633 this.mutableConsensus.onPersistBlock();
634 }
635 const peer = this.mutableBestPeer;
636 if (peer !== undefined && block.index > peer.data.startHeight) {
637 this.relay(this.createMessage({
638 command: Command.inv,
639 payload: new InvPayload({
640 type: InventoryType.Block,
641 hashes: [block.hash],
642 }),
643 }));
644 }
645 }, {
646 name: 'neo_relay_block',
647 level: { log: 'verbose', span: 'info' },
648 trace: true,
649 });
650 }
651 this.mutableKnownBlockHashes.add(block.hash);
652 this.mutableKnownHeaderHashes.add(block.hash);
653 block.transactions.forEach((transaction) => {
654 // tslint:disable-next-line no-dynamic-delete
655 delete this.mutableMemPool[transaction.hashHex];
656 this.mutableKnownTransactionHashes.add(transaction.hash);
657 });
658 NEO_PROTOCOL_MEMPOOL_SIZE.set(Object.keys(this.mutableMemPool).length);
659 }
660 finally {
661 this.tempKnownBlockHashes.delete(block.hashHex);
662 }
663 }
664 }
665 async onConsensusMessageReceived(monitor, payload) {
666 const { consensus } = this;
667 if (consensus !== undefined) {
668 await this.blockchain.verifyConsensusPayload(payload, monitor);
669 consensus.onConsensusPayloadReceived(payload);
670 }
671 }
672 onFilterAddMessageReceived(_monitor, peer, filterAdd) {
673 if (peer.data.mutableBloomFilter !== undefined) {
674 peer.data.mutableBloomFilter.insert(filterAdd.data);
675 }
676 }
677 onFilterClearMessageReceived(_monitor, peer) {
678 // tslint:disable-next-line no-object-mutation
679 peer.data.mutableBloomFilter = undefined;
680 }
681 onFilterLoadMessageReceived(_monitor, peer, filterLoad) {
682 // tslint:disable-next-line no-object-mutation
683 peer.data.mutableBloomFilter = createPeerBloomFilter(filterLoad);
684 }
685 onGetAddrMessageReceived(_monitor, peer) {
686 const addresses = _.take(_.shuffle(this.network.connectedPeers.map((connectedPeer) => connectedPeer.data.address).filter(commonUtils.notNull)), GET_ADDR_PEER_COUNT);
687 if (addresses.length > 0) {
688 this.sendMessage(peer, this.createMessage({
689 command: Command.addr,
690 payload: new AddrPayload({ addresses }),
691 }));
692 }
693 }
694 async onGetBlocksMessageReceived(_monitor, peer, getBlocks) {
695 const headers = await this.getHeaders(getBlocks, this.blockchain.currentBlockIndex);
696 this.sendMessage(peer, this.createMessage({
697 command: Command.inv,
698 payload: new InvPayload({
699 type: InventoryType.Block,
700 hashes: headers.map((header) => header.hash),
701 }),
702 }));
703 }
704 async onGetDataMessageReceived(_monitor, peer, getData) {
705 switch (getData.type) {
706 case InventoryType.Transaction:
707 await Promise.all(getData.hashes.map(async (hash) => {
708 let transaction = this.mutableMemPool[common.uInt256ToHex(hash)];
709 if (transaction === undefined) {
710 transaction = await this.blockchain.transaction.tryGet({ hash });
711 }
712 if (transaction !== undefined) {
713 this.sendMessage(peer, this.createMessage({
714 command: Command.tx,
715 payload: transaction,
716 }));
717 }
718 }));
719 break;
720 case InventoryType.Block: // Block
721 await Promise.all(getData.hashes.map(async (hash) => {
722 const block = await this.blockchain.block.tryGet({
723 hashOrIndex: hash,
724 });
725 if (block !== undefined) {
726 if (peer.data.mutableBloomFilter === undefined) {
727 this.sendMessage(peer, this.createMessage({
728 command: Command.block,
729 payload: block,
730 }));
731 }
732 else {
733 this.sendMessage(peer, this.createMessage({
734 command: Command.merkleblock,
735 payload: this.createMerkleBlockPayload({
736 block,
737 flags: block.transactions.map((transaction) => this.testFilter(peer.data.mutableBloomFilter, transaction)),
738 }),
739 }));
740 }
741 }
742 }));
743 break;
744 case InventoryType.Consensus: // Consensus
745 getData.hashes.forEach((hash) => {
746 const payload = this.consensusCache.get(common.uInt256ToHex(hash));
747 if (payload !== undefined) {
748 this.sendMessage(peer, this.createMessage({
749 command: Command.consensus,
750 payload,
751 }));
752 }
753 });
754 break;
755 default:
756 commonUtils.assertNever(getData.type);
757 }
758 }
759 async onGetHeadersMessageReceived(_monitor, peer, getBlocks) {
760 const headers = await this.getHeaders(getBlocks, this.blockchain.currentHeader.index);
761 this.sendMessage(peer, this.createMessage({
762 command: Command.headers,
763 payload: new HeadersPayload({ headers }),
764 }));
765 }
766 async onHeadersMessageReceived(_monitor, peer, headersPayload) {
767 const headers = headersPayload.headers.filter((header) => !this.mutableKnownHeaderHashes.has(header.hash) && !this.tempKnownHeaderHashes.has(header.hashHex));
768 if (headers.length > 0) {
769 headers.forEach((header) => {
770 this.tempKnownHeaderHashes.add(header.hashHex);
771 });
772 try {
773 await this.blockchain.persistHeaders(headers);
774 headers.forEach((header) => {
775 this.mutableKnownHeaderHashes.add(header.hash);
776 });
777 }
778 finally {
779 headers.forEach((header) => {
780 this.tempKnownHeaderHashes.delete(header.hashHex);
781 });
782 }
783 }
784 if (this.blockchain.currentHeader.index < peer.data.startHeight) {
785 this.sendMessage(peer, this.createMessage({
786 command: Command.getheaders,
787 payload: new GetBlocksPayload({
788 hashStart: [this.blockchain.currentHeader.hash],
789 }),
790 }));
791 }
792 }
793 onInvMessageReceived(_monitor, peer, inv) {
794 let hashes;
795 switch (inv.type) {
796 case InventoryType.Transaction: // Transaction
797 hashes = inv.hashes.filter((hash) => !this.mutableKnownTransactionHashes.has(hash) &&
798 !this.tempKnownTransactionHashes.has(common.uInt256ToHex(hash)));
799 break;
800 case InventoryType.Block: // Block
801 hashes = inv.hashes.filter((hash) => !this.mutableKnownBlockHashes.has(hash) && !this.tempKnownBlockHashes.has(common.uInt256ToHex(hash)));
802 break;
803 case InventoryType.Consensus: // Consensus
804 hashes = inv.hashes;
805 break;
806 default:
807 commonUtils.assertNever(inv.type);
808 hashes = [];
809 }
810 if (hashes.length > 0) {
811 this.sendMessage(peer, this.createMessage({
812 command: Command.getdata,
813 payload: new InvPayload({ type: inv.type, hashes }),
814 }));
815 }
816 }
817 onMemPoolMessageReceived(_monitor, peer) {
818 this.sendMessage(peer, this.createMessage({
819 command: Command.inv,
820 payload: new InvPayload({
821 type: InventoryType.Transaction,
822 hashes: Object.values(this.mutableMemPool).map((transaction) => transaction.hash),
823 }),
824 }));
825 }
826 async onTransactionReceived(_monitor, transaction) {
827 if (this.ready()) {
828 if (transaction.type === TransactionType.Miner) {
829 if (this.mutableConsensus !== undefined) {
830 this.mutableConsensus.onTransactionReceived(transaction);
831 }
832 }
833 else {
834 await this.relayTransaction(transaction);
835 }
836 }
837 }
838 onVerackMessageReceived(_monitor, peer) {
839 peer.close();
840 }
841 onVersionMessageReceived(_monitor, peer) {
842 peer.close();
843 }
844 async getHeaders(getBlocks, maxHeight) {
845 let hashStopIndexPromise = Promise.resolve(maxHeight);
846 if (!getBlocks.hashStop.equals(common.ZERO_UINT256)) {
847 hashStopIndexPromise = this.blockchain.header
848 .tryGet({ hashOrIndex: getBlocks.hashStop })
849 .then((hashStopHeader) => hashStopHeader === undefined ? maxHeight : Math.min(hashStopHeader.index, maxHeight));
850 }
851 const [hashStartHeaders, hashEnd] = await Promise.all([
852 Promise.all(getBlocks.hashStart.map(async (hash) => this.blockchain.header.tryGet({ hashOrIndex: hash }))),
853 hashStopIndexPromise,
854 ]);
855 const hashStartHeader = _.head(_.orderBy(hashStartHeaders.filter(commonUtils.notNull), [(header) => header.index]));
856 if (hashStartHeader === undefined) {
857 return [];
858 }
859 const hashStart = hashStartHeader.index + 1;
860 if (hashStart > maxHeight) {
861 return [];
862 }
863 return Promise.all(_.range(hashStart, Math.min(hashStart + GET_BLOCKS_COUNT, hashEnd)).map(async (index) => this.blockchain.header.get({ hashOrIndex: index })));
864 }
865 testFilter(bloomFilterIn, transaction) {
866 const bloomFilter = bloomFilterIn;
867 if (bloomFilter === undefined) {
868 return true;
869 }
870 return (bloomFilter.contains(transaction.hash) ||
871 transaction.outputs.some((output) => bloomFilter.contains(output.address)) ||
872 transaction.inputs.some((input) => bloomFilter.contains(input.serializeWire())) ||
873 transaction.scripts.some((script) => bloomFilter.contains(crypto.toScriptHash(script.verification))) ||
874 (transaction.type === TransactionType.Register &&
875 transaction instanceof RegisterTransaction &&
876 bloomFilter.contains(transaction.asset.admin)));
877 }
878 createMerkleBlockPayload({ block, flags, }) {
879 const tree = new MerkleTree(block.transactions.map((transaction) => transaction.hash)).trim(flags);
880 const mutableBuffer = Buffer.allocUnsafe(Math.floor((flags.length + 7) / 8));
881 // tslint:disable-next-line no-loop-statement
882 for (let i = 0; i < flags.length; i += 1) {
883 if (flags[i]) {
884 // tslint:disable-next-line no-bitwise
885 mutableBuffer[Math.floor(i / 8)] |= 1 << i % 8;
886 }
887 }
888 return new MerkleBlockPayload({
889 version: block.version,
890 previousHash: block.previousHash,
891 merkleRoot: block.merkleRoot,
892 timestamp: block.timestamp,
893 index: block.index,
894 consensusData: block.consensusData,
895 nextConsensus: block.nextConsensus,
896 script: block.script,
897 transactionCount: block.transactions.length,
898 hashes: tree.toHashArray(),
899 flags: mutableBuffer,
900 });
901 }
902 createMessage(value) {
903 return new Message({
904 magic: this.blockchain.settings.messageMagic,
905 value,
906 });
907 }
908}
909
910//# sourceMappingURL=data:application/json;charset=utf8;base64,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TyxDQUFDO1lBQ2pCLEtBQUssRUFBRSxJQUFJLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxZQUFZO1lBQzVDLEtBQUs7U0FDTixDQUFDLENBQUM7SUFDTCxDQUFDO0NBQ0YiLCJmaWxlIjoibmVvLW9uZS1ub2RlLXByb3RvY29sL3NyYy9Ob2RlLmpzIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgY29tbW9uLCBjcnlwdG8sIFVJbnQyNTZIZXgsIHV0aWxzIH0gZnJvbSAnQG5lby1vbmUvY2xpZW50LWNvbW1vbi1lc25leHQtZXNtJztcbmltcG9ydCB7IG1ldHJpY3MsIE1vbml0b3IgfSBmcm9tICdAbmVvLW9uZS9tb25pdG9yLWVzbmV4dC1lc20nO1xuaW1wb3J0IHsgQ29uc2Vuc3VzLCBDb25zZW5zdXNPcHRpb25zIH0gZnJvbSAnQG5lby1vbmUvbm9kZS1jb25zZW5zdXMtZXNuZXh0LWVzbSc7XG5pbXBvcnQge1xuICBCbG9jayxcbiAgQmxvY2tjaGFpbixcbiAgQ29ubmVjdGVkUGVlcixcbiAgQ29uc2Vuc3VzUGF5bG9hZCxcbiAgY3JlYXRlRW5kcG9pbnQsXG4gIENyZWF0ZU5ldHdvcmssXG4gIEVuZHBvaW50LFxuICBnZXRFbmRwb2ludENvbmZpZyxcbiAgSGVhZGVyLFxuICBNZXJrbGVUcmVlLFxuICBOZWdvdGlhdGVSZXN1bHQsXG4gIE5ldHdvcmssXG4gIE5ldHdvcmtFdmVudE1lc3NhZ2UsXG4gIE5vZGUgYXMgSU5vZGUsXG4gIFBlZXIsXG4gIFJlZ2lzdGVyVHJhbnNhY3Rpb24sXG4gIFJlbGF5VHJhbnNhY3Rpb25SZXN1bHQsXG4gIFRyYW5zYWN0aW9uLFxuICBUcmFuc2FjdGlvblR5cGUsXG4gIFZlcmlmeVRyYW5zYWN0aW9uUmVzdWx0LFxufSBmcm9tICdAbmVvLW9uZS9ub2RlLWNvcmUtZXNuZXh0LWVzbSc7XG5pbXBvcnQgeyBmaW5hbGl6ZSwgbGFiZWxzLCBuZXZlckNvbXBsZXRlLCB1dGlscyBhcyBjb21tb25VdGlscyB9IGZyb20gJ0BuZW8tb25lL3V0aWxzLWVzbmV4dC1lc20nO1xuaW1wb3J0IHsgU2NhbGluZ0Jsb2VtIH0gZnJvbSAnYmxvZW0nO1xuLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lOm1hdGNoLWRlZmF1bHQtZXhwb3J0LW5hbWVcbmltcG9ydCBCbG9vbUZpbHRlciBmcm9tICdibG9vbS1maWx0ZXInO1xuaW1wb3J0IEJOIGZyb20gJ2JuLmpzJztcbmltcG9ydCBmZXRjaCBmcm9tICdjcm9zcy1mZXRjaCc7XG5pbXBvcnQgeyBBZGRyZXNzNiB9IGZyb20gJ2lwLWFkZHJlc3MnO1xuaW1wb3J0IF8gZnJvbSAnbG9kYXNoJztcbmltcG9ydCBMUlUgZnJvbSAnbHJ1LWNhY2hlJztcbmltcG9ydCB7IGNvbWJpbmVMYXRlc3QsIGRlZmVyLCBPYnNlcnZhYmxlLCBvZiBhcyBfb2YgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IGRpc3RpbmN0VW50aWxDaGFuZ2VkLCBtYXAsIHN3aXRjaE1hcCwgdGFrZSB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCB7IENvbW1hbmQgfSBmcm9tICcuL0NvbW1hbmQnO1xuaW1wb3J0IHsgQWxyZWFkeUNvbm5lY3RlZEVycm9yLCBOZWdvdGlhdGlvbkVycm9yIH0gZnJvbSAnLi9lcnJvcnMnO1xuaW1wb3J0IHsgTWVzc2FnZSwgTWVzc2FnZVRyYW5zZm9ybSwgTWVzc2FnZVZhbHVlIH0gZnJvbSAnLi9NZXNzYWdlJztcbmltcG9ydCB7XG4gIEFkZHJQYXlsb2FkLFxuICBGaWx0ZXJBZGRQYXlsb2FkLFxuICBGaWx0ZXJMb2FkUGF5bG9hZCxcbiAgR2V0QmxvY2tzUGF5bG9hZCxcbiAgSGVhZGVyc1BheWxvYWQsXG4gIEludmVudG9yeVR5cGUsXG4gIEludlBheWxvYWQsXG4gIE1lcmtsZUJsb2NrUGF5bG9hZCxcbiAgTmV0d29ya0FkZHJlc3MsXG4gIFNFUlZJQ0VTLFxuICBWZXJzaW9uUGF5bG9hZCxcbn0gZnJvbSAnLi9wYXlsb2FkJztcbmltcG9ydCB7IFBlZXJEYXRhIH0gZnJvbSAnLi9QZWVyRGF0YSc7XG5cbmNvbnN0IG1lc3NhZ2VSZWNlaXZlZExhYmVsTmFtZXM6IFJlYWRvbmx5QXJyYXk8c3RyaW5nPiA9IFtsYWJlbHMuQ09NTUFORF9OQU1FXTtcbmNvbnN0IG1lc3NhZ2VSZWNlaXZlZExhYmVscyA9IE9iamVjdC5rZXlzKENvbW1hbmQpLm1hcCgoY29tbWFuZCkgPT4gKHtcbiAgW2xhYmVscy5DT01NQU5EX05BTUVdOiBjb21tYW5kLFxufSkpO1xuXG5jb25zdCBORU9fUFJPVE9DT0xfTUVTU0FHRVNfUkVDRUlWRURfVE9UQUwgPSBtZXRyaWNzLmNyZWF0ZUNvdW50ZXIoe1xuICBuYW1lOiAnbmVvX3Byb3RvY29sX21lc3NhZ2VzX3JlY2VpdmVkX3RvdGFsJyxcbiAgbGFiZWxOYW1lczogbWVzc2FnZVJlY2VpdmVkTGFiZWxOYW1lcyxcbiAgbGFiZWxzOiBtZXNzYWdlUmVjZWl2ZWRMYWJlbHMsXG59KTtcblxuY29uc3QgTkVPX1BST1RPQ09MX01FU1NBR0VTX0ZBSUxVUkVTX1RPVEFMID0gbWV0cmljcy5jcmVhdGVDb3VudGVyKHtcbiAgbmFtZTogJ25lb19wcm90b2NvbF9tZXNzYWdlc19mYWlsdXJlc190b3RhbCcsXG4gIGxhYmVsTmFtZXM6IG1lc3NhZ2VSZWNlaXZlZExhYmVsTmFtZXMsXG4gIGxhYmVsczogbWVzc2FnZVJlY2VpdmVkTGFiZWxzLFxufSk7XG5cbmNvbnN0IE5FT19QUk9UT0NPTF9NRU1QT09MX1NJWkUgPSBtZXRyaWNzLmNyZWF0ZUdhdWdlKHtcbiAgbmFtZTogJ25lb19wcm90b2NvbF9tZW1wb29sX3NpemUnLFxufSk7XG5leHBvcnQgaW50ZXJmYWNlIFRyYW5zYWN0aW9uQW5kRmVlIHtcbiAgcmVhZG9ubHkgdHJhbnNhY3Rpb246IFRyYW5zYWN0aW9uO1xuICByZWFkb25seSBuZXR3b3JrRmVlOiBCTjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBFbnZpcm9ubWVudCB7XG4gIHJlYWRvbmx5IGV4dGVybmFsUG9ydD86IG51bWJlcjtcbn1cbmV4cG9ydCBpbnRlcmZhY2UgT3B0aW9ucyB7XG4gIHJlYWRvbmx5IGNvbnNlbnN1cz86IHtcbiAgICByZWFkb25seSBlbmFibGVkOiBib29sZWFuO1xuICAgIHJlYWRvbmx5IG9wdGlvbnM6IENvbnNlbnN1c09wdGlvbnM7XG4gIH07XG4gIHJlYWRvbmx5IHJwY1VSTHM/OiBSZWFkb25seUFycmF5PHN0cmluZz47XG4gIHJlYWRvbmx5IHVuaGVhbHRoeVBlZXJTZWNvbmRzPzogbnVtYmVyO1xufVxuXG5jb25zdCBjcmVhdGVQZWVyQmxvb21GaWx0ZXIgPSAoe1xuICBmaWx0ZXIsXG4gIGssXG4gIHR3ZWFrLFxufToge1xuICByZWFkb25seSBmaWx0ZXI6IEJ1ZmZlcjtcbiAgcmVhZG9ubHkgazogbnVtYmVyO1xuICByZWFkb25seSB0d2VhazogbnVtYmVyO1xufSkgPT5cbiAgbmV3IEJsb29tRmlsdGVyKHtcbiAgICB2RGF0YTogQnVmZmVyLmZyb20oZmlsdGVyKSxcbiAgICBuSGFzaEZ1bmNzOiBrLFxuICAgIG5Ud2VhazogdHdlYWssXG4gIH0pO1xuXG5jb25zdCBjcmVhdGVTY2FsaW5nQmxvb21GaWx0ZXIgPSAoKSA9PlxuICBuZXcgU2NhbGluZ0Jsb2VtKDAuMDUsIHtcbiAgICBpbml0aWFsX2NhcGFjaXR5OiAxMDAwMDAsXG4gICAgc2NhbGluZzogNCxcbiAgfSk7XG5cbmNvbnN0IGNvbXBhcmVUcmFuc2FjdGlvbkFuZEZlZXMgPSAodmFsMTogVHJhbnNhY3Rpb25BbmRGZWUsIHZhbDI6IFRyYW5zYWN0aW9uQW5kRmVlKSA9PiB7XG4gIGNvbnN0IGEgPSB2YWwxLm5ldHdvcmtGZWUuZGl2bih2YWwxLnRyYW5zYWN0aW9uLnNpemUpO1xuICBjb25zdCBiID0gdmFsMi5uZXR3b3JrRmVlLmRpdm4odmFsMi50cmFuc2FjdGlvbi5zaXplKTtcbiAgaWYgKGEubHQoYikpIHtcbiAgICByZXR1cm4gLTE7XG4gIH1cbiAgaWYgKGIubHQoYSkpIHtcbiAgICByZXR1cm4gMTtcbiAgfVxuXG4gIHJldHVybiB2YWwxLnRyYW5zYWN0aW9uLmhhc2guY29tcGFyZSh2YWwyLnRyYW5zYWN0aW9uLmhhc2gpO1xufTtcblxuY29uc3QgTUVNX1BPT0xfU0laRSA9IDUwMDA7XG5jb25zdCBHRVRfQUREUl9QRUVSX0NPVU5UID0gMjAwO1xuY29uc3QgR0VUX0JMT0NLU19DT1VOVCA9IDUwMDtcbi8vIEFzc3VtZSB0aGF0IHdlIGdldCA1MDAgYmFjaywgYnV0IGlmIG5vdCwgYXQgbGVhc3QgcmVxdWVzdCBldmVyeSAxMCBzZWNvbmRzXG5jb25zdCBHRVRfQkxPQ0tTX0JVRkZFUiA9IEdFVF9CTE9DS1NfQ09VTlQgLyAzO1xuY29uc3QgR0VUX0JMT0NLU19USU1FX01TID0gMTAwMDA7XG5jb25zdCBHRVRfQkxPQ0tTX1RIUk9UVExFX01TID0gMTAwMDtcbmNvbnN0IFRSSU1fTUVNUE9PTF9USFJPVFRMRSA9IDUwMDA7XG5jb25zdCBHRVRfQkxPQ0tTX0NMT1NFX0NPVU5UID0gMjtcbmNvbnN0IFVOSEVBTFRIWV9QRUVSX1NFQ09ORFMgPSAzMDA7XG5jb25zdCBMT0NBTF9IT1NUX0FERFJFU1NFUyA9IG5ldyBTZXQoWycnLCAnMC4wLjAuMCcsICdsb2NhbGhvc3QnLCAnMTI3LjAuMC4xJywgJzo6JywgJzo6MSddKTtcblxuaW50ZXJmYWNlIFBlZXJIZWFsdGgge1xuICByZWFkb25seSBoZWFsdGh5OiBib29sZWFuO1xuICByZWFkb25seSBibG9ja0luZGV4OiBudW1iZXIgfCB1bmRlZmluZWQ7XG4gIHJlYWRvbmx5IGNoZWNrVGltZVNlY29uZHM6IG51bWJlcjtcbn1cblxuZXhwb3J0IGNsYXNzIE5vZGUgaW1wbGVtZW50cyBJTm9kZSB7XG4gIHB1YmxpYyBnZXQgY29uc2Vuc3VzKCk6IENvbnNlbnN1cyB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMubXV0YWJsZUNvbnNlbnN1cztcbiAgfVxuXG4gIHB1YmxpYyBnZXQgY29ubmVjdGVkUGVlcnMoKTogUmVhZG9ubHlBcnJheTxFbmRwb2ludD4ge1xuICAgIHJldHVybiB0aGlzLm5ldHdvcmsuY29ubmVjdGVkUGVlcnMubWFwKChwZWVyKSA9PiBwZWVyLmVuZHBvaW50KTtcbiAgfVxuXG4gIHB1YmxpYyBnZXQgbWVtUG9vbCgpOiB7IHJlYWRvbmx5IFtoYXNoOiBzdHJpbmddOiBUcmFuc2FjdGlvbiB9IHtcbiAgICByZXR1cm4gdGhpcy5tdXRhYmxlTWVtUG9vbDtcbiAgfVxuICBwdWJsaWMgcmVhZG9ubHkgYmxvY2tjaGFpbjogQmxvY2tjaGFpbjtcbiAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lIHJlYWRvbmx5LWtleXdvcmRcbiAgcHJpdmF0ZSBtdXRhYmxlTWVtUG9vbDogeyBbaGFzaDogc3RyaW5nXTogVHJhbnNhY3Rpb24gfTtcbiAgcHJpdmF0ZSByZWFkb25seSBtb25pdG9yOiBNb25pdG9yO1xuICBwcml2YXRlIHJlYWRvbmx5IG5ldHdvcms6IE5ldHdvcms8TWVzc2FnZSwgUGVlckRhdGE+O1xuICBwcml2YXRlIHJlYWRvbmx5IG9wdGlvbnMkOiBPYnNlcnZhYmxlPE9wdGlvbnM+O1xuICBwcml2YXRlIHJlYWRvbmx5IGV4dGVybmFsUG9ydDogbnVtYmVyO1xuICBwcml2YXRlIHJlYWRvbmx5IG5vbmNlOiBudW1iZXI7XG4gIHByaXZhdGUgcmVhZG9ubHkgdXNlckFnZW50OiBzdHJpbmc7XG4gIHByaXZhdGUgbXV0YWJsZUtub3duQmxvY2tIYXNoZXM6IFNjYWxpbmdCbG9lbTtcbiAgcHJpdmF0ZSByZWFkb25seSB0ZW1wS25vd25CbG9ja0hhc2hlczogU2V0PFVJbnQyNTZIZXg+O1xuICBwcml2YXRlIG11dGFibGVLbm93blRyYW5zYWN0aW9uSGFzaGVzOiBTY2FsaW5nQmxvZW07XG4gIHByaXZhdGUgcmVhZG9ubHkgdGVtcEtub3duVHJhbnNhY3Rpb25IYXNoZXM6IFNldDxVSW50MjU2SGV4PjtcbiAgcHJpdmF0ZSBtdXRhYmxlS25vd25IZWFkZXJIYXNoZXM6IFNjYWxpbmdCbG9lbTtcbiAgcHJpdmF0ZSByZWFkb25seSB0ZW1wS25vd25IZWFkZXJIYXNoZXM6IFNldDxVSW50MjU2SGV4PjtcbiAgcHJpdmF0ZSBtdXRhYmxlR2V0QmxvY2tzUmVxdWVzdHNJbmRleDogbnVtYmVyIHwgdW5kZWZpbmVkO1xuICBwcml2YXRlIG11dGFibGVHZXRCbG9ja3NSZXF1ZXN0VGltZTogbnVtYmVyIHwgdW5kZWZpbmVkO1xuICBwcml2YXRlIG11dGFibGVHZXRCbG9ja3NSZXF1ZXN0c0NvdW50OiBudW1iZXI7XG4gIHByaXZhdGUgbXV0YWJsZUJlc3RQZWVyOiBDb25uZWN0ZWRQZWVyPE1lc3NhZ2UsIFBlZXJEYXRhPiB8IHVuZGVmaW5lZDtcbiAgcHJpdmF0ZSBtdXRhYmxlVW5oZWFsdGh5UGVlclNlY29uZHMgPSBVTkhFQUxUSFlfUEVFUl9TRUNPTkRTO1xuICBwcml2YXRlIHJlYWRvbmx5IGNvbnNlbnN1c0NhY2hlOiBMUlUuQ2FjaGU8c3RyaW5nLCBDb25zZW5zdXNQYXlsb2FkPjtcbiAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lIHJlYWRvbmx5LWtleXdvcmRcbiAgcHJpdmF0ZSBtdXRhYmxlQmxvY2tJbmRleDogeyBbZW5kcG9pbnQ6IHN0cmluZ106IG51bWJlciB9O1xuICBwcml2YXRlIG11dGFibGVDb25zZW5zdXM6IENvbnNlbnN1cyB8IHVuZGVmaW5lZDtcbiAgcHJpdmF0ZSByZWFkb25seSByZXF1ZXN0QmxvY2tzID0gXy5kZWJvdW5jZSgoKSA9PiB7XG4gICAgY29uc3QgcGVlciA9IHRoaXMubXV0YWJsZUJlc3RQZWVyO1xuICAgIGNvbnN0IHByZXZpb3VzQmxvY2sgPSB0aGlzLmJsb2NrY2hhaW4ucHJldmlvdXNCbG9jaztcbiAgICBjb25zdCBibG9jayA9IHByZXZpb3VzQmxvY2sgPT09IHVuZGVmaW5lZCA/IHRoaXMuYmxvY2tjaGFpbi5jdXJyZW50QmxvY2sgOiBwcmV2aW91c0Jsb2NrO1xuICAgIGlmIChwZWVyICE9PSB1bmRlZmluZWQgJiYgYmxvY2suaW5kZXggPCBwZWVyLmRhdGEuc3RhcnRIZWlnaHQpIHtcbiAgICAgIGlmICh0aGlzLm11dGFibGVHZXRCbG9ja3NSZXF1ZXN0c0NvdW50ID4gR0VUX0JMT0NLU19DTE9TRV9DT1VOVCkge1xuICAgICAgICB0aGlzLm11dGFibGVCZXN0UGVlciA9IHRoaXMuZmluZEJlc3RQZWVyKHBlZXIpO1xuICAgICAgICB0aGlzLm5ldHdvcmsuYmxhY2tsaXN0QW5kQ2xvc2UocGVlcik7XG4gICAgICAgIHRoaXMubXV0YWJsZUdldEJsb2Nrc1JlcXVlc3RzQ291bnQgPSAwO1xuICAgICAgfSBlbHNlIGlmICh0aGlzLnNob3VsZFJlcXVlc3RCbG9ja3MoKSkge1xuICAgICAgICBpZiAodGhpcy5tdXRhYmxlR2V0QmxvY2tzUmVxdWVzdHNJbmRleCA9PT0gYmxvY2suaW5kZXgpIHtcbiAgICAgICAgICB0aGlzLm11dGFibGVHZXRCbG9ja3NSZXF1ZXN0c0NvdW50ICs9IDE7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhpcy5tdXRhYmxlR2V0QmxvY2tzUmVxdWVzdHNDb3VudCA9IDE7XG4gICAgICAgICAgdGhpcy5tdXRhYmxlR2V0QmxvY2tzUmVxdWVzdHNJbmRleCA9IGJsb2NrLmluZGV4O1xuICAgICAgICB9XG4gICAgICAgIHRoaXMubXV0YWJsZUdldEJsb2Nrc1JlcXVlc3RUaW1lID0gRGF0ZS5ub3coKTtcbiAgICAgICAgdGhpcy5zZW5kTWVzc2FnZShcbiAgICAgICAgICBwZWVyLFxuICAgICAgICAgIHRoaXMuY3JlYXRlTWVzc2FnZSh7XG4gICAgICAgICAgICBjb21tYW5kOiBDb21tYW5kLmdldGJsb2NrcyxcbiAgICAgICAgICAgIHBheWxvYWQ6IG5ldyBHZXRCbG9ja3NQYXlsb2FkKHtcbiAgICAgICAgICAgICAgaGFzaFN0YXJ0OiBbYmxvY2suaGFzaF0sXG4gICAgICAgICAgICB9KSxcbiAgICAgICAgICB9KSxcbiAgICAgICAgKTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5yZXF1ZXN0QmxvY2tzKCk7XG4gICAgfVxuICB9LCBHRVRfQkxPQ0tTX1RIUk9UVExFX01TKTtcbiAgcHJpdmF0ZSByZWFkb25seSBvblJlcXVlc3RFbmRwb2ludHMgPSBfLnRocm90dGxlKCgpOiB2b2lkID0+IHtcbiAgICB0aGlzLnJlbGF5KHRoaXMuY3JlYXRlTWVzc2FnZSh7IGNvbW1hbmQ6IENvbW1hbmQuZ2V0YWRkciB9KSk7XG4gICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lIG5vLWZsb2F0aW5nLXByb21pc2VzXG4gICAgdGhpcy5mZXRjaEVuZHBvaW50c0Zyb21SUEMoKTtcbiAgfSwgNTAwMCk7XG5cbiAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lIG5vLXVubmVjZXNzYXJ5LXR5cGUtYW5ub3RhdGlvblxuICBwcml2YXRlIHJlYWRvbmx5IHRyaW1NZW1Qb29sID0gXy50aHJvdHRsZShhc3luYyAobW9uaXRvcjogTW9uaXRvcik6IFByb21pc2U8dm9pZD4gPT4ge1xuICAgIGNvbnN0IG1lbVBvb2wgPSBPYmplY3QudmFsdWVzKHRoaXMubXV0YWJsZU1lbVBvb2wpO1xuICAgIGlmIChtZW1Qb29sLmxlbmd0aCA+IE1FTV9QT09MX1NJWkUpIHtcbiAgICAgIGF3YWl0IG1vbml0b3IuY2FwdHVyZVNwYW4oXG4gICAgICAgIGFzeW5jICgpID0+IHtcbiAgICAgICAgICBjb25zdCB0cmFuc2FjdGlvbkFuZEZlZXMgPSBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgICAgICAgIG1lbVBvb2wubWFwPFByb21pc2U8VHJhbnNhY3Rpb25BbmRGZWU+Pihhc3luYyAodHJhbnNhY3Rpb24pID0+IHtcbiAgICAgICAgICAgICAgY29uc3QgbmV0d29ya0ZlZSA9IGF3YWl0IHRyYW5zYWN0aW9uLmdldE5ldHdvcmtGZWUoe1xuICAgICAgICAgICAgICAgIGdldE91dHB1dDogdGhpcy5ibG9ja2NoYWluLm91dHB1dC5nZXQsXG4gICAgICAgICAgICAgICAgZ292ZXJuaW5nVG9rZW46IHRoaXMuYmxvY2tjaGFpbi5zZXR0aW5ncy5nb3Zlcm5pbmdUb2tlbixcbiAgICAgICAgICAgICAgICB1dGlsaXR5VG9rZW46IHRoaXMuYmxvY2tjaGFpbi5zZXR0aW5ncy51dGlsaXR5VG9rZW4sXG4gICAgICAgICAgICAgICAgZmVlczogdGhpcy5ibG9ja2NoYWluLnNldHRpbmdzLmZlZXMsXG4gICAgICAgICAgICAgICAgcmVnaXN0ZXJWYWxpZGF0b3JGZWU6IHRoaXMuYmxvY2tjaGFpbi5zZXR0aW5ncy5yZWdpc3RlclZhbGlkYXRvckZlZSxcbiAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgICAgcmV0dXJuIHsgdHJhbnNhY3Rpb24sIG5ldHdvcmtGZWUgfTtcbiAgICAgICAgICAgIH0pLFxuICAgICAgICAgICk7XG5cbiAgICAgICAgICBjb25zdCBoYXNoZXNUb1JlbW92ZSA9IF8udGFrZTxUcmFuc2FjdGlvbkFuZEZlZT4oXG4gICAgICAgICAgICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmUgbm8tYXJyYXktbXV0YXRpb25cbiAgICAgICAgICAgIHRyYW5zYWN0aW9uQW5kRmVlcy5zbGljZSgpLnNvcnQoY29tcGFyZVRyYW5zYWN0aW9uQW5kRmVlcyksXG4gICAgICAgICAgICB0aGlzLmJsb2NrY2hhaW4uc2V0dGluZ3MubWVtUG9vbFNpemUsXG4gICAgICAgICAgKS5tYXAoKHRyYW5zYWN0aW9uQW5kRmVlKSA9PiB0cmFuc2FjdGlvbkFuZEZlZS50cmFuc2FjdGlvbi5oYXNoSGV4KTtcbiAgICAgICAgICBoYXNoZXNUb1JlbW92ZS5mb3JFYWNoKChoYXNoKSA9PiB7XG4gICAgICAgICAgICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmUgbm8tZHluYW1pYy1kZWxldGVcbiAgICAgICAgICAgIGRlbGV0ZSB0aGlzLm11dGFibGVNZW1Qb29sW2hhc2hdO1xuICAgICAgICAgIH0pO1xuICAgICAgICAgIE5FT19QUk9UT0NPTF9NRU1QT09MX1NJWkUuc2V0KE9iamVjdC5rZXlzKHRoaXMubXV0YWJsZU1lbVBvb2wpLmxlbmd0aCk7XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBuYW1lOiAnbmVvX3Byb3RvY29sX3RyaW1fbWVtcG9vbCcsXG4gICAgICAgIH0sXG4gICAgICApO1xuICAgIH1cbiAgfSwgVFJJTV9NRU1QT09MX1RIUk9UVExFKTtcblxuICBwdWJsaWMgY29uc3RydWN0b3Ioe1xuICAgIG1vbml0b3IsXG4gICAgYmxvY2tjaGFpbixcbiAgICBjcmVhdGVOZXR3b3JrLFxuICAgIGVudmlyb25tZW50ID0ge30sXG4gICAgb3B0aW9ucyQsXG4gIH06IHtcbiAgICByZWFkb25seSBtb25pdG9yOiBNb25pdG9yO1xuICAgIHJlYWRvbmx5IGJsb2NrY2hhaW46IEJsb2NrY2hhaW47XG4gICAgcmVhZG9ubHkgY3JlYXRlTmV0d29yazogQ3JlYXRlTmV0d29yaztcbiAgICByZWFkb25seSBlbnZpcm9ubWVudD86IEVudmlyb25tZW50O1xuICAgIHJlYWRvbmx5IG9wdGlvbnMkOiBPYnNlcnZhYmxlPE9wdGlvbnM+O1xuICB9KSB7XG4gICAgdGhpcy5ibG9ja2NoYWluID0gYmxvY2tjaGFpbjtcbiAgICB0aGlzLm1vbml0b3IgPSBtb25pdG9yLmF0KCdub2RlX3Byb3RvY29sJyk7XG4gICAgdGhpcy5uZXR3b3JrID0gY3JlYXRlTmV0d29yayh7XG4gICAgICBuZWdvdGlhdGU6IHRoaXMubmVnb3RpYXRlLFxuICAgICAgY2hlY2tQZWVySGVhbHRoOiB0aGlzLmNoZWNrUGVlckhlYWx0aCxcbiAgICAgIGNyZWF0ZU1lc3NhZ2VUcmFuc2Zvcm06ICgpID0+IG5ldyBNZXNzYWdlVHJhbnNmb3JtKHRoaXMuYmxvY2tjaGFpbi5kZXNlcmlhbGl6ZVdpcmVDb250ZXh0KSxcbiAgICAgIG9uTWVzc2FnZVJlY2VpdmVkOiAocGVlciwgbWVzc2FnZTogTWVzc2FnZSkgPT4ge1xuICAgICAgICB0aGlzLm9uTWVzc2FnZVJlY2VpdmVkKHBlZXIsIG1lc3NhZ2UpO1xuICAgICAgfSxcbiAgICAgIG9uUmVxdWVzdEVuZHBvaW50czogdGhpcy5vblJlcXVlc3RFbmRwb2ludHMuYmluZCh0aGlzKSxcbiAgICAgIG9uRXZlbnQ6IHRoaXMub25FdmVudCxcbiAgICB9KTtcblxuICAgIHRoaXMub3B0aW9ucyQgPSBvcHRpb25zJDtcblxuICAgIGNvbnN0IHsgZXh0ZXJuYWxQb3J0ID0gMCB9ID0gZW52aXJvbm1lbnQ7XG4gICAgdGhpcy5leHRlcm5hbFBvcnQgPSBleHRlcm5hbFBvcnQ7XG4gICAgdGhpcy5ub25jZSA9IE1hdGguZmxvb3IoTWF0aC5yYW5kb20oKSAqIHV0aWxzLlVJTlRfTUFYX05VTUJFUik7XG4gICAgdGhpcy51c2VyQWdlbnQgPSBgTkVPOm5lby1vbmUtanM6MS4wLjAtcHJldmlld2A7XG5cbiAgICB0aGlzLm11dGFibGVNZW1Qb29sID0ge307XG4gICAgdGhpcy5tdXRhYmxlS25vd25CbG9ja0hhc2hlcyA9IGNyZWF0ZVNjYWxpbmdCbG9vbUZpbHRlcigpO1xuICAgIHRoaXMudGVtcEtub3duQmxvY2tIYXNoZXMgPSBuZXcgU2V0KCk7XG4gICAgdGhpcy5tdXRhYmxlS25vd25UcmFuc2FjdGlvbkhhc2hlcyA9IGNyZWF0ZVNjYWxpbmdCbG9vbUZpbHRlcigpO1xuICAgIHRoaXMudGVtcEtub3duVHJhbnNhY3Rpb25IYXNoZXMgPSBuZXcgU2V0KCk7XG4gICAgdGhpcy5tdXRhYmxlS25vd25IZWFkZXJIYXNoZXMgPSBjcmVhdGVTY2FsaW5nQmxvb21GaWx0ZXIoKTtcbiAgICB0aGlzLnRlbXBLbm93bkhlYWRlckhhc2hlcyA9IG5ldyBTZXQoKTtcbiAgICB0aGlzLm11dGFibGVHZXRCbG9ja3NSZXF1ZXN0c0NvdW50ID0gMTtcbiAgICB0aGlzLmNvbnNlbnN1c0NhY2hlID0gTFJVKDEwMDAwKTtcbiAgICB0aGlzLm11dGFibGVCbG9ja0luZGV4ID0ge307XG4gIH1cblxuICBwdWJsaWMgYXN5bmMgcmVzZXQoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdGhpcy5tdXRhYmxlTWVtUG9vbCA9IHt9O1xuICAgIHRoaXMubXV0YWJsZUtub3duQmxvY2tIYXNoZXMgPSBjcmVhdGVTY2FsaW5nQmxvb21GaWx0ZXIoKTtcbiAgICB0aGlzLnRlbXBLbm93bkJsb2NrSGFzaGVzLmNsZWFyKCk7XG4gICAgdGhpcy5tdXRhYmxlS25vd25UcmFuc2FjdGlvbkhhc2hlcyA9IGNyZWF0ZVNjYWxpbmdCbG9vbUZpbHRlcigpO1xuICAgIHRoaXMudGVtcEtub3duVHJhbnNhY3Rpb25IYXNoZXMuY2xlYXIoKTtcbiAgICB0aGlzLm11dGFibGVLbm93bkhlYWRlckhhc2hlcyA9IGNyZWF0ZVNjYWxpbmdCbG9vbUZpbHRlcigpO1xuICAgIHRoaXMudGVtcEtub3duSGVhZGVySGFzaGVzLmNsZWFyKCk7XG4gICAgdGhpcy5tdXRhYmxlR2V0QmxvY2tzUmVxdWVzdHNDb3VudCA9IDE7XG4gICAgdGhpcy5jb25zZW5zdXNDYWNoZS5yZXNldCgpO1xuICAgIHRoaXMubXV0YWJsZUJsb2NrSW5kZXggPSB7fTtcbiAgfVxuXG4gIC8vIHRzbGludDpkaXNhYmxlLW5leHQtbGluZSBuby1hbnlcbiAgcHVibGljIHN0YXJ0JCgpOiBPYnNlcnZhYmxlPGFueT4ge1xuICAgIGNvbnN0IG5ldHdvcmskID0gZGVmZXIoYXN5bmMgKCkgPT4ge1xuICAgICAgdGhpcy5uZXR3b3JrLnN0YXJ0KCk7XG4gICAgICB0aGlzLm1vbml0b3IubG9nKHtcbiAgICAgICAgbmFtZTogJ25lb19wcm90b2NvbF9zdGFydCcsXG4gICAgICAgIG1lc3NhZ2U6ICdQcm90b2NvbCBzdGFydGVkLicsXG4gICAgICAgIGxldmVsOiAndmVyYm9zZScsXG4gICAgICB9KTtcbiAgICB9KS5waXBlKFxuICAgICAgbmV2ZXJDb21wbGV0ZSgpLFxuICAgICAgZmluYWxpemUoKCkgPT4ge1xuICAgICAgICB0aGlzLm5ldHdvcmsuc3RvcCgpO1xuICAgICAgICB0aGlzLm1vbml0b3IubG9nKHtcbiAgICAgICAgICBuYW1lOiAnbmVvX3Byb3RvY29sX3N0b3AnLFxuICAgICAgICAgIG1lc3NhZ2U6ICdQcm90b2NvbCBzdG9wcGVkLicsXG4gICAgICAgICAgbGV2ZWw6ICd2ZXJib3NlJyxcbiAgICAgICAgfSk7XG4gICAgICB9KSxcbiAgICApO1xuXG4gICAgY29uc3QgZGVmYXVsdE9wdGlvbnMgPSB7XG4gICAgICBlbmFibGVkOiBmYWxzZSxcbiAgICAgIG9wdGlvbnM6IHsgcHJpdmF0ZUtleTogJ3VudXNlZCcsIHByaXZhdGVOZXQ6IGZhbHNlIH0sXG4gICAgfTtcblxuICAgIGNvbnN0IGNvbnNlbnN1cyQgPSB0aGlzLm9wdGlvbnMkLnBpcGUoXG4gICAgICBtYXAoKHsgY29uc2Vuc3VzID0gZGVmYXVsdE9wdGlvbnMgfSkgPT4gY29uc2Vuc3VzLmVuYWJsZWQpLFxuICAgICAgZGlzdGluY3RVbnRpbENoYW5nZWQoKSxcbiAgICAgIHN3aXRjaE1hcCgoZW5hYmxlZCkgPT4ge1xuICAgICAgICBpZiAoZW5hYmxlZCkge1xuICAgICAgICAgIGNvbnN0IG11dGFibGVDb25zZW5zdXMgPSBuZXcgQ29uc2Vuc3VzKHtcbiAgICAgICAgICAgIG1vbml0b3I6IHRoaXMubW9uaXRvcixcbiAgICAgICAgICAgIG9wdGlvbnMkOiB0aGlzLm9wdGlvbnMkLnBpcGUoXG4gICAgICAgICAgICAgIG1hcCgoeyBjb25zZW5zdXMgPSBkZWZhdWx0T3B0aW9ucyB9KSA9PiBjb25zZW5zdXMub3B0aW9ucyksXG4gICAgICAgICAgICAgIGRpc3RpbmN0VW50aWxDaGFuZ2VkKCksXG4gICAgICAgICAgICApLFxuXG4gICAgICAgICAgICBub2RlOiB0aGlzLFxuICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgdGhpcy5tdXRhYmxlQ29uc2Vuc3VzID0gbXV0YWJsZUNvbnNlbnN1cztcblxuICAgICAgICAgIHJldHVybiBtdXRhYmxlQ29uc2Vuc3VzLnN0YXJ0JCgpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIF9vZih1bmRlZmluZWQpO1xuICAgICAgfSksXG4gICAgKTtcblxuICAgIGNvbnN0IG9wdGlvbnMkID0gdGhpcy5vcHRpb25zJC5waXBlKFxuICAgICAgbWFwKCh7IHVuaGVhbHRoeVBlZXJTZWNvbmRzID0gVU5IRUFMVEhZX1BFRVJfU0VDT05EUyB9KSA9PiB7XG4gICAgICAgIHRoaXMubXV0YWJsZVVuaGVhbHRoeVBlZXJTZWNvbmRzID0gdW5oZWFsdGh5UGVlclNlY29uZHM7XG4gICAgICB9KSxcbiAgICApO1xuXG4gICAgcmV0dXJuIGNvbWJpbmVMYXRlc3QobmV0d29yayQsIGNvbnNlbnN1cyQsIG9wdGlvbnMkKTtcbiAgfVxuXG4gIHB1YmxpYyBhc3luYyByZWxheVRyYW5zYWN0aW9uKFxuICAgIHRyYW5zYWN0aW9uOiBUcmFuc2FjdGlvbixcbiAgICB7XG4gICAgICB0aHJvd1ZlcmlmeUVycm9yID0gZmFsc2UsXG4gICAgICBmb3JjZUFkZCA9IGZhbHNlLFxuICAgIH06IHsgcmVhZG9ubHkgdGhyb3dWZXJpZnlFcnJvcj86IGJvb2xlYW47IHJlYWRvbmx5IGZvcmNlQWRkPzogYm9vbGVhbiB9ID0ge1xuICAgICAgdGhyb3dWZXJpZnlFcnJvcjogZmFsc2UsXG4gICAgICBmb3JjZUFkZDogZmFsc2UsXG4gICAgfSxcbiAgKTogUHJvbWlzZTxSZWxheVRyYW5zYWN0aW9uUmVzdWx0PiB7XG4gICAgY29uc3QgcmVzdWx0ID0ge307XG5cbiAgICBpZiAoXG4gICAgICB0cmFuc2FjdGlvbi50eXBlID09PSBUcmFuc2FjdGlvblR5cGUuTWluZXIgfHxcbiAgICAgICh0aGlzLm11dGFibGVNZW1Qb29sW3RyYW5zYWN0aW9uLmhhc2hIZXhdIGFzIFRyYW5zYWN0aW9uIHwgdW5kZWZpbmVkKSAhPT0gdW5kZWZpbmVkIHx8XG4gICAgICB0aGlzLnRlbXBLbm93blRyYW5zYWN0aW9uSGFzaGVzLmhhcyh0cmFuc2FjdGlvbi5oYXNoSGV4KVxuICAgICkge1xuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9XG5cbiAgICBpZiAoIXRoaXMubXV0YWJsZUtub3duVHJhbnNhY3Rpb25IYXNoZXMuaGFzKHRyYW5zYWN0aW9uLmhhc2gpKSB7XG4gICAgICB0aGlzLnRlbXBLbm93blRyYW5zYWN0aW9uSGFzaGVzLmFkZCh0cmFuc2FjdGlvbi5oYXNoSGV4KTtcblxuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgbWVtUG9vbCA9IE9iamVjdC52YWx1ZXModGhpcy5tdXRhYmxlTWVtUG9vbCk7XG4gICAgICAgIGlmIChtZW1Qb29sLmxlbmd0aCA+IE1FTV9QT09MX1NJWkUgLyAyICYmICFmb3JjZUFkZCkge1xuICAgICAgICAgIHRoaXMubXV0YWJsZUtub3duVHJhbnNhY3Rpb25IYXNoZXMuYWRkKHRyYW5zYWN0aW9uLmhhc2gpO1xuXG4gICAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIHRzbGludDpkaXNhYmxlLW5leHQtbGluZSBwcmVmZXItaW1tZWRpYXRlLXJldHVyblxuICAgICAgICBjb25zdCBmaW5hbFJlc3VsdCA9IGF3YWl0IHRoaXMubW9uaXRvclxuICAgICAgICAgIC53aXRoRGF0YSh7IFtsYWJlbHMuTkVPX1RSQU5TQUNUSU9OX0hBU0hdOiB0cmFuc2FjdGlvbi5oYXNoSGV4IH0pXG4gICAgICAgICAgLmNhcHR1cmVTcGFuTG9nKFxuICAgICAgICAgICAgYXN5bmMgKHNwYW4pID0+IHtcbiAgICAgICAgICAgICAgbGV0IGZvdW5kVHJhbnNhY3Rpb247XG4gICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgZm91bmRUcmFuc2FjdGlvbiA9IGF3YWl0IHRoaXMuYmxvY2tjaGFpbi50cmFuc2FjdGlvbi50cnlHZXQoe1xuICAgICAgICAgICAgICAgICAgaGFzaDogdHJhbnNhY3Rpb24uaGFzaCxcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgICAgICAgICBzcGFuLnNldExhYmVscyh7XG4gICAgICAgICAgICAgICAgICBbbGFiZWxzLk5FT19UUkFOU0FDVElPTl9GT1VORF06IGZvdW5kVHJhbnNhY3Rpb24gIT09IHVuZGVmaW5lZCxcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICBsZXQgdmVyaWZ5UmVzdWx0OiBWZXJpZnlUcmFuc2FjdGlvblJlc3VsdCB8IHVuZGVmaW5lZDtcbiAgICAgICAgICAgICAgaWYgKGZvdW5kVHJhbnNhY3Rpb24gPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgIHZlcmlmeVJlc3VsdCA9IGF3YWl0IHRoaXMuYmxvY2tjaGFpbi52ZXJpZnlUcmFuc2FjdGlvbih7XG4gICAgICAgICAgICAgICAgICBtb25pdG9yOiBzcGFuLFxuICAgICAgICAgICAgICAgICAgdHJhbnNhY3Rpb24sXG4gICAgICAgICAgICAgICAgICBtZW1Qb29sOiBPYmplY3QudmFsdWVzKHRoaXMubXV0YWJsZU1lbVBvb2wpLFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIGNvbnN0IHZlcmlmaWVkID0gdmVyaWZ5UmVzdWx0LnZlcmlmaWNhdGlvbnMuZXZlcnkoKHsgZmFpbHVyZU1lc3NhZ2UgfSkgPT4gZmFpbHVyZU1lc3NhZ2UgPT09IHVuZGVmaW5lZCk7XG5cbiAgICAgICAgICAgICAgICBpZiAodmVyaWZpZWQpIHtcbiAgICAgICAgICAgICAgICAgIHRoaXMubXV0YWJsZU1lbVBvb2xbdHJhbnNhY3Rpb24uaGFzaEhleF0gPSB0cmFuc2FjdGlvbjtcbiAgICAgICAgICAgICAgICAgIE5FT19QUk9UT0NPTF9NRU1QT09MX1NJWkUuaW5jKCk7XG4gICAgICAgICAgICAgICAgICBpZiAodGhpcy5tdXRhYmxlQ29uc2Vuc3VzICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5tdXRhYmxlQ29uc2Vuc3VzLm9uVHJhbnNhY3Rpb25SZWNlaXZlZCh0cmFuc2FjdGlvbik7XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICB0aGlzLnJlbGF5VHJhbnNhY3Rpb25JbnRlcm5hbCh0cmFuc2FjdGlvbik7XG4gICAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnRyaW1NZW1Qb29sKHNwYW4pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgIHRoaXMubXV0YWJsZUtub3duVHJhbnNhY3Rpb25IYXNoZXMuYWRkKHRyYW5zYWN0aW9uLmhhc2gpO1xuXG4gICAgICAgICAgICAgIHJldHVybiB7IHZlcmlmeVJlc3VsdCB9O1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgbmFtZTogJ25lb19yZWxheV90cmFuc2FjdGlvbicsXG4gICAgICAgICAgICAgIGxldmVsOiB7IGxvZzogJ3ZlcmJvc2UnLCBzcGFuOiAnaW5mbycgfSxcbiAgICAgICAgICAgICAgdHJhY2U6IHRydWUsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICk7XG5cbiAgICAgICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lIG5vLXZhci1iZWZvcmUtcmV0dXJuXG4gICAgICAgIHJldHVybiBmaW5hbFJlc3VsdDtcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIGlmIChcbiAgICAgICAgICBlcnJvci5jb2RlID09PSB1bmRlZmluZWQgfHxcbiAgICAgICAgICB0eXBlb2YgZXJyb3IuY29kZSAhPT0gJ3N0cmluZycgfHxcbiAgICAgICAgICAhZXJyb3IuY29kZS5pbmNsdWRlcygnVkVSSUZZJykgfHxcbiAgICAgICAgICB0aHJvd1ZlcmlmeUVycm9yXG4gICAgICAgICkge1xuICAgICAgICAgIHRocm93IGVycm9yO1xuICAgICAgICB9XG4gICAgICB9IGZpbmFsbHkge1xuICAgICAgICB0aGlzLnRlbXBLbm93blRyYW5zYWN0aW9uSGFzaGVzLmRlbGV0ZSh0cmFuc2FjdGlvbi5oYXNoSGV4KTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG5cbiAgcHVibGljIGFzeW5jIHJlbGF5QmxvY2soYmxvY2s6IEJsb2NrLCBtb25pdG9yPzogTW9uaXRvcik6IFByb21pc2U8dm9pZD4ge1xuICAgIGF3YWl0IHRoaXMucGVyc2lzdEJsb2NrKGJsb2NrLCBtb25pdG9yKTtcbiAgfVxuXG4gIHB1YmxpYyByZWxheUNvbnNlbnN1c1BheWxvYWQocGF5bG9hZDogQ29uc2Vuc3VzUGF5bG9hZCk6IHZvaWQge1xuICAgIGNvbnN0IG1lc3NhZ2UgPSB0aGlzLmNyZWF0ZU1lc3NhZ2Uoe1xuICAgICAgY29tbWFuZDogQ29tbWFuZC5pbnYsXG4gICAgICBwYXlsb2FkOiBuZXcgSW52UGF5bG9hZCh7XG4gICAgICAgIHR5cGU6IEludmVudG9yeVR5cGUuQ29uc2Vuc3VzLFxuICAgICAgICBoYXNoZXM6IFtwYXlsb2FkLmhhc2hdLFxuICAgICAgfSksXG4gICAgfSk7XG5cbiAgICB0aGlzLmNvbnNlbnN1c0NhY2hlLnNldChwYXlsb2FkLmhhc2hIZXgsIHBheWxvYWQpO1xuICAgIHRoaXMucmVsYXkobWVzc2FnZSk7XG4gIH1cblxuICBwdWJsaWMgc3luY01lbVBvb2woKTogdm9pZCB7XG4gICAgdGhpcy5yZWxheSh0aGlzLmNyZWF0ZU1lc3NhZ2UoeyBjb21tYW5kOiBDb21tYW5kLm1lbXBvb2wgfSkpO1xuICB9XG5cbiAgcHJpdmF0ZSByZWxheShtZXNzYWdlOiBNZXNzYWdlKTogdm9pZCB7XG4gICAgdGhpcy5uZXR3b3JrLnJlbGF5KG1lc3NhZ2Uuc2VyaWFsaXplV2lyZSgpKTtcbiAgfVxuXG4gIHByaXZhdGUgcmVsYXlUcmFuc2FjdGlvbkludGVybmFsKHRyYW5zYWN0aW9uOiBUcmFuc2FjdGlvbik6IHZvaWQge1xuICAgIGNvbnN0IG1lc3NhZ2UgPSB0aGlzLmNyZWF0ZU1lc3NhZ2Uoe1xuICAgICAgY29tbWFuZDogQ29tbWFuZC5pbnYsXG4gICAgICBwYXlsb2FkOiBuZXcgSW52UGF5bG9hZCh7XG4gICAgICAgIHR5cGU6IEludmVudG9yeVR5cGUuVHJhbnNhY3Rpb24sXG4gICAgICAgIGhhc2hlczogW3RyYW5zYWN0aW9uLmhhc2hdLFxuICAgICAgfSksXG4gICAgfSk7XG5cbiAgICBjb25zdCBtZXNzYWdlUGF5bG9hZCA9IG1lc3NhZ2Uuc2VyaWFsaXplV2lyZSgpO1xuICAgIHRoaXMubmV0d29yay5jb25uZWN0ZWRQZWVycy5mb3JFYWNoKChwZWVyKSA9PiB7XG4gICAgICBpZiAocGVlci5yZWxheSAmJiB0aGlzLnRlc3RGaWx0ZXIocGVlci5kYXRhLm11dGFibGVCbG9vbUZpbHRlciwgdHJhbnNhY3Rpb24pKSB7XG4gICAgICAgIHBlZXIud3JpdGUobWVzc2FnZVBheWxvYWQpO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBzZW5kTWVzc2FnZShwZWVyOiBQZWVyPE1lc3NhZ2U+IHwgQ29ubmVjdGVkUGVlcjxNZXNzYWdlLCBQZWVyRGF0YT4sIG1lc3NhZ2U6IE1lc3NhZ2UpOiB2b2lkIHtcbiAgICBwZWVyLndyaXRlKG1lc3NhZ2Uuc2VyaWFsaXplV2lyZSgpKTtcbiAgfVxuICBwcml2YXRlIHJlYWRvbmx5IG5lZ290aWF0ZSA9IGFzeW5jIChwZWVyOiBQZWVyPE1lc3NhZ2U+KTogUHJvbWlzZTxOZWdvdGlhdGVSZXN1bHQ8UGVlckRhdGE+PiA9PiB7XG4gICAgdGhpcy5zZW5kTWVzc2FnZShcbiAgICAgIHBlZXIsXG4gICAgICB0aGlzLmNyZWF0ZU1lc3NhZ2Uoe1xuICAgICAgICBjb21tYW5kOiBDb21tYW5kLnZlcnNpb24sXG4gICAgICAgIHBheWxvYWQ6IG5ldyBWZXJzaW9uUGF5bG9hZCh7XG4gICAgICAgICAgcHJvdG9jb2xWZXJzaW9uOiAwLFxuICAgICAgICAgIHNlcnZpY2VzOiBTRVJWSUNFUy5OT0RFX05FVFdPUkssXG4gICAgICAgICAgdGltZXN0YW1wOiBNYXRoLnJvdW5kKERhdGUubm93KCkgLyAxMDAwKSxcbiAgICAgICAgICBwb3J0OiB0aGlzLmV4dGVybmFsUG9ydCxcbiAgICAgICAgICBub25jZTogdGhpcy5ub25jZSxcbiAgICAgICAgICB1c2VyQWdlbnQ6IHRoaXMudXNlckFnZW50LFxuICAgICAgICAgIHN0YXJ0SGVpZ2h0OiB0aGlzLmJsb2NrY2hhaW4uY3VycmVudEJsb2NrSW5kZXgsXG4gICAgICAgICAgcmVsYXk6IHRydWUsXG4gICAgICAgIH0pLFxuICAgICAgfSksXG4gICAgKTtcblxuICAgIGNvbnN0IG1lc3NhZ2UgPSBhd2FpdCBwZWVyLnJlY2VpdmVNZXNzYWdlKDMwMDAwKTtcbiAgICBsZXQgdmVyc2lvblBheWxvYWQ7XG4gICAgaWYgKG1lc3NhZ2UudmFsdWUuY29tbWFuZCA9PT0gQ29tbWFuZC52ZXJzaW9uKSB7XG4gICAgICB2ZXJzaW9uUGF5bG9hZCA9IG1lc3NhZ2UudmFsdWUucGF5bG9hZDtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhyb3cgbmV3IE5lZ290aWF0aW9uRXJyb3IobWVzc2FnZSk7XG4gICAgfVxuXG4gICAgdGhpcy5jaGVja1ZlcnNpb24ocGVlciwgbWVzc2FnZSwgdmVyc2lvblBheWxvYWQpO1xuXG4gICAgY29uc3QgeyBob3N0IH0gPSBnZXRFbmRwb2ludENvbmZpZyhwZWVyLmVuZHBvaW50KTtcbiAgICBsZXQgYWRkcmVzcztcbiAgICBpZiAoTmV0d29ya0FkZHJlc3MuaXNWYWxpZChob3N0KSkge1xuICAgICAgYWRkcmVzcyA9IG5ldyBOZXR3b3JrQWRkcmVzcyh7XG4gICAgICAgIGhvc3QsXG4gICAgICAgIHBvcnQ6IHZlcnNpb25QYXlsb2FkLnBvcnQsXG4gICAgICAgIHRpbWVzdGFtcDogdmVyc2lvblBheWxvYWQudGltZXN0YW1wLFxuICAgICAgICBzZXJ2aWNlczogdmVyc2lvblBheWxvYWQuc2VydmljZXMsXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICB0aGlzLnNlbmRNZXNzYWdlKHBlZXIsIHRoaXMuY3JlYXRlTWVzc2FnZSh7IGNvbW1hbmQ6IENvbW1hbmQudmVyYWNrIH0pKTtcblxuICAgIGNvbnN0IG5leHRNZXNzYWdlID0gYXdhaXQgcGVlci5yZWNlaXZlTWVzc2FnZSgzMDAwMCk7XG4gICAgaWYgKG5leHRNZXNzYWdlLnZhbHVlLmNvbW1hbmQgIT09IENvbW1hbmQudmVyYWNrKSB7XG4gICAgICB0aHJvdyBuZXcgTmVnb3RpYXRpb25FcnJvcihuZXh0TWVzc2FnZSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIGRhdGE6IHtcbiAgICAgICAgbm9uY2U6IHZlcnNpb25QYXlsb2FkLm5vbmNlLFxuICAgICAgICBzdGFydEhlaWdodDogdmVyc2lvblBheWxvYWQuc3RhcnRIZWlnaHQsXG4gICAgICAgIG11dGFibGVCbG9vbUZpbHRlcjogdW5kZWZpbmVkLFxuICAgICAgICBhZGRyZXNzLFxuICAgICAgfSxcblxuICAgICAgcmVsYXk6IHZlcnNpb25QYXlsb2FkLnJlbGF5LFxuICAgIH07XG4gIH07XG4gIHByaXZhdGUgcmVhZG9ubHkgY2hlY2tQZWVySGVhbHRoID0gKHBlZXI6IENvbm5lY3RlZFBlZXI8TWVzc2FnZSwgUGVlckRhdGE+LCBwcmV2SGVhbHRoPzogUGVlckhlYWx0aCkgPT4ge1xuICAgIGNvbnN0IGNoZWNrVGltZVNlY29uZHMgPSBjb21tb25VdGlscy5ub3dTZWNvbmRzKCk7XG4gICAgY29uc3QgYmxvY2tJbmRleCA9IHRoaXMubXV0YWJsZUJsb2NrSW5kZXhbcGVlci5lbmRwb2ludF0gYXMgbnVtYmVyIHwgdW5kZWZpbmVkO1xuXG4gICAgLy8gSWYgZmlyc3QgY2hlY2sgLT4gaGVhbHRoeVxuICAgIGlmIChwcmV2SGVhbHRoID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHJldHVybiB7IGhlYWx0aHk6IHRydWUsIGNoZWNrVGltZVNlY29uZHMsIGJsb2NrSW5kZXggfTtcbiAgICB9XG5cbiAgICAvLyBJZiBzZWVuIG5ldyBibG9jayAtPiBoZWFsdGh5ICsgdXBkYXRlIGNoZWNrIHRpbWVcbiAgICBpZiAocHJldkhlYWx0aC5ibG9ja0luZGV4ICE9PSB1bmRlZmluZWQgJiYgYmxvY2tJbmRleCAhPT0gdW5kZWZpbmVkICYmIHByZXZIZWFsdGguYmxvY2tJbmRleCA8IGJsb2NrSW5kZXgpIHtcbiAgICAgIHJldHVybiB7IGhlYWx0aHk6IHRydWUsIGNoZWNrVGltZVNlY29uZHMsIGJsb2NrSW5kZXggfTtcbiAgICB9XG5cbiAgICAvLyBJZiBub3Qgc2VlbiBhIGJsb2NrIG9yIGEgbmV3IGJsb2NrIEJVVCBpdCBoYXMgTk9UIGJlZW4gYSBsb25nXG4gICAgLy8gdGltZSAtPiBoZWFsdGh5XG4gICAgaWYgKFxuICAgICAgcHJldkhlYWx0aC5ibG9ja0luZGV4ID09PSBibG9ja0luZGV4ICYmXG4gICAgICBjb21tb25VdGlscy5ub3dTZWNvbmRzKCkgLSBwcmV2SGVhbHRoLmNoZWNrVGltZVNlY29uZHMgPCB0aGlzLm11dGFibGVVbmhlYWx0aHlQZWVyU2Vjb25kc1xuICAgICkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgaGVhbHRoeTogdHJ1ZSxcbiAgICAgICAgY2hlY2tUaW1lU2Vjb25kczogcHJldkhlYWx0aC5jaGVja1RpbWVTZWNvbmRzLFxuICAgICAgICBibG9ja0luZGV4OiBwcmV2SGVhbHRoLmJsb2NrSW5kZXgsXG4gICAgICB9O1xuICAgIH1cblxuICAgIHJldHVybiB7IGhlYWx0aHk6IGZhbHNlLCBjaGVja1RpbWVTZWNvbmRzLCBibG9ja0luZGV4IH07XG4gIH07XG4gIHByaXZhdGUgcmVhZG9ubHkgb25FdmVudCA9IChldmVudDogTmV0d29ya0V2ZW50TWVzc2FnZTxNZXNzYWdlLCBQZWVyRGF0YT4pID0+IHtcbiAgICBpZiAoZXZlbnQuZXZlbnQgPT09ICdQRUVSX0NPTk5FQ1RfU1VDQ0VTUycpIHtcbiAgICAgIGNvbnN0IHsgY29ubmVjdGVkUGVlciB9ID0gZXZlbnQ7XG4gICAgICBpZiAoXG4gICAgICAgIHRoaXMubXV0YWJsZUJlc3RQZWVyID09PSB1bmRlZmluZWQgfHxcbiAgICAgICAgLy8gT25seSBjaGFuZ2UgYmVzdCBwZWVyIGF0IG1vc3QgZXZlcnkgMTAwIGJsb2Nrc1xuICAgICAgICB0aGlzLm11dGFibGVCZXN0UGVlci5kYXRhLnN0YXJ0SGVpZ2h0ICsgMTAwIDwgY29ubmVjdGVkUGVlci5kYXRhLnN0YXJ0SGVpZ2h0XG4gICAgICApIHtcbiAgICAgICAgdGhpcy5tdXRhYmxlQmVzdFBlZXIgPSBjb25uZWN0ZWRQZWVyO1xuICAgICAgICB0aGlzLnJlc2V0UmVxdWVzdEJsb2NrcygpO1xuICAgICAgICB0aGlzLnJlcXVlc3RCbG9ja3MoKTtcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKFxuICAgICAgZXZlbnQuZXZlbnQgPT09ICdQRUVSX0NMT1NFRCcgJiZcbiAgICAgIHRoaXMubXV0YWJsZUJlc3RQZWVyICE9PSB1bmRlZmluZWQgJiZcbiAgICAgIHRoaXMubXV0YWJsZUJlc3RQZWVyLmVuZHBvaW50ID09PSBldmVudC5wZWVyLmVuZHBvaW50XG4gICAgKSB7XG4gICAgICB0aGlzLm11dGFibGVCZXN0UGVlciA9IHRoaXMuZmluZEJlc3RQZWVyKCk7XG4gICAgICB0aGlzLnJlc2V0UmVxdWVzdEJsb2NrcygpO1xuICAgICAgdGhpcy5yZXF1ZXN0QmxvY2tzKCk7XG4gICAgfVxuICB9O1xuXG4gIHByaXZhdGUgZmluZEJlc3RQZWVyKGJlc3RQZWVyPzogQ29ubmVjdGVkUGVlcjxNZXNzYWdlLCBQZWVyRGF0YT4pOiBDb25uZWN0ZWRQZWVyPE1lc3NhZ2UsIFBlZXJEYXRhPiB8IHVuZGVmaW5lZCB7XG4gICAgbGV0IHBlZXJzID0gdGhpcy5uZXR3b3JrLmNvbm5lY3RlZFBlZXJzO1xuICAgIGlmIChiZXN0UGVlciAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBwZWVycyA9IHBlZXJzLmZpbHRlcigocGVlcikgPT4gcGVlci5lbmRwb2ludCAhPT0gYmVzdFBlZXIuZW5kcG9pbnQpO1xuICAgIH1cbiAgICBjb25zdCByZXN1bHQgPSBfLm1heEJ5KHBlZXJzLCAocGVlcikgPT4gcGVlci5kYXRhLnN0YXJ0SGVpZ2h0KTtcbiAgICBpZiAocmVzdWx0ID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuXG4gICAgcmV0dXJuIF8uc2h1ZmZsZShwZWVycy5maWx0ZXIoKHBlZXIpID0+IHBlZXIuZGF0YS5zdGFydEhlaWdodCA9PT0gcmVzdWx0LmRhdGEuc3RhcnRIZWlnaHQpKVswXTtcbiAgfVxuXG4gIHByaXZhdGUgcmVzZXRSZXF1ZXN0QmxvY2tzKCk6IHZvaWQge1xuICAgIHRoaXMubXV0YWJsZUdldEJsb2Nrc1JlcXVlc3RzSW5kZXggPSB1bmRlZmluZWQ7XG4gICAgdGhpcy5tdXRhYmxlR2V0QmxvY2tzUmVxdWVzdHNDb3VudCA9IDA7XG4gIH1cblxuICBwcml2YXRlIHNob3VsZFJlcXVlc3RCbG9ja3MoKTogYm9vbGVhbiB7XG4gICAgY29uc3QgYmxvY2sgPSB0aGlzLmJsb2NrY2hhaW4uY3VycmVudEJsb2NrO1xuICAgIGNvbnN0IGdldEJsb2Nrc1JlcXVlc3RUaW1lID0gdGhpcy5tdXRhYmxlR2V0QmxvY2tzUmVxdWVzdFRpbWU7XG5cbiAgICByZXR1cm4gKFxuICAgICAgdGhpcy5tdXRhYmxlR2V0QmxvY2tzUmVxdWVzdHNJbmRleCA9PT0gdW5kZWZpbmVkIHx8XG4gICAgICBibG9jay5pbmRleCAtIHRoaXMubXV0YWJsZUdldEJsb2Nrc1JlcXVlc3RzSW5kZXggPiBHRVRfQkxPQ0tTX0JVRkZFUiB8fFxuICAgICAgZ2V0QmxvY2tzUmVxdWVzdFRpbWUgPT09IHVuZGVmaW5lZCB8fFxuICAgICAgRGF0ZS5ub3coKSAtIGdldEJsb2Nrc1JlcXVlc3RUaW1lID4gR0VUX0JMT0NLU19USU1FX01TXG4gICAgKTtcbiAgfVxuXG4gIHByaXZhdGUgY2hlY2tWZXJzaW9uKHBlZXI6IFBlZXI8TWVzc2FnZT4sIG1lc3NhZ2U6IE1lc3NhZ2UsIHZlcnNpb246IFZlcnNpb25QYXlsb2FkKTogdm9pZCB7XG4gICAgaWYgKHZlcnNpb24ubm9uY2UgPT09IHRoaXMubm9uY2UpIHtcbiAgICAgIHRoaXMubmV0d29yay5wZXJtYW5lbnRseUJsYWNrbGlzdChwZWVyLmVuZHBvaW50KTtcbiAgICAgIHRocm93IG5ldyBOZWdvdGlhdGlvbkVycm9yKG1lc3NhZ2UsICdOb25jZSBlcXVhbHMgbXkgbm9uY2UuJyk7XG4gICAgfVxuXG4gICAgY29uc3QgY29ubmVjdGVkUGVlciA9IHRoaXMubmV0d29yay5jb25uZWN0ZWRQZWVycy5maW5kKChvdGhlclBlZXIpID0+IHZlcnNpb24ubm9uY2UgPT09IG90aGVyUGVlci5kYXRhLm5vbmNlKTtcblxuICAgIGlmIChjb25uZWN0ZWRQZWVyICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHRocm93IG5ldyBBbHJlYWR5Q29ubmVjdGVkRXJyb3IoJ0FscmVhZHkgY29ubmVjdGVkIHRvIG5vbmNlLicpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgcmVhZHkoKTogYm9vbGVhbiB7XG4gICAgY29uc3QgcGVlciA9IHRoaXMubXV0YWJsZUJlc3RQZWVyO1xuICAgIGNvbnN0IGJsb2NrID0gdGhpcy5ibG9ja2NoYWluLmN1cnJlbnRCbG9jaztcblxuICAgIHJldHVybiBwZWVyICE9PSB1bmRlZmluZWQgJiYgYmxvY2suaW5kZXggPj0gcGVlci5kYXRhLnN0YXJ0SGVpZ2h0O1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBmZXRjaEVuZHBvaW50c0Zyb21SUEMoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHRoaXMuZG9GZXRjaEVuZHBvaW50c0Zyb21SUEMoKTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIC8vIGlnbm9yZSwgbG9nZ2VkIGRlZXBlciBpbiB0aGUgc3RhY2tcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGRvRmV0Y2hFbmRwb2ludHNGcm9tUlBDKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IHsgcnBjVVJMcyA9IFtdIH0gPSBhd2FpdCB0aGlzLm9wdGlvbnMkLnBpcGUodGFrZSgxKSkudG9Qcm9taXNlKCk7XG4gICAgYXdhaXQgUHJvbWlzZS5hbGwocnBjVVJMcy5tYXAoYXN5bmMgKHJwY1VSTCkgPT4gdGhpcy5mZXRjaEVuZHBvaW50c0Zyb21SUENVUkwocnBjVVJMKSkpO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBmZXRjaEVuZHBvaW50c0Zyb21SUENVUkwocnBjVVJMOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaChycGNVUkwsIHtcbiAgICAgICAgbWV0aG9kOiAnUE9TVCcsXG4gICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nLFxuICAgICAgICB9LFxuICAgICAgICBib2R5OiBKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgICAganNvbnJwYzogJzIuMCcsXG4gICAgICAgICAgaWQ6IDEsXG4gICAgICAgICAgbWV0aG9kOiAnZ2V0cGVlcnMnLFxuICAgICAgICAgIHBhcmFtczogW10sXG4gICAgICAgIH0pLFxuICAgICAgfSk7XG5cbiAgICAgIGlmICghcmVzcG9uc2Uub2spIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBGYWlsZWQgdG8gZmV0Y2ggcGVlcnMgZnJvbSAke3JwY1VSTH06ICR7cmVzcG9uc2Uuc3RhdHVzfSAke3Jlc3BvbnNlLnN0YXR1c1RleHR9YCk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHJlc3BvbnNlLmpzb24oKTtcblxuICAgICAgaWYgKFxuICAgICAgICB0eXBlb2YgcmVzdWx0ID09PSAnb2JqZWN0JyAmJlxuICAgICAgICByZXN1bHQuZXJyb3IgIT09IHVuZGVmaW5lZCAmJlxuICAgICAgICB0eXBlb2YgcmVzdWx0LmVycm9yID09PSAnb2JqZWN0JyAmJlxuICAgICAgICB0eXBlb2YgcmVzdWx0LmVycm9yLmNvZGUgPT09ICdudW1iZXInICYmXG4gICAgICAgIHR5cGVvZiByZXN1bHQuZXJyb3IubWVzc2FnZSA9PT0gJ3N0cmluZydcbiAgICAgICkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IocmVzdWx0LmVycm9yKTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgY29ubmVjdGVkOiBSZWFkb25seUFycmF5PHsgcmVhZG9ubHkgYWRkcmVzczogc3RyaW5nOyByZWFkb25seSBwb3J0OiBudW1iZXIgfT4gPSByZXN1bHQucmVzdWx0LmNvbm5lY3RlZDtcbiAgICAgIGNvbm5lY3RlZFxuICAgICAgICAubWFwKChwZWVyKSA9PiB7XG4gICAgICAgICAgY29uc3QgeyBhZGRyZXNzLCBwb3J0IH0gPSBwZWVyO1xuICAgICAgICAgIGNvbnN0IGhvc3QgPSBuZXcgQWRkcmVzczYoYWRkcmVzcyk7XG4gICAgICAgICAgY29uc3QgY2Fub25pY2FsRm9ybSA9IGhvc3QuY2Fub25pY2FsRm9ybSgpIGFzIHN0cmluZyB8IHVuZGVmaW5lZCB8IG51bGw7XG5cbiAgICAgICAgICByZXR1cm4geyBob3N0OiBjYW5vbmljYWxGb3JtID09IHVuZGVmaW5lZCA/ICcnIDogY2Fub25pY2FsRm9ybSwgcG9ydCB9O1xuICAgICAgICB9KVxuICAgICAgICAuZmlsdGVyKChlbmRwb2ludCkgPT4gIUxPQ0FMX0hPU1RfQUREUkVTU0VTLmhhcyhlbmRwb2ludC5ob3N0KSlcbiAgICAgICAgLm1hcCgoZW5kcG9pbnQpID0+XG4gICAgICAgICAgY3JlYXRlRW5kcG9pbnQoe1xuICAgICAgICAgICAgdHlwZTogJ3RjcCcsXG4gICAgICAgICAgICBob3N0OiBlbmRwb2ludC5ob3N0LFxuICAgICAgICAgICAgcG9ydDogZW5kcG9pbnQucG9ydCxcbiAgICAgICAgICB9KSxcbiAgICAgICAgKVxuICAgICAgICAuZm9yRWFjaCgoZW5kcG9pbnQpID0+IHRoaXMubmV0d29yay5hZGRFbmRwb2ludChlbmRwb2ludCkpO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICB0aGlzLm1vbml0b3Iud2l0aERhdGEoeyBbdGhpcy5tb25pdG9yLmxhYmVscy5IVFRQX1VSTF06IHJwY1VSTCB9KS5sb2dFcnJvcih7XG4gICAgICAgIG5hbWU6ICduZW9fcHJvdG9jb2xfZmV0Y2hfZW5kcG9pbnRzX2Vycm9yJyxcbiAgICAgICAgbWVzc2FnZTogYEZhaWxlZCB0byBmZXRjaCBlbmRwb2ludHMgZnJvbSAke3JwY1VSTH1gLFxuICAgICAgICBlcnJvcixcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgb25NZXNzYWdlUmVjZWl2ZWQocGVlcjogQ29ubmVjdGVkUGVlcjxNZXNzYWdlLCBQZWVyRGF0YT4sIG1lc3NhZ2U6IE1lc3NhZ2UpOiB2b2lkIHtcbiAgICB0aGlzLm1vbml0b3JcbiAgICAgIC53aXRoTGFiZWxzKHsgW2xhYmVscy5DT01NQU5EX05BTUVdOiBtZXNzYWdlLnZhbHVlLmNvbW1hbmQgfSlcbiAgICAgIC53aXRoRGF0YSh7IFt0aGlzLm1vbml0b3IubGFiZWxzLlBFRVJfQUREUkVTU106IHBlZXIuZW5kcG9pbnQgfSlcbiAgICAgIC5jYXB0dXJlTG9nKFxuICAgICAgICBhc3luYyAobW9uaXRvcikgPT4ge1xuICAgICAgICAgIHN3aXRjaCAobWVzc2FnZS52YWx1ZS5jb21tYW5kKSB7XG4gICAgICAgICAgICBjYXNlIENvbW1hbmQuYWRkcjpcbiAgICAgICAgICAgICAgdGhpcy5vbkFkZHJNZXNzYWdlUmVjZWl2ZWQobW9uaXRvciwgbWVzc2FnZS52YWx1ZS5wYXlsb2FkKTtcbiAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIENvbW1hbmQuYmxvY2s6XG4gICAgICAgICAgICAgIGF3YWl0IHRoaXMub25CbG9ja01lc3NhZ2VSZWNlaXZlZChtb25pdG9yLCBwZWVyLCBtZXNzYWdlLnZhbHVlLnBheWxvYWQpO1xuXG4gICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSBDb21tYW5kLmNvbnNlbnN1czpcbiAgICAgICAgICAgICAgYXdhaXQgdGhpcy5vbkNvbnNlbnN1c01lc3NhZ2VSZWNlaXZlZChtb25pdG9yLCBtZXNzYWdlLnZhbHVlLnBheWxvYWQpO1xuXG4gICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSBDb21tYW5kLmZpbHRlcmFkZDpcbiAgICAgICAgICAgICAgdGhpcy5vbkZpbHRlckFkZE1lc3NhZ2VSZWNlaXZlZChtb25pdG9yLCBwZWVyLCBtZXNzYWdlLnZhbHVlLnBheWxvYWQpO1xuXG4gICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSBDb21tYW5kLmZpbHRlcmNsZWFyOlxuICAgICAgICAgICAgICB0aGlzLm9uRmlsdGVyQ2xlYXJNZXNzYWdlUmVjZWl2ZWQobW9uaXRvciwgcGVlcik7XG4gICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSBDb21tYW5kLmZpbHRlcmxvYWQ6XG4gICAgICAgICAgICAgIHRoaXMub25GaWx0ZXJMb2FkTWVzc2FnZVJlY2VpdmVkKG1vbml0b3IsIHBlZXIsIG1lc3NhZ2UudmFsdWUucGF5bG9hZCk7XG5cbiAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIENvbW1hbmQuZ2V0YWRkcjpcbiAgICAgICAgICAgICAgdGhpcy5vbkdldEFkZHJNZXNzYWdlUmVjZWl2ZWQobW9uaXRvciwgcGVlcik7XG4gICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSBDb21tYW5kLmdldGJsb2NrczpcbiAgICAgICAgICAgICAgYXdhaXQgdGhpcy5vbkdldEJsb2Nrc01lc3NhZ2VSZWNlaXZlZChtb25pdG9yLCBwZWVyLCBtZXNzYWdlLnZhbHVlLnBheWxvYWQpO1xuXG4gICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSBDb21tYW5kLmdldGRhdGE6XG4gICAgICAgICAgICAgIGF3YWl0IHRoaXMub25HZXREYXRhTWVzc2FnZVJlY2VpdmVkKG1vbml0b3IsIHBlZXIsIG1lc3NhZ2UudmFsdWUucGF5bG9hZCk7XG5cbiAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIENvbW1hbmQuZ2V0aGVhZGVyczpcbiAgICAgICAgICAgICAgYXdhaXQgdGhpcy5vbkdldEhlYWRlcnNNZXNzYWdlUmVjZWl2ZWQobW9uaXRvciwgcGVlciwgbWVzc2FnZS52YWx1ZS5wYXlsb2FkKTtcblxuICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgQ29tbWFuZC5oZWFkZXJzOlxuICAgICAgICAgICAgICBhd2FpdCB0aGlzLm9uSGVhZGVyc01lc3NhZ2VSZWNlaXZlZChtb25pdG9yLCBwZWVyLCBtZXNzYWdlLnZhbHVlLnBheWxvYWQpO1xuXG4gICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSBDb21tYW5kLmludjpcbiAgICAgICAgICAgICAgdGhpcy5vbkludk1lc3NhZ2VSZWNlaXZlZChtb25pdG9yLCBwZWVyLCBtZXNzYWdlLnZhbHVlLnBheWxvYWQpO1xuICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgQ29tbWFuZC5tZW1wb29sOlxuICAgICAgICAgICAgICB0aGlzLm9uTWVtUG9vbE1lc3NhZ2VSZWNlaXZlZChtb25pdG9yLCBwZWVyKTtcbiAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIENvbW1hbmQudHg6XG4gICAgICAgICAgICAgIGF3YWl0IHRoaXMub25UcmFuc2FjdGlvblJlY2VpdmVkKG1vbml0b3IsIG1lc3NhZ2UudmFsdWUucGF5bG9hZCk7XG4gICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSBDb21tYW5kLnZlcmFjazpcbiAgICAgICAgICAgICAgdGhpcy5vblZlcmFja01lc3NhZ2VSZWNlaXZlZChtb25pdG9yLCBwZWVyKTtcbiAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIENvbW1hbmQudmVyc2lvbjpcbiAgICAgICAgICAgICAgdGhpcy5vblZlcnNpb25NZXNzYWdlUmVjZWl2ZWQobW9uaXRvciwgcGVlcik7XG4gICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSBDb21tYW5kLmFsZXJ0OlxuICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgQ29tbWFuZC5tZXJrbGVibG9jazpcbiAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIENvbW1hbmQubm90Zm91bmQ6XG4gICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSBDb21tYW5kLnBpbmc6XG4gICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSBDb21tYW5kLnBvbmc6XG4gICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSBDb21tYW5kLnJlamVjdDpcbiAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICBjb21tb25VdGlscy5hc3NlcnROZXZlcihtZXNzYWdlLnZhbHVlKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBuYW1lOiAnbmVvX3Byb3RvY29sX21lc3NhZ2VfcmVjZWl2ZWQnLFxuICAgICAgICAgIGxldmVsOiAnZGVidWcnLFxuICAgICAgICAgIG1lc3NhZ2U6IGBSZWNlaXZlZCAke21lc3NhZ2UudmFsdWUuY29tbWFuZH0gZnJvbSAke3BlZXIuZW5kcG9pbnR9YCxcbiAgICAgICAgICBtZXRyaWM6IE5FT19QUk9UT0NPTF9NRVNTQUdFU19SRUNFSVZFRF9UT1RBTCxcbiAgICAgICAgICBlcnJvcjoge1xuICAgICAgICAgICAgbWV0cmljOiBORU9fUFJPVE9DT0xfTUVTU0FHRVNfRkFJTFVSRVNfVE9UQUwsXG4gICAgICAgICAgICBtZXNzYWdlOiBgRmFpbGVkIHRvIHByb2Nlc3MgbWVzc2FnZSAke21lc3NhZ2UudmFsdWUuY29tbWFuZH0gZnJvbSAke3BlZXIuZW5kcG9pbnR9YCxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgKVxuICAgICAgLmNhdGNoKCgpID0+IHtcbiAgICAgICAgLy8gZG8gbm90aGluZ1xuICAgICAgfSk7XG4gIH1cblxuICBwcml2YXRlIG9uQWRkck1lc3NhZ2VSZWNlaXZlZChfbW9uaXRvcjogTW9uaXRvciwgYWRkcjogQWRkclBheWxvYWQpOiB2b2lkIHtcbiAgICBhZGRyLmFkZHJlc3Nlc1xuICAgICAgLmZpbHRlcigoYWRkcmVzcykgPT4gIUxPQ0FMX0hPU1RfQUREUkVTU0VTLmhhcyhhZGRyZXNzLmhvc3QpKVxuICAgICAgLm1hcCgoYWRkcmVzcykgPT5cbiAgICAgICAgY3JlYXRlRW5kcG9pbnQoe1xuICAgICAgICAgIHR5cGU6ICd0Y3AnLFxuICAgICAgICAgIGhvc3Q6IGFkZHJlc3MuaG9zdCxcbiAgICAgICAgICBwb3J0OiBhZGRyZXNzLnBvcnQsXG4gICAgICAgIH0pLFxuICAgICAgKVxuICAgICAgLmZvckVhY2goKGVuZHBvaW50KSA9PiB0aGlzLm5ldHdvcmsuYWRkRW5kcG9pbnQoZW5kcG9pbnQpKTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgb25CbG9ja01lc3NhZ2VSZWNlaXZlZChcbiAgICBtb25pdG9yOiBNb25pdG9yLFxuICAgIHBlZXI6IENvbm5lY3RlZFBlZXI8TWVzc2FnZSwgUGVlckRhdGE+LFxuICAgIGJsb2NrOiBCbG9jayxcbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgYmxvY2tJbmRleCA9IHRoaXMubXV0YWJsZUJsb2NrSW5kZXhbcGVlci5lbmRwb2ludF0gYXMgbnVtYmVyIHwgdW5kZWZpbmVkO1xuICAgIHRoaXMubXV0YWJsZUJsb2NrSW5kZXhbcGVlci5lbmRwb2ludF0gPSBNYXRoLm1heChibG9jay5pbmRleCwgYmxvY2tJbmRleCA9PT0gdW5kZWZpbmVkID8gMCA6IGJsb2NrSW5kZXgpO1xuXG4gICAgYXdhaXQgdGhpcy5yZWxheUJsb2NrKGJsb2NrLCBtb25pdG9yKTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgcGVyc2lzdEJsb2NrKGJsb2NrOiBCbG9jaywgbW9uaXRvcjogTW9uaXRvciA9IHRoaXMubW9uaXRvcik6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICh0aGlzLmJsb2NrY2hhaW4uY3VycmVudEJsb2NrSW5kZXggPiBibG9jay5pbmRleCB8fCB0aGlzLnRlbXBLbm93bkJsb2NrSGFzaGVzLmhhcyhibG9jay5oYXNoSGV4KSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmICghdGhpcy5tdXRhYmxlS25vd25CbG9ja0hhc2hlcy5oYXMoYmxvY2suaGFzaCkpIHtcbiAgICAgIHRoaXMudGVtcEtub3duQmxvY2tIYXNoZXMuYWRkKGJsb2NrLmhhc2hIZXgpO1xuXG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCBmb3VuZEJsb2NrID0gYXdhaXQgdGhpcy5ibG9ja2NoYWluLmJsb2NrLnRyeUdldCh7XG4gICAgICAgICAgaGFzaE9ySW5kZXg6IGJsb2NrLmhhc2gsXG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmIChmb3VuZEJsb2NrID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICBhd2FpdCBtb25pdG9yLndpdGhEYXRhKHsgW2xhYmVscy5ORU9fQkxPQ0tfSU5ERVhdOiBibG9jay5pbmRleCB9KS5jYXB0dXJlU3BhbkxvZyhcbiAgICAgICAgICAgIGFzeW5jIChzcGFuKSA9PiB7XG4gICAgICAgICAgICAgIGF3YWl0IHRoaXMuYmxvY2tjaGFpbi5wZXJzaXN0QmxvY2soeyBtb25pdG9yOiBzcGFuLCBibG9jayB9KTtcbiAgICAgICAgICAgICAgaWYgKHRoaXMubXV0YWJsZUNvbnNlbnN1cyAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5tdXRhYmxlQ29uc2Vuc3VzLm9uUGVyc2lzdEJsb2NrKCk7XG4gICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICBjb25zdCBwZWVyID0gdGhpcy5tdXRhYmxlQmVzdFBlZXI7XG4gICAgICAgICAgICAgIGlmIChwZWVyICE9PSB1bmRlZmluZWQgJiYgYmxvY2suaW5kZXggPiBwZWVyLmRhdGEuc3RhcnRIZWlnaHQpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnJlbGF5KFxuICAgICAgICAgICAgICAgICAgdGhpcy5jcmVhdGVNZXNzYWdlKHtcbiAgICAgICAgICAgICAgICAgICAgY29tbWFuZDogQ29tbWFuZC5pbnYsXG4gICAgICAgICAgICAgICAgICAgIHBheWxvYWQ6IG5ldyBJbnZQYXlsb2FkKHtcbiAgICAgICAgICAgICAgICAgICAgICB0eXBlOiBJbnZlbnRvcnlUeXBlLkJsb2NrLFxuICAgICAgICAgICAgICAgICAgICAgIGhhc2hlczogW2Jsb2NrLmhhc2hdLFxuICAgICAgICAgICAgICAgICAgICB9KSxcbiAgICAgICAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIG5hbWU6ICduZW9fcmVsYXlfYmxvY2snLFxuICAgICAgICAgICAgICBsZXZlbDogeyBsb2c6ICd2ZXJib3NlJywgc3BhbjogJ2luZm8nIH0sXG4gICAgICAgICAgICAgIHRyYWNlOiB0cnVlLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5tdXRhYmxlS25vd25CbG9ja0hhc2hlcy5hZGQoYmxvY2suaGFzaCk7XG4gICAgICAgIHRoaXMubXV0YWJsZUtub3duSGVhZGVySGFzaGVzLmFkZChibG9jay5oYXNoKTtcbiAgICAgICAgYmxvY2sudHJhbnNhY3Rpb25zLmZvckVhY2goKHRyYW5zYWN0aW9uKSA9PiB7XG4gICAgICAgICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lIG5vLWR5bmFtaWMtZGVsZXRlXG4gICAgICAgICAgZGVsZXRlIHRoaXMubXV0YWJsZU1lbVBvb2xbdHJhbnNhY3Rpb24uaGFzaEhleF07XG4gICAgICAgICAgdGhpcy5tdXRhYmxlS25vd25UcmFuc2FjdGlvbkhhc2hlcy5hZGQodHJhbnNhY3Rpb24uaGFzaCk7XG4gICAgICAgIH0pO1xuICAgICAgICBORU9fUFJPVE9DT0xfTUVNUE9PTF9TSVpFLnNldChPYmplY3Qua2V5cyh0aGlzLm11dGFibGVNZW1Qb29sKS5sZW5ndGgpO1xuICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgdGhpcy50ZW1wS25vd25CbG9ja0hhc2hlcy5kZWxldGUoYmxvY2suaGFzaEhleCk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBvbkNvbnNlbnN1c01lc3NhZ2VSZWNlaXZlZChtb25pdG9yOiBNb25pdG9yLCBwYXlsb2FkOiBDb25zZW5zdXNQYXlsb2FkKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgeyBjb25zZW5zdXMgfSA9IHRoaXM7XG4gICAgaWYgKGNvbnNlbnN1cyAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBhd2FpdCB0aGlzLmJsb2NrY2hhaW4udmVyaWZ5Q29uc2Vuc3VzUGF5bG9hZChwYXlsb2FkLCBtb25pdG9yKTtcbiAgICAgIGNvbnNlbnN1cy5vbkNvbnNlbnN1c1BheWxvYWRSZWNlaXZlZChwYXlsb2FkKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIG9uRmlsdGVyQWRkTWVzc2FnZVJlY2VpdmVkKFxuICAgIF9tb25pdG9yOiBNb25pdG9yLFxuICAgIHBlZXI6IENvbm5lY3RlZFBlZXI8TWVzc2FnZSwgUGVlckRhdGE+LFxuICAgIGZpbHRlckFkZDogRmlsdGVyQWRkUGF5bG9hZCxcbiAgKTogdm9pZCB7XG4gICAgaWYgKHBlZXIuZGF0YS5tdXRhYmxlQmxvb21GaWx0ZXIgIT09IHVuZGVmaW5lZCkge1xuICAgICAgcGVlci5kYXRhLm11dGFibGVCbG9vbUZpbHRlci5pbnNlcnQoZmlsdGVyQWRkLmRhdGEpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgb25GaWx0ZXJDbGVhck1lc3NhZ2VSZWNlaXZlZChfbW9uaXRvcjogTW9uaXRvciwgcGVlcjogQ29ubmVjdGVkUGVlcjxNZXNzYWdlLCBQZWVyRGF0YT4pOiB2b2lkIHtcbiAgICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmUgbm8tb2JqZWN0LW11dGF0aW9uXG4gICAgcGVlci5kYXRhLm11dGFibGVCbG9vbUZpbHRlciA9IHVuZGVmaW5lZDtcbiAgfVxuXG4gIHByaXZhdGUgb25GaWx0ZXJMb2FkTWVzc2FnZVJlY2VpdmVkKFxuICAgIF9tb25pdG9yOiBNb25pdG9yLFxuICAgIHBlZXI6IENvbm5lY3RlZFBlZXI8TWVzc2FnZSwgUGVlckRhdGE+LFxuICAgIGZpbHRlckxvYWQ6IEZpbHRlckxvYWRQYXlsb2FkLFxuICApOiB2b2lkIHtcbiAgICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmUgbm8tb2JqZWN0LW11dGF0aW9uXG4gICAgcGVlci5kYXRhLm11dGFibGVCbG9vbUZpbHRlciA9IGNyZWF0ZVBlZXJCbG9vbUZpbHRlcihmaWx0ZXJMb2FkKTtcbiAgfVxuXG4gIHByaXZhdGUgb25HZXRBZGRyTWVzc2FnZVJlY2VpdmVkKF9tb25pdG9yOiBNb25pdG9yLCBwZWVyOiBDb25uZWN0ZWRQZWVyPE1lc3NhZ2UsIFBlZXJEYXRhPik6IHZvaWQge1xuICAgIGNvbnN0IGFkZHJlc3NlcyA9IF8udGFrZShcbiAgICAgIF8uc2h1ZmZsZShcbiAgICAgICAgdGhpcy5uZXR3b3JrLmNvbm5lY3RlZFBlZXJzLm1hcCgoY29ubmVjdGVkUGVlcikgPT4gY29ubmVjdGVkUGVlci5kYXRhLmFkZHJlc3MpLmZpbHRlcihjb21tb25VdGlscy5ub3ROdWxsKSxcbiAgICAgICksXG4gICAgICBHRVRfQUREUl9QRUVSX0NPVU5ULFxuICAgICk7XG5cbiAgICBpZiAoYWRkcmVzc2VzLmxlbmd0aCA+IDApIHtcbiAgICAgIHRoaXMuc2VuZE1lc3NhZ2UoXG4gICAgICAgIHBlZXIsXG4gICAgICAgIHRoaXMuY3JlYXRlTWVzc2FnZSh7XG4gICAgICAgICAgY29tbWFuZDogQ29tbWFuZC5hZGRyLFxuICAgICAgICAgIHBheWxvYWQ6IG5ldyBBZGRyUGF5bG9hZCh7IGFkZHJlc3NlcyB9KSxcbiAgICAgICAgfSksXG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgb25HZXRCbG9ja3NNZXNzYWdlUmVjZWl2ZWQoXG4gICAgX21vbml0b3I6IE1vbml0b3IsXG4gICAgcGVlcjogQ29ubmVjdGVkUGVlcjxNZXNzYWdlLCBQZWVyRGF0YT4sXG4gICAgZ2V0QmxvY2tzOiBHZXRCbG9ja3NQYXlsb2FkLFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBoZWFkZXJzID0gYXdhaXQgdGhpcy5nZXRIZWFkZXJzKGdldEJsb2NrcywgdGhpcy5ibG9ja2NoYWluLmN1cnJlbnRCbG9ja0luZGV4KTtcblxuICAgIHRoaXMuc2VuZE1lc3NhZ2UoXG4gICAgICBwZWVyLFxuICAgICAgdGhpcy5jcmVhdGVNZXNzYWdlKHtcbiAgICAgICAgY29tbWFuZDogQ29tbWFuZC5pbnYsXG4gICAgICAgIHBheWxvYWQ6IG5ldyBJbnZQYXlsb2FkKHtcbiAgICAgICAgICB0eXBlOiBJbnZlbnRvcnlUeXBlLkJsb2NrLFxuICAgICAgICAgIGhhc2hlczogaGVhZGVycy5tYXAoKGhlYWRlcikgPT4gaGVhZGVyLmhhc2gpLFxuICAgICAgICB9KSxcbiAgICAgIH0pLFxuICAgICk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIG9uR2V0RGF0YU1lc3NhZ2VSZWNlaXZlZChcbiAgICBfbW9uaXRvcjogTW9uaXRvcixcbiAgICBwZWVyOiBDb25uZWN0ZWRQZWVyPE1lc3NhZ2UsIFBlZXJEYXRhPixcbiAgICBnZXREYXRhOiBJbnZQYXlsb2FkLFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBzd2l0Y2ggKGdldERhdGEudHlwZSkge1xuICAgICAgY2FzZSBJbnZlbnRvcnlUeXBlLlRyYW5zYWN0aW9uOlxuICAgICAgICBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgICAgICBnZXREYXRhLmhhc2hlcy5tYXAoYXN5bmMgKGhhc2gpID0+IHtcbiAgICAgICAgICAgIGxldCB0cmFuc2FjdGlvbiA9IHRoaXMubXV0YWJsZU1lbVBvb2xbY29tbW9uLnVJbnQyNTZUb0hleChoYXNoKV0gYXMgVHJhbnNhY3Rpb24gfCB1bmRlZmluZWQ7XG4gICAgICAgICAgICBpZiAodHJhbnNhY3Rpb24gPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICB0cmFuc2FjdGlvbiA9IGF3YWl0IHRoaXMuYmxvY2tjaGFpbi50cmFuc2FjdGlvbi50cnlHZXQoeyBoYXNoIH0pO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAodHJhbnNhY3Rpb24gIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICB0aGlzLnNlbmRNZXNzYWdlKFxuICAgICAgICAgICAgICAgIHBlZXIsXG4gICAgICAgICAgICAgICAgdGhpcy5jcmVhdGVNZXNzYWdlKHtcbiAgICAgICAgICAgICAgICAgIGNvbW1hbmQ6IENvbW1hbmQudHgsXG4gICAgICAgICAgICAgICAgICBwYXlsb2FkOiB0cmFuc2FjdGlvbixcbiAgICAgICAgICAgICAgICB9KSxcbiAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KSxcbiAgICAgICAgKTtcblxuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgSW52ZW50b3J5VHlwZS5CbG9jazogLy8gQmxvY2tcbiAgICAgICAgYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICAgICAgZ2V0RGF0YS5oYXNoZXMubWFwKGFzeW5jIChoYXNoKSA9PiB7XG4gICAgICAgICAgICBjb25zdCBibG9jayA9IGF3YWl0IHRoaXMuYmxvY2tjaGFpbi5ibG9jay50cnlHZXQoe1xuICAgICAgICAgICAgICBoYXNoT3JJbmRleDogaGFzaCxcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICBpZiAoYmxvY2sgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICBpZiAocGVlci5kYXRhLm11dGFibGVCbG9vbUZpbHRlciA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zZW5kTWVzc2FnZShcbiAgICAgICAgICAgICAgICAgIHBlZXIsXG4gICAgICAgICAgICAgICAgICB0aGlzLmNyZWF0ZU1lc3NhZ2Uoe1xuICAgICAgICAgICAgICAgICAgICBjb21tYW5kOiBDb21tYW5kLmJsb2NrLFxuICAgICAgICAgICAgICAgICAgICBwYXlsb2FkOiBibG9jayxcbiAgICAgICAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zZW5kTWVzc2FnZShcbiAgICAgICAgICAgICAgICAgIHBlZXIsXG4gICAgICAgICAgICAgICAgICB0aGlzLmNyZWF0ZU1lc3NhZ2Uoe1xuICAgICAgICAgICAgICAgICAgICBjb21tYW5kOiBDb21tYW5kLm1lcmtsZWJsb2NrLFxuICAgICAgICAgICAgICAgICAgICBwYXlsb2FkOiB0aGlzLmNyZWF0ZU1lcmtsZUJsb2NrUGF5bG9hZCh7XG4gICAgICAgICAgICAgICAgICAgICAgYmxvY2ssXG4gICAgICAgICAgICAgICAgICAgICAgZmxhZ3M6IGJsb2NrLnRyYW5zYWN0aW9ucy5tYXAoKHRyYW5zYWN0aW9uKSA9PlxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy50ZXN0RmlsdGVyKHBlZXIuZGF0YS5tdXRhYmxlQmxvb21GaWx0ZXIsIHRyYW5zYWN0aW9uKSxcbiAgICAgICAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICAgICAgICB9KSxcbiAgICAgICAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KSxcbiAgICAgICAgKTtcblxuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgSW52ZW50b3J5VHlwZS5Db25zZW5zdXM6IC8vIENvbnNlbnN1c1xuICAgICAgICBnZXREYXRhLmhhc2hlcy5mb3JFYWNoKChoYXNoKSA9PiB7XG4gICAgICAgICAgY29uc3QgcGF5bG9hZCA9IHRoaXMuY29uc2Vuc3VzQ2FjaGUuZ2V0KGNvbW1vbi51SW50MjU2VG9IZXgoaGFzaCkpO1xuICAgICAgICAgIGlmIChwYXlsb2FkICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIHRoaXMuc2VuZE1lc3NhZ2UoXG4gICAgICAgICAgICAgIHBlZXIsXG4gICAgICAgICAgICAgIHRoaXMuY3JlYXRlTWVzc2FnZSh7XG4gICAgICAgICAgICAgICAgY29tbWFuZDogQ29tbWFuZC5jb25zZW5zdXMsXG4gICAgICAgICAgICAgICAgcGF5bG9hZCxcbiAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgZGVmYXVsdDpcbiAgICAgICAgY29tbW9uVXRpbHMuYXNzZXJ0TmV2ZXIoZ2V0RGF0YS50eXBlKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIG9uR2V0SGVhZGVyc01lc3NhZ2VSZWNlaXZlZChcbiAgICBfbW9uaXRvcjogTW9uaXRvcixcbiAgICBwZWVyOiBDb25uZWN0ZWRQZWVyPE1lc3NhZ2UsIFBlZXJEYXRhPixcbiAgICBnZXRCbG9ja3M6IEdldEJsb2Nrc1BheWxvYWQsXG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IGhlYWRlcnMgPSBhd2FpdCB0aGlzLmdldEhlYWRlcnMoZ2V0QmxvY2tzLCB0aGlzLmJsb2NrY2hhaW4uY3VycmVudEhlYWRlci5pbmRleCk7XG5cbiAgICB0aGlzLnNlbmRNZXNzYWdlKFxuICAgICAgcGVlcixcbiAgICAgIHRoaXMuY3JlYXRlTWVzc2FnZSh7XG4gICAgICAgIGNvbW1hbmQ6IENvbW1hbmQuaGVhZGVycyxcbiAgICAgICAgcGF5bG9hZDogbmV3IEhlYWRlcnNQYXlsb2FkKHsgaGVhZGVycyB9KSxcbiAgICAgIH0pLFxuICAgICk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIG9uSGVhZGVyc01lc3NhZ2VSZWNlaXZlZChcbiAgICBfbW9uaXRvcjogTW9uaXRvcixcbiAgICBwZWVyOiBDb25uZWN0ZWRQZWVyPE1lc3NhZ2UsIFBlZXJEYXRhPixcbiAgICBoZWFkZXJzUGF5bG9hZDogSGVhZGVyc1BheWxvYWQsXG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IGhlYWRlcnMgPSBoZWFkZXJzUGF5bG9hZC5oZWFkZXJzLmZpbHRlcihcbiAgICAgIChoZWFkZXIpID0+ICF0aGlzLm11dGFibGVLbm93bkhlYWRlckhhc2hlcy5oYXMoaGVhZGVyLmhhc2gpICYmICF0aGlzLnRlbXBLbm93bkhlYWRlckhhc2hlcy5oYXMoaGVhZGVyLmhhc2hIZXgpLFxuICAgICk7XG5cbiAgICBpZiAoaGVhZGVycy5sZW5ndGggPiAwKSB7XG4gICAgICBoZWFkZXJzLmZvckVhY2goKGhlYWRlcikgPT4ge1xuICAgICAgICB0aGlzLnRlbXBLbm93bkhlYWRlckhhc2hlcy5hZGQoaGVhZGVyLmhhc2hIZXgpO1xuICAgICAgfSk7XG4gICAgICB0cnkge1xuICAgICAgICBhd2FpdCB0aGlzLmJsb2NrY2hhaW4ucGVyc2lzdEhlYWRlcnMoaGVhZGVycyk7XG4gICAgICAgIGhlYWRlcnMuZm9yRWFjaCgoaGVhZGVyKSA9PiB7XG4gICAgICAgICAgdGhpcy5tdXRhYmxlS25vd25IZWFkZXJIYXNoZXMuYWRkKGhlYWRlci5oYXNoKTtcbiAgICAgICAgfSk7XG4gICAgICB9IGZpbmFsbHkge1xuICAgICAgICBoZWFkZXJzLmZvckVhY2goKGhlYWRlcikgPT4ge1xuICAgICAgICAgIHRoaXMudGVtcEtub3duSGVhZGVySGFzaGVzLmRlbGV0ZShoZWFkZXIuaGFzaEhleCk7XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmICh0aGlzLmJsb2NrY2hhaW4uY3VycmVudEhlYWRlci5pbmRleCA8IHBlZXIuZGF0YS5zdGFydEhlaWdodCkge1xuICAgICAgdGhpcy5zZW5kTWVzc2FnZShcbiAgICAgICAgcGVlcixcbiAgICAgICAgdGhpcy5jcmVhdGVNZXNzYWdlKHtcbiAgICAgICAgICBjb21tYW5kOiBDb21tYW5kLmdldGhlYWRlcnMsXG4gICAgICAgICAgcGF5bG9hZDogbmV3IEdldEJsb2Nrc1BheWxvYWQoe1xuICAgICAgICAgICAgaGFzaFN0YXJ0OiBbdGhpcy5ibG9ja2NoYWluLmN1cnJlbnRIZWFkZXIuaGFzaF0sXG4gICAgICAgICAgfSksXG4gICAgICAgIH0pLFxuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIG9uSW52TWVzc2FnZVJlY2VpdmVkKF9tb25pdG9yOiBNb25pdG9yLCBwZWVyOiBDb25uZWN0ZWRQZWVyPE1lc3NhZ2UsIFBlZXJEYXRhPiwgaW52OiBJbnZQYXlsb2FkKTogdm9pZCB7XG4gICAgbGV0IGhhc2hlcztcbiAgICBzd2l0Y2ggKGludi50eXBlKSB7XG4gICAgICBjYXNlIEludmVudG9yeVR5cGUuVHJhbnNhY3Rpb246IC8vIFRyYW5zYWN0aW9uXG4gICAgICAgIGhhc2hlcyA9IGludi5oYXNoZXMuZmlsdGVyKFxuICAgICAgICAgIChoYXNoKSA9PlxuICAgICAgICAgICAgIXRoaXMubXV0YWJsZUtub3duVHJhbnNhY3Rpb25IYXNoZXMuaGFzKGhhc2gpICYmXG4gICAgICAgICAgICAhdGhpcy50ZW1wS25vd25UcmFuc2FjdGlvbkhhc2hlcy5oYXMoY29tbW9uLnVJbnQyNTZUb0hleChoYXNoKSksXG4gICAgICAgICk7XG5cbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIEludmVudG9yeVR5cGUuQmxvY2s6IC8vIEJsb2NrXG4gICAgICAgIGhhc2hlcyA9IGludi5oYXNoZXMuZmlsdGVyKFxuICAgICAgICAgIChoYXNoKSA9PlxuICAgICAgICAgICAgIXRoaXMubXV0YWJsZUtub3duQmxvY2tIYXNoZXMuaGFzKGhhc2gpICYmICF0aGlzLnRlbXBLbm93bkJsb2NrSGFzaGVzLmhhcyhjb21tb24udUludDI1NlRvSGV4KGhhc2gpKSxcbiAgICAgICAgKTtcblxuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgSW52ZW50b3J5VHlwZS5Db25zZW5zdXM6IC8vIENvbnNlbnN1c1xuICAgICAgICBoYXNoZXMgPSBpbnYuaGFzaGVzO1xuICAgICAgICBicmVhaztcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIGNvbW1vblV0aWxzLmFzc2VydE5ldmVyKGludi50eXBlKTtcbiAgICAgICAgaGFzaGVzID0gW107XG4gICAgfVxuXG4gICAgaWYgKGhhc2hlcy5sZW5ndGggPiAwKSB7XG4gICAgICB0aGlzLnNlbmRNZXNzYWdlKFxuICAgICAgICBwZWVyLFxuICAgICAgICB0aGlzLmNyZWF0ZU1lc3NhZ2Uoe1xuICAgICAgICAgIGNvbW1hbmQ6IENvbW1hbmQuZ2V0ZGF0YSxcbiAgICAgICAgICBwYXlsb2FkOiBuZXcgSW52UGF5bG9hZCh7IHR5cGU6IGludi50eXBlLCBoYXNoZXMgfSksXG4gICAgICAgIH0pLFxuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIG9uTWVtUG9vbE1lc3NhZ2VSZWNlaXZlZChfbW9uaXRvcjogTW9uaXRvciwgcGVlcjogQ29ubmVjdGVkUGVlcjxNZXNzYWdlLCBQZWVyRGF0YT4pOiB2b2lkIHtcbiAgICB0aGlzLnNlbmRNZXNzYWdlKFxuICAgICAgcGVlcixcbiAgICAgIHRoaXMuY3JlYXRlTWVzc2FnZSh7XG4gICAgICAgIGNvbW1hbmQ6IENvbW1hbmQuaW52LFxuICAgICAgICBwYXlsb2FkOiBuZXcgSW52UGF5bG9hZCh7XG4gICAgICAgICAgdHlwZTogSW52ZW50b3J5VHlwZS5UcmFuc2FjdGlvbixcbiAgICAgICAgICBoYXNoZXM6IE9iamVjdC52YWx1ZXModGhpcy5tdXRhYmxlTWVtUG9vbCkubWFwKCh0cmFuc2FjdGlvbikgPT4gdHJhbnNhY3Rpb24uaGFzaCksXG4gICAgICAgIH0pLFxuICAgICAgfSksXG4gICAgKTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgb25UcmFuc2FjdGlvblJlY2VpdmVkKF9tb25pdG9yOiBNb25pdG9yLCB0cmFuc2FjdGlvbjogVHJhbnNhY3Rpb24pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAodGhpcy5yZWFkeSgpKSB7XG4gICAgICBpZiAodHJhbnNhY3Rpb24udHlwZSA9PT0gVHJhbnNhY3Rpb25UeXBlLk1pbmVyKSB7XG4gICAgICAgIGlmICh0aGlzLm11dGFibGVDb25zZW5zdXMgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIHRoaXMubXV0YWJsZUNvbnNlbnN1cy5vblRyYW5zYWN0aW9uUmVjZWl2ZWQodHJhbnNhY3Rpb24pO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBhd2FpdCB0aGlzLnJlbGF5VHJhbnNhY3Rpb24odHJhbnNhY3Rpb24pO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgb25WZXJhY2tNZXNzYWdlUmVjZWl2ZWQoX21vbml0b3I6IE1vbml0b3IsIHBlZXI6IENvbm5lY3RlZFBlZXI8TWVzc2FnZSwgUGVlckRhdGE+KTogdm9pZCB7XG4gICAgcGVlci5jbG9zZSgpO1xuICB9XG5cbiAgcHJpdmF0ZSBvblZlcnNpb25NZXNzYWdlUmVjZWl2ZWQoX21vbml0b3I6IE1vbml0b3IsIHBlZXI6IENvbm5lY3RlZFBlZXI8TWVzc2FnZSwgUGVlckRhdGE+KTogdm9pZCB7XG4gICAgcGVlci5jbG9zZSgpO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBnZXRIZWFkZXJzKGdldEJsb2NrczogR2V0QmxvY2tzUGF5bG9hZCwgbWF4SGVpZ2h0OiBudW1iZXIpOiBQcm9taXNlPFJlYWRvbmx5QXJyYXk8SGVhZGVyPj4ge1xuICAgIGxldCBoYXNoU3RvcEluZGV4UHJvbWlzZSA9IFByb21pc2UucmVzb2x2ZShtYXhIZWlnaHQpO1xuICAgIGlmICghZ2V0QmxvY2tzLmhhc2hTdG9wLmVxdWFscyhjb21tb24uWkVST19VSU5UMjU2KSkge1xuICAgICAgaGFzaFN0b3BJbmRleFByb21pc2UgPSB0aGlzLmJsb2NrY2hhaW4uaGVhZGVyXG4gICAgICAgIC50cnlHZXQoeyBoYXNoT3JJbmRleDogZ2V0QmxvY2tzLmhhc2hTdG9wIH0pXG4gICAgICAgIC50aGVuKChoYXNoU3RvcEhlYWRlcikgPT5cbiAgICAgICAgICBoYXNoU3RvcEhlYWRlciA9PT0gdW5kZWZpbmVkID8gbWF4SGVpZ2h0IDogTWF0aC5taW4oaGFzaFN0b3BIZWFkZXIuaW5kZXgsIG1heEhlaWdodCksXG4gICAgICAgICk7XG4gICAgfVxuICAgIGNvbnN0IFtoYXNoU3RhcnRIZWFkZXJzLCBoYXNoRW5kXSA9IGF3YWl0IFByb21pc2UuYWxsKFtcbiAgICAgIFByb21pc2UuYWxsKGdldEJsb2Nrcy5oYXNoU3RhcnQubWFwKGFzeW5jIChoYXNoKSA9PiB0aGlzLmJsb2NrY2hhaW4uaGVhZGVyLnRyeUdldCh7IGhhc2hPckluZGV4OiBoYXNoIH0pKSksXG5cbiAgICAgIGhhc2hTdG9wSW5kZXhQcm9taXNlLFxuICAgIF0pO1xuXG4gICAgY29uc3QgaGFzaFN0YXJ0SGVhZGVyID0gXy5oZWFkKF8ub3JkZXJCeShoYXNoU3RhcnRIZWFkZXJzLmZpbHRlcihjb21tb25VdGlscy5ub3ROdWxsKSwgWyhoZWFkZXIpID0+IGhlYWRlci5pbmRleF0pKTtcblxuICAgIGlmIChoYXNoU3RhcnRIZWFkZXIgPT09IHVuZGVmaW5lZCkge1xuICAgICAgcmV0dXJuIFtdO1xuICAgIH1cbiAgICBjb25zdCBoYXNoU3RhcnQgPSBoYXNoU3RhcnRIZWFkZXIuaW5kZXggKyAxO1xuICAgIGlmIChoYXNoU3RhcnQgPiBtYXhIZWlnaHQpIHtcbiAgICAgIHJldHVybiBbXTtcbiAgICB9XG5cbiAgICByZXR1cm4gUHJvbWlzZS5hbGwoXG4gICAgICBfLnJhbmdlKGhhc2hTdGFydCwgTWF0aC5taW4oaGFzaFN0YXJ0ICsgR0VUX0JMT0NLU19DT1VOVCwgaGFzaEVuZCkpLm1hcChhc3luYyAoaW5kZXgpID0+XG4gICAgICAgIHRoaXMuYmxvY2tjaGFpbi5oZWFkZXIuZ2V0KHsgaGFzaE9ySW5kZXg6IGluZGV4IH0pLFxuICAgICAgKSxcbiAgICApO1xuICB9XG5cbiAgcHJpdmF0ZSB0ZXN0RmlsdGVyKGJsb29tRmlsdGVySW46IEJsb29tRmlsdGVyIHwgdW5kZWZpbmVkLCB0cmFuc2FjdGlvbjogVHJhbnNhY3Rpb24pOiBib29sZWFuIHtcbiAgICBjb25zdCBibG9vbUZpbHRlciA9IGJsb29tRmlsdGVySW47XG4gICAgaWYgKGJsb29tRmlsdGVyID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIHJldHVybiAoXG4gICAgICBibG9vbUZpbHRlci5jb250YWlucyh0cmFuc2FjdGlvbi5oYXNoKSB8fFxuICAgICAgdHJhbnNhY3Rpb24ub3V0cHV0cy5zb21lKChvdXRwdXQpID0+IGJsb29tRmlsdGVyLmNvbnRhaW5zKG91dHB1dC5hZGRyZXNzKSkgfHxcbiAgICAgIHRyYW5zYWN0aW9uLmlucHV0cy5zb21lKChpbnB1dCkgPT4gYmxvb21GaWx0ZXIuY29udGFpbnMoaW5wdXQuc2VyaWFsaXplV2lyZSgpKSkgfHxcbiAgICAgIHRyYW5zYWN0aW9uLnNjcmlwdHMuc29tZSgoc2NyaXB0KSA9PiBibG9vbUZpbHRlci5jb250YWlucyhjcnlwdG8udG9TY3JpcHRIYXNoKHNjcmlwdC52ZXJpZmljYXRpb24pKSkgfHxcbiAgICAgICh0cmFuc2FjdGlvbi50eXBlID09PSBUcmFuc2FjdGlvblR5cGUuUmVnaXN0ZXIgJiZcbiAgICAgICAgdHJhbnNhY3Rpb24gaW5zdGFuY2VvZiBSZWdpc3RlclRyYW5zYWN0aW9uICYmXG4gICAgICAgIGJsb29tRmlsdGVyLmNvbnRhaW5zKHRyYW5zYWN0aW9uLmFzc2V0LmFkbWluKSlcbiAgICApO1xuICB9XG5cbiAgcHJpdmF0ZSBjcmVhdGVNZXJrbGVCbG9ja1BheWxvYWQoe1xuICAgIGJsb2NrLFxuICAgIGZsYWdzLFxuICB9OiB7XG4gICAgcmVhZG9ubHkgYmxvY2s6IEJsb2NrO1xuICAgIHJlYWRvbmx5IGZsYWdzOiBSZWFkb25seUFycmF5PGJvb2xlYW4+O1xuICB9KTogTWVya2xlQmxvY2tQYXlsb2FkIHtcbiAgICBjb25zdCB0cmVlID0gbmV3IE1lcmtsZVRyZWUoYmxvY2sudHJhbnNhY3Rpb25zLm1hcCgodHJhbnNhY3Rpb24pID0+IHRyYW5zYWN0aW9uLmhhc2gpKS50cmltKGZsYWdzKTtcblxuICAgIGNvbnN0IG11dGFibGVCdWZmZXIgPSBCdWZmZXIuYWxsb2NVbnNhZmUoTWF0aC5mbG9vcigoZmxhZ3MubGVuZ3RoICsgNykgLyA4KSk7XG4gICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lIG5vLWxvb3Atc3RhdGVtZW50XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBmbGFncy5sZW5ndGg7IGkgKz0gMSkge1xuICAgICAgaWYgKGZsYWdzW2ldKSB7XG4gICAgICAgIC8vIHRzbGludDpkaXNhYmxlLW5leHQtbGluZSBuby1iaXR3aXNlXG4gICAgICAgIG11dGFibGVCdWZmZXJbTWF0aC5mbG9vcihpIC8gOCldIHw9IDEgPDwgaSAlIDg7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIG5ldyBNZXJrbGVCbG9ja1BheWxvYWQoe1xuICAgICAgdmVyc2lvbjogYmxvY2sudmVyc2lvbixcbiAgICAgIHByZXZpb3VzSGFzaDogYmxvY2sucHJldmlvdXNIYXNoLFxuICAgICAgbWVya2xlUm9vdDogYmxvY2subWVya2xlUm9vdCxcbiAgICAgIHRpbWVzdGFtcDogYmxvY2sudGltZXN0YW1wLFxuICAgICAgaW5kZXg6IGJsb2NrLmluZGV4LFxuICAgICAgY29uc2Vuc3VzRGF0YTogYmxvY2suY29uc2Vuc3VzRGF0YSxcbiAgICAgIG5leHRDb25zZW5zdXM6IGJsb2NrLm5leHRDb25zZW5zdXMsXG4gICAgICBzY3JpcHQ6IGJsb2NrLnNjcmlwdCxcbiAgICAgIHRyYW5zYWN0aW9uQ291bnQ6IGJsb2NrLnRyYW5zYWN0aW9ucy5sZW5ndGgsXG4gICAgICBoYXNoZXM6IHRyZWUudG9IYXNoQXJyYXkoKSxcbiAgICAgIGZsYWdzOiBtdXRhYmxlQnVmZmVyLFxuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBjcmVhdGVNZXNzYWdlKHZhbHVlOiBNZXNzYWdlVmFsdWUpOiBNZXNzYWdlIHtcbiAgICByZXR1cm4gbmV3IE1lc3NhZ2Uoe1xuICAgICAgbWFnaWM6IHRoaXMuYmxvY2tjaGFpbi5zZXR0aW5ncy5tZXNzYWdlTWFnaWMsXG4gICAgICB2YWx1ZSxcbiAgICB9KTtcbiAgfVxufVxuIl19