UNPKG

@glimmer/runtime

Version:

Minimal runtime needed to render Glimmer templates

396 lines (338 loc) 38.6 kB
import { DEBUG } from '@glimmer/env'; import { updateRef, valueForRef } from '@glimmer/reference'; import { associateDestroyableChild, destroy, destroyChildren } from '@glimmer/destroyable'; import { Stack, logStep } from '@glimmer/util'; import { resetTracking, runInTrackingTransaction } from '@glimmer/validator'; import { clear, move as moveBounds } from '../bounds'; import { NewElementBuilder } from './element-builder'; export default class UpdatingVMImpl { constructor(env, { alwaysRevalidate = false }) { this.frameStack = new Stack(); this.env = env; this.dom = env.getDOM(); this.alwaysRevalidate = alwaysRevalidate; } execute(opcodes, handler) { if (DEBUG) { let hasErrored = true; try { runInTrackingTransaction(() => this._execute(opcodes, handler), '- While rendering:'); // using a boolean here to avoid breaking ergonomics of "pause on uncaught exceptions" // which would happen with a `catch` + `throw` hasErrored = false; } finally { if (hasErrored) { // eslint-disable-next-line no-console console.error(`\n\nError occurred:\n\n${resetTracking()}\n\n`); } } } else { this._execute(opcodes, handler); } } _execute(opcodes, handler) { let { frameStack } = this; this.try(opcodes, handler); while (true) { if (frameStack.isEmpty()) break; let opcode = this.frame.nextStatement(); if (opcode === undefined) { frameStack.pop(); continue; } opcode.evaluate(this); } } get frame() { return this.frameStack.current; } goto(index) { this.frame.goto(index); } try(ops, handler) { this.frameStack.push(new UpdatingVMFrame(ops, handler)); } throw() { this.frame.handleException(); this.frameStack.pop(); } } export class ResumableVMStateImpl { constructor(state, resumeCallback) { this.state = state; this.resumeCallback = resumeCallback; } resume(runtime, builder) { return this.resumeCallback(runtime, this.state, builder); } } export class BlockOpcode { constructor(state, runtime, bounds, children) { this.state = state; this.runtime = runtime; this.children = children; this.bounds = bounds; } parentElement() { return this.bounds.parentElement(); } firstNode() { return this.bounds.firstNode(); } lastNode() { return this.bounds.lastNode(); } evaluate(vm) { vm.try(this.children, null); } } export class TryOpcode extends BlockOpcode { constructor() { super(...arguments); this.type = 'try'; } evaluate(vm) { vm.try(this.children, this); } handleException() { let { state, bounds, runtime } = this; destroyChildren(this); let elementStack = NewElementBuilder.resume(runtime.env, bounds); let vm = state.resume(runtime, elementStack); let updating = []; let children = this.children = []; let result = vm.execute(vm => { vm.pushUpdating(updating); vm.updateWith(this); vm.pushUpdating(children); }); associateDestroyableChild(this, result.drop); } } export class ListItemOpcode extends TryOpcode { constructor(state, runtime, bounds, key, memo, value) { super(state, runtime, bounds, []); this.key = key; this.memo = memo; this.value = value; this.retained = false; this.index = -1; } updateReferences(item) { this.retained = true; updateRef(this.value, item.value); updateRef(this.memo, item.memo); } shouldRemove() { return !this.retained; } reset() { this.retained = false; } } export class ListBlockOpcode extends BlockOpcode { constructor(state, runtime, bounds, children, iterableRef) { super(state, runtime, bounds, children); this.iterableRef = iterableRef; this.type = 'list-block'; this.opcodeMap = new Map(); this.marker = null; this.lastIterator = valueForRef(iterableRef); } initializeChild(opcode) { opcode.index = this.children.length - 1; this.opcodeMap.set(opcode.key, opcode); } evaluate(vm) { let iterator = valueForRef(this.iterableRef); if (this.lastIterator !== iterator) { let { bounds } = this; let { dom } = vm; let marker = this.marker = dom.createComment(''); dom.insertAfter(bounds.parentElement(), marker, bounds.lastNode()); this.sync(iterator); this.parentElement().removeChild(marker); this.marker = null; this.lastIterator = iterator; } // Run now-updated updating opcodes super.evaluate(vm); } sync(iterator) { let { opcodeMap: itemMap, children } = this; let currentOpcodeIndex = 0; let seenIndex = 0; this.children = this.bounds.boundList = []; while (true) { let item = iterator.next(); if (item === null) break; let opcode = children[currentOpcodeIndex]; let { key } = item; // Items that have already been found and moved will already be retained, // we can continue until we find the next unretained item while (opcode !== undefined && opcode.retained === true) { opcode = children[++currentOpcodeIndex]; } if (opcode !== undefined && opcode.key === key) { this.retainItem(opcode, item); currentOpcodeIndex++; } else if (itemMap.has(key)) { let itemOpcode = itemMap.get(key); // The item opcode was seen already, so we should move it. if (itemOpcode.index < seenIndex) { this.moveItem(itemOpcode, item, opcode); } else { // Update the seen index, we are going to be moving this item around // so any other items that come before it will likely need to move as // well. seenIndex = itemOpcode.index; let seenUnretained = false; // iterate through all of the opcodes between the current position and // the position of the item's opcode, and determine if they are all // retained. for (let i = currentOpcodeIndex + 1; i < seenIndex; i++) { if (children[i].retained === false) { seenUnretained = true; break; } } // If we have seen only retained opcodes between this and the matching // opcode, it means that all the opcodes in between have been moved // already, and we can safely retain this item's opcode. if (seenUnretained === false) { this.retainItem(itemOpcode, item); currentOpcodeIndex = seenIndex + 1; } else { this.moveItem(itemOpcode, item, opcode); currentOpcodeIndex++; } } } else { this.insertItem(item, opcode); } } for (let i = 0; i < children.length; i++) { let opcode = children[i]; if (opcode.retained === false) { this.deleteItem(opcode); } else { opcode.reset(); } } } retainItem(opcode, item) { if (false /* LOCAL_DEBUG */ ) { logStep('list-updates', ['retain', item.key]); } let { children } = this; updateRef(opcode.memo, item.memo); updateRef(opcode.value, item.value); opcode.retained = true; opcode.index = children.length; children.push(opcode); } insertItem(item, before) { if (false /* LOCAL_DEBUG */ ) { logStep('list-updates', ['insert', item.key]); } let { opcodeMap, bounds, state, runtime, children } = this; let { key } = item; let nextSibling = before === undefined ? this.marker : before.firstNode(); let elementStack = NewElementBuilder.forInitialRender(runtime.env, { element: bounds.parentElement(), nextSibling }); let vm = state.resume(runtime, elementStack); vm.execute(vm => { vm.pushUpdating(); let opcode = vm.enterItem(item); opcode.index = children.length; children.push(opcode); opcodeMap.set(key, opcode); associateDestroyableChild(this, opcode); }); } moveItem(opcode, item, before) { let { children } = this; updateRef(opcode.memo, item.memo); updateRef(opcode.value, item.value); opcode.retained = true; let currentSibling, nextSibling; if (before === undefined) { moveBounds(opcode, this.marker); } else { currentSibling = opcode.lastNode().nextSibling; nextSibling = before.firstNode(); // Items are moved throughout the algorithm, so there are cases where the // the items already happen to be siblings (e.g. an item in between was // moved before this move happened). Check to see if they are siblings // first before doing the move. if (currentSibling !== nextSibling) { moveBounds(opcode, nextSibling); } } opcode.index = children.length; children.push(opcode); if (false /* LOCAL_DEBUG */ ) { let type = currentSibling && currentSibling === nextSibling ? 'move-retain' : 'move'; logStep('list-updates', [type, item.key]); } } deleteItem(opcode) { if (false /* LOCAL_DEBUG */ ) { logStep('list-updates', ['delete', opcode.key]); } destroy(opcode); clear(opcode); this.opcodeMap.delete(opcode.key); } } class UpdatingVMFrame { constructor(ops, exceptionHandler) { this.ops = ops; this.exceptionHandler = exceptionHandler; this.current = 0; } goto(index) { this.current = index; } nextStatement() { return this.ops[this.current++]; } handleException() { if (this.exceptionHandler) { this.exceptionHandler.handleException(); } } } //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3BhY2thZ2VzL0BnbGltbWVyL3J1bnRpbWUvbGliL3ZtL3VwZGF0ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxTQUFTLEtBQVQsUUFBc0IsY0FBdEI7QUFpQkEsU0FJRSxTQUpGLEVBS0UsV0FMRixRQU1PLG9CQU5QO0FBT0EsU0FBUyx5QkFBVCxFQUFvQyxPQUFwQyxFQUE2QyxlQUE3QyxRQUFvRSxzQkFBcEU7QUFDQSxTQUFpQixLQUFqQixFQUF3QixPQUF4QixRQUF1QyxlQUF2QztBQUNBLFNBQVMsYUFBVCxFQUF3Qix3QkFBeEIsUUFBd0Qsb0JBQXhEO0FBRUEsU0FBUyxLQUFULEVBQWdCLElBQUksSUFBSSxVQUF4QixRQUEwQyxXQUExQztBQUVBLFNBQXdCLGlCQUF4QixRQUFpRCxtQkFBakQ7QUFFQSxlQUFjLE1BQU8sY0FBUCxDQUFxQjtBQU9qQyxFQUFBLFdBQUEsQ0FBWSxHQUFaLEVBQThCO0FBQUUsSUFBQSxnQkFBZ0IsR0FBRztBQUFyQixHQUE5QixFQUEwRDtBQUZsRCxTQUFBLFVBQUEsR0FBcUMsSUFBSSxLQUFKLEVBQXJDO0FBR04sU0FBSyxHQUFMLEdBQVcsR0FBWDtBQUNBLFNBQUssR0FBTCxHQUFXLEdBQUcsQ0FBQyxNQUFKLEVBQVg7QUFDQSxTQUFLLGdCQUFMLEdBQXdCLGdCQUF4QjtBQUNEOztBQUVELEVBQUEsT0FBTyxDQUFDLE9BQUQsRUFBNEIsT0FBNUIsRUFBcUQ7QUFDMUQsUUFBSSxLQUFKLEVBQVc7QUFDVCxVQUFJLFVBQVUsR0FBRyxJQUFqQjs7QUFDQSxVQUFJO0FBQ0YsUUFBQSx3QkFBeUIsQ0FBQyxNQUFNLEtBQUssUUFBTCxDQUFjLE9BQWQsRUFBdUIsT0FBdkIsQ0FBUCxFQUF3QyxvQkFBeEMsQ0FBekIsQ0FERSxDQUdGO0FBQ0E7O0FBQ0EsUUFBQSxVQUFVLEdBQUcsS0FBYjtBQUNELE9BTkQsU0FNVTtBQUNSLFlBQUksVUFBSixFQUFnQjtBQUNkO0FBQ0EsVUFBQSxP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QUFBLElBQUksQ0FBQyxLQUFELEVBQWM7QUFDaEIsU0FBSyxPQUFMLEdBQWUsS0FBZjtBQUNEOztBQUVELEVBQUEsYUFBYSxHQUFBO0FBQ1gsV0FBTyxLQUFLLEdBQUwsQ0FBUyxLQUFLLE9BQUwsRUFBVCxDQUFQO0FBQ0Q7O0FBRUQsRUFBQSxlQUFlLEdBQUE7QUFDYixRQUFJLEtBQUssZ0JBQVQsRUFBMkI7QUFDekIsV0FBSyxnQkFBTCxDQUFzQixlQUF0QjtBQUNEO0FBQ0Y7O0FBakJrQiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IERFQlVHIH0gZnJvbSAnQGdsaW1tZXIvZW52JztcbmltcG9ydCB7XG4gIEJvdW5kcyxcbiAgRHluYW1pY1Njb3BlLFxuICBFbGVtZW50QnVpbGRlcixcbiAgRW52aXJvbm1lbnQsXG4gIEV4Y2VwdGlvbkhhbmRsZXIsXG4gIEdsaW1tZXJUcmVlQ2hhbmdlcyxcbiAgTGl2ZUJsb2NrLFxuICBPcHRpb24sXG4gIFJ1bnRpbWVDb250ZXh0LFxuICBTY29wZSxcbiAgVXBkYXRhYmxlQmxvY2ssXG4gIFVwZGF0aW5nVk0sXG4gIFVwZGF0aW5nT3Bjb2RlLFxufSBmcm9tICdAZ2xpbW1lci9pbnRlcmZhY2VzJztcbmltcG9ydCB7IExPQ0FMX0RFQlVHIH0gZnJvbSAnQGdsaW1tZXIvbG9jYWwtZGVidWctZmxhZ3MnO1xuaW1wb3J0IHtcbiAgT3BhcXVlSXRlcmF0aW9uSXRlbSxcbiAgT3BhcXVlSXRlcmF0b3IsXG4gIFJlZmVyZW5jZSxcbiAgdXBkYXRlUmVmLFxuICB2YWx1ZUZvclJlZixcbn0gZnJvbSAnQGdsaW1tZXIvcmVmZXJlbmNlJztcbmltcG9ydCB7IGFzc29jaWF0ZURlc3Ryb3lhYmxlQ2hpbGQsIGRlc3Ryb3ksIGRlc3Ryb3lDaGlsZHJlbiB9IGZyb20gJ0BnbGltbWVyL2Rlc3Ryb3lhYmxlJztcbmltcG9ydCB7IGV4cGVjdCwgU3RhY2ssIGxvZ1N0ZXAgfSBmcm9tICdAZ2xpbW1lci91dGlsJztcbmltcG9ydCB7IHJlc2V0VHJhY2tpbmcsIHJ1bkluVHJhY2tpbmdUcmFuc2FjdGlvbiB9IGZyb20gJ0BnbGltbWVyL3ZhbGlkYXRvcic7XG5pbXBvcnQgeyBTaW1wbGVDb21tZW50IH0gZnJvbSAnQHNpbXBsZS1kb20vaW50ZXJmYWNlJztcbmltcG9ydCB7IGNsZWFyLCBtb3ZlIGFzIG1vdmVCb3VuZHMgfSBmcm9tICcuLi9ib3VuZHMnO1xuaW1wb3J0IHsgSW50ZXJuYWxWTSwgVm1Jbml0Q2FsbGJhY2sgfSBmcm9tICcuL2FwcGVuZCc7XG5pbXBvcnQgeyBMaXZlQmxvY2tMaXN0LCBOZXdFbGVtZW50QnVpbGRlciB9IGZyb20gJy4vZWxlbWVudC1idWlsZGVyJztcblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgVXBkYXRpbmdWTUltcGwgaW1wbGVtZW50cyBVcGRhdGluZ1ZNIHtcbiAgcHVibGljIGVudjogRW52aXJvbm1lbnQ7XG4gIHB1YmxpYyBkb206IEdsaW1tZXJUcmVlQ2hhbmdlcztcbiAgcHVibGljIGFsd2F5c1JldmFsaWRhdGU6IGJvb2xlYW47XG5cbiAgcHJpdmF0ZSBmcmFtZVN0YWNrOiBTdGFjazxVcGRhdGluZ1ZNRnJhbWU+ID0gbmV3IFN0YWNrPFVwZGF0aW5nVk1GcmFtZT4oKTtcblxuICBjb25zdHJ1Y3RvcihlbnY6IEVudmlyb25tZW50LCB7IGFsd2F5c1JldmFsaWRhdGUgPSBmYWxzZSB9KSB7XG4gICAgdGhpcy5lbnYgPSBlbnY7XG4gICAgdGhpcy5kb20gPSBlbnYuZ2V0RE9NKCk7XG4gICAgdGhpcy5hbHdheXNSZXZhbGlkYXRlID0gYWx3YXlzUmV2YWxpZGF0ZTtcbiAgfVxuXG4gIGV4ZWN1dGUob3Bjb2RlczogVXBkYXRpbmdPcGNvZGVbXSwgaGFuZGxlcjogRXhjZXB0aW9uSGFuZGxlcikge1xuICAgIGlmIChERUJVRykge1xuICAgICAgbGV0IGhhc0Vycm9yZWQgPSB0cnVlO1xuICAgICAgdHJ5IHtcbiAgICAgICAgcnVuSW5UcmFja2luZ1RyYW5zYWN0aW9uISgoKSA9PiB0aGlzLl9leGVjdXRlKG9wY29kZXMsIGhhbmRsZXIpLCAnLSBXaGlsZSByZW5kZXJpbmc6Jyk7XG5cbiAgICAgICAgLy8gdXNpbmcgYSBib29sZWFuIGhlcmUgdG8gYXZvaWQgYnJlYWtpbmcgZXJnb25vbWljcyBvZiBcInBhdXNlIG9uIHVuY2F1Z2h0IGV4Y2VwdGlvbnNcIlxuICAgICAgICAvLyB3aGljaCB3b3VsZCBoYXBwZW4gd2l0aCBhIGBjYXRjaGAgKyBgdGhyb3dgXG4gICAgICAgIGhhc0Vycm9yZWQgPSBmYWxzZTtcbiAgICAgIH0gZmluYWxseSB7XG4gICAgICAgIGlmIChoYXNFcnJvcmVkKSB7XG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLWNvbnNvbGVcbiAgICAgICAgICBjb25zb2xlLmVycm9yKGBcXG5cXG5FcnJvciBvY2N1cnJlZDpcXG5cXG4ke3Jlc2V0VHJhY2tpbmcoKX1cXG5cXG5gKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLl9leGVjdXRlKG9wY29kZXMsIGhhbmRsZXIpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgX2V4ZWN1dGUob3Bjb2RlczogVXBkYXRpbmdPcGNvZGVbXSwgaGFuZGxlcjogRXhjZXB0aW9uSGFuZGxlcikge1xuICAgIGxldCB7IGZyYW1lU3RhY2sgfSA9IHRoaXM7XG5cbiAgICB0aGlzLnRyeShvcGNvZGVzLCBoYW5kbGVyKTtcblxuICAgIHdoaWxlICh0cnVlKSB7XG4gICAgICBpZiAoZnJhbWVTdGFjay5pc0VtcHR5KCkpIGJyZWFrO1xuXG4gICAgICBsZXQgb3Bjb2RlID0gdGhpcy5mcmFtZS5uZXh0U3RhdGVtZW50KCk7XG5cbiAgICAgIGlmIChvcGNvZGUgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICBmcmFtZVN0YWNrLnBvcCgpO1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgb3Bjb2RlLmV2YWx1YXRlKHRoaXMpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgZ2V0IGZyYW1lKCkge1xuICAgIHJldHVybiBleHBlY3QodGhpcy5mcmFtZVN0YWNrLmN1cnJlbnQsICdidWc6IGV4cGVjdGVkIGEgZnJhbWUnKTtcbiAgfVxuXG4gIGdvdG8oaW5kZXg6IG51bWJlcikge1xuICAgIHRoaXMuZnJhbWUuZ290byhpbmRleCk7XG4gIH1cblxuICB0cnkob3BzOiBVcGRhdGluZ09wY29kZVtdLCBoYW5kbGVyOiBPcHRpb248RXhjZXB0aW9uSGFuZGxlcj4pIHtcbiAgICB0aGlzLmZyYW1lU3RhY2sucHVzaChuZXcgVXBkYXRpbmdWTUZyYW1lKG9wcywgaGFuZGxlcikpO1xuICB9XG5cbiAgdGhyb3coKSB7XG4gICAgdGhpcy5mcmFtZS5oYW5kbGVFeGNlcHRpb24oKTtcbiAgICB0aGlzLmZyYW1lU3RhY2sucG9wKCk7XG4gIH1cbn1cblxuZXhwb3J0IGludGVyZmFjZSBWTVN0YXRlIHtcbiAgcmVhZG9ubHkgcGM6IG51bWJlcjtcbiAgcmVhZG9ubHkgc2NvcGU6IFNjb3BlO1xuICByZWFkb25seSBkeW5hbWljU2NvcGU6IER5bmFtaWNTY29wZTtcbiAgcmVhZG9ubHkgc3RhY2s6IHVua25vd25bXTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBSZXN1bWFibGVWTVN0YXRlIHtcbiAgcmVzdW1lKHJ1bnRpbWU6IFJ1bnRpbWVDb250ZXh0LCBidWlsZGVyOiBFbGVtZW50QnVpbGRlcik6IEludGVybmFsVk07XG59XG5cbmV4cG9ydCBjbGFzcyBSZXN1bWFibGVWTVN0YXRlSW1wbCBpbXBsZW1lbnRzIFJlc3VtYWJsZVZNU3RhdGUge1xuICBjb25zdHJ1Y3RvcihyZWFkb25seSBzdGF0ZTogVk1TdGF0ZSwgcHJpdmF0ZSByZXN1bWVDYWxsYmFjazogVm1Jbml0Q2FsbGJhY2spIHt9XG5cbiAgcmVzdW1lKHJ1bnRpbWU6IFJ1bnRpbWVDb250ZXh0LCBidWlsZGVyOiBFbGVtZW50QnVpbGRlcik6IEludGVybmFsVk0ge1xuICAgIHJldHVybiB0aGlzLnJlc3VtZUNhbGxiYWNrKHJ1bnRpbWUsIHRoaXMuc3RhdGUsIGJ1aWxkZXIpO1xuICB9XG59XG5cbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBCbG9ja09wY29kZSBpbXBsZW1lbnRzIFVwZGF0aW5nT3Bjb2RlLCBCb3VuZHMge1xuICBwdWJsaWMgY2hpbGRyZW46IFVwZGF0aW5nT3Bjb2RlW107XG5cbiAgcHJvdGVjdGVkIHJlYWRvbmx5IGJvdW5kczogTGl2ZUJsb2NrO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByb3RlY3RlZCBzdGF0ZTogUmVzdW1hYmxlVk1TdGF0ZSxcbiAgICBwcm90ZWN0ZWQgcnVudGltZTogUnVudGltZUNvbnRleHQsXG4gICAgYm91bmRzOiBMaXZlQmxvY2ssXG4gICAgY2hpbGRyZW46IFVwZGF0aW5nT3Bjb2RlW11cbiAgKSB7XG4gICAgdGhpcy5jaGlsZHJlbiA9IGNoaWxkcmVuO1xuICAgIHRoaXMuYm91bmRzID0gYm91bmRzO1xuICB9XG5cbiAgcGFyZW50RWxlbWVudCgpIHtcbiAgICByZXR1cm4gdGhpcy5ib3VuZHMucGFyZW50RWxlbWVudCgpO1xuICB9XG5cbiAgZmlyc3ROb2RlKCkge1xuICAgIHJldHVybiB0aGlzLmJvdW5kcy5maXJzdE5vZGUoKTtcbiAgfVxuXG4gIGxhc3ROb2RlKCkge1xuICAgIHJldHVybiB0aGlzLmJvdW5kcy5sYXN0Tm9kZSgpO1xuICB9XG5cbiAgZXZhbHVhdGUodm06IFVwZGF0aW5nVk1JbXBsKSB7XG4gICAgdm0udHJ5KHRoaXMuY2hpbGRyZW4sIG51bGwpO1xuICB9XG59XG5cbmV4cG9ydCBjbGFzcyBUcnlPcGNvZGUgZXh0ZW5kcyBCbG9ja09wY29kZSBpbXBsZW1lbnRzIEV4Y2VwdGlvbkhhbmRsZXIge1xuICBwdWJsaWMgdHlwZSA9ICd0cnknO1xuXG4gIHByb3RlY3RlZCBib3VuZHMhOiBVcGRhdGFibGVCbG9jazsgLy8gSGlkZXMgcHJvcGVydHkgb24gYmFzZSBjbGFzc1xuXG4gIGV2YWx1YXRlKHZtOiBVcGRhdGluZ1ZNSW1wbCkge1xuICAgIHZtLnRyeSh0aGlzLmNoaWxkcmVuLCB0aGlzKTtcbiAgfVxuXG4gIGhhbmRsZUV4Y2VwdGlvbigpIHtcbiAgICBsZXQgeyBzdGF0ZSwgYm91bmRzLCBydW50aW1lIH0gPSB0aGlzO1xuXG4gICAgZGVzdHJveUNoaWxkcmVuKHRoaXMpO1xuXG4gICAgbGV0IGVsZW1lbnRTdGFjayA9IE5ld0VsZW1lbnRCdWlsZGVyLnJlc3VtZShydW50aW1lLmVudiwgYm91bmRzKTtcbiAgICBsZXQgdm0gPSBzdGF0ZS5yZXN1bWUocnVudGltZSwgZWxlbWVudFN0YWNrKTtcblxuICAgIGxldCB1cGRhdGluZzogVXBkYXRpbmdPcGNvZGVbXSA9IFtdO1xuICAgIGxldCBjaGlsZHJlbiA9ICh0aGlzLmNoaWxkcmVuID0gW10pO1xuXG4gICAgbGV0IHJlc3VsdCA9IHZtLmV4ZWN1dGUoKHZtKSA9PiB7XG4gICAgICB2bS5wdXNoVXBkYXRpbmcodXBkYXRpbmcpO1xuICAgICAgdm0udXBkYXRlV2l0aCh0aGlzKTtcbiAgICAgIHZtLnB1c2hVcGRhdGluZyhjaGlsZHJlbik7XG4gICAgfSk7XG5cbiAgICBhc3NvY2lhdGVEZXN0cm95YWJsZUNoaWxkKHRoaXMsIHJlc3VsdC5kcm9wKTtcbiAgfVxufVxuXG5leHBvcnQgY2xhc3MgTGlzdEl0ZW1PcGNvZGUgZXh0ZW5kcyBUcnlPcGNvZGUge1xuICBwdWJsaWMgcmV0YWluZWQgPSBmYWxzZTtcbiAgcHVibGljIGluZGV4ID0gLTE7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgc3RhdGU6IFJlc3VtYWJsZVZNU3RhdGUsXG4gICAgcnVudGltZTogUnVudGltZUNvbnRleHQsXG4gICAgYm91bmRzOiBVcGRhdGFibGVCbG9jayxcbiAgICBwdWJsaWMga2V5OiB1bmtub3duLFxuICAgIHB1YmxpYyBtZW1vOiBSZWZlcmVuY2UsXG4gICAgcHVibGljIHZhbHVlOiBSZWZlcmVuY2VcbiAgKSB7XG4gICAgc3VwZXIoc3RhdGUsIHJ1bnRpbWUsIGJvdW5kcywgW10pO1xuICB9XG5cbiAgdXBkYXRlUmVmZXJlbmNlcyhpdGVtOiBPcGFxdWVJdGVyYXRpb25JdGVtKSB7XG4gICAgdGhpcy5yZXRhaW5lZCA9IHRydWU7XG4gICAgdXBkYXRlUmVmKHRoaXMudmFsdWUsIGl0ZW0udmFsdWUpO1xuICAgIHVwZGF0ZVJlZih0aGlzLm1lbW8sIGl0ZW0ubWVtbyk7XG4gIH1cblxuICBzaG91bGRSZW1vdmUoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuICF0aGlzLnJldGFpbmVkO1xuICB9XG5cbiAgcmVzZXQoKSB7XG4gICAgdGhpcy5yZXRhaW5lZCA9IGZhbHNlO1xuICB9XG59XG5cbmV4cG9ydCBjbGFzcyBMaXN0QmxvY2tPcGNvZGUgZXh0ZW5kcyBCbG9ja09wY29kZSB7XG4gIHB1YmxpYyB0eXBlID0gJ2xpc3QtYmxvY2snO1xuICBwdWJsaWMgY2hpbGRyZW4hOiBMaXN0SXRlbU9wY29kZVtdO1xuXG4gIHByaXZhdGUgb3Bjb2RlTWFwID0gbmV3IE1hcDx1bmtub3duLCBMaXN0SXRlbU9wY29kZT4oKTtcbiAgcHJpdmF0ZSBtYXJrZXI6IFNpbXBsZUNvbW1lbnQgfCBudWxsID0gbnVsbDtcbiAgcHJpdmF0ZSBsYXN0SXRlcmF0b3I6IE9wYXF1ZUl0ZXJhdG9yO1xuXG4gIHByb3RlY3RlZCByZWFkb25seSBib3VuZHMhOiBMaXZlQmxvY2tMaXN0O1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHN0YXRlOiBSZXN1bWFibGVWTVN0YXRlLFxuICAgIHJ1bnRpbWU6IFJ1bnRpbWVDb250ZXh0LFxuICAgIGJvdW5kczogTGl2ZUJsb2NrTGlzdCxcbiAgICBjaGlsZHJlbjogTGlzdEl0ZW1PcGNvZGVbXSxcbiAgICBwcml2YXRlIGl0ZXJhYmxlUmVmOiBSZWZlcmVuY2U8T3BhcXVlSXRlcmF0b3I+XG4gICkge1xuICAgIHN1cGVyKHN0YXRlLCBydW50aW1lLCBib3VuZHMsIGNoaWxkcmVuKTtcbiAgICB0aGlzLmxhc3RJdGVyYXRvciA9IHZhbHVlRm9yUmVmKGl0ZXJhYmxlUmVmKTtcbiAgfVxuXG4gIGluaXRpYWxpemVDaGlsZChvcGNvZGU6IExpc3RJdGVtT3Bjb2RlKSB7XG4gICAgb3Bjb2RlLmluZGV4ID0gdGhpcy5jaGlsZHJlbi5sZW5ndGggLSAxO1xuICAgIHRoaXMub3Bjb2RlTWFwLnNldChvcGNvZGUua2V5LCBvcGNvZGUpO1xuICB9XG5cbiAgZXZhbHVhdGUodm06IFVwZGF0aW5nVk1JbXBsKSB7XG4gICAgbGV0IGl0ZXJhdG9yID0gdmFsdWVGb3JSZWYodGhpcy5pdGVyYWJsZVJlZik7XG5cbiAgICBpZiAodGhpcy5sYXN0SXRlcmF0b3IgIT09IGl0ZXJhdG9yKSB7XG4gICAgICBsZXQgeyBib3VuZHMgfSA9IHRoaXM7XG4gICAgICBsZXQgeyBkb20gfSA9IHZtO1xuXG4gICAgICBsZXQgbWFya2VyID0gKHRoaXMubWFya2VyID0gZG9tLmNyZWF0ZUNvbW1lbnQoJycpKTtcbiAgICAgIGRvbS5pbnNlcnRBZnRlcihcbiAgICAgICAgYm91bmRzLnBhcmVudEVsZW1lbnQoKSxcbiAgICAgICAgbWFya2VyLFxuICAgICAgICBleHBlY3QoYm91bmRzLmxhc3ROb2RlKCksIFwiY2FuJ3QgaW5zZXJ0IGFmdGVyIGFuIGVtcHR5IGJvdW5kc1wiKVxuICAgICAgKTtcblxuICAgICAgdGhpcy5zeW5jKGl0ZXJhdG9yKTtcblxuICAgICAgdGhpcy5wYXJlbnRFbGVtZW50KCkucmVtb3ZlQ2hpbGQobWFya2VyKTtcbiAgICAgIHRoaXMubWFya2VyID0gbnVsbDtcbiAgICAgIHRoaXMubGFzdEl0ZXJhdG9yID0gaXRlcmF0b3I7XG4gICAgfVxuXG4gICAgLy8gUnVuIG5vdy11cGRhdGVkIHVwZGF0aW5nIG9wY29kZXNcbiAgICBzdXBlci5ldmFsdWF0ZSh2bSk7XG4gIH1cblxuICBwcml2YXRlIHN5bmMoaXRlcmF0b3I6IE9wYXF1ZUl0ZXJhdG9yKSB7XG4gICAgbGV0IHsgb3Bjb2RlTWFwOiBpdGVtTWFwLCBjaGlsZHJlbiB9ID0gdGhpcztcblxuICAgIGxldCBjdXJyZW50T3Bjb2RlSW5kZXggPSAwO1xuICAgIGxldCBzZWVuSW5kZXggPSAwO1xuXG4gICAgdGhpcy5jaGlsZHJlbiA9IHRoaXMuYm91bmRzLmJvdW5kTGlzdCA9IFtdO1xuXG4gICAgd2hpbGUgKHRydWUpIHtcbiAgICAgIGxldCBpdGVtID0gaXRlcmF0b3IubmV4dCgpO1xuXG4gICAgICBpZiAoaXRlbSA9PT0gbnVsbCkgYnJlYWs7XG5cbiAgICAgIGxldCBvcGNvZGUgPSBjaGlsZHJlbltjdXJyZW50T3Bjb2RlSW5kZXhdO1xuICAgICAgbGV0IHsga2V5IH0gPSBpdGVtO1xuXG4gICAgICAvLyBJdGVtcyB0aGF0IGhhdmUgYWxyZWFkeSBiZWVuIGZvdW5kIGFuZCBtb3ZlZCB3aWxsIGFscmVhZHkgYmUgcmV0YWluZWQsXG4gICAgICAvLyB3ZSBjYW4gY29udGludWUgdW50aWwgd2UgZmluZCB0aGUgbmV4dCB1bnJldGFpbmVkIGl0ZW1cbiAgICAgIHdoaWxlIChvcGNvZGUgIT09IHVuZGVmaW5lZCAmJiBvcGNvZGUucmV0YWluZWQgPT09IHRydWUpIHtcbiAgICAgICAgb3Bjb2RlID0gY2hpbGRyZW5bKytjdXJyZW50T3Bjb2RlSW5kZXhdO1xuICAgICAgfVxuXG4gICAgICBpZiAob3Bjb2RlICE9PSB1bmRlZmluZWQgJiYgb3Bjb2RlLmtleSA9PT0ga2V5KSB7XG4gICAgICAgIHRoaXMucmV0YWluSXRlbShvcGNvZGUsIGl0ZW0pO1xuICAgICAgICBjdXJyZW50T3Bjb2RlSW5kZXgrKztcbiAgICAgIH0gZWxzZSBpZiAoaXRlbU1hcC5oYXMoa2V5KSkge1xuICAgICAgICBsZXQgaXRlbU9wY29kZSA9IGl0ZW1NYXAuZ2V0KGtleSkhO1xuXG4gICAgICAgIC8vIFRoZSBpdGVtIG9wY29kZSB3YXMgc2VlbiBhbHJlYWR5LCBzbyB3ZSBzaG91bGQgbW92ZSBpdC5cbiAgICAgICAgaWYgKGl0ZW1PcGNvZGUuaW5kZXggPCBzZWVuSW5kZXgpIHtcbiAgICAgICAgICB0aGlzLm1vdmVJdGVtKGl0ZW1PcGNvZGUsIGl0ZW0sIG9wY29kZSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy8gVXBkYXRlIHRoZSBzZWVuIGluZGV4LCB3ZSBhcmUgZ29pbmcgdG8gYmUgbW92aW5nIHRoaXMgaXRlbSBhcm91bmRcbiAgICAgICAgICAvLyBzbyBhbnkgb3RoZXIgaXRlbXMgdGhhdCBjb21lIGJlZm9yZSBpdCB3aWxsIGxpa2VseSBuZWVkIHRvIG1vdmUgYXNcbiAgICAgICAgICAvLyB3ZWxsLlxuICAgICAgICAgIHNlZW5JbmRleCA9IGl0ZW1PcGNvZGUuaW5kZXg7XG5cbiAgICAgICAgICBsZXQgc2VlblVucmV0YWluZWQgPSBmYWxzZTtcblxuICAgICAgICAgIC8vIGl0ZXJhdGUgdGhyb3VnaCBhbGwgb2YgdGhlIG9wY29kZXMgYmV0d2VlbiB0aGUgY3VycmVudCBwb3NpdGlvbiBhbmRcbiAgICAgICAgICAvLyB0aGUgcG9zaXRpb24gb2YgdGhlIGl0ZW0ncyBvcGNvZGUsIGFuZCBkZXRlcm1pbmUgaWYgdGhleSBhcmUgYWxsXG4gICAgICAgICAgLy8gcmV0YWluZWQuXG4gICAgICAgICAgZm9yIChsZXQgaSA9IGN1cnJlbnRPcGNvZGVJbmRleCArIDE7IGkgPCBzZWVuSW5kZXg7IGkrKykge1xuICAgICAgICAgICAgaWYgKGNoaWxkcmVuW2ldLnJldGFpbmVkID09PSBmYWxzZSkge1xuICAgICAgICAgICAgICBzZWVuVW5yZXRhaW5lZCA9IHRydWU7XG4gICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIElmIHdlIGhhdmUgc2VlbiBvbmx5IHJldGFpbmVkIG9wY29kZXMgYmV0d2VlbiB0aGlzIGFuZCB0aGUgbWF0Y2hpbmdcbiAgICAgICAgICAvLyBvcGNvZGUsIGl0IG1lYW5zIHRoYXQgYWxsIHRoZSBvcGNvZGVzIGluIGJldHdlZW4gaGF2ZSBiZWVuIG1vdmVkXG4gICAgICAgICAgLy8gYWxyZWFkeSwgYW5kIHdlIGNhbiBzYWZlbHkgcmV0YWluIHRoaXMgaXRlbSdzIG9wY29kZS5cbiAgICAgICAgICBpZiAoc2VlblVucmV0YWluZWQgPT09IGZhbHNlKSB7XG4gICAgICAgICAgICB0aGlzLnJldGFpbkl0ZW0oaXRlbU9wY29kZSwgaXRlbSk7XG4gICAgICAgICAgICBjdXJyZW50T3Bjb2RlSW5kZXggPSBzZWVuSW5kZXggKyAxO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLm1vdmVJdGVtKGl0ZW1PcGNvZGUsIGl0ZW0sIG9wY29kZSk7XG4gICAgICAgICAgICBjdXJyZW50T3Bjb2RlSW5kZXgrKztcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMuaW5zZXJ0SXRlbShpdGVtLCBvcGNvZGUpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgY2hpbGRyZW4ubGVuZ3RoOyBpKyspIHtcbiAgICAgIGxldCBvcGNvZGUgPSBjaGlsZHJlbltpXTtcblxuICAgICAgaWYgKG9wY29kZS5yZXRhaW5lZCA9PT0gZmFsc2UpIHtcbiAgICAgICAgdGhpcy5kZWxldGVJdGVtKG9wY29kZSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBvcGNvZGUucmVzZXQoKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHJldGFpbkl0ZW0ob3Bjb2RlOiBMaXN0SXRlbU9wY29kZSwgaXRlbTogT3BhcXVlSXRlcmF0aW9uSXRlbSkge1xuICAgIGlmIChMT0NBTF9ERUJVRykge1xuICAgICAgbG9nU3RlcCEoJ2xpc3QtdXBkYXRlcycsIFsncmV0YWluJywgaXRlbS5rZXldKTtcbiAgICB9XG5cbiAgICBsZXQgeyBjaGlsZHJlbiB9ID0gdGhpcztcblxuICAgIHVwZGF0ZVJlZihvcGNvZGUubWVtbywgaXRlbS5tZW1vKTtcbiAgICB1cGRhdGVSZWYob3Bjb2RlLnZhbHVlLCBpdGVtLnZhbHVlKTtcbiAgICBvcGNvZGUucmV0YWluZWQgPSB0cnVlO1xuXG4gICAgb3Bjb2RlLmluZGV4ID0gY2hpbGRyZW4ubGVuZ3RoO1xuICAgIGNoaWxkcmVuLnB1c2gob3Bjb2RlKTtcbiAgfVxuXG4gIHByaXZhdGUgaW5zZXJ0SXRlbShpdGVtOiBPcGFxdWVJdGVyYXRpb25JdGVtLCBiZWZvcmU6IExpc3RJdGVtT3Bjb2RlKSB7XG4gICAgaWYgKExPQ0FMX0RFQlVHKSB7XG4gICAgICBsb2dTdGVwISgnbGlzdC11cGRhdGVzJywgWydpbnNlcnQnLCBpdGVtLmtleV0pO1xuICAgIH1cblxuICAgIGxldCB7IG9wY29kZU1hcCwgYm91bmRzLCBzdGF0ZSwgcnVudGltZSwgY2hpbGRyZW4gfSA9IHRoaXM7XG4gICAgbGV0IHsga2V5IH0gPSBpdGVtO1xuICAgIGxldCBuZXh0U2libGluZyA9IGJlZm9yZSA9PT0gdW5kZWZpbmVkID8gdGhpcy5tYXJrZXIgOiBiZWZvcmUuZmlyc3ROb2RlKCk7XG5cbiAgICBsZXQgZWxlbWVudFN0YWNrID0gTmV3RWxlbWVudEJ1aWxkZXIuZm9ySW5pdGlhbFJlbmRlcihydW50aW1lLmVudiwge1xuICAgICAgZWxlbWVudDogYm91bmRzLnBhcmVudEVsZW1lbnQoKSxcbiAgICAgIG5leHRTaWJsaW5nLFxuICAgIH0pO1xuXG4gICAgbGV0IHZtID0gc3RhdGUucmVzdW1lKHJ1bnRpbWUsIGVsZW1lbnRTdGFjayk7XG5cbiAgICB2bS5leGVjdXRlKCh2bSkgPT4ge1xuICAgICAgdm0ucHVzaFVwZGF0aW5nKCk7XG4gICAgICBsZXQgb3Bjb2RlID0gdm0uZW50ZXJJdGVtKGl0ZW0pO1xuXG4gICAgICBvcGNvZGUuaW5kZXggPSBjaGlsZHJlbi5sZW5ndGg7XG4gICAgICBjaGlsZHJlbi5wdXNoKG9wY29kZSk7XG4gICAgICBvcGNvZGVNYXAuc2V0KGtleSwgb3Bjb2RlKTtcbiAgICAgIGFzc29jaWF0ZURlc3Ryb3lhYmxlQ2hpbGQodGhpcywgb3Bjb2RlKTtcbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgbW92ZUl0ZW0ob3Bjb2RlOiBMaXN0SXRlbU9wY29kZSwgaXRlbTogT3BhcXVlSXRlcmF0aW9uSXRlbSwgYmVmb3JlOiBMaXN0SXRlbU9wY29kZSkge1xuICAgIGxldCB7IGNoaWxkcmVuIH0gPSB0aGlzO1xuXG4gICAgdXBkYXRlUmVmKG9wY29kZS5tZW1vLCBpdGVtLm1lbW8pO1xuICAgIHVwZGF0ZVJlZihvcGNvZGUudmFsdWUsIGl0ZW0udmFsdWUpO1xuICAgIG9wY29kZS5yZXRhaW5lZCA9IHRydWU7XG5cbiAgICBsZXQgY3VycmVudFNpYmxpbmcsIG5leHRTaWJsaW5nO1xuXG4gICAgaWYgKGJlZm9yZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICBtb3ZlQm91bmRzKG9wY29kZSwgdGhpcy5tYXJrZXIpO1xuICAgIH0gZWxzZSB7XG4gICAgICBjdXJyZW50U2libGluZyA9IG9wY29kZS5sYXN0Tm9kZSgpLm5leHRTaWJsaW5nO1xuICAgICAgbmV4dFNpYmxpbmcgPSBiZWZvcmUuZmlyc3ROb2RlKCk7XG5cbiAgICAgIC8vIEl0ZW1zIGFyZSBtb3ZlZCB0aHJvdWdob3V0IHRoZSBhbGdvcml0aG0sIHNvIHRoZXJlIGFyZSBjYXNlcyB3aGVyZSB0aGVcbiAgICAgIC8vIHRoZSBpdGVtcyBhbHJlYWR5IGhhcHBlbiB0byBiZSBzaWJsaW5ncyAoZS5nLiBhbiBpdGVtIGluIGJldHdlZW4gd2FzXG4gICAgICAvLyBtb3ZlZCBiZWZvcmUgdGhpcyBtb3ZlIGhhcHBlbmVkKS4gQ2hlY2sgdG8gc2VlIGlmIHRoZXkgYXJlIHNpYmxpbmdzXG4gICAgICAvLyBmaXJzdCBiZWZvcmUgZG9pbmcgdGhlIG1vdmUuXG4gICAgICBpZiAoY3VycmVudFNpYmxpbmcgIT09IG5leHRTaWJsaW5nKSB7XG4gICAgICAgIG1vdmVCb3VuZHMob3Bjb2RlLCBuZXh0U2libGluZyk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgb3Bjb2RlLmluZGV4ID0gY2hpbGRyZW4ubGVuZ3RoO1xuICAgIGNoaWxkcmVuLnB1c2gob3Bjb2RlKTtcblxuICAgIGlmIChMT0NBTF9ERUJVRykge1xuICAgICAgbGV0IHR5cGUgPSBjdXJyZW50U2libGluZyAmJiBjdXJyZW50U2libGluZyA9PT0gbmV4dFNpYmxpbmcgPyAnbW92ZS1yZXRhaW4nIDogJ21vdmUnO1xuICAgICAgbG9nU3RlcCEoJ2xpc3QtdXBkYXRlcycsIFt0eXBlLCBpdGVtLmtleV0pO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgZGVsZXRlSXRlbShvcGNvZGU6IExpc3RJdGVtT3Bjb2RlKSB7XG4gICAgaWYgKExPQ0FMX0RFQlVHKSB7XG4gICAgICBsb2dTdGVwISgnbGlzdC11cGRhdGVzJywgWydkZWxldGUnLCBvcGNvZGUua2V5XSk7XG4gICAgfVxuXG4gICAgZGVzdHJveShvcGNvZGUpO1xuICAgIGNsZWFyKG9wY29kZSk7XG4gICAgdGhpcy5vcGNvZGVNYXAuZGVsZXRlKG9wY29kZS5rZXkpO1xuICB9XG59XG5cbmNsYXNzIFVwZGF0aW5nVk1GcmFtZSB7XG4gIHByaXZhdGUgY3VycmVudCA9IDA7XG5cbiAgY29uc3RydWN0b3IocHJpdmF0ZSBvcHM6IFVwZGF0aW5nT3Bjb2RlW10sIHByaXZhdGUgZXhjZXB0aW9uSGFuZGxlcjogT3B0aW9uPEV4Y2VwdGlvbkhhbmRsZXI+KSB7fVxuXG4gIGdvdG8oaW5kZXg6IG51bWJlcikge1xuICAgIHRoaXMuY3VycmVudCA9IGluZGV4O1xuICB9XG5cbiAgbmV4dFN0YXRlbWVudCgpOiBVcGRhdGluZ09wY29kZSB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMub3BzW3RoaXMuY3VycmVudCsrXTtcbiAgfVxuXG4gIGhhbmRsZUV4Y2VwdGlvbigpIHtcbiAgICBpZiAodGhpcy5leGNlcHRpb25IYW5kbGVyKSB7XG4gICAgICB0aGlzLmV4Y2VwdGlvbkhhbmRsZXIuaGFuZGxlRXhjZXB0aW9uKCk7XG4gICAgfVxuICB9XG59XG4iXSwic291cmNlUm9vdCI6IiJ9