@firestone-hs/replay-parser
Version:
This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.2.9.
234 lines • 41.9 kB
JavaScript
import { Injectable } from '@angular/core';
import { CardType, GameTag } from '@firestone-hs/reference-data';
import { Game } from '../../models/game/game';
import { ActionParserConfig } from '../../models/models';
import { ActionButtonUsedParser } from '../action/action-button-used-parser';
import { AttachingEnchantmentParser } from '../action/attaching-enchantment-parser';
import { AttackParser } from '../action/attack-parser';
import { BaconBattleOverParser } from '../action/battlegrounds/bacon-battle-over-parser';
import { BaconBoardVisualStateParser } from '../action/battlegrounds/bacon-board-visual-state-parser';
import { BaconOpponentRevealedParser } from '../action/battlegrounds/bacon-opponent-revealed-parser';
import { CardBurnParser } from '../action/card-burn-parser';
import { CardDiscardParser } from '../action/card-discard-parser';
import { CardDrawParser } from '../action/card-draw-parser';
import { CardPlayedFromHandParser } from '../action/card-played-from-hand-parser';
import { CardTargetParser } from '../action/card-target-parser';
import { DamageParser } from '../action/damage-parser';
import { DiscoverParser } from '../action/discover-parser';
import { DiscoveryPickParser } from '../action/discovery-pick-parser';
import { EndGameParser } from '../action/end-game-parser';
import { FatigueDamageParser } from '../action/fatigue-damage-parser';
import { LocationActivatedParser } from '../action/location-activated-parser';
import { MinionDeathParser } from '../action/minion-death-parser';
import { MulliganCardChoiceParser } from '../action/mulligan-card-choice-parser';
import { MulliganCardParser } from '../action/mulligan-card-parser';
import { OptionsParser } from '../action/options-parser';
import { PowerTargetParser } from '../action/power-target-parser';
import { QuestCompletedParser } from '../action/quest-completed-parser';
import { SecretPlayedFromHandParser } from '../action/secret-played-from-hand-parser';
import { SecretRevealedParser } from '../action/secret-revealed-parser';
import { StartOfMulliganParser } from '../action/start-of-mulligan-parser';
import { StartTurnParser } from '../action/start-turn-parser';
import { SummonsParser } from '../action/summons-parser';
import { TradeParser } from '../action/trade-parser';
import * as i0 from "@angular/core";
import * as i1 from "../all-cards.service";
import * as i2 from "../state-processor.service";
export class ActionParserService {
constructor(allCards, stateProcessorService) {
this.allCards = allCards;
this.stateProcessorService = stateProcessorService;
}
registerActionParsers(config) {
return [
new StartTurnParser(this.allCards),
new MulliganCardParser(this.allCards),
new MulliganCardChoiceParser(this.allCards),
new StartOfMulliganParser(this.allCards),
new CardDrawParser(this.allCards),
new CardBurnParser(this.allCards),
new ActionButtonUsedParser(this.allCards),
new CardPlayedFromHandParser(this.allCards),
new SecretPlayedFromHandParser(this.allCards),
new AttackParser(this.allCards),
new MinionDeathParser(this.allCards),
new PowerTargetParser(this.allCards),
new CardTargetParser(this.allCards),
new DiscoverParser(this.allCards),
new DiscoveryPickParser(this.allCards),
new SummonsParser(this.allCards),
new SecretRevealedParser(this.allCards),
new AttachingEnchantmentParser(this.allCards, config),
new DamageParser(this.allCards),
new TradeParser(this.allCards),
new LocationActivatedParser(this.allCards),
new CardDiscardParser(this.allCards),
new OptionsParser(this.allCards),
new EndGameParser(this.allCards),
new FatigueDamageParser(this.allCards),
new QuestCompletedParser(this.allCards),
new BaconOpponentRevealedParser(this.allCards),
new BaconBoardVisualStateParser(this.allCards),
new BaconBattleOverParser(this.allCards),
];
}
parseActions(game, entities, history, config = new ActionParserConfig(), debug = false) {
// Because mulligan is effectively index -1; since there is a 0 turn after that
const currentTurn = game.turns.size - 1;
let previousStateEntities = entities;
let previousProcessedItem = history[0];
let actionsForTurn = [];
// Recreating this every time lets the parsers store state and emit the action only when necessary
const actionParsers = this.registerActionParsers(config);
for (const item of history) {
const entitiesBeforeAction = previousStateEntities;
previousStateEntities = this.stateProcessorService.applyHistoryItem(previousStateEntities, item);
previousProcessedItem = item;
actionsForTurn = this.updateActionsForTurn(item, actionsForTurn, actionParsers, entitiesBeforeAction, history, game);
}
previousStateEntities = this.stateProcessorService.applyHistoryUntilEnd(previousStateEntities, history, previousProcessedItem);
// Sort actions based on their index (so that actions that were created from the same
// parent action can have a custom order)
actionsForTurn = this.sortActions(actionsForTurn, (a, b) => a.index - b.index || a.timestamp - b.timestamp);
actionsForTurn = this.fillMissingEntities(actionsForTurn, previousStateEntities);
// Give an opportunity to each parser to combine the actions it produced by merging them
// For instance, if we two card draws in a row, we might want to display them as a single
// action that draws two cards
actionsForTurn = this.reduceActions(actionParsers, actionsForTurn);
actionsForTurn = this.addDamageToEntities(actionsForTurn, previousStateEntities);
try {
if (currentTurn < 0) {
// // console.log('handling game init entity updates');
return Game.createGame(game, { entitiesBeforeMulligan: previousStateEntities });
}
if (!game.turns.get(currentTurn)) {
console.warn('could not get current turn', currentTurn, game.turns.toJS());
}
const turnWithNewActions = game.turns.get(currentTurn).update({ actions: actionsForTurn });
const turnNumber = turnWithNewActions.turn === 'mulligan' ? 0 : parseInt(turnWithNewActions.turn);
const turns = game.turns.set(turnNumber, turnWithNewActions);
// // console.log('turnWithNewActions', turnNumber, turnWithNewActions.actions);
const result = Game.createGame(game, { turns });
// // console.log('oriejg', result.getLatestParsedState().toJS());
return result;
}
catch (e) {
console.warn(currentTurn, game.turns.toJS(), actionsForTurn);
console.error(e);
return game;
}
// this.logger.log('took', Date.now() - start, 'ms for parseActions');
}
updateActionsForTurn(item, actionsForTurn, actionParsers, entitiesBeforeAction, history, game) {
const currentTurn = game.turns.size - 1;
actionParsers.forEach((parser) => {
if (parser.applies(item)) {
// When we perform an action, we want to show the result of the state updates until the next action is
// played.
const actions = parser.parse(item, currentTurn, entitiesBeforeAction, history, game.players);
if (actions && actions.length > 0) {
actionsForTurn = this.sortActions(actionsForTurn, (a, b) => a.index - b.index || a.timestamp - b.timestamp);
actionsForTurn = this.fillMissingEntities(actionsForTurn, entitiesBeforeAction);
actionsForTurn = [...actionsForTurn, ...actions];
}
}
});
return actionsForTurn;
}
fillMissingEntities(actionsForTurn, previousStateEntities) {
const newActionsForTurn = [];
for (let i = 0; i < actionsForTurn.length; i++) {
if (actionsForTurn[i].entities) {
newActionsForTurn.push(actionsForTurn[i]);
}
else {
//if (actionsForTurn[i] instanceof SummonAction) {
// // console.log(
// 'filling missing entities for',
// previousStateEntities.get(35) && previousStateEntities.get(35).tags.toJS(),
// actionsForTurn[i],
// );
//}
newActionsForTurn.push(actionsForTurn[i].update(previousStateEntities));
}
}
return newActionsForTurn;
}
addDamageToEntities(actionsForTurn, previousStateEntities) {
const newActionsForTurn = [];
for (let i = 0; i < actionsForTurn.length; i++) {
if (!actionsForTurn[i]) {
console.warn('BBBB', actionsForTurn);
}
const newEntities = actionsForTurn[i].entities ? actionsForTurn[i].entities : previousStateEntities;
const entitiesAfterDamageUpdate = newEntities
.map((entity) => this.updateDamageForEntity(actionsForTurn[i], entity))
.toMap();
newActionsForTurn.push(actionsForTurn[i].update(entitiesAfterDamageUpdate));
}
return newActionsForTurn;
}
updateDamageForEntity(action, entity) {
if (!action.damages ||
[CardType.SPELL, CardType.ENCHANTMENT, CardType.BATTLEGROUND_QUEST_REWARD, CardType.HERO_POWER].includes(entity.getTag(GameTag.CARDTYPE))) {
return entity;
}
const damages = action.damages;
const damage = damages.get(entity.id);
return entity.updateDamage(damage);
}
// private updateCurrentTurn(item: HistoryItem, game: Game, actions: readonly Action[], currentTurn): [Turn, number] {
// if (
// actions.length > 1 &&
// actions[actions.length - 1] instanceof StartTurnAction &&
// !(actions[actions.length - 1] as StartTurnAction).isStartOfMulligan
// ) {
// const turnToUpdate: Turn = game.turns.get(currentTurn);
// return [turnToUpdate, currentTurn + 1];
// }
// return [null, currentTurn];
// }
reduceActions(actionParsers, actionsForTurn) {
let reducedActions = actionsForTurn;
for (const parser of actionParsers) {
// // console.log('reducing', parser, actionsForTurn);
reducedActions = parser.reduce(reducedActions);
}
// // console.log('finished round of reduces');
// Because the different parsers can interact with each other, we need to apply all
// of them until the result doesn't change anymore
// This looks heavy in perf, but there aren't many actions, and it lets us
// handle each action type independently, which makes for more separated concerns
if (!this.areEqual(reducedActions, actionsForTurn)) {
// // console.log('going for another round');
return this.reduceActions(actionParsers, reducedActions);
}
// // console.log('fully finished');
return reducedActions;
}
sortActions(array, sortingFunction) {
const intermediate = [...array];
intermediate.sort(sortingFunction);
return intermediate;
}
areEqual(actions1, actions2) {
if (actions1.length !== actions2.length) {
return false;
}
for (let i = 0; i < actions1.length; i++) {
if (actions1[i] !== actions2[i]) {
return false;
}
}
return true;
}
}
ActionParserService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.1", ngImport: i0, type: ActionParserService, deps: [{ token: i1.AllCardsService }, { token: i2.StateProcessorService }], target: i0.ɵɵFactoryTarget.Injectable });
ActionParserService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.0.1", ngImport: i0, type: ActionParserService, providedIn: 'root' });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.1", ngImport: i0, type: ActionParserService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root',
}]
}], ctorParameters: function () { return [{ type: i1.AllCardsService }, { type: i2.StateProcessorService }]; } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWN0aW9uLXBhcnNlci5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvcmVwbGF5LXBhcnNlci9zcmMvbGliL3NlcnZpY2VzL2dhbWVwaXBlbGluZS9hY3Rpb24tcGFyc2VyLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMzQyxPQUFPLEVBQUUsUUFBUSxFQUFFLE9BQU8sRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBSWpFLE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUU5QyxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUN6RCxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSxxQ0FBcUMsQ0FBQztBQUM3RSxPQUFPLEVBQUUsMEJBQTBCLEVBQUUsTUFBTSx3Q0FBd0MsQ0FBQztBQUNwRixPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDdkQsT0FBTyxFQUFFLHFCQUFxQixFQUFFLE1BQU0sa0RBQWtELENBQUM7QUFDekYsT0FBTyxFQUFFLDJCQUEyQixFQUFFLE1BQU0seURBQXlELENBQUM7QUFDdEcsT0FBTyxFQUFFLDJCQUEyQixFQUFFLE1BQU0sd0RBQXdELENBQUM7QUFDckcsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQzVELE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBQ2xFLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUM1RCxPQUFPLEVBQUUsd0JBQXdCLEVBQUUsTUFBTSx3Q0FBd0MsQ0FBQztBQUNsRixPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUNoRSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0seUJB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S0FBSyxDQUFDLENBQUM7UUFDckMsWUFBWSxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsQ0FBQztRQUNuQyxPQUFPLFlBQTRCLENBQUM7SUFDckMsQ0FBQztJQUVPLFFBQVEsQ0FBQyxRQUEyQixFQUFFLFFBQTJCO1FBQ3hFLElBQUksUUFBUSxDQUFDLE1BQU0sS0FBSyxRQUFRLENBQUMsTUFBTSxFQUFFO1lBQ3hDLE9BQU8sS0FBSyxDQUFDO1NBQ2I7UUFDRCxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsUUFBUSxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRTtZQUN6QyxJQUFJLFFBQVEsQ0FBQyxDQUFDLENBQUMsS0FBSyxRQUFRLENBQUMsQ0FBQyxDQUFDLEVBQUU7Z0JBQ2hDLE9BQU8sS0FBSyxDQUFDO2FBQ2I7U0FDRDtRQUNELE9BQU8sSUFBSSxDQUFDO0lBQ2IsQ0FBQzs7Z0hBNU9XLG1CQUFtQjtvSEFBbkIsbUJBQW1CLGNBRm5CLE1BQU07MkZBRU4sbUJBQW1CO2tCQUgvQixVQUFVO21CQUFDO29CQUNYLFVBQVUsRUFBRSxNQUFNO2lCQUNsQiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdGFibGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgQ2FyZFR5cGUsIEdhbWVUYWcgfSBmcm9tICdAZmlyZXN0b25lLWhzL3JlZmVyZW5jZS1kYXRhJztcclxuaW1wb3J0IHsgTWFwIH0gZnJvbSAnaW1tdXRhYmxlJztcclxuaW1wb3J0IHsgQWN0aW9uIH0gZnJvbSAnLi4vLi4vbW9kZWxzL2FjdGlvbi9hY3Rpb24nO1xyXG5pbXBvcnQgeyBFbnRpdHkgfSBmcm9tICcuLi8uLi9tb2RlbHMvZ2FtZS9lbnRpdHknO1xyXG5pbXBvcnQgeyBHYW1lIH0gZnJvbSAnLi4vLi4vbW9kZWxzL2dhbWUvZ2FtZSc7XHJcbmltcG9ydCB7IEhpc3RvcnlJdGVtIH0gZnJvbSAnLi4vLi4vbW9kZWxzL2hpc3RvcnkvaGlzdG9yeS1pdGVtJztcclxuaW1wb3J0IHsgQWN0aW9uUGFyc2VyQ29uZmlnIH0gZnJvbSAnLi4vLi4vbW9kZWxzL21vZGVscyc7XHJcbmltcG9ydCB7IEFjdGlvbkJ1dHRvblVzZWRQYXJzZXIgfSBmcm9tICcuLi9hY3Rpb24vYWN0aW9uLWJ1dHRvbi11c2VkLXBhcnNlcic7XHJcbmltcG9ydCB7IEF0dGFjaGluZ0VuY2hhbnRtZW50UGFyc2VyIH0gZnJvbSAnLi4vYWN0aW9uL2F0dGFjaGluZy1lbmNoYW50bWVudC1wYXJzZXInO1xyXG5pbXBvcnQgeyBBdHRhY2tQYXJzZXIgfSBmcm9tICcuLi9hY3Rpb24vYXR0YWNrLXBhcnNlcic7XHJcbmltcG9ydCB7IEJhY29uQmF0dGxlT3ZlclBhcnNlciB9IGZyb20gJy4uL2FjdGlvbi9iYXR0bGVncm91bmRzL2JhY29uLWJhdHRsZS1vdmVyLXBhcnNlcic7XHJcbmltcG9ydCB7IEJhY29uQm9hcmRWaXN1YWxTdGF0ZVBhcnNlciB9IGZyb20gJy4uL2FjdGlvbi9iYXR0bGVncm91bmRzL2JhY29uLWJvYXJkLXZpc3VhbC1zdGF0ZS1wYXJzZXInO1xyXG5pbXBvcnQgeyBCYWNvbk9wcG9uZW50UmV2ZWFsZWRQYXJzZXIgfSBmcm9tICcuLi9hY3Rpb24vYmF0dGxlZ3JvdW5kcy9iYWNvbi1vcHBvbmVudC1yZXZlYWxlZC1wYXJzZXInO1xyXG5pbXBvcnQgeyBDYXJkQnVyblBhcnNlciB9IGZyb20gJy4uL2FjdGlvbi9jYXJkLWJ1cm4tcGFyc2VyJztcclxuaW1wb3J0IHsgQ2FyZERpc2NhcmRQYXJzZXIgfSBmcm9tICcuLi9hY3Rpb24vY2FyZC1kaXNjYXJkLXBhcnNlcic7XHJcbmltcG9ydCB7IENhcmREcmF3UGFyc2VyIH0gZnJvbSAnLi4vYWN0aW9uL2NhcmQtZHJhdy1wYXJzZXInO1xyXG5pbXBvcnQgeyBDYXJkUGxheWVkRnJvbUhhbmRQYXJzZXIgfSBmcm9tICcuLi9hY3Rpb24vY2FyZC1wbGF5ZWQtZnJvbS1oYW5kLXBhcnNlcic7XHJcbmltcG9ydCB7IENhcmRUYXJnZXRQYXJzZXIgfSBmcm9tICcuLi9hY3Rpb24vY2FyZC10YXJnZXQtcGFyc2VyJztcclxuaW1wb3J0IHsgRGFtYWdlUGFyc2VyIH0gZnJvbSAnLi4vYWN0aW9uL2RhbWFnZS1wYXJzZXInO1xyXG5pbXBvcnQgeyBEaXNjb3ZlclBhcnNlciB9IGZyb20gJy4uL2FjdGlvbi9kaXNjb3Zlci1wYXJzZXInO1xyXG5pbXBvcnQgeyBEaXNjb3ZlcnlQaWNrUGFyc2VyIH0gZnJvbSAnLi4vYWN0aW9uL2Rpc2NvdmVyeS1waWNrLXBhcnNlcic7XHJcbmltcG9ydCB7IEVuZEdhbWVQYXJzZXIgfSBmcm9tICcuLi9hY3Rpb24vZW5kLWdhbWUtcGFyc2VyJztcclxuaW1wb3J0IHsgRmF0aWd1ZURhbWFnZVBhcnNlciB9IGZyb20gJy4uL2FjdGlvbi9mYXRpZ3VlLWRhbWFnZS1wYXJzZXInO1xyXG5pbXBvcnQgeyBMb2NhdGlvbkFjdGl2YXRlZFBhcnNlciB9IGZyb20gJy4uL2FjdGlvbi9sb2NhdGlvbi1hY3RpdmF0ZWQtcGFyc2VyJztcclxuaW1wb3J0IHsgTWluaW9uRGVhdGhQYXJzZXIgfSBmcm9tICcuLi9hY3Rpb24vbWluaW9uLWRlYXRoLXBhcnNlcic7XHJcbmltcG9ydCB7IE11bGxpZ2FuQ2FyZENob2ljZVBhcnNlciB9IGZyb20gJy4uL2FjdGlvbi9tdWxsaWdhbi1jYXJkLWNob2ljZS1wYXJzZXInO1xyXG5pbXBvcnQgeyBNdWxsaWdhbkNhcmRQYXJzZXIgfSBmcm9tICcuLi9hY3Rpb24vbXVsbGlnYW4tY2FyZC1wYXJzZXInO1xyXG5pbXBvcnQgeyBPcHRpb25zUGFyc2VyIH0gZnJvbSAnLi4vYWN0aW9uL29wdGlvbnMtcGFyc2VyJztcclxuaW1wb3J0IHsgUGFyc2VyIH0gZnJvbSAnLi4vYWN0aW9uL3BhcnNlcic7XHJcbmltcG9ydCB7IFBvd2VyVGFyZ2V0UGFyc2VyIH0gZnJvbSAnLi4vYWN0aW9uL3Bvd2VyLXRhcmdldC1wYXJzZXInO1xyXG5pbXBvcnQgeyBRdWVzdENvbXBsZXRlZFBhcnNlciB9IGZyb20gJy4uL2FjdGlvbi9xdWVzdC1jb21wbGV0ZWQtcGFyc2VyJztcclxuaW1wb3J0IHsgU2VjcmV0UGxheWVkRnJvbUhhbmRQYXJzZXIgfSBmcm9tICcuLi9hY3Rpb24vc2VjcmV0LXBsYXllZC1mcm9tLWhhbmQtcGFyc2VyJztcclxuaW1wb3J0IHsgU2VjcmV0UmV2ZWFsZWRQYXJzZXIgfSBmcm9tICcuLi9hY3Rpb24vc2VjcmV0LXJldmVhbGVkLXBhcnNlcic7XHJcbmltcG9ydCB7IFN0YXJ0T2ZNdWxsaWdhblBhcnNlciB9IGZyb20gJy4uL2FjdGlvbi9zdGFydC1vZi1tdWxsaWdhbi1wYXJzZXInO1xyXG5pbXBvcnQgeyBTdGFydFR1cm5QYXJzZXIgfSBmcm9tICcuLi9hY3Rpb24vc3RhcnQtdHVybi1wYXJzZXInO1xyXG5pbXBvcnQgeyBTdW1tb25zUGFyc2VyIH0gZnJvbSAnLi4vYWN0aW9uL3N1bW1vbnMtcGFyc2VyJztcclxuaW1wb3J0IHsgVHJhZGVQYXJzZXIgfSBmcm9tICcuLi9hY3Rpb24vdHJhZGUtcGFyc2VyJztcclxuaW1wb3J0IHsgQWxsQ2FyZHNTZXJ2aWNlIH0gZnJvbSAnLi4vYWxsLWNhcmRzLnNlcnZpY2UnO1xyXG5pbXBvcnQgeyBTdGF0ZVByb2Nlc3NvclNlcnZpY2UgfSBmcm9tICcuLi9zdGF0ZS1wcm9jZXNzb3Iuc2VydmljZSc7XHJcblxyXG5ASW5qZWN0YWJsZSh7XHJcblx0cHJvdmlkZWRJbjogJ3Jvb3QnLFxyXG59KVxyXG5leHBvcnQgY2xhc3MgQWN0aW9uUGFyc2VyU2VydmljZSB7XHJcblx0Y29uc3RydWN0b3IoXHJcblx0XHRwcml2YXRlIGFsbENhcmRzOiBBbGxDYXJkc1NlcnZpY2UsXHJcblx0XHRwcml2YXRlIHN0YXRlUHJvY2Vzc29yU2VydmljZTogU3RhdGVQcm9jZXNzb3JTZXJ2aWNlLFxyXG5cdCkge31cclxuXHJcblx0cHJpdmF0ZSByZWdpc3RlckFjdGlvblBhcnNlcnMoY29uZmlnOiBBY3Rpb25QYXJzZXJDb25maWcpOiBQYXJzZXJbXSB7XHJcblx0XHRyZXR1cm4gW1xyXG5cdFx0XHRuZXcgU3RhcnRUdXJuUGFyc2VyKHRoaXMuYWxsQ2FyZHMpLFxyXG5cdFx0XHRuZXcgTXVsbGlnYW5DYXJkUGFyc2VyKHRoaXMuYWxsQ2FyZHMpLFxyXG5cdFx0XHRuZXcgTXVsbGlnYW5DYXJkQ2hvaWNlUGFyc2VyKHRoaXMuYWxsQ2FyZHMpLFxyXG5cdFx0XHRuZXcgU3RhcnRPZk11bGxpZ2FuUGFyc2VyKHRoaXMuYWxsQ2FyZHMpLFxyXG5cdFx0XHRuZXcgQ2FyZERyYXdQYXJzZXIodGhpcy5hbGxDYXJkcyksXHJcblx0XHRcdG5ldyBDYXJkQnVyblBhcnNlcih0aGlzLmFsbENhcmRzKSxcclxuXHRcdFx0bmV3IEFjdGlvbkJ1dHRvblVzZWRQYXJzZXIodGhpcy5hbGxDYXJkcyksXHJcblx0XHRcdG5ldyBDYXJkUGxheWVkRnJvbUhhbmRQYXJzZXIodGhpcy5hbGxDYXJkcyksXHJcblx0XHRcdG5ldyBTZWNyZXRQbGF5ZWRGcm9tSGFuZFBhcnNlcih0aGlzLmFsbENhcmRzKSxcclxuXHRcdFx0bmV3IEF0dGFja1BhcnNlcih0aGlzLmFsbENhcmRzKSxcclxuXHRcdFx0bmV3IE1pbmlvbkRlYXRoUGFyc2VyKHRoaXMuYWxsQ2FyZHMpLFxyXG5cdFx0XHRuZXcgUG93ZXJUYXJnZXRQYXJzZXIodGhpcy5hbGxDYXJkcyksXHJcblx0XHRcdG5ldyBDYXJkVGFyZ2V0UGFyc2VyKHRoaXMuYWxsQ2FyZHMpLFxyXG5cdFx0XHRuZXcgRGlzY292ZXJQYXJzZXIodGhpcy5hbGxDYXJkcyksXHJcblx0XHRcdG5ldyBEaXNjb3ZlcnlQaWNrUGFyc2VyKHRoaXMuYWxsQ2FyZHMpLFxyXG5cdFx0XHRuZXcgU3VtbW9uc1BhcnNlcih0aGlzLmFsbENhcmRzKSxcclxuXHRcdFx0bmV3IFNlY3JldFJldmVhbGVkUGFyc2VyKHRoaXMuYWxsQ2FyZHMpLFxyXG5cdFx0XHRuZXcgQXR0YWNoaW5nRW5jaGFudG1lbnRQYXJzZXIodGhpcy5hbGxDYXJkcywgY29uZmlnKSxcclxuXHRcdFx0bmV3IERhbWFnZVBhcnNlcih0aGlzLmFsbENhcmRzKSxcclxuXHRcdFx0bmV3IFRyYWRlUGFyc2VyKHRoaXMuYWxsQ2FyZHMpLFxyXG5cdFx0XHRuZXcgTG9jYXRpb25BY3RpdmF0ZWRQYXJzZXIodGhpcy5hbGxDYXJkcyksXHJcblx0XHRcdG5ldyBDYXJkRGlzY2FyZFBhcnNlcih0aGlzLmFsbENhcmRzKSxcclxuXHRcdFx0bmV3IE9wdGlvbnNQYXJzZXIodGhpcy5hbGxDYXJkcyksXHJcblx0XHRcdG5ldyBFbmRHYW1lUGFyc2VyKHRoaXMuYWxsQ2FyZHMpLFxyXG5cdFx0XHRuZXcgRmF0aWd1ZURhbWFnZVBhcnNlcih0aGlzLmFsbENhcmRzKSxcclxuXHRcdFx0bmV3IFF1ZXN0Q29tcGxldGVkUGFyc2VyKHRoaXMuYWxsQ2FyZHMpLFxyXG5cdFx0XHRuZXcgQmFjb25PcHBvbmVudFJldmVhbGVkUGFyc2VyKHRoaXMuYWxsQ2FyZHMpLFxyXG5cdFx0XHRuZXcgQmFjb25Cb2FyZFZpc3VhbFN0YXRlUGFyc2VyKHRoaXMuYWxsQ2FyZHMpLFxyXG5cdFx0XHRuZXcgQmFjb25CYXR0bGVPdmVyUGFyc2VyKHRoaXMuYWxsQ2FyZHMpLFxyXG5cdFx0XTtcclxuXHR9XHJcblxyXG5cdHB1YmxpYyBwYXJzZUFjdGlvbnMoXHJcblx0XHRnYW1lOiBHYW1lLFxyXG5cdFx0ZW50aXRpZXM6IE1hcDxudW1iZXIsIEVudGl0eT4sXHJcblx0XHRoaXN0b3J5OiByZWFkb25seSBIaXN0b3J5SXRlbVtdLFxyXG5cdFx0Y29uZmlnOiBBY3Rpb25QYXJzZXJDb25maWcgPSBuZXcgQWN0aW9uUGFyc2VyQ29uZmlnKCksXHJcblx0XHRkZWJ1ZyA9IGZhbHNlLFxyXG5cdCk6IEdhbWUge1xyXG5cdFx0Ly8gQmVjYXVzZSBtdWxsaWdhbiBpcyBlZmZlY3RpdmVseSBpbmRleCAtMTsgc2luY2UgdGhlcmUgaXMgYSAwIHR1cm4gYWZ0ZXIgdGhhdFxyXG5cdFx0Y29uc3QgY3VycmVudFR1cm4gPSBnYW1lLnR1cm5zLnNpemUgLSAxO1xyXG5cdFx0bGV0IHByZXZpb3VzU3RhdGVFbnRpdGllczogTWFwPG51bWJlciwgRW50aXR5PiA9IGVudGl0aWVzO1xyXG5cdFx0bGV0IHByZXZpb3VzUHJvY2Vzc2VkSXRlbTogSGlzdG9yeUl0ZW0gPSBoaXN0b3J5WzBdO1xyXG5cdFx0bGV0IGFjdGlvbnNGb3JUdXJuOiByZWFkb25seSBBY3Rpb25bXSA9IFtdO1xyXG5cdFx0Ly8gUmVjcmVhdGluZyB0aGlzIGV2ZXJ5IHRpbWUgbGV0cyB0aGUgcGFyc2VycyBzdG9yZSBzdGF0ZSBhbmQgZW1pdCB0aGUgYWN0aW9uIG9ubHkgd2hlbiBuZWNlc3NhcnlcclxuXHRcdGNvbnN0IGFjdGlvblBhcnNlcnM6IFBhcnNlcltdID0gdGhpcy5yZWdpc3RlckFjdGlvblBhcnNlcnMoY29uZmlnKTtcclxuXHRcdGZvciAoY29uc3QgaXRlbSBvZiBoaXN0b3J5KSB7XHJcblx0XHRcdGNvbnN0IGVudGl0aWVzQmVmb3JlQWN0aW9uID0gcHJldmlvdXNTdGF0ZUVudGl0aWVzO1xyXG5cdFx0XHRwcmV2aW91c1N0YXRlRW50aXRpZXMgPSB0aGlzLnN0YXRlUHJvY2Vzc29yU2VydmljZS5hcHBseUhpc3RvcnlJdGVtKHByZXZpb3VzU3RhdGVFbnRpdGllcywgaXRlbSk7XHJcblx0XHRcdHByZXZpb3VzUHJvY2Vzc2VkSXRlbSA9IGl0ZW07XHJcblx0XHRcdGFjdGlvbnNGb3JUdXJuID0gdGhpcy51cGRhdGVBY3Rpb25zRm9yVHVybihcclxuXHRcdFx0XHRpdGVtLFxyXG5cdFx0XHRcdGFjdGlvbnNGb3JUdXJuLFxyXG5cdFx0XHRcdGFjdGlvblBhcnNlcnMsXHJcblx0XHRcdFx0ZW50aXRpZXNCZWZvcmVBY3Rpb24sXHJcblx0XHRcdFx0aGlzdG9yeSxcclxuXHRcdFx0XHRnYW1lLFxyXG5cdFx0XHQpO1xyXG5cdFx0fVxyXG5cclxuXHRcdHByZXZpb3VzU3RhdGVFbnRpdGllcyA9IHRoaXMuc3RhdGVQcm9jZXNzb3JTZXJ2aWNlLmFwcGx5SGlzdG9yeVVudGlsRW5kKFxyXG5cdFx0XHRwcmV2aW91c1N0YXRlRW50aXRpZXMsXHJcblx0XHRcdGhpc3RvcnksXHJcblx0XHRcdHByZXZpb3VzUHJvY2Vzc2VkSXRlbSxcclxuXHRcdCk7XHJcblx0XHQvLyBTb3J0IGFjdGlvbnMgYmFzZWQgb24gdGhlaXIgaW5kZXggKHNvIHRoYXQgYWN0aW9ucyB0aGF0IHdlcmUgY3JlYXRlZCBmcm9tIHRoZSBzYW1lXHJcblx0XHQvLyBwYXJlbnQgYWN0aW9uIGNhbiBoYXZlIGEgY3VzdG9tIG9yZGVyKVxyXG5cdFx0YWN0aW9uc0ZvclR1cm4gPSB0aGlzLnNvcnRBY3Rpb25zKFxyXG5cdFx0XHRhY3Rpb25zRm9yVHVybixcclxuXHRcdFx0KGE6IEFjdGlvbiwgYjogQWN0aW9uKSA9PiBhLmluZGV4IC0gYi5pbmRleCB8fCBhLnRpbWVzdGFtcCAtIGIudGltZXN0YW1wLFxyXG5cdFx0KTtcclxuXHRcdGFjdGlvbnNGb3JUdXJuID0gdGhpcy5maWxsTWlzc2luZ0VudGl0aWVzKGFjdGlvbnNGb3JUdXJuLCBwcmV2aW91c1N0YXRlRW50aXRpZXMpO1xyXG5cdFx0Ly8gR2l2ZSBhbiBvcHBvcnR1bml0eSB0byBlYWNoIHBhcnNlciB0byBjb21iaW5lIHRoZSBhY3Rpb25zIGl0IHByb2R1Y2VkIGJ5IG1lcmdpbmcgdGhlbVxyXG5cdFx0Ly8gRm9yIGluc3RhbmNlLCBpZiB3ZSB0d28gY2FyZCBkcmF3cyBpbiBhIHJvdywgd2UgbWlnaHQgd2FudCB0byBkaXNwbGF5IHRoZW0gYXMgYSBzaW5nbGVcclxuXHRcdC8vIGFjdGlvbiB0aGF0IGRyYXdzIHR3byBjYXJkc1xyXG5cdFx0YWN0aW9uc0ZvclR1cm4gPSB0aGlzLnJlZHVjZUFjdGlvbnMoYWN0aW9uUGFyc2VycywgYWN0aW9uc0ZvclR1cm4pO1xyXG5cdFx0YWN0aW9uc0ZvclR1cm4gPSB0aGlzLmFkZERhbWFnZVRvRW50aXRpZXMoYWN0aW9uc0ZvclR1cm4sIHByZXZpb3VzU3RhdGVFbnRpdGllcyk7XHJcblx0XHR0cnkge1xyXG5cdFx0XHRpZiAoY3VycmVudFR1cm4gPCAwKSB7XHJcblx0XHRcdFx0Ly8gLy8gY29uc29sZS5sb2coJ2hhbmRsaW5nIGdhbWUgaW5pdCBlbnRpdHkgdXBkYXRlcycpO1xyXG5cdFx0XHRcdHJldHVybiBHYW1lLmNyZWF0ZUdhbWUoZ2FtZSwgeyBlbnRpdGllc0JlZm9yZU11bGxpZ2FuOiBwcmV2aW91c1N0YXRlRW50aXRpZXMgfSBhcyBHYW1lKTtcclxuXHRcdFx0fVxyXG5cdFx0XHRpZiAoIWdhbWUudHVybnMuZ2V0KGN1cnJlbnRUdXJuKSkge1xyXG5cdFx0XHRcdGNvbnNvbGUud2FybignY291bGQgbm90IGdldCBjdXJyZW50IHR1cm4nLCBjdXJyZW50VHVybiwgZ2FtZS50dXJucy50b0pTKCkpO1xyXG5cdFx0XHR9XHJcblx0XHRcdGNvbnN0IHR1cm5XaXRoTmV3QWN0aW9ucyA9IGdhbWUudHVybnMuZ2V0KGN1cnJlbnRUdXJuKS51cGRhdGUoeyBhY3Rpb25zOiBhY3Rpb25zRm9yVHVybiB9KTtcclxuXHRcdFx0Y29uc3QgdHVybk51bWJlciA9IHR1cm5XaXRoTmV3QWN0aW9ucy50dXJuID09PSAnbXVsbGlnYW4nID8gMCA6IHBhcnNlSW50KHR1cm5XaXRoTmV3QWN0aW9ucy50dXJuKTtcclxuXHRcdFx0Y29uc3QgdHVybnMgPSBnYW1lLnR1cm5zLnNldCh0dXJuTnVtYmVyLCB0dXJuV2l0aE5ld0FjdGlvbnMpO1xyXG5cdFx0XHQvLyAvLyBjb25zb2xlLmxvZygndHVybldpdGhOZXdBY3Rpb25zJywgdHVybk51bWJlciwgdHVybldpdGhOZXdBY3Rpb25zLmFjdGlvbnMpO1xyXG5cdFx0XHRjb25zdCByZXN1bHQgPSBHYW1lLmNyZWF0ZUdhbWUoZ2FtZSwgeyB0dXJucyB9IGFzIEdhbWUpO1xyXG5cdFx0XHQvLyAvLyBjb25zb2xlLmxvZygnb3JpZWpnJywgcmVzdWx0LmdldExhdGVzdFBhcnNlZFN0YXRlKCkudG9KUygpKTtcclxuXHRcdFx0cmV0dXJuIHJlc3VsdDtcclxuXHRcdH0gY2F0Y2ggKGUpIHtcclxuXHRcdFx0Y29uc29sZS53YXJuKGN1cnJlbnRUdXJuLCBnYW1lLnR1cm5zLnRvSlMoKSwgYWN0aW9uc0ZvclR1cm4pO1xyXG5cdFx0XHRjb25zb2xlLmVycm9yKGUpO1xyXG5cdFx0XHRyZXR1cm4gZ2FtZTtcclxuXHRcdH1cclxuXHRcdC8vIHRoaXMubG9nZ2VyLmxvZygndG9vaycsIERhdGUubm93KCkgLSBzdGFydCwgJ21zIGZvciBwYXJzZUFjdGlvbnMnKTtcclxuXHR9XHJcblxyXG5cdHByaXZhdGUgdXBkYXRlQWN0aW9uc0ZvclR1cm4oXHJcblx0XHRpdGVtOiBIaXN0b3J5SXRlbSxcclxuXHRcdGFjdGlvbnNGb3JUdXJuOiByZWFkb25seSBBY3Rpb25bXSxcclxuXHRcdGFjdGlvblBhcnNlcnM6IFBhcnNlcltdLFxyXG5cdFx0ZW50aXRpZXNCZWZvcmVBY3Rpb246IE1hcDxudW1iZXIsIEVudGl0eT4sXHJcblx0XHRoaXN0b3J5OiByZWFkb25seSBIaXN0b3J5SXRlbVtdLFxyXG5cdFx0Z2FtZTogR2FtZSxcclxuXHQpOiByZWFkb25seSBBY3Rpb25bXSB7XHJcblx0XHRjb25zdCBjdXJyZW50VHVybiA9IGdhbWUudHVybnMuc2l6ZSAtIDE7XHJcblx0XHRhY3Rpb25QYXJzZXJzLmZvckVhY2goKHBhcnNlcikgPT4ge1xyXG5cdFx0XHRpZiAocGFyc2VyLmFwcGxpZXMoaXRlbSkpIHtcclxuXHRcdFx0XHQvLyBXaGVuIHdlIHBlcmZvcm0gYW4gYWN0aW9uLCB3ZSB3YW50IHRvIHNob3cgdGhlIHJlc3VsdCBvZiB0aGUgc3RhdGUgdXBkYXRlcyB1bnRpbCB0aGUgbmV4dCBhY3Rpb24gaXNcclxuXHRcdFx0XHQvLyBwbGF5ZWQuXHJcblx0XHRcdFx0Y29uc3QgYWN0aW9uczogQWN0aW9uW10gPSBwYXJzZXIucGFyc2UoaXRlbSwgY3VycmVudFR1cm4sIGVudGl0aWVzQmVmb3JlQWN0aW9uLCBoaXN0b3J5LCBnYW1lLnBsYXllcnMpO1xyXG5cdFx0XHRcdGlmIChhY3Rpb25zICYmIGFjdGlvbnMubGVuZ3RoID4gMCkge1xyXG5cdFx0XHRcdFx0YWN0aW9uc0ZvclR1cm4gPSB0aGlzLnNvcnRBY3Rpb25zKFxyXG5cdFx0XHRcdFx0XHRhY3Rpb25zRm9yVHVybixcclxuXHRcdFx0XHRcdFx0KGE6IEFjdGlvbiwgYjogQWN0aW9uKSA9PiBhLmluZGV4IC0gYi5pbmRleCB8fCBhLnRpbWVzdGFtcCAtIGIudGltZXN0YW1wLFxyXG5cdFx0XHRcdFx0KTtcclxuXHRcdFx0XHRcdGFjdGlvbnNGb3JUdXJuID0gdGhpcy5maWxsTWlzc2luZ0VudGl0aWVzKGFjdGlvbnNGb3JUdXJuLCBlbnRpdGllc0JlZm9yZUFjdGlvbik7XHJcblx0XHRcdFx0XHRhY3Rpb25zRm9yVHVybiA9IFsuLi5hY3Rpb25zRm9yVHVybiwgLi4uYWN0aW9uc107XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9XHJcblx0XHR9KTtcclxuXHRcdHJldHVybiBhY3Rpb25zRm9yVHVybjtcclxuXHR9XHJcblxyXG5cdHByaXZhdGUgZmlsbE1pc3NpbmdFbnRpdGllcyhcclxuXHRcdGFjdGlvbnNGb3JUdXJuOiByZWFkb25seSBBY3Rpb25bXSxcclxuXHRcdHByZXZpb3VzU3RhdGVFbnRpdGllczogTWFwPG51bWJlciwgRW50aXR5PixcclxuXHQpOiByZWFkb25seSBBY3Rpb25bXSB7XHJcblx0XHRjb25zdCBuZXdBY3Rpb25zRm9yVHVybiA9IFtdO1xyXG5cdFx0Zm9yIChsZXQgaSA9IDA7IGkgPCBhY3Rpb25zRm9yVHVybi5sZW5ndGg7IGkrKykge1xyXG5cdFx0XHRpZiAoYWN0aW9uc0ZvclR1cm5baV0uZW50aXRpZXMpIHtcclxuXHRcdFx0XHRuZXdBY3Rpb25zRm9yVHVybi5wdXNoKGFjdGlvbnNGb3JUdXJuW2ldKTtcclxuXHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHQvL2lmIChhY3Rpb25zRm9yVHVybltpXSBpbnN0YW5jZW9mIFN1bW1vbkFjdGlvbikge1xyXG5cdFx0XHRcdC8vXHQvLyBjb25zb2xlLmxvZyhcclxuXHRcdFx0XHQvL1x0XHQnZmlsbGluZyBtaXNzaW5nIGVudGl0aWVzIGZvcicsXHJcblx0XHRcdFx0Ly9cdFx0cHJldmlvdXNTdGF0ZUVudGl0aWVzLmdldCgzNSkgJiYgcHJldmlvdXNTdGF0ZUVudGl0aWVzLmdldCgzNSkudGFncy50b0pTKCksXHJcblx0XHRcdFx0Ly9cdFx0YWN0aW9uc0ZvclR1cm5baV0sXHJcblx0XHRcdFx0Ly9cdCk7XHJcblx0XHRcdFx0Ly99XHJcblx0XHRcdFx0bmV3QWN0aW9uc0ZvclR1cm4ucHVzaChhY3Rpb25zRm9yVHVybltpXS51cGRhdGUocHJldmlvdXNTdGF0ZUVudGl0aWVzKSk7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHRcdHJldHVybiBuZXdBY3Rpb25zRm9yVHVybjtcclxuXHR9XHJcblxyXG5cdHByaXZhdGUgYWRkRGFtYWdlVG9FbnRpdGllcyhcclxuXHRcdGFjdGlvbnNGb3JUdXJuOiByZWFkb25seSBBY3Rpb25bXSxcclxuXHRcdHByZXZpb3VzU3RhdGVFbnRpdGllczogTWFwPG51bWJlciwgRW50aXR5PixcclxuXHQpOiByZWFkb25seSBBY3Rpb25bXSB7XHJcblx0XHRjb25zdCBuZXdBY3Rpb25zRm9yVHVybiA9IFtdO1xyXG5cdFx0Zm9yIChsZXQgaSA9IDA7IGkgPCBhY3Rpb25zRm9yVHVybi5sZW5ndGg7IGkrKykge1xyXG5cdFx0XHRpZiAoIWFjdGlvbnNGb3JUdXJuW2ldKSB7XHJcblx0XHRcdFx0Y29uc29sZS53YXJuKCdCQkJCJywgYWN0aW9uc0ZvclR1cm4pO1xyXG5cdFx0XHR9XHJcblx0XHRcdGNvbnN0IG5ld0VudGl0aWVzID0gYWN0aW9uc0ZvclR1cm5baV0uZW50aXRpZXMgPyBhY3Rpb25zRm9yVHVybltpXS5lbnRpdGllcyA6IHByZXZpb3VzU3RhdGVFbnRpdGllcztcclxuXHRcdFx0Y29uc3QgZW50aXRpZXNBZnRlckRhbWFnZVVwZGF0ZTogTWFwPG51bWJlciwgRW50aXR5PiA9IG5ld0VudGl0aWVzXHJcblx0XHRcdFx0Lm1hcCgoZW50aXR5KSA9PiB0aGlzLnVwZGF0ZURhbWFnZUZvckVudGl0eShhY3Rpb25zRm9yVHVybltpXSwgZW50aXR5KSlcclxuXHRcdFx0XHQudG9NYXAoKTtcclxuXHRcdFx0bmV3QWN0aW9uc0ZvclR1cm4ucHVzaChhY3Rpb25zRm9yVHVybltpXS51cGRhdGUoZW50aXRpZXNBZnRlckRhbWFnZVVwZGF0ZSkpO1xyXG5cdFx0fVxyXG5cdFx0cmV0dXJuIG5ld0FjdGlvbnNGb3JUdXJuO1xyXG5cdH1cclxuXHJcblx0cHJpdmF0ZSB1cGRhdGVEYW1hZ2VGb3JFbnRpdHkoYWN0aW9uOiBBY3Rpb24sIGVudGl0eTogRW50aXR5KTogRW50aXR5IHtcclxuXHRcdGlmIChcclxuXHRcdFx0IWFjdGlvbi5kYW1hZ2VzIHx8XHJcblx0XHRcdFtDYXJkVHlwZS5TUEVMTCwgQ2FyZFR5cGUuRU5DSEFOVE1FTlQsIENhcmRUeXBlLkJBVFRMRUdST1VORF9RVUVTVF9SRVdBUkQsIENhcmRUeXBlLkhFUk9fUE9XRVJdLmluY2x1ZGVzKFxyXG5cdFx0XHRcdGVudGl0eS5nZXRUYWcoR2FtZVRhZy5DQVJEVFlQRSksXHJcblx0XHRcdClcclxuXHRcdCkge1xyXG5cdFx0XHRyZXR1cm4gZW50aXR5O1xyXG5cdFx0fVxyXG5cdFx0Y29uc3QgZGFtYWdlczogTWFwPG51bWJlciwgbnVtYmVyPiA9IGFjdGlvbi5kYW1hZ2VzO1xyXG5cdFx0Y29uc3QgZGFtYWdlID0gZGFtYWdlcy5nZXQoZW50aXR5LmlkKTtcclxuXHRcdHJldHVybiBlbnRpdHkudXBkYXRlRGFtYWdlKGRhbWFnZSk7XHJcblx0fVxyXG5cclxuXHQvLyBwcml2YXRlIHVwZGF0ZUN1cnJlbnRUdXJuKGl0ZW06IEhpc3RvcnlJdGVtLCBnYW1lOiBHYW1lLCBhY3Rpb25zOiByZWFkb25seSBBY3Rpb25bXSwgY3VycmVudFR1cm4pOiBbVHVybiwgbnVtYmVyXSB7XHJcblx0Ly8gXHRpZiAoXHJcblx0Ly8gXHRcdGFjdGlvbnMubGVuZ3RoID4gMSAmJlxyXG5cdC8vIFx0XHRhY3Rpb25zW2FjdGlvbnMubGVuZ3RoIC0gMV0gaW5zdGFuY2VvZiBTdGFydFR1cm5BY3Rpb24gJiZcclxuXHQvLyBcdFx0IShhY3Rpb25zW2FjdGlvbnMubGVuZ3RoIC0gMV0gYXMgU3RhcnRUdXJuQWN0aW9uKS5pc1N0YXJ0T2ZNdWxsaWdhblxyXG5cdC8vIFx0KSB7XHJcblx0Ly8gXHRcdGNvbnN0IHR1cm5Ub1VwZGF0ZTogVHVybiA9IGdhbWUudHVybnMuZ2V0KGN1cnJlbnRUdXJuKTtcclxuXHQvLyBcdFx0cmV0dXJuIFt0dXJuVG9VcGRhdGUsIGN1cnJlbnRUdXJuICsgMV07XHJcblx0Ly8gXHR9XHJcblx0Ly8gXHRyZXR1cm4gW251bGwsIGN1cnJlbnRUdXJuXTtcclxuXHQvLyB9XHJcblxyXG5cdHByaXZhdGUgcmVkdWNlQWN0aW9ucyhhY3Rpb25QYXJzZXJzOiBQYXJzZXJbXSwgYWN0aW9uc0ZvclR1cm46IHJlYWRvbmx5IEFjdGlvbltdKTogcmVhZG9ubHkgQWN0aW9uW10ge1xyXG5cdFx0bGV0IHJlZHVjZWRBY3Rpb25zID0gYWN0aW9uc0ZvclR1cm47XHJcblx0XHRmb3IgKGNvbnN0IHBhcnNlciBvZiBhY3Rpb25QYXJzZXJzKSB7XHJcblx0XHRcdC8vIC8vIGNvbnNvbGUubG9nKCdyZWR1Y2luZycsIHBhcnNlciwgYWN0aW9uc0ZvclR1cm4pO1xyXG5cdFx0XHRyZWR1Y2VkQWN0aW9ucyA9IHBhcnNlci5yZWR1Y2UocmVkdWNlZEFjdGlvbnMpO1xyXG5cdFx0fVxyXG5cdFx0Ly8gLy8gY29uc29sZS5sb2coJ2ZpbmlzaGVkIHJvdW5kIG9mIHJlZHVjZXMnKTtcclxuXHRcdC8vIEJlY2F1c2UgdGhlIGRpZmZlcmVudCBwYXJzZXJzIGNhbiBpbnRlcmFjdCB3aXRoIGVhY2ggb3RoZXIsIHdlIG5lZWQgdG8gYXBwbHkgYWxsXHJcblx0XHQvLyBvZiB0aGVtIHVudGlsIHRoZSByZXN1bHQgZG9lc24ndCBjaGFuZ2UgYW55bW9yZVxyXG5cdFx0Ly8gVGhpcyBsb29rcyBoZWF2eSBpbiBwZXJmLCBidXQgdGhlcmUgYXJlbid0IG1hbnkgYWN0aW9ucywgYW5kIGl0IGxldHMgdXNcclxuXHRcdC8vIGhhbmRsZSBlYWNoIGFjdGlvbiB0eXBlIGluZGVwZW5kZW50bHksIHdoaWNoIG1ha2VzIGZvciBtb3JlIHNlcGFyYXRlZCBjb25jZXJuc1xyXG5cdFx0aWYgKCF0aGlzLmFyZUVxdWFsKHJlZHVjZWRBY3Rpb25zLCBhY3Rpb25zRm9yVHVybikpIHtcclxuXHRcdFx0Ly8gLy8gY29uc29sZS5sb2coJ2dvaW5nIGZvciBhbm90aGVyIHJvdW5kJyk7XHJcblx0XHRcdHJldHVybiB0aGlzLnJlZHVjZUFjdGlvbnMoYWN0aW9uUGFyc2VycywgcmVkdWNlZEFjdGlvbnMpO1xyXG5cdFx0fVxyXG5cdFx0Ly8gLy8gY29uc29sZS5sb2coJ2Z1bGx5IGZpbmlzaGVkJyk7XHJcblx0XHRyZXR1cm4gcmVkdWNlZEFjdGlvbnM7XHJcblx0fVxyXG5cclxuXHRwcml2YXRlIHNvcnRBY3Rpb25zPFQ+KGFycmF5OiByZWFkb25seSBUW10sIHNvcnRpbmdGdW5jdGlvbjogKGE6IFQsIGI6IFQpID0+IG51bWJlcik6IHJlYWRvbmx5IFRbXSB7XHJcblx0XHRjb25zdCBpbnRlcm1lZGlhdGU6IFRbXSA9IFsuLi5hcnJheV07XHJcblx0XHRpbnRlcm1lZGlhdGUuc29ydChzb3J0aW5nRnVuY3Rpb24pO1xyXG5cdFx0cmV0dXJuIGludGVybWVkaWF0ZSBhcyByZWFkb25seSBUW107XHJcblx0fVxyXG5cclxuXHRwcml2YXRlIGFyZUVxdWFsKGFjdGlvbnMxOiByZWFkb25seSBBY3Rpb25bXSwgYWN0aW9uczI6IHJlYWRvbmx5IEFjdGlvbltdKTogYm9vbGVhbiB7XHJcblx0XHRpZiAoYWN0aW9uczEubGVuZ3RoICE9PSBhY3Rpb25zMi5sZW5ndGgpIHtcclxuXHRcdFx0cmV0dXJuIGZhbHNlO1xyXG5cdFx0fVxyXG5cdFx0Zm9yIChsZXQgaSA9IDA7IGkgPCBhY3Rpb25zMS5sZW5ndGg7IGkrKykge1xyXG5cdFx0XHRpZiAoYWN0aW9uczFbaV0gIT09IGFjdGlvbnMyW2ldKSB7XHJcblx0XHRcdFx0cmV0dXJuIGZhbHNlO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblx0XHRyZXR1cm4gdHJ1ZTtcclxuXHR9XHJcbn1cclxuIl19