UNPKG

bp-prism-game

Version:
514 lines 57.9 kB
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