foxconn-yumeeting-sdk-js
Version:
A js sdk for ion yumeeting
1 lines • 88.8 kB
JavaScript
var IonSDK=function(g){var I={};function C(A){if(I[A])return I[A].exports;var c=I[A]={i:A,l:!1,exports:{}};return g[A].call(c.exports,c,c.exports,C),c.l=!0,c.exports}return C.m=g,C.c=I,C.d=function(g,I,A){C.o(g,I)||Object.defineProperty(g,I,{enumerable:!0,get:A})},C.r=function(g){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(g,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(g,"__esModule",{value:!0})},C.t=function(g,I){if(1&I&&(g=C(g)),8&I)return g;if(4&I&&"object"==typeof g&&g&&g.__esModule)return g;var A=Object.create(null);if(C.r(A),Object.defineProperty(A,"default",{enumerable:!0,value:g}),2&I&&"string"!=typeof g)for(var c in g)C.d(A,c,function(I){return g[I]}.bind(null,c));return A},C.n=function(g){var I=g&&g.__esModule?function(){return g.default}:function(){return g};return C.d(I,"a",I),I},C.o=function(g,I){return Object.prototype.hasOwnProperty.call(g,I)},C.p="",C(C.s=1)}([function(module,exports,__webpack_require__){"use strict";eval("\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nexports.makeRemote = exports.LocalStream = exports.VideoConstraints = void 0;\r\nconst resolutions = ['qvga', 'vga', 'shd', 'hd', 'fhd', 'qhd'];\r\nexports.VideoConstraints = {\r\n qvga: {\r\n resolution: {\r\n width: { ideal: 320 },\r\n height: { ideal: 180 },\r\n frameRate: {\r\n ideal: 15,\r\n max: 30,\r\n },\r\n },\r\n encodings: {\r\n maxBitrate: 300000,\r\n maxFramerate: 16.0,\r\n },\r\n screenEncodings: {\r\n maxBitrate: 300000,\r\n maxFramerate: 6.0,\r\n },\r\n screenMotionEncodings: {\r\n maxBitrate: 300000,\r\n maxFramerate: 24.0,\r\n }\r\n },\r\n vga: {\r\n resolution: {\r\n width: { ideal: 640 },\r\n height: { ideal: 360 },\r\n frameRate: {\r\n ideal: 30,\r\n max: 60,\r\n },\r\n },\r\n encodings: {\r\n maxBitrate: 500000,\r\n maxFramerate: 16.0,\r\n },\r\n screenEncodings: {\r\n maxBitrate: 500000,\r\n maxFramerate: 6.0,\r\n },\r\n screenMotionEncodings: {\r\n maxBitrate: 800000,\r\n maxFramerate: 24.0,\r\n }\r\n },\r\n shd: {\r\n resolution: {\r\n width: { ideal: 960 },\r\n height: { ideal: 540 },\r\n frameRate: {\r\n ideal: 30,\r\n max: 60,\r\n },\r\n },\r\n encodings: {\r\n maxBitrate: 800000,\r\n maxFramerate: 16.0,\r\n },\r\n screenEncodings: {\r\n maxBitrate: 800000,\r\n maxFramerate: 6.0,\r\n },\r\n screenMotionEncodings: {\r\n maxBitrate: 1500000,\r\n maxFramerate: 24.0,\r\n }\r\n },\r\n hd: {\r\n resolution: {\r\n width: { ideal: 1280 },\r\n height: { ideal: 720 },\r\n frameRate: {\r\n ideal: 30,\r\n max: 60,\r\n },\r\n },\r\n encodings: {\r\n maxBitrate: 1800000,\r\n maxFramerate: 16.0,\r\n },\r\n screenEncodings: {\r\n maxBitrate: 1800000,\r\n maxFramerate: 6.0,\r\n },\r\n screenMotionEncodings: {\r\n maxBitrate: 2000000,\r\n maxFramerate: 24.0,\r\n }\r\n },\r\n fhd: {\r\n resolution: {\r\n width: { ideal: 1920 },\r\n height: { ideal: 1080 },\r\n frameRate: {\r\n ideal: 30,\r\n max: 60,\r\n },\r\n },\r\n encodings: {\r\n maxBitrate: 2500000,\r\n maxFramerate: 24.0,\r\n },\r\n screenEncodings: {\r\n maxBitrate: 2500000,\r\n maxFramerate: 6.0,\r\n },\r\n screenMotionEncodings: {\r\n maxBitrate: 4000000,\r\n maxFramerate: 24.0,\r\n }\r\n },\r\n qhd: {\r\n resolution: {\r\n width: { ideal: 2560 },\r\n height: { ideal: 1440 },\r\n frameRate: {\r\n ideal: 30,\r\n max: 60,\r\n },\r\n },\r\n encodings: {\r\n maxBitrate: 1000000,\r\n maxFramerate: 24.0,\r\n },\r\n screenEncodings: {\r\n maxBitrate: 1000000,\r\n maxFramerate: 6.0,\r\n },\r\n screenMotionEncodings: {\r\n maxBitrate: 8000000,\r\n maxFramerate: 24.0,\r\n }\r\n },\r\n};\r\nconst defaults = {\r\n resolution: 'hd',\r\n codec: 'vp8',\r\n audio: true,\r\n video: true,\r\n simulcast: false,\r\n};\r\nclass LocalStream extends MediaStream {\r\n constructor(stream, constraints) {\r\n super(stream);\r\n this.constraints = constraints;\r\n }\r\n static async getUserMedia(constraints = defaults) {\r\n const stream = await navigator.mediaDevices.getUserMedia({\r\n audio: LocalStream.computeAudioConstraints({\r\n ...defaults,\r\n ...constraints,\r\n }),\r\n video: LocalStream.computeVideoConstraints({\r\n ...defaults,\r\n ...constraints,\r\n }),\r\n });\r\n return new LocalStream(stream, {\r\n ...defaults,\r\n ...constraints,\r\n });\r\n }\r\n static async getDisplayMedia(stream, constraints = {\r\n codec: 'vp8',\r\n resolution: 'fhd',\r\n audio: false,\r\n video: true,\r\n simulcast: false,\r\n }) {\r\n // @ts-ignore\r\n // const stream = await navigator.mediaDevices.getDisplayMedia(constraints);\r\n return new LocalStream(stream, {\r\n ...defaults,\r\n ...constraints,\r\n });\r\n }\r\n static async getDisplayMediaForWeb(constraints = {\r\n codec: 'vp8',\r\n resolution: 'fhd',\r\n audio: false,\r\n video: true,\r\n simulcast: false,\r\n }) {\r\n // @ts-ignore\r\n const stream = await navigator.mediaDevices.getDisplayMedia(constraints);\r\n return new LocalStream(stream, {\r\n ...defaults,\r\n ...constraints,\r\n });\r\n }\r\n static computeAudioConstraints(constraints) {\r\n // audio: {\r\n // channelCount: constraints.channelCount || 2,\r\n // // echoCancellation: constraints.echoCancellation || true,\r\n // // latency: constraints.latency || 200,\r\n // },\r\n return constraints.channelCount ? Object.assign(constraints.audio, {\r\n channelCount: constraints.channelCount,\r\n }) : constraints.audio;\r\n }\r\n static computeVideoConstraints(constraints) {\r\n if (constraints.video instanceof Object) {\r\n return Object.assign(constraints.video, {\r\n ...exports.VideoConstraints[constraints.resolution].resolution,\r\n });\r\n }\r\n else if (constraints.video && constraints.resolution) {\r\n return {\r\n ...exports.VideoConstraints[constraints.resolution].resolution,\r\n };\r\n }\r\n return constraints.video;\r\n }\r\n getTrack(kind) {\r\n let tracks;\r\n if (kind === 'video') {\r\n tracks = this.getVideoTracks();\r\n return tracks.length > 0 ? this.getVideoTracks()[0] : undefined;\r\n }\r\n tracks = this.getAudioTracks();\r\n return tracks.length > 0 ? this.getAudioTracks()[0] : undefined;\r\n }\r\n async getNewTrack(kind) {\r\n const stream = await navigator.mediaDevices.getUserMedia({\r\n [kind]: kind === 'video'\r\n ? LocalStream.computeVideoConstraints(this.constraints)\r\n : LocalStream.computeAudioConstraints(this.constraints),\r\n });\r\n return stream.getTracks()[0];\r\n }\r\n publishTrack(track) {\r\n if (this.pc) {\r\n if (track.kind === 'video' && this.constraints.simulcast) {\r\n const idx = resolutions.indexOf(this.constraints.resolution);\r\n let encodings = [\r\n {\r\n rid: 'f',\r\n maxBitrate: exports.VideoConstraints[resolutions[idx]].encodings.maxBitrate,\r\n maxFramerate: exports.VideoConstraints[resolutions[idx]].encodings.maxFramerate,\r\n },\r\n ];\r\n if (idx - 1 >= 0) {\r\n encodings.push({\r\n rid: 'h',\r\n scaleResolutionDownBy: 2.0,\r\n maxBitrate: exports.VideoConstraints[resolutions[idx - 1]].encodings.maxBitrate,\r\n maxFramerate: exports.VideoConstraints[resolutions[idx - 1]].encodings.maxFramerate,\r\n });\r\n }\r\n if (idx - 2 >= 0) {\r\n encodings.push({\r\n rid: 'q',\r\n scaleResolutionDownBy: 4.0,\r\n maxBitrate: exports.VideoConstraints[resolutions[idx - 2]].encodings.maxBitrate,\r\n maxFramerate: exports.VideoConstraints[resolutions[idx - 2]].encodings.maxFramerate,\r\n });\r\n }\r\n if ('contentHint' in track) {\r\n let hint = 'motion';\r\n if (track.label === 'Screen' || track.label.toLowerCase().includes('screen') || track.label.toLowerCase().includes('window') || track.label.toLowerCase().includes('web-contents')) {\r\n let tmpEncodings = exports.VideoConstraints[resolutions[idx]].screenEncodings;\r\n if (this.motion) {\r\n hint = 'motion';\r\n tmpEncodings = exports.VideoConstraints[resolutions[idx]].screenMotionEncodings;\r\n }\r\n else {\r\n hint = 'detail';\r\n }\r\n encodings = [\r\n {\r\n rid: 'f',\r\n maxBitrate: tmpEncodings.maxBitrate,\r\n maxFramerate: tmpEncodings.maxFramerate,\r\n },\r\n ];\r\n if (idx - 1 >= 0) {\r\n encodings.push({\r\n rid: 'h',\r\n scaleResolutionDownBy: 2.0,\r\n maxBitrate: tmpEncodings.maxBitrate,\r\n maxFramerate: tmpEncodings.maxFramerate,\r\n });\r\n }\r\n if (idx - 2 >= 0) {\r\n encodings.push({\r\n rid: 'q',\r\n scaleResolutionDownBy: 4.0,\r\n maxBitrate: tmpEncodings.maxBitrate,\r\n maxFramerate: tmpEncodings.maxFramerate,\r\n });\r\n }\r\n }\r\n track.contentHint = hint;\r\n if (track.contentHint !== hint) {\r\n // console.log('Invalid video track contentHint: \\'' + hint + '\\'');\r\n }\r\n }\r\n else {\r\n // console.log('MediaStreamTrack contentHint attribute not supported');\r\n }\r\n const transceiver = this.pc.addTransceiver(track, {\r\n streams: [this],\r\n direction: 'sendonly',\r\n sendEncodings: encodings,\r\n });\r\n this.setPreferredCodec(transceiver, track.kind);\r\n }\r\n else {\r\n const init = {\r\n streams: [this],\r\n direction: 'sendonly',\r\n };\r\n // video\r\n if (track.kind === 'video') {\r\n init.sendEncodings = [exports.VideoConstraints[this.constraints.resolution].encodings];\r\n if ('contentHint' in track) {\r\n let hint = 'motion';\r\n if (track.label === 'Screen' || track.label.toLowerCase().includes('screen') || track.label.toLowerCase().includes('window') || track.label.toLowerCase().includes('web-contents')) {\r\n if (this.motion) {\r\n hint = 'motion';\r\n init.sendEncodings = [exports.VideoConstraints[this.constraints.resolution].screenMotionEncodings];\r\n }\r\n else {\r\n hint = 'detail';\r\n init.sendEncodings = [exports.VideoConstraints[this.constraints.resolution].screenEncodings];\r\n }\r\n }\r\n track.contentHint = hint;\r\n if (track.contentHint !== hint) {\r\n // console.log('Invalid video track contentHint: \\'' + hint + '\\'');\r\n }\r\n }\r\n else {\r\n // console.log('MediaStreamTrack contentHint attribute not supported');\r\n }\r\n }\r\n // audio\r\n if (track.kind === 'audio') {\r\n if ('contentHint' in track) {\r\n const hint = this.constraints.contentHintAudio || '';\r\n track.contentHint = hint;\r\n if (track.contentHint !== hint) {\r\n // console.log('Invalid video track contentHint: \\'' + hint + '\\'');\r\n }\r\n }\r\n else {\r\n // console.log('MediaStreamTrack contentHint attribute not supported');\r\n }\r\n // init.sendEncodings = [VideoConstraints[this.constraints.resolution].encodings];\r\n }\r\n const transceiver = this.pc.addTransceiver(track, init);\r\n this.setPreferredCodec(transceiver, track.kind);\r\n }\r\n }\r\n }\r\n setPreferredCodec(transceiver, kind) {\r\n if ('setCodecPreferences' in transceiver) {\r\n const cap = RTCRtpSender.getCapabilities(kind);\r\n if (!cap)\r\n return;\r\n let selCodec;\r\n if (this.constraints.preferredCodecProfile && kind === 'video') {\r\n const allCodecProfiles = cap.codecs.filter((c) => c.mimeType.toLowerCase() === `video/${this.constraints.codec.toLowerCase()}`);\r\n if (!allCodecProfiles) {\r\n return;\r\n }\r\n selCodec = allCodecProfiles.find((c) => { var _a; return c.sdpFmtpLine && ((_a = c.sdpFmtpLine) === null || _a === void 0 ? void 0 : _a.indexOf(`profile-level-id=${this.constraints.preferredCodecProfile}`)) >= 0; });\r\n if (!selCodec) {\r\n // get first one\r\n selCodec = allCodecProfiles[0];\r\n }\r\n }\r\n else {\r\n selCodec = cap.codecs.find((c) => c.mimeType.toLowerCase() === `video/${this.constraints.codec.toLowerCase()}` ||\r\n c.mimeType.toLowerCase() === `audio/opus`);\r\n }\r\n if (selCodec) {\r\n transceiver.setCodecPreferences([selCodec]);\r\n }\r\n }\r\n }\r\n updateTrack(next, prev) {\r\n this.addTrack(next);\r\n // If published, replace published track with track from new device\r\n if (prev) {\r\n this.removeTrack(prev);\r\n prev.stop();\r\n if (this.pc) {\r\n this.pc.getSenders().forEach(async (sender) => {\r\n var _a, _b, _c;\r\n if (((_a = sender === null || sender === void 0 ? void 0 : sender.track) === null || _a === void 0 ? void 0 : _a.kind) === next.kind && prev.id === ((_b = sender === null || sender === void 0 ? void 0 : sender.track) === null || _b === void 0 ? void 0 : _b.id)) {\r\n (_c = sender.track) === null || _c === void 0 ? void 0 : _c.stop();\r\n sender.replaceTrack(next);\r\n }\r\n });\r\n }\r\n }\r\n else {\r\n this.addTrack(next);\r\n if (this.pc) {\r\n this.publishTrack(next);\r\n }\r\n }\r\n }\r\n initAudioEmptyTrack() {\r\n // @ts-ignore\r\n const AudioContext = window.AudioContext || window.webkitAudioContext;\r\n const ctx = new AudioContext();\r\n const oscillator = ctx.createOscillator();\r\n oscillator.frequency.setValueAtTime(20000, ctx.currentTime);\r\n const dst = oscillator.connect(ctx.createMediaStreamDestination());\r\n oscillator.start();\r\n return dst.stream.getAudioTracks()[0];\r\n }\r\n initVideoEmptyTrack(width, height) {\r\n var _a;\r\n const canvas = Object.assign(document.createElement('canvas'), { width, height });\r\n (_a = canvas.getContext('2d')) === null || _a === void 0 ? void 0 : _a.fillRect(0, 0, width, height);\r\n const stream = canvas.captureStream();\r\n return stream.getVideoTracks()[0];\r\n }\r\n publish(transport, motion) {\r\n this.pc = transport.pc;\r\n this.api = transport.api;\r\n this.motion = motion;\r\n this.getTracks().forEach(this.publishTrack.bind(this));\r\n }\r\n unpublish() {\r\n if (this.pc) {\r\n const tracks = this.getTracks();\r\n this.pc.getSenders().forEach((s) => {\r\n if (s.track && tracks.includes(s.track)) {\r\n this.pc.removeTrack(s);\r\n }\r\n });\r\n }\r\n }\r\n async switchDevice(kind, deviceId) {\r\n this.constraints = {\r\n ...this.constraints,\r\n [kind]: this.constraints[kind] instanceof Object\r\n ? {\r\n ...this.constraints[kind],\r\n deviceId,\r\n }\r\n : { deviceId },\r\n };\r\n const prev = this.getTrack(kind);\r\n const next = await this.getNewTrack(kind);\r\n this.updateTrack(next, prev);\r\n }\r\n mute(kind) {\r\n const track = this.getTrack(kind);\r\n if (track && this.constraints.sendEmptyOnMute) {\r\n const emptyTrack = kind === 'audio'\r\n ? this.initAudioEmptyTrack()\r\n : this.initVideoEmptyTrack((track === null || track === void 0 ? void 0 : track.getSettings().width) || 640, (track === null || track === void 0 ? void 0 : track.getSettings().height) || 360);\r\n emptyTrack.enabled = false;\r\n this.updateTrack(emptyTrack, track);\r\n return;\r\n }\r\n if (track) {\r\n track.stop();\r\n }\r\n }\r\n async unmute(kind) {\r\n const prev = this.getTrack(kind);\r\n const track = await this.getNewTrack(kind);\r\n this.updateTrack(track, prev);\r\n }\r\n async enableLayers(layers) {\r\n const call = {\r\n streamId: this.id,\r\n layers,\r\n };\r\n const callStr = JSON.stringify(call);\r\n if (this.api) {\r\n if (this.api.readyState !== 'open') {\r\n // queue call if we aren't open yet\r\n this.api.onopen = () => { var _a; return (_a = this.api) === null || _a === void 0 ? void 0 : _a.send(JSON.stringify(call)); };\r\n }\r\n else {\r\n this.api.send(JSON.stringify(call));\r\n }\r\n }\r\n const layerValues = ['high', 'medium', 'low'];\r\n await Promise.all(layerValues.map(async (layer) => {\r\n await this.updateMediaEncodingParams({ active: layers.includes(layer) }, layer);\r\n }));\r\n }\r\n async updateMediaEncodingParams(encodingParams, layer) {\r\n var _a;\r\n if (!this.pc)\r\n return;\r\n const tracks = this.getTracks();\r\n await Promise.all((_a = this.pc) === null || _a === void 0 ? void 0 : _a.getSenders().filter((sender) => sender.track && tracks.includes(sender.track)).map(async (sender) => {\r\n const params = sender.getParameters();\r\n if (!params.encodings) {\r\n params.encodings = [{}];\r\n }\r\n let idx = 0;\r\n if (this.constraints.simulcast && layer) {\r\n const rid = layer === 'high' ? 'f' : layer === 'medium' ? 'h' : 'q';\r\n idx = params.encodings.findIndex((encoding) => encoding.rid === rid);\r\n if (params.encodings.length < idx + 1)\r\n return;\r\n }\r\n params.encodings[idx] = {\r\n ...params.encodings[idx],\r\n ...encodingParams,\r\n };\r\n await sender.setParameters(params);\r\n }));\r\n }\r\n}\r\nexports.LocalStream = LocalStream;\r\nfunction makeRemote(stream, transport) {\r\n const remote = stream;\r\n remote.audio = true;\r\n remote.video = 'none';\r\n remote.framerate = 'high';\r\n remote._videoPreMute = 'high';\r\n const select = () => {\r\n const call = {\r\n streamId: remote.id,\r\n video: remote.video,\r\n audio: remote.audio,\r\n framerate: remote.framerate,\r\n };\r\n if (transport.api) {\r\n if (transport.api.readyState !== 'open') {\r\n // queue call if we aren't open yet\r\n transport.api.onopen = () => { var _a; return (_a = transport.api) === null || _a === void 0 ? void 0 : _a.send(JSON.stringify(call)); };\r\n }\r\n else {\r\n transport.api.send(JSON.stringify(call));\r\n }\r\n }\r\n };\r\n remote.preferLayer = (layer) => {\r\n remote.video = layer;\r\n select();\r\n };\r\n remote.preferFramerate = (layer) => {\r\n remote.framerate = layer;\r\n select();\r\n };\r\n remote.mute = (kind) => {\r\n if (kind === 'audio') {\r\n remote.audio = false;\r\n }\r\n else if (kind === 'video') {\r\n remote._videoPreMute = remote.video;\r\n remote.video = 'none';\r\n }\r\n select();\r\n };\r\n remote.unmute = (kind) => {\r\n if (kind === 'audio') {\r\n remote.audio = true;\r\n }\r\n else if (kind === 'video') {\r\n remote.video = remote._videoPreMute;\r\n }\r\n select();\r\n };\r\n return remote;\r\n}\r\nexports.makeRemote = makeRemote;\r\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9Jb25TREsvLi9zcmMvc3RyZWFtLnRzP2U2ZGYiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQWE7QUFDYiw4Q0FBOEMsY0FBYztBQUM1RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esb0JBQW9CLGFBQWE7QUFDakMscUJBQXFCLGFBQWE7QUFDbEM7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQSxvQkFBb0IsYUFBYTtBQUNqQyxxQkFBcUIsYUFBYTtBQUNsQztBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2IsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBLG9CQUFvQixhQUFhO0FBQ2pDLHFCQUFxQixhQUFhO0FBQ2xDO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYixTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0Esb0JBQW9CLGNBQWM7QUFDbEMscUJBQXFCLGFBQWE7QUFDbEM7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQSxvQkFBb0IsY0FBYztBQUNsQyxxQkFBcUIsY0FBYztBQUNuQztBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2IsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBLG9CQUFvQixjQUFjO0FBQ2xDLHFCQUFxQixjQUFjO0FBQ25DO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYixTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVk7QUFDWjtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHFCQUFxQjtBQUNyQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHFCQUFxQjtBQUNyQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHFCQUFxQjtBQUNyQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNkJBQTZCO0FBQzdCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNkJBQTZCO0FBQzdCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNkJBQTZCO0FBQzdCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxpQkFBaUI7QUFDakI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esd0dBQXdHLHFDQUFxQztBQUM3STtBQUNBO0FBQ0E7QUFDQSx5REFBeUQsUUFBUSxtSEFBbUgsdUNBQXVDLFNBQVMsRUFBRTtBQUN0TztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx3RkFBd0YscUNBQXFDO0FBQzdIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxpQkFBaUI7QUFDakI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esd0VBQXdFLGdCQUFnQjtBQUN4RjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsbUJBQW1CLFdBQVc7QUFDOUI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EseUNBQXlDLFFBQVEsMkZBQTJGO0FBQzVJO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esa0RBQWtELGlDQUFpQztBQUNuRixTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esc0NBQXNDO0FBQ3RDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsOENBQThDLFFBQVEsZ0dBQWdHO0FBQ3RKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiIwLmpzIiwic291cmNlc0NvbnRlbnQiOlsiXCJ1c2Ugc3RyaWN0XCI7XHJcbk9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBcIl9fZXNNb2R1bGVcIiwgeyB2YWx1ZTogdHJ1ZSB9KTtcclxuZXhwb3J0cy5tYWtlUmVtb3RlID0gZXhwb3J0cy5Mb2NhbFN0cmVhbSA9IGV4cG9ydHMuVmlkZW9Db25zdHJhaW50cyA9IHZvaWQgMDtcclxuY29uc3QgcmVzb2x1dGlvbnMgPSBbJ3F2Z2EnLCAndmdhJywgJ3NoZCcsICdoZCcsICdmaGQnLCAncWhkJ107XHJcbmV4cG9ydHMuVmlkZW9Db25zdHJhaW50cyA9IHtcclxuICAgIHF2Z2E6IHtcclxuICAgICAgICByZXNvbHV0aW9uOiB7XHJcbiAgICAgICAgICAgIHdpZHRoOiB7IGlkZWFsOiAzMjAgfSxcclxuICAgICAgICAgICAgaGVpZ2h0OiB7IGlkZWFsOiAxODAgfSxcclxuICAgICAgICAgICAgZnJhbWVSYXRlOiB7XHJcbiAgICAgICAgICAgICAgICBpZGVhbDogMTUsXHJcbiAgICAgICAgICAgICAgICBtYXg6IDMwLFxyXG4gICAgICAgICAgICB9LFxyXG4gICAgICAgIH0sXHJcbiAgICAgICAgZW5jb2RpbmdzOiB7XHJcbiAgICAgICAgICAgIG1heEJpdHJhdGU6IDMwMDAwMCxcclxuICAgICAgICAgICAgbWF4RnJhbWVyYXRlOiAxNi4wLFxyXG4gICAgICAgIH0sXHJcbiAgICAgICAgc2NyZWVuRW5jb2RpbmdzOiB7XHJcbiAgICAgICAgICAgIG1heEJpdHJhdGU6IDMwMDAwMCxcclxuICAgICAgICAgICAgbWF4RnJhbWVyYXRlOiA2LjAsXHJcbiAgICAgICAgfSxcclxuICAgICAgICBzY3JlZW5Nb3Rpb25FbmNvZGluZ3M6IHtcclxuICAgICAgICAgICAgbWF4Qml0cmF0ZTogMzAwMDAwLFxyXG4gICAgICAgICAgICBtYXhGcmFtZXJhdGU6IDI0LjAsXHJcbiAgICAgICAgfVxyXG4gICAgfSxcclxuICAgIHZnYToge1xyXG4gICAgICAgIHJlc29sdXRpb246IHtcclxuICAgICAgICAgICAgd2lkdGg6IHsgaWRlYWw6IDY0MCB9LFxyXG4gICAgICAgICAgICBoZWlnaHQ6IHsgaWRlYWw6IDM2MCB9LFxyXG4gICAgICAgICAgICBmcmFtZVJhdGU6IHtcclxuICAgICAgICAgICAgICAgIGlkZWFsOiAzMCxcclxuICAgICAgICAgICAgICAgIG1heDogNjAsXHJcbiAgICAgICAgICAgIH0sXHJcbiAgICAgICAgfSxcclxuICAgICAgICBlbmNvZGluZ3M6IHtcclxuICAgICAgICAgICAgbWF4Qml0cmF0ZTogNTAwMDAwLFxyXG4gICAgICAgICAgICBtYXhGcmFtZXJhdGU6IDE2LjAsXHJcbiAgICAgICAgfSxcclxuICAgICAgICBzY3JlZW5FbmNvZGluZ3M6IHtcclxuICAgICAgICAgICAgbWF4Qml0cmF0ZTogNTAwMDAwLFxyXG4gICAgICAgICAgICBtYXhGcmFtZXJhdGU6IDYuMCxcclxuICAgICAgICB9LFxyXG4gICAgICAgIHNjcmVlbk1vdGlvbkVuY29kaW5nczoge1xyXG4gICAgICAgICAgICBtYXhCaXRyYXRlOiA4MDAwMDAsXHJcbiAgICAgICAgICAgIG1heEZyYW1lcmF0ZTogMjQuMCxcclxuICAgICAgICB9XHJcbiAgICB9LFxyXG4gICAgc2hkOiB7XHJcbiAgICAgICAgcmVzb2x1dGlvbjoge1xyXG4gICAgICAgICAgICB3aWR0aDogeyBpZGVhbDogOTYwIH0sXHJcbiAgICAgICAgICAgIGhlaWdodDogeyBpZGVhbDogNTQwIH0sXHJcbiAgICAgICAgICAgIGZyYW1lUmF0ZToge1xyXG4gICAgICAgICAgICAgICAgaWRlYWw6IDMwLFxyXG4gICAgICAgICAgICAgICAgbWF4OiA2MCxcclxuICAgICAgICAgICAgfSxcclxuICAgICAgICB9LFxyXG4gICAgICAgIGVuY29kaW5nczoge1xyXG4gICAgICAgICAgICBtYXhCaXRyYXRlOiA4MDAwMDAsXHJcbiAgICAgICAgICAgIG1heEZyYW1lcmF0ZTogMTYuMCxcclxuICAgICAgICB9LFxyXG4gICAgICAgIHNjcmVlbkVuY29kaW5nczoge1xyXG4gICAgICAgICAgICBtYXhCaXRyYXRlOiA4MDAwMDAsXHJcbiAgICAgICAgICAgIG1heEZyYW1lcmF0ZTogNi4wLFxyXG4gICAgICAgIH0sXHJcbiAgICAgICAgc2NyZWVuTW90aW9uRW5jb2RpbmdzOiB7XHJcbiAgICAgICAgICAgIG1heEJpdHJhdGU6IDE1MDAwMDAsXHJcbiAgICAgICAgICAgIG1heEZyYW1lcmF0ZTogMjQuMCxcclxuICAgICAgICB9XHJcbiAgICB9LFxyXG4gICAgaGQ6IHtcclxuICAgICAgICByZXNvbHV0aW9uOiB7XHJcbiAgICAgICAgICAgIHdpZHRoOiB7IGlkZWFsOiAxMjgwIH0sXHJcbiAgICAgICAgICAgIGhlaWdodDogeyBpZGVhbDogNzIwIH0sXHJcbiAgICAgICAgICAgIGZyYW1lUmF0ZToge1xyXG4gICAgICAgICAgICAgICAgaWRlYWw6IDMwLFxyXG4gICAgICAgICAgICAgICAgbWF4OiA2MCxcclxuICAgICAgICAgICAgfSxcclxuICAgICAgICB9LFxyXG4gICAgICAgIGVuY29kaW5nczoge1xyXG4gICAgICAgICAgICBtYXhCaXRyYXRlOiAxODAwMDAwLFxyXG4gICAgICAgICAgICBtYXhGcmFtZXJhdGU6IDE2LjAsXHJcbiAgICAgICAgfSxcclxuICAgICAgICBzY3JlZW5FbmNvZGluZ3M6IHtcclxuICAgICAgICAgICAgbWF4Qml0cmF0ZTogMTgwMDAwMCxcclxuICAgICAgICAgICAgbWF4RnJhbWVyYXRlOiA2LjAsXHJcbiAgICAgICAgfSxcclxuICAgICAgICBzY3JlZW5Nb3Rpb25FbmNvZGluZ3M6IHtcclxuICAgICAgICAgICAgbWF4Qml0cmF0ZTogMjAwMDAwMCxcclxuICAgICAgICAgICAgbWF4RnJhbWVyYXRlOiAyNC4wLFxyXG4gICAgICAgIH1cclxuICAgIH0sXHJcbiAgICBmaGQ6IHtcclxuICAgICAgICByZXNvbHV0aW9uOiB7XHJcbiAgICAgICAgICAgIHdpZHRoOiB7IGlkZWFsOiAxOTIwIH0sXHJcbiAgICAgICAgICAgIGhlaWdodDogeyBpZGVhbDogMTA4MCB9LFxyXG4gICAgICAgICAgICBmcmFtZVJhdGU6IHtcclxuICAgICAgICAgICAgICAgIGlkZWFsOiAzMCxcclxuICAgICAgICAgICAgICAgIG1heDogNjAsXHJcbiAgICAgICAgICAgIH0sXHJcbiAgICAgICAgfSxcclxuICAgICAgICBlbmNvZGluZ3M6IHtcclxuICAgICAgICAgICAgbWF4Qml0cmF0ZTogMjUwMDAwMCxcclxuICAgICAgICAgICAgbWF4RnJhbWVyYXRlOiAyNC4wLFxyXG4gICAgICAgIH0sXHJcbiAgICAgICAgc2NyZWVuRW5jb2RpbmdzOiB7XHJcbiAgICAgICAgICAgIG1heEJpdHJhdGU6IDI1MDAwMDAsXHJcbiAgICAgICAgICAgIG1heEZyYW1lcmF0ZTogNi4wLFxyXG4gICAgICAgIH0sXHJcbiAgICAgICAgc2NyZWVuTW90aW9uRW5jb2RpbmdzOiB7XHJcbiAgICAgICAgICAgIG1heEJpdHJhdGU6IDQwMDAwMDAsXHJcbiAgICAgICAgICAgIG1heEZyYW1lcmF0ZTogMjQuMCxcclxuICAgICAgICB9XHJcbiAgICB9LFxyXG4gICAgcWhkOiB7XHJcbiAgICAgICAgcmVzb2x1dGlvbjoge1xyXG4gICAgICAgICAgICB3aWR0aDogeyBpZGVhbDogMjU2MCB9LFxyXG4gICAgICAgICAgICBoZWlnaHQ6IHsgaWRlYWw6IDE0NDAgfSxcclxuICAgICAgICAgICAgZnJhbWVSYXRlOiB7XHJcbiAgICAgICAgICAgICAgICBpZGVhbDogMzAsXHJcbiAgICAgICAgICAgICAgICBtYXg6IDYwLFxyXG4gICAgICAgICAgICB9LFxyXG4gICAgICAgIH0sXHJcbiAgICAgICAgZW5jb2RpbmdzOiB7XHJcbiAgICAgICAgICAgIG1heEJpdHJhdGU6IDEwMDAwMDAsXHJcbiAgICAgICAgICAgIG1heEZyYW1lcmF0ZTogMjQuMCxcclxuICAgICAgICB9LFxyXG4gICAgICAgIHNjcmVlbkVuY29kaW5nczoge1xyXG4gICAgICAgICAgICBtYXhCaXRyYXRlOiAxMDAwMDAwLFxyXG4gICAgICAgICAgICBtYXhGcmFtZXJhdGU6IDYuMCxcclxuICAgICAgICB9LFxyXG4gICAgICAgIHNjcmVlbk1vdGlvbkVuY29kaW5nczoge1xyXG4gICAgICAgICAgICBtYXhCaXRyYXRlOiA4MDAwMDAwLFxyXG4gICAgICAgICAgICBtYXhGcmFtZXJhdGU6IDI0LjAsXHJcbiAgICAgICAgfVxyXG4gICAgfSxcclxufTtcclxuY29uc3QgZGVmYXVsdHMgPSB7XHJcbiAgICByZXNvbHV0aW9uOiAnaGQnLFxyXG4gICAgY29kZWM6ICd2cDgnLFxyXG4gICAgYXVkaW86IHRydWUsXHJcbiAgICB2aWRlbzogdHJ1ZSxcclxuICAgIHNpbXVsY2FzdDogZmFsc2UsXHJcbn07XHJcbmNsYXNzIExvY2FsU3RyZWFtIGV4dGVuZHMgTWVkaWFTdHJlYW0ge1xyXG4gICAgY29uc3RydWN0b3Ioc3RyZWFtLCBjb25zdHJhaW50cykge1xyXG4gICAgICAgIHN1cGVyKHN0cmVhbSk7XHJcbiAgICAgICAgdGhpcy5jb25zdHJhaW50cyA9IGNvbnN0cmFpbnRzO1xyXG4gICAgfVxyXG4gICAgc3RhdGljIGFzeW5jIGdldFVzZXJNZWRpYShjb25zdHJhaW50cyA9IGRlZmF1bHRzKSB7XHJcbiAgICAgICAgY29uc3Qgc3RyZWFtID0gYXdhaXQgbmF2aWdhdG9yLm1lZGlhRGV2aWNlcy5nZXRVc2VyTWVkaWEoe1xyXG4gICAgICAgICAgICBhdWRpbzogTG9jYWxTdHJlYW0uY29tcHV0ZUF1ZGlvQ29uc3RyYWludHMoe1xyXG4gICAgICAgICAgICAgICAgLi4uZGVmYXVsdHMsXHJcbiAgICAgICAgICAgICAgICAuLi5jb25zdHJhaW50cyxcclxuICAgICAgICAgICAgfSksXHJcbiAgICAgICAgICAgIHZpZGVvOiBMb2NhbFN0cmVhbS5jb21wdXRlVmlkZW9Db25zdHJhaW50cyh7XHJcbiAgICAgICAgICAgICAgICAuLi5kZWZhdWx0cyxcclxuICAgICAgICAgICAgICAgIC4uLmNvbnN0cmFpbnRzLFxyXG4gICAgICAgICAgICB9KSxcclxuICAgICAgICB9KTtcclxuICAgICAgICByZXR1cm4gbmV3IExvY2FsU3RyZWFtKHN0cmVhbSwge1xyXG4gICAgICAgICAgICAuLi5kZWZhdWx0cyxcclxuICAgICAgICAgICAgLi4uY29uc3RyYWludHMsXHJcbiAgICAgICAgfSk7XHJcbiAgICB9XHJcbiAgICBzdGF0aWMgYXN5bmMgZ2V0RGlzcGxheU1lZGlhKHN0cmVhbSwgY29uc3RyYWludHMgPSB7XHJcbiAgICAgICAgY29kZWM6ICd2cDgnLFxyXG4gICAgICAgIHJlc29sdXRpb246ICdmaGQnLFxyXG4gICAgICAgIGF1ZGlvOiBmYWxzZSxcclxuICAgICAgICB2aWRlbzogdHJ1ZSxcclxuICAgICAgICBzaW11bGNhc3Q6IGZhbHNlLFxyXG4gICAgfSkge1xyXG4gICAgICAgIC8vIEB0cy1pZ25vcmVcclxuICAgICAgICAvLyBjb25zdCBzdHJlYW0gPSBhd2FpdCBuYXZpZ2F0b3IubWVkaWFEZXZpY2VzLmdldERpc3BsYXlNZWRpYShjb25zdHJhaW50cyk7XHJcbiAgICAgICAgcmV0dXJuIG5ldyBMb2NhbFN0cmVhbShzdHJlYW0sIHtcclxuICAgICAgICAgICAgLi4uZGVmYXVsdHMsXHJcbiAgICAgICAgICAgIC4uLmNvbnN0cmFpbnRzLFxyXG4gICAgICAgIH0pO1xyXG4gICAgfVxyXG4gICAgc3RhdGljIGFzeW5jIGdldERpc3BsYXlNZWRpYUZvcldlYihjb25zdHJhaW50cyA9IHtcclxuICAgICAgICBjb2RlYzogJ3ZwOCcsXHJcbiAgICAgICAgcmVzb2x1dGlvbjogJ2ZoZCcsXHJcbiAgICAgICAgYXVkaW86IGZhbHNlLFxyXG4gICAgICAgIHZpZGVvOiB0cnVlLFxyXG4gICAgICAgIHNpbXVsY2FzdDogZmFsc2UsXHJcbiAgICB9KSB7XHJcbiAgICAgICAgLy8gQHRzLWlnbm9yZVxyXG4gICAgICAgIGNvbnN0IHN0cmVhbSA9IGF3YWl0IG5hdmlnYXRvci5tZWRpYURldmljZXMuZ2V0RGlzcGxheU1lZGlhKGNvbnN0cmFpbnRzKTtcclxuICAgICAgICByZXR1cm4gbmV3IExvY2FsU3RyZWFtKHN0cmVhbSwge1xyXG4gICAgICAgICAgICAuLi5kZWZhdWx0cyxcclxuICAgICAgICAgICAgLi4uY29uc3RyYWludHMsXHJcbiAgICAgICAgfSk7XHJcbiAgICB9XHJcbiAgICBzdGF0aWMgY29tcHV0ZUF1ZGlvQ29uc3RyYWludHMoY29uc3RyYWludHMpIHtcclxuICAgICAgICAvLyBhdWRpbzoge1xyXG4gICAgICAgIC8vICAgY2hhbm5lbENvdW50OiBjb25zdHJhaW50cy5jaGFubmVsQ291bnQgfHwgMixcclxuICAgICAgICAvLyAgIC8vIGVjaG9DYW5jZWxsYXRpb246IGNvbnN0cmFpbnRzLmVjaG9DYW5jZWxsYXRpb24gfHwgdHJ1ZSxcclxuICAgICAgICAvLyAgIC8vIGxhdGVuY3k6IGNvbnN0cmFpbnRzLmxhdGVuY3kgfHwgMjAwLFxyXG4gICAgICAgIC8vIH0sXHJcbiAgICAgICAgcmV0dXJuIGNvbnN0cmFpbnRzLmNoYW5uZWxDb3VudCA/IE9iamVjdC5hc3NpZ24oY29uc3RyYWludHMuYXVkaW8sIHtcclxuICAgICAgICAgICAgY2hhbm5lbENvdW50OiBjb25zdHJhaW50cy5jaGFubmVsQ291bnQsXHJcbiAgICAgICAgfSkgOiBjb25zdHJhaW50cy5hdWRpbztcclxuICAgIH1cclxuICAgIHN0YXRpYyBjb21wdXRlVmlkZW9Db25zdHJhaW50cyhjb25zdHJhaW50cykge1xyXG4gICAgICAgIGlmIChjb25zdHJhaW50cy52aWRlbyBpbnN0YW5jZW9mIE9iamVjdCkge1xyXG4gICAgICAgICAgICByZXR1cm4gT2JqZWN0LmFzc2lnbihjb25zdHJhaW50cy52aWRlbywge1xyXG4gICAgICAgICAgICAgICAgLi4uZXhwb3J0cy5WaWRlb0NvbnN0cmFpbnRzW2NvbnN0cmFpbnRzLnJlc29sdXRpb25dLnJlc29sdXRpb24sXHJcbiAgICAgICAgICAgIH0pO1xyXG4gICAgICAgIH1cclxuICAgICAgICBlbHNlIGlmIChjb25zdHJhaW50cy52aWRlbyAmJiBjb25zdHJhaW50cy5yZXNvbHV0aW9uKSB7XHJcbiAgICAgICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICAgICAgICAuLi5leHBvcnRzLlZpZGVvQ29uc3RyYWludHNbY29uc3RyYWludHMucmVzb2x1dGlvbl0ucmVzb2x1dGlvbixcclxuICAgICAgICAgICAgfTtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIGNvbnN0cmFpbnRzLnZpZGVvO1xyXG4gICAgfVxyXG4gICAgZ2V0VHJhY2soa2luZCkge1xyXG4gICAgICAgIGxldCB0cmFja3M7XHJcbiAgICAgICAgaWYgKGtpbmQgPT09ICd2aWRlbycpIHtcclxuICAgICAgICAgICAgdHJhY2tzID0gdGhpcy5nZXRWaWRlb1RyYWNrcygpO1xyXG4gICAgICAgICAgICByZXR1cm4gdHJhY2tzLmxlbmd0aCA+IDAgPyB0aGlzLmdldFZpZGVvVHJhY2tzKClbMF0gOiB1bmRlZmluZWQ7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHRyYWNrcyA9IHRoaXMuZ2V0QXVkaW9UcmFja3MoKTtcclxuICAgICAgICByZXR1cm4gdHJhY2tzLmxlbmd0aCA+IDAgPyB0aGlzLmdldEF1ZGlvVHJhY2tzKClbMF0gOiB1bmRlZmluZWQ7XHJcbiAgICB9XHJcbiAgICBhc3luYyBnZXROZXdUcmFjayhraW5kKSB7XHJcbiAgICAgICAgY29uc3Qgc3RyZWFtID0gYXdhaXQgbmF2aWdhdG9yLm1lZGlhRGV2aWNlcy5nZXRVc2VyTWVkaWEoe1xyXG4gICAgICAgICAgICBba2luZF06IGtpbmQgPT09ICd2aWRlbydcclxuICAgICAgICAgICAgICAgID8gTG9jYWxTdHJlYW0uY29tcHV0ZVZpZGVvQ29uc3RyYWludHModGhpcy5jb25zdHJhaW50cylcclxuICAgICAgICAgICAgICAgIDogTG9jYWxTdHJlYW0uY29tcHV0ZUF1ZGlvQ29uc3RyYWludHModGhpcy5jb25zdHJhaW50cyksXHJcbiAgICAgICAgfSk7XHJcbiAgICAgICAgcmV0dXJuIHN0cmVhbS5nZXRUcmFja3MoKVswXTtcclxuICAgIH1cclxuICAgIHB1Ymxpc2hUcmFjayh0cmFjaykge1xyXG4gICAgICAgIGlmICh0aGlzLnBjKSB7XHJcbiAgICAgICAgICAgIGlmICh0cmFjay5raW5kID09PSAndmlkZW8nICYmIHRoaXMuY29uc3RyYWludHMuc2ltdWxjYXN0KSB7XHJcbiAgICAgICAgICAgICAgICBjb25zdCBpZHggPSByZXNvbHV0aW9ucy5pbmRleE9mKHRoaXMuY29uc3RyYWludHMucmVzb2x1dGlvbik7XHJcbiAgICAgICAgICAgICAgICBsZXQgZW5jb2RpbmdzID0gW1xyXG4gICAgICAgICAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgcmlkOiAnZicsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIG1heEJpdHJhdGU6IGV4cG9ydHMuVmlkZW9Db25zdHJhaW50c1tyZXNvbHV0aW9uc1tpZHhdXS5lbmNvZGluZ3MubWF4Qml0cmF0ZSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgbWF4RnJhbWVyYXRlOiBleHBvcnRzLlZpZGVvQ29uc3RyYWludHNbcmVzb2x1dGlvbnNbaWR4XV0uZW5jb2RpbmdzLm1heEZyYW1lcmF0ZSxcclxuICAgICAgICAgICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICAgICAgXTtcclxuICAgICAgICAgICAgICAgIGlmIChpZHggLSAxID49IDApIHtcclxuICAgICAgICAgICAgICAgICAgICBlbmNvZGluZ3MucHVzaCh7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHJpZDogJ2gnLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICBzY2FsZVJlc29sdXRpb25Eb3duQnk6IDIuMCxcclxuICAgICAgICAgICAgICAgICAgICAgICAgbWF4Qml0cmF0ZTogZXhwb3J0cy5WaWRlb0NvbnN0cmFpbnRzW3Jlc29sdXRpb25zW2lkeCAtIDFdXS5lbmNvZGluZ3MubWF4Qml0cmF0ZSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgbWF4RnJhbWVyYXRlOiBleHBvcnRzLlZpZGVvQ29uc3RyYWludHNbcmVzb2x1dGlvbnNbaWR4IC0gMV1dLmVuY29kaW5ncy5tYXhGcmFtZXJhdGUsXHJcbiAgICAgICAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICBpZiAoaWR4IC0gMiA+PSAwKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgZW5jb2RpbmdzLnB1c2goe1xyXG4gICAgICAgICAgICAgICAgICAgICAgICByaWQ6ICdxJyxcclxuICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVSZXNvbHV0aW9uRG93bkJ5OiA0LjAsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIG1heEJpdHJhdGU6IGV4cG9ydHMuVmlkZW9Db25zdHJhaW50c1tyZXNvbHV0aW9uc1tpZHggLSAyXV0uZW5jb2RpbmdzLm1heEJpdHJhdGUsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIG1heEZyYW1lcmF0ZTogZXhwb3J0cy5WaWRlb0NvbnN0cmFpbnRzW3Jlc29sdXRpb25zW2lkeCAtIDJdXS5lbmNvZGluZ3MubWF4RnJhbWVyYXRlLFxyXG4gICAgICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgaWYgKCdjb250ZW50SGludCcgaW4gdHJhY2spIHtcclxuICAgICAgICAgICAgICAgICAgICBsZXQgaGludCA9ICdtb3Rpb24nO1xyXG4gICAgICAgICAgICAgICAgICAgIGlmICh0cmFjay5sYWJlbCA9PT0gJ1NjcmVlbicgfHwgdHJhY2subGFiZWwudG9Mb3dlckNhc2UoKS5pbmNsdWRlcygnc2NyZWVuJykgfHwgdHJhY2subGFiZWwudG9Mb3dlckNhc2UoKS5pbmNsdWRlcygnd2luZG93JykgfHwgdHJhY2subGFiZWwudG9Mb3dlckNhc2UoKS5pbmNsdWRlcygnd2ViLWNvbnRlbnRzJykpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgbGV0IHRtcEVuY29kaW5ncyA9IGV4cG9ydHMuVmlkZW9Db25zdHJhaW50c1tyZXNvbHV0aW9uc1tpZHhdXS5zY3JlZW5FbmNvZGluZ3M7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLm1vdGlvbikge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaGludCA9ICdtb3Rpb24nO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdG1wRW5jb2RpbmdzID0gZXhwb3J0cy5WaWRlb0NvbnN0cmFpbnRzW3Jlc29sdXRpb25zW2lkeF1dLnNjcmVlbk1vdGlvbkVuY29kaW5ncztcclxuICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICBlbHNlIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhpbnQgPSAnZGV0YWlsJztcclxuICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICBlbmNvZGluZ3MgPSBbXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmlkOiAnZicsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4Qml0cmF0ZTogdG1wRW5jb2RpbmdzLm1heEJpdHJhdGUsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4RnJhbWVyYXRlOiB0bXBFbmNvZGluZ3MubWF4RnJhbWVyYXRlLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgXTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGlkeCAtIDEgPj0gMCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZW5jb2RpbmdzLnB1c2goe1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJpZDogJ2gnLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlUmVzb2x1dGlvbkRvd25CeTogMi4wLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1heEJpdHJhdGU6IHRtcEVuY29kaW5ncy5tYXhCaXRyYXRlLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1heEZyYW1lcmF0ZTogdG1wRW5jb2RpbmdzLm1heEZyYW1lcmF0ZSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChpZHggLSAyID49IDApIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVuY29kaW5ncy5wdXNoKHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByaWQ6ICdxJyxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZVJlc29sdXRpb25Eb3duQnk6IDQuMCxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXhCaXRyYXRlOiB0bXBFbmNvZGluZ3MubWF4Qml0cmF0ZSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXhGcmFtZXJhdGU6IHRtcEVuY29kaW5ncy5tYXhGcmFtZXJhdGUsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICB0cmFjay5jb250ZW50SGludCA9IGhpbnQ7XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKHRyYWNrLmNvbnRlbnRIaW50ICE9PSBoaW50KSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGNvbnNvbGUubG9nKCdJbnZhbGlkIHZpZGVvIHRyYWNrIGNvbnRlbnRIaW50OiBcXCcnICsgaGludCArICdcXCcnKTtcclxuICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICBlbHNlIHtcclxuICAgICAgICAgICAgICAgICAgICAvLyBjb25zb2xlLmxvZygnTWVkaWFTdHJlYW1UcmFjayBjb250ZW50SGludCBhdHRyaWJ1dGUgbm90IHN1cHBvcnRlZCcpO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgY29uc3QgdHJhbnNjZWl2ZXIgPSB0aGlzLnBjLmFkZFRyYW5zY2VpdmVyKHRyYWNrLCB7XHJcbiAgICAgICAgICAgICAgICAgICAgc3RyZWFtczogW3RoaXNdLFxyXG4gICAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbjogJ3NlbmRvbmx5JyxcclxuICAgICAgICAgICAgICAgICAgICBzZW5kRW5jb2RpbmdzOiBlbmNvZGluZ3MsXHJcbiAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICAgIHRoaXMuc2V0UHJlZmVycmVkQ29kZWModHJhbnNjZWl2ZXIsIHRyYWNrLmtpbmQpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgY29uc3QgaW5pdCA9IHtcclxuICAgICAgICAgICAgICAgICAgICBzdHJlYW1zOiBbdGhpc10sXHJcbiAgICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uOiAnc2VuZG9ubHknLFxyXG4gICAgICAgICAgICAgICAgfTtcclxuICAgICAgICAgICAgICAgIC8vIHZpZGVvXHJcbiAgICAgICAgICAgICAgICBpZiAodHJhY2sua2luZCA9PT0gJ3ZpZGVvJykge1xyXG4gICAgICAgICAgICAgICAgICAgIGluaXQuc2VuZEVuY29kaW5ncyA9IFtleHBvcnRzLlZpZGVvQ29uc3RyYWludHNbdGhpcy5jb25zdHJhaW50cy5yZXNvbHV0aW9uXS5lbmNvZGluZ3NdO1xyXG4gICAgICAgICAgICAgICAgICAgIGlmICgnY29udGVudEhpbnQnIGluIHRyYWNrKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGxldCBoaW50ID0gJ21vdGlvbic7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0cmFjay5sYWJlbCA9PT0gJ1NjcmVlbicgfHwgdHJhY2subGFiZWwudG9Mb3dlckNhc2UoKS5pbmNsdWRlcygnc2NyZWVuJykgfHwgdHJhY2subGFiZWwudG9Mb3dlckNhc2UoKS5pbmNsdWRlcygnd2luZG93JykgfHwgdHJhY2subGFiZWwudG9Mb3dlckNhc2UoKS5pbmNsdWRlcygnd2ViLWNvbnRlbnRzJykpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLm1vdGlvbikge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhpbnQgPSAnbW90aW9uJztcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbml0LnNlbmRFbmNvZGluZ3MgPSBbZXhwb3J0cy5WaWRlb0NvbnN0cmFpbnRzW3RoaXMuY29uc3RyYWludHMucmVzb2x1dGlvbl0uc2NyZWVuTW90aW9uRW5jb2RpbmdzXTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhpbnQgPSAnZGV0YWlsJztcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbml0LnNlbmRFbmNvZGluZ3MgPSBbZXhwb3J0cy5WaWRlb0NvbnN0cmFpbnRzW3RoaXMuY29uc3RyYWludHMucmVzb2x1dGlvbl0uc2NyZWVuRW5jb2RpbmdzXTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICB0cmFjay5jb250ZW50SGludCA9IGhpbnQ7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0cmFjay5jb250ZW50SGludCAhPT0gaGludCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gY29uc29sZS5sb2coJ0ludmFsaWQgdmlkZW8gdHJhY2sgY29udGVudEhpbnQ6IFxcJycgKyBoaW50ICsgJ1xcJycpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgIGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBjb25zb2xlLmxvZygnTWVkaWFTdHJlYW1UcmFjayBjb250ZW50SGludCBhdHRyaWJ1dGUgbm90IHN1cHBvcnRlZCcpO1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIC8vIGF1ZGlvXHJcbiAgICAgICAgICAgICAgICBpZiAodHJhY2sua2luZCA9PT0gJ2F1ZGlvJykge1xyXG4gICAgICAgICAgICAgICAgICAgIGlmICgnY29udGVudEhpbnQnIGluIHRyYWNrKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGhpbnQgPSB0aGlzLmNvbnN0cmFpbnRzLmNvbnRlbnRIaW50QXVkaW8gfHwgJyc7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHRyYWNrLmNvbnRlbnRIaW50ID0gaGludDtcclxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHRyYWNrLmNvbnRlbnRIaW50ICE9PSBoaW50KSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBjb25zb2xlLmxvZygnSW52YWxpZCB2aWRlbyB0cmFjayBjb250ZW50SGludDogXFwnJyArIGhpbnQgKyAnXFwnJyk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGNvbnNvbGUubG9nKCdNZWRpYVN0cmVhbVRyYWNrIGNvbnRlbnRIaW50IGF0dHJpYnV0ZSBub3Qgc3VwcG9ydGVkJyk7XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgIC8vIGluaXQuc2VuZEVuY29kaW5ncyA9IFtWaWRlb0NvbnN0cmFpbnRzW3RoaXMuY29uc3RyYWludHMucmVzb2x1dGlvbl0uZW5jb2RpbmdzXTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIGNvbnN0IHRyYW5zY2VpdmVyID0gdGhpcy5wYy5hZGRUcmFuc2NlaXZlcih0cmFjaywgaW5pdCk7XHJcbiAgICAgICAgICAgICAgICB0aGlzLnNldFByZWZlcnJlZENvZGVjKHRyYW5zY2VpdmVyLCB0cmFjay5raW5kKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgIH1cclxuICAgIHNldFByZWZlcnJlZENvZGVjKHRyYW5zY2VpdmVyLCBraW5kKSB7XHJcbiAgICAgICAgaWYgKCdzZXRDb2RlY1ByZWZlcmVuY2VzJyBpbiB0cmFuc2NlaXZlcikge1xyXG4gICAgICAgICAgICBjb25zdCBjYXAgPSBSVENSdHBTZW5kZXIuZ2V0Q2FwYWJpbGl0aWVzKGtpbmQpO1xyXG4gICAgICAgICAgICBpZiAoIWNhcClcclxuICAgICAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICAgICAgbGV0IHNlbENvZGVjO1xyXG4gICAgICAgICAgICBpZiAodGhpcy5jb25zdHJhaW50cy5wcmVmZXJyZWRDb2RlY1Byb2ZpbGUgJiYga2luZCA9PT0gJ3ZpZGVvJykge1xyXG4gICAgICAgICAgICAgICAgY29uc3QgYWxsQ29kZWNQcm9maWxlcyA9IGNhcC5jb2RlY3MuZmlsdGVyKChjKSA9PiBjLm1pbWVUeXBlLnRvTG93ZXJDYXNlKCkgPT09IGB2aWRlby8ke3RoaXMuY29uc3RyYWludHMuY29kZWMudG9Mb3dlckNhc2UoKX1gKTtcclxuICAgICAgICAgICAgICAgIGlmICghYWxsQ29kZWNQcm9maWxlcykge1xyXG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIHNlbENvZGVjID0gYWxsQ29kZWNQcm9maWxlcy5maW5kKChjKSA9PiB7IHZhciBfYTsgcmV0dXJuIGMuc2RwRm10cExpbmUgJiYgKChfYSA9IGMuc2RwRm10cExpbmUpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5pbmRleE9mKGBwcm9maWxlLWxldmVsLWlkPSR7dGhpcy5jb25zdHJhaW50cy5wcmVmZXJyZWRDb2RlY1Byb2ZpbGV9YCkpID49IDA7IH0pO1xyXG4gICAgICAgICAgICAgICAgaWYgKCFzZWxDb2RlYykge1xyXG4gICAgICAgICAgICAgICAgICAgIC8vIGdldCBmaXJzdCBvbmVcclxuICAgICAgICAgICAgICAgICAgICBzZWxDb2RlYyA9IGFsbENvZGVjUHJvZmlsZXNbMF07XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgZWxzZSB7XHJcbiAgICAgICAgICAgICAgICBzZWxDb2RlYyA9IGNhcC5jb2RlY3MuZmluZCgoYykgPT4gYy5taW1lVHlwZS50b0xvd2VyQ2FzZSgpID09PSBgdmlkZW8vJHt0aGlzLmNvbnN0cmFpbnRzLmNvZGVjLnRvTG93ZXJDYXNlKCl9YCB8fFxyXG4gICAgICAgICAgICAgICAgICAgIGMubWltZVR5cGUudG9Mb3dlckNhc2UoKSA9PT0gYGF1ZGlvL29wdXNgKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICBpZiAoc2VsQ29kZWMpIHtcclxuICAgICAgICAgICAgICAgIHRyYW5zY2VpdmVyLnNldENvZGVjUHJlZmVyZW5jZXMoW3NlbENvZGVjXSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICB9XHJcbiAgICB1cGRhdGVUcmFjayhuZXh0LCBwcmV2KSB7XHJcbiAgICAgICAgdGhpcy5hZGRUcmFjayhuZXh0KTtcclxuICAgICAgICAvLyBJZiBwdWJsaXNoZWQsIHJlcGxhY2UgcHVibGlzaGVkIHRyYWNrIHdpdGggdHJhY2sgZnJvbSBuZXcgZGV2aWNlXHJcbiAgICAgICAgaWYgKHByZXYpIHtcclxuICAgICAgICAgICAgdGhpcy5yZW1vdmVUcmFjayhwcmV2KTtcclxuICAgICAgICAgICAgcHJldi5zdG9wKCk7XHJcbiAgICAgICAgICAgIGlmICh0aGlzLnBjKSB7XHJcbiAgICAgICAgICAgICAgICB0aGlzLnBjLmdldFNlbmRlcnMoKS5mb3JFYWNoKGFzeW5jIChzZW5kZXIpID0+IHtcclxuICAgICAgICAgICAgICAgICAgICB2YXIgX2EsIF9iLCBfYztcclxuICAgICAgICAgICAgICAgICAgICBpZiAoKChfYSA9IHNlbmRlciA9PT0gbnVsbCB8fCBzZW5kZXIgPT09IHZvaWQgMCA/IHZvaWQgMCA6IHNlbmRlci50cmFjaykgPT09IG51bGwgfHwgX2EgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9hLmtpbmQpID09PSBuZXh0LmtpbmQgJiYgcHJldi5pZCA9PT0gKChfYiA9IHNlbmRlciA9PT0gbnVsbCB8fCBzZW5kZXIgPT09IHZvaWQgMCA/IHZvaWQgMCA6IHNlbmRlci50cmFjaykgPT09IG51bGwgfHwgX2IgPT09IHZvaWQgMCA/IHZvaWQgMCA6IF9iLmlkKSkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAoX2MgPSBzZW5kZXIudHJhY2spID09PSBudWxsIHx8IF9jID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYy5zdG9wKCk7XHJcbiAgICAgICAgICAgICAgICA