bp-prism-game
Version:
The BP Prism Game
514 lines • 57.9 kB
JavaScript
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs/internal/Subject';
import { AlienPathEnum } from '../enum/alien-path.enum';
import { BLOCK_SIZE } from '../gameboard/gameboard-constants';
import { ObservableTypeEnum } from '../enum/observable-type.enum';
import { TextTypeEnum } from '../enum/text-type.enum';
import { GameAssetEnum } from '../enum/game-assets.enum';
import { AssetTypeEnum } from '../enum/asset-type.enum';
import { ImageLoadedEnum } from '../enum/image-loaded.enum';
import { WaterService } from './water.service';
import { PathService } from './path.service';
import * as i0 from "@angular/core";
import * as i1 from "./image.service";
/**
* The game service
*/
export class GameService {
/**
* The constructor
* @param imageService The imageService from DI
*/
constructor(imageService) {
this.imageService = imageService;
/**
* Master Observable Subject$
*/
this.masterSubject$ = new Subject();
this.addExtraScenery = false;
this.alienBasePositions = [];
this.textPositions = [];
this.sceneryPositions = [];
this.levelPositions = [];
}
/**
* Initialize the board
*
* @param canvas The canvas element
* @param rows The number of rows
* @param columns The number of Columns
* @param blockSize The block size
* @param gameboard The gameboard
*
*
*/
initBoard(canvas, rows, columns, blockSize, gameboard, isAddExtraScenery = false) {
this.addExtraScenery = isAddExtraScenery;
const ctx = canvas.nativeElement.getContext('2d');
// Calculate size of canvas from constants.
ctx.canvas.width = columns * blockSize + 1;
ctx.canvas.height = rows * blockSize + 1;
// Scale so we don't need to give size on every draw.
ctx.scale(blockSize, blockSize);
this.boardsize = {
x: 0,
y: 0,
height: rows,
width: columns
};
this.setGameBoard(gameboard);
this.imageService.loadImages().subscribe((event) => {
if (event === true) {
this.emitMasterObservableEvent({
type: ObservableTypeEnum.imagesLoaded,
booleanData: true
});
}
});
return ctx;
}
/**
* set the board
*
* @param gameboard The gameboard
*
*
* The Game board
* 1 - Blank
* 2 - Trees
* 3 - Rocks
* 4 - Water
* 5 - Grass
* 6 - Slime
* 7 - Lava
* 8 - Main Gunner
* 9 - Alien Base
* 10 - Prism Base
* 11 - Score
* 12 - High Score
* 13 - Level
* 14 - PrismBlastIcon
* 15 - Bridge
* 16 - Path
*/
setGameBoard(inputGameboard) {
const gameboard = JSON.parse(JSON.stringify(inputGameboard));
/* eslint-disable-next-line */
this.gameBoard = Array.from({ length: gameboard.length }, () =>
/* eslint-disable-next-line */
Array(gameboard[0].length).fill(AlienPathEnum.empty));
this.alienBasePositions.length = 0;
this.sceneryPositions.length = 0;
this.levelPositions.length = 0;
this.textPositions.length = 0;
gameboard.map((row, dy) => {
row.map((value, dx) => {
if (value === GameAssetEnum.prismBase) {
this.basePosition = {
x: dx * BLOCK_SIZE,
y: dy * BLOCK_SIZE
};
this.gameBoard[dy][dx] = AlienPathEnum.goal;
}
else if (value === GameAssetEnum.slime ||
value === GameAssetEnum.grass ||
value === GameAssetEnum.tree ||
value === GameAssetEnum.lava ||
value === GameAssetEnum.water ||
value === GameAssetEnum.rock) {
this.gameBoard[dy][dx] = AlienPathEnum.obstacle;
}
else if (value === GameAssetEnum.bridge) {
this.levelPositions.push({
type: AssetTypeEnum.bridge,
imageType: ImageLoadedEnum.bridge,
position: {
x: dx * BLOCK_SIZE,
y: dy * BLOCK_SIZE
}
});
}
else if (value === GameAssetEnum.alienBase) {
this.alienBasePositions.push({
x: dx * BLOCK_SIZE,
y: dy * BLOCK_SIZE
});
this.gameBoard[dy][dx] = AlienPathEnum.alientBase;
}
else if (value === GameAssetEnum.prismBlastIcon) {
this.prismBlastIconPosition = {
x: dx * BLOCK_SIZE,
y: dy * BLOCK_SIZE
};
this.gameBoard[dy][dx] = AlienPathEnum.obstacle;
}
else if (value === GameAssetEnum.mainGunner) {
this.gunnerPosition = {
x: dx * BLOCK_SIZE,
y: dy * BLOCK_SIZE
};
this.gameBoard[dy][dx] = AlienPathEnum.gunner;
}
else if (value === GameAssetEnum.score) {
this.textPositions.push({
type: TextTypeEnum.score,
position: {
x: dx * BLOCK_SIZE,
y: dy * BLOCK_SIZE
}
});
this.gameBoard[dy][dx] = AlienPathEnum.obstacle;
}
else if (value === GameAssetEnum.highScore) {
this.textPositions.push({
type: TextTypeEnum.highScore,
position: {
x: dx * BLOCK_SIZE,
y: dy * BLOCK_SIZE
}
});
this.gameBoard[dy][dx] = AlienPathEnum.obstacle;
}
else if (value === GameAssetEnum.level) {
this.textPositions.push({
type: TextTypeEnum.level,
position: {
x: dx * BLOCK_SIZE,
y: dy * BLOCK_SIZE
}
});
this.gameBoard[dy][dx] = AlienPathEnum.obstacle;
}
else if (value > 0) {
this.gameBoard[dy][dx] = AlienPathEnum.obstacle;
}
});
});
this.addScenery(gameboard);
}
/**
* Add a scenery position
*
* @param dx The x position
* @param dy The y position
* @param type The Asset Type
* @param imageType The Image Type
*/
addNewScenery(dx, dy, type, imageType) {
this.sceneryPositions.push({
type,
imageType,
position: {
x: dx * BLOCK_SIZE,
y: dy * BLOCK_SIZE
}
});
}
/**
* add the scenery
*
* @param sceneryGameboard The gameboard
*
* The Game board
* 1 - Blank
* 2 - Trees
* 3 - Rocks
* 4 - Water
* 5 - Grass
* 6 - Slime
* 7 - Lava
* 8 - Main Gunner
* 9 - Alien Base
* 10 - Prism Base
* 11 - Score
* 12 - High Score
* 13 - Level
* 14 - PrismBlastIcon
* 15 - Bridge
* 16 - Path
*/
addScenery(gameboard) {
const sceneryGameboard = JSON.parse(JSON.stringify(gameboard));
if (this.addExtraScenery) {
const pathService = new PathService();
this.getAlienBasePositions().map((alienBasePosition) => {
const alienPosition = this.convertIAssetToGameboardIAsset(alienBasePosition);
sceneryGameboard[alienPosition.y][alienPosition.x] = GameAssetEnum.path;
sceneryGameboard[alienPosition.y][alienPosition.x + 1] = GameAssetEnum.path;
pathService
.findShortestPath(this.convertIAssetToGameboardIAsset(alienBasePosition), this.gameBoard)
.map((position) => {
position = this.convertIAssetToGameboardIAsset(position);
if (sceneryGameboard[position.y][position.x] !== GameAssetEnum.bridge) {
sceneryGameboard[position.y][position.x] = GameAssetEnum.path;
}
});
});
}
const waterService = new WaterService(sceneryGameboard);
sceneryGameboard.map((row, dy) => {
row.map((value, dx) => {
if (value === GameAssetEnum.slime) {
this.addNewScenery(dx, dy, AssetTypeEnum.slime, ImageLoadedEnum.slime);
}
else if (value === GameAssetEnum.rock) {
this.addNewScenery(dx, dy, AssetTypeEnum.rock, ImageLoadedEnum.rock);
}
else if (value === GameAssetEnum.grass) {
this.addNewScenery(dx, dy, AssetTypeEnum.grass, ImageLoadedEnum.grass);
}
else if (value === GameAssetEnum.tree) {
this.addNewScenery(dx, dy, AssetTypeEnum.tree, ImageLoadedEnum.tree);
}
else if (value === GameAssetEnum.lava) {
this.addNewScenery(dx, dy, AssetTypeEnum.lava, ImageLoadedEnum.lava);
}
else if (value === GameAssetEnum.water) {
this.addNewScenery(dx, dy, AssetTypeEnum.water, waterService.determineWaterValue(dy, dx));
}
else if (value === GameAssetEnum.empty && this.addExtraScenery) {
const randomTreeNumber = Math.floor(Math.random() * 5);
const addNewTree = randomTreeNumber === 0 || randomTreeNumber === 2;
if (addNewTree) {
this.addNewScenery(dx, dy, AssetTypeEnum.tree, ImageLoadedEnum.tree);
}
else {
const randomRockNumber = Math.floor(Math.random() * 2);
const addRock = randomRockNumber === 0;
if (addRock) {
this.addNewScenery(dx, dy, AssetTypeEnum.rock, ImageLoadedEnum.rock);
}
else {
this.addNewScenery(dx, dy, AssetTypeEnum.grass, ImageLoadedEnum.grass);
}
}
}
});
});
}
/**
* Get image
* @param imageType The image type to get
*/
getImage(imageType) {
return this.imageService.getImage(imageType);
}
/**
* Ge the gameboard
*/
getGameBoard() {
return this.gameBoard;
}
/**
* Return the coordinates for the prism blast
*/
getCoordinatesForPrismBlast() {
const position2 = this.getGunnerPosition();
const position1 = this.getBasePosition();
const xDistance = position2.x - position1.x;
const xDistanceSquared = Math.pow(xDistance, 2);
const yDistance = position2.y - position1.y;
const yDistanceSquared = Math.pow(yDistance, 2);
return {
distance: Math.round(Math.pow(xDistanceSquared + yDistanceSquared, 0.5) / BLOCK_SIZE) - 1,
angle: 90 - (Math.atan2(yDistanceSquared, xDistanceSquared) * 180) / Math.PI
};
}
/**
* Get the board size
*/
getBoardSize() {
return this.boardsize;
}
/**
* Valid the Asset
* @param asset The asset
*/
valid(asset) {
return this.gameBoard.every((row) => {
return row.every(() => {
return this.insideWalls(asset.x) && this.aboveFloor(asset.y) && this.belowCeiling(asset.y);
});
});
}
/**
* Convert degress to radians
* @param degrees The degress to conver
*/
getRadians(degrees) {
return Math.round((((degrees % 360) * Math.PI) / 180) * 100000) / 100000;
}
/**
* If the shape has value
* @param value value of the shape
*/
/*
private isEmpty(asset: IAsset): boolean {
const row = this.gameBoard[asset.y];
if (row) {
return this.gameBoard[asset.y][asset.x] === AlienPathEnum.empty;
} else {
return false;
}
}
*/
/**
* Is the piece within the gameboard walls
* @param x The x position
* @param boundary The boundary object
*/
insideWalls(x) {
return x >= 0 && x <= this.boardsize.width;
}
/**
* Is the piece within the gameboard floor
* @param y The y position
*/
belowCeiling(y) {
return y >= 0;
}
/**
* Is the piece within the gameboard floor
* @param y The y position
*/
aboveFloor(y) {
return y < this.boardsize.height;
}
/**
* Is the Base Destroyed
* @param alienPosition The position of the alien
*/
isBaseDestroy(alienPosition) {
if (alienPosition.x === this.basePosition.x && alienPosition.y === this.basePosition.y) {
this.emitMasterObservableEvent({
type: ObservableTypeEnum.prismBaseDestroyed,
booleanData: true
});
return true;
}
return false;
}
/**
* Get the text positions
*/
getTextPositions() {
return this.textPositions;
}
/**
* Get the base position
*/
getBasePosition() {
return this.basePosition;
}
/**
* Get the prism blast icon
*/
getPrismBlastIconPosition() {
return this.prismBlastIconPosition;
}
/**
* Get the gunner position
*/
getGunnerPosition() {
return this.gunnerPosition;
}
/**
* Get the scenery positions
*/
getSceneryPositions() {
return this.sceneryPositions;
}
/**
* Get the level positions
*/
getLevelPositions() {
return this.levelPositions;
}
/**
* Get the alien base positions
*/
getAlienBasePositions() {
return this.alienBasePositions;
}
/**
* convert IAsset to gameboard IAsset
*/
convertIAssetToGameboardIAsset(asset) {
return {
x: Math.round(asset.x / BLOCK_SIZE),
y: Math.round(asset.y / BLOCK_SIZE)
};
}
/**
* Get the boundary
*/
getBoundary() {
return {
left: 0,
right: this.boardsize.width,
ceiling: 0,
floor: this.boardsize.height
};
}
/**
* Determine if an asset has collided with another asset
* @param asset The asset receiving the damage
* @param damageAsset The asset giving the damage
*/
isHit(asset, damageAsset) {
asset = this.convertIAssetToGameboardIAsset(asset);
damageAsset = this.convertIAssetToGameboardIAsset(damageAsset);
return (asset.x <= damageAsset.x &&
damageAsset.x <= asset.x + 1 &&
asset.y <= damageAsset.y &&
damageAsset.y <= asset.y + 1);
}
/**
* Provide the outline
*
* @param ctx The Canvas Rendering Context 2D
* @param columns The number of Columns
* @param rows The number of rows
* @param offset The offset for the grid
*/
addOutlines(ctx, offset, width) {
ctx.fillStyle = 'grey';
let lastIndex = 0;
// vertical lines
for (let index = 0; index < ctx.canvas.width; index += offset) {
ctx.fillRect(index, 0, width, ctx.canvas.height);
lastIndex = index;
}
ctx.fillRect(lastIndex + 1, 0, width, ctx.canvas.height);
// horizontal lines
for (let index = 0; index < ctx.canvas.height; index += offset) {
ctx.fillRect(0, index, ctx.canvas.width, width);
lastIndex = index;
}
ctx.fillRect(0, lastIndex + 1, ctx.canvas.width, width);
ctx.fillStyle = 'red';
ctx.fillRect(ctx.canvas.width / (BLOCK_SIZE * 2), 0, width, ctx.canvas.height);
ctx.fillRect(0, ctx.canvas.height / (BLOCK_SIZE * 2), ctx.canvas.width, width);
}
/**
* Get the master observable
*/
getMasterObservable() {
return this.masterSubject$;
}
/**
* Get the master observable
*/
emitMasterObservableEvent(data) {
this.masterSubject$.next(data);
}
}
GameService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.3.2", ngImport: i0, type: GameService, deps: [{ token: i1.ImageService }], target: i0.ɵɵFactoryTarget.Injectable });
GameService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.3.2", ngImport: i0, type: GameService, providedIn: 'root' });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.3.2", ngImport: i0, type: GameService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root'
}]
}], ctorParameters: function () { return [{ type: i1.ImageService }]; } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2FtZS5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvcHJpc20vc3JjL2xpYi9zZXJ2aWNlL2dhbWUuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFjLE1BQU0sZUFBZSxDQUFDO0FBR3ZELE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUdoRCxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDeEQsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGtDQUFrQyxDQUFDO0FBQzlELE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBRWxFLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUN0RCxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFJekQsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ3hELE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUc1RCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDL0MsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGdCQUFnQixDQUFDOzs7QUFFN0M7O0dBRUc7QUFJSCxNQUFNLE9BQU8sV0FBVztJQXdEdEI7OztPQUdHO0lBQ0gsWUFBb0IsWUFBMEI7UUFBMUIsaUJBQVksR0FBWixZQUFZLENBQWM7UUEzRDlDOztXQUVHO1FBQ0ssbUJBQWMsR0FBRyxJQUFJLE9BQU8sRUFBbUIsQ0FBQztRQXlEdEQsSUFBSSxDQUFDLGVBQWUsR0FBRyxLQUFLLENBQUM7UUFDN0IsSUFBSSxDQUFDLGtCQUFrQixHQUFHLEVBQUUsQ0FBQztRQUM3QixJQUFJLENBQUMsYUFBYSxHQUFHLEVBQUUsQ0FBQztRQUN4QixJQUFJLENBQUMsZ0JBQWdC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TSxFQUFFO1lBQzlELEdBQUcsQ0FBQyxRQUFRLENBQUMsQ0FBQyxFQUFFLEtBQUssRUFBRSxHQUFHLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FBQztZQUNoRCxTQUFTLEdBQUcsS0FBSyxDQUFDO1NBQ25CO1FBRUQsR0FBRyxDQUFDLFFBQVEsQ0FBQyxDQUFDLEVBQUUsU0FBUyxHQUFHLENBQUMsRUFBRSxHQUFHLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FBQztRQUV4RCxHQUFHLENBQUMsU0FBUyxHQUFHLEtBQUssQ0FBQztRQUN0QixHQUFHLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsS0FBSyxHQUFHLENBQUMsVUFBVSxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxLQUFLLEVBQUUsR0FBRyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUMvRSxHQUFHLENBQUMsUUFBUSxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUMsTUFBTSxDQUFDLE1BQU0sR0FBRyxDQUFDLFVBQVUsR0FBRyxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FBQztJQUNqRixDQUFDO0lBRUQ7O09BRUc7SUFDSCxtQkFBbUI7UUFDakIsT0FBTyxJQUFJLENBQUMsY0FBYyxDQUFDO0lBQzdCLENBQUM7SUFFRDs7T0FFRztJQUNILHlCQUF5QixDQUFDLElBQXFCO1FBQzdDLElBQUksQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ2pDLENBQUM7O3dHQW5rQlUsV0FBVzs0R0FBWCxXQUFXLGNBRlYsTUFBTTsyRkFFUCxXQUFXO2tCQUh2QixVQUFVO21CQUFDO29CQUNWLFVBQVUsRUFBRSxNQUFNO2lCQUNuQiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdGFibGUsIEVsZW1lbnRSZWYgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IElBc3NldCB9IGZyb20gJy4uL2ludGVyZmFjZS9hc3NldC5pbnRlcmZhY2UnO1xuaW1wb3J0IHsgT2JzZXJ2YWJsZSB9IGZyb20gJ3J4anMvaW50ZXJuYWwvT2JzZXJ2YWJsZSc7XG5pbXBvcnQgeyBTdWJqZWN0IH0gZnJvbSAncnhqcy9pbnRlcm5hbC9TdWJqZWN0JztcbmltcG9ydCB7IE9ic2VydmFibGVNb2RlbCB9IGZyb20gJy4uL21vZGVsL29ic2VydmFibGUubW9kZWwnO1xuaW1wb3J0IHsgQm91bmRhcnlNb2RlbCB9IGZyb20gJy4uL21vZGVsL2JvdW5kYXJ5Lm1vZGVsJztcbmltcG9ydCB7IEFsaWVuUGF0aEVudW0gfSBmcm9tICcuLi9lbnVtL2FsaWVuLXBhdGguZW51bSc7XG5pbXBvcnQgeyBCTE9DS19TSVpFIH0gZnJvbSAnLi4vZ2FtZWJvYXJkL2dhbWVib2FyZC1jb25zdGFudHMnO1xuaW1wb3J0IHsgT2JzZXJ2YWJsZVR5cGVFbnVtIH0gZnJvbSAnLi4vZW51bS9vYnNlcnZhYmxlLXR5cGUuZW51bSc7XG5pbXBvcnQgeyBCb2FyZE1vZGVsIH0gZnJvbSAnLi4vbW9kZWwvYm9hcmQubW9kZWwnO1xuaW1wb3J0IHsgVGV4dFR5cGVFbnVtIH0gZnJvbSAnLi4vZW51bS90ZXh0LXR5cGUuZW51bSc7XG5pbXBvcnQgeyBHYW1lQXNzZXRFbnVtIH0gZnJvbSAnLi4vZW51bS9nYW1lLWFzc2V0cy5lbnVtJztcbmltcG9ydCB7IFRleHRMb2NhdGlvbk1vZGVsIH0gZnJvbSAnLi4vbW9kZWwvdGV4dC1sb2NhdGlvbi5tb2RlbCc7XG5pbXBvcnQgeyBQcmlzbUJsYXN0Q29vcmRpbmF0ZXNNb2RlbCB9IGZyb20gJy4uL21vZGVsL3ByaXNtLWJsYXN0LWNvb3JkaW5hdGVzLm1vZGVsJztcbmltcG9ydCB7IEFzc2V0TG9jYXRpb25Nb2RlbCB9IGZyb20gJy4uL21vZGVsL2Fzc2V0LWxvY2F0aW9uLm1vZGVsJztcbmltcG9ydCB7IEFzc2V0VHlwZUVudW0gfSBmcm9tICcuLi9lbnVtL2Fzc2V0LXR5cGUuZW51bSc7XG5pbXBvcnQgeyBJbWFnZUxvYWRlZEVudW0gfSBmcm9tICcuLi9lbnVtL2ltYWdlLWxvYWRlZC5lbnVtJztcbmltcG9ydCB7IEltYWdlTG9jYXRpb25Nb2RlbCB9IGZyb20gJy4uL21vZGVsL2ltYWdlL2ltYWdlLWxvY2F0aW9uLm1vZGVsJztcbmltcG9ydCB7IEltYWdlU2VydmljZSB9IGZyb20gJy4vaW1hZ2Uuc2VydmljZSc7XG5pbXBvcnQgeyBXYXRlclNlcnZpY2UgfSBmcm9tICcuL3dhdGVyLnNlcnZpY2UnO1xuaW1wb3J0IHsgUGF0aFNlcnZpY2UgfSBmcm9tICcuL3BhdGguc2VydmljZSc7XG5cbi8qKlxuICogVGhlIGdhbWUgc2VydmljZVxuICovXG5ASW5qZWN0YWJsZSh7XG4gIHByb3ZpZGVkSW46ICdyb290J1xufSlcbmV4cG9ydCBjbGFzcyBHYW1lU2VydmljZSB7XG4gIC8qKlxuICAgKiAgTWFzdGVyIE9ic2VydmFibGUgU3ViamVjdCRcbiAgICovXG4gIHByaXZhdGUgbWFzdGVyU3ViamVjdCQgPSBuZXcgU3ViamVjdDxPYnNlcnZhYmxlTW9kZWw+KCk7XG5cbiAgLyoqXG4gICAqIFRoZSBiYXNlIHBvc2l0aW9uXG4gICAqL1xuICBwcml2YXRlIGJhc2VQb3NpdGlvbjogSUFzc2V0O1xuXG4gIC8qKlxuICAgKiBUaGUgZ3VubmVyIHBvc2l0aW9uXG4gICAqL1xuICBwcml2YXRlIGd1bm5lclBvc2l0aW9uOiBJQXNzZXQ7XG5cbiAgLyoqXG4gICAqIFRoZSBwcmlzbSBibGFzdCBpY29uIHBvc2l0aW9uXG4gICAqL1xuICBwcml2YXRlIHByaXNtQmxhc3RJY29uUG9zaXRpb246IElBc3NldDtcblxuICAvKipcbiAgICogVGhlIHdhdGVyIHBvc2l0aW9uc1xuICAgKi9cbiAgcHJpdmF0ZSBzY2VuZXJ5UG9zaXRpb25zOiBBc3NldExvY2F0aW9uTW9kZWxbXTtcblxuICAvKipcbiAgICogVGhlIGxldmVsIHBvc2l0aW9uc1xuICAgKi9cbiAgcHJpdmF0ZSBsZXZlbFBvc2l0aW9uczogQXNzZXRMb2NhdGlvbk1vZGVsW107XG5cbiAgLyoqXG4gICAqIFRoZSBhbGllbiBiYXNlIHBvc2l0aW9uc1xuICAgKi9cbiAgcHJpdmF0ZSBhbGllbkJhc2VQb3NpdGlvbnM6IElBc3NldFtdO1xuXG4gIC8qKlxuICAgKiBUaGUgZ2FtZSBib2FyZFxuICAgKi9cbiAgcHJpdmF0ZSBnYW1lQm9hcmQ6IEFsaWVuUGF0aEVudW1bXVtdO1xuXG4gIC8qKlxuICAgKiBUaGUgdGV4dCBwb3NpdGlvbnNcbiAgICovXG4gIHByaXZhdGUgdGV4dFBvc2l0aW9uczogVGV4dExvY2F0aW9uTW9kZWxbXTtcblxuICAvKipcbiAgICogVGhlIGJvYXJkXG4gICAqL1xuICBwcml2YXRlIGJvYXJkc2l6ZTogQm9hcmRNb2RlbDtcblxuICAvKipcbiAgICogVGhlIGFkZCBleHRyYSBzY2VuZXJ5XG4gICAqL1xuICBwcml2YXRlIGFkZEV4dHJhU2NlbmVyeTogYm9vbGVhbjtcblxuICAvKipcbiAgICogVGhlIGNvbnN0cnVjdG9yXG4gICAqIEBwYXJhbSBpbWFnZVNlcnZpY2UgVGhlIGltYWdlU2VydmljZSBmcm9tIERJXG4gICAqL1xuICBjb25zdHJ1Y3Rvcihwcml2YXRlIGltYWdlU2VydmljZTogSW1hZ2VTZXJ2aWNlKSB7XG4gICAgdGhpcy5hZGRFeHRyYVNjZW5lcnkgPSBmYWxzZTtcbiAgICB0aGlzLmFsaWVuQmFzZVBvc2l0aW9ucyA9IFtdO1xuICAgIHRoaXMudGV4dFBvc2l0aW9ucyA9IFtdO1xuICAgIHRoaXMuc2NlbmVyeVBvc2l0aW9ucyA9IFtdO1xuICAgIHRoaXMubGV2ZWxQb3NpdGlvbnMgPSBbXTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJbml0aWFsaXplIHRoZSBib2FyZFxuICAgKlxuICAgKiBAcGFyYW0gY2FudmFzIFRoZSBjYW52YXMgZWxlbWVudFxuICAgKiBAcGFyYW0gcm93cyBUaGUgbnVtYmVyIG9mIHJvd3NcbiAgICogQHBhcmFtIGNvbHVtbnMgVGhlIG51bWJlciBvZiBDb2x1bW5zXG4gICAqIEBwYXJhbSBibG9ja1NpemUgVGhlIGJsb2NrIHNpemVcbiAgICogQHBhcmFtIGdhbWVib2FyZCBUaGUgZ2FtZWJvYXJkXG4gICAqXG4gICAqXG4gICAqL1xuICBpbml0Qm9hcmQoXG4gICAgY2FudmFzOiBFbGVtZW50UmVmPEhUTUxDYW52YXNFbGVtZW50PixcbiAgICByb3dzOiBudW1iZXIsXG4gICAgY29sdW1uczogbnVtYmVyLFxuICAgIGJsb2NrU2l6ZTogbnVtYmVyLFxuICAgIGdhbWVib2FyZDogbnVtYmVyW11bXSxcbiAgICBpc0FkZEV4dHJhU2NlbmVyeSA9IGZhbHNlXG4gICk6IENhbnZhc1JlbmRlcmluZ0NvbnRleHQyRCB7XG4gICAgdGhpcy5hZGRFeHRyYVNjZW5lcnkgPSBpc0FkZEV4dHJhU2NlbmVyeTtcbiAgICBjb25zdCBjdHggPSBjYW52YXMubmF0aXZlRWxlbWVudC5nZXRDb250ZXh0KCcyZCcpO1xuXG4gICAgLy8gQ2FsY3VsYXRlIHNpemUgb2YgY2FudmFzIGZyb20gY29uc3RhbnRzLlxuICAgIGN0eC5jYW52YXMud2lkdGggPSBjb2x1bW5zICogYmxvY2tTaXplICsgMTtcbiAgICBjdHguY2FudmFzLmhlaWdodCA9IHJvd3MgKiBibG9ja1NpemUgKyAxO1xuXG4gICAgLy8gU2NhbGUgc28gd2UgZG9uJ3QgbmVlZCB0byBnaXZlIHNpemUgb24gZXZlcnkgZHJhdy5cbiAgICBjdHguc2NhbGUoYmxvY2tTaXplLCBibG9ja1NpemUpO1xuXG4gICAgdGhpcy5ib2FyZHNpemUgPSB7XG4gICAgICB4OiAwLFxuICAgICAgeTogMCxcbiAgICAgIGhlaWdodDogcm93cyxcbiAgICAgIHdpZHRoOiBjb2x1bW5zXG4gICAgfSBhcyBCb2FyZE1vZGVsO1xuXG4gICAgdGhpcy5zZXRHYW1lQm9hcmQoZ2FtZWJvYXJkKTtcblxuICAgIHRoaXMuaW1hZ2VTZXJ2aWNlLmxvYWRJbWFnZXMoKS5zdWJzY3JpYmUoKGV2ZW50OiBib29sZWFuKSA9PiB7XG4gICAgICBpZiAoZXZlbnQgPT09IHRydWUpIHtcbiAgICAgICAgdGhpcy5lbWl0TWFzdGVyT2JzZXJ2YWJsZUV2ZW50KHtcbiAgICAgICAgICB0eXBlOiBPYnNlcnZhYmxlVHlwZUVudW0uaW1hZ2VzTG9hZGVkLFxuICAgICAgICAgIGJvb2xlYW5EYXRhOiB0cnVlXG4gICAgICAgIH0gYXMgT2JzZXJ2YWJsZU1vZGVsKTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHJldHVybiBjdHg7XG4gIH1cblxuICAvKipcbiAgICogc2V0IHRoZSBib2FyZFxuICAgKlxuICAgKiBAcGFyYW0gZ2FtZWJvYXJkIFRoZSBnYW1lYm9hcmRcbiAgICpcbiAgICpcbiAgICogVGhlIEdhbWUgYm9hcmRcbiAgICogMSAtIEJsYW5rXG4gICAqIDIgLSBUcmVlc1xuICAgKiAzIC0gUm9ja3NcbiAgICogNCAtIFdhdGVyXG4gICAqIDUgLSBHcmFzc1xuICAgKiA2IC0gU2xpbWVcbiAgICogNyAtIExhdmFcbiAgICogOCAtIE1haW4gR3VubmVyXG4gICAqIDkgLSBBbGllbiBCYXNlXG4gICAqIDEwIC0gUHJpc20gQmFzZVxuICAgKiAxMSAtIFNjb3JlXG4gICAqIDEyIC0gSGlnaCBTY29yZVxuICAgKiAxMyAtIExldmVsXG4gICAqIDE0IC0gUHJpc21CbGFzdEljb25cbiAgICogMTUgLSBCcmlkZ2VcbiAgICogMTYgLSBQYXRoXG4gICAqL1xuICBzZXRHYW1lQm9hcmQoaW5wdXRHYW1lYm9hcmQ6IG51bWJlcltdW10pOiB2b2lkIHtcbiAgICBjb25zdCBnYW1lYm9hcmQgPSBKU09OLnBhcnNlKEpTT04uc3RyaW5naWZ5KGlucHV0R2FtZWJvYXJkKSkgYXMgbnVtYmVyW11bXTtcbiAgICAvKiBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgKi9cbiAgICB0aGlzLmdhbWVCb2FyZCA9IEFycmF5LmZyb20oeyBsZW5ndGg6IGdhbWVib2FyZC5sZW5ndGggfSwgKCkgPT5cbiAgICAvKiBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgKi9cbiAgICAgIEFycmF5KGdhbWVib2FyZFswXS5sZW5ndGgpLmZpbGwoQWxpZW5QYXRoRW51bS5lbXB0eSlcbiAgICApO1xuXG4gICAgdGhpcy5hbGllbkJhc2VQb3NpdGlvbnMubGVuZ3RoID0gMDtcbiAgICB0aGlzLnNjZW5lcnlQb3NpdGlvbnMubGVuZ3RoID0gMDtcbiAgICB0aGlzLmxldmVsUG9zaXRpb25zLmxlbmd0aCA9IDA7XG4gICAgdGhpcy50ZXh0UG9zaXRpb25zLmxlbmd0aCA9IDA7XG5cbiAgICBnYW1lYm9hcmQubWFwKChyb3c6IG51bWJlcltdLCBkeTogbnVtYmVyKSA9PiB7XG4gICAgICByb3cubWFwKCh2YWx1ZTogbnVtYmVyLCBkeDogbnVtYmVyKSA9PiB7XG4gICAgICAgIGlmICh2YWx1ZSA9PT0gR2FtZUFzc2V0RW51bS5wcmlzbUJhc2UpIHtcbiAgICAgICAgICB0aGlzLmJhc2VQb3NpdGlvbiA9IHtcbiAgICAgICAgICAgIHg6IGR4ICogQkxPQ0tfU0laRSxcbiAgICAgICAgICAgIHk6IGR5ICogQkxPQ0tfU0laRVxuICAgICAgICAgIH0gYXMgSUFzc2V0O1xuICAgICAgICAgIHRoaXMuZ2FtZUJvYXJkW2R5XVtkeF0gPSBBbGllblBhdGhFbnVtLmdvYWw7XG4gICAgICAgIH0gZWxzZSBpZiAoXG4gICAgICAgICAgdmFsdWUgPT09IEdhbWVBc3NldEVudW0uc2xpbWUgfHxcbiAgICAgICAgICB2YWx1ZSA9PT0gR2FtZUFzc2V0RW51bS5ncmFzcyB8fFxuICAgICAgICAgIHZhbHVlID09PSBHYW1lQXNzZXRFbnVtLnRyZWUgfHxcbiAgICAgICAgICB2YWx1ZSA9PT0gR2FtZUFzc2V0RW51bS5sYXZhIHx8XG4gICAgICAgICAgdmFsdWUgPT09IEdhbWVBc3NldEVudW0ud2F0ZXIgfHxcbiAgICAgICAgICB2YWx1ZSA9PT0gR2FtZUFzc2V0RW51bS5yb2NrXG4gICAgICAgICkge1xuICAgICAgICAgIHRoaXMuZ2FtZUJvYXJkW2R5XVtkeF0gPSBBbGllblBhdGhFbnVtLm9ic3RhY2xlO1xuICAgICAgICB9IGVsc2UgaWYgKHZhbHVlID09PSBHYW1lQXNzZXRFbnVtLmJyaWRnZSkge1xuICAgICAgICAgIHRoaXMubGV2ZWxQb3NpdGlvbnMucHVzaCh7XG4gICAgICAgICAgICB0eXBlOiBBc3NldFR5cGVFbnVtLmJyaWRnZSxcbiAgICAgICAgICAgIGltYWdlVHlwZTogSW1hZ2VMb2FkZWRFbnVtLmJyaWRnZSxcbiAgICAgICAgICAgIHBvc2l0aW9uOiB7XG4gICAgICAgICAgICAgIHg6IGR4ICogQkxPQ0tfU0laRSxcbiAgICAgICAgICAgICAgeTogZHkgKiBCTE9DS19TSVpFXG4gICAgICAgICAgICB9IGFzIElBc3NldFxuICAgICAgICAgIH0gYXMgQXNzZXRMb2NhdGlvbk1vZGVsKTtcbiAgICAgICAgfSBlbHNlIGlmICh2YWx1ZSA9PT0gR2FtZUFzc2V0RW51bS5hbGllbkJhc2UpIHtcbiAgICAgICAgICB0aGlzLmFsaWVuQmFzZVBvc2l0aW9ucy5wdXNoKHtcbiAgICAgICAgICAgIHg6IGR4ICogQkxPQ0tfU0laRSxcbiAgICAgICAgICAgIHk6IGR5ICogQkxPQ0tfU0laRVxuICAgICAgICAgIH0gYXMgSUFzc2V0KTtcbiAgICAgICAgICB0aGlzLmdhbWVCb2FyZFtkeV1bZHhdID0gQWxpZW5QYXRoRW51bS5hbGllbnRCYXNlO1xuICAgICAgICB9IGVsc2UgaWYgKHZhbHVlID09PSBHYW1lQXNzZXRFbnVtLnByaXNtQmxhc3RJY29uKSB7XG4gICAgICAgICAgdGhpcy5wcmlzbUJsYXN0SWNvblBvc2l0aW9uID0ge1xuICAgICAgICAgICAgeDogZHggKiBCTE9DS19TSVpFLFxuICAgICAgICAgICAgeTogZHkgKiBCTE9DS19TSVpFXG4gICAgICAgICAgfSBhcyBJQXNzZXQ7XG4gICAgICAgICAgdGhpcy5nYW1lQm9hcmRbZHldW2R4XSA9IEFsaWVuUGF0aEVudW0ub2JzdGFjbGU7XG4gICAgICAgIH0gZWxzZSBpZiAodmFsdWUgPT09IEdhbWVBc3NldEVudW0ubWFpbkd1bm5lcikge1xuICAgICAgICAgIHRoaXMuZ3VubmVyUG9zaXRpb24gPSB7XG4gICAgICAgICAgICB4OiBkeCAqIEJMT0NLX1NJWkUsXG4gICAgICAgICAgICB5OiBkeSAqIEJMT0NLX1NJWkVcbiAgICAgICAgICB9IGFzIElBc3NldDtcbiAgICAgICAgICB0aGlzLmdhbWVCb2FyZFtkeV1bZHhdID0gQWxpZW5QYXRoRW51bS5ndW5uZXI7XG4gICAgICAgIH0gZWxzZSBpZiAodmFsdWUgPT09IEdhbWVBc3NldEVudW0uc2NvcmUpIHtcbiAgICAgICAgICB0aGlzLnRleHRQb3NpdGlvbnMucHVzaCh7XG4gICAgICAgICAgICB0eXBlOiBUZXh0VHlwZUVudW0uc2NvcmUsXG4gICAgICAgICAgICBwb3NpdGlvbjoge1xuICAgICAgICAgICAgICB4OiBkeCAqIEJMT0NLX1NJWkUsXG4gICAgICAgICAgICAgIHk6IGR5ICogQkxPQ0tfU0laRVxuICAgICAgICAgICAgfSBhcyBJQXNzZXRcbiAgICAgICAgICB9IGFzIFRleHRMb2NhdGlvbk1vZGVsKTtcbiAgICAgICAgICB0aGlzLmdhbWVCb2FyZFtkeV1bZHhdID0gQWxpZW5QYXRoRW51bS5vYnN0YWNsZTtcbiAgICAgICAgfSBlbHNlIGlmICh2YWx1ZSA9PT0gR2FtZUFzc2V0RW51bS5oaWdoU2NvcmUpIHtcbiAgICAgICAgICB0aGlzLnRleHRQb3NpdGlvbnMucHVzaCh7XG4gICAgICAgICAgICB0eXBlOiBUZXh0VHlwZUVudW0uaGlnaFNjb3JlLFxuICAgICAgICAgICAgcG9zaXRpb246IHtcbiAgICAgICAgICAgICAgeDogZHggKiBCTE9DS19TSVpFLFxuICAgICAgICAgICAgICB5OiBkeSAqIEJMT0NLX1NJWkVcbiAgICAgICAgICAgIH0gYXMgSUFzc2V0XG4gICAgICAgICAgfSBhcyBUZXh0TG9jYXRpb25Nb2RlbCk7XG4gICAgICAgICAgdGhpcy5nYW1lQm9hcmRbZHldW2R4XSA9IEFsaWVuUGF0aEVudW0ub2JzdGFjbGU7XG4gICAgICAgIH0gZWxzZSBpZiAodmFsdWUgPT09IEdhbWVBc3NldEVudW0ubGV2ZWwpIHtcbiAgICAgICAgICB0aGlzLnRleHRQb3NpdGlvbnMucHVzaCh7XG4gICAgICAgICAgICB0eXBlOiBUZXh0VHlwZUVudW0ubGV2ZWwsXG4gICAgICAgICAgICBwb3NpdGlvbjoge1xuICAgICAgICAgICAgICB4OiBkeCAqIEJMT0NLX1NJWkUsXG4gICAgICAgICAgICAgIHk6IGR5ICogQkxPQ0tfU0laRVxuICAgICAgICAgICAgfSBhcyBJQXNzZXRcbiAgICAgICAgICB9IGFzIFRleHRMb2NhdGlvbk1vZGVsKTtcbiAgICAgICAgICB0aGlzLmdhbWVCb2FyZFtkeV1bZHhdID0gQWxpZW5QYXRoRW51bS5vYnN0YWNsZTtcbiAgICAgICAgfSBlbHNlIGlmICh2YWx1ZSA+IDApIHtcbiAgICAgICAgICB0aGlzLmdhbWVCb2FyZFtkeV1bZHhdID0gQWxpZW5QYXRoRW51bS5vYnN0YWNsZTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICB0aGlzLmFkZFNjZW5lcnkoZ2FtZWJvYXJkKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGQgYSBzY2VuZXJ5IHBvc2l0aW9uXG4gICAqXG4gICAqIEBwYXJhbSBkeCBUaGUgeCBwb3NpdGlvblxuICAgKiBAcGFyYW0gZHkgVGhlIHkgcG9zaXRpb25cbiAgICogQHBhcmFtIHR5cGUgVGhlIEFzc2V0IFR5cGVcbiAgICogQHBhcmFtIGltYWdlVHlwZSBUaGUgSW1hZ2UgVHlwZVxuICAgKi9cbiAgcHJpdmF0ZSBhZGROZXdTY2VuZXJ5KGR4OiBudW1iZXIsIGR5OiBudW1iZXIsIHR5cGU6IEFzc2V0VHlwZUVudW0sIGltYWdlVHlwZTogSW1hZ2VMb2FkZWRFbnVtKTogdm9pZCB7XG4gICAgdGhpcy5zY2VuZXJ5UG9zaXRpb25zLnB1c2goe1xuICAgICAgdHlwZSxcbiAgICAgIGltYWdlVHlwZSxcbiAgICAgIHBvc2l0aW9uOiB7XG4gICAgICAgIHg6IGR4ICogQkxPQ0tfU0laRSxcbiAgICAgICAgeTogZHkgKiBCTE9DS19TSVpFXG4gICAgICB9IGFzIElBc3NldFxuICAgIH0gYXMgQXNzZXRMb2NhdGlvbk1vZGVsKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBhZGQgdGhlIHNjZW5lcnlcbiAgICpcbiAgICogQHBhcmFtIHNjZW5lcnlHYW1lYm9hcmQgVGhlIGdhbWVib2FyZFxuICAgKlxuICAgKiBUaGUgR2FtZSBib2FyZFxuICAgKiAxIC0gQmxhbmtcbiAgICogMiAtIFRyZWVzXG4gICAqIDMgLSBSb2Nrc1xuICAgKiA0IC0gV2F0ZXJcbiAgICogNSAtIEdyYXNzXG4gICAqIDYgLSBTbGltZVxuICAgKiA3IC0gTGF2YVxuICAgKiA4IC0gTWFpbiBHdW5uZXJcbiAgICogOSAtIEFsaWVuIEJhc2VcbiAgICogMTAgLSBQcmlzbSBCYXNlXG4gICAqIDExIC0gU2NvcmVcbiAgICogMTIgLSBIaWdoIFNjb3JlXG4gICAqIDEzIC0gTGV2ZWxcbiAgICogMTQgLSBQcmlzbUJsYXN0SWNvblxuICAgKiAxNSAtIEJyaWRnZVxuICAgKiAxNiAtIFBhdGhcbiAgICovXG4gIHByaXZhdGUgYWRkU2NlbmVyeShnYW1lYm9hcmQ6IG51bWJlcltdW10pOiB2b2lkIHtcbiAgICBjb25zdCBzY2VuZXJ5R2FtZWJvYXJkID0gSlNPTi5wYXJzZShKU09OLnN0cmluZ2lmeShnYW1lYm9hcmQpKSBhcyBudW1iZXJbXVtdO1xuXG4gICAgaWYgKHRoaXMuYWRkRXh0cmFTY2VuZXJ5KSB7XG4gICAgICBjb25zdCBwYXRoU2VydmljZSA9IG5ldyBQYXRoU2VydmljZSgpO1xuICAgICAgdGhpcy5nZXRBbGllbkJhc2VQb3NpdGlvbnMoKS5tYXAoKGFsaWVuQmFzZVBvc2l0aW9uOiBJQXNzZXQpID0+IHtcbiAgICAgICAgY29uc3QgYWxpZW5Qb3NpdGlvbiA9IHRoaXMuY29udmVydElBc3NldFRvR2FtZWJvYXJkSUFzc2V0KGFsaWVuQmFzZVBvc2l0aW9uKTtcbiAgICAgICAgc2NlbmVyeUdhbWVib2FyZFthbGllblBvc2l0aW9uLnldW2FsaWVuUG9zaXRpb24ueF0gPSBHYW1lQXNzZXRFbnVtLnBhdGg7XG4gICAgICAgIHNjZW5lcnlHYW1lYm9hcmRbYWxpZW5Qb3NpdGlvbi55XVthbGllblBvc2l0aW9uLnggKyAxXSA9IEdhbWVBc3NldEVudW0ucGF0aDtcblxuICAgICAgICBwYXRoU2VydmljZVxuICAgICAgICAgIC5maW5kU2hvcnRlc3RQYXRoKHRoaXMuY29udmVydElBc3NldFRvR2FtZWJvYXJkSUFzc2V0KGFsaWVuQmFzZVBvc2l0aW9uKSwgdGhpcy5nYW1lQm9hcmQpXG4gICAgICAgICAgLm1hcCgocG9zaXRpb246IElBc3NldCkgPT4ge1xuICAgICAgICAgICAgcG9zaXRpb24gPSB0aGlzLmNvbnZlcnRJQXNzZXRUb0dhbWVib2FyZElBc3NldChwb3NpdGlvbik7XG4gICAgICAgICAgICBpZiAoc2NlbmVyeUdhbWVib2FyZFtwb3NpdGlvbi55XVtwb3NpdGlvbi54XSAhPT0gR2FtZUFzc2V0RW51bS5icmlkZ2UpIHtcbiAgICAgICAgICAgICAgc2NlbmVyeUdhbWVib2FyZFtwb3NpdGlvbi55XVtwb3NpdGlvbi54XSA9IEdhbWVBc3NldEVudW0ucGF0aDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KTtcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGNvbnN0IHdhdGVyU2VydmljZSA9IG5ldyBXYXRlclNlcnZpY2Uoc2NlbmVyeUdhbWVib2FyZCk7XG4gICAgc2NlbmVyeUdhbWVib2FyZC5tYXAoKHJvdzogbnVtYmVyW10sIGR5OiBudW1iZXIpID0+IHtcbiAgICAgIHJvdy5tYXAoKHZhbHVlOiBudW1iZXIsIGR4OiBudW1iZXIpID0+IHtcbiAgICAgICAgaWYgKHZhbHVlID09PSBHYW1lQXNzZXRFbnVtLnNsaW1lKSB7XG4gICAgICAgICAgdGhpcy5hZGROZXdTY2VuZXJ5KGR4LCBkeSwgQXNzZXRUeXBlRW51bS5zbGltZSwgSW1hZ2VMb2FkZWRFbnVtLnNsaW1lKTtcbiAgICAgICAgfSBlbHNlIGlmICh2YWx1ZSA9PT0gR2FtZUFzc2V0RW51bS5yb2NrKSB7XG4gICAgICAgICAgdGhpcy5hZGROZXdTY2VuZXJ5KGR4LCBkeSwgQXNzZXRUeXBlRW51bS5yb2NrLCBJbWFnZUxvYWRlZEVudW0ucm9jayk7XG4gICAgICAgIH0gZWxzZSBpZiAodmFsdWUgPT09IEdhbWVBc3NldEVudW0uZ3Jhc3MpIHtcbiAgICAgICAgICB0aGlzLmFkZE5ld1NjZW5lcnkoZHgsIGR5LCBBc3NldFR5cGVFbnVtLmdyYXNzLCBJbWFnZUxvYWRlZEVudW0uZ3Jhc3MpO1xuICAgICAgICB9IGVsc2UgaWYgKHZhbHVlID09PSBHYW1lQXNzZXRFbnVtLnRyZWUpIHtcbiAgICAgICAgICB0aGlzLmFkZE5ld1NjZW5lcnkoZHgsIGR5LCBBc3NldFR5cGVFbnVtLnRyZWUsIEltYWdlTG9hZGVkRW51bS50cmVlKTtcbiAgICAgICAgfSBlbHNlIGlmICh2YWx1ZSA9PT0gR2FtZUFzc2V0RW51bS5sYXZhKSB7XG4gICAgICAgICAgdGhpcy5hZGROZXdTY2VuZXJ5KGR4LCBkeSwgQXNzZXRUeXBlRW51bS5sYXZhLCBJbWFnZUxvYWRlZEVudW0ubGF2YSk7XG4gICAgICAgIH0gZWxzZSBpZiAodmFsdWUgPT09IEdhbWVBc3NldEVudW0ud2F0ZXIpIHtcbiAgICAgICAgICB0aGlzLmFkZE5ld1NjZW5lcnkoZHgsIGR5LCBBc3NldFR5cGVFbnVtLndhdGVyLCB3YXRlclNlcnZpY2UuZGV0ZXJtaW5lV2F0ZXJWYWx1ZShkeSwgZHgpKTtcbiAgICAgICAgfSBlbHNlIGlmICh2YWx1ZSA9PT0gR2FtZUFzc2V0RW51bS5lbXB0eSAmJiB0aGlzLmFkZEV4dHJhU2NlbmVyeSkge1xuICAgICAgICAgIGNvbnN0IHJhbmRvbVRyZWVOdW1iZXIgPSBNYXRoLmZsb29yKE1hdGgucmFuZG9tKCkgKiA1KTtcbiAgICAgICAgICBjb25zdCBhZGROZXdUcmVlID0gcmFuZG9tVHJlZU51bWJlciA9PT0gMCB8fCByYW5kb21UcmVlTnVtYmVyID09PSAyO1xuXG4gICAgICAgICAgaWYgKGFkZE5ld1RyZWUpIHtcbiAgICAgICAgICAgIHRoaXMuYWRkTmV3U2NlbmVyeShkeCwgZHksIEFzc2V0VHlwZUVudW0udHJlZSwgSW1hZ2VMb2FkZWRFbnVtLnRyZWUpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjb25zdCByYW5kb21Sb2NrTnVtYmVyID0gTWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpICogMik7XG4gICAgICAgICAgICBjb25zdCBhZGRSb2NrID0gcmFuZG9tUm9ja051bWJlciA9PT0gMDtcbiAgICAgICAgICAgIGlmIChhZGRSb2NrKSB7XG4gICAgICAgICAgICAgIHRoaXMuYWRkTmV3U2NlbmVyeShkeCwgZHksIEFzc2V0VHlwZUVudW0ucm9jaywgSW1hZ2VMb2FkZWRFbnVtLnJvY2spO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgdGhpcy5hZGROZXdTY2VuZXJ5KGR4LCBkeSwgQXNzZXRUeXBlRW51bS5ncmFzcywgSW1hZ2VMb2FkZWRFbnVtLmdyYXNzKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBpbWFnZVxuICAgKiBAcGFyYW0gaW1hZ2VUeXBlIFRoZSBpbWFnZSB0eXBlIHRvIGdldFxuICAgKi9cbiAgcHVibGljIGdldEltYWdlKGltYWdlVHlwZTogSW1hZ2VMb2FkZWRFbnVtKTogSW1hZ2VMb2NhdGlvbk1vZGVsIHtcbiAgICByZXR1cm4gdGhpcy5pbWFnZVNlcnZpY2UuZ2V0SW1hZ2UoaW1hZ2VUeXBlKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZSB0aGUgZ2FtZWJvYXJkXG4gICAqL1xuICBwdWJsaWMgZ2V0R2FtZUJvYXJkKCk6IEFsaWVuUGF0aEVudW1bXVtdIHtcbiAgICByZXR1cm4gdGhpcy5nYW1lQm9hcmQ7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJuIHRoZSBjb29yZGluYXRlcyBmb3IgdGhlIHByaXNtIGJsYXN0XG4gICAqL1x