UNPKG

homebridge-luxor

Version:

Homebridge Plug-in for the FX Luminaire (Luxor) lighting controller

266 lines 43.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.LuxorPlatform = void 0; const axios = require('axios').default; const BaseController_1 = require("./controller/BaseController"); const ControllerFactory_1 = require("./controller/ControllerFactory"); const LightFactory_1 = require("./lights/LightFactory"); const ZD_Light_1 = require("./lights/ZD_Light"); class LuxorPlatform { constructor(log, config, api) { this.log = log; this.config = config; this.api = api; // this is used to track restored cached accessories this.accessories = []; this.currGroupsAndThemes = []; this.config = config; this.log = log; this.Service = this.api.hap.Service; this.Characteristic = this.api.hap.Characteristic; this.Name = config.name; this.lastDateAdded = Date.now(); this.controller = ControllerFactory_1.ControllerFactory.createController({ type: 'base' }, this.log); if (api) { // Save the API object as plugin needs to register new this.api.platformAccessory via this object. this.api = api; // Listen to event "didFinishLaunching", this means homebridge already finished loading cached accessories // Platform Plugin should only register new this.api.platformAccessory that doesn't exist in homebridge after this event. // Or start discover new accessories this.api.on('didFinishLaunching', this.didFinishLaunchingAsync.bind(this)); } } async sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } // Function invoked when homebridge tries to restore cached accessory // Developer can configure accessory at here (like setup event handler) configureAccessory(accessory) { this.log.debug(`Retrieved cached accessory ${accessory.displayName} with UUID ${accessory.UUID}`); this.accessories[accessory.UUID] = accessory; } async getControllerAsync() { // get the name of the controller this.log.info(this.Name + ": Starting search for controller at: " + this.config.ipAddr); try { //Search for controllor and make sure we can find it const response = await axios({ method: 'post', url: 'http://' + this.config.ipAddr + '/ControllerName.json', timeout: this.config.commandTimeout || 750 }); if (response.status !== 200) { this.log.error('Received a status code of ' + response.status + ' when trying to connect to the controller.'); return false; } let controllerNameData = response.data; controllerNameData.ip = this.config.ipAddr; controllerNameData.platform = this; controllerNameData.commandTimeout = this.config.commandTimeout; if (controllerNameData.Controller.substring(0, 5) === 'luxor') { controllerNameData.type = BaseController_1.IControllerType.ZD; } else if (controllerNameData.Controller.substring(0, 5) === 'lxzdc') { controllerNameData.type = BaseController_1.IControllerType.ZDC; } else if (controllerNameData.Controller.substring(0, 5) === 'lxtwo') { controllerNameData.type = BaseController_1.IControllerType.ZDTWO; } else { controllerNameData.type = BaseController_1.IControllerType.ZDTWO; this.log.info('Found unknown controller named %s of type %s, assuming a ZDTWO', controllerNameData.Controller, controllerNameData.type); } this.log.info(`Found Controller named ${controllerNameData.Controller} of type ${controllerNameData.type}.`); this.controller = ControllerFactory_1.ControllerFactory.createController(controllerNameData, this.log); return true; } catch (err) { this.log.error(this.Name + ' was not able to connect to connect to the controller. ', err); return false; } ; } async getControllerGroupListAsync() { // Get the list of light groups from the controller if (this.config.hideGroups) return; try { let groupLists = await this.controller.GroupListGetAsync(); this.log.info(`Retrieved ${groupLists.length} light groups from controller.`); for (var i in groupLists) { this.currGroupsAndThemes.push(groupLists[i]); } } catch (err) { this.log.error(`was not able to retrieve light groups from controller.\n${err}\n${err}`); } ; } async getControllerThemeListAsync() { // Get the list of light LuxorThemes from the controller try { let themeLists = await this.controller.ThemeListGetAsync(); this.log.info(`Retrieved ${themeLists.length} themes from controller.`); if (typeof this.config.noAllThemes !== 'undefined' && this.config.noAllThemes) { this.log.info(`Not creating Illuminate All and Extinguish All themes per config setting.`); } else { themeLists.push({ Name: 'Illuminate all lights', ThemeIndex: 100, OnOff: 0, isOn: false, type: ZD_Light_1.ILightType.THEME }); themeLists.push({ Name: 'Extinguish all lights', ThemeIndex: 101, OnOff: 0, isOn: false, type: ZD_Light_1.ILightType.THEME }); } for (var i in themeLists) { themeLists[i].type = ZD_Light_1.ILightType.THEME; this.currGroupsAndThemes.push(themeLists[i]); } } catch (err) { this.log.error('was not able to retrieve light themes from controller.', err); } ; } removeAccessories() { for (var UUID in this.accessories) { let accessory = this.accessories[UUID]; if (typeof this.config.removeAllAccessories !== 'undefined' && this.config.removeAllAccessories || typeof this.config.removeAccessories !== 'undefined' && this.config.removeAccessories.includes(accessory.UUID)) { this.log.info(`Removing cached accessory ${accessory.displayName} with UUID ${accessory.UUID} per platform configuration settings.`); this.api.unregisterPlatformAccessories("homebridge-luxor", "Luxor", [accessory]); this.accessories = this.accessories.filter(item => item.UUID !== UUID); } ; } } addGroupAccessory(lightGroup) { var accessory = new this.api.platformAccessory(lightGroup.Name, lightGroup.UUID); let context = { lastDateAdded: this.lastDateAdded, color: lightGroup.Color, groupNumber: lightGroup.GroupNumber, brightness: lightGroup.Intensity, type: lightGroup.type, isOn: lightGroup.Intensity > 0, independentColors: this.config.independentColors, commandTimeout: this.config.commandTimeout }; accessory.context = context; LightFactory_1.LightFactory.createLight(this, accessory); this.api.registerPlatformAccessories("homebridge-luxor", "Luxor", [accessory]); } addThemeAccessory(themeGroup) { var accessory = new this.api.platformAccessory(themeGroup.Name, themeGroup.UUID); let context = { lastDateAdded: this.lastDateAdded, type: ZD_Light_1.ILightType.THEME, isOn: themeGroup.OnOff === 1, themeIndex: themeGroup.ThemeIndex, OnOff: themeGroup.OnOff, commandTimeout: this.config.commandTimeout }; accessory.context = context; LightFactory_1.LightFactory.createLight(this, accessory); this.accessories[accessory.UUID] = accessory; this.api.registerPlatformAccessories("homebridge-luxor", "Luxor", [accessory]); } assignUUIDs() { for (let i = 0; i < this.currGroupsAndThemes.length; i++) { let acc = this.currGroupsAndThemes[i]; if (typeof acc.ThemeIndex !== 'undefined') { acc.UUID = this.api.hap.uuid.generate('luxor.' + `theme-${acc.ThemeIndex}`); } else { acc.UUID = this.api.hap.uuid.generate('luxor.' + `group.-${acc.GroupNumber}`); } } } async processAccessories() { this.assignUUIDs(); this.removeAccessories(); for (var UUID in this.accessories) { let cachedAcc = this.accessories[UUID]; // look for match on current devices let remove = true; for (let j = 0; j < this.currGroupsAndThemes.length; j++) { let currAcc = this.currGroupsAndThemes[j]; if (cachedAcc.UUID === currAcc.UUID) { // found existing device this.log.info(`Loading cached accessory ${cachedAcc.displayName} with UUID ${cachedAcc.UUID}.`); // update cached device (name, etc) let context = cachedAcc.context; context.lastDateAdded = this.lastDateAdded; if (typeof currAcc.Color !== 'undefined') context.color = currAcc.Color; if (typeof currAcc.GroupNumber !== 'undefined') context.groupNumber = currAcc.GroupNumber; if (typeof currAcc.ThemeIndex !== 'undefined') context.themeIndex = currAcc.ThemeIndex; if (typeof currAcc.Intensity !== 'undefined') { context.brightness = currAcc.Intensity; context.isOn = currAcc.Intensity > 0; } if (typeof currAcc.type !== 'undefined') context.type = currAcc.type; if (typeof currAcc.isOn !== 'undefined') context.isOn = currAcc.isOn; if (typeof currAcc.Name !== 'undefined') cachedAcc.displayName = currAcc.Name; cachedAcc.context = context; this.api.updatePlatformAccessories([cachedAcc]); LightFactory_1.LightFactory.createLight(this, cachedAcc); this.currGroupsAndThemes.splice(j, 1); remove = false; break; } } // remove the cachedAcc that can't be matched if (remove) { this.log.info(`Removing cached accessory ${cachedAcc.displayName} with UUID ${cachedAcc.UUID}.`); this.api.unregisterPlatformAccessories("homebridge-luxor", "Luxor", [cachedAcc]); } } // add any new accessories that were not previously matched if (this.currGroupsAndThemes.length > 0) { for (let j = 0; j < this.currGroupsAndThemes.length; j++) { let currAcc = this.currGroupsAndThemes[j]; this.log.info(`Adding new accessory ${currAcc.Name} with UUID ${currAcc.UUID}.`); if (currAcc.type === ZD_Light_1.ILightType.THEME) this.addThemeAccessory(currAcc); else this.addGroupAccessory(currAcc); } } } async didFinishLaunchingAsync() { if (!this.config.ipAddr) { this.log.error(this.Name + " needs an IP Address in the config file. Please see sample_config.json."); } try { while (await this.getControllerAsync() == false) { this.log.info(`Unable to connect to Luxor controller. Waiting 60s and will retry.`); await this.sleep(60 * 1000); } //this.retrieveCachedAccessories(); await this.getControllerGroupListAsync(); await this.getControllerThemeListAsync(); await this.processAccessories(); // this.removeOphanedAccessories(); this.log.info('Finished initializing'); } catch (err) { this.log.error('Error in didFinishLaunching', err); } ; } } exports.LuxorPlatform = LuxorPlatform; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTHV4b3JQbGF0Zm9ybS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9MdXhvclBsYXRmb3JtLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLE1BQU0sS0FBSyxHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQyxPQUFPLENBQUM7QUFLdkMsZ0VBQXNHO0FBQ3RHLHNFQUFtRTtBQUNuRSx3REFBcUQ7QUFFckQsZ0RBQStDO0FBSS9DLE1BQWEsYUFBYTtJQVV0QixZQUNvQixHQUFXLEVBQ1gsTUFBc0IsRUFDdEIsR0FBUTtRQUZSLFFBQUcsR0FBSCxHQUFHLENBQVE7UUFDWCxXQUFNLEdBQU4sTUFBTSxDQUFnQjtRQUN0QixRQUFHLEdBQUgsR0FBRyxDQUFLO1FBWjVCLG9EQUFvRDtRQUM3QyxnQkFBVyxHQUF3QixFQUFFLENBQUM7UUFNckMsd0JBQW1CLEdBQWdDLEVBQUUsQ0FBQztRQU8xRCxJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQztRQUNyQixJQUFJLENBQUMsR0FBRyxHQUFHLEdBQUcsQ0FBQztRQUNmLElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDO1FBQ3BDLElBQUksQ0FBQyxjQUFjLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsY0FBYyxDQUFDO1FBQ2xELElBQUksQ0FBQyxJQUFJLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQztRQUN4QixJQUFJLENBQUMsYUFBYSxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztRQUNoQyxJQUFJLENBQUMsVUFBVSxHQUFHLHFDQUFpQixDQUFDLGdCQUFnQixDQUFDLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRSxFQUFFLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQTtRQUVoRixJQUFJLEdBQUcsRUFBRTtZQUNMLGtHQUFrRztZQUNsRyxJQUFJLENBQUMsR0FBRyxHQUFHLEdBQUcsQ0FB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Q0FBQzs7b0JBRWhDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxPQUFPLENBQUMsQ0FBQzthQUN2QztTQUNKO0lBQ0wsQ0FBQztJQUVELEtBQUssQ0FBQyx1QkFBdUI7UUFDekIsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxFQUFFO1lBQ3JCLElBQUksQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLEdBQUcsMEVBQTBFLENBQUMsQ0FBQztTQUMxRztRQUNELElBQUk7WUFDQSxPQUFPLE1BQU0sSUFBSSxDQUFDLGtCQUFrQixFQUFFLElBQUksS0FBSyxFQUFFO2dCQUM3QyxJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxxRUFBcUUsQ0FBQyxDQUFBO2dCQUNwRixNQUFNLElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRSxHQUFDLElBQUksQ0FBQyxDQUFDO2FBQzdCO1lBQ0QsbUNBQW1DO1lBQ25DLE1BQU0sSUFBSSxDQUFDLDJCQUEyQixFQUFFLENBQUM7WUFDekMsTUFBTSxJQUFJLENBQUMsMkJBQTJCLEVBQUUsQ0FBQztZQUN6QyxNQUFNLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxDQUFDO1lBQ2hDLG1DQUFtQztZQUNuQyxJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyx1QkFBdUIsQ0FBQyxDQUFDO1NBQzFDO1FBQ0QsT0FBTyxHQUFHLEVBQUU7WUFDUixJQUFJLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyw2QkFBNkIsRUFBRSxHQUFHLENBQUMsQ0FBQztTQUN0RDtRQUFBLENBQUM7SUFDTixDQUFDO0NBQ0o7QUFoUUQsc0NBZ1FDIiwic291cmNlc0NvbnRlbnQiOlsiY29uc3QgYXhpb3MgPSByZXF1aXJlKCdheGlvcycpLmRlZmF1bHQ7XG5cbmltcG9ydCB7IEF4aW9zUmVzcG9uc2UgfSBmcm9tICdheGlvcyc7XG5pbXBvcnQgeyBBUEksIENoYXJhY3RlcmlzdGljLCBEeW5hbWljUGxhdGZvcm1QbHVnaW4sIExvZ2dlciwgUGxhdGZvcm1BY2Nlc3NvcnksIFBsYXRmb3JtQ29uZmlnLCBTZXJ2aWNlIH0gZnJvbSAnaG9tZWJyaWRnZSc7XG5cbmltcG9ydCB7IEJhc2VDb250cm9sbGVyLCBJQ29udHJvbGxlclR5cGUsIElHcm91cExpc3QsIElUaGVtZUxpc3QgfSBmcm9tICcuL2NvbnRyb2xsZXIvQmFzZUNvbnRyb2xsZXInO1xuaW1wb3J0IHsgQ29udHJvbGxlckZhY3RvcnkgfSBmcm9tICcuL2NvbnRyb2xsZXIvQ29udHJvbGxlckZhY3RvcnknO1xuaW1wb3J0IHsgTGlnaHRGYWN0b3J5IH0gZnJvbSAnLi9saWdodHMvTGlnaHRGYWN0b3J5JztcbmltcG9ydCB7IFRoZW1lIH0gZnJvbSAnLi9saWdodHMvVGhlbWUnO1xuaW1wb3J0IHsgSUxpZ2h0VHlwZSB9IGZyb20gJy4vbGlnaHRzL1pEX0xpZ2h0JztcblxuXG5cbmV4cG9ydCBjbGFzcyBMdXhvclBsYXRmb3JtIGltcGxlbWVudHMgRHluYW1pY1BsYXRmb3JtUGx1Z2luIHtcbiAgICAvLyB0aGlzIGlzIHVzZWQgdG8gdHJhY2sgcmVzdG9yZWQgY2FjaGVkIGFjY2Vzc29yaWVzXG4gICAgcHVibGljIGFjY2Vzc29yaWVzOiBQbGF0Zm9ybUFjY2Vzc29yeVtdID0gW107XG4gICAgcHVibGljIGNvbnRyb2xsZXI6IEJhc2VDb250cm9sbGVyOy8vIHdpbGwgYmUgYXNzaWduZWQgdG8gWkQgb3IgWkRDIGNvbnRyb2xsZXJcbiAgICBwdWJsaWMgTmFtZTogc3RyaW5nO1xuICAgIHB1YmxpYyBsYXN0RGF0ZUFkZGVkOiBudW1iZXI7XG4gICAgcHVibGljIHJlYWRvbmx5IFNlcnZpY2U6IHR5cGVvZiBTZXJ2aWNlO1xuICAgIHB1YmxpYyByZWFkb25seSBDaGFyYWN0ZXJpc3RpYzogdHlwZW9mIENoYXJhY3RlcmlzdGljO1xuICAgIHByaXZhdGUgY3Vyckdyb3Vwc0FuZFRoZW1lczogSUdyb3VwTGlzdFtdICYgSVRoZW1lTGlzdFtdID0gW107XG5cbiAgICBjb25zdHJ1Y3RvcihcbiAgICAgICAgcHVibGljIHJlYWRvbmx5IGxvZzogTG9nZ2VyLFxuICAgICAgICBwdWJsaWMgcmVhZG9ubHkgY29uZmlnOiBQbGF0Zm9ybUNvbmZpZyxcbiAgICAgICAgcHVibGljIHJlYWRvbmx5IGFwaTogQVBJXG4gICAgKSB7XG4gICAgICAgIHRoaXMuY29uZmlnID0gY29uZmlnO1xuICAgICAgICB0aGlzLmxvZyA9IGxvZztcbiAgICAgICAgdGhpcy5TZXJ2aWNlID0gdGhpcy5hcGkuaGFwLlNlcnZpY2U7XG4gICAgICAgIHRoaXMuQ2hhcmFjdGVyaXN0aWMgPSB0aGlzLmFwaS5oYXAuQ2hhcmFjdGVyaXN0aWM7XG4gICAgICAgIHRoaXMuTmFtZSA9IGNvbmZpZy5uYW1lO1xuICAgICAgICB0aGlzLmxhc3REYXRlQWRkZWQgPSBEYXRlLm5vdygpO1xuICAgICAgICB0aGlzLmNvbnRyb2xsZXIgPSBDb250cm9sbGVyRmFjdG9yeS5jcmVhdGVDb250cm9sbGVyKHsgdHlwZTogJ2Jhc2UnIH0sIHRoaXMubG9nKVxuXG4gICAgICAgIGlmIChhcGkpIHtcbiAgICAgICAgICAgIC8vIFNhdmUgdGhlIEFQSSBvYmplY3QgYXMgcGx1Z2luIG5lZWRzIHRvIHJlZ2lzdGVyIG5ldyB0aGlzLmFwaS5wbGF0Zm9ybUFjY2Vzc29yeSB2aWEgdGhpcyBvYmplY3QuXG4gICAgICAgICAgICB0aGlzLmFwaSA9IGFwaTtcblxuICAgICAgICAgICAgLy8gTGlzdGVuIHRvIGV2ZW50IFwiZGlkRmluaXNoTGF1bmNoaW5nXCIsIHRoaXMgbWVhbnMgaG9tZWJyaWRnZSBhbHJlYWR5IGZpbmlzaGVkIGxvYWRpbmcgY2FjaGVkIGFjY2Vzc29yaWVzXG4gICAgICAgICAgICAvLyBQbGF0Zm9ybSBQbHVnaW4gc2hvdWxkIG9ubHkgcmVnaXN0ZXIgbmV3IHRoaXMuYXBpLnBsYXRmb3JtQWNjZXNzb3J5IHRoYXQgZG9lc24ndCBleGlzdCBpbiBob21lYnJpZGdlIGFmdGVyIHRoaXMgZXZlbnQuXG4gICAgICAgICAgICAvLyBPciBzdGFydCBkaXNjb3ZlciBuZXcgYWNjZXNzb3JpZXNcbiAgICAgICAgICAgIHRoaXMuYXBpLm9uKCdkaWRGaW5pc2hMYXVuY2hpbmcnLCB0aGlzLmRpZEZpbmlzaExhdW5jaGluZ0FzeW5jLmJpbmQodGhpcykpO1xuICAgICAgICB9XG4gICAgfVxuICAgIGFzeW5jIHNsZWVwKG1zKSB7XG4gICAgICAgIHJldHVybiBuZXcgUHJvbWlzZShyZXNvbHZlID0+IHNldFRpbWVvdXQocmVzb2x2ZSwgbXMpKTtcbiAgICB9XG4gICAgLy8gRnVuY3Rpb24gaW52b2tlZCB3aGVuIGhvbWVicmlkZ2UgdHJpZXMgdG8gcmVzdG9yZSBjYWNoZWQgYWNjZXNzb3J5XG4gICAgLy8gRGV2ZWxvcGVyIGNhbiBjb25maWd1cmUgYWNjZXNzb3J5IGF0IGhlcmUgKGxpa2Ugc2V0dXAgZXZlbnQgaGFuZGxlcilcbiAgICBjb25maWd1cmVBY2Nlc3NvcnkoYWNjZXNzb3J5OiBQbGF0Zm9ybUFjY2Vzc29yeSkge1xuICAgICAgICB0aGlzLmxvZy5kZWJ1ZyhgUmV0cmlldmVkIGNhY2hlZCBhY2Nlc3NvcnkgJHthY2Nlc3NvcnkuZGlzcGxheU5hbWV9IHdpdGggVVVJRCAke2FjY2Vzc29yeS5VVUlEfWApO1xuICAgICAgICB0aGlzLmFjY2Vzc29yaWVzW2FjY2Vzc29yeS5VVUlEXSA9IGFjY2Vzc29yeTtcbiAgICB9XG4gICAgYXN5bmMgZ2V0Q29udHJvbGxlckFzeW5jKCk6UHJvbWlzZTxib29sZWFuPiB7XG4gICAgICAgIC8vIGdldCB0aGUgbmFtZSBvZiB0aGUgY29udHJvbGxlclxuXG4gICAgICAgIHRoaXMubG9nLmluZm8odGhpcy5OYW1lICsgXCI6IFN0YXJ0aW5nIHNlYXJjaCBmb3IgY29udHJvbGxlciBhdDogXCIgKyB0aGlzLmNvbmZpZy5pcEFkZHIpO1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgLy9TZWFyY2ggZm9yIGNvbnRyb2xsb3IgYW5kIG1ha2Ugc3VyZSB3ZSBjYW4gZmluZCBpdFxuICAgICAgICAgICAgY29uc3QgcmVzcG9uc2U6QXhpb3NSZXNwb25zZSA9IGF3YWl0IGF4aW9zKHtcbiAgICAgICAgICAgICAgICBtZXRob2Q6ICdwb3N0JyxcbiAgICAgICAgICAgICAgICB1cmw6ICdodHRwOi8vJyArIHRoaXMuY29uZmlnLmlwQWRkciArICcvQ29udHJvbGxlck5hbWUuanNvbicsXG4gICAgICAgICAgICAgICAgdGltZW91dDogdGhpcy5jb25maWcuY29tbWFuZFRpbWVvdXQgfHwgNzUwXG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICBcbiAgICAgICAgICAgIGlmIChyZXNwb25zZS5zdGF0dXMgIT09IDIwMCkgeyB0aGlzLmxvZy5lcnJvcignUmVjZWl2ZWQgYSBzdGF0dXMgY29kZSBvZiAnICsgcmVzcG9uc2Uuc3RhdHVzICsgJyB3aGVuIHRyeWluZyB0byBjb25uZWN0IHRvIHRoZSBjb250cm9sbGVyLicpOyByZXR1cm4gZmFsc2U7IH1cbiAgICAgICAgICAgIGxldCBjb250cm9sbGVyTmFtZURhdGEgPSByZXNwb25zZS5kYXRhO1xuICAgICAgICAgICAgY29udHJvbGxlck5hbWVEYXRhLmlwID0gdGhpcy5jb25maWcuaXBBZGRyO1xuICAgICAgICAgICAgY29udHJvbGxlck5hbWVEYXRhLnBsYXRmb3JtID0gdGhpcztcbiAgICAgICAgICAgIGNvbnRyb2xsZXJOYW1lRGF0YS5jb21tYW5kVGltZW91dCA9IHRoaXMuY29uZmlnLmNvbW1hbmRUaW1lb3V0O1xuICAgICAgICAgICAgaWYgKGNvbnRyb2xsZXJOYW1lRGF0YS5Db250cm9sbGVyLnN1YnN0cmluZygwLCA1KSA9PT0gJ2x1eG9yJykge1xuICAgICAgICAgICAgICAgIGNvbnRyb2xsZXJOYW1lRGF0YS50eXBlID0gSUNvbnRyb2xsZXJUeXBlLlpEO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChjb250cm9sbGVyTmFtZURhdGEuQ29udHJvbGxlci5zdWJzdHJpbmcoMCwgNSkgPT09ICdseHpkYycpIHtcbiAgICAgICAgICAgICAgICBjb250cm9sbGVyTmFtZURhdGEudHlwZSA9IElDb250cm9sbGVyVHlwZS5aREM7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKGNvbnRyb2xsZXJOYW1lRGF0YS5Db250cm9sbGVyLnN1YnN0cmluZygwLCA1KSA9PT0gJ2x4dHdvJykge1xuICAgICAgICAgICAgICAgIGNvbnRyb2xsZXJOYW1lRGF0YS50eXBlID0gSUNvbnRyb2xsZXJUeXBlLlpEVFdPO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBjb250cm9sbGVyTmFtZURhdGEudHlwZSA9IElDb250cm9sbGVyVHlwZS5aRFRXTztcbiAgICAgICAgICAgICAgICB0aGlzLmxvZy5pbmZvKCdGb3VuZCB1bmtub3duIGNvbnRyb2xsZXIgbmFtZWQgJXMgb2YgdHlwZSAlcywgYXNzdW1pbmcgYSBaRFRXTycsIGNvbnRyb2xsZXJOYW1lRGF0YS5Db250cm9sbGVyLCBjb250cm9sbGVyTmFtZURhdGEudHlwZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLmxvZy5pbmZvKGBGb3VuZCBDb250cm9sbGVyIG5hbWVkICR7Y29udHJvbGxlck5hbWVEYXRhLkNvbnRyb2xsZXJ9IG9mIHR5cGUgJHtjb250cm9sbGVyTmFtZURhdGEudHlwZX0uYCk7XG4gICAgICAgICAgICB0aGlzLmNvbnRyb2xsZXIgPSBDb250cm9sbGVyRmFjdG9yeS5jcmVhdGVDb250cm9sbGVyKGNvbnRyb2xsZXJOYW1lRGF0YSwgdGhpcy5sb2cpO1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICAgICAgY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgdGhpcy5sb2cuZXJyb3IodGhpcy5OYW1lICsgJyB3YXMgbm90IGFibGUgdG8gY29ubmVjdCB0byBjb25uZWN0IHRvIHRoZSBjb250cm9sbGVyLiAnLCBlcnIpO1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9O1xuXG4gICAgfVxuICAgIGFzeW5jIGdldENvbnRyb2xsZXJHcm91cExpc3RBc3luYygpIHtcbiAgICAgICAgLy8gR2V0IHRoZSBsaXN0IG9mIGxpZ2h0IGdyb3VwcyBmcm9tIHRoZSBjb250cm9sbGVyXG4gICAgICAgIGlmICh0aGlzLmNvbmZpZy5oaWRlR3JvdXBzKSByZXR1cm47XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBsZXQgZ3JvdXBMaXN0cyA9IGF3YWl0IHRoaXMuY29udHJvbGxlci5Hcm91cExpc3RHZXRBc3luYygpO1xuICAgICAgICAgICAgdGhpcy5sb2cuaW5mbyhgUmV0cmlldmVkICR7Z3JvdXBMaXN0cy5sZW5ndGh9IGxpZ2h0IGdyb3VwcyBmcm9tIGNvbnRyb2xsZXIuYCk7XG4gICAgICAgICAgICBmb3IgKHZhciBpIGluIGdyb3VwTGlzdHMpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmN1cnJHcm91cHNBbmRUaGVtZXMucHVzaChncm91cExpc3RzW2ldKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICB0aGlzLmxvZy5lcnJvcihgd2FzIG5vdCBhYmxlIHRvIHJldHJpZXZlIGxpZ2h0IGdyb3VwcyBmcm9tIGNvbnRyb2xsZXIuXFxuJHtlcnJ9XFxuJHtlcnJ9YCk7XG4gICAgICAgIH07XG4gICAgfVxuICAgIGFzeW5jIGdldENvbnRyb2xsZXJUaGVtZUxpc3RBc3luYygpIHtcbiAgICAgICAgLy8gR2V0IHRoZSBsaXN0IG9mIGxpZ2h0IEx1eG9yVGhlbWVzIGZyb20gdGhlIGNvbnRyb2xsZXJcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGxldCB0aGVtZUxpc3RzID0gYXdhaXQgdGhpcy5jb250cm9sbGVyLlRoZW1lTGlzdEdldEFzeW5jKCk7XG4gICAgICAgICAgICB0aGlzLmxvZy5pbmZvKGBSZXRyaWV2ZWQgJHt0aGVtZUxpc3RzLmxlbmd0aH0gdGhlbWVzIGZyb20gY29udHJvbGxlci5gKTtcblxuICAgICAgICAgICAgaWYgKHR5cGVvZiB0aGlzLmNvbmZpZy5ub0FsbFRoZW1lcyAhPT0gJ3VuZGVmaW5lZCcgJiYgdGhpcy5jb25maWcubm9BbGxUaGVtZXMpe1xuICAgICAgICAgICAgICAgIHRoaXMubG9nLmluZm8oYE5vdCBjcmVhdGluZyBJbGx1bWluYXRlIEFsbCBhbmQgRXh0aW5ndWlzaCBBbGwgdGhlbWVzIHBlciBjb25maWcgc2V0dGluZy5gKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIHRoZW1lTGlzdHMucHVzaCh7XG4gICAgICAgICAgICAgICAgICAgIE5hbWU6ICdJbGx1bWluYXRlIGFsbCBsaWdodHMnLFxuICAgICAgICAgICAgICAgICAgICBUaGVtZUluZGV4OiAxMDAsXG4gICAgICAgICAgICAgICAgICAgIE9uT2ZmOiAwLFxuICAgICAgICAgICAgICAgICAgICBpc09uOiBmYWxzZSxcbiAgICAgICAgICAgICAgICAgICAgdHlwZTogSUxpZ2h0VHlwZS5USEVNRVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIHRoZW1lTGlzdHMucHVzaCh7XG4gICAgICAgICAgICAgICAgICAgIE5hbWU6ICdFeHRpbmd1aXNoIGFsbCBsaWdodHMnLFxuICAgICAgICAgICAgICAgICAgICBUaGVtZUluZGV4OiAxMDEsXG4gICAgICAgICAgICAgICAgICAgIE9uT2ZmOiAwLFxuICAgICAgICAgICAgICAgICAgICBpc09uOiBmYWxzZSxcbiAgICAgICAgICAgICAgICAgICAgdHlwZTogSUxpZ2h0VHlwZS5USEVNRVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZm9yICh2YXIgaSBpbiB0aGVtZUxpc3RzKSB7XG4gICAgICAgICAgICAgICAgdGhlbWVMaXN0c1tpXS50eXBlID0gSUxpZ2h0VHlwZS5USEVNRTtcbiAgICAgICAgICAgICAgICB0aGlzLmN1cnJHcm91cHNBbmRUaGVtZXMucHVzaCh0aGVtZUxpc3RzW2ldKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICB0aGlzLmxvZy5lcnJvcignd2FzIG5vdCBhYmxlIHRvIHJldHJpZXZlIGxpZ2h0IHRoZW1lcyBmcm9tIGNvbnRyb2xsZXIuJywgZXJyKTtcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICByZW1vdmVBY2Nlc3NvcmllcygpIHtcbiAgICAgICAgZm9yICh2YXIgVVVJRCBpbiB0aGlzLmFjY2Vzc29yaWVzKSB7XG4gICAgICAgICAgICBsZXQgYWNjZXNzb3J5ID0gdGhpcy5hY2Nlc3Nvcmllc1tVVUlEXTtcbiAgICAgICAgICAgIGlmICh0eXBlb2YgdGhpcy5jb25maWcucmVtb3ZlQWxsQWNjZXNzb3JpZXMgIT09ICd1bmRlZmluZWQnICYmIHRoaXMuY29uZmlnLnJlbW92ZUFsbEFjY2Vzc29yaWVzIHx8IHR5cGVvZiB0aGlzLmNvbmZpZy5yZW1vdmVBY2Nlc3NvcmllcyAhPT0gJ3VuZGVmaW5lZCcgJiYgdGhpcy5jb25maWcucmVtb3ZlQWNjZXNzb3JpZXMuaW5jbHVkZXMoYWNjZXNzb3J5LlVVSUQpKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5sb2cuaW5mbyhgUmVtb3ZpbmcgY2FjaGVkIGFjY2Vzc29yeSAke2FjY2Vzc29yeS5kaXNwbGF5TmFtZX0gd2l0aCBVVUlEICR7YWNjZXNzb3J5LlVVSUR9IHBlciBwbGF0Zm9ybSBjb25maWd1cmF0aW9uIHNldHRpbmdzLmApO1xuICAgICAgICAgICAgICAgIHRoaXMuYXBpLnVucmVnaXN0ZXJQbGF0Zm9ybUFjY2Vzc29yaWVzKFwiaG9tZWJyaWRnZS1sdXhvclwiLCBcIkx1eG9yXCIsIFthY2Nlc3NvcnldKTtcbiAgICAgICAgICAgICAgICB0aGlzLmFjY2Vzc29yaWVzID0gdGhpcy5hY2Nlc3Nvcmllcy5maWx0ZXIoaXRlbSA9PiBpdGVtLlVVSUQgIT09IFVVSUQpO1xuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGFkZEdyb3VwQWNjZXNzb3J5KGxpZ2h0R3JvdXA6IElHcm91cExpc3QpIHtcbiAgICAgICAgdmFyIGFjY2Vzc29yeSA9IG5ldyB0aGlzLmFwaS5wbGF0Zm9ybUFjY2Vzc29yeShsaWdodEdyb3VwLk5hbWUsIGxpZ2h0R3JvdXAuVVVJRCk7XG4gICAgICAgIGxldCBjb250ZXh0OiBJQ29udGV4dCA9IHtcbiAgICAgICAgICAgIGxhc3REYXRlQWRkZWQ6IHRoaXMubGFzdERhdGVBZGRlZCxcbiAgICAgICAgICAgIGNvbG9yOiBsaWdodEdyb3VwLkNvbG9yLFxuICAgICAgICAgICAgZ3JvdXBOdW1iZXI6IGxpZ2h0R3JvdXAuR3JvdXBOdW1iZXIsXG4gICAgICAgICAgICBicmlnaHRuZXNzOiBsaWdodEdyb3VwLkludGVuc2l0eSxcbiAgICAgICAgICAgIHR5cGU6IGxpZ2h0R3JvdXAudHlwZSxcbiAgICAgICAgICAgIGlzT246IGxpZ2h0R3JvdXAuSW50ZW5zaXR5ID4gMCxcbiAgICAgICAgICAgIGluZGVwZW5kZW50Q29sb3JzOiB0aGlzLmNvbmZpZy5pbmRlcGVuZGVudENvbG9ycyxcbiAgICAgICAgICAgIGNvbW1hbmRUaW1lb3V0OiB0aGlzLmNvbmZpZy5jb21tYW5kVGltZW91dFxuICAgICAgICB9XG4gICAgICAgIGFjY2Vzc29yeS5jb250ZXh0ID0gY29udGV4dDtcbiAgICAgICAgTGlnaHRGYWN0b3J5LmNyZWF0ZUxpZ2h0KHRoaXMsIGFjY2Vzc29yeSk7XG4gICAgICAgIHRoaXMuYXBpLnJlZ2lzdGVyUGxhdGZvcm1BY2Nlc3NvcmllcyhcImhvbWVicmlkZ2UtbHV4b3JcIiwgXCJMdXhvclwiLCBbYWNjZXNzb3J5XSk7XG4gICAgfVxuXG4gICAgYWRkVGhlbWVBY2Nlc3NvcnkodGhlbWVHcm91cDogSVRoZW1lTGlzdCkge1xuICAgICAgICB2YXIgYWNjZXNzb3J5ID0gbmV3IHRoaXMuYXBpLnBsYXRmb3JtQWNjZXNzb3J5KHRoZW1lR3JvdXAuTmFtZSwgdGhlbWVHcm91cC5VVUlEKTtcbiAgICAgICAgbGV0IGNvbnRleHQ6IElDb250ZXh0ID0ge1xuICAgICAgICAgICAgbGFzdERhdGVBZGRlZDogdGhpcy5sYXN0RGF0ZUFkZGVkLFxuICAgICAgICAgICAgdHlwZTogSUxpZ2h0VHlwZS5USEVNRSxcbiAgICAgICAgICAgIGlzT246IHRoZW1lR3JvdXAuT25PZmYgPT09IDEsXG4gICAgICAgICAgICB0aGVtZUluZGV4OiB0aGVtZUdyb3VwLlRoZW1lSW5kZXgsXG4gICAgICAgICAgICBPbk9mZjogdGhlbWVHcm91cC5Pbk9mZixcbiAgICAgICAgICAgIGNvbW1hbmRUaW1lb3V0OiB0aGlzLmNvbmZpZy5jb21tYW5kVGltZW91dFxuICAgICAgICB9XG4gICAgICAgIGFjY2Vzc29yeS5jb250ZXh0ID0gY29udGV4dDtcbiAgICAgICAgTGlnaHRGYWN0b3J5LmNyZWF0ZUxpZ2h0KHRoaXMsIGFjY2Vzc29yeSk7XG4gICAgICAgIHRoaXMuYWNjZXNzb3JpZXNbYWNjZXNzb3J5LlVVSURdID0gYWNjZXNzb3J5O1xuICAgICAgICB0aGlzLmFwaS5yZWdpc3RlclBsYXRmb3JtQWNjZXNzb3JpZXMoXCJob21lYnJpZGdlLWx1eG9yXCIsIFwiTHV4b3JcIiwgW2FjY2Vzc29yeV0pO1xuICAgIH1cblxuICAgIGFzc2lnblVVSURzKCkge1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMuY3Vyckdyb3Vwc0FuZFRoZW1lcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgbGV0IGFjYyA9IHRoaXMuY3Vyckdyb3Vwc0FuZFRoZW1lc1tpXTtcbiAgICAgICAgICAgIGlmICh0eXBlb2YgYWNjLlRoZW1lSW5kZXggIT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgICAgICAgICAgYWNjLlVVSUQgPSB0aGlzLmFwaS5oYXAudXVpZC5nZW5lcmF0ZSgnbHV4b3IuJyArIGB0aGVtZS0ke2FjYy5UaGVtZUluZGV4fWApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgYWNjLlVVSUQgPSB0aGlzLmFwaS5oYXAudXVpZC5nZW5lcmF0ZSgnbHV4b3IuJyArIGBncm91cC4tJHthY2MuR3JvdXBOdW1iZXJ9YCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBhc3luYyBwcm9jZXNzQWNjZXNzb3JpZXMoKSB7XG4gICAgICAgIHRoaXMuYXNzaWduVVVJRHMoKTtcbiAgICAgICAgdGhpcy5yZW1vdmVBY2Nlc3NvcmllcygpXG4gICAgICAgIGZvciAodmFyIFVVSUQgaW4gdGhpcy5hY2Nlc3Nvcmllcykge1xuICAgICAgICAgICAgbGV0IGNhY2hlZEFjYyA9IHRoaXMuYWNjZXNzb3JpZXNbVVVJRF07XG4gICAgICAgICAgICAvLyBsb29rIGZvciBtYXRjaCBvbiBjdXJyZW50IGRldmljZXNcbiAgICAgICAgICAgIGxldCByZW1vdmUgPSB0cnVlO1xuICAgICAgICAgICAgZm9yIChsZXQgaiA9IDA7IGogPCB0aGlzLmN1cnJHcm91cHNBbmRUaGVtZXMubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgICAgICAgICBsZXQgY3VyckFjYyA9IHRoaXMuY3Vyckdyb3Vwc0FuZFRoZW1lc1tqXTtcbiAgICAgICAgICAgICAgICBpZiAoY2FjaGVkQWNjLlVVSUQgPT09IGN1cnJBY2MuVVVJRCkge1xuICAgICAgICAgICAgICAgICAgICAvLyBmb3VuZCBleGlzdGluZyBkZXZpY2VcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5sb2cuaW5mbyhgTG9hZGluZyBjYWNoZWQgYWNjZXNzb3J5ICR7Y2FjaGVkQWNjLmRpc3BsYXlOYW1lfSB3aXRoIFVVSUQgJHtjYWNoZWRBY2MuVVVJRH0uYCk7XG4gICAgICAgICAgICAgICAgICAgIC8vIHVwZGF0ZSBjYWNoZWQgZGV2aWNlIChuYW1lLCBldGMpXG4gICAgICAgICAgICAgICAgICAgIGxldCBjb250ZXh0OiBJQ29udGV4dCA9IGNhY2hlZEFjYy5jb250ZXh0IGFzIElDb250ZXh0O1xuICAgICAgICAgICAgICAgICAgICBjb250ZXh0Lmxhc3REYXRlQWRkZWQgPSB0aGlzLmxhc3REYXRlQWRkZWQ7XG4gICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgY3VyckFjYy5Db2xvciAhPT0gJ3VuZGVmaW5lZCcpIGNvbnRleHQuY29sb3IgPSBjdXJyQWNjLkNvbG9yO1xuICAgICAgICAgICAgICAgICAgICBpZiAodHlwZW9mIGN1cnJBY2MuR3JvdXBOdW1iZXIgIT09ICd1bmRlZmluZWQnKSBjb250ZXh0Lmdyb3VwTnVtYmVyID0gY3VyckFjYy5Hcm91cE51bWJlcjtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBjdXJyQWNjLlRoZW1lSW5kZXggIT09ICd1bmRlZmluZWQnKSBjb250ZXh0LnRoZW1lSW5kZXggPSBjdXJyQWNjLlRoZW1lSW5kZXg7XG4gICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgY3VyckFjYy5JbnRlbnNpdHkgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb250ZXh0LmJyaWdodG5lc3MgPSBjdXJyQWNjLkludGVuc2l0eTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRleHQuaXNPbiA9IGN1cnJBY2MuSW50ZW5zaXR5ID4gMDtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBpZiAodHlwZW9mIGN1cnJBY2MudHlwZSAhPT0gJ3VuZGVmaW5lZCcpIGNvbnRleHQudHlwZSA9IGN1cnJBY2MudHlwZTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBjdXJyQWNjLmlzT24gIT09ICd1bmRlZmluZWQnKSBjb250ZXh0LmlzT24gPSBjdXJyQWNjLmlzT247XG4gICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgY3VyckFjYy5OYW1lICE9PSAndW5kZWZpbmVkJykgY2FjaGVkQWNjLmRpc3BsYXlOYW1lID0gY3VyckFjYy5OYW1lO1xuICAgICAgICAgICAgICAgICAgICBjYWNoZWRBY2MuY29udGV4dCA9IGNvbnRleHQ7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuYXBpLnVwZGF0ZVBsYXRmb3JtQWNjZXNzb3JpZXMoW2NhY2hlZEFjY10pO1xuICAgICAgICAgICAgICAgICAgICBMaWdodEZhY3RvcnkuY3JlYXRlTGlnaHQodGhpcywgY2FjaGVkQWNjKTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jdXJyR3JvdXBzQW5kVGhlbWVzLnNwbGljZShqLCAxKTtcbiAgICAgICAgICAgICAgICAgICAgcmVtb3ZlID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIHJlbW92ZSB0aGUgY2FjaGVkQWNjIHRoYXQgY2FuJ3QgYmUgbWF0Y2hlZFxuICAgICAgICAgICAgaWYgKHJlbW92ZSkge1xuICAgICAgICAgICAgICAgIHRoaXMubG9nLmluZm8oYFJlbW92aW5nIGNhY2hlZCBhY2Nlc3NvcnkgJHtjYWNoZWRBY2MuZGlzcGxheU5hbWV9IHdpdGggVVVJRCAke2NhY2hlZEFjYy5VVUlEfS5gKTtcbiAgICAgICAgICAgICAgICB0aGlzLmFwaS51bnJlZ2lzdGVyUGxhdGZvcm1BY2Nlc3NvcmllcyhcImhvbWVicmlkZ2UtbHV4b3JcIiwgXCJMdXhvclwiLCBbY2FjaGVkQWNjXSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgLy8gYWRkIGFueSBuZXcgYWNjZXNzb3JpZXMgdGhhdCB3ZXJlIG5vdCBwcmV2aW91c2x5IG1hdGNoZWRcbiAgICAgICAgaWYgKHRoaXMuY3Vyckdyb3Vwc0FuZFRoZW1lcy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICBmb3IgKGxldCBqID0gMDsgaiA8IHRoaXMuY3Vyckdyb3Vwc0FuZFRoZW1lcy5sZW5ndGg7IGorKykge1xuICAgICAgICAgICAgICAgIGxldCBjdXJyQWNjID0gdGhpcy5jdXJyR3JvdXBzQW5kVGhlbWVzW2pdO1xuICAgICAgICAgICAgICAgIHRoaXMubG9nLmluZm8oYEFkZGluZyBuZXcgYWNjZXNzb3J5ICR7Y3VyckFjYy5OYW1lfSB3aXRoIFVVSUQgJHtjdXJyQWNjLlVVSUR9LmApO1xuICAgICAgICAgICAgICAgIGlmIChjdXJyQWNjLnR5cGUgPT09IElMaWdodFR5cGUuVEhFTUUpXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuYWRkVGhlbWVBY2Nlc3NvcnkoY3VyckFjYyk7XG4gICAgICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgICAgICB0aGlzLmFkZEdyb3VwQWNjZXNzb3J5KGN1cnJBY2MpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgYXN5bmMgZGlkRmluaXNoTGF1bmNoaW5nQXN5bmMoKSB7XG4gICAgICAgIGlmICghdGhpcy5jb25maWcuaXBBZGRyKSB7XG4gICAgICAgICAgICB0aGlzLmxvZy5lcnJvcih0aGlzLk5hbWUgKyBcIiBuZWVkcyBhbiBJUCBBZGRyZXNzIGluIHRoZSBjb25maWcgZmlsZS4gIFBsZWFzZSBzZWUgc2FtcGxlX2NvbmZpZy5qc29uLlwiKTtcbiAgICAgICAgfVxuICAgICAgICB0cnkge1xuICAgICAgICAgICAgd2hpbGUgKGF3YWl0IHRoaXMuZ2V0Q29udHJvbGxlckFzeW5jKCkgPT0gZmFsc2UpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmxvZy5pbmZvKGBVbmFibGUgdG8gY29ubmVjdCB0byBMdXhvciBjb250cm9sbGVyLiAgV2FpdGluZyA2MHMgYW5kIHdpbGwgcmV0cnkuYClcbiAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnNsZWVwKDYwKjEwMDApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy90aGlzLnJldHJpZXZlQ2FjaGVkQWNjZXNzb3JpZXMoKTtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuZ2V0Q29udHJvbGxlckdyb3VwTGlzdEFzeW5jKCk7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLmdldENvbnRyb2xsZXJUaGVtZUxpc3RBc3luYygpO1xuICAgICAgICAgICAgYXdhaXQgdGhpcy5wcm9jZXNzQWNjZXNzb3JpZXMoKTtcbiAgICAgICAgICAgIC8vIHRoaXMucmVtb3ZlT3BoYW5lZEFjY2Vzc29yaWVzKCk7XG4gICAgICAgICAgICB0aGlzLmxvZy5pbmZvKCdGaW5pc2hlZCBpbml0aWFsaXppbmcnKTtcbiAgICAgICAgfVxuICAgICAgICBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICB0aGlzLmxvZy5lcnJvcignRXJyb3IgaW4gZGlkRmluaXNoTGF1bmNoaW5nJywgZXJyKTtcbiAgICAgICAgfTtcbiAgICB9XG59XG5leHBvcnQgaW50ZXJmYWNlIElDb250ZXh0IHtcbiAgICBsYXN0RGF0ZUFkZGVkOiBudW1iZXI7XG4gICAgZ3JvdXBOdW1iZXI/OiBudW1iZXI7XG4gICAgYnJpZ2h0bmVzcz86IG51bWJlcjtcbiAgICB0eXBlOiBJTGlnaHRUeXBlXG4gICAgY29sb3I/OiBudW1iZXI7XG4gICAgc3RhdHVzPzogYW55O1xuICAgIGlzT246IGJvb2xlYW47XG4gICAgaHVlPzogbnVtYmVyO1xuICAgIHNhdHVyYXRpb24/OiBudW1iZXI7XG4gICAgdGhlbWVJbmRleD86IG51bWJlcjtcbiAgICBPbk9mZj86IDAgfCAxO1xuICAgIGluZGVwZW5kZW50Q29sb3JzPzogYm9vbGVhbjtcbiAgICBjb21tYW5kVGltZW91dDogbnVtYmVyO1xufSJdfQ==