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.
@@ -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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZnJhbWUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9ieC1yZXN0L3NyYy9zZXJ2aWNlcy9mcmFtZS9mcmFtZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsY0FBYyxFQUFFLE1BQU0sYUFBYSxDQUFBO0FBTzlELE1BQU0sZUFBZSxHQUFHLEtBQUssQ0FBQTtBQUU3Qjs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FpQkc7QUFDSCxNQUFNLE9BQU8sV0FBVztJQTJGdEIsWUFBWSxVQUE4QixFQUFFO1FBekYzQixjQUFTLEdBQUcsSUFBSSxjQUFjLEVBQUUsQ0FBQTtRQUlqRCw4RUFBOEU7UUFDN0QsWUFBTyxHQUFHLElBQUksR0FBRyxFQUE4QyxDQUFBO1FBRWhGLHFFQUFxRTtRQUM1RCxPQUFFLEdBQUc7WUFDWixpREFBaUQ7WUFDakQsTUFBTSxFQUFFLEtBQUssRUFBRSxNQUF1QixFQUFFLEtBQWUsRUFBaUIsRUFBRTtnQkFDeEUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUE7WUFDcEQsQ0FBQztZQUNELGtEQUFrRDtZQUNsRCxPQUFPLEVBQUUsS0FBSyxFQUFFLEtBQWEsRUFBaUIsRUFBRTtnQkFDOUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQTtZQUM3QyxDQUFDO1lBQ0QsK0NBQStDO1lBQy9DLGFBQWEsRUFBRSxLQUFLLEVBQUUsUUFBMEIsRUFBaUIsRUFBRTtnQkFDakUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsaUJBQWlCLEVBQUUsRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFBO1lBQ3RELENBQUM7WUFDRCxzREFBc0Q7WUFDdEQsV0FBVyxFQUFFLEtBQUssRUFBRSxRQUF5QixFQUFpQixFQUFFO2dCQUM5RCxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxlQUFlLEVBQUUsRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFBO1lBQ3BELENBQUM7U0FDRixDQUFBO1FBRUQsMENBQTBDO1FBQ2pDLGNBQVMsR0FBRztZQUNuQiw2REFBNkQ7WUFDN0QsSUFBSSxFQUFFLEtBQUssSUFBd0MsRUFBRTtnQkFDbkQsTUFBTSxFQUFFLFNBQVMsRUFBRSxnQkFBZ0IsRUFBRSxHQUFHLE1BQU0sSUFBSSxDQUFDLElBQUksRUFBRSxDQUFBO2dCQUN6RCxPQUFPLEVBQUUsU0FBUyxFQUFFLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxDQUFBO1lBQ2pELENBQUM7WUFDRCxnRkFBZ0Y7WUFDaEYsWUFBWSxFQUFFLEtBQUssSUFBNkMsRUFBRTtnQkFDaEUsT0FBTyxNQUFNLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLGNBQWMsRUFBRSxJQUFJLEVBQUUsRUFBRSxPQUFPLEVBQUUsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFtQyxDQUFBO1lBQ3hILENBQUM7WUFDRDs7OztlQUlHO1lBQ0gsSUFBSSxFQUFFLEtBQUssRUFBRSxPQUFlLEVBQUUsTUFBZ0IsRUFBRSxVQUF3QyxFQUFFLEVBQW9CLEVBQUU7Z0JBQzlHLE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRTtvQkFDN0MsT0FBTyxFQUFFLE9BQU8sQ0FBQyxPQUFPLElBQUksSUFBSSxDQUFDLE9BQU87b0JBQ3hDLFNBQVMsRUFBRSxTQUFTO2lCQUNyQixDQUFDLENBQUE7WUFDSixDQUFDO1lBQ0Q7Ozs7OztlQU1HO1lBQ0gsU0FBUyxFQUFFLENBQUMsS0FBYSxFQUFFLE9BQWdDLEVBQWMsRUFBRTtnQkFDekUsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDLFNBQVMsQ0FBQyxvQkFBb0IsRUFBRSxFQUFFLEtBQUssRUFBRSxFQUFFLE9BQU8sQ0FBQyxDQUFBO1lBQzNFLENBQUM7U0FDRixDQUFBO1FBRUQsOEVBQThFO1FBQ3JFLGVBQVUsR0FBRztZQUNwQixHQUFHLEVBQUUsS0FBSyxFQUFFLElBQVksRUFBb0IsRUFBRSxDQUFDLENBQUMsTUFBTSxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDO1lBQ3BGLEdBQUcsRUFBRSxLQUFLLEVBQUUsSUFBWSxFQUFFLEtBQWMsRUFBaUIsRUFBRTtnQkFDekQsTUFBTSxJQUFJLEdBQUcsTUFBTSxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUE7Z0JBQzlCLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLEdBQUcsS0FBSyxDQUFBO2dCQUM5QixNQUFNLElBQUksQ0FBQyxHQUFHLENBQUMsZUFBZSxFQUFFLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUE7WUFDbEQsQ0FBQztTQUNGLENBQUE7UUFFRCxxRUFBcUU7UUFDNUQsY0FBUyxHQUFHO1lBQ25CLEdBQUcsRUFBRSxLQUFLLEVBQUUsSUFBWSxFQUFvQixFQUFFLENBQUMsQ0FBQyxNQUFNLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUM7WUFDbkY7Ozs7ZUFJRztZQUNILEdBQUcsRUFBRSxLQUFLLEVBQUUsSUFBWSxFQUFFLEtBQWMsRUFBb0MsRUFBRTtnQkFDNUUsTUFBTSxJQUFJLEdBQUcsTUFBTSxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUE7Z0JBQzlCLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7b0JBQ2xCLE1BQU0sSUFBSSxnQkFBZ0IsQ0FBQyxlQUFlLEVBQUUsK0RBQStELENBQUMsQ0FBQTtnQkFDOUcsQ0FBQztnQkFDRCxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxHQUFHLEtBQUssQ0FBQTtnQkFDN0IsT0FBTyxNQUFNLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLGNBQWMsRUFBRSxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsRUFBRSxFQUFFLE9BQU8sRUFBRSxJQUFJLENBQUMsT0FBTyxFQUFFLENBQTRCLENBQUE7WUFDNUgsQ0FBQztTQUNGLENBQUE7UUFHQyxJQUFJLENBQUMsT0FBTyxHQUFHLE9BQU8sQ0FBQyxPQUFPLElBQUksZUFBZSxDQUFBO0lBQ25ELENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsSUFBSTtRQUNGLElBQUksSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO1lBQ25CLE9BQU8sT0FBTyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUE7UUFDeEMsQ0FBQztRQUNELElBQUksQ0FBQyxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7WUFDdEIsSUFBSSxDQUFDLFdBQVcsR0FBRyxJQUFJLENBQUMsV0FBVyxFQUFFO2lCQUNsQyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLFNBQTZCLENBQUM7aUJBQzlDLE9BQU8sQ0FBQyxHQUFHLEVBQUU7Z0JBQ1osSUFBSSxDQUFDLFdBQVcsR0FBRyxTQUFTLENBQUE7WUFDOUIsQ0FBQyxDQUFDLENBQUE7UUFDTixDQUFDO1FBQ0QsT0FBTyxJQUFJLENBQUMsV0FBVyxDQUFBO0lBQ3pCLENBQUM7SUFFRDs7Ozs7OztPQU9HO0lBQ0gsS0FBSyxDQUFDLE9BQU87UUFDWCxNQUFNLElBQUksR0FBRyxNQUFNLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQTtRQUNyQyxPQUFPLElBQUksQ0FBQyxNQUFNLENBQUMsYUFBYSxFQUFFLElBQUksRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUE7SUFDMUUsQ0FBQztJQUVEOzs7OztPQUtHO0lBQ0gsS0FBSyxDQUFDLFdBQVc7UUFDZiwwRUFBMEU7UUFDMUUsTUFBTSxFQUFFLFFBQVEsRUFBRSxHQUFHLE1BQU0sSUFBSSxDQUFDLElBQUksRUFBRSxDQUFBO1FBQ3RDLE1BQU0sSUFBSSxHQUFHLFFBQVEsQ0FBQyxhQUFhLEVBQUUsTUFBTSxJQUFJLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxhQUFhLEVBQUUsRUFBRSxFQUFFLEVBQUUsT0FBTyxFQUFFLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDLENBQUE7UUFDaEgsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDLGFBQWEsRUFBRSxJQUFJLEVBQUUsUUFBUSxDQUFDLENBQUE7SUFDbkQsQ0FBQztJQUVEOzs7O09BSUc7SUFDSCxLQUFLLENBQUMsYUFBYTtRQUNqQixJQUFJLENBQUMsTUFBTSxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUNoQyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxFQUFFLENBQUMsQ0FBQTtRQUM3QyxDQUFDO0lBQ0gsQ0FBQztJQUVEOzs7OztPQUtHO0lBQ0gsS0FBSyxDQUFDLGNBQWM7UUFDbEIsTUFBTSxJQUFJLEdBQUcsTUFBTSxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUE7UUFDOUIsSUFBSSxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDbEIsTUFBTSxJQUFJLENBQUMsR0FBRyxDQUFDLFlBQVksRUFBRSxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFBO1lBQy9DLElBQUksQ0FBQyxRQUFRLEdBQUcsS0FBSyxDQUFBO1FBQ3ZCLENBQUM7SUFDSCxDQUFDO0lBRUQsZ0dBQWdHO0lBQ2hHLEtBQUssQ0FBQyxZQUFZLENBQUMsS0FBc0IsRUFBRSxNQUF1QjtRQUNoRSxNQUFNLENBQUMsR0FBRyxNQUFNLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQTtRQUM1QyxNQUFNLENBQUMsR0FBRyxNQUFNLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQTtRQUM3QyxJQUFJLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDO1lBQ3RCLE1BQU0sSUFBSSxTQUFTLENBQUMsMERBQTBELENBQUMsQ0FBQTtRQUNqRixDQUFDO1FBQ0QsT0FBTyxNQUFNLElBQUksQ0FBQyxHQUFHLENBQUMsY0FBYyxFQUFFLEVBQUUsS0FBSyxFQUFFLENBQUMsRUFBRSxNQUFNLEVBQUUsQ0FBQyxFQUFFLENBQWlDLENBQUE7SUFDaEcsQ0FBQztJQUVELG1FQUFtRTtJQUNuRSxLQUFLLENBQUMsU0FBUztRQUNiLE1BQU0sSUFBSSxHQUFHLFFBQVEsQ0FBQyxlQUFlLENBQUE7UUFDckMsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsWUFBWSxFQUFFLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQTtRQUM3RCxPQUFPLE1BQU0sSUFBSSxDQUFDLEdBQUcsQ0FBQyxjQUFjLEVBQUUsRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxDQUFpQyxDQUFBO0lBQ2xHLENBQUM7SUFFRDs7O09BR0c7SUFDSCxLQUFLLENBQUMsWUFBWTtRQUNoQixJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxjQUFjLEVBQUUsRUFBRSxDQUFDLENBQUE7SUFDekMsQ0FBQztJQUVELHNEQUFzRDtJQUN0RCxLQUFLLENBQUMsUUFBUSxDQUFDLEtBQWE7UUFDMUIsT0FBTyxNQUFNLElBQUksQ0FBQyxHQUFHLENBQUMsVUFBVSxFQUFFLEVBQUUsS0FBSyxFQUFFLE1BQU0sQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFrQyxDQUFBO0lBQzlGLENBQUM7SUFFRCxpRUFBaUU7SUFDakUsS0FBSyxDQUFDLGtCQUFrQixDQUFDLE1BQXVCO1FBQzlDLE1BQU0sS0FBSyxHQUFHLE1BQU0sQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFBO1FBQ2pELElBQUksTUFBTSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQ3hCLE1BQU0sSUFBSSxTQUFTLENBQUMsOENBQThDLENBQUMsQ0FBQTtRQUNyRSxDQUFDO1FBQ0QsT0FBTyxNQUFNLElBQUksQ0FBQyxHQUFHLENBQUMsV0FBVyxFQUFFLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRSxDQUFtQyxDQUFBO0lBQ3pGLENBQUM7SUFFRDs7Ozs7T0FLRztJQUNILFVBQVUsQ0FBQyxVQUFvRCxFQUFFO1FBQy9ELE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEVBQUUsWUFBWSxFQUFFLEVBQUUsS0FBSyxFQUFFLE9BQU8sQ0FBQyxLQUFLLElBQUksRUFBRSxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsRUFBRSxPQUFPLENBQUMsTUFBTSxDQUE4QixDQUFBO0lBQ3BJLENBQUM7SUFFRCxvR0FBb0c7SUFDcEcsV0FBVyxDQUFDLFVBQW9ELEVBQUU7UUFDaEUsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sRUFBRSxZQUFZLEVBQUUsRUFBRSxLQUFLLEVBQUUsT0FBTyxDQUFDLEtBQUssSUFBSSxFQUFFLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxFQUFFLE9BQU8sQ0FBQyxNQUFNLENBQWdDLENBQUE7SUFDckksQ0FBQztJQUVEOzs7T0FHRztJQUNILFlBQVksQ0FBQyxVQUFzRCxFQUFFO1FBQ25FLE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRLEVBQUUsY0FBYyxFQUFFLEVBQUUsS0FBSyxFQUFFLE9BQU8sQ0FBQyxLQUFLLElBQUksRUFBRSxFQUFFLEVBQUUsT0FBTyxDQUFDLE1BQU0sQ0FBa0MsQ0FBQTtJQUMvSCxDQUFDO0lBRUQsd0ZBQXdGO0lBQ3hGLFNBQVMsQ0FBQyxVQUF3QyxFQUFFO1FBQ2xELE1BQU0sRUFBRSxVQUFVLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsR0FBRyxPQUFPLENBQUE7UUFDdkQsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRSxXQUFXLEVBQUUsRUFBRSxVQUFVLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxFQUFFLE1BQU0sQ0FBc0MsQ0FBQTtJQUN0SCxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILEtBQUssQ0FBQyxlQUFlLENBQ25CLFNBQWtDLEVBQUUsRUFDcEMsV0FBb0MsRUFBRSxFQUN0QyxVQUFvQyxFQUFFO1FBRXRDLE1BQU0sT0FBTyxHQUE0QixFQUFFLEdBQUcsTUFBTSxFQUFFLENBQUE7UUFDdEQsS0FBSyxNQUFNLENBQUMsR0FBRyxFQUFFLEtBQUssQ0FBQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQztZQUNwRCxPQUFPLENBQUMsUUFBUSxHQUFHLEVBQUUsQ0FBQyxHQUFHLEtBQUssQ0FBQTtRQUNoQyxDQUFDO1FBQ0QsTUFBTSxJQUFJLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxpQkFBaUIsRUFBRSxPQUFPLEVBQUUsRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxPQUFPLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQTtJQUN0RyxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILEtBQUssQ0FBQyxRQUFRLENBQUMsSUFBWSxFQUFFLFVBQW9DLEVBQUU7UUFDakUsT0FBTyxNQUFNLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLFVBQVUsRUFBRSxFQUFFLElBQUksRUFBRSxFQUFFLEVBQUUsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsT0FBTyxDQUFDLE1BQU0sRUFBRSxDQUErQixDQUFBO0lBQ3JJLENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsS0FBSyxDQUFDLGdCQUFnQjtRQUNwQixJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxJQUFJLENBQUMsQ0FBQTtJQUMvQyxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNLLEdBQUcsQ0FBQyxPQUFlLEVBQUUsTUFBZTtRQUMxQyxPQUFPLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsRUFBRSxPQUFPLEVBQUUsSUFBSSxDQUFDLE9BQU8sRUFBRSxTQUFTLEVBQUUsU0FBUyxFQUFFLENBQUMsQ0FBQTtJQUNqRyxDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSyxNQUFNLENBQUMsSUFBK0IsRUFBRSxPQUFlLEVBQUUsTUFBZSxFQUFFLE1BQW9CO1FBQ3BHLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFLEtBQUssRUFBRSxDQUFBO1FBQy9CLE1BQU0sVUFBVSxHQUFHLElBQUksZUFBZSxFQUFFLENBQUE7UUFDeEMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLFVBQVUsQ0FBQyxDQUFBO1FBRWxDLE1BQU0sT0FBTyxHQUFHLEdBQUcsRUFBRSxDQUFDLFVBQVUsQ0FBQyxLQUFLLEVBQUUsQ0FBQTtRQUN4QyxJQUFJLE1BQU0sRUFBRSxPQUFPLEVBQUUsQ0FBQztZQUNwQixVQUFVLENBQUMsS0FBSyxFQUFFLENBQUE7UUFDcEIsQ0FBQztRQUNELE1BQU0sRUFBRSxnQkFBZ0IsQ0FBQyxPQUFPLEVBQUUsT0FBTyxFQUFFLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxDQUFDLENBQUE7UUFFMUQsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxPQUFPLEVBQUUsTUFBTSxFQUFFLEVBQUUsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsVUFBVSxDQUFDLE1BQU0sRUFBRSxDQUFDO2FBQzFGLE9BQU8sQ0FBQyxHQUFHLEVBQUU7WUFDWixNQUFNLEVBQUUsbUJBQW1CLENBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxDQUFBO1lBQzdDLElBQUksSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEtBQUssVUFBVSxFQUFFLENBQUM7Z0JBQzFDLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFBO1lBQzNCLENBQUM7UUFDSCxDQUFDLENBQUMsQ0FBQTtJQUNOLENBQUM7SUFFTyxLQUFLLENBQUMsV0FBVztRQUN2QixNQUFNLElBQUksR0FBRyxRQUFRLENBQUMsYUFBYSxFQUFFLE1BQU0sSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsYUFBYSxFQUFFLElBQUksRUFBRSxFQUFFLE9BQU8sRUFBRSxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQyxDQUFBO1FBQ2xILHVFQUF1RTtRQUN2RSxtRUFBbUU7UUFDbkUsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztZQUNwQixJQUFJLENBQUMsU0FBUyxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUE7UUFDcEMsQ0FBQztRQUNELE9BQU8sSUFBSSxDQUFBO0lBQ2IsQ0FBQztJQUVPLE1BQU0sQ0FBQyxJQUE2QjtRQUMxQyxPQUFPO1lBQ0wsc0VBQXNFO1lBQ3RFLE1BQU0sRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLE1BQU0sSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUM3RCxJQUFJLEVBQUUsTUFBTSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDaEMsSUFBSSxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksRUFBRSxDQUFDO1lBQ2hDLEtBQUssRUFBRSxNQUFNLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDO1lBQzFELFFBQVEsRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUN6QyxPQUFPLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUM7WUFDM0IsT0FBTyxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDO1lBQzFCLFFBQVEsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQztZQUM3QixTQUFTLEVBQUUsTUFBTSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxTQUFTLENBQUM7WUFDakQsZ0JBQWdCLEVBQUUsSUFBSSxDQUFDLG1CQUFtQixDQUFDO1lBQzNDLFdBQVcsRUFBRSxRQUFRLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxDQUFDO1lBQzNDLFVBQVUsRUFBRSxRQUFRLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDO1NBQzFDLENBQUE7SUFDSCxDQUFDO0lBRU8sTUFBTSxDQUFDLE9BQWUsRUFBRSxJQUE2QixFQUFFLFFBQWdCO1FBQzdFLE1BQU0sRUFBRSxPQUFPLEVBQUUsVUFBVSxFQUFFLFlBQVksRUFBRSxHQUFHLElBQUksQ0FBQTtRQUNsRCxJQUFJLENBQUMsT0FBTyxJQUFJLE9BQU8sT0FBTyxLQUFLLFFBQVEsRUFBRSxDQUFDO1lBQzVDLE1BQU0sSUFBSSxnQkFBZ0IsQ0FBQyxTQUFTLEVBQUUscUJBQXFCLE9BQU8sMkJBQTJCLENBQUMsQ0FBQTtRQUNoRyxDQUFDO1FBQ0QsdUVBQXVFO1FBQ3ZFLHdEQUF3RDtRQUN4RCxNQUFNLFNBQVMsR0FBRyxNQUFNLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxZQUFZLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQTtRQUMzRCxJQUFJLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxTQUFTLENBQUMsSUFBSSxTQUFTLElBQUksQ0FBQyxFQUFFLENBQUM7WUFDbEQsTUFBTSxJQUFJLGdCQUFnQixDQUFDLGNBQWMsRUFBRSxxQkFBcUIsT0FBTyxpQ0FBaUMsQ0FBQyxDQUFBO1FBQzNHLENBQUM7UUFDRCxPQUFPO1lBQ0wsWUFBWSxFQUFFLE9BQU87WUFDckIsYUFBYSxFQUFFLE9BQU8sVUFBVSxLQUFLLFFBQVEsQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxFQUFFO1lBQy9ELFVBQVUsRUFBRSxJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsU0FBUyxHQUFHLElBQUk7WUFDekMsTUFBTSxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsTUFBTTtZQUM3QixTQUFTLEVBQUUsUUFBUTtTQUNwQixDQUFBO0lBQ0gsQ0FBQztDQUNGO0FBRUQsU0FBUyxRQUFRLENBQUMsT0FBZSxFQUFFLElBQWE7SUFDOUMsSUFBSSxDQUFDLElBQUksSUFBSSxPQUFPLElBQUksS0FBSyxRQUFRLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO1FBQzdELE1BQU0sSUFBSSxnQkFBZ0IsQ0FBQyxjQUFjLEVBQUUscUJBQXFCLE9BQU8sd0NBQXdDLENBQUMsQ0FBQTtJQUNsSCxDQUFDO0lBQ0QsT0FBTyxJQUErQixDQUFBO0FBQ3hDLENBQUM7QUFFRCw0Q0FBNEM7QUFDNUMsU0FBUyxRQUFRLENBQUMsS0FBYztJQUM5QixPQUFPLENBQUMsS0FBSyxJQUFJLE9BQU8sS0FBSyxLQUFLLFFBQVEsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDbEUsQ0FBQyxDQUFDLEVBQUUsR0FBRyxLQUFnQyxFQUFFO1FBQ3pDLENBQUMsQ0FBQyxFQUFFLENBQUE7QUFDUixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQlhSZXN0RnJhbWVFcnJvciwgRnJhbWVUcmFuc3BvcnQgfSBmcm9tICcuL3RyYW5zcG9ydCdcbmltcG9ydCB7XG4gIEJYUmVzdEZyYW1lT3B0aW9ucywgaUJYUmVzdEZyYW1lQWNjZXNzLCBpQlhSZXN0RnJhbWVBdXRoLCBpQlhSZXN0RnJhbWVDcm1TZWxlY3Rpb24sIGlCWFJlc3RGcmFtZUNybVNlbGVjdE9wdGlvbnMsXG4gIGlCWFJlc3RGcmFtZUluaXQsIGlCWFJlc3RGcmFtZU9wZW5QYXRoUmVzdWx0LCBpQlhSZXN0RnJhbWVQbGFjZW1lbnRJbmZvLCBpQlhSZXN0RnJhbWVQbGFjZW1lbnRJbnRlcmZhY2UsXG4gIGlCWFJlc3RGcmFtZVNpemUsIGlCWFJlc3RGcmFtZVVzZXIsXG59IGZyb20gJy4vdHlwZXMnXG5cbmNvbnN0IERFRkFVTFRfVElNRU9VVCA9IDEwMDAwXG5cbi8qKlxuICog0JrQvtC80LDQvdC00Ysg0L/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