bx-rest 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +40 -0
- package/README.en.md +206 -2
- package/README.md +206 -2
- package/esm2022/functions/errors.mjs +18 -2
- package/esm2022/public-api.mjs +6 -2
- package/esm2022/services/frame/frame.mjs +347 -0
- package/esm2022/services/frame/transport.mjs +224 -0
- package/esm2022/services/frame/types.mjs +2 -0
- package/esm2022/services/http/HttpBX.mjs +14 -6
- package/esm2022/services/http/authRefresh.mjs +89 -0
- package/esm2022/services/navvy/extends/navvy-pag-base.mjs +11 -3
- package/esm2022/typification/settings.mjs +1 -1
- package/fesm2022/bx-rest.mjs +766 -81
- package/fesm2022/bx-rest.mjs.map +1 -1
- package/functions/errors.d.ts +17 -0
- package/package.json +1 -1
- package/public-api.d.ts +5 -1
- package/services/frame/frame.d.ts +191 -0
- package/services/frame/transport.d.ts +75 -0
- package/services/frame/types.d.ts +123 -0
- package/services/http/authRefresh.d.ts +19 -0
- package/typification/settings.d.ts +17 -0
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
import { BXRestFrameError, FrameTransport } from './transport';
|
|
2
|
+
const DEFAULT_TIMEOUT = 10000;
|
|
3
|
+
/**
|
|
4
|
+
* Команды порталу Bitrix24 из iframe приложения — без подключения BX24.js.
|
|
5
|
+
* Те же команды и те же имена, что у BX24.js, но вместо колбэков —
|
|
6
|
+
* промисы. Протокол внутренний и недокументированный, см. `transport.ts`.
|
|
7
|
+
*
|
|
8
|
+
* Создавайте один экземпляр на страницу и при старте приложения: параметры
|
|
9
|
+
* портала читаются в конструкторе (до того, как роутер перепишет адрес), а
|
|
10
|
+
* `firstRun` портал сообщает только в первом ответе на `getInitData`.
|
|
11
|
+
*
|
|
12
|
+
* Токены класс не логирует и никуда не сохраняет: `getAuth()` и
|
|
13
|
+
* `refreshAuth()` каждый раз спрашивают портал, а в `init()` токенов нет.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* const frame = new BXRestFrame()
|
|
17
|
+
* const { lang, placement } = await frame.init()
|
|
18
|
+
* await frame.fitWindow()
|
|
19
|
+
* const user = await frame.selectUser()
|
|
20
|
+
*/
|
|
21
|
+
export class BXRestFrame {
|
|
22
|
+
constructor(options = {}) {
|
|
23
|
+
this.transport = new FrameTransport();
|
|
24
|
+
// Открытый диалог каждого вида — новый вызов того же диалога отменяет прошлый
|
|
25
|
+
this.dialogs = new Map();
|
|
26
|
+
/** Мессенджер — как `BX24.im`. Портал на эти команды не отвечает. */
|
|
27
|
+
this.im = {
|
|
28
|
+
/** Позвонить сотруднику — `BX24.im.callTo()`. */
|
|
29
|
+
callTo: async (userId, video) => {
|
|
30
|
+
this.transport.post('imCallTo', { userId, video });
|
|
31
|
+
},
|
|
32
|
+
/** Позвонить на телефон — `BX24.im.phoneTo()`. */
|
|
33
|
+
phoneTo: async (phone) => {
|
|
34
|
+
this.transport.post('imPhoneTo', { phone });
|
|
35
|
+
},
|
|
36
|
+
/** Открыть чат — `BX24.im.openMessenger()`. */
|
|
37
|
+
openMessenger: async (dialogId) => {
|
|
38
|
+
this.transport.post('imOpenMessenger', { dialogId });
|
|
39
|
+
},
|
|
40
|
+
/** Открыть историю чата — `BX24.im.openHistory()`. */
|
|
41
|
+
openHistory: async (dialogId) => {
|
|
42
|
+
this.transport.post('imOpenHistory', { dialogId });
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
/** Встраивание — как `BX24.placement`. */
|
|
46
|
+
this.placement = {
|
|
47
|
+
/** Код и параметры встраивания — `BX24.placement.info()`. */
|
|
48
|
+
info: async () => {
|
|
49
|
+
const { placement, placementOptions } = await this.init();
|
|
50
|
+
return { placement, options: placementOptions };
|
|
51
|
+
},
|
|
52
|
+
/** Команды и события текущего встраивания — `BX24.placement.getInterface()`. */
|
|
53
|
+
getInterface: async () => {
|
|
54
|
+
return await this.transport.request('getInterface', null, { timeout: this.timeout });
|
|
55
|
+
},
|
|
56
|
+
/**
|
|
57
|
+
* Команда встраивания — `BX24.placement.call()`. Набор команд зависит от
|
|
58
|
+
* встраивания (см. `getInterface()`). Не на все команды портал отвечает:
|
|
59
|
+
* без ответа за `timeout` промис завершается с `undefined`.
|
|
60
|
+
*/
|
|
61
|
+
call: async (command, params, options = {}) => {
|
|
62
|
+
return this.transport.request(command, params, {
|
|
63
|
+
timeout: options.timeout ?? this.timeout,
|
|
64
|
+
onTimeout: 'resolve',
|
|
65
|
+
});
|
|
66
|
+
},
|
|
67
|
+
/**
|
|
68
|
+
* Подписка на событие встраивания — `BX24.placement.bindEvent()`.
|
|
69
|
+
* `handler` вызывается при каждом событии. Возвращает функцию отписки:
|
|
70
|
+
* она только перестаёт вызывать `handler` — отменить подписку на
|
|
71
|
+
* стороне портала протокол не позволяет. Вне iframe бросает
|
|
72
|
+
* `BXRestFrameError` с кодом `NOT_IN_FRAME`.
|
|
73
|
+
*/
|
|
74
|
+
bindEvent: (event, handler) => {
|
|
75
|
+
return this.transport.subscribe('placementBindEvent', { event }, handler);
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
/** Настройки приложения для текущего пользователя — как `BX24.userOption`. */
|
|
79
|
+
this.userOption = {
|
|
80
|
+
get: async (name) => (await this.init()).userOptions[name],
|
|
81
|
+
set: async (name, value) => {
|
|
82
|
+
const init = await this.init();
|
|
83
|
+
init.userOptions[name] = value;
|
|
84
|
+
await this.ack('setUserOption', { name, value });
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
/** Настройки приложения для всего портала — как `BX24.appOption`. */
|
|
88
|
+
this.appOption = {
|
|
89
|
+
get: async (name) => (await this.init()).appOptions[name],
|
|
90
|
+
/**
|
|
91
|
+
* Менять их может только администратор портала: остальным — ошибка
|
|
92
|
+
* `ACCESS_DENIED` (BX24.js в этом случае молча ничего не делает).
|
|
93
|
+
* Возвращает настройки приложения после сохранения.
|
|
94
|
+
*/
|
|
95
|
+
set: async (name, value) => {
|
|
96
|
+
const init = await this.init();
|
|
97
|
+
if (!init.isAdmin) {
|
|
98
|
+
throw new BXRestFrameError('ACCESS_DENIED', 'Only a Bitrix24 administrator can change application options.');
|
|
99
|
+
}
|
|
100
|
+
init.appOptions[name] = value;
|
|
101
|
+
return await this.transport.request('setAppOption', { name, value }, { timeout: this.timeout });
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
this.timeout = options.timeout ?? DEFAULT_TIMEOUT;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Данные запуска приложения — аналог `BX24.init()`: язык, домен, права,
|
|
108
|
+
* встраивание, настройки, признаки установки. Запрашиваются у портала
|
|
109
|
+
* один раз, дальше берутся из памяти. Токенов здесь нет — см. `getAuth()`.
|
|
110
|
+
*/
|
|
111
|
+
init() {
|
|
112
|
+
if (this.initValue) {
|
|
113
|
+
return Promise.resolve(this.initValue);
|
|
114
|
+
}
|
|
115
|
+
if (!this.initRequest) {
|
|
116
|
+
this.initRequest = this.getInitData()
|
|
117
|
+
.then(() => this.initValue)
|
|
118
|
+
.finally(() => {
|
|
119
|
+
this.initRequest = undefined;
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
return this.initRequest;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Текущая авторизация приложения — аналог `BX24.getAuth()`. Каждый вызов —
|
|
126
|
+
* новый запрос `getInitData` к порталу.
|
|
127
|
+
*
|
|
128
|
+
* `expires_in` портал считает от срока жизни токена в момент выдачи, а не
|
|
129
|
+
* от остатка: если страница открыта давно, значение будет завышено (так
|
|
130
|
+
* же и у BX24.js). Для свежего токена используйте `refreshAuth()`.
|
|
131
|
+
*/
|
|
132
|
+
async getAuth() {
|
|
133
|
+
const data = await this.getInitData();
|
|
134
|
+
return this.toAuth('getInitData', data, String(data['MEMBER_ID'] || ''));
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Новая авторизация приложения — аналог `BX24.refreshAuth()`: портал
|
|
138
|
+
* выпускает новую пару `access_token`/`refresh_token`. Если портал не может
|
|
139
|
+
* выдать токен, он показывает `alert` «Unable to get new token!» и не
|
|
140
|
+
* отвечает — тогда ошибка `TIMEOUT`.
|
|
141
|
+
*/
|
|
142
|
+
async refreshAuth() {
|
|
143
|
+
// member_id приходит только в getInitData — refreshAuth его не возвращает
|
|
144
|
+
const { memberId } = await this.init();
|
|
145
|
+
const data = asObject('refreshAuth', await this.transport.request('refreshAuth', {}, { timeout: this.timeout }));
|
|
146
|
+
return this.toAuth('refreshAuth', data, memberId);
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Завершить установку — аналог `BX24.installFinish()`: портал отмечает
|
|
150
|
+
* приложение установленным и перезагружает страницу. Делает что-то только
|
|
151
|
+
* на странице установщика (`init().install`), иначе — ничего, как и BX24.js.
|
|
152
|
+
*/
|
|
153
|
+
async installFinish() {
|
|
154
|
+
if ((await this.init()).install) {
|
|
155
|
+
this.transport.post('setInstallFinish', {});
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Отметить, что первый запуск у этого пользователя пройден, — то, что
|
|
160
|
+
* BX24.js делает после последнего обработчика `BX24.install()`. Без этого
|
|
161
|
+
* `init().firstRun` останется `true` и при следующих запусках. Делает
|
|
162
|
+
* что-то только при первом запуске.
|
|
163
|
+
*/
|
|
164
|
+
async firstRunFinish() {
|
|
165
|
+
const init = await this.init();
|
|
166
|
+
if (init.firstRun) {
|
|
167
|
+
await this.ack('setInstall', { install: true });
|
|
168
|
+
init.firstRun = false;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/** Задать размер фрейма — `BX24.resizeWindow()`. Возвращает размер, который выставил портал. */
|
|
172
|
+
async resizeWindow(width, height) {
|
|
173
|
+
const w = Number.parseInt(String(width), 10);
|
|
174
|
+
const h = Number.parseInt(String(height), 10);
|
|
175
|
+
if (!(w > 0 && h > 0)) {
|
|
176
|
+
throw new TypeError('resizeWindow: width and height must be positive numbers.');
|
|
177
|
+
}
|
|
178
|
+
return await this.ack('resizeWindow', { width: w, height: h });
|
|
179
|
+
}
|
|
180
|
+
/** Подогнать высоту фрейма под содержимое — `BX24.fitWindow()`. */
|
|
181
|
+
async fitWindow() {
|
|
182
|
+
const root = document.documentElement;
|
|
183
|
+
const height = Math.max(root.scrollHeight, root.offsetHeight);
|
|
184
|
+
return await this.ack('resizeWindow', { width: '100%', height });
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Перезагрузить страницу портала с приложением — `BX24.reloadWindow()`.
|
|
188
|
+
* Портал на эту команду не отвечает.
|
|
189
|
+
*/
|
|
190
|
+
async reloadWindow() {
|
|
191
|
+
this.transport.post('reloadWindow', {});
|
|
192
|
+
}
|
|
193
|
+
/** Заголовок страницы портала — `BX24.setTitle()`. */
|
|
194
|
+
async setTitle(title) {
|
|
195
|
+
return await this.ack('setTitle', { title: String(title) });
|
|
196
|
+
}
|
|
197
|
+
/** Прокрутить страницу портала — `BX24.scrollParentWindow()`. */
|
|
198
|
+
async scrollParentWindow(scroll) {
|
|
199
|
+
const value = Number.parseInt(String(scroll), 10);
|
|
200
|
+
if (Number.isNaN(value)) {
|
|
201
|
+
throw new TypeError('scrollParentWindow: scroll must be a number.');
|
|
202
|
+
}
|
|
203
|
+
return await this.ack('setScroll', { scroll: value });
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Диалог выбора одного сотрудника — `BX24.selectUser()`. Ждёт выбора без
|
|
207
|
+
* ограничения по времени: если пользователь закрыл диалог, портал не
|
|
208
|
+
* отвечает вовсе. Отменить ожидание — `signal` или новый вызов
|
|
209
|
+
* `selectUser()`/`selectUsers()` (ошибка `CANCELLED`).
|
|
210
|
+
*/
|
|
211
|
+
selectUser(options = {}) {
|
|
212
|
+
return this.dialog('user', 'selectUser', { title: options.title ?? '', mult: false }, options.signal);
|
|
213
|
+
}
|
|
214
|
+
/** Диалог выбора нескольких сотрудников — `BX24.selectUsers()`. Ожидание — как у `selectUser()`. */
|
|
215
|
+
selectUsers(options = {}) {
|
|
216
|
+
return this.dialog('user', 'selectUser', { title: options.title ?? '', mult: true }, options.signal);
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Диалог выбора прав доступа — `BX24.selectAccess()`. `value` — коды,
|
|
220
|
+
* которые нельзя выбрать. Ожидание — как у `selectUser()`.
|
|
221
|
+
*/
|
|
222
|
+
selectAccess(options = {}) {
|
|
223
|
+
return this.dialog('access', 'selectAccess', { value: options.value ?? [] }, options.signal);
|
|
224
|
+
}
|
|
225
|
+
/** Диалог выбора объектов CRM — `BX24.selectCRM()`. Ожидание — как у `selectUser()`. */
|
|
226
|
+
selectCRM(options = {}) {
|
|
227
|
+
const { entityType, multiple, value, signal } = options;
|
|
228
|
+
return this.dialog('crm', 'selectCRM', { entityType, multiple, value }, signal);
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Открыть приложение в слайдере — `BX24.openApplication()`. Промис
|
|
232
|
+
* завершается, когда слайдер закрыли. `settings` — настройки слайдера
|
|
233
|
+
* (уходят как `bx24_<ключ>`, как в BX24.js).
|
|
234
|
+
*/
|
|
235
|
+
async openApplication(params = {}, settings = {}, options = {}) {
|
|
236
|
+
const message = { ...params };
|
|
237
|
+
for (const [key, value] of Object.entries(settings)) {
|
|
238
|
+
message[`bx24_${key}`] = value;
|
|
239
|
+
}
|
|
240
|
+
await this.transport.request('openApplication', message, { timeout: false, signal: options.signal });
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Открыть страницу портала в слайдере — `BX24.openPath()`. Промис
|
|
244
|
+
* завершается, когда слайдер закрыли (`{ result: 'close' }`), или сразу,
|
|
245
|
+
* если путь не открылся (`{ result: 'error', errorCode }`).
|
|
246
|
+
*/
|
|
247
|
+
async openPath(path, options = {}) {
|
|
248
|
+
return await this.transport.request('openPath', { path }, { timeout: false, signal: options.signal });
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Закрыть слайдер с приложением — `BX24.closeApplication()`. Если
|
|
252
|
+
* приложение открыто не в слайдере, ничего не происходит. Узнать о
|
|
253
|
+
* закрытии может открывший слайдер — через `openApplication()`.
|
|
254
|
+
*/
|
|
255
|
+
async closeApplication() {
|
|
256
|
+
this.transport.post('closeApplication', null);
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Команда, на которую портал отвечает подтверждением. В некоторых
|
|
260
|
+
* встраиваниях портал на такие команды не отвечает (так считает и
|
|
261
|
+
* b24jssdk) — тогда промис завершается с `undefined`, а не ошибкой.
|
|
262
|
+
*/
|
|
263
|
+
ack(command, params) {
|
|
264
|
+
return this.transport.request(command, params, { timeout: this.timeout, onTimeout: 'resolve' });
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Диалоги ждут пользователя без таймаута. Портал держит один обработчик
|
|
268
|
+
* на диалог (у выбора сотрудников он общий для `selectUser` и
|
|
269
|
+
* `selectUsers`) и на прошлый вызов уже не ответит — поэтому новый вызов
|
|
270
|
+
* отменяет ожидание прошлого.
|
|
271
|
+
*/
|
|
272
|
+
dialog(kind, command, params, signal) {
|
|
273
|
+
this.dialogs.get(kind)?.abort();
|
|
274
|
+
const controller = new AbortController();
|
|
275
|
+
this.dialogs.set(kind, controller);
|
|
276
|
+
const onAbort = () => controller.abort();
|
|
277
|
+
if (signal?.aborted) {
|
|
278
|
+
controller.abort();
|
|
279
|
+
}
|
|
280
|
+
signal?.addEventListener('abort', onAbort, { once: true });
|
|
281
|
+
return this.transport.request(command, params, { timeout: false, signal: controller.signal })
|
|
282
|
+
.finally(() => {
|
|
283
|
+
signal?.removeEventListener('abort', onAbort);
|
|
284
|
+
if (this.dialogs.get(kind) === controller) {
|
|
285
|
+
this.dialogs.delete(kind);
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
async getInitData() {
|
|
290
|
+
const data = asObject('getInitData', await this.transport.request('getInitData', null, { timeout: this.timeout }));
|
|
291
|
+
// firstRun портал отдаёт только в первом ответе за загрузку страницы —
|
|
292
|
+
// поэтому запоминаем данные первого ответа, кто бы его ни запросил
|
|
293
|
+
if (!this.initValue) {
|
|
294
|
+
this.initValue = this.toInit(data);
|
|
295
|
+
}
|
|
296
|
+
return data;
|
|
297
|
+
}
|
|
298
|
+
toInit(data) {
|
|
299
|
+
return {
|
|
300
|
+
// Как BX24.js: домен — из параметров фрейма, DOMAIN ответа — запасной
|
|
301
|
+
domain: this.transport.domain || String(data['DOMAIN'] || ''),
|
|
302
|
+
lang: String(data['LANG'] || ''),
|
|
303
|
+
path: String(data['PATH'] || ''),
|
|
304
|
+
https: Number.parseInt(String(data['PROTOCOL']), 10) === 1,
|
|
305
|
+
memberId: String(data['MEMBER_ID'] || ''),
|
|
306
|
+
isAdmin: !!data['IS_ADMIN'],
|
|
307
|
+
install: !!data['INSTALL'],
|
|
308
|
+
firstRun: !!data['FIRST_RUN'],
|
|
309
|
+
placement: String(data['PLACEMENT'] || 'DEFAULT'),
|
|
310
|
+
placementOptions: data['PLACEMENT_OPTIONS'],
|
|
311
|
+
userOptions: toRecord(data['USER_OPTIONS']),
|
|
312
|
+
appOptions: toRecord(data['APP_OPTIONS']),
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
toAuth(command, data, memberId) {
|
|
316
|
+
const { AUTH_ID, REFRESH_ID, AUTH_EXPIRES } = data;
|
|
317
|
+
if (!AUTH_ID || typeof AUTH_ID !== 'string') {
|
|
318
|
+
throw new BXRestFrameError('NO_AUTH', `Bitrix24 answered ${command} without an access token.`);
|
|
319
|
+
}
|
|
320
|
+
// AUTH_EXPIRES — срок жизни токена в секундах. BX24.js переводит его в
|
|
321
|
+
// момент истечения в миллисекундах — так же, как здесь.
|
|
322
|
+
const expiresIn = Number.parseInt(String(AUTH_EXPIRES), 10);
|
|
323
|
+
if (!Number.isFinite(expiresIn) || expiresIn <= 0) {
|
|
324
|
+
throw new BXRestFrameError('BAD_RESPONSE', `Bitrix24 answered ${command} without a usable AUTH_EXPIRES.`);
|
|
325
|
+
}
|
|
326
|
+
return {
|
|
327
|
+
access_token: AUTH_ID,
|
|
328
|
+
refresh_token: typeof REFRESH_ID === 'string' ? REFRESH_ID : '',
|
|
329
|
+
expires_in: Date.now() + expiresIn * 1000,
|
|
330
|
+
domain: this.transport.domain,
|
|
331
|
+
member_id: memberId,
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
function asObject(command, data) {
|
|
336
|
+
if (!data || typeof data !== 'object' || Array.isArray(data)) {
|
|
337
|
+
throw new BXRestFrameError('BAD_RESPONSE', `Bitrix24 answered ${command} with a payload that is not an object.`);
|
|
338
|
+
}
|
|
339
|
+
return data;
|
|
340
|
+
}
|
|
341
|
+
// Пустые настройки PHP отдаёт массивом `[]`
|
|
342
|
+
function toRecord(value) {
|
|
343
|
+
return (value && typeof value === 'object' && !Array.isArray(value))
|
|
344
|
+
? { ...value }
|
|
345
|
+
: {};
|
|
346
|
+
}
|
|
347
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZnJhbWUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9ieC1yZXN0L3NyYy9zZXJ2aWNlcy9mcmFtZS9mcmFtZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsY0FBYyxFQUFFLE1BQU0sYUFBYSxDQUFBO0FBTzlELE1BQU0sZUFBZSxHQUFHLEtBQUssQ0FBQTtBQUU3Qjs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FpQkc7QUFDSCxNQUFNLE9BQU8sV0FBVztJQTJGdEIsWUFBWSxVQUE4QixFQUFFO1FBekYzQixjQUFTLEdBQUcsSUFBSSxjQUFjLEVBQUUsQ0FBQTtRQUlqRCw4RUFBOEU7UUFDN0QsWUFBTyxHQUFHLElBQUksR0FBRyxFQUE4QyxDQUFBO1FBRWhGLHFFQUFxRTtRQUM1RCxPQUFFLEdBQUc7WUFDWixpREFBaUQ7WUFDakQsTUFBTSxFQUFFLEtBQUssRUFBRSxNQUF1QixFQUFFLEtBQWUsRUFBaUIsRUFBRTtnQkFDeEUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUE7WUFDcEQsQ0FBQztZQUNELGtEQUFrRDtZQUNsRCxPQUFPLEVBQUUsS0FBSyxFQUFFLEtBQWEsRUFBaUIsRUFBRTtnQkFDOUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQTtZQUM3QyxDQUFDO1lBQ0QsK0NBQStDO1lBQy9DLGFBQWEsRUFBRSxLQUFLLEVBQUUsUUFBMEIsRUFBaUIsRUFBRTtnQkFDakUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsaUJBQWlCLEVBQUUsRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFBO1lBQ3RELENBQUM7WUFDRCxzREFBc0Q7WUFDdEQsV0FBVyxFQUFFLEtBQUssRUFBRSxRQUF5QixFQUFpQixF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LElBQWE7SUFDOUMsSUFBSSxDQUFDLElBQUksSUFBSSxPQUFPLElBQUksS0FBSyxRQUFRLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO1FBQzdELE1BQU0sSUFBSSxnQkFBZ0IsQ0FBQyxjQUFjLEVBQUUscUJBQXFCLE9BQU8sd0NBQXdDLENBQUMsQ0FBQTtJQUNsSCxDQUFDO0lBQ0QsT0FBTyxJQUErQixDQUFBO0FBQ3hDLENBQUM7QUFFRCw0Q0FBNEM7QUFDNUMsU0FBUyxRQUFRLENBQUMsS0FBYztJQUM5QixPQUFPLENBQUMsS0FBSyxJQUFJLE9BQU8sS0FBSyxLQUFLLFFBQVEsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDbEUsQ0FBQyxDQUFDLEVBQUUsR0FBRyxLQUFnQyxFQUFFO1FBQ3pDLENBQUMsQ0FBQyxFQUFFLENBQUE7QUFDUixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQlhSZXN0RnJhbWVFcnJvciwgRnJhbWVUcmFuc3BvcnQgfSBmcm9tICcuL3RyYW5zcG9ydCdcbmltcG9ydCB7XG4gIEJYUmVzdEZyYW1lT3B0aW9ucywgaUJYUmVzdEZyYW1lQWNjZXNzLCBpQlhSZXN0RnJhbWVBdXRoLCBpQlhSZXN0RnJhbWVDcm1TZWxlY3Rpb24sIGlCWFJlc3RGcmFtZUNybVNlbGVjdE9wdGlvbnMsXG4gIGlCWFJlc3RGcmFtZUluaXQsIGlCWFJlc3RGcmFtZU9wZW5QYXRoUmVzdWx0LCBpQlhSZXN0RnJhbWVQbGFjZW1lbnRJbmZvLCBpQlhSZXN0RnJhbWVQbGFjZW1lbnRJbnRlcmZhY2UsXG4gIGlCWFJlc3RGcmFtZVNpemUsIGlCWFJlc3RGcmFtZVVzZXIsXG59IGZyb20gJy4vdHlwZXMnXG5cbmNvbnN0IERFRkFVTFRfVElNRU9VVCA9IDEwMDAwXG5cbi8qKlxuICog0JrQvtC80LDQvdC00Ysg0L/QvtGA0YLQsNC70YMgQml0cml4MjQg0LjQtyBpZnJhbWUg0L/RgNC40LvQvtC20LXQvdC40Y8g4oCUINCx0LXQtyDQv9C+0LTQutC70Y7Rh9C10L3QuNGPIEJYMjQuanMuXG4gKiDQotC1INC20LUg0LrQvtC80LDQvdC00Ysg0Lgg0YLQtSDQttC1INC40LzQtdC90LAsINGH0YLQviDRgyBCWDI0LmpzLCDQvdC+INCy0LzQtdGB0YLQviDQutC+0LvQsdGN0LrQvtCyIOKAlFxuICog0L/RgNC+0LzQuNGB0YsuINCf0YDQvtGC0L7QutC+0Lsg0LLQvdGD0YLRgNC10L3QvdC40Lkg0Lgg0L3QtdC00L7QutGD0LzQtdC90YLQuNGA0L7QstCw0L3QvdGL0LksINGB0LwuIGB0cmFuc3BvcnQudHNgLlxuICpcbiAqINCh0L7Qt9C00LDQstCw0LnRgtC1INC+0LTQuNC9INGN0LrQt9C10LzQv9C70Y/RgCDQvdCwINGB0YLRgNCw0L3QuNGG0YMg0Lgg0L/RgNC4INGB0YLQsNGA0YLQtSDQv9GA0LjQu9C+0LbQtdC90LjRjzog0L/QsNGA0LDQvNC10YLRgNGLXG4gKiDQv9C+0YDRgtCw0LvQsCDRh9C40YLQsNGO0YLRgdGPINCyINC60L7QvdGB0YLRgNGD0LrRgtC+0YDQtSAo0LTQviDRgtC+0LPQviwg0LrQsNC6INGA0L7Rg9GC0LXRgCDQv9C10YDQtdC/0LjRiNC10YIg0LDQtNGA0LXRgSksINCwXG4gKiBgZmlyc3RSdW5gINC/0L7RgNGC0LDQuyDRgdC+0L7QsdGJ0LDQtdGCINGC0L7Qu9GM0LrQviDQsiDQv9C10YDQstC+0Lwg0L7RgtCy0LXRgtC1INC90LAgYGdldEluaXREYXRhYC5cbiAqXG4gKiDQotC+0LrQtdC90Ysg0LrQu9Cw0YHRgSDQvdC1INC70L7Qs9C40YDRg9C10YIg0Lgg0L3QuNC60YPQtNCwINC90LUg0YHQvtGF0YDQsNC90Y/QtdGCOiBgZ2V0QXV0aCgpYCDQuFxuICogYHJlZnJlc2hBdXRoKClgINC60LDQttC00YvQuSDRgNCw0Lcg0YHQv9GA0LDRiNC40LLQsNGO0YIg0L/QvtGA0YLQsNC7LCDQsCDQsiBgaW5pdCgpYCDRgtC+0LrQtdC90L7QsiDQvdC10YIuXG4gKlxuICogQGV4YW1wbGVcbiAqIGNvbnN0IGZyYW1lID0gbmV3IEJYUmVzdEZyYW1lKClcbiAqIGNvbnN0IHsgbGFuZywgcGxhY2VtZW50IH0gPSBhd2FpdCBmcmFtZS5pbml0KClcbiAqIGF3YWl0IGZyYW1lLmZpdFdpbmRvdygpXG4gKiBjb25zdCB1c2VyID0gYXdhaXQgZnJhbWUuc2VsZWN0VXNlcigpXG4gKi9cbmV4cG9ydCBjbGFzcyBCWFJlc3RGcmFtZSB7XG5cbiAgcHJpdmF0ZSByZWFkb25seSB0cmFuc3BvcnQgPSBuZXcgRnJhbWVUcmFuc3BvcnQoKVxuICBwcml2YXRlIHJlYWRvbmx5IHRpbWVvdXQ6IG51bWJlclxuICBwcml2YXRlIGluaXRWYWx1ZT86IGlCWFJlc3RGcmFtZUluaXRcbiAgcHJpdmF0ZSBpbml0UmVxdWVzdD86IFByb21pc2U8aUJYUmVzdEZyYW1lSW5pdD5cbiAgLy8g0J7RgtC60YDRi9GC0YvQuSDQtNC40LDQu9C+0LMg0LrQsNC20LTQvtCz0L4g0LLQuNC00LAg4oCUINC90L7QstGL0Lkg0LLRi9C30L7QsiDRgtC+0LPQviDQttC1INC00LjQsNC70L7Qs9CwINC+0YLQvNC10L3Rj9C10YIg0L/RgNC+0YjQu9GL0LlcbiAgcHJpdmF0ZSByZWFkb25seSBkaWFsb2dzID0gbmV3IE1hcDwndXNlcicgfCAnYWNjZXNzJyB8ICdjcm0nLCBBYm9ydENvbnRyb2xsZXI+KClcblxuICAvKiog0JzQtdGB0YHQtdC90LTQttC10YAg4oCUINC60LDQuiBgQlgyNC5pbWAuINCf0L7RgNGC0LDQuyDQvdCwINGN0YLQuCDQutC+0LzQsNC90LTRiyDQvdC1INC+0YLQstC10YfQsNC10YIuICovXG4gIHJlYWRvbmx5IGltID0ge1xuICAgIC8qKiDQn9C+0LfQstC+0L3QuNGC0Ywg0YHQvtGC0YDRg9C00L3QuNC60YMg4oCUIGBCWDI0LmltLmNhbGxUbygpYC4gKi9cbiAgICBjYWxsVG86IGFzeW5jICh1c2VySWQ6IG51bWJlciB8IHN0cmluZywgdmlkZW8/OiBib29sZWFuKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgICB0aGlzLnRyYW5zcG9ydC5wb3N0KCdpbUNhbGxUbycsIHsgdXNlcklkLCB2aWRlbyB9KVxuICAgIH0sXG4gICAgLyoqINCf0L7Qt9Cy0L7QvdC40YLRjCDQvdCwINGC0LXQu9C10YTQvtC9IOKAlCBgQlgyNC5pbS5waG9uZVRvKClgLiAqL1xuICAgIHBob25lVG86IGFzeW5jIChwaG9uZTogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgICB0aGlzLnRyYW5zcG9ydC5wb3N0KCdpbVBob25lVG8nLCB7IHBob25lIH0pXG4gICAgfSxcbiAgICAvKiog0J7RgtC60YDRi9GC0Ywg0YfQsNGCIOKAlCBgQlgyNC5pbS5vcGVuTWVzc2VuZ2VyKClgLiAqL1xuICAgIG9wZW5NZXNzZW5nZXI6IGFzeW5jIChkaWFsb2dJZD86IG51bWJlciB8IHN0cmluZyk6IFByb21pc2U8dm9pZD4gPT4ge1xuICAgICAgdGhpcy50cmFuc3BvcnQucG9zdCgnaW1PcGVuTWVzc2VuZ2VyJywgeyBkaWFsb2dJZCB9KVxuICAgIH0sXG4gICAgLyoqINCe0YLQutGA0YvRgtGMINC40YHRgtC+0YDQuNGOINGH0LDRgtCwIOKAlCBgQlgyNC5pbS5vcGVuSGlzdG9yeSgpYC4gKi9cbiAgICBvcGVuSGlzdG9yeTogYXN5bmMgKGRpYWxvZ0lkOiBudW1iZXIgfCBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+ID0+IHtcbiAgICAgIHRoaXMudHJhbnNwb3J0LnBvc3QoJ2ltT3Blbkhpc3RvcnknLCB7IGRpYWxvZ0lkIH0pXG4gICAgfSxcbiAgfVxuXG4gIC8qKiDQktGB0YLRgNCw0LjQstCw0L3QuNC1IOKAlCDQutCw0LogYEJYMjQucGxhY2VtZW50YC4gKi9cbiAgcmVhZG9ubHkgcGxhY2VtZW50ID0ge1xuICAgIC8qKiDQmtC+0LQg0Lgg0L/QsNGA0LDQvNC10YLRgNGLINCy0YHRgtGA0LDQuNCy0LDQvdC40Y8g4oCUIGBCWDI0LnBsYWNlbWVudC5pbmZvKClgLiAqL1xuICAgIGluZm86IGFzeW5jICgpOiBQcm9taXNlPGlCWFJlc3RGcmFtZVBsYWNlbWVudEluZm8+ID0+IHtcbiAgICAgIGNvbnN0IHsgcGxhY2VtZW50LCBwbGFjZW1lbnRPcHRpb25zIH0gPSBhd2FpdCB0aGlzLmluaXQoKVxuICAgICAgcmV0dXJuIHsgcGxhY2VtZW50LCBvcHRpb25zOiBwbGFjZW1lbnRPcHRpb25zIH1cbiAgICB9LFxuICAgIC8qKiDQmtC+0LzQsNC90LTRiyDQuCDRgdC+0LHRi9GC0LjRjyDRgtC10LrRg9GJ0LXQs9C+INCy0YHRgtGA0LDQuNCy0LDQvdC40Y8g4oCUIGBCWDI0LnBsYWNlbWVudC5nZXRJbnRlcmZhY2UoKWAuICovXG4gICAgZ2V0SW50ZXJmYWNlOiBhc3luYyAoKTogUHJvbWlzZTxpQlhSZXN0RnJhbWVQbGFjZW1lbnRJbnRlcmZhY2U+ID0+IHtcbiAgICAgIHJldHVybiBhd2FpdCB0aGlzLnRyYW5zcG9ydC5yZXF1ZXN0KCdnZXRJbnRlcmZhY2UnLCBudWxsLCB7IHRpbWVvdXQ6IHRoaXMudGltZW91dCB9KSBhcyBpQlhSZXN0RnJhbWVQbGFjZW1lbnRJbnRlcmZhY2VcbiAgICB9LFxuICAgIC8qKlxuICAgICAqINCa0L7QvNCw0L3QtNCwINCy0YHRgtGA0LDQuNCy0LDQvdC40Y8g4oCUIGBCWDI0LnBsYWNlbWVudC5jYWxsKClgLiDQndCw0LHQvtGAINC60L7QvNCw0L3QtCDQt9Cw0LLQuNGB0LjRgiDQvtGCXG4gICAgICog0LLRgdGC0YDQsNC40LLQsNC90LjRjyAo0YHQvC4gYGdldEludGVyZmFjZSgpYCkuINCd0LUg0L3QsCDQstGB0LUg0LrQvtC80LDQvdC00Ysg0L/QvtGA0YLQsNC7INC+0YLQstC10YfQsNC10YI6XG4gICAgICog0LHQtdC3INC+0YLQstC10YLQsCDQt9CwIGB0aW1lb3V0YCDQv9GA0L7QvNC40YEg0LfQsNCy0LXRgNGI0LDQtdGC0YHRjyDRgSBgdW5kZWZpbmVkYC5cbiAgICAgKi9cbiAgICBjYWxsOiBhc3luYyAoY29tbWFuZDogc3RyaW5nLCBwYXJhbXM/OiB1bmtub3duLCBvcHRpb25zOiB7IHRpbWVvdXQ/OiBudW1iZXIgfCBmYWxzZSB9ID0ge30pOiBQcm9taXNlPHVua25vd24+ID0+IHtcbiAgICAgIHJldHVybiB0aGlzLnRyYW5zcG9ydC5yZXF1ZXN0KGNvbW1hbmQsIHBhcmFtcywge1xuICAgICAgICB0aW1lb3V0OiBvcHRpb25zLnRpbWVvdXQgPz8gdGhpcy50aW1lb3V0LFxuICAgICAgICBvblRpbWVvdXQ6ICdyZXNvbHZlJyxcbiAgICAgIH0pXG4gICAgfSxcbiAgICAvKipcbiAgICAgKiDQn9C+0LTQv9C40YHQutCwINC90LAg0YHQvtCx0YvRgtC40LUg0LLRgdGC0YDQsNC40LLQsNC90LjRjyDigJQgYEJYMjQucGxhY2VtZW50LmJpbmRFdmVudCgpYC5cbiAgICAgKiBgaGFuZGxlcmAg0LLRi9C30YvQstCw0LXRgtGB0Y8g0L/RgNC4INC60LDQttC00L7QvCDRgdC+0LHRi9GC0LjQuC4g0JLQvtC30LLRgNCw0YnQsNC10YIg0YTRg9C90LrRhtC40Y4g0L7RgtC/0LjRgdC60Lg6XG4gICAgICog0L7QvdCwINGC0L7Qu9GM0LrQviDQv9C10YDQtdGB0YLQsNGR0YIg0LLRi9C30YvQstCw0YLRjCBgaGFuZGxlcmAg4oCUINC+0YLQvNC10L3QuNGC0Ywg0L/QvtC00L/QuNGB0LrRgyDQvdCwXG4gICAgICog0YHRgtC+0YDQvtC90LUg0L/QvtGA0YLQsNC70LAg0L/RgNC+0YLQvtC60L7QuyDQvdC1INC/0L7Qt9Cy0L7Qu9GP0LXRgi4g0JLQvdC1IGlmcmFtZSDQsdGA0L7RgdCw0LXRglxuICAgICAqIGBCWFJlc3RGcmFtZUVycm9yYCDRgSDQutC+0LTQvtC8IGBOT1RfSU5fRlJBTUVgLlxuICAgICAqL1xuICAgIGJpbmRFdmVudDogKGV2ZW50OiBzdHJpbmcsIGhhbmRsZXI6IChkYXRhOiB1bmtub3duKSA9PiB2b2lkKTogKCkgPT4gdm9pZCA9PiB7XG4gICAgICByZXR1cm4gdGhpcy50cmFuc3BvcnQuc3Vic2NyaWJlKCdwbGFjZW1lbnRCaW5kRXZlbnQnLCB7IGV2ZW50IH0sIGhhbmRsZXIpXG4gICAgfSxcbiAgfVxuXG4gIC8qKiDQndCw0YHRgtGA0L7QudC60Lgg0L/RgNC40LvQvtC20LXQvdC40Y8g0LTQu9GPINGC0LXQutGD0YnQtdCz0L4g0L/QvtC70YzQt9C+0LLQsNGC0LXQu9GPIOKAlCDQutCw0LogYEJYMjQudXNlck9wdGlvbmAuICovXG4gIHJlYWRvbmx5IHVzZXJPcHRpb24gPSB7XG4gICAgZ2V0OiBhc3luYyAobmFtZTogc3RyaW5nKTogUHJvbWlzZTx1bmtub3duPiA9PiAoYXdhaXQgdGhpcy5pbml0KCkpLnVzZXJPcHRpb25zW25hbWVdLFxuICAgIHNldDogYXN5bmMgKG5hbWU6IHN0cmluZywgdmFsdWU6IHVua25vd24pOiBQcm9taXNlPHZvaWQ+ID0+IHtcbiAgICAgIGNvbnN0IGluaXQgPSBhd2FpdCB0aGlzLmluaXQoKVxuICAgICAgaW5pdC51c2VyT3B0aW9uc1tuYW1lXSA9IHZhbHVlXG4gICAgICBhd2FpdCB0aGlzLmFjaygnc2V0VXNlck9wdGlvbicsIHsgbmFtZSwgdmFsdWUgfSlcbiAgICB9LFxuICB9XG5cbiAgLyoqINCd0LDRgdGC0YDQvtC50LrQuCDQv9GA0LjQu9C+0LbQtdC90LjRjyDQtNC70Y8g0LLRgdC10LPQviDQv9C+0YDRgtCw0LvQsCDigJQg0LrQsNC6IGBCWDI0LmFwcE9wdGlvbmAuICovXG4gIHJlYWRvbmx5IGFwcE9wdGlvbiA9IHtcbiAgICBnZXQ6IGFzeW5jIChuYW1lOiBzdHJpbmcpOiBQcm9taXNlPHVua25vd24+ID0+IChhd2FpdCB0aGlzLmluaXQoKSkuYXBwT3B0aW9uc1tuYW1lXSxcbiAgICAvKipcbiAgICAgKiDQnNC10L3Rj9GC0Ywg0LjRhSDQvNC+0LbQtdGCINGC0L7Qu9GM0LrQviDQsNC00LzQuNC90LjRgdGC0YDQsNGC0L7RgCDQv9C+0YDRgtCw0LvQsDog0L7RgdGC0LDQu9GM0L3Ri9C8IOKAlCDQvtGI0LjQsdC60LBcbiAgICAgKiBgQUNDRVNTX0RFTklFRGAgKEJYMjQuanMg0LIg0Y3RgtC+0Lwg0YHQu9GD0YfQsNC1INC80L7Qu9GH0LAg0L3QuNGH0LXQs9C+INC90LUg0LTQtdC70LDQtdGCKS5cbiAgICAgKiDQktC+0LfQstGA0LDRidCw0LXRgiDQvdCw0YHRgtGA0L7QudC60Lgg0L/RgNC40LvQvtC20LXQvdC40Y8g0L/QvtGB0LvQtSDRgdC+0YXRgNCw0L3QtdC90LjRjy5cbiAgICAgKi9cbiAgICBzZXQ6IGFzeW5jIChuYW1lOiBzdHJpbmcsIHZhbHVlOiB1bmtub3duKTogUHJvbWlzZTxSZWNvcmQ8c3RyaW5nLCB1bmtub3duPj4gPT4ge1xuICAgICAgY29uc3QgaW5pdCA9IGF3YWl0IHRoaXMuaW5pdCgpXG4gICAgICBpZiAoIWluaXQuaXNBZG1pbikge1xuICAgICAgICB0aHJvdyBuZXcgQlhSZXN0RnJhbWVFcnJvcignQUNDRVNTX0RFTklFRCcsICdPbmx5IGEgQml0cml4MjQgYWRtaW5pc3RyYXRvciBjYW4gY2hhbmdlIGFwcGxpY2F0aW9uIG9wdGlvbnMuJylcbiAgICAgIH1cbiAgICAgIGluaXQuYXBwT3B0aW9uc1tuYW1lXSA9IHZhbHVlXG4gICAgICByZXR1cm4gYXdhaXQgdGhpcy50cmFuc3BvcnQucmVxdWVzdCgnc2V0QXBwT3B0aW9uJywgeyBuYW1lLCB2YWx1ZSB9LCB7IHRpbWVvdXQ6IHRoaXMudGltZW91dCB9KSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPlxuICAgIH0sXG4gIH1cblxuICBjb25zdHJ1Y3RvcihvcHRpb25zOiBCWFJlc3RGcmFtZU9wdGlvbnMgPSB7fSkge1xuICAgIHRoaXMudGltZW91dCA9IG9wdGlvbnMudGltZW91dCA/PyBERUZBVUxUX1RJTUVPVVRcbiAgfVxuXG4gIC8qKlxuICAgKiDQlNCw0L3QvdGL0LUg0LfQsNC/0YPRgdC60LAg0L/RgNC40LvQvtC20LXQvdC40Y8g4oCUINCw0L3QsNC70L7QsyBgQlgyNC5pbml0KClgOiDRj9C30YvQuiwg0LTQvtC80LXQvSwg0L/RgNCw0LLQsCxcbiAgICog0LLRgdGC0YDQsNC40LLQsNC90LjQtSwg0L3QsNGB0YLRgNC+0LnQutC4LCDQv9GA0LjQt9C90LDQutC4INGD0YHRgtCw0L3QvtCy0LrQuC4g0JfQsNC/0YDQsNGI0LjQstCw0Y7RgtGB0Y8g0YMg0L/QvtGA0YLQsNC70LBcbiAgICog0L7QtNC40L0g0YDQsNC3LCDQtNCw0LvRjNGI0LUg0LHQtdGA0YPRgtGB0Y8g0LjQtyDQv9Cw0LzRj9GC0LguINCi0L7QutC10L3QvtCyINC30LTQtdGB0Ywg0L3QtdGCIOKAlCDRgdC8LiBgZ2V0QXV0aCgpYC5cbiAgICovXG4gIGluaXQoKTogUHJvbWlzZTxpQlhSZXN0RnJhbWVJbml0PiB7XG4gICAgaWYgKHRoaXMuaW5pdFZhbHVlKSB7XG4gICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHRoaXMuaW5pdFZhbHVlKVxuICAgIH1cbiAgICBpZiAoIXRoaXMuaW5pdFJlcXVlc3QpIHtcbiAgICAgIHRoaXMuaW5pdFJlcXVlc3QgPSB0aGlzLmdldEluaXREYXRhKClcbiAgICAgICAgLnRoZW4oKCkgPT4gdGhpcy5pbml0VmFsdWUgYXMgaUJYUmVzdEZyYW1lSW5pdClcbiAgICAgICAgLmZpbmFsbHkoKCkgPT4ge1xuICAgICAgICAgIHRoaXMuaW5pdFJlcXVlc3QgPSB1bmRlZmluZWRcbiAgICAgICAgfSlcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuaW5pdFJlcXVlc3RcbiAgfVxuXG4gIC8qKlxuICAgKiDQotC10LrRg9GJ0LDRjyDQsNCy0YLQvtGA0LjQt9Cw0YbQuNGPINC/0YDQuNC70L7QttC10L3QuNGPIOKAlCDQsNC90LDQu9C+0LMgYEJYMjQuZ2V0QXV0aCgpYC4g0JrQsNC20LTRi9C5INCy0YvQt9C+0LIg4oCUXG4gICAqINC90L7QstGL0Lkg0LfQsNC/0YDQvtGBIGBnZXRJbml0RGF0YWAg0Log0L/QvtGA0YLQsNC70YMuXG4gICAqXG4gICAqIGBleHBpcmVzX2luYCDQv9C+0YDRgtCw0Lsg0YHRh9C40YLQsNC10YIg0L7RgiDRgdGA0L7QutCwINC20LjQt9C90Lgg0YLQvtC60LXQvdCwINCyINC80L7QvNC10L3RgiDQstGL0LTQsNGH0LgsINCwINC90LVcbiAgICog0L7RgiDQvtGB0YLQsNGC0LrQsDog0LXRgdC70Lgg0YHRgtGA0LDQvdC40YbQsCDQvtGC0LrRgNGL0YLQsCDQtNCw0LLQvdC+LCDQt9C90LDRh9C10L3QuNC1INCx0YPQtNC10YIg0LfQsNCy0YvRiNC10L3QviAo0YLQsNC6XG4gICAqINC20LUg0Lgg0YMgQlgyNC5qcykuINCU0LvRjyDRgdCy0LXQttC10LPQviDRgtC+0LrQtdC90LAg0LjRgdC/0L7Qu9GM0LfRg9C50YLQtSBgcmVmcmVzaEF1dGgoKWAuXG4gICAqL1xuICBhc3luYyBnZXRBdXRoKCk6IFByb21pc2U8aUJYUmVzdEZyYW1lQXV0aD4ge1xuICAgIGNvbnN0IGRhdGEgPSBhd2FpdCB0aGlzLmdldEluaXREYXRhKClcbiAgICByZXR1cm4gdGhpcy50b0F1dGgoJ2dldEluaXREYXRhJywgZGF0YSwgU3RyaW5nKGRhdGFbJ01FTUJFUl9JRCddIHx8ICcnKSlcbiAgfVxuXG4gIC8qKlxuICAgKiDQndC+0LLQsNGPINCw0LLRgtC+0YDQuNC30LDRhtC40Y8g0L/RgNC40LvQvtC20LXQvdC40Y8g4oCUINCw0L3QsNC70L7QsyBgQlgyNC5yZWZyZXNoQXV0aCgpYDog0L/QvtGA0YLQsNC7XG4gICAqINCy0YvQv9GD0YHQutCw0LXRgiDQvdC+0LLRg9GOINC/0LDRgNGDIGBhY2Nlc3NfdG9rZW5gL2ByZWZyZXNoX3Rva2VuYC4g0JXRgdC70Lgg0L/QvtGA0YLQsNC7INC90LUg0LzQvtC20LXRglxuICAgKiDQstGL0LTQsNGC0Ywg0YLQvtC60LXQvSwg0L7QvSDQv9C+0LrQsNC30YvQstCw0LXRgiBgYWxlcnRgIMKrVW5hYmxlIHRvIGdldCBuZXcgdG9rZW4hwrsg0Lgg0L3QtVxuICAgKiDQvtGC0LLQtdGH0LDQtdGCIOKAlCDRgtC+0LPQtNCwINC+0YjQuNCx0LrQsCBgVElNRU9VVGAuXG4gICAqL1xuICBhc3luYyByZWZyZXNoQXV0aCgpOiBQcm9taXNlPGlCWFJlc3RGcmFtZUF1dGg+IHtcbiAgICAvLyBtZW1iZXJfaWQg0L/RgNC40YXQvtC00LjRgiDRgtC+0LvRjNC60L4g0LIgZ2V0SW5pdERhdGEg4oCUIHJlZnJlc2hBdXRoINC10LPQviDQvdC1INCy0L7Qt9Cy0YDQsNGJ0LDQtdGCXG4gICAgY29uc3QgeyBtZW1iZXJJZCB9ID0gYXdhaXQgdGhpcy5pbml0KClcbiAgICBjb25zdCBkYXRhID0gYXNPYmplY3QoJ3JlZnJlc2hBdXRoJywgYXdhaXQgdGhpcy50cmFuc3BvcnQucmVxdWVzdCgncmVmcmVzaEF1dGgnLCB7fSwgeyB0aW1lb3V0OiB0aGlzLnRpbWVvdXQgfSkpXG4gICAgcmV0dXJuIHRoaXMudG9BdXRoKCdyZWZyZXNoQXV0aCcsIGRhdGEsIG1lbWJlcklkKVxuICB9XG5cbiAgLyoqXG4gICAqINCX0LDQstC10YDRiNC40YLRjCDRg9GB0YLQsNC90L7QstC60YMg4oCUINCw0L3QsNC70L7QsyBgQlgyNC5pbnN0YWxsRmluaXNoKClgOiDQv9C+0YDRgtCw0Lsg0L7RgtC80LXRh9Cw0LXRglxuICAgKiDQv9GA0LjQu9C+0LbQtdC90LjQtSDRg9GB0YLQsNC90L7QstC70LXQvdC90YvQvCDQuCDQv9C10YDQtdC30LDQs9GA0YPQttCw0LXRgiDRgdGC0YDQsNC90LjRhtGDLiDQlNC10LvQsNC10YIg0YfRgtC+LdGC0L4g0YLQvtC70YzQutC+XG4gICAqINC90LAg0YHRgtGA0LDQvdC40YbQtSDRg9GB0YLQsNC90L7QstGJ0LjQutCwIChgaW5pdCgpLmluc3RhbGxgKSwg0LjQvdCw0YfQtSDigJQg0L3QuNGH0LXQs9C+LCDQutCw0Log0LggQlgyNC5qcy5cbiAgICovXG4gIGFzeW5jIGluc3RhbGxGaW5pc2goKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKChhd2FpdCB0aGlzLmluaXQoKSkuaW5zdGFsbCkge1xuICAgICAgdGhpcy50cmFuc3BvcnQucG9zdCgnc2V0SW5zdGFsbEZpbmlzaCcsIHt9KVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiDQntGC0LzQtdGC0LjRgtGMLCDRh9GC0L4g0L/QtdGA0LLRi9C5INC30LDQv9GD0YHQuiDRgyDRjdGC0L7Qs9C+INC/0L7Qu9GM0LfQvtCy0LDRgtC10LvRjyDQv9GA0L7QudC00LXQvSwg4oCUINGC0L4sINGH0YLQvlxuICAgKiBCWDI0LmpzINC00LXQu9Cw0LXRgiDQv9C+0YHQu9C1INC/0L7RgdC70LXQtNC90LXQs9C+INC+0LHRgNCw0LHQvtGC0YfQuNC60LAgYEJYMjQuaW5zdGFsbCgpYC4g0JHQtdC3INGN0YLQvtCz0L5cbiAgICogYGluaXQoKS5maXJzdFJ1bmAg0L7RgdGC0LDQvdC10YLRgdGPIGB0cnVlYCDQuCDQv9GA0Lgg0YHQu9C10LTRg9GO0YnQuNGFINC30LDQv9GD0YHQutCw0YUuINCU0LXQu9Cw0LXRglxuICAgKiDRh9GC0L4t0YLQviDRgtC+0LvRjNC60L4g0L/RgNC4INC/0LXRgNCy0L7QvCDQt9Cw0L/Rg9GB0LrQtS5cbiAgICovXG4gIGFzeW5jIGZpcnN0UnVuRmluaXNoKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IGluaXQgPSBhd2FpdCB0aGlzLmluaXQoKVxuICAgIGlmIChpbml0LmZpcnN0UnVuKSB7XG4gICAgICBhd2FpdCB0aGlzLmFjaygnc2V0SW5zdGFsbCcsIHsgaW5zdGFsbDogdHJ1ZSB9KVxuICAgICAgaW5pdC5maXJzdFJ1biA9IGZhbHNlXG4gICAgfVxuICB9XG5cbiAgLyoqINCX0LDQtNCw0YLRjCDRgNCw0LfQvNC10YAg0YTRgNC10LnQvNCwIOKAlCBgQlgyNC5yZXNpemVXaW5kb3coKWAuINCS0L7Qt9Cy0YDQsNGJ0LDQtdGCINGA0LDQt9C80LXRgCwg0LrQvtGC0L7RgNGL0Lkg0LLRi9GB0YLQsNCy0LjQuyDQv9C+0YDRgtCw0LsuICovXG4gIGFzeW5jIHJlc2l6ZVdpbmRvdyh3aWR0aDogbnVtYmVyIHwgc3RyaW5nLCBoZWlnaHQ6IG51bWJlciB8IHN0cmluZyk6IFByb21pc2U8aUJYUmVzdEZyYW1lU2l6ZSB8IHVuZGVmaW5lZD4ge1xuICAgIGNvbnN0IHcgPSBOdW1iZXIucGFyc2VJbnQoU3RyaW5nKHdpZHRoKSwgMTApXG4gICAgY29uc3QgaCA9IE51bWJlci5wYXJzZUludChTdHJpbmcoaGVpZ2h0KSwgMTApXG4gICAgaWYgKCEodyA+IDAgJiYgaCA+IDApKSB7XG4gICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdyZXNpemVXaW5kb3c6IHdpZHRoIGFuZCBoZWlnaHQgbXVzdCBiZSBwb3NpdGl2ZSBudW1iZXJzLicpXG4gICAgfVxuICAgIHJldHVybiBhd2FpdCB0aGlzLmFjaygncmVzaXplV2luZG93JywgeyB3aWR0aDogdywgaGVpZ2h0OiBoIH0pIGFzIGlCWFJlc3RGcmFtZVNpemUgfCB1bmRlZmluZWRcbiAgfVxuXG4gIC8qKiDQn9C+0LTQvtCz0L3QsNGC0Ywg0LLRi9GB0L7RgtGDINGE0YDQtdC50LzQsCDQv9C+0LQg0YHQvtC00LXRgNC20LjQvNC+0LUg4oCUIGBCWDI0LmZpdFdpbmRvdygpYC4gKi9cbiAgYXN5bmMgZml0V2luZG93KCk6IFByb21pc2U8aUJYUmVzdEZyYW1lU2l6ZSB8IHVuZGVmaW5lZD4ge1xuICAgIGNvbnN0IHJvb3QgPSBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnRcbiAgICBjb25zdCBoZWlnaHQgPSBNYXRoLm1heChyb290LnNjcm9sbEhlaWdodCwgcm9vdC5vZmZzZXRIZWlnaHQpXG4gICAgcmV0dXJuIGF3YWl0IHRoaXMuYWNrKCdyZXNpemVXaW5kb3cnLCB7IHdpZHRoOiAnMTAwJScsIGhlaWdodCB9KSBhcyBpQlhSZXN0RnJhbWVTaXplIHwgdW5kZWZpbmVkXG4gIH1cblxuICAvKipcbiAgICog0J/QtdGA0LXQt9Cw0LPRgNGD0LfQuNGC0Ywg0YHRgtGA0LDQvdC40YbRgyDQv9C+0YDRgtCw0LvQsCDRgSDQv9GA0LjQu9C+0LbQtdC90LjQtdC8IOKAlCBgQlgyNC5yZWxvYWRXaW5kb3coKWAuXG4gICAqINCf0L7RgNGC0LDQuyDQvdCwINGN0YLRgyDQutC+0LzQsNC90LTRgyDQvdC1INC+0YLQstC10YfQsNC10YIuXG4gICAqL1xuICBhc3luYyByZWxvYWRXaW5kb3coKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdGhpcy50cmFuc3BvcnQucG9zdCgncmVsb2FkV2luZG93Jywge30pXG4gIH1cblxuICAvKiog0JfQsNCz0L7Qu9C+0LLQvtC6INGB0YLRgNCw0L3QuNGG0Ysg0L/QvtGA0YLQsNC70LAg4oCUIGBCWDI0LnNldFRpdGxlKClgLiAqL1xuICBhc3luYyBzZXRUaXRsZSh0aXRsZTogc3RyaW5nKTogUHJvbWlzZTx7IHRpdGxlOiBzdHJpbmcgfSB8IHVuZGVmaW5lZD4ge1xuICAgIHJldHVybiBhd2FpdCB0aGlzLmFjaygnc2V0VGl0bGUnLCB7IHRpdGxlOiBTdHJpbmcodGl0bGUpIH0pIGFzIHsgdGl0bGU6IHN0cmluZyB9IHwgdW5kZWZpbmVkXG4gIH1cblxuICAvKiog0J/RgNC+0LrRgNGD0YLQuNGC0Ywg0YHRgtGA0LDQvdC40YbRgyDQv9C+0YDRgtCw0LvQsCDigJQgYEJYMjQuc2Nyb2xsUGFyZW50V2luZG93KClgLiAqL1xuICBhc3luYyBzY3JvbGxQYXJlbnRXaW5kb3coc2Nyb2xsOiBudW1iZXIgfCBzdHJpbmcpOiBQcm9taXNlPHsgc2Nyb2xsOiBudW1iZXIgfSB8IHVuZGVmaW5lZD4ge1xuICAgIGNvbnN0IHZhbHVlID0gTnVtYmVyLnBhcnNlSW50KFN0cmluZyhzY3JvbGwpLCAxMClcbiAgICBpZiAoTnVtYmVyLmlzTmFOKHZhbHVlKSkge1xuICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcignc2Nyb2xsUGFyZW50V2luZG93OiBzY3JvbGwgbXVzdCBiZSBhIG51bWJlci4nKVxuICAgIH1cbiAgICByZXR1cm4gYXdhaXQgdGhpcy5hY2soJ3NldFNjcm9sbCcsIHsgc2Nyb2xsOiB2YWx1ZSB9KSBhcyB7IHNjcm9sbDogbnVtYmVyIH0gfCB1bmRlZmluZWRcbiAgfVxuXG4gIC8qKlxuICAgKiDQlNC40LDQu9C+0LMg0LLRi9Cx0L7RgNCwINC+0LTQvdC+0LPQviDRgdC+0YLRgNGD0LTQvdC40LrQsCDigJQgYEJYMjQuc2VsZWN0VXNlcigpYC4g0JbQtNGR0YIg0LLRi9Cx0L7RgNCwINCx0LXQt1xuICAgKiDQvtCz0YDQsNC90LjRh9C10L3QuNGPINC/0L4g0LLRgNC10LzQtdC90Lg6INC10YHQu9C4INC/0L7Qu9GM0LfQvtCy0LDRgtC10LvRjCDQt9Cw0LrRgNGL0Lsg0LTQuNCw0LvQvtCzLCDQv9C+0YDRgtCw0Lsg0L3QtVxuICAgKiDQvtGC0LLQtdGH0LDQtdGCINCy0L7QstGB0LUuINCe0YLQvNC10L3QuNGC0Ywg0L7QttC40LTQsNC90LjQtSDigJQgYHNpZ25hbGAg0LjQu9C4INC90L7QstGL0Lkg0LLRi9C30L7QslxuICAgKiBgc2VsZWN0VXNlcigpYC9gc2VsZWN0VXNlcnMoKWAgKNC+0YjQuNCx0LrQsCBgQ0FOQ0VMTEVEYCkuXG4gICAqL1xuICBzZWxlY3RVc2VyKG9wdGlvbnM6IHsgdGl0bGU/OiBzdHJpbmcsIHNpZ25hbD86IEFib3J0U2lnbmFsIH0gPSB7fSk6IFByb21pc2U8aUJYUmVzdEZyYW1lVXNlcj4ge1xuICAgIHJldHVybiB0aGlzLmRpYWxvZygndXNlcicsICdzZWxlY3RVc2VyJywgeyB0aXRsZTogb3B0aW9ucy50aXRsZSA/PyAnJywgbXVsdDogZmFsc2UgfSwgb3B0aW9ucy5zaWduYWwpIGFzIFByb21pc2U8aUJYUmVzdEZyYW1lVXNlcj5cbiAgfVxuXG4gIC8qKiDQlNC40LDQu9C+0LMg0LLRi9Cx0L7RgNCwINC90LXRgdC60L7Qu9GM0LrQuNGFINGB0L7RgtGA0YPQtNC90LjQutC+0LIg4oCUIGBCWDI0LnNlbGVjdFVzZXJzKClgLiDQntC20LjQtNCw0L3QuNC1IOKAlCDQutCw0Log0YMgYHNlbGVjdFVzZXIoKWAuICovXG4gIHNlbGVjdFVzZXJzKG9wdGlvbnM6IHsgdGl0bGU/OiBzdHJpbmcsIHNpZ25hbD86IEFib3J0U2lnbmFsIH0gPSB7fSk6IFByb21pc2U8aUJYUmVzdEZyYW1lVXNlcltdPiB7XG4gICAgcmV0dXJuIHRoaXMuZGlhbG9nKCd1c2VyJywgJ3NlbGVjdFVzZXInLCB7IHRpdGxlOiBvcHRpb25zLnRpdGxlID8/ICcnLCBtdWx0OiB0cnVlIH0sIG9wdGlvbnMuc2lnbmFsKSBhcyBQcm9taXNlPGlCWFJlc3RGcmFtZVVzZXJbXT5cbiAgfVxuXG4gIC8qKlxuICAgKiDQlNC40LDQu9C+0LMg0LLRi9Cx0L7RgNCwINC/0YDQsNCyINC00L7RgdGC0YPQv9CwIOKAlCBgQlgyNC5zZWxlY3RBY2Nlc3MoKWAuIGB2YWx1ZWAg4oCUINC60L7QtNGLLFxuICAgKiDQutC+0YLQvtGA0YvQtSDQvdC10LvRjNC30Y8g0LLRi9Cx0YDQsNGC0YwuINCe0LbQuNC00LDQvdC40LUg4oCUINC60LDQuiDRgyBgc2VsZWN0VXNlcigpYC5cbiAgICovXG4gIHNlbGVjdEFjY2VzcyhvcHRpb25zOiB7IHZhbHVlPzogc3RyaW5nW10sIHNpZ25hbD86IEFib3J0U2lnbmFsIH0gPSB7fSk6IFByb21pc2U8aUJYUmVzdEZyYW1lQWNjZXNzW10+IHtcbiAgICByZXR1cm4gdGhpcy5kaWFsb2coJ2FjY2VzcycsICdzZWxlY3RBY2Nlc3MnLCB7IHZhbHVlOiBvcHRpb25zLnZhbHVlID8/IFtdIH0sIG9wdGlvbnMuc2lnbmFsKSBhcyBQcm9taXNlPGlCWFJlc3RGcmFtZUFjY2Vzc1tdPlxuICB9XG5cbiAgLyoqINCU0LjQsNC70L7QsyDQstGL0LHQvtGA0LAg0L7QsdGK0LXQutGC0L7QsiBDUk0g4oCUIGBCWDI0LnNlbGVjdENSTSgpYC4g0J7QttC40LTQsNC90LjQtSDigJQg0LrQsNC6INGDIGBzZWxlY3RVc2VyKClgLiAqL1xuICBzZWxlY3RDUk0ob3B0aW9uczogaUJYUmVzdEZyYW1lQ3JtU2VsZWN0T3B0aW9ucyA9IHt9KTogUHJvbWlzZTxpQlhSZXN0RnJhbWVDcm1TZWxlY3Rpb24+IHtcbiAgICBjb25zdCB7IGVudGl0eVR5cGUsIG11bHRpcGxlLCB2YWx1ZSwgc2lnbmFsIH0gPSBvcHRpb25zXG4gICAgcmV0dXJuIHRoaXMuZGlhbG9nKCdjcm0nLCAnc2VsZWN0Q1JNJywgeyBlbnRpdHlUeXBlLCBtdWx0aXBsZSwgdmFsdWUgfSwgc2lnbmFsKSBhcyBQcm9taXNlPGlCWFJlc3RGcmFtZUNybVNlbGVjdGlvbj5cbiAgfVxuXG4gIC8qKlxuICAgKiDQntGC0LrRgNGL0YLRjCDQv9GA0LjQu9C+0LbQtdC90LjQtSDQsiDRgdC70LDQudC00LXRgNC1IOKAlCBgQlgyNC5vcGVuQXBwbGljYXRpb24oKWAuINCf0YDQvtC80LjRgVxuICAgKiDQt9Cw0LLQtdGA0YjQsNC10YLRgdGPLCDQutC+0LPQtNCwINGB0LvQsNC50LTQtdGAINC30LDQutGA0YvQu9C4LiBgc2V0dGluZ3NgIOKAlCDQvdCw0YHRgtGA0L7QudC60Lgg0YHQu9Cw0LnQtNC10YDQsFxuICAgKiAo0YPRhdC+0LTRj9GCINC60LDQuiBgYngyNF880LrQu9GO0Yc+YCwg0LrQsNC6INCyIEJYMjQuanMpLlxuICAgKi9cbiAgYXN5bmMgb3BlbkFwcGxpY2F0aW9uKFxuICAgIHBhcmFtczogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPSB7fSxcbiAgICBzZXR0aW5nczogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPSB7fSxcbiAgICBvcHRpb25zOiB7IHNpZ25hbD86IEFib3J0U2lnbmFsIH0gPSB7fVxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBtZXNzYWdlOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IHsgLi4ucGFyYW1zIH1cbiAgICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhzZXR0aW5ncykpIHtcbiAgICAgIG1lc3NhZ2VbYGJ4MjRfJHtrZXl9YF0gPSB2YWx1ZVxuICAgIH1cbiAgICBhd2FpdCB0aGlzLnRyYW5zcG9ydC5yZXF1ZXN0KCdvcGVuQXBwbGljYXRpb24nLCBtZXNzYWdlLCB7IHRpbWVvdXQ6IGZhbHNlLCBzaWduYWw6IG9wdGlvbnMuc2lnbmFsIH0pXG4gIH1cblxuICAvKipcbiAgICog0J7RgtC60YDRi9GC0Ywg0YHRgtGA0LDQvdC40YbRgyDQv9C+0YDRgtCw0LvQsCDQsiDRgdC70LDQudC00LXRgNC1IOKAlCBgQlgyNC5vcGVuUGF0aCgpYC4g0J/RgNC+0LzQuNGBXG4gICAqINC30LDQstC10YDRiNCw0LXRgtGB0Y8sINC60L7Qs9C00LAg0YHQu9Cw0LnQtNC10YAg0LfQsNC60YDRi9C70LggKGB7IHJlc3VsdDogJ2Nsb3NlJyB9YCksINC40LvQuCDRgdGA0LDQt9GDLFxuICAgKiDQtdGB0LvQuCDQv9GD0YLRjCDQvdC1INC+0YLQutGA0YvQu9GB0Y8gKGB7IHJlc3VsdDogJ2Vycm9yJywgZXJyb3JDb2RlIH1gKS5cbiAgICovXG4gIGFzeW5jIG9wZW5QYXRoKHBhdGg6IHN0cmluZywgb3B0aW9uczogeyBzaWduYWw/OiBBYm9ydFNpZ25hbCB9ID0ge30pOiBQcm9taXNlPGlCWFJlc3RGcmFtZU9wZW5QYXRoUmVzdWx0PiB7XG4gICAgcmV0dXJuIGF3YWl0IHRoaXMudHJhbnNwb3J0LnJlcXVlc3QoJ29wZW5QYXRoJywgeyBwYXRoIH0sIHsgdGltZW91dDogZmFsc2UsIHNpZ25hbDogb3B0aW9ucy5zaWduYWwgfSkgYXMgaUJYUmVzdEZyYW1lT3BlblBhdGhSZXN1bHRcbiAgfVxuXG4gIC8qKlxuICAgKiDQl9Cw0LrRgNGL0YLRjCDRgdC70LDQudC00LXRgCDRgSDQv9GA0LjQu9C+0LbQtdC90LjQtdC8IOKAlCBgQlgyNC5jbG9zZUFwcGxpY2F0aW9uKClgLiDQldGB0LvQuFxuICAgKiDQv9GA0LjQu9C+0LbQtdC90LjQtSDQvtGC0LrRgNGL0YLQviDQvdC1INCyINGB0LvQsNC50LTQtdGA0LUsINC90LjRh9C10LPQviDQvdC1INC/0YDQvtC40YHRhdC+0LTQuNGCLiDQo9C30L3QsNGC0Ywg0L5cbiAgICog0LfQsNC60YDRi9GC0LjQuCDQvNC+0LbQtdGCINC+0YLQutGA0YvQstGI0LjQuSDRgdC70LDQudC00LXRgCDigJQg0YfQtdGA0LXQtyBgb3BlbkFwcGxpY2F0aW9uKClgLlxuICAgKi9cbiAgYXN5bmMgY2xvc2VBcHBsaWNhdGlvbigpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0aGlzLnRyYW5zcG9ydC5wb3N0KCdjbG9zZUFwcGxpY2F0aW9uJywgbnVsbClcbiAgfVxuXG4gIC8qKlxuICAgKiDQmtC+0LzQsNC90LTQsCwg0L3QsCDQutC+0YLQvtGA0YPRjiDQv9C+0YDRgtCw0Lsg0L7RgtCy0LXRh9Cw0LXRgiDQv9C+0LTRgtCy0LXRgNC20LTQtdC90LjQtdC8LiDQkiDQvdC10LrQvtGC0L7RgNGL0YVcbiAgICog0LLRgdGC0YDQsNC40LLQsNC90LjRj9GFINC/0L7RgNGC0LDQuyDQvdCwINGC0LDQutC40LUg0LrQvtC80LDQvdC00Ysg0L3QtSDQvtGC0LLQtdGH0LDQtdGCICjRgtCw0Log0YHRh9C40YLQsNC10YIg0LhcbiAgICogYjI0anNzZGspIOKAlCDRgtC+0LPQtNCwINC/0YDQvtC80LjRgSDQt9Cw0LLQtdGA0YjQsNC10YLRgdGPINGBIGB1bmRlZmluZWRgLCDQsCDQvdC1INC+0YjQuNCx0LrQvtC5LlxuICAgKi9cbiAgcHJpdmF0ZSBhY2soY29tbWFuZDogc3RyaW5nLCBwYXJhbXM6IHVua25vd24pOiBQcm9taXNlPHVua25vd24+IHtcbiAgICByZXR1cm4gdGhpcy50cmFuc3BvcnQucmVxdWVzdChjb21tYW5kLCBwYXJhbXMsIHsgdGltZW91dDogdGhpcy50aW1lb3V0LCBvblRpbWVvdXQ6ICdyZXNvbHZlJyB9KVxuICB9XG5cbiAgLyoqXG4gICAqINCU0LjQsNC70L7Qs9C4INC20LTRg9GCINC/0L7Qu9GM0LfQvtCy0LDRgtC10LvRjyDQsdC10Lcg0YLQsNC50LzQsNGD0YLQsC4g0J/QvtGA0YLQsNC7INC00LXRgNC20LjRgiDQvtC00LjQvSDQvtCx0YDQsNCx0L7RgtGH0LjQulxuICAgKiDQvdCwINC00LjQsNC70L7QsyAo0YMg0LLRi9Cx0L7RgNCwINGB0L7RgtGA0YPQtNC90LjQutC+0LIg0L7QvSDQvtCx0YnQuNC5INC00LvRjyBgc2VsZWN0VXNlcmAg0LhcbiAgICogYHNlbGVjdFVzZXJzYCkg0Lgg0L3QsCDQv9GA0L7RiNC70YvQuSDQstGL0LfQvtCyINGD0LbQtSDQvdC1INC+0YLQstC10YLQuNGCIOKAlCDQv9C+0Y3RgtC+0LzRgyDQvdC+0LLRi9C5INCy0YvQt9C+0LJcbiAgICog0L7RgtC80LXQvdGP0LXRgiDQvtC20LjQtNCw0L3QuNC1INC/0YDQvtGI0LvQvtCz0L4uXG4gICAqL1xuICBwcml2YXRlIGRpYWxvZyhraW5kOiAndXNlcicgfCAnYWNjZXNzJyB8ICdjcm0nLCBjb21tYW5kOiBzdHJpbmcsIHBhcmFtczogdW5rbm93biwgc2lnbmFsPzogQWJvcnRTaWduYWwpOiBQcm9taXNlPHVua25vd24+IHtcbiAgICB0aGlzLmRpYWxvZ3MuZ2V0KGtpbmQpPy5hYm9ydCgpXG4gICAgY29uc3QgY29udHJvbGxlciA9IG5ldyBBYm9ydENvbnRyb2xsZXIoKVxuICAgIHRoaXMuZGlhbG9ncy5zZXQoa2luZCwgY29udHJvbGxlcilcblxuICAgIGNvbnN0IG9uQWJvcnQgPSAoKSA9PiBjb250cm9sbGVyLmFib3J0KClcbiAgICBpZiAoc2lnbmFsPy5hYm9ydGVkKSB7XG4gICAgICBjb250cm9sbGVyLmFib3J0KClcbiAgICB9XG4gICAgc2lnbmFsPy5hZGRFdmVudExpc3RlbmVyKCdhYm9ydCcsIG9uQWJvcnQsIHsgb25jZTogdHJ1ZSB9KVxuXG4gICAgcmV0dXJuIHRoaXMudHJhbnNwb3J0LnJlcXVlc3QoY29tbWFuZCwgcGFyYW1zLCB7IHRpbWVvdXQ6IGZhbHNlLCBzaWduYWw6IGNvbnRyb2xsZXIuc2lnbmFsIH0pXG4gICAgICAuZmluYWxseSgoKSA9PiB7XG4gICAgICAgIHNpZ25hbD8ucmVtb3ZlRXZlbnRMaXN0ZW5lcignYWJvcnQnLCBvbkFib3J0KVxuICAgICAgICBpZiAodGhpcy5kaWFsb2dzLmdldChraW5kKSA9PT0gY29udHJvbGxlcikge1xuICAgICAgICAgIHRoaXMuZGlhbG9ncy5kZWxldGUoa2luZClcbiAgICAgICAgfVxuICAgICAgfSlcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgZ2V0SW5pdERhdGEoKTogUHJvbWlzZTxSZWNvcmQ8c3RyaW5nLCB1bmtub3duPj4ge1xuICAgIGNvbnN0IGRhdGEgPSBhc09iamVjdCgnZ2V0SW5pdERhdGEnLCBhd2FpdCB0aGlzLnRyYW5zcG9ydC5yZXF1ZXN0KCdnZXRJbml0RGF0YScsIG51bGwsIHsgdGltZW91dDogdGhpcy50aW1lb3V0IH0pKVxuICAgIC8vIGZpcnN0UnVuINC/0L7RgNGC0LDQuyDQvtGC0LTQsNGR0YIg0YLQvtC70YzQutC+INCyINC/0LXRgNCy0L7QvCDQvtGC0LLQtdGC0LUg0LfQsCDQt9Cw0LPRgNGD0LfQutGDINGB0YLRgNCw0L3QuNGG0Ysg4oCUXG4gICAgLy8g0L/QvtGN0YLQvtC80YMg0LfQsNC/0L7QvNC40L3QsNC10Lwg0LTQsNC90L3Ri9C1INC/0LXRgNCy0L7Qs9C+INC+0YLQstC10YLQsCwg0LrRgtC+INCx0Ysg0LXQs9C+INC90Lgg0LfQsNC/0YDQvtGB0LjQu1xuICAgIGlmICghdGhpcy5pbml0VmFsdWUpIHtcbiAgICAgIHRoaXMuaW5pdFZhbHVlID0gdGhpcy50b0luaXQoZGF0YSlcbiAgICB9XG4gICAgcmV0dXJuIGRhdGFcbiAgfVxuXG4gIHByaXZhdGUgdG9Jbml0KGRhdGE6IFJlY29yZDxzdHJpbmcsIHVua25vd24+KTogaUJYUmVzdEZyYW1lSW5pdCB7XG4gICAgcmV0dXJuIHtcbiAgICAgIC8vINCa0LDQuiBCWDI0LmpzOiDQtNC+0LzQtdC9IOKAlCDQuNC3INC/0LDRgNCw0LzQtdGC0YDQvtCyINGE0YDQtdC50LzQsCwgRE9NQUlOINC+0YLQstC10YLQsCDigJQg0LfQsNC/0LDRgdC90L7QuVxuICAgICAgZG9tYWluOiB0aGlzLnRyYW5zcG9ydC5kb21haW4gfHwgU3RyaW5nKGRhdGFbJ0RPTUFJTiddIHx8ICcnKSxcbiAgICAgIGxhbmc6IFN0cmluZyhkYXRhWydMQU5HJ10gfHwgJycpLFxuICAgICAgcGF0aDogU3RyaW5nKGRhdGFbJ1BBVEgnXSB8fCAnJyksXG4gICAgICBodHRwczogTnVtYmVyLnBhcnNlSW50KFN0cmluZyhkYXRhWydQUk9UT0NPTCddKSwgMTApID09PSAxLFxuICAgICAgbWVtYmVySWQ6IFN0cmluZyhkYXRhWydNRU1CRVJfSUQnXSB8fCAnJyksXG4gICAgICBpc0FkbWluOiAhIWRhdGFbJ0lTX0FETUlOJ10sXG4gICAgICBpbnN0YWxsOiAhIWRhdGFbJ0lOU1RBTEwnXSxcbiAgICAgIGZpcnN0UnVuOiAhIWRhdGFbJ0ZJUlNUX1JVTiddLFxuICAgICAgcGxhY2VtZW50OiBTdHJpbmcoZGF0YVsnUExBQ0VNRU5UJ10gfHwgJ0RFRkFVTFQnKSxcbiAgICAgIHBsYWNlbWVudE9wdGlvbnM6IGRhdGFbJ1BMQUNFTUVOVF9PUFRJT05TJ10sXG4gICAgICB1c2VyT3B0aW9uczogdG9SZWNvcmQoZGF0YVsnVVNFUl9PUFRJT05TJ10pLFxuICAgICAgYXBwT3B0aW9uczogdG9SZWNvcmQoZGF0YVsnQVBQX09QVElPTlMnXSksXG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSB0b0F1dGgoY29tbWFuZDogc3RyaW5nLCBkYXRhOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiwgbWVtYmVySWQ6IHN0cmluZyk6IGlCWFJlc3RGcmFtZUF1dGgge1xuICAgIGNvbnN0IHsgQVVUSF9JRCwgUkVGUkVTSF9JRCwgQVVUSF9FWFBJUkVTIH0gPSBkYXRhXG4gICAgaWYgKCFBVVRIX0lEIHx8IHR5cGVvZiBBVVRIX0lEICE9PSAnc3RyaW5nJykge1xuICAgICAgdGhyb3cgbmV3IEJYUmVzdEZyYW1lRXJyb3IoJ05PX0FVVEgnLCBgQml0cml4MjQgYW5zd2VyZWQgJHtjb21tYW5kfSB3aXRob3V0IGFuIGFjY2VzcyB0b2tlbi5gKVxuICAgIH1cbiAgICAvLyBBVVRIX0VYUElSRVMg4oCUINGB0YDQvtC6INC20LjQt9C90Lgg0YLQvtC60LXQvdCwINCyINGB0LXQutGD0L3QtNCw0YUuIEJYMjQuanMg0L/QtdGA0LXQstC+0LTQuNGCINC10LPQviDQslxuICAgIC8vINC80L7QvNC10L3RgiDQuNGB0YLQtdGH0LXQvdC40Y8g0LIg0LzQuNC70LvQuNGB0LXQutGD0L3QtNCw0YUg4oCUINGC0LDQuiDQttC1LCDQutCw0Log0LfQtNC10YHRjC5cbiAgICBjb25zdCBleHBpcmVzSW4gPSBOdW1iZXIucGFyc2VJbnQoU3RyaW5nKEFVVEhfRVhQSVJFUyksIDEwKVxuICAgIGlmICghTnVtYmVyLmlzRmluaXRlKGV4cGlyZXNJbikgfHwgZXhwaXJlc0luIDw9IDApIHtcbiAgICAgIHRocm93IG5ldyBCWFJlc3RGcmFtZUVycm9yKCdCQURfUkVTUE9OU0UnLCBgQml0cml4MjQgYW5zd2VyZWQgJHtjb21tYW5kfSB3aXRob3V0IGEgdXNhYmxlIEFVVEhfRVhQSVJFUy5gKVxuICAgIH1cbiAgICByZXR1cm4ge1xuICAgICAgYWNjZXNzX3Rva2VuOiBBVVRIX0lELFxuICAgICAgcmVmcmVzaF90b2tlbjogdHlwZW9mIFJFRlJFU0hfSUQgPT09ICdzdHJpbmcnID8gUkVGUkVTSF9JRCA6ICcnLFxuICAgICAgZXhwaXJlc19pbjogRGF0ZS5ub3coKSArIGV4cGlyZXNJbiAqIDEwMDAsXG4gICAgICBkb21haW46IHRoaXMudHJhbnNwb3J0LmRvbWFpbixcbiAgICAgIG1lbWJlcl9pZDogbWVtYmVySWQsXG4gICAgfVxuICB9XG59XG5cbmZ1bmN0aW9uIGFzT2JqZWN0KGNvbW1hbmQ6IHN0cmluZywgZGF0YTogdW5rbm93bik6IFJlY29yZDxzdHJpbmcsIHVua25vd24+IHtcbiAgaWYgKCFkYXRhIHx8IHR5cGVvZiBkYXRhICE9PSAnb2JqZWN0JyB8fCBBcnJheS5pc0FycmF5KGRhdGEpKSB7XG4gICAgdGhyb3cgbmV3IEJYUmVzdEZyYW1lRXJyb3IoJ0JBRF9SRVNQT05TRScsIGBCaXRyaXgyNCBhbnN3ZXJlZCAke2NvbW1hbmR9IHdpdGggYSBwYXlsb2FkIHRoYXQgaXMgbm90IGFuIG9iamVjdC5gKVxuICB9XG4gIHJldHVybiBkYXRhIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+XG59XG5cbi8vINCf0YPRgdGC0YvQtSDQvdCw0YHRgtGA0L7QudC60LggUEhQINC+0YLQtNCw0ZHRgiDQvNCw0YHRgdC40LLQvtC8IGBbXWBcbmZ1bmN0aW9uIHRvUmVjb3JkKHZhbHVlOiB1bmtub3duKTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4ge1xuICByZXR1cm4gKHZhbHVlICYmIHR5cGVvZiB2YWx1ZSA9PT0gJ29iamVjdCcgJiYgIUFycmF5LmlzQXJyYXkodmFsdWUpKVxuICAgID8geyAuLi52YWx1ZSBhcyBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB9XG4gICAgOiB7fVxufVxuIl19
|