@okeyamy/lua 5.0.4
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/README.md +552 -0
- package/build/es5/__tests__/ai-personalize.test.js +811 -0
- package/build/es5/__tests__/lua.js +134 -0
- package/build/es5/__tests__/original-roughly.js +197 -0
- package/build/es5/__tests__/original.js +174 -0
- package/build/es5/__tests__/unit.js +72 -0
- package/build/es5/__tests__/weighted-history.test.js +376 -0
- package/build/es5/ai-personalize.js +641 -0
- package/build/es5/index.js +30 -0
- package/build/es5/lua.js +366 -0
- package/build/es5/personalization.js +811 -0
- package/build/es5/prompts/personalization-prompts.js +260 -0
- package/build/es5/storage/weighted-history.js +384 -0
- package/build/es5/stores/browser-cookie.js +25 -0
- package/build/es5/stores/local.js +29 -0
- package/build/es5/stores/memory.js +22 -0
- package/build/es5/utils.js +54 -0
- package/build/es5/utm-personalize.js +817 -0
- package/build/es5/utm.js +304 -0
- package/build/lua.dev.js +1574 -0
- package/build/lua.es.js +1566 -0
- package/build/lua.js +1574 -0
- package/build/lua.min.js +8 -0
- package/package.json +68 -0
|
@@ -0,0 +1,811 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
|
|
5
|
+
/**
|
|
6
|
+
* DOM Personalization Engine
|
|
7
|
+
* Handles content injection with data-personalize attributes
|
|
8
|
+
* Uses textContent for text, DOMPurify-style sanitized HTML for rich content
|
|
9
|
+
*
|
|
10
|
+
* No ES6 imports - self-contained IIFE that registers on window.LuaPersonalize
|
|
11
|
+
* Depends on window.LuaUTM (from utm.js) for context extraction
|
|
12
|
+
* Falls back to random A/B test when no UTM params are present
|
|
13
|
+
*/
|
|
14
|
+
;
|
|
15
|
+
(function (root) {
|
|
16
|
+
'use strict';
|
|
17
|
+
|
|
18
|
+
// ===================================================================
|
|
19
|
+
// DOMPurify-style HTML Sanitizer (inline, OWASP-recommended approach)
|
|
20
|
+
// Provides safe HTML injection without external dependencies
|
|
21
|
+
// ===================================================================
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Inline DOMPurify-style sanitizer
|
|
25
|
+
* Uses the browser's DOMParser to safely parse and sanitize HTML
|
|
26
|
+
* Falls back to regex-based sanitization if DOMParser unavailable
|
|
27
|
+
*/
|
|
28
|
+
var Sanitizer = function () {
|
|
29
|
+
// Allowed HTML tags (safe for content injection)
|
|
30
|
+
var ALLOWED_TAGS = {
|
|
31
|
+
'p': true,
|
|
32
|
+
'span': true,
|
|
33
|
+
'strong': true,
|
|
34
|
+
'em': true,
|
|
35
|
+
'b': true,
|
|
36
|
+
'i': true,
|
|
37
|
+
'br': true,
|
|
38
|
+
'a': true,
|
|
39
|
+
'img': true,
|
|
40
|
+
'h1': true,
|
|
41
|
+
'h2': true,
|
|
42
|
+
'h3': true,
|
|
43
|
+
'h4': true,
|
|
44
|
+
'h5': true,
|
|
45
|
+
'h6': true,
|
|
46
|
+
'div': true,
|
|
47
|
+
'section': true,
|
|
48
|
+
'ul': true,
|
|
49
|
+
'ol': true,
|
|
50
|
+
'li': true,
|
|
51
|
+
'blockquote': true,
|
|
52
|
+
'figure': true,
|
|
53
|
+
'figcaption': true
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// Allowed HTML attributes (safe subset)
|
|
57
|
+
var ALLOWED_ATTRS = {
|
|
58
|
+
'href': true,
|
|
59
|
+
'src': true,
|
|
60
|
+
'alt': true,
|
|
61
|
+
'class': true,
|
|
62
|
+
'id': true,
|
|
63
|
+
'title': true,
|
|
64
|
+
'target': true,
|
|
65
|
+
'rel': true,
|
|
66
|
+
'width': true,
|
|
67
|
+
'height': true,
|
|
68
|
+
'loading': true
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// Dangerous URI schemes
|
|
72
|
+
var DANGEROUS_URI = /^(javascript|vbscript|data):/i;
|
|
73
|
+
|
|
74
|
+
// Event handler pattern (onclick, onerror, onload, etc.)
|
|
75
|
+
var EVENT_HANDLER = /^on/i;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Check if DOMParser is available (modern browsers)
|
|
79
|
+
* @returns {boolean}
|
|
80
|
+
*/
|
|
81
|
+
function hasDOMParser() {
|
|
82
|
+
try {
|
|
83
|
+
return typeof DOMParser !== 'undefined' && new DOMParser();
|
|
84
|
+
} catch (e) {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Sanitize HTML using DOMParser (preferred, secure method)
|
|
91
|
+
* Parses HTML into a DOM tree, walks nodes, and rebuilds safe HTML
|
|
92
|
+
* @param {string} dirty - Untrusted HTML string
|
|
93
|
+
* @returns {string} - Sanitized HTML string
|
|
94
|
+
*/
|
|
95
|
+
function sanitizeWithDOMParser(dirty) {
|
|
96
|
+
if (typeof dirty !== 'string' || !dirty.trim()) return '';
|
|
97
|
+
try {
|
|
98
|
+
var parser = new DOMParser();
|
|
99
|
+
var doc = parser.parseFromString(dirty, 'text/html');
|
|
100
|
+
var body = doc.body;
|
|
101
|
+
if (!body) return '';
|
|
102
|
+
return walkAndClean(body);
|
|
103
|
+
} catch (e) {
|
|
104
|
+
console.warn('[Lua Sanitizer] DOMParser failed, using fallback:', e);
|
|
105
|
+
return sanitizeWithRegex(dirty);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Recursively walk DOM nodes and build clean HTML
|
|
111
|
+
* @param {Node} node - DOM node to process
|
|
112
|
+
* @returns {string} - Cleaned HTML string
|
|
113
|
+
*/
|
|
114
|
+
function walkAndClean(node) {
|
|
115
|
+
var output = '';
|
|
116
|
+
for (var i = 0; i < node.childNodes.length; i++) {
|
|
117
|
+
var child = node.childNodes[i];
|
|
118
|
+
|
|
119
|
+
// Text node - safe to include
|
|
120
|
+
if (child.nodeType === 3) {
|
|
121
|
+
output += escapeText(child.textContent);
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Element node
|
|
126
|
+
if (child.nodeType === 1) {
|
|
127
|
+
var tagName = child.tagName.toLowerCase();
|
|
128
|
+
|
|
129
|
+
// Skip disallowed tags entirely (including children)
|
|
130
|
+
if (tagName === 'script' || tagName === 'style' || tagName === 'iframe' || tagName === 'object' || tagName === 'embed' || tagName === 'form' || tagName === 'input' || tagName === 'textarea') {
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// If tag is allowed, include it with filtered attributes
|
|
135
|
+
if (ALLOWED_TAGS[tagName]) {
|
|
136
|
+
output += '<' + tagName;
|
|
137
|
+
output += cleanAttributes(child);
|
|
138
|
+
output += '>';
|
|
139
|
+
|
|
140
|
+
// Self-closing tags
|
|
141
|
+
if (tagName === 'br' || tagName === 'img') {
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Recurse into children
|
|
146
|
+
output += walkAndClean(child);
|
|
147
|
+
output += '</' + tagName + '>';
|
|
148
|
+
} else {
|
|
149
|
+
// Tag not allowed - include children only (strip the tag)
|
|
150
|
+
output += walkAndClean(child);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return output;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Filter element attributes to only allowed ones
|
|
159
|
+
* @param {Element} element - DOM element
|
|
160
|
+
* @returns {string} - Attribute string
|
|
161
|
+
*/
|
|
162
|
+
function cleanAttributes(element) {
|
|
163
|
+
var attrStr = '';
|
|
164
|
+
var attrs = element.attributes;
|
|
165
|
+
for (var i = 0; i < attrs.length; i++) {
|
|
166
|
+
var attr = attrs[i];
|
|
167
|
+
var name = attr.name.toLowerCase();
|
|
168
|
+
var value = attr.value;
|
|
169
|
+
|
|
170
|
+
// Skip event handlers (onclick, onerror, etc.)
|
|
171
|
+
if (EVENT_HANDLER.test(name)) continue;
|
|
172
|
+
|
|
173
|
+
// Skip disallowed attributes
|
|
174
|
+
if (!ALLOWED_ATTRS[name]) continue;
|
|
175
|
+
|
|
176
|
+
// Check URI safety for href/src
|
|
177
|
+
if ((name === 'href' || name === 'src') && DANGEROUS_URI.test(value.trim())) {
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Add rel="noopener noreferrer" for external links
|
|
182
|
+
if (name === 'target' && value === '_blank') {
|
|
183
|
+
attrStr += ' target="_blank" rel="noopener noreferrer"';
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
attrStr += ' ' + name + '="' + escapeAttr(value) + '"';
|
|
187
|
+
}
|
|
188
|
+
return attrStr;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Escape text content for safe HTML inclusion
|
|
193
|
+
* @param {string} text - Raw text
|
|
194
|
+
* @returns {string} - Escaped text
|
|
195
|
+
*/
|
|
196
|
+
function escapeText(text) {
|
|
197
|
+
if (!text) return '';
|
|
198
|
+
return text.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Escape attribute value for safe HTML inclusion
|
|
203
|
+
* @param {string} value - Raw attribute value
|
|
204
|
+
* @returns {string} - Escaped attribute value
|
|
205
|
+
*/
|
|
206
|
+
function escapeAttr(value) {
|
|
207
|
+
if (!value) return '';
|
|
208
|
+
return value.replace(/&/g, '&').replace(/"/g, '"').replace(/'/g, ''').replace(/</g, '<').replace(/>/g, '>');
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Fallback regex-based sanitizer for environments without DOMParser
|
|
213
|
+
* @param {string} html - Raw HTML string
|
|
214
|
+
* @returns {string} - Sanitized HTML
|
|
215
|
+
*/
|
|
216
|
+
function sanitizeWithRegex(html) {
|
|
217
|
+
if (typeof html !== 'string') return '';
|
|
218
|
+
var DANGEROUS_PATTERNS = [/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, /<iframe\b[^<]*(?:(?!<\/iframe>)<[^<]*)*<\/iframe>/gi, /<object\b[^<]*(?:(?!<\/object>)<[^<]*)*<\/object>/gi, /<embed\b[^>]*>/gi, /<link\b[^>]*>/gi, /<style\b[^<]*(?:(?!<\/style>)<[^<]*)*<\/style>/gi, /<form\b[^<]*(?:(?!<\/form>)<[^<]*)*<\/form>/gi, /javascript:/gi, /vbscript:/gi, /data:/gi, /on\w+\s*=/gi];
|
|
219
|
+
var sanitized = html;
|
|
220
|
+
DANGEROUS_PATTERNS.forEach(function (pattern) {
|
|
221
|
+
sanitized = sanitized.replace(pattern, '');
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
// Remove disallowed tags but keep their text content
|
|
225
|
+
sanitized = sanitized.replace(/<\/?(\w+)([^>]*)>/g, function (match, tagName, attrs) {
|
|
226
|
+
var tag = tagName.toLowerCase();
|
|
227
|
+
if (!ALLOWED_TAGS[tag]) return '';
|
|
228
|
+
|
|
229
|
+
// For closing tags, just return the closing tag
|
|
230
|
+
if (match.charAt(1) === '/') return '</' + tag + '>';
|
|
231
|
+
|
|
232
|
+
// Filter attributes
|
|
233
|
+
var cleanAttrs = '';
|
|
234
|
+
var attrRegex = /(\w+)=['"]([^'"]*)['"]/g;
|
|
235
|
+
var attrMatch;
|
|
236
|
+
while ((attrMatch = attrRegex.exec(attrs)) !== null) {
|
|
237
|
+
var attrName = attrMatch[1].toLowerCase();
|
|
238
|
+
if (ALLOWED_ATTRS[attrName] && !EVENT_HANDLER.test(attrName)) {
|
|
239
|
+
var val = attrMatch[2];
|
|
240
|
+
if ((attrName === 'href' || attrName === 'src') && DANGEROUS_URI.test(val)) {
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
cleanAttrs += ' ' + attrName + '="' + val + '"';
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
return '<' + tag + cleanAttrs + '>';
|
|
247
|
+
});
|
|
248
|
+
return sanitized;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Public sanitizer API
|
|
252
|
+
return {
|
|
253
|
+
/**
|
|
254
|
+
* Sanitize HTML string (main entry point)
|
|
255
|
+
* Uses DOMParser when available, regex fallback otherwise
|
|
256
|
+
* @param {string} dirty - Untrusted HTML
|
|
257
|
+
* @returns {string} - Sanitized HTML
|
|
258
|
+
*/
|
|
259
|
+
sanitize: function sanitize(dirty) {
|
|
260
|
+
if (typeof dirty !== 'string') return '';
|
|
261
|
+
if (!dirty.trim()) return '';
|
|
262
|
+
if (hasDOMParser()) {
|
|
263
|
+
return sanitizeWithDOMParser(dirty);
|
|
264
|
+
}
|
|
265
|
+
return sanitizeWithRegex(dirty);
|
|
266
|
+
},
|
|
267
|
+
escapeText: escapeText,
|
|
268
|
+
escapeAttr: escapeAttr
|
|
269
|
+
};
|
|
270
|
+
}();
|
|
271
|
+
|
|
272
|
+
// ===================================================================
|
|
273
|
+
// Templates & Assets
|
|
274
|
+
// ===================================================================
|
|
275
|
+
// NOTE: Templates are NOT provided by this package.
|
|
276
|
+
// Users must provide their own templates via options.templates
|
|
277
|
+
// This keeps the package modular and allows users full control
|
|
278
|
+
// over their content, assets, and personalization strategy.
|
|
279
|
+
|
|
280
|
+
// ===================================================================
|
|
281
|
+
// DOM Interaction (safe methods - never raw innerHTML)
|
|
282
|
+
// ===================================================================
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Safely set text content on an element (no HTML parsing)
|
|
286
|
+
* @param {Element} element - DOM element
|
|
287
|
+
* @param {string} text - Text to set
|
|
288
|
+
*/
|
|
289
|
+
function safeSetText(element, text) {
|
|
290
|
+
if (!element) return;
|
|
291
|
+
element.textContent = text;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Safely set HTML content on an element (DOMPurify-sanitized)
|
|
296
|
+
* @param {Element} element - DOM element
|
|
297
|
+
* @param {string} html - HTML to set (will be sanitized)
|
|
298
|
+
*/
|
|
299
|
+
function safeSetHTML(element, html) {
|
|
300
|
+
if (!element) return;
|
|
301
|
+
element.innerHTML = Sanitizer.sanitize(html);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Find all elements with data-personalize attribute
|
|
306
|
+
* @param {string} [key] - Optional specific key to find
|
|
307
|
+
* @param {Element} [searchRoot] - Root element to search from (default: document)
|
|
308
|
+
* @returns {NodeList|Array} - Matching elements
|
|
309
|
+
*/
|
|
310
|
+
function findPersonalizeElements(key, searchRoot) {
|
|
311
|
+
searchRoot = searchRoot || (typeof document !== 'undefined' ? document : null);
|
|
312
|
+
if (!searchRoot) return [];
|
|
313
|
+
var selector = key ? '[data-personalize="' + key + '"]' : '[data-personalize]';
|
|
314
|
+
return searchRoot.querySelectorAll(selector);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Get template for a given intent
|
|
319
|
+
* Templates must be provided by the user via options.templates
|
|
320
|
+
* Falls back to 'default' template if intent not found
|
|
321
|
+
* @param {string} intent - Intent key
|
|
322
|
+
* @param {Object} userTemplates - User-provided templates (required)
|
|
323
|
+
* @returns {Object|null} - Template data or null if no templates provided
|
|
324
|
+
*/
|
|
325
|
+
function getTemplate(intent, userTemplates) {
|
|
326
|
+
if (!userTemplates || (0, _typeof2.default)(userTemplates) !== 'object') {
|
|
327
|
+
console.warn('[Lua Personalize] No templates provided. Templates must be passed via options.templates');
|
|
328
|
+
return null;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Try to get the intent template
|
|
332
|
+
if (userTemplates[intent]) {
|
|
333
|
+
return userTemplates[intent];
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// Fall back to 'default' template if available
|
|
337
|
+
if (userTemplates['default']) {
|
|
338
|
+
return userTemplates['default'];
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// If no default, return the first available template
|
|
342
|
+
var firstKey = Object.keys(userTemplates)[0];
|
|
343
|
+
if (firstKey) {
|
|
344
|
+
console.warn('[Lua Personalize] Intent "' + intent + '" not found, using first available template:', firstKey);
|
|
345
|
+
return userTemplates[firstKey];
|
|
346
|
+
}
|
|
347
|
+
return null;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// ===================================================================
|
|
351
|
+
// Random A/B Fallback (used when no UTM params are present)
|
|
352
|
+
// ===================================================================
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Simple weighted random selection for A/B fallback
|
|
356
|
+
* @param {Array} names - Array of bucket/template names
|
|
357
|
+
* @param {Array} weights - Corresponding weights
|
|
358
|
+
* @returns {string} - Selected name
|
|
359
|
+
*/
|
|
360
|
+
function chooseWeightedRandom(names, weights) {
|
|
361
|
+
if (names.length !== weights.length) return names[0];
|
|
362
|
+
var sum = 0;
|
|
363
|
+
var i;
|
|
364
|
+
for (i = 0; i < weights.length; i++) {
|
|
365
|
+
sum += weights[i];
|
|
366
|
+
}
|
|
367
|
+
var n = Math.random() * sum;
|
|
368
|
+
var limit = 0;
|
|
369
|
+
for (i = 0; i < names.length; i++) {
|
|
370
|
+
limit += weights[i];
|
|
371
|
+
if (n <= limit) return names[i];
|
|
372
|
+
}
|
|
373
|
+
return names[names.length - 1];
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Get a random template key from user-provided templates
|
|
378
|
+
* Used as fallback when no UTM/referrer context is available
|
|
379
|
+
* @param {Object} userTemplates - User-provided templates (required)
|
|
380
|
+
* @returns {string|null} - Random template intent key or null if no templates
|
|
381
|
+
*/
|
|
382
|
+
function getRandomFallbackIntent(userTemplates) {
|
|
383
|
+
if (!userTemplates || (0, _typeof2.default)(userTemplates) !== 'object') {
|
|
384
|
+
return null;
|
|
385
|
+
}
|
|
386
|
+
var names = Object.keys(userTemplates);
|
|
387
|
+
if (names.length === 0) {
|
|
388
|
+
return null;
|
|
389
|
+
}
|
|
390
|
+
var weights = [];
|
|
391
|
+
for (var i = 0; i < names.length; i++) {
|
|
392
|
+
weights.push(1); // Equal weight by default
|
|
393
|
+
}
|
|
394
|
+
return chooseWeightedRandom(names, weights);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// ===================================================================
|
|
398
|
+
// Decision Engine
|
|
399
|
+
// ===================================================================
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* Personalization Decision Engine
|
|
403
|
+
* Determines which content to show based on context
|
|
404
|
+
* Priority: AI (if enabled) -> UTM params -> Referrer -> Random A/B fallback
|
|
405
|
+
*/
|
|
406
|
+
var DecisionEngine = {
|
|
407
|
+
/**
|
|
408
|
+
* Standard (non-AI) decision logic
|
|
409
|
+
* @param {Object} context - Context from LuaUTM.getContext()
|
|
410
|
+
* @param {Object} [options] - Configuration options
|
|
411
|
+
* @param {Object} [options.rules] - Custom matching rules
|
|
412
|
+
* @param {Object} options.templates - User-provided templates (REQUIRED)
|
|
413
|
+
* @param {boolean} [options.randomFallback] - Enable random A/B fallback (default: true)
|
|
414
|
+
* @returns {Object} - { template, intent, source }
|
|
415
|
+
*/
|
|
416
|
+
standardDecide: function standardDecide(context, options) {
|
|
417
|
+
options = options || {};
|
|
418
|
+
var customRules = options.rules || {};
|
|
419
|
+
var userTemplates = options.templates;
|
|
420
|
+
var enableRandomFallback = options.randomFallback !== false;
|
|
421
|
+
|
|
422
|
+
// Templates are required - warn if not provided
|
|
423
|
+
if (!userTemplates || (0, _typeof2.default)(userTemplates) !== 'object' || Object.keys(userTemplates).length === 0) {
|
|
424
|
+
console.warn('[Lua Personalize] No templates provided. Templates must be passed via options.templates');
|
|
425
|
+
return {
|
|
426
|
+
template: null,
|
|
427
|
+
intent: 'default',
|
|
428
|
+
source: 'error',
|
|
429
|
+
context: context,
|
|
430
|
+
error: 'No templates provided'
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
var intent = context.primaryIntent;
|
|
434
|
+
var source = 'default';
|
|
435
|
+
|
|
436
|
+
// Determine the source of the decision
|
|
437
|
+
if (context.hasUTM) {
|
|
438
|
+
source = 'utm';
|
|
439
|
+
} else if (context.referrer && context.referrer.category !== 'direct') {
|
|
440
|
+
source = 'referrer';
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// Check custom rules first (highest priority)
|
|
444
|
+
for (var ruleKey in customRules) {
|
|
445
|
+
var rule = customRules[ruleKey];
|
|
446
|
+
if (typeof rule.match === 'function' && rule.match(context)) {
|
|
447
|
+
intent = rule.intent || ruleKey;
|
|
448
|
+
source = 'custom-rule';
|
|
449
|
+
break;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// If intent is still 'default' and random fallback is enabled,
|
|
454
|
+
// pick a random template for A/B testing
|
|
455
|
+
if (intent === 'default' && source === 'default' && enableRandomFallback) {
|
|
456
|
+
var randomIntent = getRandomFallbackIntent(userTemplates);
|
|
457
|
+
if (randomIntent) {
|
|
458
|
+
intent = randomIntent;
|
|
459
|
+
source = 'random-ab';
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// Record visit to history if LuaWeightedHistory is available
|
|
464
|
+
if (root.LuaWeightedHistory && typeof root.LuaWeightedHistory.recordVisit === 'function') {
|
|
465
|
+
root.LuaWeightedHistory.recordVisit({
|
|
466
|
+
context: context,
|
|
467
|
+
intent: intent,
|
|
468
|
+
selectedVariant: intent,
|
|
469
|
+
source: source,
|
|
470
|
+
aiDecision: false
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
return {
|
|
474
|
+
template: getTemplate(intent, userTemplates),
|
|
475
|
+
intent: intent,
|
|
476
|
+
source: source,
|
|
477
|
+
context: context
|
|
478
|
+
};
|
|
479
|
+
},
|
|
480
|
+
/**
|
|
481
|
+
* Main decide function - routes to AI or standard engine
|
|
482
|
+
* @param {Object} context - Context from LuaUTM.getContext()
|
|
483
|
+
* @param {Object} [options] - Configuration options
|
|
484
|
+
* @param {boolean} [options.enableAI] - Enable AI-powered decisions
|
|
485
|
+
* @param {Object} [options.aiConfig] - AI configuration
|
|
486
|
+
* @returns {Object|Promise<Object>} - Decision result (Promise if AI enabled)
|
|
487
|
+
*/
|
|
488
|
+
decide: function decide(context, options) {
|
|
489
|
+
options = options || {};
|
|
490
|
+
|
|
491
|
+
// If AI is enabled and configured, try AI decision first
|
|
492
|
+
if (options.enableAI && options.aiConfig && root.LuaAIPersonalize) {
|
|
493
|
+
var self = this;
|
|
494
|
+
var aiModule = root.LuaAIPersonalize;
|
|
495
|
+
var readiness = aiModule.isReady(options.aiConfig);
|
|
496
|
+
if (readiness.ready) {
|
|
497
|
+
return aiModule.decide(context, options).catch(function (error) {
|
|
498
|
+
// AI failed - fall back to standard engine
|
|
499
|
+
var fallback = options.aiConfig.fallbackToStandard !== false;
|
|
500
|
+
if (fallback) {
|
|
501
|
+
console.warn('[Lua Personalize] AI failed, using standard engine:', error.message);
|
|
502
|
+
return self.standardDecide(context, options);
|
|
503
|
+
}
|
|
504
|
+
throw error;
|
|
505
|
+
});
|
|
506
|
+
} else {
|
|
507
|
+
console.warn('[Lua Personalize] AI not ready:', readiness.error, '- using standard engine');
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// Standard decision (synchronous)
|
|
512
|
+
return this.standardDecide(context, options);
|
|
513
|
+
}
|
|
514
|
+
};
|
|
515
|
+
|
|
516
|
+
// ===================================================================
|
|
517
|
+
// Personalization Application
|
|
518
|
+
// ===================================================================
|
|
519
|
+
|
|
520
|
+
// ===================================================================
|
|
521
|
+
// DOM Application (extracted for reuse by both sync and async paths)
|
|
522
|
+
// ===================================================================
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* Apply a decision to the DOM
|
|
526
|
+
* Injects content into elements with data-personalize attributes
|
|
527
|
+
*
|
|
528
|
+
* @param {Object} decision - Decision object { template, intent, source, context }
|
|
529
|
+
* @param {Object} [options] - Configuration options
|
|
530
|
+
* @param {boolean} [options.log] - Enable console logging
|
|
531
|
+
* @returns {Object} - The decision (pass-through)
|
|
532
|
+
*/
|
|
533
|
+
function applyDecisionToDOM(decision, options) {
|
|
534
|
+
options = options || {};
|
|
535
|
+
var template = decision.template;
|
|
536
|
+
var context = decision.context || {};
|
|
537
|
+
var log = options.log !== false;
|
|
538
|
+
if (!template) {
|
|
539
|
+
console.warn('[Lua Personalize] No template in decision, skipping DOM update');
|
|
540
|
+
return decision;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
// Find and update each personalize slot in the DOM
|
|
544
|
+
var slots = ['image', 'headline', 'subheadline', 'ctaLabel', 'ctaLink'];
|
|
545
|
+
slots.forEach(function (slot) {
|
|
546
|
+
var elements = findPersonalizeElements(slot);
|
|
547
|
+
for (var i = 0; i < elements.length; i++) {
|
|
548
|
+
var element = elements[i];
|
|
549
|
+
var value = template[slot];
|
|
550
|
+
if (!value) continue;
|
|
551
|
+
if (slot === 'image') {
|
|
552
|
+
// For images, set background-image or src attribute
|
|
553
|
+
if (element.tagName === 'IMG') {
|
|
554
|
+
element.src = value;
|
|
555
|
+
element.alt = template.headline || 'Personalized image';
|
|
556
|
+
} else {
|
|
557
|
+
element.style.backgroundImage = 'url(' + value + ')';
|
|
558
|
+
}
|
|
559
|
+
} else if (slot === 'ctaLink') {
|
|
560
|
+
// For links, set href attribute
|
|
561
|
+
element.href = value;
|
|
562
|
+
} else {
|
|
563
|
+
// For text content, use textContent (safe, no HTML parsing)
|
|
564
|
+
safeSetText(element, value);
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
});
|
|
568
|
+
|
|
569
|
+
// Apply to generic 'hero' sections with data-personalize="hero"
|
|
570
|
+
var heroElements = findPersonalizeElements('hero');
|
|
571
|
+
for (var h = 0; h < heroElements.length; h++) {
|
|
572
|
+
var heroEl = heroElements[h];
|
|
573
|
+
heroEl.setAttribute('data-intent', decision.intent);
|
|
574
|
+
heroEl.setAttribute('data-source', decision.source);
|
|
575
|
+
|
|
576
|
+
// If hero has a background image slot, apply it
|
|
577
|
+
if (template.image && !heroEl.querySelector('[data-personalize="image"]')) {
|
|
578
|
+
heroEl.style.backgroundImage = 'url(' + template.image + ')';
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
// Log the personalization decision (for debugging/demo)
|
|
583
|
+
if (log && typeof console !== 'undefined') {
|
|
584
|
+
console.log('[Lua Personalize] Applied:', {
|
|
585
|
+
intent: decision.intent,
|
|
586
|
+
source: decision.source,
|
|
587
|
+
headline: template.headline,
|
|
588
|
+
hasUTM: context.hasUTM,
|
|
589
|
+
utmParams: context.utm || {},
|
|
590
|
+
aiPowered: decision.source === 'ai' || decision.source === 'ai-cached'
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
return decision;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
// ===================================================================
|
|
597
|
+
// Context Resolution
|
|
598
|
+
// ===================================================================
|
|
599
|
+
|
|
600
|
+
/**
|
|
601
|
+
* Resolve context from available sources
|
|
602
|
+
* @param {Object} [options] - Options with optional context
|
|
603
|
+
* @returns {Object} - Resolved context
|
|
604
|
+
*/
|
|
605
|
+
function resolveContext(options) {
|
|
606
|
+
if (options && options.context) {
|
|
607
|
+
return options.context;
|
|
608
|
+
}
|
|
609
|
+
if (root.LuaUTM && typeof root.LuaUTM.getContext === 'function') {
|
|
610
|
+
return root.LuaUTM.getContext();
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
// No UTM module available - create minimal default context
|
|
614
|
+
return {
|
|
615
|
+
utm: {},
|
|
616
|
+
referrer: {
|
|
617
|
+
source: 'direct',
|
|
618
|
+
category: 'direct',
|
|
619
|
+
url: ''
|
|
620
|
+
},
|
|
621
|
+
userAgent: {
|
|
622
|
+
raw: '',
|
|
623
|
+
isMobile: false,
|
|
624
|
+
isTablet: false,
|
|
625
|
+
isDesktop: true
|
|
626
|
+
},
|
|
627
|
+
timestamp: Date.now(),
|
|
628
|
+
hasUTM: false,
|
|
629
|
+
primaryIntent: 'default'
|
|
630
|
+
};
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
// ===================================================================
|
|
634
|
+
// Main Personalization Functions
|
|
635
|
+
// ===================================================================
|
|
636
|
+
|
|
637
|
+
/**
|
|
638
|
+
* Apply personalization to the page via data-personalize attributes
|
|
639
|
+
* Main entry point for personalization
|
|
640
|
+
*
|
|
641
|
+
* Supported data-personalize values:
|
|
642
|
+
* - "hero" : Generic hero section (sets data-intent, data-source)
|
|
643
|
+
* - "image" : Image slot (sets src or background-image)
|
|
644
|
+
* - "headline" : Headline text
|
|
645
|
+
* - "subheadline" : Subheadline text
|
|
646
|
+
* - "ctaLabel" : CTA button text
|
|
647
|
+
* - "ctaLink" : CTA link href
|
|
648
|
+
*
|
|
649
|
+
* @param {Object} [options] - Configuration options
|
|
650
|
+
* @param {Object} [options.context] - Pre-computed UTM context
|
|
651
|
+
* @param {Object} [options.rules] - Custom matching rules
|
|
652
|
+
* @param {Object} options.templates - User-provided templates (REQUIRED)
|
|
653
|
+
* @param {boolean} [options.enableAI] - Enable AI-powered decisions
|
|
654
|
+
* @param {Object} [options.aiConfig] - AI configuration (required if enableAI is true)
|
|
655
|
+
* @param {boolean} [options.randomFallback] - Enable random A/B fallback (default: true)
|
|
656
|
+
* @param {boolean} [options.log] - Enable console logging (default: true)
|
|
657
|
+
* @returns {Object|Promise<Object>} - Result with applied decision (Promise if AI enabled)
|
|
658
|
+
*/
|
|
659
|
+
function personalize(options) {
|
|
660
|
+
options = options || {};
|
|
661
|
+
|
|
662
|
+
// Templates are required
|
|
663
|
+
if (!options.templates || (0, _typeof2.default)(options.templates) !== 'object' || Object.keys(options.templates).length === 0) {
|
|
664
|
+
console.error('[Lua Personalize] Templates are required. Provide templates via options.templates');
|
|
665
|
+
return {
|
|
666
|
+
template: null,
|
|
667
|
+
intent: 'default',
|
|
668
|
+
source: 'error',
|
|
669
|
+
context: {},
|
|
670
|
+
error: 'No templates provided'
|
|
671
|
+
};
|
|
672
|
+
}
|
|
673
|
+
var context = resolveContext(options);
|
|
674
|
+
var decision = DecisionEngine.decide(context, options);
|
|
675
|
+
|
|
676
|
+
// If decision is a Promise (AI path), handle async flow
|
|
677
|
+
if (decision && typeof decision.then === 'function') {
|
|
678
|
+
return decision.then(function (aiDecision) {
|
|
679
|
+
return applyDecisionToDOM(aiDecision, options);
|
|
680
|
+
}).catch(function (err) {
|
|
681
|
+
console.warn('[Lua Personalize] AI decision failed, using standard:', err.message);
|
|
682
|
+
// Fallback to standard decision + DOM application
|
|
683
|
+
var fallbackDecision = DecisionEngine.standardDecide(context, options);
|
|
684
|
+
return applyDecisionToDOM(fallbackDecision, options);
|
|
685
|
+
});
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
// Synchronous path (standard engine)
|
|
689
|
+
return applyDecisionToDOM(decision, options);
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
/**
|
|
693
|
+
* Async personalization with timeout fallback
|
|
694
|
+
* Uses LuaUTM.getContextAsync for non-blocking UTM extraction
|
|
695
|
+
* Automatically handles AI decisions (which are always async)
|
|
696
|
+
*
|
|
697
|
+
* @param {Object} [options] - Configuration options
|
|
698
|
+
* @returns {Promise<Object>} - Result with applied decision
|
|
699
|
+
*/
|
|
700
|
+
function personalizeAsync(options) {
|
|
701
|
+
options = options || {};
|
|
702
|
+
|
|
703
|
+
// Use async context getter if available
|
|
704
|
+
if (root.LuaUTM && typeof root.LuaUTM.getContextAsync === 'function') {
|
|
705
|
+
return root.LuaUTM.getContextAsync(options).then(function (context) {
|
|
706
|
+
options.context = context;
|
|
707
|
+
return personalize(options);
|
|
708
|
+
}).then(function (decision) {
|
|
709
|
+
// Ensure we always return a resolved promise
|
|
710
|
+
return decision;
|
|
711
|
+
}).catch(function (err) {
|
|
712
|
+
console.warn('[Lua Personalize] Async error, using default:', err);
|
|
713
|
+
// Force standard engine fallback
|
|
714
|
+
var fallbackOptions = {
|
|
715
|
+
templates: options.templates,
|
|
716
|
+
context: resolveContext(options),
|
|
717
|
+
log: options.log
|
|
718
|
+
};
|
|
719
|
+
var fallbackDecision = DecisionEngine.standardDecide(fallbackOptions.context, fallbackOptions);
|
|
720
|
+
return applyDecisionToDOM(fallbackDecision, fallbackOptions);
|
|
721
|
+
});
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
// Wrap synchronous/AI personalization in a promise
|
|
725
|
+
try {
|
|
726
|
+
var result = personalize(options);
|
|
727
|
+
// If result is a promise (AI path), return it directly
|
|
728
|
+
if (result && typeof result.then === 'function') {
|
|
729
|
+
return result;
|
|
730
|
+
}
|
|
731
|
+
return Promise.resolve(result);
|
|
732
|
+
} catch (err) {
|
|
733
|
+
console.warn('[Lua Personalize] Error, using default:', err);
|
|
734
|
+
var defaultContext = {
|
|
735
|
+
utm: {},
|
|
736
|
+
referrer: {
|
|
737
|
+
source: 'direct',
|
|
738
|
+
category: 'direct',
|
|
739
|
+
url: ''
|
|
740
|
+
},
|
|
741
|
+
userAgent: {
|
|
742
|
+
raw: '',
|
|
743
|
+
isMobile: false,
|
|
744
|
+
isTablet: false,
|
|
745
|
+
isDesktop: true
|
|
746
|
+
},
|
|
747
|
+
timestamp: Date.now(),
|
|
748
|
+
hasUTM: false,
|
|
749
|
+
primaryIntent: 'default'
|
|
750
|
+
};
|
|
751
|
+
var fallback = DecisionEngine.standardDecide(defaultContext, {
|
|
752
|
+
templates: options.templates
|
|
753
|
+
});
|
|
754
|
+
return Promise.resolve(applyDecisionToDOM(fallback, options));
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
/**
|
|
759
|
+
* Auto-initialize personalization when DOM is ready
|
|
760
|
+
* Scans for data-personalize attributes and applies content
|
|
761
|
+
* @param {Object} [options] - Configuration options
|
|
762
|
+
*/
|
|
763
|
+
function autoInit(options) {
|
|
764
|
+
options = options || {};
|
|
765
|
+
function run() {
|
|
766
|
+
// Check if there are any data-personalize elements on the page
|
|
767
|
+
var elements = findPersonalizeElements();
|
|
768
|
+
if (elements.length > 0) {
|
|
769
|
+
personalize(options);
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
// Wait for DOM ready
|
|
774
|
+
if (typeof document !== 'undefined') {
|
|
775
|
+
if (document.readyState === 'loading') {
|
|
776
|
+
document.addEventListener('DOMContentLoaded', run);
|
|
777
|
+
} else {
|
|
778
|
+
run();
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
// ===================================================================
|
|
784
|
+
// Public API - Register on window.LuaPersonalize
|
|
785
|
+
// ===================================================================
|
|
786
|
+
|
|
787
|
+
var LuaPersonalize = {
|
|
788
|
+
// Note: Templates are NOT provided by this package
|
|
789
|
+
// Users must provide their own templates via options.templates
|
|
790
|
+
sanitizer: Sanitizer,
|
|
791
|
+
sanitizeHTML: function sanitizeHTML(html) {
|
|
792
|
+
return Sanitizer.sanitize(html);
|
|
793
|
+
},
|
|
794
|
+
safeSetText: safeSetText,
|
|
795
|
+
safeSetHTML: safeSetHTML,
|
|
796
|
+
findElements: findPersonalizeElements,
|
|
797
|
+
getTemplate: getTemplate,
|
|
798
|
+
engine: DecisionEngine,
|
|
799
|
+
personalize: personalize,
|
|
800
|
+
personalizeAsync: personalizeAsync,
|
|
801
|
+
autoInit: autoInit,
|
|
802
|
+
chooseWeightedRandom: chooseWeightedRandom,
|
|
803
|
+
getRandomFallbackIntent: getRandomFallbackIntent,
|
|
804
|
+
applyDecisionToDOM: applyDecisionToDOM,
|
|
805
|
+
resolveContext: resolveContext
|
|
806
|
+
};
|
|
807
|
+
|
|
808
|
+
// Expose globally
|
|
809
|
+
root.LuaPersonalize = LuaPersonalize;
|
|
810
|
+
})(typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : void 0);
|
|
811
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJyb290IiwiU2FuaXRpemVyIiwiQUxMT1dFRF9UQUdTIiwiQUxMT1dFRF9BVFRSUyIsIkRBTkdFUk9VU19VUkkiLCJFVkVOVF9IQU5ETEVSIiwiaGFzRE9NUGFyc2VyIiwiRE9NUGFyc2VyIiwiZSIsInNhbml0aXplV2l0aERPTVBhcnNlciIsImRpcnR5IiwidHJpbSIsInBhcnNlciIsImRvYyIsInBhcnNlRnJvbVN0cmluZyIsImJvZHkiLCJ3YWxrQW5kQ2xlYW4iLCJjb25zb2xlIiwid2FybiIsInNhbml0aXplV2l0aFJlZ2V4Iiwibm9kZSIsIm91dHB1dCIsImkiLCJjaGlsZE5vZGVzIiwibGVuZ3RoIiwiY2hpbGQiLCJub2RlVHlwZSIsImVzY2FwZVRleHQiLCJ0ZXh0Q29udGVudCIsInRhZ05hbWUiLCJ0b0xvd2VyQ2FzZSIsImNsZWFuQXR0cmlidXRlcyIsImVsZW1lbnQiLCJhdHRyU3RyIiwiYXR0cnMiLCJhdHRyaWJ1dGVzIiwiYXR0ciIsIm5hbWUiLCJ2YWx1ZSIsInRlc3QiLCJlc2NhcGVBdHRyIiwidGV4dCIsInJlcGxhY2UiLCJodG1sIiwiREFOR0VST1VTX1BBVFRFUk5TIiwic2FuaXRpemVkIiwiZm9yRWFjaCIsInBhdHRlcm4iLCJtYXRjaCIsInRhZyIsImNoYXJBdCIsImNsZWFuQXR0cnMiLCJhdHRyUmVnZXgiLCJhdHRyTWF0Y2giLCJleGVjIiwiYXR0ck5hbWUiLCJ2YWwiLCJzYW5pdGl6ZSIsInNhZmVTZXRUZXh0Iiwic2FmZVNldEhUTUwiLCJpbm5lckhUTUwiLCJmaW5kUGVyc29uYWxpemVFbGVtZW50cyIsImtleSIsInNlYXJjaFJvb3QiLCJkb2N1bWVudCIsInNlbGVjdG9yIiwicXVlcnlTZWxlY3RvckFsbCIsImdldFRlbXBsYXRlIiwiaW50ZW50IiwidXNlclRlbXBsYXRlcyIsIl90eXBlb2YyIiwiZGVmYXVsdCIsImZpcnN0S2V5IiwiT2JqZWN0Iiwia2V5cyIsImNob29zZVdlaWdodGVkUmFuZG9tIiwibmFtZXMiLCJ3ZWlnaHRzIiwic3VtIiwibiIsIk1hdGgiLCJyYW5kb20iLCJsaW1pdCIsImdldFJhbmRvbUZhbGxiYWNrSW50ZW50IiwicHVzaCIsIkRlY2lzaW9uRW5naW5lIiwic3RhbmRhcmREZWNpZGUiLCJjb250ZXh0Iiwib3B0aW9ucyIsImN1c3RvbVJ1bGVzIiwicnVsZXMiLCJ0ZW1wbGF0ZXMiLCJlbmFibGVSYW5kb21GYWxsYmFjayIsInJhbmRvbUZhbGxiYWNrIiwidGVtcGxhdGUiLCJzb3VyY2UiLCJlcnJvciIsInByaW1hcnlJbnRlbnQiLCJoYXNVVE0iLCJyZWZlcnJlciIsImNhdGVnb3J5IiwicnVsZUtleSIsInJ1bGUiLCJyYW5kb21JbnRlbnQiLCJMdWFXZWlnaHRlZEhpc3RvcnkiLCJyZWNvcmRWaXNpdCIsInNlbGVjdGVkVmFyaWFudCIsImFpRGVjaXNpb24iLCJkZWNpZGUiLCJlbmFibGVBSSIsImFpQ29uZmlnIiwiTHVhQUlQZXJzb25hbGl6ZSIsInNlbGYiLCJhaU1vZHVsZSIsInJlYWRpbmVzcyIsImlzUmVhZHkiLCJyZWFkeSIsImNhdGNoIiwiZmFsbGJhY2siLCJmYWxsYmFja1RvU3RhbmRhcmQiLCJtZXNzYWdlIiwiYXBwbHlEZWNpc2lvblRvRE9NIiwiZGVjaXNpb24iLCJsb2ciLCJzbG90cyIsInNsb3QiLCJlbGVtZW50cyIsInNyYyIsImFsdCIsImhlYWRsaW5lIiwic3R5bGUiLCJiYWNrZ3JvdW5kSW1hZ2UiLCJocmVmIiwiaGVyb0VsZW1lbnRzIiwiaCIsImhlcm9FbCIsInNldEF0dHJpYnV0ZSIsImltYWdlIiwicXVlcnlTZWxlY3RvciIsInV0bVBhcmFtcyIsInV0bSIsImFpUG93ZXJlZCIsInJlc29sdmVDb250ZXh0IiwiTHVhVVRNIiwiZ2V0Q29udGV4dCIsInVybCIsInVzZXJBZ2VudCIsInJhdyIsImlzTW9iaWxlIiwiaXNUYWJsZXQiLCJpc0Rlc2t0b3AiLCJ0aW1lc3RhbXAiLCJEYXRlIiwibm93IiwicGVyc29uYWxpemUiLCJ0aGVuIiwiZXJyIiwiZmFsbGJhY2tEZWNpc2lvbiIsInBlcnNvbmFsaXplQXN5bmMiLCJnZXRDb250ZXh0QXN5bmMiLCJmYWxsYmFja09wdGlvbnMiLCJyZXN1bHQiLCJQcm9taXNlIiwicmVzb2x2ZSIsImRlZmF1bHRDb250ZXh0IiwiYXV0b0luaXQiLCJydW4iLCJyZWFkeVN0YXRlIiwiYWRkRXZlbnRMaXN0ZW5lciIsIkx1YVBlcnNvbmFsaXplIiwic2FuaXRpemVyIiwic2FuaXRpemVIVE1MIiwiZmluZEVsZW1lbnRzIiwiZW5naW5lIiwid2luZG93IiwiZ2xvYmFsIl0sInNvdXJjZXMiOlsiLi4vLi4vc3JjL3BlcnNvbmFsaXphdGlvbi5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyJcbi8qKlxuICogRE9NIFBlcnNvbmFsaXphdGlvbiBFbmdpbmVcbiAqIEhhbmRsZXMgY29udGVudCBpbmplY3Rpb24gd2l0aCBkYXRhLXBlcnNvbmFsaXplIGF0dHJpYnV0ZXNcbiAqIFVzZXMgdGV4dENvbnRlbnQgZm9yIHRleHQsIERPTVB1cmlmeS1zdHlsZSBzYW5pdGl6ZWQgSFRNTCBmb3IgcmljaCBjb250ZW50XG4gKlxuICogTm8gRVM2IGltcG9ydHMgLSBzZWxmLWNvbnRhaW5lZCBJSUZFIHRoYXQgcmVnaXN0ZXJzIG9uIHdpbmRvdy5MdWFQZXJzb25hbGl6ZVxuICogRGVwZW5kcyBvbiB3aW5kb3cuTHVhVVRNIChmcm9tIHV0bS5qcykgZm9yIGNvbnRleHQgZXh0cmFjdGlvblxuICogRmFsbHMgYmFjayB0byByYW5kb20gQS9CIHRlc3Qgd2hlbiBubyBVVE0gcGFyYW1zIGFyZSBwcmVzZW50XG4gKi9cbjsoZnVuY3Rpb24gKHJvb3QpIHtcbiAgICAndXNlIHN0cmljdCdcblxuICAgIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgICAvLyBET01QdXJpZnktc3R5bGUgSFRNTCBTYW5pdGl6ZXIgKGlubGluZSwgT1dBU1AtcmVjb21tZW5kZWQgYXBwcm9hY2gpXG4gICAgLy8gUHJvdmlkZXMgc2FmZSBIVE1MIGluamVjdGlvbiB3aXRob3V0IGV4dGVybmFsIGRlcGVuZGVuY2llc1xuICAgIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuICAgIC8qKlxuICAgICAqIElubGluZSBET01QdXJpZnktc3R5bGUgc2FuaXRpemVyXG4gICAgICogVXNlcyB0aGUgYnJvd3NlcidzIERPTVBhcnNlciB0byBzYWZlbHkgcGFyc2UgYW5kIHNhbml0aXplIEhUTUxcbiAgICAgKiBGYWxscyBiYWNrIHRvIHJlZ2V4LWJhc2VkIHNhbml0aXphdGlvbiBpZiBET01QYXJzZXIgdW5hdmFpbGFibGVcbiAgICAgKi9cbiAgICB2YXIgU2FuaXRpemVyID0gKGZ1bmN0aW9uICgpIHtcblxuICAgICAgICAvLyBBbGxvd2VkIEhUTUwgdGFncyAoc2FmZSBmb3IgY29udGVudCBpbmplY3Rpb24pXG4gICAgICAgIHZhciBBTExPV0VEX1RBR1MgPSB7XG4gICAgICAgICAgICAncCc6IHRydWUsICdzcGFuJzogdHJ1ZSwgJ3N0cm9uZyc6IHRydWUsICdlbSc6IHRydWUsXG4gICAgICAgICAgICAnYic6IHRydWUsICdpJzogdHJ1ZSwgJ2JyJzogdHJ1ZSwgJ2EnOiB0cnVlLCAnaW1nJzogdHJ1ZSxcbiAgICAgICAgICAgICdoMSc6IHRydWUsICdoMic6IHRydWUsICdoMyc6IHRydWUsICdoNCc6IHRydWUsICdoNSc6IHRydWUsICdoNic6IHRydWUsXG4gICAgICAgICAgICAnZGl2JzogdHJ1ZSwgJ3NlY3Rpb24nOiB0cnVlLCAndWwnOiB0cnVlLCAnb2wnOiB0cnVlLCAnbGknOiB0cnVlLFxuICAgICAgICAgICAgJ2Jsb2NrcXVvdGUnOiB0cnVlLCAnZmlndXJlJzogdHJ1ZSwgJ2ZpZ2NhcHRpb24nOiB0cnVlXG4gICAgICAgIH1cblxuICAgICAgICAvLyBBbGxvd2VkIEhUTUwgYXR0cmlidXRlcyAoc2FmZSBzdWJzZXQpXG4gICAgICAgIHZhciBBTExPV0VEX0FUVFJTID0ge1xuICAgICAgICAgICAgJ2hyZWYnOiB0cnVlLCAnc3JjJzogdHJ1ZSwgJ2FsdCc6IHRydWUsICdjbGFzcyc6IHRydWUsXG4gICAgICAgICAgICAnaWQnOiB0cnVlLCAndGl0bGUnOiB0cnVlLCAndGFyZ2V0JzogdHJ1ZSwgJ3JlbCc6IHRydWUsXG4gICAgICAgICAgICAnd2lkdGgnOiB0cnVlLCAnaGVpZ2h0JzogdHJ1ZSwgJ2xvYWRpbmcnOiB0cnVlXG4gICAgICAgIH1cblxuICAgICAgICAvLyBEYW5nZXJvdXMgVVJJIHNjaGVtZXNcbiAgICAgICAgdmFyIERBTkdFUk9VU19VUkkgPSAvXihqYXZhc2NyaXB0fHZic2NyaXB0fGRhdGEpOi9pXG5cbiAgICAgICAgLy8gRXZlbnQgaGFuZGxlciBwYXR0ZXJuIChvbmNsaWNrLCBvbmVycm9yLCBvbmxvYWQsIGV0Yy4pXG4gICAgICAgIHZhciBFVkVOVF9IQU5ETEVSID0gL15vbi9pXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENoZWNrIGlmIERPTVBhcnNlciBpcyBhdmFpbGFibGUgKG1vZGVybiBicm93c2VycylcbiAgICAgICAgICogQHJldHVybnMge2Jvb2xlYW59XG4gICAgICAgICAqL1xuICAgICAgICBmdW5jdGlvbiBoYXNET01QYXJzZXIoKSB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIHJldHVybiB0eXBlb2YgRE9NUGFyc2VyICE9PSAndW5kZWZpbmVkJyAmJiBuZXcgRE9NUGFyc2VyKClcbiAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2VcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBTYW5pdGl6ZSBIVE1MIHVzaW5nIERPTVBhcnNlciAocHJlZmVycmVkLCBzZWN1cmUgbWV0aG9kKVxuICAgICAgICAgKiBQYXJzZXMgSFRNTCBpbnRvIGEgRE9NIHRyZWUsIHdhbGtzIG5vZGVzLCBhbmQgcmVidWlsZHMgc2FmZSBIVE1MXG4gICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBkaXJ0eSAtIFVudHJ1c3RlZCBIVE1MIHN0cmluZ1xuICAgICAgICAgKiBAcmV0dXJucyB7c3RyaW5nfSAtIFNhbml0aXplZCBIVE1MIHN0cmluZ1xuICAgICAgICAgKi9cbiAgICAgICAgZnVuY3Rpb24gc2FuaXRpemVXaXRoRE9NUGFyc2VyKGRpcnR5KSB7XG4gICAgICAgICAgICBpZiAodHlwZW9mIGRpcnR5ICE9PSAnc3RyaW5nJyB8fCAhZGlydHkudHJpbSgpKSByZXR1cm4gJydcblxuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICB2YXIgcGFyc2VyID0gbmV3IERPTVBhcnNlcigpXG4gICAgICAgICAgICAgICAgdmFyIGRvYyA9IHBhcnNlci5wYXJzZUZyb21TdHJpbmcoZGlydHksICd0ZXh0L2h0bWwnKVxuICAgICAgICAgICAgICAgIHZhciBib2R5ID0gZG9jLmJvZHlcblxuICAgICAgICAgICAgICAgIGlmICghYm9keSkgcmV0dXJuICcnXG5cbiAgICAgICAgICAgICAgICByZXR1cm4gd2Fsa0FuZENsZWFuKGJvZHkpXG4gICAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS53YXJuKCdbTHVhIFNhbml0aXplcl0gRE9NUGFyc2VyIGZhaWxlZCwgdXNpbmcgZmFsbGJhY2s6JywgZSlcbiAgICAgICAgICAgICAgICByZXR1cm4gc2FuaXRpemVXaXRoUmVnZXgoZGlydHkpXG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvKipcbiAgICAgICAgICogUmVjdXJzaXZlbHkgd2FsayBET00gbm9kZXMgYW5kIGJ1aWxkIGNsZWFuIEhUTUxcbiAgICAgICAgICogQHBhcmFtIHtOb2RlfSBub2RlIC0gRE9NIG5vZGUgdG8gcHJvY2Vzc1xuICAgICAgICAgKiBAcmV0dXJucyB7c3RyaW5nfSAtIENsZWFuZWQgSFRNTCBzdHJpbmdcbiAgICAgICAgICovXG4gICAgICAgIGZ1bmN0aW9uIHdhbGtBbmRDbGVhbihub2RlKSB7XG4gICAgICAgICAgICB2YXIgb3V0cHV0ID0gJydcblxuICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBub2RlLmNoaWxkTm9kZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICB2YXIgY2hpbGQgPSBub2RlLmNoaWxkTm9kZXNbaV1cblxuICAgICAgICAgICAgICAgIC8vIFRleHQgbm9kZSAtIHNhZmUgdG8gaW5jbHVkZVxuICAgICAgICAgICAgICAgIGlmIChjaGlsZC5ub2RlVHlwZSA9PT0gMykge1xuICAgICAgICAgICAgICAgICAgICBvdXRwdXQgKz0gZXNjYXBlVGV4dChjaGlsZC50ZXh0Q29udGVudClcbiAgICAgICAgICAgICAgICAgICAgY29udGludWVcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAvLyBFbGVtZW50IG5vZGVcbiAgICAgICAgICAgICAgICBpZiAoY2hpbGQubm9kZVR5cGUgPT09IDEpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHRhZ05hbWUgPSBjaGlsZC50YWdOYW1lLnRvTG93ZXJDYXNlKClcblxuICAgICAgICAgICAgICAgICAgICAvLyBTa2lwIGRpc2FsbG93ZWQgdGFncyBlbnRpcmVseSAoaW5jbHVkaW5nIGNoaWxkcmVuKVxuICAgICAgICAgICAgICAgICAgICBpZiAodGFnTmFtZSA9PT0gJ3NjcmlwdCcgfHwgdGFnTmFtZSA9PT0gJ3N0eWxlJyB8fFxuICAgICAgICAgICAgICAgICAgICAgICAgdGFnTmFtZSA9PT0gJ2lmcmFtZScgfHwgdGFnTmFtZSA9PT0gJ29iamVjdCcgfHxcbiAgICAgICAgICAgICAgICAgICAgICAgIHRhZ05hbWUgPT09ICdlbWJlZCcgfHwgdGFnTmFtZSA9PT0gJ2Zvcm0nIHx8XG4gICAgICAgICAgICAgICAgICAgICAgICB0YWdOYW1lID09PSAnaW5wdXQnIHx8IHRhZ05hbWUgPT09ICd0ZXh0YXJlYScpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlXG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAvLyBJZiB0YWcgaXMgYWxsb3dlZCwgaW5jbHVkZSBpdCB3aXRoIGZpbHRlcmVkIGF0dHJpYnV0ZXNcbiAgICAgICAgICAgICAgICAgICAgaWYgKEFMTE9XRURfVEFHU1t0YWdOYW1lXSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgb3V0cHV0ICs9ICc8JyArIHRhZ05hbWVcbiAgICAgICAgICAgICAgICAgICAgICAgIG91dHB1dCArPSBjbGVhbkF0dHJpYnV0ZXMoY2hpbGQpXG4gICAgICAgICAgICAgICAgICAgICAgICBvdXRwdXQgKz0gJz4nXG5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFNlbGYtY2xvc2luZyB0YWdzXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAodGFnTmFtZSA9PT0gJ2JyJyB8fCB0YWdOYW1lID09PSAnaW1nJykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlXG4gICAgICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFJlY3Vyc2UgaW50byBjaGlsZHJlblxuICAgICAgICAgICAgICAgICAgICAgICAgb3V0cHV0ICs9IHdhbGtBbmRDbGVhbihjaGlsZClcbiAgICAgICAgICAgICAgICAgICAgICAgIG91dHB1dCArPSAnPC8nICsgdGFnTmFtZSArICc+J1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gVGFnIG5vdCBhbGxvd2VkIC0gaW5jbHVkZSBjaGlsZHJlbiBvbmx5IChzdHJpcCB0aGUgdGFnKVxuICAgICAgICAgICAgICAgICAgICAgICAgb3V0cHV0ICs9IHdhbGtBbmRDbGVhbihjaGlsZClcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIG91dHB1dFxuICAgICAgICB9XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEZpbHRlciBlbGVtZW50IGF0dHJpYnV0ZXMgdG8gb25seSBhbGxvd2VkIG9uZXNcbiAgICAgICAgICogQHBhcmFtIHtFbGVtZW50fSBlbGVtZW50IC0gRE9NIGVsZW1lbnRcbiAgICAgICAgICogQHJldHVybnMge3N0cmluZ30gLSBBdHRyaWJ1dGUgc3RyaW5nXG4gICAgICAgICAqL1xuICAgICAgICBmdW5jdGlvbiBjbGVhbkF0dHJpYnV0ZXMoZWxlbWVudCkge1xuICAgICAgICAgICAgdmFyIGF0dHJTdHIgPSAnJ1xuICAgICAgICAgICAgdmFyIGF0dHJzID0gZWxlbWVudC5hdHRyaWJ1dGVzXG5cbiAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgYXR0cnMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICB2YXIgYXR0ciA9IGF0dHJzW2ldXG4gICAgICAgICAgICAgICAgdmFyIG5hbWUgPSBhdHRyLm5hbWUudG9Mb3dlckNhc2UoKVxuICAgICAgICAgICAgICAgIHZhciB2YWx1ZSA9IGF0dHIudmFsdWVcblxuICAgICAgICAgICAgICAgIC8vIFNraXAgZXZlbnQgaGFuZGxlcnMgKG9uY2xpY2ssIG9uZXJyb3IsIGV0Yy4pXG4gICAgICAgICAgICAgICAgaWYgKEVWRU5UX0hBTkRMRVIudGVzdChuYW1lKSkgY29udGludWVcblxuICAgICAgICAgICAgICAgIC8vIFNraXAgZGlzYWxsb3dlZCBhdHRyaWJ1dGVzXG4gICAgICAgICAgICAgICAgaWYgKCFBTExPV0VEX0FUVFJTW25hbWVdKSBjb250aW51ZVxuXG4gICAgICAgICAgICAgICAgLy8gQ2hlY2sgVVJJIHNhZmV0eSBmb3IgaHJlZi9zcmNcbiAgICAgICAgICAgICAgICBpZiAoKG5hbWUgPT09ICdocmVmJyB8fCBuYW1lID09PSAnc3JjJykgJiYgREFOR0VST1VTX1VSSS50ZXN0KHZhbHVlLnRyaW0oKSkpIHtcbiAgICAgICAgICAgICAgICAgICAgY29udGludWVcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAvLyBBZGQgcmVsPVwibm9vcGVuZXIgbm9yZWZlcnJlclwiIGZvciBleHRlcm5hbCBsaW5rc1xuICAgICAgICAgICAgICAgIGlmIChuYW1lID09PSAndGFyZ2V0JyAmJiB2YWx1ZSA9PT0gJ19ibGFuaycpIHtcbiAgICAgICAgICAgICAgICAgICAgYXR0clN0ciArPSAnIHRhcmdldD1cIl9ibGFua1wiIHJlbD1cIm5vb3BlbmVyIG5vcmVmZXJyZXJcIidcbiAgICAgICAgICAgICAgICAgICAgY29udGludWVcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBhdHRyU3RyICs9ICcgJyArIG5hbWUgKyAnPVwiJyArIGVzY2FwZUF0dHIodmFsdWUpICsgJ1wiJ1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gYXR0clN0clxuICAgICAgICB9XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEVzY2FwZSB0ZXh0IGNvbnRlbnQgZm9yIHNhZmUgSFRNTCBpbmNsdXNpb25cbiAgICAgICAgICogQHBhcmFtIHtzdHJpbmd9IHRleHQgLSBSYXcgdGV4dFxuICAgICAgICAgKiBAcmV0dXJucyB7c3RyaW5nfSAtIEVzY2FwZWQgdGV4dFxuICAgICAgICAgKi9cbiAgICAgICAgZnVuY3Rpb24gZXNjYXBlVGV4dCh0ZXh0KSB7XG4gICAgICAgICAgICBpZiAoIXRleHQpIHJldHVybiAnJ1xuICAgICAgICAgICAgcmV0dXJuIHRleHRcbiAgICAgICAgICAgICAgICAucmVwbGFjZSgvJi9nLCAnJmFtcDsnKVxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKC88L2csICcmbHQ7JylcbiAgICAgICAgICAgICAgICAucmVwbGFjZSgvPi9nLCAnJmd0OycpXG4gICAgICAgIH1cblxuICAgICAgICAvKipcbiAgICAgICAgICogRXNjYXBlIGF0dHJpYnV0ZSB2YWx1ZSBmb3Igc2FmZSBIVE1MIGluY2x1c2lvblxuICAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gdmFsdWUgLSBSYXcgYXR0cmlidXRlIHZhbHVlXG4gICAgICAgICAqIEByZXR1cm5zIHtzdHJpbmd9IC0gRXNjYXBlZCBhdHRyaWJ1dGUgdmFsdWVcbiAgICAgICAgICovXG4gICAgICAgIGZ1bmN0aW9uIGVzY2FwZUF0dHIodmFsdWUpIHtcbiAgICAgICAgICAgIGlmICghdmFsdWUpIHJldHVybiAnJ1xuICAgICAgICAgICAgcmV0dXJuIHZhbHVlXG4gICAgICAgICAgICAgICAgLnJlcGxhY2UoLyYvZywgJyZhbXA7JylcbiAgICAgICAgICAgICAgICAucmVwbGFjZSgvXCIvZywgJyZxdW90OycpXG4gICAgICAgICAgICAgICAgLnJlcGxhY2UoLycvZywgJyYjMzk7JylcbiAgICAgICAgICAgICAgICAucmVwbGFjZSgvPC9nLCAnJmx0OycpXG4gICAgICAgICAgICAgICAgLnJlcGxhY2UoLz4vZywgJyZndDsnKVxuICAgICAgICB9XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEZhbGxiYWNrIHJlZ2V4LWJhc2VkIHNhbml0aXplciBmb3IgZW52aXJvbm1lbnRzIHdpdGhvdXQgRE9NUGFyc2VyXG4gICAgICAgICAqIEBwYXJhbSB7c3RyaW5nfSBodG1sIC0gUmF3IEhUTUwgc3RyaW5nXG4gICAgICAgICAqIEByZXR1cm5zIHtzdHJpbmd9IC0gU2FuaXRpemVkIEhUTUxcbiAgICAgICAgICovXG4gICAgICAgIGZ1bmN0aW9uIHNhbml0aXplV2l0aFJlZ2V4KGh0bWwpIHtcbiAgICAgICAgICAgIGlmICh0eXBlb2YgaHRtbCAhPT0gJ3N0cmluZycpIHJldHVybiAnJ1xuXG4gICAgICAgICAgICB2YXIgREFOR0VST1VTX1BBVFRFUk5TID0gW1xuICAgICAgICAgICAgICAgIC88c2NyaXB0XFxiW148XSooPzooPyE8XFwvc2NyaXB0Pik8W148XSopKjxcXC9zY3JpcHQ+L2dpLFxuICAgICAgICAgICAgICAgIC88aWZyYW1lXFxiW148XSooPzooPyE8XFwvaWZyYW1lPik8W148XSopKjxcXC9pZnJhbWU+L2dpLFxuICAgICAgICAgICAgICAgIC88b2JqZWN0XFxiW148XSooPzooPyE8XFwvb2JqZWN0Pik8W148XSopKjxcXC9vYmplY3Q+L2dpLFxuICAgICAgICAgICAgICAgIC88ZW1iZWRcXGJbXj5dKj4vZ2ksXG4gICAgICAgICAgICAgICAgLzxsaW5rXFxiW14+XSo+L2dpLFxuICAgICAgICAgICAgICAgIC88c3R5bGVcXGJbXjxdKig/Oig/ITxcXC9zdHlsZT4pPFtePF0qKSo8XFwvc3R5bGU+L2dpLFxuICAgICAgICAgICAgICAgIC88Zm9ybVxcYltePF0qKD86KD8hPFxcL2Zvcm0+KTxbXjxdKikqPFxcL2Zvcm0+L2dpLFxuICAgICAgICAgICAgICAgIC9qYXZhc2NyaXB0Oi9naSxcbiAgICAgICAgICAgICAgICAvdmJzY3JpcHQ6L2dpLFxuICAgICAgICAgICAgICAgIC9kYXRhOi9naSxcbiAgICAgICAgICAgICAgICAvb25cXHcrXFxzKj0vZ2lcbiAgICAgICAgICAgIF1cblxuICAgICAgICAgICAgdmFyIHNhbml0aXplZCA9IGh0bWxcblxuICAgICAgICAgICAgREFOR0VST1VTX1BBVFRFUk5TLmZvckVhY2goZnVuY3Rpb24gKHBhdHRlcm4pIHtcbiAgICAgICAgICAgICAgICBzYW5pdGl6ZWQgPSBzYW5pdGl6ZWQucmVwbGFjZShwYXR0ZXJuLCAnJylcbiAgICAgICAgICAgIH0pXG5cbiAgICAgICAgICAgIC8vIFJlbW92ZSBkaXNhbGxvd2VkIHRhZ3MgYnV0IGtlZXAgdGhlaXIgdGV4dCBjb250ZW50XG4gICAgICAgICAgICBzYW5pdGl6ZWQgPSBzYW5pdGl6ZWQucmVwbGFjZSgvPFxcLz8oXFx3KykoW14+XSopPi9nLCBmdW5jdGlvbiAobWF0Y2gsIHRhZ05hbWUsIGF0dHJzKSB7XG4gICAgICAgICAgICAgICAgdmFyIHRhZyA9IHRhZ05hbWUudG9Mb3dlckNhc2UoKVxuICAgICAgICAgICAgICAgIGlmICghQUxMT1dFRF9UQUdTW3RhZ10pIHJldHVybiAnJ1xuXG4gICAgICAgICAgICAgICAgLy8gRm9yIGNsb3NpbmcgdGFncywganVzdCByZXR1cm4gdGhlIGNsb3NpbmcgdGFnXG4gICAgICAgICAgICAgICAgaWYgKG1hdGNoLmNoYXJBdCgxKSA9PT0gJy8nKSByZXR1cm4gJzwvJyArIHRhZyArICc+J1xuXG4gICAgICAgICAgICAgICAgLy8gRmlsdGVyIGF0dHJpYnV0ZXNcbiAgICAgICAgICAgICAgICB2YXIgY2xlYW5BdHRycyA9ICcnXG4gICAgICAgICAgICAgICAgdmFyIGF0dHJSZWdleCA9IC8oXFx3Kyk9WydcIl0oW14nXCJdKilbJ1wiXS9nXG4gICAgICAgICAgICAgICAgdmFyIGF0dHJNYXRjaFxuXG4gICAgICAgICAgICAgICAgd2hpbGUgKChhdHRyTWF0Y2ggPSBhdHRyUmVnZXguZXhlYyhhdHRycykpICE9PSBudWxsKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBhdHRyTmFtZSA9IGF0dHJNYXRjaFsxXS50b0xvd2VyQ2FzZSgpXG4gICAgICAgICAgICAgICAgICAgIGlmIChBTExPV0VEX0FUVFJTW2F0dHJOYW1lXSAmJiAhRVZFTlRfSEFORExFUi50ZXN0KGF0dHJOYW1lKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHZhbCA9IGF0dHJNYXRjaFsyXVxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKChhdHRyTmFtZSA9PT0gJ2hyZWYnIHx8IGF0dHJOYW1lID09PSAnc3JjJykgJiYgREFOR0VST1VTX1VSSS50ZXN0KHZhbCkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250aW51ZVxuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgY2xlYW5BdHRycyArPSAnICcgKyBhdHRyTmFtZSArICc9XCInICsgdmFsICsgJ1wiJ1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuICc8JyArIHRhZyArIGNsZWFuQXR0cnMgKyAnPidcbiAgICAgICAgICAgIH0pXG5cbiAgICAgICAgICAgIHJldHVybiBzYW5pdGl6ZWRcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFB1YmxpYyBzYW5pdGl6ZXIgQVBJXG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAvKipcbiAgICAgICAgICAgICAqIFNhbml0aXplIEhUTUwgc3RyaW5nIChtYWluIGVudHJ5IHBvaW50KVxuICAgICAgICAgICAgICogVXNlcyBET01QYXJzZXIgd2hlbiBhdmFpbGFibGUsIHJlZ2V4IGZhbGxiYWNrIG90aGVyd2lzZVxuICAgICAgICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGRpcnR5IC0gVW50cnVzdGVkIEhUTUxcbiAgICAgICAgICAgICAqIEByZXR1cm5zIHtzdHJpbmd9IC0gU2FuaXRpemVkIEhUTUxcbiAgICAgICAgICAgICAqL1xuICAgICAgICAgICAgc2FuaXRpemU6IGZ1bmN0aW9uIChkaXJ0eSkge1xuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgZGlydHkgIT09ICdzdHJpbmcnKSByZXR1cm4gJydcbiAgICAgICAgICAgICAgICBpZiAoIWRpcnR5LnRyaW0oKSkgcmV0dXJuICcnXG5cbiAgICAgICAgICAgICAgICBpZiAoaGFzRE9NUGFyc2VyKCkpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHNhbml0aXplV2l0aERPTVBhcnNlcihkaXJ0eSlcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuIHNhbml0aXplV2l0aFJlZ2V4KGRpcnR5KVxuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgZXNjYXBlVGV4dDogZXNjYXBlVGV4dCxcbiAgICAgICAgICAgIGVzY2FwZUF0dHI6IGVzY2FwZUF0dHJcbiAgICAgICAgfVxuICAgIH0pKClcblxuICAgIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgICAvLyBUZW1wbGF0ZXMgJiBBc3NldHNcbiAgICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gICAgLy8gTk9URTogVGVtcGxhdGVzIGFyZSBOT1QgcHJvdmlkZWQgYnkgdGhpcyBwYWNrYWdlLlxuICAgIC8vIFVzZXJzIG11c3QgcHJvdmlkZSB0aGVpciBvd24gdGVtcGxhdGVzIHZpYSBvcHRpb25zLnRlbXBsYXRlc1xuICAgIC8vIFRoaXMga2VlcHMgdGhlIHBhY2thZ2UgbW9kdWxhciBhbmQgYWxsb3dzIHVzZXJzIGZ1bGwgY29udHJvbFxuICAgIC8vIG92ZXIgdGhlaXIgY29udGVudCwgYXNzZXRzLCBhbmQgcGVyc29uYWxpemF0aW9uIHN0cmF0ZWd5LlxuXG4gICAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICAgIC8vIERPTSBJbnRlcmFjdGlvbiAoc2FmZSBtZXRob2RzIC0gbmV2ZXIgcmF3IGlubmVySFRNTClcbiAgICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbiAgICAvKipcbiAgICAgKiBTYWZlbHkgc2V0IHRleHQgY29udGVudCBvbiBhbiBlbGVtZW50IChubyBIVE1MIHBhcnNpbmcpXG4gICAgICogQHBhcmFtIHtFbGVtZW50fSBlbGVtZW50IC0gRE9NIGVsZW1lbnRcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gdGV4dCAtIFRleHQgdG8gc2V0XG4gICAgICovXG4gICAgZnVuY3Rpb24gc2FmZVNldFRleHQoZWxlbWVudCwgdGV4dCkge1xuICAgICAgICBpZiAoIWVsZW1lbnQpIHJldHVyblxuICAgICAgICBlbGVtZW50LnRleHRDb250ZW50ID0gdGV4dFxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNhZmVseSBzZXQgSFRNTCBjb250ZW50IG9uIGFuIGVsZW1lbnQgKERPTVB1cmlmeS1zYW5pdGl6ZWQpXG4gICAgICogQHBhcmFtIHtFbGVtZW50fSBlbGVtZW50IC0gRE9NIGVsZW1lbnRcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gaHRtbCAtIEhUTUwgdG8gc2V0ICh3aWxsIGJlIHNhbml0aXplZClcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBzYWZlU2V0SFRNTChlbGVtZW50LCBodG1sKSB7XG4gICAgICAgIGlmICghZWxlbWVudCkgcmV0dXJuXG4gICAgICAgIGVsZW1lbnQuaW5uZXJIVE1MID0gU2FuaXRpemVyLnNhbml0aXplKGh0bWwpXG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRmluZCBhbGwgZWxlbWVudHMgd2l0aCBkYXRhLXBlcnNvbmFsaXplIGF0dHJpYnV0ZVxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBba2V5XSAtIE9wdGlvbmFsIHNwZWNpZmljIGtleSB0byBmaW5kXG4gICAgICogQHBhcmFtIHtFbGVtZW50fSBbc2VhcmNoUm9vdF0gLSBSb290IGVsZW1lbnQgdG8gc2VhcmNoIGZyb20gKGRlZmF1bHQ6IGRvY3VtZW50KVxuICAgICAqIEByZXR1cm5zIHtOb2RlTGlzdHxBcnJheX0gLSBNYXRjaGluZyBlbGVtZW50c1xuICAgICAqL1xuICAgIGZ1bmN0aW9uIGZpbmRQZXJzb25hbGl6ZUVsZW1lbnRzKGtleSwgc2VhcmNoUm9vdCkge1xuICAgICAgICBzZWFyY2hSb290ID0gc2VhcmNoUm9vdCB8fCAodHlwZW9mIGRvY3VtZW50ICE9PSAndW5kZWZpbmVkJyA/IGRvY3VtZW50IDogbnVsbClcbiAgICAgICAgaWYgKCFzZWFyY2hSb290KSByZXR1cm4gW11cblxuICAgICAgICB2YXIgc2VsZWN0b3IgPSBrZXlcbiAgICAgICAgICAgID8gJ1tkYXRhLXBlcnNvbmFsaXplPVwiJyArIGtleSArICdcIl0nXG4gICAgICAgICAgICA6ICdbZGF0YS1wZXJzb25hbGl6ZV0nXG5cbiAgICAgICAgcmV0dXJuIHNlYXJjaFJvb3QucXVlcnlTZWxlY3RvckFsbChzZWxlY3RvcilcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBHZXQgdGVtcGxhdGUgZm9yIGEgZ2l2ZW4gaW50ZW50XG4gICAgICogVGVtcGxhdGVzIG11c3QgYmUgcHJvdmlkZWQgYnkgdGhlIHVzZXIgdmlhIG9wdGlvbnMudGVtcGxhdGVzXG4gICAgICogRmFsbHMgYmFjayB0byAnZGVmYXVsdCcgdGVtcGxhdGUgaWYgaW50ZW50IG5vdCBmb3VuZFxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBpbnRlbnQgLSBJbnRlbnQga2V5XG4gICAgICogQHBhcmFtIHtPYmplY3R9IHVzZXJUZW1wbGF0ZXMgLSBVc2VyLXByb3ZpZGVkIHRlbXBsYXRlcyAocmVxdWlyZWQpXG4gICAgICogQHJldHVybnMge09iamVjdHxudWxsfSAtIFRlbXBsYXRlIGRhdGEgb3IgbnVsbCBpZiBubyB0ZW1wbGF0ZXMgcHJvdmlkZWRcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBnZXRUZW1wbGF0ZShpbnRlbnQsIHVzZXJUZW1wbGF0ZXMpIHtcbiAgICAgICAgaWYgKCF1c2VyVGVtcGxhdGVzIHx8IHR5cGVvZiB1c2VyVGVtcGxhdGVzICE9PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgY29uc29sZS53YXJuKCdbTHVhIFBlcnNvbmFsaXplXSBObyB0ZW1wbGF0ZXMgcHJvdmlkZWQuIFRlbXBsYXRlcyBtdXN0IGJlIHBhc3NlZCB2aWEgb3B0aW9ucy50ZW1wbGF0ZXMnKVxuICAgICAgICAgICAgcmV0dXJuIG51bGxcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFRyeSB0byBnZXQgdGhlIGludGVudCB0ZW1wbGF0ZVxuICAgICAgICBpZiAodXNlclRlbXBsYXRlc1tpbnRlbnRdKSB7XG4gICAgICAgICAgICByZXR1cm4gdXNlclRlbXBsYXRlc1tpbnRlbnRdXG4gICAgICAgIH1cblxuICAgICAgICAvLyBGYWxsIGJhY2sgdG8gJ2RlZmF1bHQnIHRlbXBsYXRlIGlmIGF2YWlsYWJsZVxuICAgICAgICBpZiAodXNlclRlbXBsYXRlc1snZGVmYXVsdCddKSB7XG4gICAgICAgICAgICByZXR1cm4gdXNlclRlbXBsYXRlc1snZGVmYXVsdCddXG4gICAgICAgIH1cblxuICAgICAgICAvLyBJZiBubyBkZWZhdWx0LCByZXR1cm4gdGhlIGZpcnN0IGF2YWlsYWJsZSB0ZW1wbGF0ZVxuICAgICAgICB2YXIgZmlyc3RLZXkgPSBPYmplY3Qua2V5cyh1c2VyVGVtcGxhdGVzKVswXVxuICAgICAgICBpZiAoZmlyc3RLZXkpIHtcbiAgICAgICAgICAgIGNvbnNvbGUud2FybignW0x1YSBQZXJzb25hbGl6ZV0gSW50ZW50IFwiJyArIGludGVudCArICdcIiBub3QgZm91bmQsIHVzaW5nIGZpcnN0IGF2YWlsYWJsZSB0ZW1wbGF0ZTonLCBmaXJzdEtleSlcbiAgICAgICAgICAgIHJldHVybiB1c2VyVGVtcGxhdGVzW2ZpcnN0S2V5XVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG51bGxcbiAgICB9XG5cbiAgICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gICAgLy8gUmFuZG9tIEEvQiBGYWxsYmFjayAodXNlZCB3aGVuIG5vIFVUTSBwYXJhbXMgYXJlIHByZXNlbnQpXG4gICAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4gICAgLyoqXG4gICAgICogU2ltcGxlIHdlaWdodGVkIHJhbmRvbSBzZWxlY3Rpb24gZm9yIEEvQiBmYWxsYmFja1xuICAgICAqIEBwYXJhbSB7QXJyYXl9IG5hbWVzIC0gQXJyYXkgb2YgYnVja2V0L3RlbXBsYXRlIG5hbWVzXG4gICAgICogQHBhcmFtIHtBcnJheX0gd2VpZ2h0cyAtIENvcnJlc3BvbmRpbmcgd2VpZ2h0c1xuICAgICAqIEByZXR1cm5zIHtzdHJpbmd9IC0gU2VsZWN0ZWQgbmFtZVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIGNob29zZVdlaWdodGVkUmFuZG9tKG5hbWVzLCB3ZWlnaHRzKSB7XG4gICAgICAgIGlmIChuYW1lcy5sZW5ndGggIT09IHdlaWdodHMubGVuZ3RoKSByZXR1cm4gbmFtZXNbMF1cbiAgICAgICAgdmFyIHN1bSA9IDBcbiAgICAgICAgdmFyIGlcbiAgICAgICAgZm9yIChpID0gMDsgaSA8IHdlaWdodHMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIHN1bSArPSB3ZWlnaHRzW2ldXG4gICAgICAgIH1cbiAgICAgICAgdmFyIG4gPSBNYXRoLnJhbmRvbSgpICogc3VtXG4gICAgICAgIHZhciBsaW1pdCA9IDBcbiAgICAgICAgZm9yIChpID0gMDsgaSA8IG5hbWVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBsaW1pdCArPSB3ZWlnaHRzW2ldXG4gICAgICAgICAgICBpZiAobiA8PSBsaW1pdCkgcmV0dXJuIG5hbWVzW2ldXG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG5hbWVzW25hbWVzLmxlbmd0aCAtIDFdXG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0IGEgcmFuZG9tIHRlbXBsYXRlIGtleSBmcm9tIHVzZXItcHJvdmlkZWQgdGVtcGxhdGVzXG4gICAgICogVXNlZCBhcyBmYWxsYmFjayB3aGVuIG5vIFVUTS9yZWZlcnJlciBjb250ZXh0IGlzIGF2YWlsYWJsZVxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSB1c2VyVGVtcGxhdGVzIC0gVXNlci1wcm92aWRlZCB0ZW1wbGF0ZXMgKHJlcXVpcmVkKVxuICAgICAqIEByZXR1cm5zIHtzdHJpbmd8bnVsbH0gLSBSYW5kb20gdGVtcGxhdGUgaW50ZW50IGtleSBvciBudWxsIGlmIG5vIHRlbXBsYXRlc1xuICAgICAqL1xuICAgIGZ1bmN0aW9uIGdldFJhbmRvbUZhbGxiYWNrSW50ZW50KHVzZXJUZW1wbGF0ZXMpIHtcbiAgICAgICAgaWYgKCF1c2VyVGVtcGxhdGVzIHx8IHR5cGVvZiB1c2VyVGVtcGxhdGVzICE9PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgcmV0dXJuIG51bGxcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBuYW1lcyA9IE9iamVjdC5rZXlzKHVzZXJUZW1wbGF0ZXMpXG4gICAgICAgIGlmIChuYW1lcy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgIHJldHVybiBudWxsXG4gICAgICAgIH1cblxuICAgICAgICB2YXIgd2VpZ2h0cyA9IFtdXG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbmFtZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIHdlaWdodHMucHVzaCgxKSAvLyBFcXVhbCB3ZWlnaHQgYnkgZGVmYXVsdFxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBjaG9vc2VXZWlnaHRlZFJhbmRvbShuYW1lcywgd2VpZ2h0cylcbiAgICB9XG5cbiAgICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gICAgLy8gRGVjaXNpb24gRW5naW5lXG4gICAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4gICAgLyoqXG4gICAgICogUGVyc29uYWxpemF0aW9uIERlY2lzaW9uIEVuZ2luZVxuICAgICAqIERldGVybWluZXMgd2hpY2ggY29udGVudCB0byBzaG93IGJhc2VkIG9uIGNvbnRleHRcbiAgICAgKiBQcmlvcml0eTogQUkgKGlmIGVuYWJsZWQpIC0+IFVUTSBwYXJhbXMgLT4gUmVmZXJyZXIgLT4gUmFuZG9tIEEvQiBmYWxsYmFja1xuICAgICAqL1xuICAgIHZhciBEZWNpc2lvbkVuZ2luZSA9IHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIFN0YW5kYXJkIChub24tQUkpIGRlY2lzaW9uIGxvZ2ljXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBjb250ZXh0IC0gQ29udGV4dCBmcm9tIEx1YVVUTS5nZXRDb250ZXh0KClcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IFtvcHRpb25zXSAtIENvbmZpZ3VyYXRpb24gb3B0aW9uc1xuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gW29wdGlvbnMucnVsZXNdIC0gQ3VzdG9tIG1hdGNoaW5nIHJ1bGVzXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zLnRlbXBsYXRlcyAtIFVzZXItcHJvdmlkZWQgdGVtcGxhdGVzIChSRVFVSVJFRClcbiAgICAgICAgICogQHBhcmFtIHtib29sZWFufSBbb3B0aW9ucy5yYW5kb21GYWxsYmFja10gLSBFbmFibGUgcmFuZG9tIEEvQiBmYWxsYmFjayAoZGVmYXVsdDogdHJ1ZSlcbiAgICAgICAgICogQHJldHVybnMge09iamVjdH0gLSB7IHRlbXBsYXRlLCBpbnRlbnQsIHNvdXJjZSB9XG4gICAgICAgICAqL1xuICAgICAgICBzdGFuZGFyZERlY2lkZTogZnVuY3Rpb24gKGNvbnRleHQsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9XG4gICAgICAgICAgICB2YXIgY3VzdG9tUnVsZXMgPSBvcHRpb25zLnJ1bGVzIHx8IHt9XG4gICAgICAgICAgICB2YXIgdXNlclRlbXBsYXRlcyA9IG9wdGlvbnMudGVtcGxhdGVzXG4gICAgICAgICAgICB2YXIgZW5hYmxlUmFuZG9tRmFsbGJhY2sgPSBvcHRpb25zLnJhbmRvbUZhbGxiYWNrICE9PSBmYWxzZVxuXG4gICAgICAgICAgICAvLyBUZW1wbGF0ZXMgYXJlIHJlcXVpcmVkIC0gd2FybiBpZiBub3QgcHJvdmlkZWRcbiAgICAgICAgICAgIGlmICghdXNlclRlbXBsYXRlcyB8fCB0eXBlb2YgdXNlclRlbXBsYXRlcyAhPT0gJ29iamVjdCcgfHwgT2JqZWN0LmtleXModXNlclRlbXBsYXRlcykubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS53YXJuKCdbTHVhIFBlcnNvbmFsaXplXSBObyB0ZW1wbGF0ZXMgcHJvdmlkZWQuIFRlbXBsYXRlcyBtdXN0IGJlIHBhc3NlZCB2aWEgb3B0aW9ucy50ZW1wbGF0ZXMnKVxuICAgICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgICAgIHRlbXBsYXRlOiBudWxsLFxuICAgICAgICAgICAgICAgICAgICBpbnRlbnQ6ICdkZWZhdWx0JyxcbiAgICAgICAgICAgICAgICAgICAgc291cmNlOiAnZXJyb3InLFxuICAgICAgICAgICAgICAgICAgICBjb250ZXh0OiBjb250ZXh0LFxuICAgICAgICAgICAgICAgICAgICBlcnJvcjogJ05vIHRlbXBsYXRlcyBwcm92aWRlZCdcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciBpbnRlbnQgPSBjb250ZXh0LnByaW1hcnlJbnRlbnRcbiAgICAgICAgICAgIHZhciBzb3VyY2UgPSAnZGVmYXVsdCdcblxuICAgICAgICAgICAgLy8gRGV0ZXJtaW5lIHRoZSBzb3VyY2Ugb2YgdGhlIGRlY2lzaW9uXG4gICAgICAgICAgICBpZiAoY29udGV4dC5oYXNVVE0pIHtcbiAgICAgICAgICAgICAgICBzb3VyY2UgPSAndXRtJ1xuICAgICAgICAgICAgfSBlbHNlIGlmIChjb250ZXh0LnJlZmVycmVyICYmIGNvbnRleHQucmVmZXJyZXIuY2F0ZWdvcnkgIT09ICdkaXJlY3QnKSB7XG4gICAgICAgICAgICAgICAgc291cmNlID0gJ3JlZmVycmVyJ1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBDaGVjayBjdXN0b20gcnVsZXMgZmlyc3QgKGhpZ2hlc3QgcHJpb3JpdHkpXG4gICAgICAgICAgICBmb3IgKHZhciBydWxlS2V5IGluIGN1c3RvbVJ1bGVzKSB7XG4gICAgICAgICAgICAgICAgdmFyIHJ1bGUgPSBjdXN0b21SdWxlc1tydWxlS2V5XVxuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgcnVsZS5tYXRjaCA9PT0gJ2Z1bmN0aW9uJyAmJiBydWxlLm1hdGNoKGNvbnRleHQpKSB7XG4gICAgICAgICAgICAgICAgICAgIGludGVudCA9IHJ1bGUuaW50ZW50IHx8IHJ1bGVLZXlcbiAgICAgICAgICAgICAgICAgICAgc291cmNlID0gJ2N1c3RvbS1ydWxlJ1xuICAgICAgICAgICAgICAgICAgICBicmVha1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gSWYgaW50ZW50IGlzIHN0aWxsICdkZWZhdWx0JyBhbmQgcmFuZG9tIGZhbGxiYWNrIGlzIGVuYWJsZWQsXG4gICAgICAgICAgICAvLyBwaWNrIGEgcmFuZG9tIHRlbXBsYXRlIGZvciBBL0IgdGVzdGluZ1xuICAgICAgICAgICAgaWYgKGludGVudCA9PT0gJ2RlZmF1bHQnICYmIHNvdXJjZSA9PT0gJ2RlZmF1bHQnICYmIGVuYWJsZVJhbmRvbUZhbGxiYWNrKSB7XG4gICAgICAgICAgICAgICAgdmFyIHJhbmRvbUludGVudCA9IGdldFJhbmRvbUZhbGxiYWNrSW50ZW50KHVzZXJUZW1wbGF0ZXMpXG4gICAgICAgICAgICAgICAgaWYgKHJhbmRvbUludGVudCkge1xuICAgICAgICAgICAgICAgICAgICBpbnRlbnQgPSByYW5kb21JbnRlbnRcbiAgICAgICAgICAgICAgICAgICAgc291cmNlID0gJ3JhbmRvbS1hYidcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIFJlY29yZCB2aXNpdCB0byBoaXN0b3J5IGlmIEx1YVdlaWdodGVkSGlzdG9yeSBpcyBhdmFpbGFibGVcbiAgICAgICAgICAgIGlmIChyb290Lkx1YVdlaWdodGVkSGlzdG9yeSAmJiB0eXBlb2Ygcm9vdC5MdWFXZWlnaHRlZEhpc3RvcnkucmVjb3JkVmlzaXQgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICAgICAgICByb290Lkx1YVdlaWdodGVkSGlzdG9yeS5yZWNvcmRWaXNpdCh7XG4gICAgICAgICAgICAgICAgICAgIGNvbnRleHQ6IGNvbnRleHQsXG4gICAgICAgICAgICAgICAgICAgIGludGVudDogaW50ZW50LFxuICAgICAgICAgICAgICAgICAgICBzZWxlY3RlZFZhcmlhbnQ6IGludGVudCxcbiAgICAgICAgICAgICAgICAgICAgc291cmNlOiBzb3VyY2UsXG4gICAgICAgICAgICAgICAgICAgIGFpRGVjaXNpb246IGZhbHNlXG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICB0ZW1wbGF0ZTogZ2V0VGVtcGxhdGUoaW50ZW50LCB1c2VyVGVtcGxhdGVzKSxcbiAgICAgICAgICAgICAgICBpbnRlbnQ6IGludGVudCxcbiAgICAgICAgICAgICAgICBzb3VyY2U6IHNvdXJjZSxcbiAgICAgICAgICAgICAgICBjb250ZXh0OiBjb250ZXh0XG4gICAgICAgICAgICB9XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIE1haW4gZGVjaWRlIGZ1bmN0aW9uIC0gcm91dGVzIHRvIEFJIG9yIHN0YW5kYXJkIGVuZ2luZVxuICAgICAgICAgKiBAcGFyYW0ge09iamVjdH0gY29udGV4dCAtIENvbnRleHQgZnJvbSBMdWFVVE0uZ2V0Q29udGV4dCgpXG4gICAgICAgICAqIEBwYXJhbSB7T2JqZWN0fSBbb3B0aW9uc10gLSBDb25maWd1cmF0aW9uIG9wdGlvbnNcbiAgICAgICAgICogQHBhcmFtIHtib29sZWFufSBbb3B0aW9ucy5lbmFibGVBSV0gLSBFbmFibGUgQUktcG93ZXJlZCBkZWNpc2lvbnNcbiAgICAgICAgICogQHBhcmFtIHtPYmplY3R9IFtvcHRpb25zLmFpQ29uZmlnXSAtIEFJIGNvbmZpZ3VyYXRpb25cbiAgICAgICAgICogQHJldHVybnMge09iamVjdHxQcm9taXNlPE9iamVjdD59IC0gRGVjaXNpb24gcmVzdWx0IChQcm9taXNlIGlmIEFJIGVuYWJsZWQpXG4gICAgICAgICAqL1xuICAgICAgICBkZWNpZGU6IGZ1bmN0aW9uIChjb250ZXh0LCBvcHRpb25zKSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fVxuXG4gICAgICAgICAgICAvLyBJZiBBSSBpcyBlbmFibGVkIGFuZCBjb25maWd1cmVkLCB0cnkgQUkgZGVjaXNpb24gZmlyc3RcbiAgICAgICAgICAgIGlmIChvcHRpb25zLmVuYWJsZUFJICYmIG9wdGlvbnMuYWlDb25maWcgJiYgcm9vdC5MdWFBSVBlcnNvbmFsaXplKSB7XG4gICAgICAgICAgICAgICAgdmFyIHNlbGYgPSB0aGlzXG4gICAgICAgICAgICAgICAgdmFyIGFpTW9kdWxlID0gcm9vdC5MdWFBSVBlcnNvbmFsaXplXG4gICAgICAgICAgICAgICAgdmFyIHJlYWRpbmVzcyA9IGFpTW9kdWxlLmlzUmVhZHkob3B0aW9ucy5haUNvbmZpZylcblxuICAgICAgICAgICAgICAgIGlmIChyZWFkaW5lc3MucmVhZHkpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGFpTW9kdWxlLmRlY2lkZShjb250ZXh0LCBvcHRpb25zKVxuICAgICAgICAgICAgICAgICAgICAgICAgLmNhdGNoKGZ1bmN0aW9uIChlcnJvcikge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEFJIGZhaWxlZCAtIGZhbGwgYmFjayB0byBzdGFuZGFyZCBlbmdpbmVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgZmFsbGJhY2sgPSBvcHRpb25zLmFpQ29uZmlnLmZhbGxiYWNrVG9TdGFuZGFyZCAhPT0gZmFsc2VcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoZmFsbGJhY2spIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc29sZS53YXJuKCdbTHVhIFBlcnNvbmFsaXplXSBBSSBmYWlsZWQsIHVzaW5nIHN0YW5kYXJkIGVuZ2luZTonLCBlcnJvci5tZXNzYWdlKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gc2VsZi5zdGFuZGFyZERlY2lkZShjb250ZXh0LCBvcHRpb25zKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aHJvdyBlcnJvclxuICAgICAgICAgICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oJ1tMdWEgUGVyc29uYWxpemVdIEFJIG5vdCByZWFkeTonLCByZWFkaW5lc3MuZXJyb3IsICctIHVzaW5nIHN0YW5kYXJkIGVuZ2luZScpXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBTdGFuZGFyZCBkZWNpc2lvbiAoc3luY2hyb25vdXMpXG4gICAgICAgICAgICByZXR1cm4gdGhpcy5zdGFuZGFyZERlY2lkZShjb250ZXh0LCBvcHRpb25zKVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICAgIC8vIFBlcnNvbmFsaXphdGlvbiBBcHBsaWNhdGlvblxuICAgIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuICAgIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgICAvLyBET00gQXBwbGljYXRpb24gKGV4dHJhY3RlZCBmb3IgcmV1c2UgYnkgYm90aCBzeW5jIGFuZCBhc3luYyBwYXRocylcbiAgICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbiAgICAvKipcbiAgICAgKiBBcHBseSBhIGRlY2lzaW9uIHRvIHRoZSBET01cbiAgICAgKiBJbmplY3RzIGNvbnRlbnQgaW50byBlbGVtZW50cyB3aXRoIGRhdGEtcGVyc29uYWxpemUgYXR0cmlidXRlc1xuICAgICAqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGRlY2lzaW9uIC0gRGVjaXNpb24gb2JqZWN0IHsgdGVtcGxhdGUsIGludGVudCwgc291cmNlLCBjb250ZXh0IH1cbiAgICAgKiBAcGFyYW0ge09iamVjdH0gW29wdGlvbnNdIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zXG4gICAgICogQHBhcmFtIHtib29sZWFufSBbb3B0aW9ucy5sb2ddIC0gRW5hYmxlIGNvbnNvbGUgbG9nZ2luZ1xuICAgICAqIEByZXR1cm5zIHtPYmplY3R9IC0gVGhlIGRlY2lzaW9uIChwYXNzLXRocm91Z2gpXG4gICAgICovXG4gICAgZnVuY3Rpb24gYXBwbHlEZWNpc2lvblRvRE9NKGRlY2lzaW9uLCBvcHRpb25zKSB7XG4gICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9XG4gICAgICAgIHZhciB0ZW1wbGF0ZSA9IGRlY2lzaW9uLnRlbXBsYXRlXG4gICAgICAgIHZhciBjb250ZXh0ID0gZGVjaXNpb24uY29udGV4dCB8fCB7fVxuICAgICAgICB2YXIgbG9nID0gb3B0aW9ucy5sb2cgIT09IGZhbHNlXG5cbiAgICAgICAgaWYgKCF0ZW1wbGF0ZSkge1xuICAgICAgICAgICAgY29uc29sZS53YXJuKCdbTHVhIFBlcnNvbmFsaXplXSBObyB0ZW1wbGF0ZSBpbiBkZWNpc2lvbiwgc2tpcHBpbmcgRE9NIHVwZGF0ZScpXG4gICAgICAgICAgICByZXR1cm4gZGVjaXNpb25cbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEZpbmQgYW5kIHVwZGF0ZSBlYWNoIHBlcnNvbmFsaXplIHNsb3QgaW4gdGhlIERPTVxuICAgICAgICB2YXIgc2xvdHMgPSBbJ2ltYWdlJywgJ2hlYWRsaW5lJywgJ3N1YmhlYWRsaW5lJywgJ2N0YUxhYmVsJywgJ2N0YUxpbmsnXVxuXG4gICAgICAgIHNsb3RzLmZvckVhY2goZnVuY3Rpb24gKHNsb3QpIHtcbiAgICAgICAgICAgIHZhciBlbGVtZW50cyA9IGZpbmRQZXJzb25hbGl6ZUVsZW1lbnRzKHNsb3QpXG5cbiAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgZWxlbWVudHMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICB2YXIgZWxlbWVudCA9IGVsZW1lbnRzW2ldXG4gICAgICAgICAgICAgICAgdmFyIHZhbHVlID0gdGVtcGxhdGVbc2xvdF1cbiAgICAgICAgICAgICAgICBpZiAoIXZhbHVlKSBjb250aW51ZVxuXG4gICAgICAgICAgICAgICAgaWYgKHNsb3QgPT09ICdpbWFnZScpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gRm9yIGltYWdlcywgc2V0IGJhY2tncm91bmQtaW1hZ2Ugb3Igc3JjIGF0dHJpYnV0ZVxuICAgICAgICAgICAgICAgICAgICBpZiAoZWxlbWVudC50YWdOYW1lID09PSAnSU1HJykge1xuICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudC5zcmMgPSB2YWx1ZVxuICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudC5hbHQgPSB0ZW1wbGF0ZS5oZWFkbGluZSB8fCAnUGVyc29uYWxpemVkIGltYWdlJ1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudC5zdHlsZS5iYWNrZ3JvdW5kSW1hZ2UgPSAndXJsKCcgKyB2YWx1ZSArICcpJ1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmIChzbG90ID09PSAnY3RhTGluaycpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gRm9yIGxpbmtzLCBzZXQgaHJlZiBhdHRyaWJ1dGVcbiAgICAgICAgICAgICAgICAgICAgZWxlbWVudC5ocmVmID0gdmFsdWVcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAvLyBGb3IgdGV4dCBjb250ZW50LCB1c2UgdGV4dENvbnRlbnQgKHNhZmUsIG5vIEhUTUwgcGFyc2luZylcbiAgICAgICAgICAgICAgICAgICAgc2FmZVNldFRleHQoZWxlbWVudCwgdmFsdWUpXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9KVxuXG4gICAgICAgIC8vIEFwcGx5IHRvIGdlbmVyaWMgJ2hlcm8nIHNlY3Rpb25zIHdpdGggZGF0YS1wZXJzb25hbGl6ZT1cImhlcm9cIlxuICAgICAgICB2YXIgaGVyb0VsZW1lbnRzID0gZmluZFBlcnNvbmFsaXplRWxlbWVudHMoJ2hlcm8nKVxuICAgICAgICBmb3IgKHZhciBoID0gMDsgaCA8IGhlcm9FbGVtZW50cy5sZW5ndGg7IGgrKykge1xuICAgICAgICAgICAgdmFyIGhlcm9FbCA9IGhlcm9FbGVtZW50c1toXVxuICAgICAgICAgICAgaGVyb0VsLnNldEF0dHJpYnV0ZSgnZGF0YS1pbnRlbnQnLCBkZWNpc2lvbi5pbnRlbnQpXG4gICAgICAgICAgICBoZXJvRWwuc2V0QXR0cmlidXRlKCdkYXRhLXNvdXJjZScsIGRlY2lzaW9uLnNvdXJjZSlcblxuICAgICAgICAgICAgLy8gSWYgaGVybyBoYXMgYSBiYWNrZ3JvdW5kIGltYWdlIHNsb3QsIGFwcGx5IGl0XG4gICAgICAgICAgICBpZiAodGVtcGxhdGUuaW1hZ2UgJiYgIWhlcm9FbC5xdWVyeVNlbGVjdG9yKCdbZGF0YS1wZXJzb25hbGl6ZT1cImltYWdlXCJdJykpIHtcbiAgICAgICAgICAgICAgICBoZXJvRWwuc3R5bGUuYmFja2dyb3VuZEltYWdlID0gJ3VybCgnICsgdGVtcGxhdGUuaW1hZ2UgKyAnKSdcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIC8vIExvZyB0aGUgcGVyc29uYWxpemF0aW9uIGRlY2lzaW9uIChmb3IgZGVidWdnaW5nL2RlbW8pXG4gICAgICAgIGlmIChsb2cgJiYgdHlwZW9mIGNvbnNvbGUgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZygnW0x1YSBQZXJzb25hbGl6ZV0gQXBwbGllZDonLCB7XG4gICAgICAgICAgICAgICAgaW50ZW50OiBkZWNpc2lvbi5pbnRlbnQsXG4gICAgICAgICAgICAgICAgc291cmNlOiBkZWNpc2lvbi5zb3VyY2UsXG4gICAgICAgICAgICAgICAgaGVhZGxpbmU6IHRlbXBsYXRlLmhlYWRsaW5lLFxuICAgICAgICAgICAgICAgIGhhc1VUTTogY29udGV4dC5oYXNVVE0sXG4gICAgICAgICAgICAgICAgdXRtUGFyYW1zOiBjb250ZXh0LnV0bSB8fCB7fSxcbiAgICAgICAgICAgICAgICBhaVBvd2VyZWQ6IGRlY2lzaW9uLnNvdXJjZSA9PT0gJ2FpJyB8fCBkZWNpc2lvbi5zb3VyY2UgPT09ICdhaS1jYWNoZWQnXG4gICAgICAgICAgICB9KVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGRlY2lzaW9uXG4gICAgfVxuXG4gICAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICAgIC8vIENvbnRleHQgUmVzb2x1dGlvblxuICAgIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuICAgIC8qKlxuICAgICAqIFJlc29sdmUgY29udGV4dCBmcm9tIGF2YWlsYWJsZSBzb3VyY2VzXG4gICAgICogQHBhcmFtIHtPYmplY3R9IFtvcHRpb25zXSAtIE9wdGlvbnMgd2l0aCBvcHRpb25hbCBjb250ZXh0XG4gICAgICogQHJldHVybnMge09iamVjdH0gLSBSZXNvbHZlZCBjb250ZXh0XG4gICAgICovXG4gICAgZnVuY3Rpb24gcmVzb2x2ZUNvbnRleHQob3B0aW9ucykge1xuICAgICAgICBpZiAob3B0aW9ucyAmJiBvcHRpb25zLmNvbnRleHQpIHtcbiAgICAgICAgICAgIHJldHVybiBvcHRpb25zLmNvbnRleHRcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChyb290Lkx1YVVUTSAmJiB0eXBlb2Ygcm9vdC5MdWFVVE0uZ2V0Q29udGV4dCA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgcmV0dXJuIHJvb3QuTHVhVVRNLmdldENvbnRleHQoKVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gTm8gVVRNIG1vZHVsZSBhdmFpbGFibGUgLSBjcmVhdGUgbWluaW1hbCBkZWZhdWx0IGNvbnRleHRcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHV0bToge30sXG4gICAgICAgICAgICByZWZlcnJlcjogeyBzb3VyY2U6ICdkaXJlY3QnLCBjYXRlZ29yeTogJ2RpcmVjdCcsIHVybDogJycgfSxcbiAgICAgICAgICAgIHVzZXJBZ2VudDogeyByYXc6ICcnLCBpc01vYmlsZTogZmFsc2UsIGlzVGFibGV0OiBmYWxzZSwgaXNEZXNrdG9wOiB0cnVlIH0sXG4gICAgICAgICAgICB0aW1lc3RhbXA6IERhdGUubm93KCksXG4gICAgICAgICAgICBoYXNVVE06IGZhbHNlLFxuICAgICAgICAgICAgcHJpbWFyeUludGVudDogJ2RlZmF1bHQnXG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gICAgLy8gTWFpbiBQZXJzb25hbGl6YXRpb24gRnVuY3Rpb25zXG4gICAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4gICAgLyoqXG4gICAgICogQXBwbHkgcGVyc29uYWxpemF0aW9uIHRvIHRoZSBwYWdlIHZpYSBkYXRhLXBlcnNvbmFsaXplIGF0dHJpYnV0ZXNcbiAgICAgKiBNYWluIGVudHJ5IHBvaW50IGZvciBwZXJzb25hbGl6YXRpb25cbiAgICAgKlxuICAgICAqIFN1cHBvcnRlZCBkYXRhLXBlcnNvbmFsaXplIHZhbHVlczpcbiAgICAgKiAgIC0gXCJoZXJvXCIgICAgICAgIDogR2VuZXJpYyBoZXJvIHNlY3Rpb24gKHNldHMgZGF0YS1pbnRlbnQsIGRhdGEtc291cmNlKVxuICAgICAqICAgLSBcImltYWdlXCIgICAgICAgOiBJbWFnZSBzbG90IChzZXRzIHNyYyBvciBiYWNrZ3JvdW5kLWltYWdlKVxuICAgICAqICAgLSBcImhlYWRsaW5lXCIgICAgOiBIZWFkbGluZSB0ZXh0XG4gICAgICogICAtIFwic3ViaGVhZGxpbmVcIiA6IFN1YmhlYWRsaW5lIHRleHRcbiAgICAgKiAgIC0gXCJjdGFMYWJlbFwiICAgIDogQ1RBIGJ1dHRvbiB0ZXh0XG4gICAgICogICAtIFwiY3RhTGlua1wiICAgICA6IENUQSBsaW5rIGhyZWZcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBbb3B0aW9uc10gLSBDb25maWd1cmF0aW9uIG9wdGlvbnNcbiAgICAgKiBAcGFyYW0ge09iamVjdH0gW29wdGlvbnMuY29udGV4dF0gLSBQcmUtY29tcHV0ZWQgVVRNIGNvbnRleHRcbiAgICAgKiBAcGFyYW0ge09iamVjdH0gW29wdGlvbnMucnVsZXNdIC0gQ3VzdG9tIG1hdGNoaW5nIHJ1bGVzXG4gICAgICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMudGVtcGxhdGVzIC0gVXNlci1wcm92aWRlZCB0ZW1wbGF0ZXMgKFJFUVVJUkVEKVxuICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gW29wdGlvbnMuZW5hYmxlQUldIC0gRW5hYmxlIEFJLXBvd2VyZWQgZGVjaXNpb25zXG4gICAgICogQHBhcmFtIHtPYmplY3R9IFtvcHRpb25zLmFpQ29uZmlnXSAtIEFJIGNvbmZpZ3VyYXRpb24gKHJlcXVpcmVkIGlmIGVuYWJsZUFJIGlzIHRydWUpXG4gICAgICogQHBhcmFtIHtib29sZWFufSBbb3B0aW9ucy5yYW5kb21GYWxsYmFja10gLSBFbmFibGUgcmFuZG9tIEEvQiBmYWxsYmFjayAoZGVmYXVsdDogdHJ1ZSlcbiAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRpb25zLmxvZ10gLSBFbmFibGUgY29uc29sZSBsb2dnaW5nIChkZWZhdWx0OiB0cnVlKVxuICAgICAqIEByZXR1cm5zIHtPYmplY3R8UHJvbWlzZTxPYmplY3Q+fSAtIFJlc3VsdCB3aXRoIGFwcGxpZWQgZGVjaXNpb24gKFByb21pc2UgaWYgQUkgZW5hYmxlZClcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBwZXJzb25hbGl6ZShvcHRpb25zKSB7XG4gICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9XG5cbiAgICAgICAgLy8gVGVtcGxhdGVzIGFyZSByZXF1aXJlZFxuICAgICAgICBpZiAoIW9wdGlvbnMudGVtcGxhdGVzIHx8IHR5cGVvZiBvcHRpb25zLnRlbXBsYXRlcyAhPT0gJ29iamVjdCcgfHwgT2JqZWN0LmtleXMob3B0aW9ucy50ZW1wbGF0ZXMpLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcignW0x1YSBQZXJzb25hbGl6ZV0gVGVtcGxhdGVzIGFyZSByZXF1aXJlZC4gUHJvdmlkZSB0ZW1wbGF0ZXMgdmlhIG9wdGlvbnMudGVtcGxhdGVzJylcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgdGVtcGxhdGU6IG51bGwsXG4gICAgICAgICAgICAgICAgaW50ZW50OiAnZGVmYXVsdCcsXG4gICAgICAgICAgICAgICAgc291cmNlOiAnZXJyb3InLFxuICAgICAgICAgICAgICAgIGNvbnRleHQ6IHt9LFxuICAgICAgICAgICAgICAgIGVycm9yOiAnTm8gdGVtcGxhdGVzIHByb3ZpZGVkJ1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGNvbnRleHQgPSByZXNvbHZlQ29udGV4dChvcHRpb25zKVxuICAgICAgICB2YXIgZGVjaXNpb24gPSBEZWNpc2lvbkVuZ2luZS5kZWNpZGUoY29udGV4dCwgb3B0aW9ucylcblxuICAgICAgICAvLyBJZiBkZWNpc2lvbiBpcyBhIFByb21pc2UgKEFJIHBhdGgpLCBoYW5kbGUgYXN5bmMgZmxvd1xuICAgICAgICBpZiAoZGVjaXNpb24gJiYgdHlwZW9mIGRlY2lzaW9uLnRoZW4gPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICAgIHJldHVybiBkZWNpc2lvbi50aGVuKGZ1bmN0aW9uIChhaURlY2lzaW9uKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGFwcGx5RGVjaXNpb25Ub0RPTShhaURlY2lzaW9uLCBvcHRpb25zKVxuICAgICAgICAgICAgfSkuY2F0Y2goZnVuY3Rpb24gKGVycikge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybignW0x1YSBQZXJzb25hbGl6ZV0gQUkgZGVjaXNpb24gZmFpbGVkLCB1c2luZyBzdGFuZGFyZDonLCBlcnIubWVzc2FnZSlcbiAgICAgICAgICAgICAgICAvLyBGYWxsYmFjayB0byBzdGFuZGFyZCBkZWNpc2lvbiArIERPTSBhcHBsaWNhdGlvblxuICAgICAgICAgICAgICAgIHZhciBmYWxsYmFja0RlY2lzaW9uID0gRGVjaXNpb25FbmdpbmUuc3RhbmRhcmREZWNpZGUoY29udGV4dCwgb3B0aW9ucylcbiAgICAgICAgICAgICAgICByZXR1cm4gYXBwbHlEZWNpc2lvblRvRE9NKGZhbGxiYWNrRGVjaXNpb24sIG9wdGlvbnMpXG4gICAgICAgICAgICB9KVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gU3luY2hyb25vdXMgcGF0aCAoc3RhbmRhcmQgZW5naW5lKVxuICAgICAgICByZXR1cm4gYXBwbHlEZWNpc2lvblRvRE9NKGRlY2lzaW9uLCBvcHRpb25zKVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEFzeW5jIHBlcnNvbmFsaXphdGlvbiB3aXRoIHRpbWVvdXQgZmFsbGJhY2tcbiAgICAgKiBVc2VzIEx1YVVUTS5nZXRDb250ZXh0QXN5bmMgZm9yIG5vbi1ibG9ja2luZyBVVE0gZXh0cmFjdGlvblxuICAgICAqIEF1dG9tYXRpY2FsbHkgaGFuZGxlcyBBSSBkZWNpc2lvbnMgKHdoaWNoIGFyZSBhbHdheXMgYXN5bmMpXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge09iamVjdH0gW29wdGlvbnNdIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zXG4gICAgICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gLSBSZXN1bHQgd2l0aCBhcHBsaWVkIGRlY2lzaW9uXG4gICAgICovXG4gICAgZnVuY3Rpb24gcGVyc29uYWxpemVBc3luYyhvcHRpb25zKSB7XG4gICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9XG5cbiAgICAgICAgLy8gVXNlIGFzeW5jIGNvbnRleHQgZ2V0dGVyIGlmIGF2YWlsYWJsZVxuICAgICAgICBpZiAocm9vdC5MdWFVVE0gJiYgdHlwZW9mIHJvb3QuTHVhVVRNLmdldENvbnRleHRBc3luYyA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgcmV0dXJuIHJvb3QuTHVhVVRNLmdldENvbnRleHRBc3luYyhvcHRpb25zKS50aGVuKGZ1bmN0aW9uIChjb250ZXh0KSB7XG4gICAgICAgICAgICAgICAgb3B0aW9ucy5jb250ZXh0ID0gY29udGV4dFxuICAgICAgICAgICAgICAgIHJldHVybiBwZXJzb25hbGl6ZShvcHRpb25zKVxuICAgICAgICAgICAgfSkudGhlbihmdW5jdGlvbiAoZGVjaXNpb24pIHtcbiAgICAgICAgICAgICAgICAvLyBFbnN1cmUgd2UgYWx3YXlzIHJldHVybiBhIHJlc29sdmVkIHByb21pc2VcbiAgICAgICAgICAgICAgICByZXR1cm4gZGVjaXNpb25cbiAgICAgICAgICAgIH0pLmNhdGNoKGZ1bmN0aW9uIChlcnIpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oJ1tMdWEgUGVyc29uYWxpemVdIEFzeW5jIGVycm9yLCB1c2luZyBkZWZhdWx0OicsIGVycilcbiAgICAgICAgICAgICAgICAvLyBGb3JjZSBzdGFuZGFyZCBlbmdpbmUgZmFsbGJhY2tcbiAgICAgICAgICAgICAgICB2YXIgZmFsbGJhY2tPcHRpb25zID0ge1xuICAgICAgICAgICAgICAgICAgICB0ZW1wbGF0ZXM6IG9wdGlvbnMudGVtcGxhdGVzLFxuICAgICAgICAgICAgICAgICAgICBjb250ZXh0OiByZXNvbHZlQ29udGV4dChvcHRpb25zKSxcbiAgICAgICAgICAgICAgICAgICAgbG9nOiBvcHRpb25zLmxvZ1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB2YXIgZmFsbGJhY2tEZWNpc2lvbiA9IERlY2lzaW9uRW5naW5lLnN0YW5kYXJkRGVjaWRlKGZhbGxiYWNrT3B0aW9ucy5jb250ZXh0LCBmYWxsYmFja09wdGlvbnMpXG4gICAgICAgICAgICAgICAgcmV0dXJuIGFwcGx5RGVjaXNpb25Ub0RPTShmYWxsYmFja0RlY2lzaW9uLCBmYWxsYmFja09wdGlvbnMpXG4gICAgICAgICAgICB9KVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gV3JhcCBzeW5jaHJvbm91cy9BSSBwZXJzb25hbGl6YXRpb24gaW4gYSBwcm9taXNlXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICB2YXIgcmVzdWx0ID0gcGVyc29uYWxpemUob3B0aW9ucylcbiAgICAgICAgICAgIC8vIElmIHJlc3VsdCBpcyBhIHByb21pc2UgKEFJIHBhdGgpLCByZXR1cm4gaXQgZGlyZWN0bHlcbiAgICAgICAgICAgIGlmIChyZXN1bHQgJiYgdHlwZW9mIHJlc3VsdC50aGVuID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJlc3VsdFxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZShyZXN1bHQpXG4gICAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAgICAgY29uc29sZS53YXJuKCdbTHVhIFBlcnNvbmFsaXplXSBFcnJvciwgdXNpbmcgZGVmYXVsdDonLCBlcnIpXG4gICAgICAgICAgICB2YXIgZGVmYXVsdENvbnRleHQgPSB7XG4gICAgICAgICAgICAgICAgdXRtOiB7fSxcbiAgICAgICAgICAgICAgICByZWZlcnJlcjogeyBzb3VyY2U6ICdkaXJlY3QnLCBjYXRlZ29yeTogJ2RpcmVjdCcsIHVybDogJycgfSxcbiAgICAgICAgICAgICAgICB1c2VyQWdlbnQ6IHsgcmF3OiAnJywgaXNNb2JpbGU6IGZhbHNlLCBpc1RhYmxldDogZmFsc2UsIGlzRGVza3RvcDogdHJ1ZSB9LFxuICAgICAgICAgICAgICAgIHRpbWVzdGFtcDogRGF0ZS5ub3coKSxcbiAgICAgICAgICAgICAgICBoYXNVVE06IGZhbHNlLFxuICAgICAgICAgICAgICAgIHByaW1hcnlJbnRlbnQ6ICdkZWZhdWx0J1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIGZhbGxiYWNrID0gRGVjaXNpb25FbmdpbmUuc3RhbmRhcmREZWNpZGUoZGVmYXVsdENvbnRleHQsIHsgdGVtcGxhdGVzOiBvcHRpb25zLnRlbXBsYXRlcyB9KVxuICAgICAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZShhcHBseURlY2lzaW9uVG9ET00oZmFsbGJhY2ssIG9wdGlvbnMpKVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQXV0by1pbml0aWFsaXplIHBlcnNvbmFsaXphdGlvbiB3aGVuIERPTSBpcyByZWFkeVxuICAgICAqIFNjYW5zIGZvciBkYXRhLXBlcnNvbmFsaXplIGF0dHJpYnV0ZXMgYW5kIGFwcGxpZXMgY29udGVudFxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBbb3B0aW9uc10gLSBDb25maWd1cmF0aW9uIG9wdGlvbnNcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBhdXRvSW5pdChvcHRpb25zKSB7XG4gICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9XG5cbiAgICAgICAgZnVuY3Rpb24gcnVuKCkge1xuICAgICAgICAgICAgLy8gQ2hlY2sgaWYgdGhlcmUgYXJlIGFueSBkYXRhLXBlcnNvbmFsaXplIGVsZW1lbnRzIG9uIHRoZSBwYWdlXG4gICAgICAgICAgICB2YXIgZWxlbWVudHMgPSBmaW5kUGVyc29uYWxpemVFbGVtZW50cygpXG4gICAgICAgICAgICBpZiAoZWxlbWVudHMubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgIHBlcnNvbmFsaXplKG9wdGlvbnMpXG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvLyBXYWl0IGZvciBET00gcmVhZHlcbiAgICAgICAgaWYgKHR5cGVvZiBkb2N1bWVudCAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgICAgIGlmIChkb2N1bWVudC5yZWFkeVN0YXRlID09PSAnbG9hZGluZycpIHtcbiAgICAgICAgICAgICAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCdET01Db250ZW50TG9hZGVkJywgcnVuKVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBydW4oKVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICAgIC8vIFB1YmxpYyBBUEkgLSBSZWdpc3RlciBvbiB3aW5kb3cuTHVhUGVyc29uYWxpemVcbiAgICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbiAgICB2YXIgTHVhUGVyc29uYWxpemUgPSB7XG4gICAgICAgIC8vIE5vdGU6IFRlbXBsYXRlcyBhcmUgTk9UIHByb3ZpZGVkIGJ5IHRoaXMgcGFja2FnZVxuICAgICAgICAvLyBVc2VycyBtdXN0IHByb3ZpZGUgdGhlaXIgb3duIHRlbXBsYXRlcyB2aWEgb3B0aW9ucy50ZW1wbGF0ZXNcbiAgICAgICAgc2FuaXRpemVyOiBTYW5pdGl6ZXIsXG4gICAgICAgIHNhbml0aXplSFRNTDogZnVuY3Rpb24gKGh0bWwpIHsgcmV0dXJuIFNhbml0aXplci5zYW5pdGl6ZShodG1sKSB9LFxuICAgICAgICBzYWZlU2V0VGV4dDogc2FmZVNldFRleHQsXG4gICAgICAgIHNhZmVTZXRIVE1MOiBzYWZlU2V0SFRNTCxcbiAgICAgICAgZmluZEVsZW1lbnRzOiBmaW5kUGVyc29uYWxpemVFbGVtZW50cyxcbiAgICAgICAgZ2V0VGVtcGxhdGU6IGdldFRlbXBsYXRlLFxuICAgICAgICBlbmdpbmU6IERlY2lzaW9uRW5naW5lLFxuICAgICAgICBwZXJzb25hbGl6ZTogcGVyc29uYWxpemUsXG4gICAgICAgIHBlcnNvbmFsaXplQXN5bmM6IHBlcnNvbmFsaXplQXN5bmMsXG4gICAgICAgIGF1dG9Jbml0OiBhdXRvSW5pdCxcbiAgICAgICAgY2hvb3NlV2VpZ2h0ZWRSYW5kb206IGNob29zZVdlaWdodGVkUmFuZG9tLFxuICAgICAgICBnZXRSYW5kb21GYWxsYmFja0ludGVudDogZ2V0UmFuZG9tRmFsbGJhY2tJbnRlbnQsXG4gICAgICAgIGFwcGx5RGVjaXNpb25Ub0RPTTogYXBwbHlEZWNpc2lvblRvRE9NLFxuICAgICAgICByZXNvbHZlQ29udGV4dDogcmVzb2x2ZUNvbnRleHRcbiAgICB9XG5cbiAgICAvLyBFeHBvc2UgZ2xvYmFsbHlcbiAgICByb290Lkx1YVBlcnNvbmFsaXplID0gTHVhUGVyc29uYWxpemVcblxufSkodHlwZW9mIHdpbmRvdyAhPT0gJ3VuZGVmaW5lZCcgPyB3aW5kb3cgOiB0eXBlb2YgZ2xvYmFsICE9PSAndW5kZWZpbmVkJyA/IGdsb2JhbCA6IHRoaXMpXG4iXSwibWFwcGluZ3MiOiI7Ozs7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUFDLENBQUMsVUFBVUEsSUFBSSxFQUFFO0VBQ2QsWUFBWTs7RUFFWjtFQUNBO0VBQ0E7RUFDQTs7RUFFQTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0VBQ0ksSUFBSUMsU0FBUyxHQUFJLFlBQVk7SUFFekI7SUFDQSxJQUFJQyxZQUFZLEdBQUc7TUFDZixHQUFHLEVBQUUsSUFBSTtNQUFFLE1BQU0sRUFBRSxJQUFJO01BQUUsUUFBUSxFQUFFLElBQUk7TUFBRSxJQUFJLEVBQUUsSUFBSTtNQUNuRCxHQUFHLEVBQUUsSUFBSTtNQUFFLEdBQUcsRUFBRSxJQUFJO01BQUUsSUFBSSxFQUFFLElBQUk7TUFBRSxHQUFHLEVBQUUsSUFBSTtNQUFFLEtBQUssRUFBRSxJQUFJO01BQ3hELElBQUksRUFBRSxJQUFJO01BQUUsSUFBSSxFQUFFLElBQUk7TUFBRSxJQUFJLEVBQUUsSUFBSTtNQUFFLElBQUksRUFBRSxJQUFJO01BQUUsSUFBSSxFQUFFLElBQUk7TUFBRSxJQUFJLEVBQUUsSUFBSTtNQUN0RSxLQUFLLEVBQUUsSUFBSTtNQUFFLFNBQVMsRUFBRSxJQUFJO01BQUUsSUFBSSxFQUFFLElBQUk7TUFBRSxJQUFJLEVBQUUsSUFBSTtNQUFFLElBQUksRUFBRSxJQUFJO01BQ2hFLFlBQVksRUFBRSxJQUFJO01BQUUsUUFBUSxFQUFFLElBQUk7TUFBRSxZQUFZLEVBQUU7SUFDdEQsQ0FBQzs7SUFFRDtJQUNBLElBQUlDLGFBQWEsR0FBRztNQUNoQixNQUFNLEVBQUUsSUFBSTtNQUFFLEtBQUssRUFBRSxJQUFJO01BQUUsS0FBSyxFQUFFLElBQUk7TUFBRSxPQUFPLEVBQUUsSUFBSTtNQUNyRCxJQUFJLEVBQUUsSUFBSTtNQUFFLE9BQU8sRUFBRSxJQUFJO01BQUUsUUFBUSxFQUFFLElBQUk7TUFBRSxLQUFLLEVBQUUsSUFBSTtNQUN0RCxPQUFPLEVBQUUsSUFBSTtNQUFFLFFBQVEsRUFBRSxJQUFJO01BQUUsU0FBUyxFQUFFO0lBQzlDLENBQUM7O0lBRUQ7SUFDQSxJQUFJQyxhQUFhLEdBQUcsK0JBQStCOztJQUVuRDtJQUNBLElBQUlDLGFBQWEsR0FBRyxNQUFNOztJQUUxQjtBQUNSO0FBQ0E7QUFDQTtJQUNRLFNBQVNDLFlBQVlBLENBQUEsRUFBRztNQUNwQixJQUFJO1FBQ0EsT0FBTyxPQUFPQyxTQUFTLEtBQUssV0FBVyxJQUFJLElBQUlBLFNBQVMsQ0FBQyxDQUFDO01BQzlELENBQUMsQ0FBQyxPQUFPQyxDQUFDLEVBQUU7UUFDUixPQUFPLEtBQUs7TUFDaEI7SUFDSjs7SUFFQTtBQUNSO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7SUFDUSxTQUFTQyxxQkFBcUJBLENBQUNDLEtBQUssRUFBRTtNQUNsQyxJQUFJLE9BQU9BLEtBQUssS0FBSyxRQUFRLElBQUksQ0FBQ0EsS0FBSyxDQUFDQyxJQUFJLENBQUMsQ0FBQyxFQUFFLE9BQU8sRUFBRTtNQUV6RCxJQUFJO1FBQ0EsSUFBSUMsTUFBTSxHQUFHLElBQUlMLFNBQVMsQ0FBQyxDQUFDO1FBQzVCLElBQUlNLEdBQUcsR0FBR0QsTUFBTSxDQUFDRSxlQUFlLENBQUNKLEtBQUssRUFBRSxXQUFXLENBQUM7UUFDcEQsSUFBSUssSUFBSSxHQUFHRixHQUFHLENBQUNFLElBQUk7UUFFbkIsSUFBSSxDQUFDQSxJQUFJLEVBQUUsT0FBTyxFQUFFO1FBRXBCLE9BQU9DLFlBQVksQ0FBQ0QsSUFBSSxDQUFDO01BQzdCLENBQUMsQ0FBQyxPQUFPUCxDQUFDLEVBQUU7UUFDUlMsT0FBTyxDQUFDQyxJQUFJLENBQUMsbURBQW1ELEVBQUVWLENBQUMsQ0FBQztRQUNwRSxPQUFPVyxpQkFBaUIsQ0FBQ1QsS0FBSyxDQUFDO01BQ25DO0lBQ0o7O0lBRUE7QUFDUjtBQUNBO0FBQ0E7QUFDQTtJQUNRLFNBQVNNLFlBQVlBLENBQUNJLElBQUksRUFBRTtNQUN4QixJQUFJQyxNQUFNLEdBQUcsRUFBRTtNQUVmLEtBQUssSUFBSUMsQ0FBQyxHQUFHLENBQUMsRUFBRUEsQ0FBQyxHQUFHRixJQUFJLENBQUNHLFVBQVUsQ0FBQ0MsTUFBTSxFQUFFRixDQUFDLEVBQUUsRUFBRTtRQUM3QyxJQUFJRyxLQUFLLEdBQUdMLElBQUksQ0FBQ0csVUFBVSxDQUFDRCxDQUFDLENBQUM7O1FBRTlCO1FBQ0EsSUFBSUcsS0FBSyxDQUFDQyxRQUFRLEtBQUssQ0FBQyxFQUFFO1VBQ3RCTCxNQUFNLElBQUlNLFVBQVUsQ0FBQ0YsS0FBSyxDQUFDRyxXQUFXLENBQUM7VUFDdkM7UUFDSjs7UUFFQTtRQUNBLElBQUlILEtBQUssQ0FBQ0MsUUFBUSxLQUFLLENBQUMsRUFBRTtVQUN0QixJQUFJRyxPQUFPLEdBQUdKLEtBQUssQ0FBQ0ksT0FBTyxDQUFDQyxXQUFXLENBQUMsQ0FBQzs7VUFFekM7VUFDQSxJQUFJRCxPQUFPLEtBQUssUUFBUSxJQUFJQSxPQUFPLEtBQUssT0FBTyxJQUMzQ0EsT0FBTyxLQUFLLFFBQVEsSUFBSUEsT0FBTyxLQUFLLFFBQVEsSUFDNUNBLE9BQU8sS0FBSyxPQUFPLElBQUlBLE9BQU8sS0FBSyxNQUFNLElBQ3pDQSxPQUFPLEtBQUssT0FBTyxJQUFJQSxPQUFPLEtBQUssVUFBVSxFQUFFO1lBQy9DO1VBQ0o7O1VBRUE7VUFDQSxJQUFJM0IsWUFBWSxDQUFDMkIsT0FBTyxDQUFDLEVBQUU7WUFDdkJSLE1BQU0sSUFBSSxHQUFHLEdBQUdRLE9BQU87WUFDdkJSLE1BQU0sSUFBSVUsZUFBZSxDQUFDTixLQUFLLENBQUM7WUFDaENKLE1BQU0sSUFBSSxHQUFHOztZQUViO1lBQ0EsSUFBSVEsT0FBTyxLQUFLLElBQUksSUFBSUEsT0FBTyxLQUFLLEtBQUssRUFBRTtjQUN2QztZQUNKOztZQUVBO1lBQ0FSLE1BQU0sSUFBSUwsWUFBWSxDQUFDUyxLQUFLLENBQUM7WUFDN0JKLE1BQU0sSUFBSSxJQUFJLEdBQUdRLE9BQU8sR0FBRyxHQUFHO1VBQ2xDLENBQUMsTUFBTTtZQUNIO1lBQ0FSLE1BQU0sSUFBSUwsWUFBWSxDQUFDUyxLQUFLLENBQUM7VUFDakM7UUFDSjtNQUNKO01BRUEsT0FBT0osTUFBTTtJQUNqQjs7SUFFQTtBQUNSO0FBQ0E7QUFDQTtBQUNBO0lBQ1EsU0FBU1UsZUFBZUEsQ0FBQ0MsT0FBTyxFQUFFO01BQzlCLElBQUlDLE9BQU8sR0FBRyxFQUFFO01BQ2hCLElBQUlDLEtBQUssR0FBR0YsT0FBTyxDQUFDRyxVQUFVO01BRTlCLEtBQUssSUFBSWIsQ0FBQyxHQUFHLENBQUMsRUFBRUEsQ0FBQyxHQUFHWSxLQUFLLENBQUNWLE1BQU0sRUFBRUYsQ0FBQyxFQUFFLEVBQUU7UUFDbkMsSUFBSWMsSUFBSSxHQUFHRixLQUFLLENBQUNaLENBQUMsQ0FBQztRQUNuQixJQUFJZSxJQUFJLEdBQUdELElBQUksQ0FBQ0MsSUFBSSxDQUFDUCxXQUFXLENBQUMsQ0FBQztRQUNsQyxJQUFJUSxLQUFLLEdBQUdGLElBQUksQ0FBQ0UsS0FBSzs7UUFFdEI7UUFDQSxJQUFJakMsYUFBYSxDQUFDa0MsSUFBSSxDQUFDRixJQUFJLENBQUMsRUFBRTs7UUFFOUI7UUFDQSxJQUFJLENBQUNsQyxhQUFhLENBQUNrQyxJQUFJLENBQUMsRUFBRTs7UUFFMUI7UUFDQSxJQUFJLENBQUNBLElBQUksS0FBSyxNQUFNLElBQUlBLElBQUksS0FBSyxLQUFLLEtBQUtqQyxhQUFhLENBQUNtQyxJQUFJLENBQUNELEtBQUssQ0FBQzNCLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRTtVQUN6RTtRQUNKOztRQUVBO1FBQ0EsSUFBSTBCLElBQUksS0FBSyxRQUFRLElBQUlDLEtBQUssS0FBSyxRQUFRLEVBQUU7VUFDekNMLE9BQU8sSUFBSSw0Q0FBNEM7VUFDdkQ7UUFDSjtRQUVBQSxPQUFPLElBQUksR0FBRyxHQUFHSSxJQUFJLEdBQUcsSUFBSSxHQUFHRyxVQUFVLENBQUNGLEtBQUssQ0FBQyxHQUFHLEdBQUc7TUFDMUQ7TUFFQSxPQUFPTCxPQUFPO0lBQ2xCOztJQUVBO0FBQ1I7QUFDQTtBQUNBO0FBQ0E7SUFDUSxTQUFTTixVQUFVQSxDQUFDYyxJQUFJLEVBQUU7TUFDdEIsSUFBSSxDQUFDQSxJQUFJLEVBQUUsT0FBTyxFQUFFO01BQ3BCLE9BQU9BLElBQUksQ0FDTkMsT0FBTyxDQUFDLElBQUksRUFBRSxPQUFPLENBQUMsQ0FDdEJBLE9BQU8sQ0FBQyxJQUFJLEVBQUUsTUFBTSxDQUFDLENBQ3JCQSxPQUFPLENBQUMsSUFBSSxFQUFFLE1BQU0sQ0FBQztJQUM5Qjs7SUFFQTtBQUNSO0FBQ0E7QUFDQTtBQUNBO0lBQ1EsU0FBU0YsVUFBVUEsQ0FBQ0YsS0FBSyxFQUFFO01BQ3ZCLElBQUksQ0FBQ0EsS0FBSyxFQUFFLE9BQU8sRUFBRTtNQUNyQixPQUFPQSxLQUFLLENBQ1BJLE9BQU8sQ0FBQyxJQUFJLEVBQUUsT0FBTyxDQUFDLENBQ3RCQSxPQUFPLENBQUMsSUFBSSxFQUFFLFFBQVEsQ0FBQyxDQUN2QkEsT0FBTyxDQUFDLElBQUksRUFBRSxPQUFPLENBQUMsQ0FDdEJBLE9BQU8sQ0FBQyxJQUFJLEVBQUUsTUFBTSxDQUFDLENBQ3JCQSxPQUFPLENBQUMsSUFBSSxFQUFFLE1BQU0sQ0FBQztJQUM5Qjs7SUFFQTtBQUNSO0FBQ0E7QUFDQTtBQUNBO0lBQ1EsU0FBU3ZCLGlCQUFpQkEsQ0FBQ3dCLElBQUksRUFBRTtNQUM3QixJQUFJLE9BQU9BLElBQUksS0FBSyxRQUFRLEVBQUUsT0FBTyxFQUFFO01BRXZDLElBQUlDLGtCQUFrQixHQUFHLENBQ3JCLHFEQUFxRCxFQUNyRCxxREFBcUQsRUFDckQscURBQXFELEVBQ3JELGtCQUFrQixFQUNsQixpQkFBaUIsRUFDakIsa0RBQWtELEVBQ2xELCtDQUErQyxFQUMvQyxlQUFlLEVBQ2YsYUFBYSxFQUNiLFNBQVMsRUFDVCxhQUFhLENBQ2hCO01BRUQsSUFBSUMsU0FBUyxHQUFHRixJQUFJO01BRXBCQyxrQkFBa0IsQ0FBQ0UsT0FBTyxDQUFDLFVBQVVDLE9BQU8sRUFBRTtRQUMxQ0YsU0FBUyxHQUFHQSxTQUFTLENBQUNILE9BQU8sQ0FBQ0ssT0FBTyxFQUFFLEVBQUUsQ0FBQztNQUM5QyxDQUFDLENBQUM7O01BRUY7TUFDQUYsU0FBUyxHQUFHQSxTQUFTLENBQUNILE9BQU8sQ0FBQyxvQkFBb0IsRUFBRSxVQUFVTSxLQUFLLEVBQUVuQixPQUFPLEVBQUVLLEtBQUssRUFBRTtRQUNqRixJQUFJZSxHQUFHLEdBQUdwQixPQUFPLENBQUNDLFdBQVcsQ0FBQyxDQUFDO1FBQy9CLElBQUksQ0FBQzVCLFlBQVksQ0FBQytDLEdBQUcsQ0FBQyxFQUFFLE9BQU8sRUFBRTs7UUFFakM7UUFDQSxJQUFJRCxLQUFLLENBQUNFLE1BQU0sQ0FBQyxDQUFDLENBQUMsS0FBSyxHQUFHLEVBQUUsT0FBTyxJQUFJLEdBQUdELEdBQUcsR0FBRyxHQUFHOztRQUVwRDtRQUNBLElBQUlFLFVBQVUsR0FBRyxFQUFFO1FBQ25CLElBQUlDLFNBQVMsR0FBRyx5QkFBeUI7UUFDekMsSUFBSUMsU0FBUztRQUViLE9BQU8sQ0FBQ0EsU0FBUyxHQUFHRCxTQUFTLENBQUNFLElBQUksQ0FBQ3BCLEtBQUssQ0FBQyxNQUFNLElBQUksRUFBRTtVQUNqRCxJQUFJcUIsUUFBUSxHQUFHRixTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUN2QixXQUFXLENBQUMsQ0FBQztVQUN6QyxJQUFJM0IsYUFBYSxDQUFDb0QsUUFBUSxDQUFDLElBQUksQ0FBQ2xELGFBQWEsQ0FBQ2tDLElBQUksQ0FBQ2dCLFFBQVEsQ0FBQyxFQUFFO1lBQzFELElBQUlDLEdBQUcsR0FBR0gsU0FBUyxDQUFDLENBQUMsQ0FBQztZQUN0QixJQUFJLENBQUNFLFFBQVEsS0FBSyxNQUFNLElBQUlBLFFBQVEsS0FBSyxLQUFLLEtBQUtuRCxhQUFhLENBQUNtQyxJQUFJLENBQUNpQixHQUFHLENBQUMsRUFBRTtjQUN4RTtZQUNKO1lBQ0FMLFVBQVUsSUFBSSxHQUFHLEdBQUdJLFFBQVEsR0FBRyxJQUFJLEdBQUdDLEdBQUcsR0FBRyxHQUFHO1VBQ25EO1FBQ0o7UUFFQSxPQUFPLEdBQUcsR0FBR1AsR0FBRyxHQUFHRSxVQUFVLEdBQUcsR0FBRztNQUN2QyxDQUFDLENBQUM7TUFFRixPQUFPTixTQUFTO0lBQ3BCOztJQUVBO0lBQ0EsT0FBTztNQUNIO0FBQ1o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtNQUNZWSxRQUFRLEVBQUUsU0FBVkEsUUFBUUEsQ0FBWS9DLEtBQUssRUFBRTtRQUN2QixJQUFJLE9BQU9BLEtBQUssS0FBSyxRQUFRLEVBQUUsT0FBTyxFQUFFO1FBQ3hDLElBQUksQ0FBQ0EsS0FBSyxDQUFDQyxJQUFJLENBQUMsQ0FBQyxFQUFFLE9BQU8sRUFBRTtRQUU1QixJQUFJTCxZQUFZLENBQUMsQ0FBQyxFQUFFO1VBQ2hCLE9BQU9HLHFCQUFxQixDQUFDQyxLQUFLLENBQUM7UUFDdkM7UUFDQSxPQUFPUyxpQkFBaUIsQ0FBQ1QsS0FBSyxDQUFDO01BQ25DLENBQUM7TUFFRGlCLFVBQVUsRUFBRUEsVUFBVTtNQUN0QmEsVUFBVSxFQUFFQTtJQUNoQixDQUFDO0VBQ0wsQ0FBQyxDQUFFLENBQUM7O0VBRUo7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7O0VBRUE7RUFDQTtFQUNBOztFQUVBO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7RUFDSSxTQUFTa0IsV0FBV0EsQ0FBQzFCLE9BQU8sRUFBRVMsSUFBSSxFQUFFO0lBQ2hDLElBQUksQ0FBQ1QsT0FBTyxFQUFFO0lBQ2RBLE9BQU8sQ0FBQ0osV0FBVyxHQUFHYSxJQUFJO0VBQzlCOztFQUVBO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7RUFDSSxTQUFTa0IsV0FBV0EsQ0FBQzNCLE9BQU8sRUFBRVcsSUFBSSxFQUFFO0lBQ2hDLElBQUksQ0FBQ1gsT0FBTyxFQUFFO0lBQ2RBLE9BQU8sQ0FBQzRCLFNBQVMsR0FBRzNELFNBQVMsQ0FBQ3dELFFBQVEsQ0FBQ2QsSUFBSSxDQUFDO0VBQ2hEOztFQUVBO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtFQUNJLFNBQVNrQix1QkFBdUJBLENBQUNDLEdBQUcsRUFBRUMsVUFBVSxFQUFFO0lBQzlDQSxVQUFVLEdBQUdBLFVBQVUsS0FBSyxPQUFPQyxRQUFRLEtBQUssV0FBVyxHQUFHQSxRQUFRLEdBQUcsSUFBSSxDQUFDO0lBQzlFLElBQUksQ0FBQ0QsVUFBVSxFQUFFLE9BQU8sRUFBRTtJQUUxQixJQUFJRSxRQUFRLEdBQUdILEdBQUcsR0FDWixxQkFBcUIsR0FBR0EsR0FBRyxHQUFHLElBQUksR0FDbEMsb0JBQW9CO0lBRTFCLE9BQU9DLFVBQVUsQ0FBQ0csZ0JBQWdCLENBQUNELFFBQVEsQ0FBQztFQUNoRDs7RUFFQTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0VBQ0ksU0FBU0UsV0FBV0EsQ0FBQ0MsTUFBTSxFQUFFQyxhQUFhLEVBQUU7SUFDeEMsSUFBSSxDQUFDQSxhQUFhLElBQUksSUFBQUMsUUFBQSxDQUFBQyxPQUFBLEVBQU9GLGFBQWEsTUFBSyxRQUFRLEVBQUU7TUFDckRwRCxPQUFPLENBQUNDLElBQUksQ0FBQyx5RkFBeUYsQ0FBQztNQUN2RyxPQUFPLElBQUk7SUFDZjs7SUFFQTtJQUNBLElBQUltRCxhQUFhLENBQUNELE1BQU0sQ0FBQyxFQUFFO01BQ3ZCLE9BQU9DLGFBQWEsQ0FBQ0QsTUFBTSxDQUFDO0lBQ2hDOztJQUVBO0lBQ0EsSUFBSUMsYUFBYSxDQUFDLFNBQVMsQ0FBQyxFQUFFO01BQzFCLE9BQU9BLGFBQWEsQ0FBQyxTQUFTLENBQUM7SUFDbkM7O0lBRUE7SUFDQSxJQUFJRyxRQUFRLEdBQUdDLE1BQU0sQ0FBQ0MsSUFBSSxDQUFDTCxhQUFhLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDNUMsSUFBSUcsUUFBUSxFQUFFO01BQ1Z2RCxPQUFPLENBQUNDLElBQUksQ0FBQyw0QkFBNEIsR0FBR2tELE1BQU0sR0FBRyw4Q0FBOEMsRUFBRUksUUFBUSxDQUFDO01BQzlHLE9BQU9ILGFBQWEsQ0FBQ0csUUFBUSxDQUFDO0lBQ2xDO0lBRUEsT0FBTyxJQUFJO0VBQ2Y7O0VBRUE7RUFDQTtFQUNBOztFQUVBO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtFQUNJLFNBQVNHLG9CQUFvQkEsQ0FBQ0MsS0FBSyxFQUFFQyxPQUFPLEVBQUU7SUFDMUMsSUFBSUQsS0FBSyxDQUFDcEQsTUFBTSxLQUFLcUQsT0FBTyxDQUFDckQsTUFBTSxFQUFFLE9BQU9vRCxLQUFLLENBQUMsQ0FBQyxDQUFDO0lBQ3BELElBQUlFLEdBQUcsR0FBRyxDQUFDO0lBQ1gsSUFBSXhELENBQUM7SUFDTCxLQUFLQSxDQUFDLEdBQUcsQ0FBQyxFQUFFQSxDQUFDLEdBQUd1RCxPQUFPLENBQUNyRCxNQUFNLEVBQUVGLENBQUMsRUFBRSxFQUFFO01BQ2pDd0QsR0FBRyxJQUFJRCxPQUFPLENBQUN2RCxDQUFDLENBQUM7SUFDckI7SUFDQSxJQUFJeUQsQ0FBQyxHQUFHQyxJQUFJLENBQUNDLE1BQU0sQ0FBQyxDQUFDLEdBQUdILEdBQUc7SUFDM0IsSUFBSUksS0FBSyxHQUFHLENBQUM7SUFDYixLQUFLNUQsQ0FBQyxHQUFHLENBQUMsRUFBRUEsQ0FBQyxHQUFHc0QsS0FBSyxDQUFDcEQsTUFBTSxFQUFFRixDQUFDLEVBQUUsRUFBRTtNQUMvQjRELEtBQUssSUFBSUwsT0FBTyxDQUFDdkQsQ0FBQyxDQUFDO01BQ25CLElBQUl5RCxDQUFDLElBQUlHLEtBQUssRUFBRSxPQUFPTixLQUFLLENBQUN0RCxDQUFDLENBQUM7SUFDbkM7SUFDQSxPQUFPc0QsS0FBSyxDQUFDQSxLQUFLLENBQUNwRCxNQUFNLEdBQUcsQ0FBQyxDQUFDO0VBQ2xDOztFQUVBO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtFQUNJLFNBQVMyRCx1QkFBdUJBLENBQUNkLGFBQWEsRUFBRTtJQUM1QyxJQUFJLENBQUNBLGFBQWEsSUFBSSxJQUFBQyxRQUFBLENBQUFDLE9BQUEsRUFBT0YsYUFBYSxNQUFLLFFBQVEsRUFBRTtNQUNyRCxPQUFPLElBQUk7SUFDZjtJQUVBLElBQUlPLEtBQUssR0FBR0gsTUFBTSxDQUFDQyxJQUFJLENBQUNMLGFBQWEsQ0FBQztJQUN0QyxJQUFJTyxLQUFLLENBQUNwRCxNQUFNLEtBQUssQ0FBQyxFQUFFO01BQ3BCLE9BQU8sSUFBSTtJQUNmO0lBRUEsSUFBSXFELE9BQU8sR0FBRyxFQUFFO0lBQ2hCLEtBQUssSUFBSXZELENBQUMsR0FBRyxDQUFDLEVBQUVBLENBQUMsR0FBR3NELEtBQUssQ0FBQ3BELE1BQU0sRUFBRUYsQ0FBQyxFQUFFLEVBQUU7TUFDbkN1RCxPQUFPLENBQUNPLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBQztJQUNwQjtJQUNBLE9BQU9ULG9CQUFvQixDQUFDQyxLQUFLLEVBQUVDLE9BQU8sQ0FBQztFQUMvQzs7RUFFQTtFQUNBO0VBQ0E7O0VBRUE7QUFDSjtBQUNBO0FBQ0E7QUFDQTtFQUNJLElBQUlRLGNBQWMsR0FBRztJQUNqQjtBQUNSO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7SUFDUUMsY0FBYyxFQUFFLFNBQWhCQSxjQUFjQSxDQUFZQyxPQUFPLEVBQUVDLE9BQU8sRUFBRTtNQUN4Q0EsT0FBTyxHQUFHQSxPQUFPLElBQUksQ0FBQyxDQUFDO01BQ3ZCLElBQUlDLFdBQVcsR0FBR0QsT0FBTyxDQUFDRSxLQUFLLElBQUksQ0FBQyxDQUFDO01BQ3JDLElBQUlyQixhQUFhLEdBQUdtQixPQUFPLENBQUNHLFNBQVM7TUFDckMsSUFBSUMsb0JBQW9CLEdBQUdKLE9BQU8sQ0FBQ0ssY0FBYyxLQUFLLEtBQUs7O01BRTNEO01BQ0EsSUFBSSxDQUFDeEIsYUFBYSxJQUFJLElBQUFDLFFBQUEsQ0FBQUMsT0FBQSxFQUFPRixhQUFhLE1BQUssUUFBUSxJQUFJSSxNQUFNLENBQUNDLElBQUksQ0FBQ0wsYUFBYSxDQUFDLENBQUM3QyxNQUFNLEtBQUssQ0FBQyxFQUFFO1FBQ2hHUCxPQUFPLENBQUNDLElBQUksQ0FBQyx5RkFBeUYsQ0FBQztRQUN2RyxPQUFPO1VBQ0g0RSxRQUFRLEVBQUUsSUFBSTtVQUNkMUIsTUFBTSxFQUFFLFNBQVM7VUFDakIyQixNQUFNLEVBQUUsT0FBTztVQUNmUixPQUFPLEVBQUVBLE9BQU87VUFDaEJTLEtBQUssRUFBRTtRQUNYLENBQUM7TUFDTDtNQUVBLElBQUk1QixNQUFNLEdBQUdtQixPQUFPLENBQUNVLGFBQWE7TUFDbEMsSUFBSUYsTUFBTSxHQUFHLFNBQVM7O01BRXRCO01BQ0EsSUFBSVIsT0FBTyxDQUFDVyxNQUFNLEVBQUU7UUFDaEJILE1BQU0sR0FBRyxLQUFLO01BQ2xCLENBQUMsTUFBTSxJQUFJUixPQUFPLENBQUNZLFFBQVEsSUFBSVosT0FBTyxDQUFDWSxRQUFRLENBQUNDLFFBQVEsS0FBSyxRQUFRLEVBQUU7UUFDbkVMLE1BQU0sR0FBRyxVQUFVO01BQ3ZCOztNQUVBO01BQ0EsS0FBSyxJQUFJTSxPQUFPLElBQUlaLFdBQVcsRUFBRTtRQUM3QixJQUFJYSxJQUFJLEdBQUdiLFdBQVcsQ0FBQ1ksT0FBTyxDQUFDO1FBQy9CLElBQUksT0FBT0MsSUFBSSxDQUFDdEQsS0FBSyxLQUFLLFVBQVUsSUFBSXNELElBQUksQ0FBQ3RELEtBQUssQ0FBQ3VDLE9BQU8sQ0FBQyxFQUFFO1VBQ3pEbkIsTUFBTSxHQUFHa0MsSUFBSSxDQUFDbEMsTUFBTSxJQUFJaUMsT0FBTztVQUMvQk4sTUFBTSxHQUFHLGFBQWE7VUFDdEI7UUFDSjtNQUNKOztNQUVBO01BQ0E7TUFDQSxJQUFJM0IsTUFBTSxLQUFLLFNBQVMsSUFBSTJCLE1BQU0sS0FBSyxTQUFTLElBQUlILG9CQUFvQixFQUFFO1FBQ3RFLElBQUlXLFlBQVksR0FBR3BCLHVCQUF1QixDQUFDZCxhQUFhLENBQUM7UUFDekQsSUFBSWtDLFlBQVksRUFBRTtVQUNkbkMsTUFBTSxHQUFHbUMsWUFBWTtVQUNyQlIsTUFBTSxHQUFHLFdBQVc7UUFDeEI7TUFDSjs7TUFFQTtNQUNBLElBQUkvRixJQUFJLENBQUN3RyxrQkFBa0IsSUFBSSxPQUFPeEcsSUFBSSxDQUFDd0csa0JBQWtCLENBQUNDLFdBQVcsS0FBSyxVQUFVLEVBQUU7UUFDdEZ6RyxJQUFJLENBQUN3RyxrQkFBa0IsQ0FBQ0MsV0FBVyxDQUFDO1VBQ2hDbEIsT0FBTyxFQUFFQSxPQUFPO1VBQ2hCbkIsTUFBTSxFQUFFQSxNQUFNO1VBQ2RzQyxlQUFlLEVBQUV0QyxNQUFNO1VBQ3ZCMkIsTUFBTSxFQUFFQSxNQUFNO1VBQ2RZLFVBQVUsRUFBRTtRQUNoQixDQUFDLENBQUM7TUFDTjtNQUVBLE9BQU87UUFDSGIsUUFBUSxFQUFFM0IsV0FBVyxDQUFDQyxNQUFNLEVBQUVDLGFBQWEsQ0FBQztRQUM1Q0QsTUFBTSxFQUFFQSxNQUFNO1FBQ2QyQixNQUFNLEVBQUVBLE1BQU07UUFDZFIsT0FBTyxFQUFFQTtNQUNiLENBQUM7SUFDTCxDQUFDO0lBRUQ7QUFDUjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtJQUNRcUIsTUFBTSxFQUFFLFNBQVJBLE1BQU1BLENBQVlyQixPQUFPLEVBQUVDLE9BQU8sRUFBRTtNQUNoQ0EsT0FBTyxHQUFHQSxPQUFPLElBQUksQ0FBQyxDQUFDOztNQUV2QjtNQUNBLElBQUlBLE9BQU8sQ0FBQ3FCLFFBQVEsSUFBSXJCLE9BQU8sQ0FBQ3NCLFFBQVEsSUFBSTlHLElBQUksQ0FBQytHLGdCQUFnQixFQUFFO1FBQy9ELElBQUlDLElBQUksR0FBRyxJQUFJO1FBQ2YsSUFBSUMsUUFBUSxHQUFHakgsSUFBSSxDQUFDK0csZ0JBQWdCO1FBQ3BDLElBQUlHLFNBQVMsR0FBR0QsUUFBUSxDQUFDRSxPQUFPLENBQUMzQixPQUFPLENBQUNzQixRQUFRLENBQUM7UUFFbEQsSUFBSUksU0FBUyxDQUFDRSxLQUFLLEVBQUU7VUFDakIsT0FBT0gsUUFBUSxDQUFDTCxNQUFNLENBQUNyQixPQUFPLEVBQUVDLE9BQU8sQ0FBQyxDQUNuQzZCLEtBQUssQ0FBQyxVQUFVckIsS0FBSyxFQUFFO1lBQ3BCO1lBQ0EsSUFBSXNCLFFBQVEsR0FBRzlCLE9BQU8sQ0FBQ3NCLFFBQVEsQ0FBQ1Msa0JBQWtCLEtBQUssS0FBSztZQUM1RCxJQUFJRCxRQUFRLEVBQUU7Y0FDVnJHLE9BQU8sQ0FBQ0MsSUFBSSxDQUFDLHFEQUFxRCxFQUFFOEUsS0FBSyxDQUFDd0IsT0FBTyxDQUFDO2NBQ2xGLE9BQU9SLElBQUksQ0FBQzFCLGNBQWMsQ0FBQ0MsT0FBTyxFQUFFQyxPQUFPLENBQUM7WUFDaEQ7WUFDQSxNQUFNUSxLQUFLO1VBQ2YsQ0FBQyxDQUFDO1FBQ1YsQ0FBQyxNQUFNO1VBQ0gvRSxPQUFPLENBQUNDLElBQUksQ0FBQyxpQ0FBaUMsRUFBRWdHLFNBQVMsQ0FBQ2xCLEtBQUssRUFBRSx5QkFBeUIsQ0FBQztRQUMvRjtNQUNKOztNQUVBO01BQ0EsT0FBTyxJQUFJLENBQUNWLGNBQWMsQ0FBQ0MsT0FBTyxFQUFFQyxPQUFPLENBQUM7SUFDaEQ7RUFDSixDQUFDOztFQUVEO0VBQ0E7RUFDQTs7RUFFQTtFQUNBO0VBQ0E7O0VBRUE7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0VBQ0ksU0FBU2lDLGtCQUFrQkEsQ0FBQ0MsUUFBUSxFQUFFbEMsT0FBTyxFQUFFO0lBQzNDQSxPQUFPLEdBQUdBLE9BQU8sSUFBSSxDQUFDLENBQUM7SUFDdkIsSUFBSU0sUUFBUSxHQUFHNEIsUUFBUSxDQUFDNUIsUUFBUTtJQUNoQyxJQUFJUCxPQUFPLEdBQUdtQyxRQUFRLENBQUNuQyxPQUFPLElBQUksQ0FBQyxDQUFDO0lBQ3BDLElBQUlvQyxHQUFHLEdBQUduQyxPQUFPLENBQUNtQyxHQUFHLEtBQUssS0FBSztJQUUvQixJQUFJLENBQUM3QixRQUFRLEVBQUU7TUFDWDdFLE9BQU8sQ0FBQ0MsSUFBSSxDQUFDLGdFQUFnRSxDQUFDO01BQzlFLE9BQU93RyxRQUFRO0lBQ25COztJQUVBO0lBQ0EsSUFBSUUsS0FBSyxHQUFHLENBQUMsT0FBTyxFQUFFLFVBQVUsRUFBRSxhQUFhLEVBQUUsVUFBVSxFQUFFLFNBQVMsQ0FBQztJQUV2RUEsS0FBSyxDQUFDOUUsT0FBTyxDQUFDLFVBQVUrRSxJQUFJLEVBQUU7TUFDMUIsSUFBSUMsUUFBUSxHQUFHakUsdUJBQXVCLENBQUNnRSxJQUFJLENBQUM7TUFFNUMsS0FBSyxJQUFJdkcsQ0FBQyxHQUFHLENBQUMsRUFBRUEsQ0FBQyxHQUFHd0csUUFBUSxDQUFDdEcsTUFBTSxFQUFFRixDQUFDLEVBQUUsRUFBRTtRQUN0QyxJQUFJVSxPQUFPLEdBQUc4RixRQUFRLENBQUN4RyxDQUFDLENBQUM7UUFDekIsSUFBSWdCLEtBQUssR0FBR3dELFFBQVEsQ0FBQytCLElBQUksQ0FBQztRQUMxQixJQUFJLENBQUN2RixLQUFLLEVBQUU7UUFFWixJQUFJdUYsSUFBSSxLQUFLLE9BQU8sRUFBRTtVQUNsQjtVQUNBLElBQUk3RixPQUFPLENBQUNILE9BQU8sS0FBSyxLQUFLLEVBQUU7WUFDM0JHLE9BQU8sQ0FBQytGLEdBQUcsR0FBR3pGLEtBQUs7WUFDbkJOLE9BQU8sQ0FBQ2dHLEdBQUcsR0FBR2xDLFFBQVEsQ0FBQ21DLFFBQVEsSUFBSSxvQkFBb0I7VUFDM0QsQ0FBQyxNQUFNO1lBQ0hqRyxPQUFPLENBQUNrRyxLQUFLLENBQUNDLGVBQWUsR0FBRyxNQUFNLEdBQUc3RixLQUFLLEdBQUcsR0FBRztVQUN4RDtRQUNKLENBQUMsTUFBTSxJQUFJdUYsSUFBSSxLQUFLLFNBQVMsRUFBRTtVQUMzQjtVQUNBN0YsT0FBTyxDQUFDb0csSUFBSSxHQUFHOUYsS0FBSztRQUN4QixDQUFDLE1BQU07VUFDSDtVQUNBb0IsV0FBVyxDQUFDMUIsT0FBTyxFQUFFTSxLQUFLLENBQUM7UUFDL0I7TUFDSjtJQUNKLENBQUMsQ0FBQzs7SUFFRjtJQUNBLElBQUkrRixZQUFZLEdBQUd4RSx1QkFBdUIsQ0FBQyxNQUFNLENBQUM7SUFDbEQsS0FBSyxJQUFJeUUsQ0FBQyxHQUFHLENBQUMsRUFBRUEsQ0FBQyxHQUFHRCxZQUFZLENBQUM3RyxNQUFNLEVBQUU4RyxDQUFDLEVBQUUsRUFBRTtNQUMxQyxJQUFJQyxNQUFNLEdBQUdGLFlBQVksQ0FBQ0MsQ0FBQyxDQUFDO01BQzVCQyxNQUFNLENBQUNDLFlBQVksQ0FBQyxhQUFhLEVBQUVkLFFBQVEsQ0FBQ3RELE1BQU0sQ0FBQztNQUNuRG1FLE1BQU0sQ0FBQ0MsWUFBWSxDQUFDLGFBQWEsRUFBRWQsUUFBUSxDQUFDM0IsTUFBTSxDQUFDOztNQUVuRDtNQUNBLElBQUlELFFBQVEsQ0FBQzJDLEtBQUssSUFBSSxDQUFDRixNQUFNLENBQUNHLGFBQWEsQ0FBQyw0QkFBNEIsQ0FBQyxFQUFFO1FBQ3ZFSCxNQUFNLENBQUNMLEtBQUssQ0FBQ0MsZUFBZSxHQUFHLE1BQU0sR0FBR3JDLFFBQVEsQ0FBQzJDLEtBQUssR0FBRyxHQUFHO01BQ2hFO0lBQ0o7O0lBRUE7SUFDQSxJQUFJZCxHQUFHLElBQUksT0FBTzFHLE9BQU8sS0FBSyxXQUFXLEVBQUU7TUFDdkNBLE9BQU8sQ0FBQzBHLEdBQUcsQ0FBQyw0QkFBNEIsRUFBRTtRQUN0Q3ZELE1BQU0sRUFBRXNELFFBQVEsQ0FBQ3RELE1BQU07UUFDdkIyQixNQUFNLEVBQUUyQixRQUFRLENBQUMzQixNQUFNO1FBQ3ZCa0MsUUFBUSxFQUFFbkMsUUFBUSxDQUFDbUMsUUFBUTtRQUMzQi9CLE1BQU0sRUFBRVgsT0FBTyxDQUFDVyxNQUFNO1FBQ3RCeUMsU0FBUyxFQUFFcEQsT0FBTyxDQUFDcUQsR0FBRyxJQUFJLENBQUMsQ0FBQztRQUM1QkMsU0FBUyxFQUFFbkIsUUFBUSxDQUFDM0IsTUFBTSxLQUFLLElBQUksSUFBSTJCLFFBQVEsQ0FBQzNCLE1BQU0sS0FBSztNQUMvRCxDQUFDLENBQUM7SUFDTjtJQUVBLE9BQU8yQixRQUFRO0VBQ25COztFQUVBO0VBQ0E7RUFDQTs7RUFFQTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0VBQ0ksU0FBU29CLGNBQWNBLENBQUN0RCxPQUFPLEVBQUU7SUFDN0IsSUFBSUEsT0FBTyxJQUFJQSxPQUFPLENBQUNELE9BQU8sRUFBRTtNQUM1QixPQUFPQyxPQUFPLENBQUNELE9BQU87SUFDMUI7SUFFQSxJQUFJdkYsSUFBSSxDQUFDK0ksTUFBTSxJQUFJLE9BQU8vSSxJQUFJLENBQUMrSSxNQUFNLENBQUNDLFVBQVUsS0FBSyxVQUFVLEVBQUU7TUFDN0QsT0FBT2hKLElBQUksQ0FBQytJLE1BQU0sQ0FBQ0MsVUFBVSxDQUFDLENBQUM7SUFDbkM7O0lBRUE7SUFDQSxPQUFPO01BQ0hKLEdBQUcsRUFBRSxDQUFDLENBQUM7TUFDUHpDLFFBQVEsRUFBRTtRQUFFSixNQUFNLEVBQUUsUUFBUTtRQUFFSyxRQUFRLEVBQUUsUUFBUTtRQUFFNkMsR0FBRyxFQUFFO01BQUcsQ0FBQztNQUMzREMsU0FBUyxFQUFFO1FBQUVDLEdBQUcsRUFBRSxFQUFFO1FBQUVDLFFBQVEsRUFBRSxLQUFLO1FBQUVDLFFBQVEsRUFBRSxLQUFLO1FBQUVDLFNBQVMsRUFBRTtNQUFLLENBQUM7TUFDekVDLFNBQVMsRUFBRUMsSUFBSSxDQUFDQyxHQUFHLENBQUMsQ0FBQztNQUNyQnZELE1BQU0sRUFBRSxLQUFLO01BQ2JELGFBQWEsRUFBRTtJQUNuQixDQUFDO0VBQ0w7O0VBRUE7RUFDQTtFQUNBOztFQUVBO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0VBQ0ksU0FBU3lELFdBQVdBLENBQUNsRSxPQUFPLEVBQUU7SUFDMUJBLE9BQU8sR0FBR0EsT0FBTyxJQUFJLENBQUMsQ0FBQzs7SUFFdkI7SUFDQSxJQUFJLENBQUNBLE9BQU8sQ0FBQ0csU0FBUyxJQUFJLElBQUFyQixRQUFBLENBQUFDLE9BQUEsRUFBT2lCLE9BQU8sQ0FBQ0csU0FBUyxNQUFLLFFBQVEsSUFBSWxCLE1BQU0sQ0FBQ0MsSUFBSSxDQUFDYyxPQUFPLENBQUNHLFNBQVMsQ0FBQyxDQUFDbkUsTUFBTSxLQUFLLENBQUMsRUFBRTtNQUM1R1AsT0FBTyxDQUFDK0UsS0FBSyxDQUFDLG1GQUFtRixDQUFDO01BQ2xHLE9BQU87UUFDSEYsUUFBUSxFQUFFLElBQUk7UUFDZDFCLE1BQU0sRUFBRSxTQUFTO1FBQ2pCMkIsTUFBTSxFQUFFLE9BQU87UUFDZlIsT0FBTyxFQUFFLENBQUMsQ0FBQztRQUNYUyxLQUFLLEVBQUU7TUFDWCxDQUFDO0lBQ0w7SUFFQSxJQUFJVCxPQUFPLEdBQUd1RCxjQUFjLENBQUN0RCxPQUFPLENBQUM7SUFDckMsSUFBSWtDLFFBQVEsR0FBR3JDLGNBQWMsQ0FBQ3VCLE1BQU0sQ0FBQ3JCLE9BQU8sRUFBRUMsT0FBTyxDQUFDOztJQUV0RDtJQUNBLElBQUlrQyxRQUFRLElBQUksT0FBT0EsUUFBUSxDQUFDaUMsSUFBSSxLQUFLLFVBQVUsRUFBRTtNQUNqRCxPQUFPakMsUUFBUSxDQUFDaUMsSUFBSSxDQUFDLFVBQVVoRCxVQUFVLEVBQUU7UUFDdkMsT0FBT2Msa0JBQWtCLENBQUNkLFVBQVUsRUFBRW5CLE9BQU8sQ0FBQztNQUNsRCxDQUFDLENBQUMsQ0FBQzZCLEtBQUssQ0FBQyxVQUFVdUMsR0FBRyxFQUFFO1FBQ3BCM0ksT0FBTyxDQUFDQyxJQUFJLENBQUMsdURBQXVELEVBQUUwSSxHQUFHLENBQUNwQyxPQUFPLENBQUM7UUFDbEY7UUFDQSxJQUFJcUMsZ0JBQWdCLEdBQUd4RSxjQUFjLENBQUNDLGNBQWMsQ0FBQ0MsT0FBTyxFQUFFQyxPQUFPLENBQUM7UUFDdEUsT0FBT2lDLGtCQUFrQixDQUFDb0MsZ0JBQWdCLEVBQUVyRSxPQUFPLENBQUM7TUFDeEQsQ0FBQyxDQUFDO0lBQ047O0lBRUE7SUFDQSxPQUFPaUMsa0JBQWtCLENBQUNDLFFBQVEsRUFBRWxDLE9BQU8sQ0FBQztFQUNoRDs7RUFFQTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0VBQ0ksU0FBU3NFLGdCQUFnQkEsQ0FBQ3RFLE9BQU8sRUFBRTtJQUMvQkEsT0FBTyxHQUFHQSxPQUFPLElBQUksQ0FBQyxDQUFDOztJQUV2QjtJQUNBLElBQUl4RixJQUFJLENBQUMrSSxNQUFNLElBQUksT0FBTy9JLElBQUksQ0FBQytJLE1BQU0sQ0FBQ2dCLGVBQWUsS0FBSyxVQUFVLEVBQUU7TUFDbEUsT0FBTy9KLElBQUksQ0FBQytJLE1BQU0sQ0FBQ2dCLGVBQWUsQ0FBQ3ZFLE9BQU8sQ0FBQyxDQUFDbUUsSUFBSSxDQUFDLFVBQVVwRSxPQUFPLEVBQUU7UUFDaEVDLE9BQU8sQ0FBQ0QsT0FBTyxHQUFHQSxPQUFPO1FBQ3pCLE9BQU9tRSxXQUFXLENBQUNsRSxPQUFPLENBQUM7TUFDL0IsQ0FBQyxDQUFDLENBQUNtRSxJQUFJLENBQUMsVUFBVWpDLFFBQVEsRUFBRTtRQUN4QjtRQUNBLE9BQU9BLFFBQVE7TUFDbkIsQ0FBQyxDQUFDLENBQUNMLEtBQUssQ0FBQyxVQUFVdUMsR0FBRyxFQUFFO1FBQ3BCM0ksT0FBTyxDQUFDQyxJQUFJLENBQUMsK0NBQStDLEVBQUUwSSxHQUFHLENBQUM7UUFDbEU7UUFDQSxJQUFJSSxlQUFlLEdBQUc7VUFDbEJyRSxTQUFTLEVBQUVILE9BQU8sQ0FBQ0csU0FBUztVQUM1QkosT0FBTyxFQUFFdUQsY0FBYyxDQUFDdEQsT0FBTyxDQUFDO1VBQ2hDbUMsR0FBRyxFQUFFbkMsT0FBTyxDQUFDbUM7UUFDakIsQ0FBQztRQUNELElBQUlrQyxnQkFBZ0IsR0FBR3hFLGNBQWMsQ0FBQ0MsY0FBYyxDQUFDMEUsZUFBZSxDQUFDekUsT0FBTyxFQUFFeUUsZUFBZSxDQUFDO1FBQzlGLE9BQU92QyxrQkFBa0IsQ0FBQ29DLGdCQUFnQixFQUFFRyxlQUFlLENBQUM7TUFDaEUsQ0FBQyxDQUFDO0lBQ047O0lBRUE7SUFDQSxJQUFJO01BQ0EsSUFBSUMsTUFBTSxHQUFHUCxXQUFXLENBQUNsRSxPQUFPLENBQUM7TUFDakM7TUFDQSxJQUFJeUUsTUFBTSxJQUFJLE9BQU9BLE1BQU0sQ0FBQ04sSUFBSSxLQUFLLFVBQVUsRUFBRTtRQUM3QyxPQUFPTSxNQUFNO01BQ2pCO01BQ0EsT0FBT0MsT0FBTyxDQUFDQyxPQUFPLENBQUNGLE1BQU0sQ0FBQztJQUNsQyxDQUFDLENBQUMsT0FBT0wsR0FBRyxFQUFFO01BQ1YzSSxPQUFPLENBQUNDLElBQUksQ0FBQyx5Q0FBeUMsRUFBRTBJLEdBQUcsQ0FBQztNQUM1RCxJQUFJUSxjQUFjLEdBQUc7UUFDakJ4QixHQUFHLEVBQUUsQ0FBQyxDQUFDO1FBQ1B6QyxRQUFRLEVBQUU7VUFBRUosTUFBTSxFQUFFLFFBQVE7VUFBRUssUUFBUSxFQUFFLFFBQVE7VUFBRTZDLEdBQUcsRUFBRTtRQUFHLENBQUM7UUFDM0RDLFNBQVMsRUFBRTtVQUFFQyxHQUFHLEVBQUUsRUFBRTtVQUFFQyxRQUFRLEVBQUUsS0FBSztVQUFFQyxRQUFRLEVBQUUsS0FBSztVQUFFQyxTQUFTLEVBQUU7UUFBSyxDQUFDO1FBQ3pFQyxTQUFTLEVBQUVDLElBQUksQ0FBQ0MsR0FBRyxDQUFDLENBQUM7UUFDckJ2RCxNQUFNLEVBQUUsS0FBSztRQUNiRCxhQUFhLEVBQUU7TUFDbkIsQ0FBQztNQUNELElBQUlxQixRQUFRLEdBQUdqQyxjQUFjLENBQUNDLGNBQWMsQ0FBQzhFLGNBQWMsRUFBRTtRQUFFekUsU0FBUyxFQUFFSCxPQUFPLENBQUNHO01BQVUsQ0FBQyxDQUFDO01BQzlGLE9BQU91RSxPQUFPLENBQUNDLE9BQU8sQ0FBQzFDLGtCQUFrQixDQUFDSCxRQUFRLEVBQUU5QixPQUFPLENBQUMsQ0FBQztJQUNqRTtFQUNKOztFQUVBO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7RUFDSSxTQUFTNkUsUUFBUUEsQ0FBQzdFLE9BQU8sRUFBRTtJQUN2QkEsT0FBTyxHQUFHQSxPQUFPLElBQUksQ0FBQyxDQUFDO0lBRXZCLFNBQVM4RSxHQUFHQSxDQUFBLEVBQUc7TUFDWDtNQUNBLElBQUl4QyxRQUFRLEdBQUdqRSx1QkFBdUIsQ0FBQyxDQUFDO01BQ3hDLElBQUlpRSxRQUFRLENBQUN0RyxNQUFNLEdBQUcsQ0FBQyxFQUFFO1FBQ3JCa0ksV0FBVyxDQUFDbEUsT0FBTyxDQUFDO01BQ3hCO0lBQ0o7O0lBRUE7SUFDQSxJQUFJLE9BQU94QixRQUFRLEtBQUssV0FBVyxFQUFFO01BQ2pDLElBQUlBLFFBQVEsQ0FBQ3VHLFVBQVUsS0FBSyxTQUFTLEVBQUU7UUFDbkN2RyxRQUFRLENBQUN3RyxnQkFBZ0IsQ0FBQyxrQkFBa0IsRUFBRUYsR0FBRyxDQUFDO01BQ3RELENBQUMsTUFBTTtRQUNIQSxHQUFHLENBQUMsQ0FBQztNQUNUO0lBQ0o7RUFDSjs7RUFFQTtFQUNBO0VBQ0E7O0VBRUEsSUFBSUcsY0FBYyxHQUFHO0lBQ2pCO0lBQ0E7SUFDQUMsU0FBUyxFQUFFekssU0FBUztJQUNwQjBLLFlBQVksRUFBRSxTQUFkQSxZQUFZQSxDQUFZaEksSUFBSSxFQUFFO01BQUUsT0FBTzFDLFNBQVMsQ0FBQ3dELFFBQVEsQ0FBQ2QsSUFBSSxDQUFDO0lBQUMsQ0FBQztJQUNqRWUsV0FBVyxFQUFFQSxXQUFXO0lBQ3hCQyxXQUFXLEVBQUVBLFdBQVc7SUFDeEJpSCxZQUFZLEVBQUUvRyx1QkFBdUI7SUFDckNNLFdBQVcsRUFBRUEsV0FBVztJQUN4QjBHLE1BQU0sRUFBRXhGLGNBQWM7SUFDdEJxRSxXQUFXLEVBQUVBLFdBQVc7SUFDeEJJLGdCQUFnQixFQUFFQSxnQkFBZ0I7SUFDbENPLFFBQVEsRUFBRUEsUUFBUTtJQUNsQjFGLG9CQUFvQixFQUFFQSxvQkFBb0I7SUFDMUNRLHVCQUF1QixFQUFFQSx1QkFBdUI7SUFDaERzQyxrQkFBa0IsRUFBRUEsa0JBQWtCO0lBQ3RDcUIsY0FBYyxFQUFFQTtFQUNwQixDQUFDOztFQUVEO0VBQ0E5SSxJQUFJLENBQUN5SyxjQUFjLEdBQUdBLGNBQWM7QUFFeEMsQ0FBQyxFQUFFLE9BQU9LLE1BQU0sS0FBSyxXQUFXLEdBQUdBLE1BQU0sR0FBRyxPQUFPQyxNQUFNLEtBQUssV0FBVyxHQUFHQSxNQUFNLFNBQU8sQ0FBQyIsImlnbm9yZUxpc3QiOltdfQ==
|