fable 2.0.5 → 3.0.1

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/dist/fable.js CHANGED
@@ -1,1096 +1,1210 @@
1
- (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Fable = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
2
- /**
3
- * Base Logger Class
4
- *
5
- * @license MIT
6
- *
7
- * @author Steven Velozo <steven@velozo.com>
8
- */
9
- const libFableUUID = new (require('fable-uuid').FableUUID)();
10
-
11
- class BaseLogger
12
- {
13
- constructor(pLogStreamSettings, pFableLog)
14
- {
15
- // This should not possibly be able to be instantiated without a settings object
16
- this._Settings = pLogStreamSettings;
17
-
18
- // The base logger does nothing but associate a UUID with itself
19
- this.loggerUUID = libFableUUID.getUUID();
20
- }
21
-
22
- initialize()
23
- {
24
- // No operation.
25
- }
26
-
27
- trace(pLogText, pLogObject)
28
- {
29
- this.write("trace", pLogText, pLogObject);
30
- }
31
-
32
- debug(pLogText, pLogObject)
33
- {
34
- this.write("debug", pLogText, pLogObject);
35
- }
36
-
37
- info(pLogText, pLogObject)
38
- {
39
- this.write("info", pLogText, pLogObject);
40
- }
41
-
42
- warn(pLogText, pLogObject)
43
- {
44
- this.write("warn", pLogText, pLogObject);
45
- }
46
-
47
- error(pLogText, pLogObject)
48
- {
49
- this.write("error", pLogText, pLogObject);
50
- }
51
-
52
- fatal(pLogText, pLogObject)
53
- {
54
- this.write("fatal", pLogText, pLogObject);
55
- }
56
-
57
- write(pLogLevel, pLogText, pLogObject)
58
- {
59
- // The base logger does nothing.
60
- return true;
61
- }
62
- }
63
-
64
- module.exports = BaseLogger;
65
-
66
- },{"fable-uuid":9}],2:[function(require,module,exports){
67
- /**
68
- * Default Logger Provider Function --- Browser
69
- *
70
- * @license MIT
71
- *
72
- * @author Steven Velozo <steven@velozo.com>
73
- */
74
-
75
- // Return the providers that are available without extensions loaded
76
- getDefaultProviders = () =>
77
- {
78
- let tmpDefaultProviders = {};
79
-
80
- tmpDefaultProviders.console = require('./Fable-Log-Logger-Console.js');
81
- tmpDefaultProviders.default = tmpDefaultProviders.console;
82
-
83
- return tmpDefaultProviders;
84
- }
85
-
86
- module.exports = getDefaultProviders();
87
- },{"./Fable-Log-Logger-Console.js":4}],3:[function(require,module,exports){
88
- module.exports=[
89
- {
1
+ (function (f) {
2
+ if (typeof exports === "object" && typeof module !== "undefined") {
3
+ module.exports = f();
4
+ } else if (typeof define === "function" && define.amd) {
5
+ define([], f);
6
+ } else {
7
+ var g;
8
+ if (typeof window !== "undefined") {
9
+ g = window;
10
+ } else if (typeof global !== "undefined") {
11
+ g = global;
12
+ } else if (typeof self !== "undefined") {
13
+ g = self;
14
+ } else {
15
+ g = this;
16
+ }
17
+ g.Fable = f();
18
+ }
19
+ })(function () {
20
+ var define, module, exports;
21
+ return function () {
22
+ function r(e, n, t) {
23
+ function o(i, f) {
24
+ if (!n[i]) {
25
+ if (!e[i]) {
26
+ var c = "function" == typeof require && require;
27
+ if (!f && c) return c(i, !0);
28
+ if (u) return u(i, !0);
29
+ var a = new Error("Cannot find module '" + i + "'");
30
+ throw a.code = "MODULE_NOT_FOUND", a;
31
+ }
32
+ var p = n[i] = {
33
+ exports: {}
34
+ };
35
+ e[i][0].call(p.exports, function (r) {
36
+ var n = e[i][1][r];
37
+ return o(n || r);
38
+ }, p, p.exports, r, e, n, t);
39
+ }
40
+ return n[i].exports;
41
+ }
42
+ for (var u = "function" == typeof require && require, i = 0; i < t.length; i++) o(t[i]);
43
+ return o;
44
+ }
45
+ return r;
46
+ }()({
47
+ 1: [function (require, module, exports) {
48
+ /**
49
+ * Base Logger Class
50
+ *
51
+ * @license MIT
52
+ *
53
+ * @author Steven Velozo <steven@velozo.com>
54
+ */
55
+
56
+ class BaseLogger {
57
+ constructor(pLogStreamSettings, pFableLog) {
58
+ // This should not possibly be able to be instantiated without a settings object
59
+ this._Settings = pLogStreamSettings;
60
+
61
+ // The base logger does nothing but associate a UUID with itself
62
+ // We added this as the mechanism for tracking loggers to allow multiple simultaneous streams
63
+ // to the same provider.
64
+ this.loggerUUID = this.generateInsecureUUID();
65
+
66
+ // Eventually we can use this array to ompute which levels the provider allows.
67
+ // For now it's just used to precompute some string concatenations.
68
+ this.levels = ["trace", "debug", "info", "warn", "error", "fatal"];
69
+ }
70
+
71
+ // This is meant to generate programmatically insecure UUIDs to identify loggers
72
+ generateInsecureUUID() {
73
+ let tmpDate = new Date().getTime();
74
+ let tmpUUID = 'LOGSTREAM-xxxxxx-yxxxxx'.replace(/[xy]/g, pCharacter => {
75
+ // Funny algorithm from w3resource that is twister-ish without the deep math and security
76
+ // ..but good enough for unique log stream identifiers
77
+ let tmpRandomData = (tmpDate + Math.random() * 16) % 16 | 0;
78
+ tmpDate = Math.floor(tmpDate / 16);
79
+ return (pCharacter == 'x' ? tmpRandomData : tmpRandomData & 0x3 | 0x8).toString(16);
80
+ });
81
+ return tmpUUID;
82
+ }
83
+ initialize() {
84
+ // No operation.
85
+ }
86
+ trace(pLogText, pLogObject) {
87
+ this.write("trace", pLogText, pLogObject);
88
+ }
89
+ debug(pLogText, pLogObject) {
90
+ this.write("debug", pLogText, pLogObject);
91
+ }
92
+ info(pLogText, pLogObject) {
93
+ this.write("info", pLogText, pLogObject);
94
+ }
95
+ warn(pLogText, pLogObject) {
96
+ this.write("warn", pLogText, pLogObject);
97
+ }
98
+ error(pLogText, pLogObject) {
99
+ this.write("error", pLogText, pLogObject);
100
+ }
101
+ fatal(pLogText, pLogObject) {
102
+ this.write("fatal", pLogText, pLogObject);
103
+ }
104
+ write(pLogLevel, pLogText, pLogObject) {
105
+ // The base logger does nothing.
106
+ return true;
107
+ }
108
+ }
109
+ module.exports = BaseLogger;
110
+ }, {}],
111
+ 2: [function (require, module, exports) {
112
+ /**
113
+ * Default Logger Provider Function
114
+ *
115
+ * @license MIT
116
+ *
117
+ * @author Steven Velozo <steven@velozo.com>
118
+ */
119
+
120
+ // Return the providers that are available without extensions loaded
121
+ getDefaultProviders = () => {
122
+ let tmpDefaultProviders = {};
123
+ tmpDefaultProviders.console = require('./Fable-Log-Logger-Console.js');
124
+ tmpDefaultProviders.default = tmpDefaultProviders.console;
125
+ return tmpDefaultProviders;
126
+ };
127
+ module.exports = getDefaultProviders();
128
+ }, {
129
+ "./Fable-Log-Logger-Console.js": 4
130
+ }],
131
+ 3: [function (require, module, exports) {
132
+ module.exports = [{
90
133
  "loggertype": "console",
91
134
  "streamtype": "console",
92
135
  "level": "trace"
93
- }
94
- ]
95
- },{}],4:[function(require,module,exports){
96
- let libBaseLogger = require('./Fable-Log-BaseLogger.js');
97
-
98
- class ConsoleLogger extends libBaseLogger
99
- {
100
- constructor(pLogStreamSettings, pFableLog)
101
- {
102
- super(pLogStreamSettings)
103
-
104
- this._ShowTimeStamps = pLogStreamSettings.hasOwnProperty('ShowTimeStamps') ? (pLogStreamSettings.ShowTimeStamps == true) : false;
105
- this._FormattedTimeStamps = pLogStreamSettings.hasOwnProperty('FormattedTimeStamps') ? (pLogStreamSettings.FormattedTimeStamps == true) : false;
106
-
107
- this._ContextMessage = pLogStreamSettings.hasOwnProperty('Context') ? ` (${pLogStreamSettings.Context})` :
108
- pFableLog._Settings.hasOwnProperty('Product') ? ` (${pFableLog._Settings.Product})` :
109
- '';
110
- }
111
-
112
- write(pLevel, pLogText, pObject)
113
- {
114
- if (this._ShowTimeStamps && this._FormattedTimeStamps)
115
- {
116
- let tmpDate = (new Date()).toISOString();
117
- console.log(`${tmpDate} [${pLevel}]${this._ContextMessage} ${pLogText}`);
118
- }
119
- else if (this._ShowTimeStamps)
120
- {
121
- let tmpDate = +new Date();
122
- console.log(`${tmpDate} [${pLevel}]${this._ContextMessage} ${pLogText}`);
123
- }
124
- else
125
- {
126
- console.log(`[${pLevel}]${this._ContextMessage} ${pLogText}`);
127
- }
128
-
129
- // Write out the object on a separate line if it is passed in
130
- if (typeof(pObject) !== 'undefined')
131
- {
132
- console.log(JSON.stringify(pObject, null, 4));
133
- }
134
- }
135
-
136
- }
137
-
138
- module.exports = ConsoleLogger;
139
- },{"./Fable-Log-BaseLogger.js":1}],5:[function(require,module,exports){
140
- /**
141
- * Fable Logging Add-on
142
- *
143
- * @license MIT
144
- *
145
- * @author Steven Velozo <steven@velozo.com>
146
- * @module Fable Logger
147
- */
148
-
149
- /**
150
- * Fable Solution Log Wrapper Main Class
151
- *
152
- * @class FableLog
153
- * @constructor
154
- */
155
- class FableLog
156
- {
157
- constructor(pFableSettings, pFable)
158
- {
159
- let tmpSettings = (typeof(pFableSettings) === 'object') ? pFableSettings : {}
160
- this._Settings = tmpSettings;
161
-
162
- this._Providers = require('./Fable-Log-DefaultProviders.js');
163
-
164
- this._StreamDefinitions = (tmpSettings.hasOwnProperty('LogStreams')) ? tmpSettings.LogStreams : require('./Fable-Log-DefaultStreams.json');
165
-
166
- this.logStreams = [];
167
-
168
- // This object gets decorated for one-time instantiated providers that
169
- // have multiple outputs, such as bunyan.
170
- this.logProviders = {};
171
-
172
- // A hash list of the GUIDs for each log stream, so they can't be added to the set more than one time
173
- this.activeLogStreams = {};
174
-
175
- this.logStreamsTrace = [];
176
- this.logStreamsDebug = [];
177
- this.logStreamsInfo = [];
178
- this.logStreamsWarn = [];
179
- this.logStreamsError = [];
180
- this.logStreamsFatal = [];
181
-
182
- this.datumDecorator = (pDatum) => pDatum;
183
-
184
- this.uuid = (typeof(tmpSettings.Product) === 'string') ? tmpSettings.Product : 'Default';
185
- }
186
-
187
- addLogger(pLogger, pLevel)
188
- {
189
- // Bail out if we've already created one.
190
- if (this.activeLogStreams.hasOwnProperty(pLogger.loggerUUID))
191
- {
192
- return false;
193
- }
194
-
195
- // Add it to the streams and to the mutex
196
- this.logStreams.push(pLogger);
197
- this.activeLogStreams[pLogger.loggerUUID] = true;
198
-
199
- // Make sure a kosher level was passed in
200
- switch (pLevel)
201
- {
202
- case 'trace':
203
- this.logStreamsTrace.push(pLogger);
204
- case 'debug':
205
- this.logStreamsDebug.push(pLogger);
206
- case 'info':
207
- this.logStreamsInfo.push(pLogger);
208
- case 'warn':
209
- this.logStreamsWarn.push(pLogger);
210
- case 'error':
211
- this.logStreamsError.push(pLogger);
212
- case 'fatal':
213
- this.logStreamsFatal.push(pLogger);
214
- break;
215
- }
216
-
217
- return true;
218
- }
219
-
220
- setDatumDecorator(fDatumDecorator)
221
- {
222
- if (typeof(fDatumDecorator) === 'function')
223
- {
224
- this.datumDecorator = fDatumDecorator;
225
- }
226
- else
227
- {
228
- this.datumDecorator = (pDatum) => pDatum;
229
- }
230
- }
231
-
232
- trace(pMessage, pDatum)
233
- {
234
- const tmpDecoratedDatum = this.datumDecorator(pDatum);
235
- for (let i = 0; i < this.logStreamsTrace.length; i++)
236
- {
237
- this.logStreamsTrace[i].trace(pMessage, tmpDecoratedDatum);
238
- }
239
- }
240
-
241
- debug(pMessage, pDatum)
242
- {
243
- const tmpDecoratedDatum = this.datumDecorator(pDatum);
244
- for (let i = 0; i < this.logStreamsDebug.length; i++)
245
- {
246
- this.logStreamsDebug[i].debug(pMessage, tmpDecoratedDatum);
247
- }
248
- }
249
-
250
- info(pMessage, pDatum)
251
- {
252
- const tmpDecoratedDatum = this.datumDecorator(pDatum);
253
- for (let i = 0; i < this.logStreamsInfo.length; i++)
254
- {
255
- this.logStreamsInfo[i].info(pMessage, tmpDecoratedDatum);
256
- }
257
- }
258
-
259
- warn(pMessage, pDatum)
260
- {
261
- const tmpDecoratedDatum = this.datumDecorator(pDatum);
262
- for (let i = 0; i < this.logStreamsWarn.length; i++)
263
- {
264
- this.logStreamsWarn[i].warn(pMessage, tmpDecoratedDatum);
265
- }
266
- }
267
-
268
- error(pMessage, pDatum)
269
- {
270
- const tmpDecoratedDatum = this.datumDecorator(pDatum);
271
- for (let i = 0; i < this.logStreamsError.length; i++)
272
- {
273
- this.logStreamsError[i].error(pMessage, tmpDecoratedDatum);
274
- }
275
- }
276
-
277
- fatal(pMessage, pDatum)
278
- {
279
- const tmpDecoratedDatum = this.datumDecorator(pDatum);
280
- for (let i = 0; i < this.logStreamsFatal.length; i++)
281
- {
282
- this.logStreamsFatal[i].fatal(pMessage, tmpDecoratedDatum);
283
- }
284
- }
285
-
286
- initialize()
287
- {
288
- // "initialize" each logger as defined in the logging parameters
289
- for (let i = 0; i < this._StreamDefinitions.length; i++)
290
- {
291
- let tmpStreamDefinition = Object.assign({loggertype:'default',streamtype:'console',level:'info'},this._StreamDefinitions[i]);
292
-
293
- if (!this._Providers.hasOwnProperty(tmpStreamDefinition.loggertype))
294
- {
295
- console.log(`Error initializing log stream: bad loggertype in stream definition ${JSON.stringify(tmpStreamDefinition)}`);
296
- }
297
- else
298
- {
299
- this.addLogger(new this._Providers[tmpStreamDefinition.loggertype](tmpStreamDefinition, this), tmpStreamDefinition.level);
300
- }
301
- }
302
-
303
- // Now initialize each one.
304
- for (let i = 0; i < this.logStreams.length; i++)
305
- {
306
- this.logStreams[i].initialize();
307
- }
308
- }
309
-
310
- logTime(pMessage, pDatum)
311
- {
312
- let tmpMessage = (typeof(pMessage) !== 'undefined') ? pMessage : 'Time';
313
- let tmpTime = new Date();
314
- this.info(`${tmpMessage} ${tmpTime} (epoch ${+tmpTime})`, pDatum);
315
- }
316
-
317
- // Get a timestamp
318
- getTimeStamp()
319
- {
320
- return +new Date();
321
- }
322
-
323
- getTimeDelta(pTimeStamp)
324
- {
325
- let tmpEndTime = +new Date();
326
- return tmpEndTime-pTimeStamp;
327
- }
328
-
329
- // Log the delta between a timestamp, and now with a message
330
- logTimeDelta(pTimeDelta, pMessage, pDatum)
331
- {
332
- let tmpMessage = (typeof(pMessage) !== 'undefined') ? pMessage : 'Time Measurement';
333
- let tmpDatum = (typeof(pDatum) === 'object') ? pDatum : {};
334
-
335
- let tmpEndTime = +new Date();
336
-
337
- this.info(`${tmpMessage} logged at (epoch ${+tmpEndTime}) took (${pTimeDelta}ms)`, pDatum);
338
- }
339
-
340
- logTimeDeltaHuman(pTimeDelta, pMessage, pDatum)
341
- {
342
- let tmpMessage = (typeof(pMessage) !== 'undefined') ? pMessage : 'Time Measurement';
343
-
344
- let tmpEndTime = +new Date();
345
-
346
- let tmpMs = parseInt(pTimeDelta%1000);
347
- let tmpSeconds = parseInt((pTimeDelta/1000)%60);
348
- let tmpMinutes = parseInt((pTimeDelta/(1000*60))%60);
349
- let tmpHours = parseInt(pTimeDelta/(1000*60*60));
350
-
351
- tmpMs = (tmpMs < 10) ? "00"+tmpMs : (tmpMs < 100) ? "0"+tmpMs : tmpMs;
352
- tmpSeconds = (tmpSeconds < 10) ? "0"+tmpSeconds : tmpSeconds;
353
- tmpMinutes = (tmpMinutes < 10) ? "0"+tmpMinutes : tmpMinutes;
354
- tmpHours = (tmpHours < 10) ? "0"+tmpHours : tmpHours;
355
-
356
- this.info(`${tmpMessage} logged at (epoch ${+tmpEndTime}) took (${pTimeDelta}ms) or (${tmpHours}:${tmpMinutes}:${tmpSeconds}.${tmpMs})`, pDatum);
357
- }
358
-
359
- logTimeDeltaRelative(pStartTime, pMessage, pDatum)
360
- {
361
- this.logTimeDelta(this.getTimeDelta(pStartTime), pMessage, pDatum);
362
- }
363
-
364
- logTimeDeltaRelativeHuman(pStartTime, pMessage, pDatum)
365
- {
366
- this.logTimeDeltaHuman(this.getTimeDelta(pStartTime), pMessage, pDatum);
367
- }
368
- }
369
-
370
- // This is for backwards compatibility
371
- function autoConstruct(pSettings)
372
- {
373
- return new FableLog(pSettings);
374
- }
375
-
376
-
377
- module.exports = {new:autoConstruct, FableLog:FableLog};
378
-
379
- },{"./Fable-Log-DefaultProviders.js":2,"./Fable-Log-DefaultStreams.json":3}],6:[function(require,module,exports){
380
- module.exports={
381
- "Product": "ApplicationNameHere",
382
- "ProductVersion": "0.0.0",
383
-
384
- "ConfigFile": false,
385
-
386
- "LogStreams":
387
- [
388
- {
389
- "level": "trace"
390
- }
391
- ]
392
- }
393
-
394
- },{}],7:[function(require,module,exports){
395
- (function (process){(function (){
396
- /**
397
- * Fable Settings Add-on
398
- *
399
- * @license MIT
400
- *
401
- * @author Steven Velozo <steven@velozo.com>
402
- * @module Fable Settings
403
- */
404
-
405
- // needed since String.matchAll wasn't added to node until v12
406
- const libMatchAll = require('match-all');
407
-
408
- /**
409
- * Fable Solution Settings
410
- *
411
- * @class FableSettings
412
- * @constructor
413
- */
414
-
415
- class FableSettings
416
- {
417
- constructor(pFableSettings)
418
- {
419
- this.default = this.buildDefaultSettings();
420
-
421
- // Construct a new settings object
422
- let tmpSettings = this.merge(pFableSettings, this.buildDefaultSettings());
423
-
424
- // default environment variable templating to on
425
- this._PerformEnvTemplating = !tmpSettings || tmpSettings.NoEnvReplacement !== true;
426
-
427
- // The base settings object (what they were on initialization, before other actors have altered them)
428
- this.base = JSON.parse(JSON.stringify(tmpSettings));
429
-
430
- if (tmpSettings.DefaultConfigFile)
431
- {
432
- try
433
- {
434
- // If there is a DEFAULT configuration file, try to load and merge it.
435
- tmpSettings = this.merge(require(tmpSettings.DefaultConfigFile), tmpSettings);
436
- }
437
- catch (pException)
438
- {
439
- // Why this? Often for an app we want settings to work out of the box, but
440
- // would potentially want to have a config file for complex settings.
441
- console.log('Fable-Settings Warning: Default configuration file specified but there was a problem loading it. Falling back to base.');
442
- console.log(' Loading Exception: '+pException);
443
- }
444
- }
445
-
446
- if (tmpSettings.ConfigFile)
447
- {
448
- try
449
- {
450
- // If there is a configuration file, try to load and merge it.
451
- tmpSettings = this.merge(require(tmpSettings.ConfigFile), tmpSettings);
452
- }
453
- catch (pException)
454
- {
455
- // Why this? Often for an app we want settings to work out of the box, but
456
- // would potentially want to have a config file for complex settings.
457
- console.log('Fable-Settings Warning: Configuration file specified but there was a problem loading it. Falling back to base.');
458
- console.log(' Loading Exception: '+pException);
459
- }
460
- }
461
-
462
- this.settings = tmpSettings;
463
- }
464
-
465
- // Build a default settings object. Use the JSON jimmy to ensure it is always a new object.
466
- buildDefaultSettings()
467
- {
468
- return JSON.parse(JSON.stringify(require('./Fable-Settings-Default')));
469
- }
470
-
471
-
472
- // Resolve (recursive) any environment variables found in settings object.
473
- _resolveEnv(pSettings)
474
- {
475
- for (const tmpKey in pSettings)
476
- {
477
- const tmpValue = pSettings[tmpKey];
478
- if (typeof(tmpValue) === 'object') // && !Array.isArray(tmpValue))
479
- {
480
- this._resolveEnv(tmpValue);
481
- }
482
- else if (typeof(tmpValue) === 'string')
483
- {
484
- if (tmpValue.indexOf('${') >= 0)
485
- {
486
- //pick out and resolve env constiables from the settings value.
487
- const tmpMatches = libMatchAll(tmpValue, /\$\{(.*?)\}/g).toArray();
488
- tmpMatches.forEach((tmpMatch) =>
489
- {
490
- //format: VAR_NAME|DEFAULT_VALUE
491
- const tmpParts = tmpMatch.split('|');
492
- let tmpResolvedValue = process.env[tmpParts[0]] || '';
493
- if (!tmpResolvedValue && tmpParts.length > 1)
494
- {
495
- tmpResolvedValue = tmpParts[1];
496
- }
497
-
498
- pSettings[tmpKey] = pSettings[tmpKey].replace('${' + tmpMatch + '}', tmpResolvedValue);
499
- });
500
- }
501
- }
502
- }
503
- }
504
-
505
- /**
506
- * Check to see if a value is an object (but not an array).
507
- */
508
- _isObject(value)
509
- {
510
- return typeof(value) === 'object' && !Array.isArray(value);
511
- }
512
-
513
- /**
514
- * Merge two plain objects. Keys that are objects in both will be merged property-wise.
515
- */
516
- _deepMergeObjects(toObject, fromObject)
517
- {
518
- if (!fromObject || !this._isObject(fromObject))
519
- {
520
- return;
521
- }
522
- Object.keys(fromObject).forEach((key) =>
523
- {
524
- const fromValue = fromObject[key];
525
- if (this._isObject(fromValue))
526
- {
527
- const toValue = toObject[key];
528
- if (toValue && this._isObject(toValue))
529
- {
530
- // both are objects, so do a recursive merge
531
- this._deepMergeObjects(toValue, fromValue);
532
- return;
533
- }
534
- }
535
- toObject[key] = fromValue;
536
- });
537
- return toObject;
538
- }
539
-
540
- // Merge some new object into the existing settings.
541
- merge(pSettingsFrom, pSettingsTo)
542
- {
543
- // If an invalid settings from object is passed in (e.g. object constructor without passing in anything) this should still work
544
- let tmpSettingsFrom = (typeof(pSettingsFrom) === 'object') ? pSettingsFrom : {};
545
- // Default to the settings object if none is passed in for the merge.
546
- let tmpSettingsTo = (typeof(pSettingsTo) === 'object') ? pSettingsTo : this.settings;
547
-
548
- // do not mutate the From object property values
549
- let tmpSettingsFromCopy = JSON.parse(JSON.stringify(tmpSettingsFrom));
550
- tmpSettingsTo = this._deepMergeObjects(tmpSettingsTo, tmpSettingsFromCopy);
551
-
552
- if (this._PerformEnvTemplating)
553
- {
554
- this._resolveEnv(tmpSettingsTo);
555
- }
556
-
557
- return tmpSettingsTo;
558
- }
559
-
560
- // Fill in settings gaps without overwriting settings that are already there
561
- fill(pSettingsFrom)
562
- {
563
- // If an invalid settings from object is passed in (e.g. object constructor without passing in anything) this should still work
564
- let tmpSettingsFrom = (typeof(pSettingsFrom) === 'object') ? pSettingsFrom : {};
565
-
566
- // do not mutate the From object property values
567
- let tmpSettingsFromCopy = JSON.parse(JSON.stringify(tmpSettingsFrom));
568
-
569
- this.settings = this._deepMergeObjects(tmpSettingsFromCopy, this.settings);
570
-
571
- return this.settings;
572
- }
573
- };
574
-
575
- // This is for backwards compatibility
576
- function autoConstruct(pSettings)
577
- {
578
- return new FableSettings(pSettings);
579
- }
580
-
581
- module.exports = {new:autoConstruct, FableSettings:FableSettings};
582
-
583
- }).call(this)}).call(this,require('_process'))
584
-
585
- },{"./Fable-Settings-Default":6,"_process":11,"match-all":10}],8:[function(require,module,exports){
586
- /**
587
- * Random Byte Generator - Browser version
588
- *
589
- * @license MIT
590
- *
591
- * @author Steven Velozo <steven@velozo.com>
592
- */
593
-
594
- // Adapted from node-uuid (https://github.com/kelektiv/node-uuid)
595
- // Unique ID creation requires a high quality random # generator. In the
596
- // browser this is a little complicated due to unknown quality of Math.random()
597
- // and inconsistent support for the `crypto` API. We do the best we can via
598
- // feature-detection
599
- class RandomBytes
600
- {
601
- constructor()
602
- {
603
-
604
- // getRandomValues needs to be invoked in a context where "this" is a Crypto
605
- // implementation. Also, find the complete implementation of crypto on IE11.
606
- this.getRandomValues = (typeof(crypto) != 'undefined' && crypto.getRandomValues && crypto.getRandomValues.bind(crypto)) ||
607
- (typeof(msCrypto) != 'undefined' && typeof window.msCrypto.getRandomValues == 'function' && msCrypto.getRandomValues.bind(msCrypto));
608
- }
609
-
610
- // WHATWG crypto RNG - http://wiki.whatwg.org/wiki/Crypto
611
- generateWhatWGBytes()
612
- {
613
- let tmpBuffer = new Uint8Array(16); // eslint-disable-line no-undef
614
-
615
- this.getRandomValues(tmpBuffer);
616
- return tmpBuffer;
617
- }
618
-
619
- // Math.random()-based (RNG)
620
- generateRandomBytes()
621
- {
622
- // If all else fails, use Math.random(). It's fast, but is of unspecified
623
- // quality.
624
- let tmpBuffer = new Uint8Array(16); // eslint-disable-line no-undef
625
-
626
- for (let i = 0, tmpValue; i < 16; i++)
627
- {
628
- if ((i & 0x03) === 0)
629
- {
630
- tmpValue = Math.random() * 0x100000000;
631
- }
632
-
633
- tmpBuffer[i] = tmpValue >>> ((i & 0x03) << 3) & 0xff;
634
- }
635
-
636
- return tmpBuffer;
637
- }
638
-
639
- generate()
640
- {
641
- if (this.getRandomValues)
642
- {
643
- return this.generateWhatWGBytes();
644
- }
645
- else
646
- {
647
- return this.generateRandomBytes();
648
- }
649
- }
650
- }
651
-
652
- module.exports = RandomBytes;
653
-
654
- },{}],9:[function(require,module,exports){
655
- /**
656
- * Fable UUID Generator
657
- *
658
- * @license MIT
659
- *
660
- * @author Steven Velozo <steven@velozo.com>
661
- * @module Fable UUID
662
- */
663
-
664
- /**
665
- * Fable Solution UUID Generation Main Class
666
- *
667
- * @class FableUUID
668
- * @constructor
669
- */
670
-
671
- var libRandomByteGenerator = require('./Fable-UUID-Random.js')
672
-
673
- class FableUUID
674
- {
675
- constructor(pSettings)
676
- {
677
- // Determine if the module is in "Random UUID Mode" which means just use the random character function rather than the v4 random UUID spec.
678
- // Note this allows UUIDs of various lengths (including very short ones) although guaranteed uniqueness goes downhill fast.
679
- this._UUIDModeRandom = (typeof(pSettings) === 'object') && (pSettings.hasOwnProperty('UUIDModeRandom')) ? (pSettings.UUIDModeRandom == true) : false;
680
- // These two properties are only useful if we are in Random mode. Otherwise it generates a v4 spec
681
- // Length for "Random UUID Mode" is set -- if not set it to 8
682
- this._UUIDLength = (typeof(pSettings) === 'object') && (pSettings.hasOwnProperty('UUIDLength')) ? (pSettings.UUIDLength + 0) : 8;
683
- // Dictionary for "Random UUID Mode"
684
- this._UUIDRandomDictionary = (typeof(pSettings) === 'object') && (pSettings.hasOwnProperty('UUIDDictionary')) ? (pSettings.UUIDDictionary + 0) : '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
685
-
686
- this.randomByteGenerator = new libRandomByteGenerator();
687
-
688
- // Lookup table for hex codes
689
- this._HexLookup = [];
690
- for (let i = 0; i < 256; ++i)
691
- {
692
- this._HexLookup[i] = (i + 0x100).toString(16).substr(1);
693
- }
694
- }
695
-
696
- // Adapted from node-uuid (https://github.com/kelektiv/node-uuid)
697
- bytesToUUID(pBuffer)
698
- {
699
- let i = 0;
700
- // join used to fix memory issue caused by concatenation: https://bugs.chromium.org/p/v8/issues/detail?id=3175#c4
701
- return ([
702
- this._HexLookup[pBuffer[i++]], this._HexLookup[pBuffer[i++]],
703
- this._HexLookup[pBuffer[i++]], this._HexLookup[pBuffer[i++]], '-',
704
- this._HexLookup[pBuffer[i++]], this._HexLookup[pBuffer[i++]], '-',
705
- this._HexLookup[pBuffer[i++]], this._HexLookup[pBuffer[i++]], '-',
706
- this._HexLookup[pBuffer[i++]], this._HexLookup[pBuffer[i++]], '-',
707
- this._HexLookup[pBuffer[i++]], this._HexLookup[pBuffer[i++]], this._HexLookup[pBuffer[i++]], this._HexLookup[pBuffer[i++]], this._HexLookup[pBuffer[i++]], this._HexLookup[pBuffer[i++]]
708
- ]).join('');
709
- }
710
-
711
- // Adapted from node-uuid (https://github.com/kelektiv/node-uuid)
712
- generateUUIDv4()
713
- {
714
- let tmpBuffer = new Array(16);
715
- var tmpRandomBytes = this.randomByteGenerator.generate();
716
-
717
- // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
718
- tmpRandomBytes[6] = (tmpRandomBytes[6] & 0x0f) | 0x40;
719
- tmpRandomBytes[8] = (tmpRandomBytes[8] & 0x3f) | 0x80;
720
-
721
- return this.bytesToUUID(tmpRandomBytes);
722
- }
723
-
724
- // Simple random UUID generation
725
- generateRandom()
726
- {
727
- let tmpUUID = '';
728
-
729
- for (let i = 0; i < this._UUIDLength; i++)
730
- {
731
- tmpUUID += this._UUIDRandomDictionary.charAt(Math.floor(Math.random() * (this._UUIDRandomDictionary.length-1)));
732
- }
733
-
734
- return tmpUUID;
735
- }
736
-
737
- // Adapted from node-uuid (https://github.com/kelektiv/node-uuid)
738
- getUUID()
739
- {
740
- if (this._UUIDModeRandom)
741
- {
742
- return this.generateRandom();
743
- }
744
- else
745
- {
746
- return this.generateUUIDv4();
747
- }
748
- }
749
- }
750
-
751
- // This is for backwards compatibility
752
- function autoConstruct(pSettings)
753
- {
754
- return new FableUUID(pSettings);
755
- }
756
-
757
-
758
- module.exports = {new:autoConstruct, FableUUID:FableUUID};
759
-
760
- },{"./Fable-UUID-Random.js":8}],10:[function(require,module,exports){
761
- "use strict";
762
-
763
- /**
764
- * matchAll
765
- * Get all the matches for a regular expression in a string.
766
- *
767
- * @name matchAll
768
- * @function
769
- * @param {String} s The input string.
770
- * @param {RegExp} r The regular expression.
771
- * @return {Object} An object containing the following fields:
772
- *
773
- * - `input` (String): The input string.
774
- * - `regex` (RegExp): The regular expression.
775
- * - `next` (Function): Get the next match.
776
- * - `toArray` (Function): Get all the matches.
777
- * - `reset` (Function): Reset the index.
778
- */
779
- module.exports = function matchAll(s, r) {
780
- return {
781
- input: s,
782
- regex: r
136
+ }];
137
+ }, {}],
138
+ 4: [function (require, module, exports) {
139
+ let libBaseLogger = require('./Fable-Log-BaseLogger.js');
140
+ class ConsoleLogger extends libBaseLogger {
141
+ constructor(pLogStreamSettings, pFableLog) {
142
+ super(pLogStreamSettings);
143
+ this._ShowTimeStamps = pLogStreamSettings.hasOwnProperty('showtimestamps') ? pLogStreamSettings.showtimestamps == true : false;
144
+ this._FormattedTimeStamps = pLogStreamSettings.hasOwnProperty('formattedtimestamps') ? pLogStreamSettings.formattedtimestamps == true : false;
145
+ this._ContextMessage = pLogStreamSettings.hasOwnProperty('Context') ? `(${pLogStreamSettings.Context})` : pFableLog._Settings.hasOwnProperty('Product') ? `(${pFableLog._Settings.Product})` : 'Unnamed_Log_Context';
146
+
147
+ // Allow the user to decide what gets output to the console
148
+ this._OutputLogLinesToConsole = pLogStreamSettings.hasOwnProperty('outputloglinestoconsole') ? pLogStreamSettings.outputloglinestoconsole : true;
149
+ this._OutputObjectsToConsole = pLogStreamSettings.hasOwnProperty('outputobjectstoconsole') ? pLogStreamSettings.outputobjectstoconsole : true;
150
+
151
+ // Precompute the prefix for each level
152
+ this.prefixCache = {};
153
+ for (let i = 0; i <= this.levels.length; i++) {
154
+ this.prefixCache[this.levels[i]] = `[${this.levels[i]}] ${this._ContextMessage}: `;
155
+ if (this._ShowTimeStamps) {
156
+ // If there is a timestamp we need a to prepend space before the prefixcache string, since the timestamp comes first
157
+ this.prefixCache[this.levels[i]] = ' ' + this.prefixCache[this.levels[i]];
158
+ }
159
+ }
160
+ }
161
+ write(pLevel, pLogText, pObject) {
162
+ let tmpTimeStamp = '';
163
+ if (this._ShowTimeStamps && this._FormattedTimeStamps) {
164
+ tmpTimeStamp = new Date().toISOString();
165
+ } else if (this._ShowTimeStamps) {
166
+ tmpTimeStamp = +new Date();
167
+ }
168
+ let tmpLogLine = `${tmpTimeStamp}${this.prefixCache[pLevel]}${pLogText}`;
169
+ if (this._OutputLogLinesToConsole) {
170
+ console.log(tmpLogLine);
171
+ }
172
+
173
+ // Write out the object on a separate line if it is passed in
174
+ if (this._OutputObjectsToConsole && typeof pObject !== 'undefined') {
175
+ console.log(JSON.stringify(pObject, null, 2));
176
+ }
177
+
178
+ // Provide an easy way to be overridden and be consistent
179
+ return tmpLogLine;
180
+ }
181
+ }
182
+ module.exports = ConsoleLogger;
183
+ }, {
184
+ "./Fable-Log-BaseLogger.js": 1
185
+ }],
186
+ 5: [function (require, module, exports) {
187
+ /**
188
+ * Fable Logging Add-on
189
+ *
190
+ * @license MIT
191
+ *
192
+ * @author Steven Velozo <steven@velozo.com>
193
+ * @module Fable Logger
194
+ */
195
+
196
+ /**
197
+ * Fable Solution Log Wrapper Main Class
198
+ *
199
+ * @class FableLog
200
+ * @constructor
201
+ */
202
+ class FableLog {
203
+ constructor(pFableSettings, pFable) {
204
+ let tmpSettings = typeof pFableSettings === 'object' ? pFableSettings : {};
205
+ this._Settings = tmpSettings;
206
+ this._Providers = require('./Fable-Log-DefaultProviders-Node.js');
207
+ this._StreamDefinitions = tmpSettings.hasOwnProperty('LogStreams') ? tmpSettings.LogStreams : require('./Fable-Log-DefaultStreams.json');
208
+ this.logStreams = [];
209
+
210
+ // This object gets decorated for one-time instantiated providers that
211
+ // have multiple outputs, such as bunyan.
212
+ this.logProviders = {};
213
+
214
+ // A hash list of the GUIDs for each log stream, so they can't be added to the set more than one time
215
+ this.activeLogStreams = {};
216
+ this.logStreamsTrace = [];
217
+ this.logStreamsDebug = [];
218
+ this.logStreamsInfo = [];
219
+ this.logStreamsWarn = [];
220
+ this.logStreamsError = [];
221
+ this.logStreamsFatal = [];
222
+ this.datumDecorator = pDatum => pDatum;
223
+ this.uuid = typeof tmpSettings.Product === 'string' ? tmpSettings.Product : 'Default';
224
+ }
225
+ addLogger(pLogger, pLevel) {
226
+ // Bail out if we've already created one.
227
+ if (this.activeLogStreams.hasOwnProperty(pLogger.loggerUUID)) {
228
+ return false;
229
+ }
230
+
231
+ // Add it to the streams and to the mutex
232
+ this.logStreams.push(pLogger);
233
+ this.activeLogStreams[pLogger.loggerUUID] = true;
234
+
235
+ // Make sure a kosher level was passed in
236
+ switch (pLevel) {
237
+ case 'trace':
238
+ this.logStreamsTrace.push(pLogger);
239
+ case 'debug':
240
+ this.logStreamsDebug.push(pLogger);
241
+ case 'info':
242
+ this.logStreamsInfo.push(pLogger);
243
+ case 'warn':
244
+ this.logStreamsWarn.push(pLogger);
245
+ case 'error':
246
+ this.logStreamsError.push(pLogger);
247
+ case 'fatal':
248
+ this.logStreamsFatal.push(pLogger);
249
+ break;
250
+ }
251
+ return true;
252
+ }
253
+ setDatumDecorator(fDatumDecorator) {
254
+ if (typeof fDatumDecorator === 'function') {
255
+ this.datumDecorator = fDatumDecorator;
256
+ } else {
257
+ this.datumDecorator = pDatum => pDatum;
258
+ }
259
+ }
260
+ trace(pMessage, pDatum) {
261
+ const tmpDecoratedDatum = this.datumDecorator(pDatum);
262
+ for (let i = 0; i < this.logStreamsTrace.length; i++) {
263
+ this.logStreamsTrace[i].trace(pMessage, tmpDecoratedDatum);
264
+ }
265
+ }
266
+ debug(pMessage, pDatum) {
267
+ const tmpDecoratedDatum = this.datumDecorator(pDatum);
268
+ for (let i = 0; i < this.logStreamsDebug.length; i++) {
269
+ this.logStreamsDebug[i].debug(pMessage, tmpDecoratedDatum);
270
+ }
271
+ }
272
+ info(pMessage, pDatum) {
273
+ const tmpDecoratedDatum = this.datumDecorator(pDatum);
274
+ for (let i = 0; i < this.logStreamsInfo.length; i++) {
275
+ this.logStreamsInfo[i].info(pMessage, tmpDecoratedDatum);
276
+ }
277
+ }
278
+ warn(pMessage, pDatum) {
279
+ const tmpDecoratedDatum = this.datumDecorator(pDatum);
280
+ for (let i = 0; i < this.logStreamsWarn.length; i++) {
281
+ this.logStreamsWarn[i].warn(pMessage, tmpDecoratedDatum);
282
+ }
283
+ }
284
+ error(pMessage, pDatum) {
285
+ const tmpDecoratedDatum = this.datumDecorator(pDatum);
286
+ for (let i = 0; i < this.logStreamsError.length; i++) {
287
+ this.logStreamsError[i].error(pMessage, tmpDecoratedDatum);
288
+ }
289
+ }
290
+ fatal(pMessage, pDatum) {
291
+ const tmpDecoratedDatum = this.datumDecorator(pDatum);
292
+ for (let i = 0; i < this.logStreamsFatal.length; i++) {
293
+ this.logStreamsFatal[i].fatal(pMessage, tmpDecoratedDatum);
294
+ }
295
+ }
296
+ initialize() {
297
+ // "initialize" each logger as defined in the logging parameters
298
+ for (let i = 0; i < this._StreamDefinitions.length; i++) {
299
+ let tmpStreamDefinition = Object.assign({
300
+ loggertype: 'default',
301
+ streamtype: 'console',
302
+ level: 'info'
303
+ }, this._StreamDefinitions[i]);
304
+ if (!this._Providers.hasOwnProperty(tmpStreamDefinition.loggertype)) {
305
+ console.log(`Error initializing log stream: bad loggertype in stream definition ${JSON.stringify(tmpStreamDefinition)}`);
306
+ } else {
307
+ this.addLogger(new this._Providers[tmpStreamDefinition.loggertype](tmpStreamDefinition, this), tmpStreamDefinition.level);
308
+ }
309
+ }
783
310
 
784
- /**
785
- * next
786
- * Get the next match in single group match.
787
- *
788
- * @name next
789
- * @function
790
- * @return {String|null} The matched snippet.
791
- */
792
- , next: function next() {
793
- var c = this.nextRaw();
794
- if (c) {
795
- for (var i = 1; i < c.length; i++) {
796
- if (c[i]) {
797
- return c[i];
798
- }
311
+ // Now initialize each one.
312
+ for (let i = 0; i < this.logStreams.length; i++) {
313
+ this.logStreams[i].initialize();
314
+ }
315
+ }
316
+ logTime(pMessage, pDatum) {
317
+ let tmpMessage = typeof pMessage !== 'undefined' ? pMessage : 'Time';
318
+ let tmpTime = new Date();
319
+ this.info(`${tmpMessage} ${tmpTime} (epoch ${+tmpTime})`, pDatum);
320
+ }
321
+
322
+ // Get a timestamp
323
+ getTimeStamp() {
324
+ return +new Date();
325
+ }
326
+ getTimeDelta(pTimeStamp) {
327
+ let tmpEndTime = +new Date();
328
+ return tmpEndTime - pTimeStamp;
329
+ }
330
+
331
+ // Log the delta between a timestamp, and now with a message
332
+ logTimeDelta(pTimeDelta, pMessage, pDatum) {
333
+ let tmpMessage = typeof pMessage !== 'undefined' ? pMessage : 'Time Measurement';
334
+ let tmpDatum = typeof pDatum === 'object' ? pDatum : {};
335
+ let tmpEndTime = +new Date();
336
+ this.info(`${tmpMessage} logged at (epoch ${+tmpEndTime}) took (${pTimeDelta}ms)`, pDatum);
337
+ }
338
+ logTimeDeltaHuman(pTimeDelta, pMessage, pDatum) {
339
+ let tmpMessage = typeof pMessage !== 'undefined' ? pMessage : 'Time Measurement';
340
+ let tmpEndTime = +new Date();
341
+ let tmpMs = parseInt(pTimeDelta % 1000);
342
+ let tmpSeconds = parseInt(pTimeDelta / 1000 % 60);
343
+ let tmpMinutes = parseInt(pTimeDelta / (1000 * 60) % 60);
344
+ let tmpHours = parseInt(pTimeDelta / (1000 * 60 * 60));
345
+ tmpMs = tmpMs < 10 ? "00" + tmpMs : tmpMs < 100 ? "0" + tmpMs : tmpMs;
346
+ tmpSeconds = tmpSeconds < 10 ? "0" + tmpSeconds : tmpSeconds;
347
+ tmpMinutes = tmpMinutes < 10 ? "0" + tmpMinutes : tmpMinutes;
348
+ tmpHours = tmpHours < 10 ? "0" + tmpHours : tmpHours;
349
+ this.info(`${tmpMessage} logged at (epoch ${+tmpEndTime}) took (${pTimeDelta}ms) or (${tmpHours}:${tmpMinutes}:${tmpSeconds}.${tmpMs})`, pDatum);
350
+ }
351
+ logTimeDeltaRelative(pStartTime, pMessage, pDatum) {
352
+ this.logTimeDelta(this.getTimeDelta(pStartTime), pMessage, pDatum);
353
+ }
354
+ logTimeDeltaRelativeHuman(pStartTime, pMessage, pDatum) {
355
+ this.logTimeDeltaHuman(this.getTimeDelta(pStartTime), pMessage, pDatum);
356
+ }
357
+ }
358
+
359
+ // This is for backwards compatibility
360
+ function autoConstruct(pSettings) {
361
+ return new FableLog(pSettings);
362
+ }
363
+ module.exports = {
364
+ new: autoConstruct,
365
+ FableLog: FableLog
366
+ };
367
+ }, {
368
+ "./Fable-Log-DefaultProviders-Node.js": 2,
369
+ "./Fable-Log-DefaultStreams.json": 3
370
+ }],
371
+ 6: [function (require, module, exports) {
372
+ module.exports = {
373
+ "Product": "ApplicationNameHere",
374
+ "ProductVersion": "0.0.0",
375
+ "ConfigFile": false,
376
+ "LogStreams": [{
377
+ "level": "trace"
378
+ }]
379
+ };
380
+ }, {}],
381
+ 7: [function (require, module, exports) {
382
+ (function (process) {
383
+ (function () {
384
+ /**
385
+ * Fable Settings Template Processor
386
+ *
387
+ * This class allows environment variables to come in via templated expressions, and defaults to be set.
388
+ *
389
+ * @license MIT
390
+ *
391
+ * @author Steven Velozo <steven@velozo.com>
392
+ * @module Fable Settings
393
+ */
394
+
395
+ class FableSettingsTemplateProcessor {
396
+ constructor(pDependencies) {
397
+ // Use a no-dependencies templating engine to parse out environment variables
398
+ this.templateProcessor = new pDependencies.precedent();
399
+
400
+ // TODO: Make the environment variable wrap expression demarcation characters configurable?
401
+ this.templateProcessor.addPattern('${', '}', pTemplateValue => {
402
+ let tmpTemplateValue = pTemplateValue.trim();
403
+ let tmpSeparatorIndex = tmpTemplateValue.indexOf('|');
404
+
405
+ // If there is no pipe, the default value will end up being whatever the variable name is.
406
+ let tmpDefaultValue = tmpTemplateValue.substring(tmpSeparatorIndex + 1);
407
+ let tmpEnvironmentVariableName = tmpSeparatorIndex > -1 ? tmpTemplateValue.substring(0, tmpSeparatorIndex) : tmpTemplateValue;
408
+ if (process.env.hasOwnProperty(tmpEnvironmentVariableName)) {
409
+ return process.env[tmpEnvironmentVariableName];
410
+ } else {
411
+ return tmpDefaultValue;
799
412
  }
413
+ });
800
414
  }
801
- return null;
415
+ parseSetting(pString) {
416
+ return this.templateProcessor.parseString(pString);
417
+ }
418
+ }
419
+ module.exports = FableSettingsTemplateProcessor;
420
+ }).call(this);
421
+ }).call(this, require('_process'));
422
+ }, {
423
+ "_process": 14
424
+ }],
425
+ 8: [function (require, module, exports) {
426
+ /**
427
+ * Fable Settings Add-on
428
+ *
429
+ * @license MIT
430
+ *
431
+ * @author Steven Velozo <steven@velozo.com>
432
+ * @module Fable Settings
433
+ */
434
+
435
+ const libPrecedent = require('precedent');
436
+ const libFableSettingsTemplateProcessor = require('./Fable-Settings-TemplateProcessor.js');
437
+ class FableSettings {
438
+ constructor(pFableSettings) {
439
+ // Expose the dependencies for downstream re-use
440
+ this.dependencies = {
441
+ precedent: libPrecedent
442
+ };
443
+
444
+ // Initialize the settings value template processor
445
+ this.settingsTemplateProcessor = new libFableSettingsTemplateProcessor(this.dependencies);
446
+
447
+ // set straight away so anything that uses it respects the initial setting
448
+ this._configureEnvTemplating(pFableSettings);
449
+ this.default = this.buildDefaultSettings();
450
+
451
+ // Construct a new settings object
452
+ let tmpSettings = this.merge(pFableSettings, this.buildDefaultSettings());
453
+
454
+ // The base settings object (what they were on initialization, before other actors have altered them)
455
+ this.base = JSON.parse(JSON.stringify(tmpSettings));
456
+ if (tmpSettings.DefaultConfigFile) {
457
+ try {
458
+ // If there is a DEFAULT configuration file, try to load and merge it.
459
+ tmpSettings = this.merge(require(tmpSettings.DefaultConfigFile), tmpSettings);
460
+ } catch (pException) {
461
+ // Why this? Often for an app we want settings to work out of the box, but
462
+ // would potentially want to have a config file for complex settings.
463
+ console.log('Fable-Settings Warning: Default configuration file specified but there was a problem loading it. Falling back to base.');
464
+ console.log(' Loading Exception: ' + pException);
465
+ }
466
+ }
467
+ if (tmpSettings.ConfigFile) {
468
+ try {
469
+ // If there is a configuration file, try to load and merge it.
470
+ tmpSettings = this.merge(require(tmpSettings.ConfigFile), tmpSettings);
471
+ } catch (pException) {
472
+ // Why this? Often for an app we want settings to work out of the box, but
473
+ // would potentially want to have a config file for complex settings.
474
+ console.log('Fable-Settings Warning: Configuration file specified but there was a problem loading it. Falling back to base.');
475
+ console.log(' Loading Exception: ' + pException);
476
+ }
477
+ }
478
+ this.settings = tmpSettings;
479
+ }
480
+
481
+ // Build a default settings object. Use the JSON jimmy to ensure it is always a new object.
482
+ buildDefaultSettings() {
483
+ return JSON.parse(JSON.stringify(require('./Fable-Settings-Default')));
484
+ }
485
+
486
+ // Update the configuration for environment variable templating based on the current settings object
487
+ _configureEnvTemplating(pSettings) {
488
+ // default environment variable templating to on
489
+ this._PerformEnvTemplating = !pSettings || pSettings.NoEnvReplacement !== true;
490
+ }
491
+
492
+ // Resolve (recursive) any environment variables found in settings object.
493
+ _resolveEnv(pSettings) {
494
+ for (const tmpKey in pSettings) {
495
+ if (typeof pSettings[tmpKey] === 'object') {
496
+ this._resolveEnv(pSettings[tmpKey]);
497
+ } else if (typeof pSettings[tmpKey] === 'string') {
498
+ pSettings[tmpKey] = this.settingsTemplateProcessor.parseSetting(pSettings[tmpKey]);
499
+ }
500
+ }
802
501
  }
803
502
 
804
503
  /**
805
- * nextRaw
806
- * Get the next match in raw regex output. Usefull to get another group match.
807
- *
808
- * @name nextRaw
809
- * @function
810
- * @returns {Array|null} The matched snippet
504
+ * Check to see if a value is an object (but not an array).
811
505
  */
812
- ,
813
- nextRaw: function nextRaw() {
814
- var c = this.regex.exec(this.input);
815
- return c;
506
+ _isObject(value) {
507
+ return typeof value === 'object' && !Array.isArray(value);
816
508
  }
817
509
 
818
510
  /**
819
- * toArray
820
- * Get all the matches.
821
- *
822
- * @name toArray
823
- * @function
824
- * @return {Array} The matched snippets.
511
+ * Merge two plain objects. Keys that are objects in both will be merged property-wise.
825
512
  */
826
- ,
827
- toArray: function toArray() {
828
- var res = [],
829
- c = null;
513
+ _deepMergeObjects(toObject, fromObject) {
514
+ if (!fromObject || !this._isObject(fromObject)) {
515
+ return;
516
+ }
517
+ Object.keys(fromObject).forEach(key => {
518
+ const fromValue = fromObject[key];
519
+ if (this._isObject(fromValue)) {
520
+ const toValue = toObject[key];
521
+ if (toValue && this._isObject(toValue)) {
522
+ // both are objects, so do a recursive merge
523
+ this._deepMergeObjects(toValue, fromValue);
524
+ return;
525
+ }
526
+ }
527
+ toObject[key] = fromValue;
528
+ });
529
+ return toObject;
530
+ }
531
+
532
+ // Merge some new object into the existing settings.
533
+ merge(pSettingsFrom, pSettingsTo) {
534
+ // If an invalid settings from object is passed in (e.g. object constructor without passing in anything) this should still work
535
+ let tmpSettingsFrom = typeof pSettingsFrom === 'object' ? pSettingsFrom : {};
536
+ // Default to the settings object if none is passed in for the merge.
537
+ let tmpSettingsTo = typeof pSettingsTo === 'object' ? pSettingsTo : this.settings;
538
+
539
+ // do not mutate the From object property values
540
+ let tmpSettingsFromCopy = JSON.parse(JSON.stringify(tmpSettingsFrom));
541
+ tmpSettingsTo = this._deepMergeObjects(tmpSettingsTo, tmpSettingsFromCopy);
542
+ if (this._PerformEnvTemplating) {
543
+ this._resolveEnv(tmpSettingsTo);
544
+ }
545
+ // Update env tempating config, since we just updated the config object, and it may have changed
546
+ this._configureEnvTemplating(tmpSettingsTo);
547
+ return tmpSettingsTo;
548
+ }
549
+
550
+ // Fill in settings gaps without overwriting settings that are already there
551
+ fill(pSettingsFrom) {
552
+ // If an invalid settings from object is passed in (e.g. object constructor without passing in anything) this should still work
553
+ let tmpSettingsFrom = typeof pSettingsFrom === 'object' ? pSettingsFrom : {};
554
+
555
+ // do not mutate the From object property values
556
+ let tmpSettingsFromCopy = JSON.parse(JSON.stringify(tmpSettingsFrom));
557
+ this.settings = this._deepMergeObjects(tmpSettingsFromCopy, this.settings);
558
+ return this.settings;
559
+ }
560
+ }
561
+ ;
562
+
563
+ // This is for backwards compatibility
564
+ function autoConstruct(pSettings) {
565
+ return new FableSettings(pSettings);
566
+ }
567
+ module.exports = {
568
+ new: autoConstruct,
569
+ FableSettings: FableSettings
570
+ };
571
+ }, {
572
+ "./Fable-Settings-Default": 6,
573
+ "./Fable-Settings-TemplateProcessor.js": 7,
574
+ "precedent": 11
575
+ }],
576
+ 9: [function (require, module, exports) {
577
+ /**
578
+ * Random Byte Generator - Browser version
579
+ *
580
+ * @license MIT
581
+ *
582
+ * @author Steven Velozo <steven@velozo.com>
583
+ */
584
+
585
+ // Adapted from node-uuid (https://github.com/kelektiv/node-uuid)
586
+ // Unique ID creation requires a high quality random # generator. In the
587
+ // browser this is a little complicated due to unknown quality of Math.random()
588
+ // and inconsistent support for the `crypto` API. We do the best we can via
589
+ // feature-detection
590
+ class RandomBytes {
591
+ constructor() {
592
+ // getRandomValues needs to be invoked in a context where "this" is a Crypto
593
+ // implementation. Also, find the complete implementation of crypto on IE11.
594
+ this.getRandomValues = typeof crypto != 'undefined' && crypto.getRandomValues && crypto.getRandomValues.bind(crypto) || typeof msCrypto != 'undefined' && typeof window.msCrypto.getRandomValues == 'function' && msCrypto.getRandomValues.bind(msCrypto);
595
+ }
596
+
597
+ // WHATWG crypto RNG - http://wiki.whatwg.org/wiki/Crypto
598
+ generateWhatWGBytes() {
599
+ let tmpBuffer = new Uint8Array(16); // eslint-disable-line no-undef
600
+
601
+ this.getRandomValues(tmpBuffer);
602
+ return tmpBuffer;
603
+ }
830
604
 
831
- while (c = this.next()) {
832
- res.push(c);
605
+ // Math.random()-based (RNG)
606
+ generateRandomBytes() {
607
+ // If all else fails, use Math.random(). It's fast, but is of unspecified
608
+ // quality.
609
+ let tmpBuffer = new Uint8Array(16); // eslint-disable-line no-undef
610
+
611
+ for (let i = 0, tmpValue; i < 16; i++) {
612
+ if ((i & 0x03) === 0) {
613
+ tmpValue = Math.random() * 0x100000000;
833
614
  }
615
+ tmpBuffer[i] = tmpValue >>> ((i & 0x03) << 3) & 0xff;
616
+ }
617
+ return tmpBuffer;
618
+ }
619
+ generate() {
620
+ if (this.getRandomValues) {
621
+ return this.generateWhatWGBytes();
622
+ } else {
623
+ return this.generateRandomBytes();
624
+ }
625
+ }
626
+ }
627
+ module.exports = RandomBytes;
628
+ }, {}],
629
+ 10: [function (require, module, exports) {
630
+ /**
631
+ * Fable UUID Generator
632
+ *
633
+ * @license MIT
634
+ *
635
+ * @author Steven Velozo <steven@velozo.com>
636
+ * @module Fable UUID
637
+ */
638
+
639
+ /**
640
+ * Fable Solution UUID Generation Main Class
641
+ *
642
+ * @class FableUUID
643
+ * @constructor
644
+ */
645
+
646
+ var libRandomByteGenerator = require('./Fable-UUID-Random.js');
647
+ class FableUUID {
648
+ constructor(pSettings) {
649
+ // Determine if the module is in "Random UUID Mode" which means just use the random character function rather than the v4 random UUID spec.
650
+ // Note this allows UUIDs of various lengths (including very short ones) although guaranteed uniqueness goes downhill fast.
651
+ this._UUIDModeRandom = typeof pSettings === 'object' && pSettings.hasOwnProperty('UUIDModeRandom') ? pSettings.UUIDModeRandom == true : false;
652
+ // These two properties are only useful if we are in Random mode. Otherwise it generates a v4 spec
653
+ // Length for "Random UUID Mode" is set -- if not set it to 8
654
+ this._UUIDLength = typeof pSettings === 'object' && pSettings.hasOwnProperty('UUIDLength') ? pSettings.UUIDLength + 0 : 8;
655
+ // Dictionary for "Random UUID Mode"
656
+ this._UUIDRandomDictionary = typeof pSettings === 'object' && pSettings.hasOwnProperty('UUIDDictionary') ? pSettings.UUIDDictionary + 0 : '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
657
+ this.randomByteGenerator = new libRandomByteGenerator();
658
+
659
+ // Lookup table for hex codes
660
+ this._HexLookup = [];
661
+ for (let i = 0; i < 256; ++i) {
662
+ this._HexLookup[i] = (i + 0x100).toString(16).substr(1);
663
+ }
664
+ }
665
+
666
+ // Adapted from node-uuid (https://github.com/kelektiv/node-uuid)
667
+ bytesToUUID(pBuffer) {
668
+ let i = 0;
669
+ // join used to fix memory issue caused by concatenation: https://bugs.chromium.org/p/v8/issues/detail?id=3175#c4
670
+ return [this._HexLookup[pBuffer[i++]], this._HexLookup[pBuffer[i++]], this._HexLookup[pBuffer[i++]], this._HexLookup[pBuffer[i++]], '-', this._HexLookup[pBuffer[i++]], this._HexLookup[pBuffer[i++]], '-', this._HexLookup[pBuffer[i++]], this._HexLookup[pBuffer[i++]], '-', this._HexLookup[pBuffer[i++]], this._HexLookup[pBuffer[i++]], '-', this._HexLookup[pBuffer[i++]], this._HexLookup[pBuffer[i++]], this._HexLookup[pBuffer[i++]], this._HexLookup[pBuffer[i++]], this._HexLookup[pBuffer[i++]], this._HexLookup[pBuffer[i++]]].join('');
671
+ }
672
+
673
+ // Adapted from node-uuid (https://github.com/kelektiv/node-uuid)
674
+ generateUUIDv4() {
675
+ let tmpBuffer = new Array(16);
676
+ var tmpRandomBytes = this.randomByteGenerator.generate();
677
+
678
+ // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
679
+ tmpRandomBytes[6] = tmpRandomBytes[6] & 0x0f | 0x40;
680
+ tmpRandomBytes[8] = tmpRandomBytes[8] & 0x3f | 0x80;
681
+ return this.bytesToUUID(tmpRandomBytes);
682
+ }
683
+
684
+ // Simple random UUID generation
685
+ generateRandom() {
686
+ let tmpUUID = '';
687
+ for (let i = 0; i < this._UUIDLength; i++) {
688
+ tmpUUID += this._UUIDRandomDictionary.charAt(Math.floor(Math.random() * (this._UUIDRandomDictionary.length - 1)));
689
+ }
690
+ return tmpUUID;
691
+ }
692
+
693
+ // Adapted from node-uuid (https://github.com/kelektiv/node-uuid)
694
+ getUUID() {
695
+ if (this._UUIDModeRandom) {
696
+ return this.generateRandom();
697
+ } else {
698
+ return this.generateUUIDv4();
699
+ }
700
+ }
701
+ }
702
+
703
+ // This is for backwards compatibility
704
+ function autoConstruct(pSettings) {
705
+ return new FableUUID(pSettings);
706
+ }
707
+ module.exports = {
708
+ new: autoConstruct,
709
+ FableUUID: FableUUID
710
+ };
711
+ }, {
712
+ "./Fable-UUID-Random.js": 9
713
+ }],
714
+ 11: [function (require, module, exports) {
715
+ /**
716
+ * Precedent Meta-Templating
717
+ *
718
+ * @license MIT
719
+ *
720
+ * @author Steven Velozo <steven@velozo.com>
721
+ *
722
+ * @description Process text streams, parsing out meta-template expressions.
723
+ */
724
+ var libWordTree = require(`./WordTree.js`);
725
+ var libStringParser = require(`./StringParser.js`);
726
+ class Precedent {
727
+ /**
728
+ * Precedent Constructor
729
+ */
730
+ constructor() {
731
+ this.WordTree = new libWordTree();
732
+ this.StringParser = new libStringParser();
733
+ this.ParseTree = this.WordTree.ParseTree;
734
+ }
834
735
 
835
- return res;
736
+ /**
737
+ * Add a Pattern to the Parse Tree
738
+ * @method addPattern
739
+ * @param {Object} pTree - A node on the parse tree to push the characters into
740
+ * @param {string} pPattern - The string to add to the tree
741
+ * @param {number} pIndex - callback function
742
+ * @return {bool} True if adding the pattern was successful
743
+ */
744
+ addPattern(pPatternStart, pPatternEnd, pParser) {
745
+ return this.WordTree.addPattern(pPatternStart, pPatternEnd, pParser);
836
746
  }
837
747
 
838
748
  /**
839
- * reset
840
- * Reset the index.
841
- *
842
- * @name reset
843
- * @function
844
- * @param {Number} i The new index (default: `0`).
845
- * @return {Number} The new index.
749
+ * Parse a string with the existing parse tree
750
+ * @method parseString
751
+ * @param {string} pString - The string to parse
752
+ * @return {string} The result from the parser
846
753
  */
847
- ,
848
- reset: function reset(i) {
849
- return this.regex.lastIndex = i || 0;
850
- }
851
- };
852
- };
853
- },{}],11:[function(require,module,exports){
854
- // shim for using process in browser
855
- var process = module.exports = {};
856
-
857
- // cached from whatever global is present so that test runners that stub it
858
- // don't break things. But we need to wrap it in a try catch in case it is
859
- // wrapped in strict mode code which doesn't define any globals. It's inside a
860
- // function because try/catches deoptimize in certain engines.
861
-
862
- var cachedSetTimeout;
863
- var cachedClearTimeout;
864
-
865
- function defaultSetTimout() {
866
- throw new Error('setTimeout has not been defined');
867
- }
868
- function defaultClearTimeout () {
869
- throw new Error('clearTimeout has not been defined');
870
- }
871
- (function () {
872
- try {
873
- if (typeof setTimeout === 'function') {
754
+ parseString(pString) {
755
+ return this.StringParser.parseString(pString, this.ParseTree);
756
+ }
757
+ }
758
+ module.exports = Precedent;
759
+ }, {
760
+ "./StringParser.js": 12,
761
+ "./WordTree.js": 13
762
+ }],
763
+ 12: [function (require, module, exports) {
764
+ /**
765
+ * String Parser
766
+ *
767
+ * @license MIT
768
+ *
769
+ * @author Steven Velozo <steven@velozo.com>
770
+ *
771
+ * @description Parse a string, properly processing each matched token in the word tree.
772
+ */
773
+
774
+ class StringParser {
775
+ /**
776
+ * StringParser Constructor
777
+ */
778
+ constructor() {}
779
+
780
+ /**
781
+ * Create a fresh parsing state object to work with.
782
+ * @method newParserState
783
+ * @param {Object} pParseTree - A node on the parse tree to begin parsing from (usually root)
784
+ * @return {Object} A new parser state object for running a character parser on
785
+ * @private
786
+ */
787
+ newParserState(pParseTree) {
788
+ return {
789
+ ParseTree: pParseTree,
790
+ Output: '',
791
+ OutputBuffer: '',
792
+ Pattern: false,
793
+ PatternMatch: false,
794
+ PatternMatchOutputBuffer: ''
795
+ };
796
+ }
797
+
798
+ /**
799
+ * Assign a node of the parser tree to be the next potential match.
800
+ * If the node has a PatternEnd property, it is a valid match and supercedes the last valid match (or becomes the initial match).
801
+ * @method assignNode
802
+ * @param {Object} pNode - A node on the parse tree to assign
803
+ * @param {Object} pParserState - The state object for the current parsing task
804
+ * @private
805
+ */
806
+ assignNode(pNode, pParserState) {
807
+ pParserState.PatternMatch = pNode;
808
+
809
+ // If the pattern has a END we can assume it has a parse function...
810
+ if (pParserState.PatternMatch.hasOwnProperty('PatternEnd')) {
811
+ // ... this is the legitimate start of a pattern.
812
+ pParserState.Pattern = pParserState.PatternMatch;
813
+ }
814
+ }
815
+
816
+ /**
817
+ * Append a character to the output buffer in the parser state.
818
+ * This output buffer is used when a potential match is being explored, or a match is being explored.
819
+ * @method appendOutputBuffer
820
+ * @param {string} pCharacter - The character to append
821
+ * @param {Object} pParserState - The state object for the current parsing task
822
+ * @private
823
+ */
824
+ appendOutputBuffer(pCharacter, pParserState) {
825
+ pParserState.OutputBuffer += pCharacter;
826
+ }
827
+
828
+ /**
829
+ * Flush the output buffer to the output and clear it.
830
+ * @method flushOutputBuffer
831
+ * @param {Object} pParserState - The state object for the current parsing task
832
+ * @private
833
+ */
834
+ flushOutputBuffer(pParserState) {
835
+ pParserState.Output += pParserState.OutputBuffer;
836
+ pParserState.OutputBuffer = '';
837
+ }
838
+
839
+ /**
840
+ * Check if the pattern has ended. If it has, properly flush the buffer and start looking for new patterns.
841
+ * @method checkPatternEnd
842
+ * @param {Object} pParserState - The state object for the current parsing task
843
+ * @private
844
+ */
845
+ checkPatternEnd(pParserState) {
846
+ if (pParserState.OutputBuffer.length >= pParserState.Pattern.PatternEnd.length + pParserState.Pattern.PatternStart.length && pParserState.OutputBuffer.substr(-pParserState.Pattern.PatternEnd.length) === pParserState.Pattern.PatternEnd) {
847
+ // ... this is the end of a pattern, cut off the end tag and parse it.
848
+ // Trim the start and end tags off the output buffer now
849
+ pParserState.OutputBuffer = pParserState.Pattern.Parse(pParserState.OutputBuffer.substr(pParserState.Pattern.PatternStart.length, pParserState.OutputBuffer.length - (pParserState.Pattern.PatternStart.length + pParserState.Pattern.PatternEnd.length)));
850
+ // Flush the output buffer.
851
+ this.flushOutputBuffer(pParserState);
852
+ // End pattern mode
853
+ pParserState.Pattern = false;
854
+ pParserState.PatternMatch = false;
855
+ }
856
+ }
857
+
858
+ /**
859
+ * Parse a character in the buffer.
860
+ * @method parseCharacter
861
+ * @param {string} pCharacter - The character to append
862
+ * @param {Object} pParserState - The state object for the current parsing task
863
+ * @private
864
+ */
865
+ parseCharacter(pCharacter, pParserState) {
866
+ // (1) If we aren't in a pattern match, and we aren't potentially matching, and this may be the start of a new pattern....
867
+ if (!pParserState.PatternMatch && pParserState.ParseTree.hasOwnProperty(pCharacter)) {
868
+ // ... assign the node as the matched node.
869
+ this.assignNode(pParserState.ParseTree[pCharacter], pParserState);
870
+ this.appendOutputBuffer(pCharacter, pParserState);
871
+ }
872
+ // (2) If we are in a pattern match (actively seeing if this is part of a new pattern token)
873
+ else if (pParserState.PatternMatch) {
874
+ // If the pattern has a subpattern with this key
875
+ if (pParserState.PatternMatch.hasOwnProperty(pCharacter)) {
876
+ // Continue matching patterns.
877
+ this.assignNode(pParserState.PatternMatch[pCharacter], pParserState);
878
+ }
879
+ this.appendOutputBuffer(pCharacter, pParserState);
880
+ if (pParserState.Pattern) {
881
+ // ... Check if this is the end of the pattern (if we are matching a valid pattern)...
882
+ this.checkPatternEnd(pParserState);
883
+ }
884
+ }
885
+ // (3) If we aren't in a pattern match or pattern, and this isn't the start of a new pattern (RAW mode)....
886
+ else {
887
+ pParserState.Output += pCharacter;
888
+ }
889
+ }
890
+
891
+ /**
892
+ * Parse a string for matches, and process any template segments that occur.
893
+ * @method parseString
894
+ * @param {string} pString - The string to parse.
895
+ * @param {Object} pParseTree - The parse tree to begin parsing from (usually root)
896
+ */
897
+ parseString(pString, pParseTree) {
898
+ let tmpParserState = this.newParserState(pParseTree);
899
+ for (var i = 0; i < pString.length; i++) {
900
+ // TODO: This is not fast.
901
+ this.parseCharacter(pString[i], tmpParserState);
902
+ }
903
+ this.flushOutputBuffer(tmpParserState);
904
+ return tmpParserState.Output;
905
+ }
906
+ }
907
+ module.exports = StringParser;
908
+ }, {}],
909
+ 13: [function (require, module, exports) {
910
+ /**
911
+ * Word Tree
912
+ *
913
+ * @license MIT
914
+ *
915
+ * @author Steven Velozo <steven@velozo.com>
916
+ *
917
+ * @description Create a tree (directed graph) of Javascript objects, one character per object.
918
+ */
919
+
920
+ class WordTree {
921
+ /**
922
+ * WordTree Constructor
923
+ */
924
+ constructor() {
925
+ this.ParseTree = {};
926
+ }
927
+
928
+ /**
929
+ * Add a child character to a Parse Tree node
930
+ * @method addChild
931
+ * @param {Object} pTree - A parse tree to push the characters into
932
+ * @param {string} pPattern - The string to add to the tree
933
+ * @param {number} pIndex - The index of the character in the pattern
934
+ * @returns {Object} The resulting leaf node that was added (or found)
935
+ * @private
936
+ */
937
+ addChild(pTree, pPattern, pIndex) {
938
+ if (!pTree.hasOwnProperty(pPattern[pIndex])) pTree[pPattern[pIndex]] = {};
939
+ return pTree[pPattern[pIndex]];
940
+ }
941
+
942
+ /** Add a Pattern to the Parse Tree
943
+ * @method addPattern
944
+ * @param {Object} pPatternStart - The starting string for the pattern (e.g. "${")
945
+ * @param {string} pPatternEnd - The ending string for the pattern (e.g. "}")
946
+ * @param {number} pParser - The function to parse if this is the matched pattern, once the Pattern End is met. If this is a string, a simple replacement occurs.
947
+ * @return {bool} True if adding the pattern was successful
948
+ */
949
+ addPattern(pPatternStart, pPatternEnd, pParser) {
950
+ if (pPatternStart.length < 1) return false;
951
+ if (typeof pPatternEnd === 'string' && pPatternEnd.length < 1) return false;
952
+ let tmpLeaf = this.ParseTree;
953
+
954
+ // Add the tree of leaves iteratively
955
+ for (var i = 0; i < pPatternStart.length; i++) tmpLeaf = this.addChild(tmpLeaf, pPatternStart, i);
956
+ tmpLeaf.PatternStart = pPatternStart;
957
+ tmpLeaf.PatternEnd = typeof pPatternEnd === 'string' && pPatternEnd.length > 0 ? pPatternEnd : pPatternStart;
958
+ tmpLeaf.Parse = typeof pParser === 'function' ? pParser : typeof pParser === 'string' ? () => {
959
+ return pParser;
960
+ } : pData => {
961
+ return pData;
962
+ };
963
+ return true;
964
+ }
965
+ }
966
+ module.exports = WordTree;
967
+ }, {}],
968
+ 14: [function (require, module, exports) {
969
+ // shim for using process in browser
970
+ var process = module.exports = {};
971
+
972
+ // cached from whatever global is present so that test runners that stub it
973
+ // don't break things. But we need to wrap it in a try catch in case it is
974
+ // wrapped in strict mode code which doesn't define any globals. It's inside a
975
+ // function because try/catches deoptimize in certain engines.
976
+
977
+ var cachedSetTimeout;
978
+ var cachedClearTimeout;
979
+ function defaultSetTimout() {
980
+ throw new Error('setTimeout has not been defined');
981
+ }
982
+ function defaultClearTimeout() {
983
+ throw new Error('clearTimeout has not been defined');
984
+ }
985
+ (function () {
986
+ try {
987
+ if (typeof setTimeout === 'function') {
874
988
  cachedSetTimeout = setTimeout;
875
- } else {
989
+ } else {
876
990
  cachedSetTimeout = defaultSetTimout;
991
+ }
992
+ } catch (e) {
993
+ cachedSetTimeout = defaultSetTimout;
877
994
  }
878
- } catch (e) {
879
- cachedSetTimeout = defaultSetTimout;
880
- }
881
- try {
882
- if (typeof clearTimeout === 'function') {
995
+ try {
996
+ if (typeof clearTimeout === 'function') {
883
997
  cachedClearTimeout = clearTimeout;
884
- } else {
998
+ } else {
885
999
  cachedClearTimeout = defaultClearTimeout;
1000
+ }
1001
+ } catch (e) {
1002
+ cachedClearTimeout = defaultClearTimeout;
1003
+ }
1004
+ })();
1005
+ function runTimeout(fun) {
1006
+ if (cachedSetTimeout === setTimeout) {
1007
+ //normal enviroments in sane situations
1008
+ return setTimeout(fun, 0);
1009
+ }
1010
+ // if setTimeout wasn't available but was latter defined
1011
+ if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
1012
+ cachedSetTimeout = setTimeout;
1013
+ return setTimeout(fun, 0);
886
1014
  }
887
- } catch (e) {
888
- cachedClearTimeout = defaultClearTimeout;
889
- }
890
- } ())
891
- function runTimeout(fun) {
892
- if (cachedSetTimeout === setTimeout) {
893
- //normal enviroments in sane situations
894
- return setTimeout(fun, 0);
895
- }
896
- // if setTimeout wasn't available but was latter defined
897
- if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
898
- cachedSetTimeout = setTimeout;
899
- return setTimeout(fun, 0);
900
- }
901
- try {
902
- // when when somebody has screwed with setTimeout but no I.E. maddness
903
- return cachedSetTimeout(fun, 0);
904
- } catch(e){
905
1015
  try {
1016
+ // when when somebody has screwed with setTimeout but no I.E. maddness
1017
+ return cachedSetTimeout(fun, 0);
1018
+ } catch (e) {
1019
+ try {
906
1020
  // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
907
1021
  return cachedSetTimeout.call(null, fun, 0);
908
- } catch(e){
1022
+ } catch (e) {
909
1023
  // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
910
1024
  return cachedSetTimeout.call(this, fun, 0);
1025
+ }
1026
+ }
1027
+ }
1028
+ function runClearTimeout(marker) {
1029
+ if (cachedClearTimeout === clearTimeout) {
1030
+ //normal enviroments in sane situations
1031
+ return clearTimeout(marker);
1032
+ }
1033
+ // if clearTimeout wasn't available but was latter defined
1034
+ if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
1035
+ cachedClearTimeout = clearTimeout;
1036
+ return clearTimeout(marker);
911
1037
  }
912
- }
913
-
914
-
915
- }
916
- function runClearTimeout(marker) {
917
- if (cachedClearTimeout === clearTimeout) {
918
- //normal enviroments in sane situations
919
- return clearTimeout(marker);
920
- }
921
- // if clearTimeout wasn't available but was latter defined
922
- if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
923
- cachedClearTimeout = clearTimeout;
924
- return clearTimeout(marker);
925
- }
926
- try {
927
- // when when somebody has screwed with setTimeout but no I.E. maddness
928
- return cachedClearTimeout(marker);
929
- } catch (e){
930
1038
  try {
1039
+ // when when somebody has screwed with setTimeout but no I.E. maddness
1040
+ return cachedClearTimeout(marker);
1041
+ } catch (e) {
1042
+ try {
931
1043
  // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
932
1044
  return cachedClearTimeout.call(null, marker);
933
- } catch (e){
1045
+ } catch (e) {
934
1046
  // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
935
1047
  // Some versions of I.E. have different rules for clearTimeout vs setTimeout
936
1048
  return cachedClearTimeout.call(this, marker);
1049
+ }
937
1050
  }
938
- }
939
-
940
-
941
-
942
- }
943
- var queue = [];
944
- var draining = false;
945
- var currentQueue;
946
- var queueIndex = -1;
947
-
948
- function cleanUpNextTick() {
949
- if (!draining || !currentQueue) {
950
- return;
951
- }
952
- draining = false;
953
- if (currentQueue.length) {
954
- queue = currentQueue.concat(queue);
955
- } else {
956
- queueIndex = -1;
957
- }
958
- if (queue.length) {
959
- drainQueue();
960
- }
961
- }
962
-
963
- function drainQueue() {
964
- if (draining) {
965
- return;
966
- }
967
- var timeout = runTimeout(cleanUpNextTick);
968
- draining = true;
969
-
970
- var len = queue.length;
971
- while(len) {
972
- currentQueue = queue;
973
- queue = [];
974
- while (++queueIndex < len) {
1051
+ }
1052
+ var queue = [];
1053
+ var draining = false;
1054
+ var currentQueue;
1055
+ var queueIndex = -1;
1056
+ function cleanUpNextTick() {
1057
+ if (!draining || !currentQueue) {
1058
+ return;
1059
+ }
1060
+ draining = false;
1061
+ if (currentQueue.length) {
1062
+ queue = currentQueue.concat(queue);
1063
+ } else {
1064
+ queueIndex = -1;
1065
+ }
1066
+ if (queue.length) {
1067
+ drainQueue();
1068
+ }
1069
+ }
1070
+ function drainQueue() {
1071
+ if (draining) {
1072
+ return;
1073
+ }
1074
+ var timeout = runTimeout(cleanUpNextTick);
1075
+ draining = true;
1076
+ var len = queue.length;
1077
+ while (len) {
1078
+ currentQueue = queue;
1079
+ queue = [];
1080
+ while (++queueIndex < len) {
975
1081
  if (currentQueue) {
976
- currentQueue[queueIndex].run();
1082
+ currentQueue[queueIndex].run();
977
1083
  }
1084
+ }
1085
+ queueIndex = -1;
1086
+ len = queue.length;
978
1087
  }
979
- queueIndex = -1;
980
- len = queue.length;
981
- }
982
- currentQueue = null;
983
- draining = false;
984
- runClearTimeout(timeout);
985
- }
986
-
987
- process.nextTick = function (fun) {
988
- var args = new Array(arguments.length - 1);
989
- if (arguments.length > 1) {
990
- for (var i = 1; i < arguments.length; i++) {
1088
+ currentQueue = null;
1089
+ draining = false;
1090
+ runClearTimeout(timeout);
1091
+ }
1092
+ process.nextTick = function (fun) {
1093
+ var args = new Array(arguments.length - 1);
1094
+ if (arguments.length > 1) {
1095
+ for (var i = 1; i < arguments.length; i++) {
991
1096
  args[i - 1] = arguments[i];
1097
+ }
992
1098
  }
993
- }
994
- queue.push(new Item(fun, args));
995
- if (queue.length === 1 && !draining) {
996
- runTimeout(drainQueue);
997
- }
998
- };
999
-
1000
- // v8 likes predictible objects
1001
- function Item(fun, array) {
1002
- this.fun = fun;
1003
- this.array = array;
1004
- }
1005
- Item.prototype.run = function () {
1006
- this.fun.apply(null, this.array);
1007
- };
1008
- process.title = 'browser';
1009
- process.browser = true;
1010
- process.env = {};
1011
- process.argv = [];
1012
- process.version = ''; // empty string to avoid regexp issues
1013
- process.versions = {};
1014
-
1015
- function noop() {}
1016
-
1017
- process.on = noop;
1018
- process.addListener = noop;
1019
- process.once = noop;
1020
- process.off = noop;
1021
- process.removeListener = noop;
1022
- process.removeAllListeners = noop;
1023
- process.emit = noop;
1024
- process.prependListener = noop;
1025
- process.prependOnceListener = noop;
1026
-
1027
- process.listeners = function (name) { return [] }
1028
-
1029
- process.binding = function (name) {
1030
- throw new Error('process.binding is not supported');
1031
- };
1032
-
1033
- process.cwd = function () { return '/' };
1034
- process.chdir = function (dir) {
1035
- throw new Error('process.chdir is not supported');
1036
- };
1037
- process.umask = function() { return 0; };
1038
-
1039
- },{}],12:[function(require,module,exports){
1040
- // ##### Part of the **[retold](https://stevenvelozo.github.io/retold/)** system
1041
- /**
1042
- * @license MIT
1043
- * @author <steven@velozo.com>
1044
- */
1045
- const libFableSettings = require('fable-settings').FableSettings;
1046
- const libFableUUID = require('fable-uuid').FableUUID;
1047
- const libFableLog = require('fable-log').FableLog;
1048
-
1049
-
1050
- /**
1051
- * Fable Application Services Support Library
1052
- *
1053
- * @class Fable
1054
- */
1055
- class Fable
1056
- {
1057
- constructor(pSettings)
1058
- {
1059
- let tmpSettings = new libFableSettings(pSettings);
1060
-
1061
- this.settingsManager = tmpSettings;
1062
-
1063
- // Instantiate the UUID generator
1064
- this.libUUID = new libFableUUID(this.settingsManager.settings);
1065
-
1066
- this.log = new libFableLog(this.settingsManager.settings);
1067
- this.log.initialize();
1068
- }
1069
-
1070
- get settings()
1071
- {
1072
- return this.settingsManager.settings;
1073
- }
1074
-
1075
- get fable()
1076
- {
1077
- return this;
1078
- }
1079
-
1080
- getUUID()
1081
- {
1082
- return this.libUUID.getUUID();
1083
- }
1084
- }
1085
-
1086
- // This is for backwards compatibility
1087
- function autoConstruct(pSettings)
1088
- {
1089
- return new Fable(pSettings);
1090
- }
1091
-
1092
- module.exports = {new:autoConstruct, Fable:Fable};
1093
- },{"fable-log":5,"fable-settings":7,"fable-uuid":9}]},{},[12])(12)
1094
- });
1095
-
1096
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJub2RlX21vZHVsZXMvZmFibGUtbG9nL3NvdXJjZS9GYWJsZS1Mb2ctQmFzZUxvZ2dlci5qcyIsIm5vZGVfbW9kdWxlcy9mYWJsZS1sb2cvc291cmNlL0ZhYmxlLUxvZy1EZWZhdWx0UHJvdmlkZXJzLUJyb3dzZXIuanMiLCJub2RlX21vZHVsZXMvZmFibGUtbG9nL3NvdXJjZS9GYWJsZS1Mb2ctRGVmYXVsdFN0cmVhbXMuanNvbiIsIm5vZGVfbW9kdWxlcy9mYWJsZS1sb2cvc291cmNlL0ZhYmxlLUxvZy1Mb2dnZXItQ29uc29sZS5qcyIsIm5vZGVfbW9kdWxlcy9mYWJsZS1sb2cvc291cmNlL0ZhYmxlLUxvZy5qcyIsIm5vZGVfbW9kdWxlcy9mYWJsZS1zZXR0aW5ncy9zb3VyY2UvRmFibGUtU2V0dGluZ3MtRGVmYXVsdC5qc29uIiwibm9kZV9tb2R1bGVzL2ZhYmxlLXNldHRpbmdzL3NvdXJjZS9GYWJsZS1TZXR0aW5ncy5qcyIsIm5vZGVfbW9kdWxlcy9mYWJsZS11dWlkL3NvdXJjZS9GYWJsZS1VVUlELVJhbmRvbS1Ccm93c2VyLmpzIiwibm9kZV9tb2R1bGVzL2ZhYmxlLXV1aWQvc291cmNlL0ZhYmxlLVVVSUQuanMiLCJub2RlX21vZHVsZXMvbWF0Y2gtYWxsL2xpYi9pbmRleC5qcyIsIm5vZGVfbW9kdWxlcy9wcm9jZXNzL2Jyb3dzZXIuanMiLCJzb3VyY2UvRmFibGUuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDTkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOU9BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQ2JBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FDMUxBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbkVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4R0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4TEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uKCl7ZnVuY3Rpb24gcihlLG4sdCl7ZnVuY3Rpb24gbyhpLGYpe2lmKCFuW2ldKXtpZighZVtpXSl7dmFyIGM9XCJmdW5jdGlvblwiPT10eXBlb2YgcmVxdWlyZSYmcmVxdWlyZTtpZighZiYmYylyZXR1cm4gYyhpLCEwKTtpZih1KXJldHVybiB1KGksITApO3ZhciBhPW5ldyBFcnJvcihcIkNhbm5vdCBmaW5kIG1vZHVsZSAnXCIraStcIidcIik7dGhyb3cgYS5jb2RlPVwiTU9EVUxFX05PVF9GT1VORFwiLGF9dmFyIHA9bltpXT17ZXhwb3J0czp7fX07ZVtpXVswXS5jYWxsKHAuZXhwb3J0cyxmdW5jdGlvbihyKXt2YXIgbj1lW2ldWzFdW3JdO3JldHVybiBvKG58fHIpfSxwLHAuZXhwb3J0cyxyLGUsbix0KX1yZXR1cm4gbltpXS5leHBvcnRzfWZvcih2YXIgdT1cImZ1bmN0aW9uXCI9PXR5cGVvZiByZXF1aXJlJiZyZXF1aXJlLGk9MDtpPHQubGVuZ3RoO2krKylvKHRbaV0pO3JldHVybiBvfXJldHVybiByfSkoKSIsIi8qKlxuKiBCYXNlIExvZ2dlciBDbGFzc1xuKlxuKiBAbGljZW5zZSBNSVRcbipcbiogQGF1dGhvciBTdGV2ZW4gVmVsb3pvIDxzdGV2ZW5AdmVsb3pvLmNvbT5cbiovXG5jb25zdCBsaWJGYWJsZVVVSUQgPSBuZXcgKHJlcXVpcmUoJ2ZhYmxlLXV1aWQnKS5GYWJsZVVVSUQpKCk7XG5cbmNsYXNzIEJhc2VMb2dnZXJcbntcblx0Y29uc3RydWN0b3IocExvZ1N0cmVhbVNldHRpbmdzLCBwRmFibGVMb2cpXG5cdHtcblx0XHQvLyBUaGlzIHNob3VsZCBub3QgcG9zc2libHkgYmUgYWJsZSB0byBiZSBpbnN0YW50aWF0ZWQgd2l0aG91dCBhIHNldHRpbmdzIG9iamVjdFxuXHRcdHRoaXMuX1NldHRpbmdzID0gcExvZ1N0cmVhbVNldHRpbmdzO1xuXHRcdFxuXHRcdC8vIFRoZSBiYXNlIGxvZ2dlciBkb2VzIG5vdGhpbmcgYnV0IGFzc29jaWF0ZSBhIFVVSUQgd2l0aCBpdHNlbGZcblx0XHR0aGlzLmxvZ2dlclVVSUQgPSBsaWJGYWJsZVVVSUQuZ2V0VVVJRCgpO1xuXHR9XG5cblx0aW5pdGlhbGl6ZSgpXG5cdHtcblx0XHQvLyBObyBvcGVyYXRpb24uXG5cdH1cblxuXHR0cmFjZShwTG9nVGV4dCwgcExvZ09iamVjdClcblx0e1xuXHRcdHRoaXMud3JpdGUoXCJ0cmFjZVwiLCBwTG9nVGV4dCwgcExvZ09iamVjdCk7XG5cdH1cblxuXHRkZWJ1ZyhwTG9nVGV4dCwgcExvZ09iamVjdClcblx0e1xuXHRcdHRoaXMud3JpdGUoXCJkZWJ1Z1wiLCBwTG9nVGV4dCwgcExvZ09iamVjdCk7XG5cdH1cblxuXHRpbmZvKHBMb2dUZXh0LCBwTG9nT2JqZWN0KVxuXHR7XG5cdFx0dGhpcy53cml0ZShcImluZm9cIiwgcExvZ1RleHQsIHBMb2dPYmplY3QpO1xuXHR9XG5cblx0d2FybihwTG9nVGV4dCwgcExvZ09iamVjdClcblx0e1xuXHRcdHRoaXMud3JpdGUoXCJ3YXJuXCIsIHBMb2dUZXh0LCBwTG9nT2JqZWN0KTtcblx0fVxuXG5cdGVycm9yKHBMb2dUZXh0LCBwTG9nT2JqZWN0KVxuXHR7XG5cdFx0dGhpcy53cml0ZShcImVycm9yXCIsIHBMb2dUZXh0LCBwTG9nT2JqZWN0KTtcblx0fVxuXG5cdGZhdGFsKHBMb2dUZXh0LCBwTG9nT2JqZWN0KVxuXHR7XG5cdFx0dGhpcy53cml0ZShcImZhdGFsXCIsIHBMb2dUZXh0LCBwTG9nT2JqZWN0KTtcblx0fVxuXG5cdHdyaXRlKHBMb2dMZXZlbCwgcExvZ1RleHQsIHBMb2dPYmplY3QpXG5cdHtcblx0XHQvLyBUaGUgYmFzZSBsb2dnZXIgZG9lcyBub3RoaW5nLlxuXHRcdHJldHVybiB0cnVlO1xuXHR9XG59XG5cbm1vZHVsZS5leHBvcnRzID0gQmFzZUxvZ2dlcjtcbiIsIi8qKlxuKiBEZWZhdWx0IExvZ2dlciBQcm92aWRlciBGdW5jdGlvbiAtLS0gQnJvd3NlclxuKlxuKiBAbGljZW5zZSBNSVRcbipcbiogQGF1dGhvciBTdGV2ZW4gVmVsb3pvIDxzdGV2ZW5AdmVsb3pvLmNvbT5cbiovXG5cbi8vIFJldHVybiB0aGUgcHJvdmlkZXJzIHRoYXQgYXJlIGF2YWlsYWJsZSB3aXRob3V0IGV4dGVuc2lvbnMgbG9hZGVkXG5nZXREZWZhdWx0UHJvdmlkZXJzID0gKCkgPT5cbntcblx0bGV0IHRtcERlZmF1bHRQcm92aWRlcnMgPSB7fTtcblxuXHR0bXBEZWZhdWx0UHJvdmlkZXJzLmNvbnNvbGUgPSByZXF1aXJlKCcuL0ZhYmxlLUxvZy1Mb2dnZXItQ29uc29sZS5qcycpO1xuXHR0bXBEZWZhdWx0UHJvdmlkZXJzLmRlZmF1bHQgPSB0bXBEZWZhdWx0UHJvdmlkZXJzLmNvbnNvbGU7XG5cblx0cmV0dXJuIHRtcERlZmF1bHRQcm92aWRlcnM7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gZ2V0RGVmYXVsdFByb3ZpZGVycygpOyIsIm1vZHVsZS5leHBvcnRzPVtcbiAgICB7XG4gICAgICAgIFwibG9nZ2VydHlwZVwiOiBcImNvbnNvbGVcIixcbiAgICAgICAgXCJzdHJlYW10eXBlXCI6IFwiY29uc29sZVwiLFxuICAgICAgICBcImxldmVsXCI6IFwidHJhY2VcIlxuICAgIH1cbl0iLCJsZXQgbGliQmFzZUxvZ2dlciA9IHJlcXVpcmUoJy4vRmFibGUtTG9nLUJhc2VMb2dnZXIuanMnKTtcblxuY2xhc3MgQ29uc29sZUxvZ2dlciBleHRlbmRzIGxpYkJhc2VMb2dnZXJcbntcblx0Y29uc3RydWN0b3IocExvZ1N0cmVhbVNldHRpbmdzLCBwRmFibGVMb2cpXG5cdHtcblx0XHRzdXBlcihwTG9nU3RyZWFtU2V0dGluZ3MpXG5cblx0XHR0aGlzLl9TaG93VGltZVN0YW1wcyA9IHBMb2dTdHJlYW1TZXR0aW5ncy5oYXNPd25Qcm9wZXJ0eSgnU2hvd1RpbWVTdGFtcHMnKSA/IChwTG9nU3RyZWFtU2V0dGluZ3MuU2hvd1RpbWVTdGFtcHMgPT0gdHJ1ZSkgOiBmYWxzZTtcblx0XHR0aGlzLl9Gb3JtYXR0ZWRUaW1lU3RhbXBzID0gcExvZ1N0cmVhbVNldHRpbmdzLmhhc093blByb3BlcnR5KCdGb3JtYXR0ZWRUaW1lU3RhbXBzJykgPyAocExvZ1N0cmVhbVNldHRpbmdzLkZvcm1hdHRlZFRpbWVTdGFtcHMgPT0gdHJ1ZSkgOiBmYWxzZTtcblxuXHRcdHRoaXMuX0NvbnRleHRNZXNzYWdlID0gcExvZ1N0cmVhbVNldHRpbmdzLmhhc093blByb3BlcnR5KCdDb250ZXh0JykgPyBgICgke3BMb2dTdHJlYW1TZXR0aW5ncy5Db250ZXh0fSlgIDogXG5cdFx0XHRcdFx0XHRcdFx0cEZhYmxlTG9nLl9TZXR0aW5ncy5oYXNPd25Qcm9wZXJ0eSgnUHJvZHVjdCcpID8gYCAoJHtwRmFibGVMb2cuX1NldHRpbmdzLlByb2R1Y3R9KWAgOlxuXHRcdFx0XHRcdFx0XHRcdCcnO1xuXHR9XG5cblx0d3JpdGUocExldmVsLCBwTG9nVGV4dCwgcE9iamVjdClcblx0e1xuXHRcdGlmICh0aGlzLl9TaG93VGltZVN0YW1wcyAmJiB0aGlzLl9Gb3JtYXR0ZWRUaW1lU3RhbXBzKVxuXHRcdHtcblx0XHRcdGxldCB0bXBEYXRlID0gKG5ldyBEYXRlKCkpLnRvSVNPU3RyaW5nKCk7XG5cdFx0XHRjb25zb2xlLmxvZyhgJHt0bXBEYXRlfSBbJHtwTGV2ZWx9XSR7dGhpcy5fQ29udGV4dE1lc3NhZ2V9ICR7cExvZ1RleHR9YCk7XG5cdFx0fVxuXHRcdGVsc2UgaWYgKHRoaXMuX1Nob3dUaW1lU3RhbXBzKVxuXHRcdHtcblx0XHRcdGxldCB0bXBEYXRlID0gK25ldyBEYXRlKCk7XG5cdFx0XHRjb25zb2xlLmxvZyhgJHt0bXBEYXRlfSBbJHtwTGV2ZWx9XSR7dGhpcy5fQ29udGV4dE1lc3NhZ2V9ICR7cExvZ1RleHR9YCk7XG5cdFx0fVxuXHRcdGVsc2Vcblx0XHR7XG5cdFx0XHRjb25zb2xlLmxvZyhgWyR7cExldmVsfV0ke3RoaXMuX0NvbnRleHRNZXNzYWdlfSAke3BMb2dUZXh0fWApO1xuXHRcdH1cblxuXHRcdC8vIFdyaXRlIG91dCB0aGUgb2JqZWN0IG9uIGEgc2VwYXJhdGUgbGluZSBpZiBpdCBpcyBwYXNzZWQgaW5cblx0XHRpZiAodHlwZW9mKHBPYmplY3QpICE9PSAndW5kZWZpbmVkJylcblx0XHR7XG5cdFx0XHRjb25zb2xlLmxvZyhKU09OLnN0cmluZ2lmeShwT2JqZWN0LCBudWxsLCA0KSk7XG5cdFx0fVxuXHR9XG5cbn1cblxubW9kdWxlLmV4cG9ydHMgPSBDb25zb2xlTG9nZ2VyOyIsIi8qKlxuKiBGYWJsZSBMb2dnaW5nIEFkZC1vblxuKlxuKiBAbGljZW5zZSBNSVRcbipcbiogQGF1dGhvciBTdGV2ZW4gVmVsb3pvIDxzdGV2ZW5AdmVsb3pvLmNvbT5cbiogQG1vZHVsZSBGYWJsZSBMb2dnZXJcbiovXG5cbi8qKlxuKiBGYWJsZSBTb2x1dGlvbiBMb2cgV3JhcHBlciBNYWluIENsYXNzXG4qXG4qIEBjbGFzcyBGYWJsZUxvZ1xuKiBAY29uc3RydWN0b3JcbiovXG5jbGFzcyBGYWJsZUxvZ1xue1xuXHRjb25zdHJ1Y3RvcihwRmFibGVTZXR0aW5ncywgcEZhYmxlKVxuXHR7XG5cdFx0bGV0IHRtcFNldHRpbmdzID0gKHR5cGVvZihwRmFibGVTZXR0aW5ncykgPT09ICdvYmplY3QnKSA/IHBGYWJsZVNldHRpbmdzIDoge31cblx0XHR0aGlzLl9TZXR0aW5ncyA9IHRtcFNldHRpbmdzO1xuXG5cdFx0dGhpcy5fUHJvdmlkZXJzID0gcmVxdWlyZSgnLi9GYWJsZS1Mb2ctRGVmYXVsdFByb3ZpZGVycy5qcycpO1xuXG5cdFx0dGhpcy5fU3RyZWFtRGVmaW5pdGlvbnMgPSAodG1wU2V0dGluZ3MuaGFzT3duUHJvcGVydHkoJ0xvZ1N0cmVhbXMnKSkgPyB0bXBTZXR0aW5ncy5Mb2dTdHJlYW1zIDogcmVxdWlyZSgnLi9GYWJsZS1Mb2ctRGVmYXVsdFN0cmVhbXMuanNvbicpO1xuXG5cdFx0dGhpcy5sb2dTdHJlYW1zID0gW107XG5cblx0XHQvLyBUaGlzIG9iamVjdCBnZXRzIGRlY29yYXRlZCBmb3Igb25lLXRpbWUgaW5zdGFudGlhdGVkIHByb3ZpZGVycyB0aGF0XG5cdFx0Ly8gIGhhdmUgbXVsdGlwbGUgb3V0cHV0cywgc3VjaCBhcyBidW55YW4uXG5cdFx0dGhpcy5sb2dQcm92aWRlcnMgPSB7fTtcblxuXHRcdC8vIEEgaGFzaCBsaXN0IG9mIHRoZSBHVUlEcyBmb3IgZWFjaCBsb2cgc3RyZWFtLCBzbyB0aGV5IGNhbid0IGJlIGFkZGVkIHRvIHRoZSBzZXQgbW9yZSB0aGFuIG9uZSB0aW1lXG5cdFx0dGhpcy5hY3RpdmVMb2dTdHJlYW1zID0ge307XG5cblx0XHR0aGlzLmxvZ1N0cmVhbXNUcmFjZSA9IFtdO1xuXHRcdHRoaXMubG9nU3RyZWFtc0RlYnVnID0gW107XG5cdFx0dGhpcy5sb2dTdHJlYW1zSW5mbyA9IFtdO1xuXHRcdHRoaXMubG9nU3RyZWFtc1dhcm4gPSBbXTtcblx0XHR0aGlzLmxvZ1N0cmVhbXNFcnJvciA9IFtdO1xuXHRcdHRoaXMubG9nU3RyZWFtc0ZhdGFsID0gW107XG5cblx0XHR0aGlzLmRhdHVtRGVjb3JhdG9yID0gKHBEYXR1bSkgPT4gcERhdHVtO1xuXG5cdFx0dGhpcy51dWlkID0gKHR5cGVvZih0bXBTZXR0aW5ncy5Qcm9kdWN0KSA9PT0gJ3N0cmluZycpID8gdG1wU2V0dGluZ3MuUHJvZHVjdCA6ICdEZWZhdWx0Jztcblx0fVxuXG5cdGFkZExvZ2dlcihwTG9nZ2VyLCBwTGV2ZWwpXG5cdHtcblx0XHQvLyBCYWlsIG91dCBpZiB3ZSd2ZSBhbHJlYWR5IGNyZWF0ZWQgb25lLlxuXHRcdGlmICh0aGlzLmFjdGl2ZUxvZ1N0cmVhbXMuaGFzT3duUHJvcGVydHkocExvZ2dlci5sb2dnZXJVVUlEKSlcblx0XHR7XG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0fVxuXG5cdFx0Ly8gQWRkIGl0IHRvIHRoZSBzdHJlYW1zIGFuZCB0byB0aGUgbXV0ZXhcblx0XHR0aGlzLmxvZ1N0cmVhbXMucHVzaChwTG9nZ2VyKTtcblx0XHR0aGlzLmFjdGl2ZUxvZ1N0cmVhbXNbcExvZ2dlci5sb2dnZXJVVUlEXSA9IHRydWU7XG5cblx0XHQvLyBNYWtlIHN1cmUgYSBrb3NoZXIgbGV2ZWwgd2FzIHBhc3NlZCBpblxuXHRcdHN3aXRjaCAocExldmVsKVxuXHRcdHtcblx0XHRcdGNhc2UgJ3RyYWNlJzpcblx0XHRcdFx0dGhpcy5sb2dTdHJlYW1zVHJhY2UucHVzaChwTG9nZ2VyKTtcblx0XHRcdGNhc2UgJ2RlYnVnJzpcblx0XHRcdFx0dGhpcy5sb2dTdHJlYW1zRGVidWcucHVzaChwTG9nZ2VyKTtcblx0XHRcdGNhc2UgJ2luZm8nOlxuXHRcdFx0XHR0aGlzLmxvZ1N0cmVhbXNJbmZvLnB1c2gocExvZ2dlcik7XG5cdFx0XHRjYXNlICd3YXJuJzpcblx0XHRcdFx0dGhpcy5sb2dTdHJlYW1zV2Fybi5wdXNoKHBMb2dnZXIpO1xuXHRcdFx0Y2FzZSAnZXJyb3InOlxuXHRcdFx0XHR0aGlzLmxvZ1N0cmVhbXNFcnJvci5wdXNoKHBMb2dnZXIpO1xuXHRcdFx0Y2FzZSAnZmF0YWwnOlxuXHRcdFx0XHR0aGlzLmxvZ1N0cmVhbXNGYXRhbC5wdXNoKHBMb2dnZXIpO1xuXHRcdFx0XHRicmVhaztcblx0XHR9XG5cblx0XHRyZXR1cm4gdHJ1ZTtcblx0fVxuXG5cdHNldERhdHVtRGVjb3JhdG9yKGZEYXR1bURlY29yYXRvcilcblx0e1xuXHRcdGlmICh0eXBlb2YoZkRhdHVtRGVjb3JhdG9yKSA9PT0gJ2Z1bmN0aW9uJylcblx0XHR7XG5cdFx0XHR0aGlzLmRhdHVtRGVjb3JhdG9yID0gZkRhdHVtRGVjb3JhdG9yO1xuXHRcdH1cblx0XHRlbHNlXG5cdFx0e1xuXHRcdFx0dGhpcy5kYXR1bURlY29yYXRvciA9IChwRGF0dW0pID0+IHBEYXR1bTtcblx0XHR9XG5cdH1cblxuXHR0cmFjZShwTWVzc2FnZSwgcERhdHVtKVxuXHR7XG5cdFx0Y29uc3QgdG1wRGVjb3JhdGVkRGF0dW0gPSB0aGlzLmRhdHVtRGVjb3JhdG9yKHBEYXR1bSk7XG5cdFx0Zm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLmxvZ1N0cmVhbXNUcmFjZS5sZW5ndGg7IGkrKylcblx0XHR7XG5cdFx0XHR0aGlzLmxvZ1N0cmVhbXNUcmFjZVtpXS50cmFjZShwTWVzc2FnZSwgdG1wRGVjb3JhdGVkRGF0dW0pO1xuXHRcdH1cblx0fVxuXG5cdGRlYnVnKHBNZXNzYWdlLCBwRGF0dW0pXG5cdHtcblx0XHRjb25zdCB0bXBEZWNvcmF0ZWREYXR1bSA9IHRoaXMuZGF0dW1EZWNvcmF0b3IocERhdHVtKTtcblx0XHRmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMubG9nU3RyZWFtc0RlYnVnLmxlbmd0aDsgaSsrKVxuXHRcdHtcblx0XHRcdHRoaXMubG9nU3RyZWFtc0RlYnVnW2ldLmRlYnVnKHBNZXNzYWdlLCB0bXBEZWNvcmF0ZWREYXR1bSk7XG5cdFx0fVxuXHR9XG5cblx0aW5mbyhwTWVzc2FnZSwgcERhdHVtKVxuXHR7XG5cdFx0Y29uc3QgdG1wRGVjb3JhdGVkRGF0dW0gPSB0aGlzLmRhdHVtRGVjb3JhdG9yKHBEYXR1bSk7XG5cdFx0Zm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLmxvZ1N0cmVhbXNJbmZvLmxlbmd0aDsgaSsrKVxuXHRcdHtcblx0XHRcdHRoaXMubG9nU3RyZWFtc0luZm9baV0uaW5mbyhwTWVzc2FnZSwgdG1wRGVjb3JhdGVkRGF0dW0pO1xuXHRcdH1cblx0fVxuXG5cdHdhcm4ocE1lc3NhZ2UsIHBEYXR1bSlcblx0e1xuXHRcdGNvbnN0IHRtcERlY29yYXRlZERhdHVtID0gdGhpcy5kYXR1bURlY29yYXRvcihwRGF0dW0pO1xuXHRcdGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5sb2dTdHJlYW1zV2Fybi5sZW5ndGg7IGkrKylcblx0XHR7XG5cdFx0XHR0aGlzLmxvZ1N0cmVhbXNXYXJuW2ldLndhcm4ocE1lc3NhZ2UsIHRtcERlY29yYXRlZERhdHVtKTtcblx0XHR9XG5cdH1cblxuXHRlcnJvcihwTWVzc2FnZSwgcERhdHVtKVxuXHR7XG5cdFx0Y29uc3QgdG1wRGVjb3JhdGVkRGF0dW0gPSB0aGlzLmRhdHVtRGVjb3JhdG9yKHBEYXR1bSk7XG5cdFx0Zm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLmxvZ1N0cmVhbXNFcnJvci5sZW5ndGg7IGkrKylcblx0XHR7XG5cdFx0XHR0aGlzLmxvZ1N0cmVhbXNFcnJvcltpXS5lcnJvcihwTWVzc2FnZSwgdG1wRGVjb3JhdGVkRGF0dW0pO1xuXHRcdH1cblx0fVxuXG5cdGZhdGFsKHBNZXNzYWdlLCBwRGF0dW0pXG5cdHtcblx0XHRjb25zdCB0bXBEZWNvcmF0ZWREYXR1bSA9IHRoaXMuZGF0dW1EZWNvcmF0b3IocERhdHVtKTtcblx0XHRmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMubG9nU3RyZWFtc0ZhdGFsLmxlbmd0aDsgaSsrKVxuXHRcdHtcblx0XHRcdHRoaXMubG9nU3RyZWFtc0ZhdGFsW2ldLmZhdGFsKHBNZXNzYWdlLCB0bXBEZWNvcmF0ZWREYXR1bSk7XG5cdFx0fVxuXHR9XG5cblx0aW5pdGlhbGl6ZSgpXG5cdHtcblx0XHQvLyBcImluaXRpYWxpemVcIiBlYWNoIGxvZ2dlciBhcyBkZWZpbmVkIGluIHRoZSBsb2dnaW5nIHBhcmFtZXRlcnNcblx0XHRmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMuX1N0cmVhbURlZmluaXRpb25zLmxlbmd0aDsgaSsrKVxuXHRcdHtcblx0XHRcdGxldCB0bXBTdHJlYW1EZWZpbml0aW9uID0gT2JqZWN0LmFzc2lnbih7bG9nZ2VydHlwZTonZGVmYXVsdCcsc3RyZWFtdHlwZTonY29uc29sZScsbGV2ZWw6J2luZm8nfSx0aGlzLl9TdHJlYW1EZWZpbml0aW9uc1tpXSk7XG5cblx0XHRcdGlmICghdGhpcy5fUHJvdmlkZXJzLmhhc093blByb3BlcnR5KHRtcFN0cmVhbURlZmluaXRpb24ubG9nZ2VydHlwZSkpXG5cdFx0XHR7XG5cdFx0XHRcdGNvbnNvbGUubG9nKGBFcnJvciBpbml0aWFsaXppbmcgbG9nIHN0cmVhbTogYmFkIGxvZ2dlcnR5cGUgaW4gc3RyZWFtIGRlZmluaXRpb24gJHtKU09OLnN0cmluZ2lmeSh0bXBTdHJlYW1EZWZpbml0aW9uKX1gKTtcblx0XHRcdH1cblx0XHRcdGVsc2Vcblx0XHRcdHtcblx0XHRcdFx0dGhpcy5hZGRMb2dnZXIobmV3IHRoaXMuX1Byb3ZpZGVyc1t0bXBTdHJlYW1EZWZpbml0aW9uLmxvZ2dlcnR5cGVdKHRtcFN0cmVhbURlZmluaXRpb24sIHRoaXMpLCB0bXBTdHJlYW1EZWZpbml0aW9uLmxldmVsKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHQvLyBOb3cgaW5pdGlhbGl6ZSBlYWNoIG9uZS5cblx0XHRmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMubG9nU3RyZWFtcy5sZW5ndGg7IGkrKylcblx0XHR7XG5cdFx0XHR0aGlzLmxvZ1N0cmVhbXNbaV0uaW5pdGlhbGl6ZSgpO1xuXHRcdH1cblx0fVxuXG5cdGxvZ1RpbWUocE1lc3NhZ2UsIHBEYXR1bSlcblx0e1xuXHRcdGxldCB0bXBNZXNzYWdlID0gKHR5cGVvZihwTWVzc2FnZSkgIT09ICd1bmRlZmluZWQnKSA/IHBNZXNzYWdlIDogJ1RpbWUnO1xuXHRcdGxldCB0bXBUaW1lID0gbmV3IERhdGUoKTtcblx0XHR0aGlzLmluZm8oYCR7dG1wTWVzc2FnZX0gJHt0bXBUaW1lfSAoZXBvY2ggJHsrdG1wVGltZX0pYCwgcERhdHVtKTtcblx0fVxuXG5cdC8vIEdldCBhIHRpbWVzdGFtcFxuXHRnZXRUaW1lU3RhbXAoKVxuXHR7XG5cdFx0cmV0dXJuICtuZXcgRGF0ZSgpO1xuXHR9XG5cblx0Z2V0VGltZURlbHRhKHBUaW1lU3RhbXApXG5cdHtcblx0XHRsZXQgdG1wRW5kVGltZSA9ICtuZXcgRGF0ZSgpO1xuXHRcdHJldHVybiB0bXBFbmRUaW1lLXBUaW1lU3RhbXA7XG5cdH1cblxuXHQvLyBMb2cgdGhlIGRlbHRhIGJldHdlZW4gYSB0aW1lc3RhbXAsIGFuZCBub3cgd2l0aCBhIG1lc3NhZ2Vcblx0bG9nVGltZURlbHRhKHBUaW1lRGVsdGEsIHBNZXNzYWdlLCBwRGF0dW0pXG5cdHtcblx0XHRsZXQgdG1wTWVzc2FnZSA9ICh0eXBlb2YocE1lc3NhZ2UpICE9PSAndW5kZWZpbmVkJykgPyBwTWVzc2FnZSA6ICdUaW1lIE1lYXN1cmVtZW50Jztcblx0XHRsZXQgdG1wRGF0dW0gPSAodHlwZW9mKHBEYXR1bSkgPT09ICdvYmplY3QnKSA/IHBEYXR1bSA6IHt9O1xuXG5cdFx0bGV0IHRtcEVuZFRpbWUgPSArbmV3IERhdGUoKTtcblxuXHRcdHRoaXMuaW5mbyhgJHt0bXBNZXNzYWdlfSBsb2dnZWQgYXQgKGVwb2NoICR7K3RtcEVuZFRpbWV9KSB0b29rICgke3BUaW1lRGVsdGF9bXMpYCwgcERhdHVtKTtcblx0fVxuXG5cdGxvZ1RpbWVEZWx0YUh1bWFuKHBUaW1lRGVsdGEsIHBNZXNzYWdlLCBwRGF0dW0pXG5cdHtcblx0XHRsZXQgdG1wTWVzc2FnZSA9ICh0eXBlb2YocE1lc3NhZ2UpICE9PSAndW5kZWZpbmVkJykgPyBwTWVzc2FnZSA6ICdUaW1lIE1lYXN1cmVtZW50JztcblxuXHRcdGxldCB0bXBFbmRUaW1lID0gK25ldyBEYXRlKCk7XG5cblx0XHRsZXQgdG1wTXMgPSBwYXJzZUludChwVGltZURlbHRhJTEwMDApO1xuXHRcdGxldCB0bXBTZWNvbmRzID0gcGFyc2VJbnQoKHBUaW1lRGVsdGEvMTAwMCklNjApO1xuXHRcdGxldCB0bXBNaW51dGVzID0gcGFyc2VJbnQoKHBUaW1lRGVsdGEvKDEwMDAqNjApKSU2MCk7XG5cdFx0bGV0IHRtcEhvdXJzID0gcGFyc2VJbnQocFRpbWVEZWx0YS8oMTAwMCo2MCo2MCkpO1xuXG5cdFx0dG1wTXMgPSAodG1wTXMgPCAxMCkgPyBcIjAwXCIrdG1wTXMgOiAodG1wTXMgPCAxMDApID8gXCIwXCIrdG1wTXMgOiB0bXBNcztcblx0XHR0bXBTZWNvbmRzID0gKHRtcFNlY29uZHMgPCAxMCkgPyBcIjBcIit0bXBTZWNvbmRzIDogdG1wU2Vjb25kcztcblx0XHR0bXBNaW51dGVzID0gKHRtcE1pbnV0ZXMgPCAxMCkgPyBcIjBcIit0bXBNaW51dGVzIDogdG1wTWludXRlcztcblx0XHR0bXBIb3VycyA9ICh0bXBIb3VycyA8IDEwKSA/IFwiMFwiK3RtcEhvdXJzIDogdG1wSG91cnM7XG5cblx0XHR0aGlzLmluZm8oYCR7dG1wTWVzc2FnZX0gbG9nZ2VkIGF0IChlcG9jaCAkeyt0bXBFbmRUaW1lfSkgdG9vayAoJHtwVGltZURlbHRhfW1zKSBvciAoJHt0bXBIb3Vyc306JHt0bXBNaW51dGVzfToke3RtcFNlY29uZHN9LiR7dG1wTXN9KWAsIHBEYXR1bSk7XG5cdH1cblxuXHRsb2dUaW1lRGVsdGFSZWxhdGl2ZShwU3RhcnRUaW1lLCBwTWVzc2FnZSwgcERhdHVtKVxuXHR7XG5cdFx0dGhpcy5sb2dUaW1lRGVsdGEodGhpcy5nZXRUaW1lRGVsdGEocFN0YXJ0VGltZSksIHBNZXNzYWdlLCBwRGF0dW0pO1xuXHR9XG5cblx0bG9nVGltZURlbHRhUmVsYXRpdmVIdW1hbihwU3RhcnRUaW1lLCBwTWVzc2FnZSwgcERhdHVtKVxuXHR7XG5cdFx0dGhpcy5sb2dUaW1lRGVsdGFIdW1hbih0aGlzLmdldFRpbWVEZWx0YShwU3RhcnRUaW1lKSwgcE1lc3NhZ2UsIHBEYXR1bSk7XG5cdH1cbn1cblxuLy8gVGhpcyBpcyBmb3IgYmFja3dhcmRzIGNvbXBhdGliaWxpdHlcbmZ1bmN0aW9uIGF1dG9Db25zdHJ1Y3QocFNldHRpbmdzKVxue1xuXHRyZXR1cm4gbmV3IEZhYmxlTG9nKHBTZXR0aW5ncyk7XG59XG5cblxubW9kdWxlLmV4cG9ydHMgPSB7bmV3OmF1dG9Db25zdHJ1Y3QsIEZhYmxlTG9nOkZhYmxlTG9nfTtcbiIsIm1vZHVsZS5leHBvcnRzPXtcblx0XCJQcm9kdWN0XCI6IFwiQXBwbGljYXRpb25OYW1lSGVyZVwiLFxuXHRcIlByb2R1Y3RWZXJzaW9uXCI6IFwiMC4wLjBcIixcblxuXHRcIkNvbmZpZ0ZpbGVcIjogZmFsc2UsXG5cblx0XCJMb2dTdHJlYW1zXCI6XG5cdFtcblx0XHR7XG5cdFx0XHRcImxldmVsXCI6IFwidHJhY2VcIlxuXHRcdH1cblx0XVxufVxuIiwiLyoqXG4qIEZhYmxlIFNldHRpbmdzIEFkZC1vblxuKlxuKiBAbGljZW5zZSBNSVRcbipcbiogQGF1dGhvciBTdGV2ZW4gVmVsb3pvIDxzdGV2ZW5AdmVsb3pvLmNvbT5cbiogQG1vZHVsZSBGYWJsZSBTZXR0aW5nc1xuKi9cblxuLy8gbmVlZGVkIHNpbmNlIFN0cmluZy5tYXRjaEFsbCB3YXNuJ3QgYWRkZWQgdG8gbm9kZSB1bnRpbCB2MTJcbmNvbnN0IGxpYk1hdGNoQWxsID0gcmVxdWlyZSgnbWF0Y2gtYWxsJyk7XG5cbi8qKlxuKiBGYWJsZSBTb2x1dGlvbiBTZXR0aW5nc1xuKlxuKiBAY2xhc3MgRmFibGVTZXR0aW5nc1xuKiBAY29uc3RydWN0b3JcbiovXG5cbmNsYXNzIEZhYmxlU2V0dGluZ3Ncbntcblx0Y29uc3RydWN0b3IocEZhYmxlU2V0dGluZ3MpXG5cdHtcblx0XHR0aGlzLmRlZmF1bHQgPSB0aGlzLmJ1aWxkRGVmYXVsdFNldHRpbmdzKCk7XG5cblx0XHQvLyBDb25zdHJ1Y3QgYSBuZXcgc2V0dGluZ3Mgb2JqZWN0XG5cdFx0bGV0IHRtcFNldHRpbmdzID0gdGhpcy5tZXJnZShwRmFibGVTZXR0aW5ncywgdGhpcy5idWlsZERlZmF1bHRTZXR0aW5ncygpKTtcblxuXHRcdC8vIGRlZmF1bHQgZW52aXJvbm1lbnQgdmFyaWFibGUgdGVtcGxhdGluZyB0byBvblxuXHRcdHRoaXMuX1BlcmZvcm1FbnZUZW1wbGF0aW5nID0gIXRtcFNldHRpbmdzIHx8IHRtcFNldHRpbmdzLk5vRW52UmVwbGFjZW1lbnQgIT09IHRydWU7XG5cblx0XHQvLyBUaGUgYmFzZSBzZXR0aW5ncyBvYmplY3QgKHdoYXQgdGhleSB3ZXJlIG9uIGluaXRpYWxpemF0aW9uLCBiZWZvcmUgb3RoZXIgYWN0b3JzIGhhdmUgYWx0ZXJlZCB0aGVtKVxuXHRcdHRoaXMuYmFzZSA9IEpTT04ucGFyc2UoSlNPTi5zdHJpbmdpZnkodG1wU2V0dGluZ3MpKTtcblxuXHRcdGlmICh0bXBTZXR0aW5ncy5EZWZhdWx0Q29uZmlnRmlsZSlcblx0XHR7XG5cdFx0XHR0cnlcblx0XHRcdHtcblx0XHRcdFx0Ly8gSWYgdGhlcmUgaXMgYSBERUZBVUxUIGNvbmZpZ3VyYXRpb24gZmlsZSwgdHJ5IHRvIGxvYWQgYW5kIG1lcmdlIGl0LlxuXHRcdFx0XHR0bXBTZXR0aW5ncyA9IHRoaXMubWVyZ2UocmVxdWlyZSh0bXBTZXR0aW5ncy5EZWZhdWx0Q29uZmlnRmlsZSksIHRtcFNldHRpbmdzKTtcblx0XHRcdH1cblx0XHRcdGNhdGNoIChwRXhjZXB0aW9uKVxuXHRcdFx0e1xuXHRcdFx0XHQvLyBXaHkgdGhpcz8gIE9mdGVuIGZvciBhbiBhcHAgd2Ugd2FudCBzZXR0aW5ncyB0byB3b3JrIG91dCBvZiB0aGUgYm94LCBidXRcblx0XHRcdFx0Ly8gd291bGQgcG90ZW50aWFsbHkgd2FudCB0byBoYXZlIGEgY29uZmlnIGZpbGUgZm9yIGNvbXBsZXggc2V0dGluZ3MuXG5cdFx0XHRcdGNvbnNvbGUubG9nKCdGYWJsZS1TZXR0aW5ncyBXYXJuaW5nOiBEZWZhdWx0IGNvbmZpZ3VyYXRpb24gZmlsZSBzcGVjaWZpZWQgYnV0IHRoZXJlIHdhcyBhIHByb2JsZW0gbG9hZGluZyBpdC4gIEZhbGxpbmcgYmFjayB0byBiYXNlLicpO1xuXHRcdFx0XHRjb25zb2xlLmxvZygnICAgICBMb2FkaW5nIEV4Y2VwdGlvbjogJytwRXhjZXB0aW9uKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHRpZiAodG1wU2V0dGluZ3MuQ29uZmlnRmlsZSlcblx0XHR7XG5cdFx0XHR0cnlcblx0XHRcdHtcblx0XHRcdFx0Ly8gSWYgdGhlcmUgaXMgYSBjb25maWd1cmF0aW9uIGZpbGUsIHRyeSB0byBsb2FkIGFuZCBtZXJnZSBpdC5cblx0XHRcdFx0dG1wU2V0dGluZ3MgPSB0aGlzLm1lcmdlKHJlcXVpcmUodG1wU2V0dGluZ3MuQ29uZmlnRmlsZSksIHRtcFNldHRpbmdzKTtcblx0XHRcdH1cblx0XHRcdGNhdGNoIChwRXhjZXB0aW9uKVxuXHRcdFx0e1xuXHRcdFx0XHQvLyBXaHkgdGhpcz8gIE9mdGVuIGZvciBhbiBhcHAgd2Ugd2FudCBzZXR0aW5ncyB0byB3b3JrIG91dCBvZiB0aGUgYm94LCBidXRcblx0XHRcdFx0Ly8gd291bGQgcG90ZW50aWFsbHkgd2FudCB0byBoYXZlIGEgY29uZmlnIGZpbGUgZm9yIGNvbXBsZXggc2V0dGluZ3MuXG5cdFx0XHRcdGNvbnNvbGUubG9nKCdGYWJsZS1TZXR0aW5ncyBXYXJuaW5nOiBDb25maWd1cmF0aW9uIGZpbGUgc3BlY2lmaWVkIGJ1dCB0aGVyZSB3YXMgYSBwcm9ibGVtIGxvYWRpbmcgaXQuICBGYWxsaW5nIGJhY2sgdG8gYmFzZS4nKTtcblx0XHRcdFx0Y29uc29sZS5sb2coJyAgICAgTG9hZGluZyBFeGNlcHRpb246ICcrcEV4Y2VwdGlvbik7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0dGhpcy5zZXR0aW5ncyA9IHRtcFNldHRpbmdzO1xuXHR9XG5cblx0Ly8gQnVpbGQgYSBkZWZhdWx0IHNldHRpbmdzIG9iamVjdC4gIFVzZSB0aGUgSlNPTiBqaW1teSB0byBlbnN1cmUgaXQgaXMgYWx3YXlzIGEgbmV3IG9iamVjdC5cblx0YnVpbGREZWZhdWx0U2V0dGluZ3MoKVxuXHR7XG5cdFx0cmV0dXJuIEpTT04ucGFyc2UoSlNPTi5zdHJpbmdpZnkocmVxdWlyZSgnLi9GYWJsZS1TZXR0aW5ncy1EZWZhdWx0JykpKTtcblx0fVxuXG5cblx0Ly8gUmVzb2x2ZSAocmVjdXJzaXZlKSBhbnkgZW52aXJvbm1lbnQgdmFyaWFibGVzIGZvdW5kIGluIHNldHRpbmdzIG9iamVjdC5cblx0X3Jlc29sdmVFbnYocFNldHRpbmdzKVxuXHR7XG5cdFx0Zm9yIChjb25zdCB0bXBLZXkgaW4gcFNldHRpbmdzKVxuXHRcdHtcblx0XHRcdGNvbnN0IHRtcFZhbHVlID0gcFNldHRpbmdzW3RtcEtleV07XG5cdFx0XHRpZiAodHlwZW9mKHRtcFZhbHVlKSA9PT0gJ29iamVjdCcpIC8vICYmICFBcnJheS5pc0FycmF5KHRtcFZhbHVlKSlcblx0XHRcdHtcblx0XHRcdFx0dGhpcy5fcmVzb2x2ZUVudih0bXBWYWx1ZSk7XG5cdFx0XHR9XG5cdFx0XHRlbHNlIGlmICh0eXBlb2YodG1wVmFsdWUpID09PSAnc3RyaW5nJylcblx0XHRcdHtcblx0XHRcdFx0aWYgKHRtcFZhbHVlLmluZGV4T2YoJyR7JykgPj0gMClcblx0XHRcdFx0e1xuXHRcdFx0XHRcdC8vcGljayBvdXQgYW5kIHJlc29sdmUgZW52IGNvbnN0aWFibGVzIGZyb20gdGhlIHNldHRpbmdzIHZhbHVlLlxuXHRcdFx0XHRcdGNvbnN0IHRtcE1hdGNoZXMgPSBsaWJNYXRjaEFsbCh0bXBWYWx1ZSwgL1xcJFxceyguKj8pXFx9L2cpLnRvQXJyYXkoKTtcblx0XHRcdFx0XHR0bXBNYXRjaGVzLmZvckVhY2goKHRtcE1hdGNoKSA9PlxuXHRcdFx0XHRcdHtcblx0XHRcdFx0XHRcdC8vZm9ybWF0OiBWQVJfTkFNRXxERUZBVUxUX1ZBTFVFXG5cdFx0XHRcdFx0XHRjb25zdCB0bXBQYXJ0cyA9IHRtcE1hdGNoLnNwbGl0KCd8Jyk7XG5cdFx0XHRcdFx0XHRsZXQgdG1wUmVzb2x2ZWRWYWx1ZSA9IHByb2Nlc3MuZW52W3RtcFBhcnRzWzBdXSB8fCAnJztcblx0XHRcdFx0XHRcdGlmICghdG1wUmVzb2x2ZWRWYWx1ZSAmJiB0bXBQYXJ0cy5sZW5ndGggPiAxKVxuXHRcdFx0XHRcdFx0e1xuXHRcdFx0XHRcdFx0XHR0bXBSZXNvbHZlZFZhbHVlID0gdG1wUGFydHNbMV07XG5cdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdHBTZXR0aW5nc1t0bXBLZXldID0gcFNldHRpbmdzW3RtcEtleV0ucmVwbGFjZSgnJHsnICsgdG1wTWF0Y2ggKyAnfScsIHRtcFJlc29sdmVkVmFsdWUpO1xuXHRcdFx0XHRcdH0pO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cblx0LyoqXG5cdCAqIENoZWNrIHRvIHNlZSBpZiBhIHZhbHVlIGlzIGFuIG9iamVjdCAoYnV0IG5vdCBhbiBhcnJheSkuXG5cdCAqL1xuXHRfaXNPYmplY3QodmFsdWUpXG5cdHtcblx0XHRyZXR1cm4gdHlwZW9mKHZhbHVlKSA9PT0gJ29iamVjdCcgJiYgIUFycmF5LmlzQXJyYXkodmFsdWUpO1xuXHR9XG5cblx0LyoqXG5cdCAqIE1lcmdlIHR3byBwbGFpbiBvYmplY3RzLiBLZXlzIHRoYXQgYXJlIG9iamVjdHMgaW4gYm90aCB3aWxsIGJlIG1lcmdlZCBwcm9wZXJ0eS13aXNlLlxuXHQgKi9cblx0X2RlZXBNZXJnZU9iamVjdHModG9PYmplY3QsIGZyb21PYmplY3QpXG5cdHtcblx0XHRpZiAoIWZyb21PYmplY3QgfHwgIXRoaXMuX2lzT2JqZWN0KGZyb21PYmplY3QpKVxuXHRcdHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cdFx0T2JqZWN0LmtleXMoZnJvbU9iamVjdCkuZm9yRWFjaCgoa2V5KSA9PlxuXHRcdHtcblx0XHRcdGNvbnN0IGZyb21WYWx1ZSA9IGZyb21PYmplY3Rba2V5XTtcblx0XHRcdGlmICh0aGlzLl9pc09iamVjdChmcm9tVmFsdWUpKVxuXHRcdFx0e1xuXHRcdFx0XHRjb25zdCB0b1ZhbHVlID0gdG9PYmplY3Rba2V5XTtcblx0XHRcdFx0aWYgKHRvVmFsdWUgJiYgdGhpcy5faXNPYmplY3QodG9WYWx1ZSkpXG5cdFx0XHRcdHtcblx0XHRcdFx0XHQvLyBib3RoIGFyZSBvYmplY3RzLCBzbyBkbyBhIHJlY3Vyc2l2ZSBtZXJnZVxuXHRcdFx0XHRcdHRoaXMuX2RlZXBNZXJnZU9iamVjdHModG9WYWx1ZSwgZnJvbVZhbHVlKTtcblx0XHRcdFx0XHRyZXR1cm47XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdHRvT2JqZWN0W2tleV0gPSBmcm9tVmFsdWU7XG5cdFx0fSk7XG5cdFx0cmV0dXJuIHRvT2JqZWN0O1xuXHR9XG5cblx0Ly8gTWVyZ2Ugc29tZSBuZXcgb2JqZWN0IGludG8gdGhlIGV4aXN0aW5nIHNldHRpbmdzLlxuXHRtZXJnZShwU2V0dGluZ3NGcm9tLCBwU2V0dGluZ3NUbylcblx0e1xuXHRcdC8vIElmIGFuIGludmFsaWQgc2V0dGluZ3MgZnJvbSBvYmplY3QgaXMgcGFzc2VkIGluIChlLmcuIG9iamVjdCBjb25zdHJ1Y3RvciB3aXRob3V0IHBhc3NpbmcgaW4gYW55dGhpbmcpIHRoaXMgc2hvdWxkIHN0aWxsIHdvcmtcblx0XHRsZXQgdG1wU2V0dGluZ3NGcm9tID0gKHR5cGVvZihwU2V0dGluZ3NGcm9tKSA9PT0gJ29iamVjdCcpID8gcFNldHRpbmdzRnJvbSA6IHt9O1xuXHRcdC8vIERlZmF1bHQgdG8gdGhlIHNldHRpbmdzIG9iamVjdCBpZiBub25lIGlzIHBhc3NlZCBpbiBmb3IgdGhlIG1lcmdlLlxuXHRcdGxldCB0bXBTZXR0aW5nc1RvID0gKHR5cGVvZihwU2V0dGluZ3NUbykgPT09ICdvYmplY3QnKSA/IHBTZXR0aW5nc1RvIDogdGhpcy5zZXR0aW5ncztcblxuXHRcdC8vIGRvIG5vdCBtdXRhdGUgdGhlIEZyb20gb2JqZWN0IHByb3BlcnR5IHZhbHVlc1xuXHRcdGxldCB0bXBTZXR0aW5nc0Zyb21Db3B5ID0gSlNPTi5wYXJzZShKU09OLnN0cmluZ2lmeSh0bXBTZXR0aW5nc0Zyb20pKTtcblx0XHR0bXBTZXR0aW5nc1RvID0gdGhpcy5fZGVlcE1lcmdlT2JqZWN0cyh0bXBTZXR0aW5nc1RvLCB0bXBTZXR0aW5nc0Zyb21Db3B5KTtcblxuXHRcdGlmICh0aGlzLl9QZXJmb3JtRW52VGVtcGxhdGluZylcblx0XHR7XG5cdFx0XHR0aGlzLl9yZXNvbHZlRW52KHRtcFNldHRpbmdzVG8pO1xuXHRcdH1cblxuXHRcdHJldHVybiB0bXBTZXR0aW5nc1RvO1xuXHR9XG5cblx0Ly8gRmlsbCBpbiBzZXR0aW5ncyBnYXBzIHdpdGhvdXQgb3ZlcndyaXRpbmcgc2V0dGluZ3MgdGhhdCBhcmUgYWxyZWFkeSB0aGVyZVxuXHRmaWxsKHBTZXR0aW5nc0Zyb20pXG5cdHtcblx0XHQvLyBJZiBhbiBpbnZhbGlkIHNldHRpbmdzIGZyb20gb2JqZWN0IGlzIHBhc3NlZCBpbiAoZS5nLiBvYmplY3QgY29uc3RydWN0b3Igd2l0aG91dCBwYXNzaW5nIGluIGFueXRoaW5nKSB0aGlzIHNob3VsZCBzdGlsbCB3b3JrXG5cdFx0bGV0IHRtcFNldHRpbmdzRnJvbSA9ICh0eXBlb2YocFNldHRpbmdzRnJvbSkgPT09ICdvYmplY3QnKSA/IHBTZXR0aW5nc0Zyb20gOiB7fTtcblxuXHRcdC8vIGRvIG5vdCBtdXRhdGUgdGhlIEZyb20gb2JqZWN0IHByb3BlcnR5IHZhbHVlc1xuXHRcdGxldCB0bXBTZXR0aW5nc0Zyb21Db3B5ID0gSlNPTi5wYXJzZShKU09OLnN0cmluZ2lmeSh0bXBTZXR0aW5nc0Zyb20pKTtcblxuXHRcdHRoaXMuc2V0dGluZ3MgPSB0aGlzLl9kZWVwTWVyZ2VPYmplY3RzKHRtcFNldHRpbmdzRnJvbUNvcHksIHRoaXMuc2V0dGluZ3MpO1xuXG5cdFx0cmV0dXJuIHRoaXMuc2V0dGluZ3M7XG5cdH1cbn07XG5cbi8vIFRoaXMgaXMgZm9yIGJhY2t3YXJkcyBjb21wYXRpYmlsaXR5XG5mdW5jdGlvbiBhdXRvQ29uc3RydWN0KHBTZXR0aW5ncylcbntcblx0cmV0dXJuIG5ldyBGYWJsZVNldHRpbmdzKHBTZXR0aW5ncyk7XG59XG5cbm1vZHVsZS5leHBvcnRzID0ge25ldzphdXRvQ29uc3RydWN0LCBGYWJsZVNldHRpbmdzOkZhYmxlU2V0dGluZ3N9O1xuIiwiLyoqXG4qIFJhbmRvbSBCeXRlIEdlbmVyYXRvciAtIEJyb3dzZXIgdmVyc2lvblxuKlxuKiBAbGljZW5zZSBNSVRcbipcbiogQGF1dGhvciBTdGV2ZW4gVmVsb3pvIDxzdGV2ZW5AdmVsb3pvLmNvbT5cbiovXG5cbi8vIEFkYXB0ZWQgZnJvbSBub2RlLXV1aWQgKGh0dHBzOi8vZ2l0aHViLmNvbS9rZWxla3Rpdi9ub2RlLXV1aWQpXG4vLyBVbmlxdWUgSUQgY3JlYXRpb24gcmVxdWlyZXMgYSBoaWdoIHF1YWxpdHkgcmFuZG9tICMgZ2VuZXJhdG9yLiAgSW4gdGhlXG4vLyBicm93c2VyIHRoaXMgaXMgYSBsaXR0bGUgY29tcGxpY2F0ZWQgZHVlIHRvIHVua25vd24gcXVhbGl0eSBvZiBNYXRoLnJhbmRvbSgpXG4vLyBhbmQgaW5jb25zaXN0ZW50IHN1cHBvcnQgZm9yIHRoZSBgY3J5cHRvYCBBUEkuICBXZSBkbyB0aGUgYmVzdCB3ZSBjYW4gdmlhXG4vLyBmZWF0dXJlLWRldGVjdGlvblxuY2xhc3MgUmFuZG9tQnl0ZXNcbntcblx0Y29uc3RydWN0b3IoKVxuXHR7XG5cblx0XHQvLyBnZXRSYW5kb21WYWx1ZXMgbmVlZHMgdG8gYmUgaW52b2tlZCBpbiBhIGNvbnRleHQgd2hlcmUgXCJ0aGlzXCIgaXMgYSBDcnlwdG9cblx0XHQvLyBpbXBsZW1lbnRhdGlvbi4gQWxzbywgZmluZCB0aGUgY29tcGxldGUgaW1wbGVtZW50YXRpb24gb2YgY3J5cHRvIG9uIElFMTEuXG5cdFx0dGhpcy5nZXRSYW5kb21WYWx1ZXMgPSAodHlwZW9mKGNyeXB0bykgIT0gJ3VuZGVmaW5lZCcgJiYgY3J5cHRvLmdldFJhbmRvbVZhbHVlcyAmJiBjcnlwdG8uZ2V0UmFuZG9tVmFsdWVzLmJpbmQoY3J5cHRvKSkgfHxcbiAgICAgICAgICAgICAgICAgICAgICBcdFx0KHR5cGVvZihtc0NyeXB0bykgIT0gJ3VuZGVmaW5lZCcgJiYgdHlwZW9mIHdpbmRvdy5tc0NyeXB0by5nZXRSYW5kb21WYWx1ZXMgPT0gJ2Z1bmN0aW9uJyAmJiBtc0NyeXB0by5nZXRSYW5kb21WYWx1ZXMuYmluZChtc0NyeXB0bykpO1xuXHR9XG5cblx0Ly8gV0hBVFdHIGNyeXB0byBSTkcgLSBodHRwOi8vd2lraS53aGF0d2cub3JnL3dpa2kvQ3J5cHRvXG5cdGdlbmVyYXRlV2hhdFdHQnl0ZXMoKVxuXHR7XG5cdFx0bGV0IHRtcEJ1ZmZlciA9IG5ldyBVaW50OEFycmF5KDE2KTsgLy8gZXNsaW50LWRpc2FibGUtbGluZSBuby11bmRlZlxuXG5cdFx0dGhpcy5nZXRSYW5kb21WYWx1ZXModG1wQnVmZmVyKTtcblx0XHRyZXR1cm4gdG1wQnVmZmVyO1xuXHR9XG5cblx0Ly8gTWF0aC5yYW5kb20oKS1iYXNlZCAoUk5HKVxuXHRnZW5lcmF0ZVJhbmRvbUJ5dGVzKClcblx0e1xuXHRcdC8vIElmIGFsbCBlbHNlIGZhaWxzLCB1c2UgTWF0aC5yYW5kb20oKS4gIEl0J3MgZmFzdCwgYnV0IGlzIG9mIHVuc3BlY2lmaWVkXG5cdFx0Ly8gcXVhbGl0eS5cblx0XHRsZXQgdG1wQnVmZmVyID0gbmV3IFVpbnQ4QXJyYXkoMTYpOyAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIG5vLXVuZGVmXG5cblx0XHRmb3IgKGxldCBpID0gMCwgdG1wVmFsdWU7IGkgPCAxNjsgaSsrKVxuXHRcdHtcblx0XHRcdGlmICgoaSAmIDB4MDMpID09PSAwKVxuXHRcdFx0e1xuXHRcdFx0XHR0bXBWYWx1ZSA9IE1hdGgucmFuZG9tKCkgKiAweDEwMDAwMDAwMDtcblx0XHRcdH1cblxuXHRcdFx0dG1wQnVmZmVyW2ldID0gdG1wVmFsdWUgPj4+ICgoaSAmIDB4MDMpIDw8IDMpICYgMHhmZjtcblx0XHR9XG5cblx0XHRyZXR1cm4gdG1wQnVmZmVyO1xuXHR9XG5cblx0Z2VuZXJhdGUoKVxuXHR7XG5cdFx0aWYgKHRoaXMuZ2V0UmFuZG9tVmFsdWVzKVxuXHRcdHtcblx0XHRcdHJldHVybiB0aGlzLmdlbmVyYXRlV2hhdFdHQnl0ZXMoKTtcblx0XHR9XG5cdFx0ZWxzZVxuXHRcdHtcblx0XHRcdHJldHVybiB0aGlzLmdlbmVyYXRlUmFuZG9tQnl0ZXMoKTtcblx0XHR9XG5cdH1cbn1cblxubW9kdWxlLmV4cG9ydHMgPSBSYW5kb21CeXRlcztcbiIsIi8qKlxuKiBGYWJsZSBVVUlEIEdlbmVyYXRvclxuKlxuKiBAbGljZW5zZSBNSVRcbipcbiogQGF1dGhvciBTdGV2ZW4gVmVsb3pvIDxzdGV2ZW5AdmVsb3pvLmNvbT5cbiogQG1vZHVsZSBGYWJsZSBVVUlEXG4qL1xuXG4vKipcbiogRmFibGUgU29sdXRpb24gVVVJRCBHZW5lcmF0aW9uIE1haW4gQ2xhc3NcbipcbiogQGNsYXNzIEZhYmxlVVVJRFxuKiBAY29uc3RydWN0b3JcbiovXG5cbnZhciBsaWJSYW5kb21CeXRlR2VuZXJhdG9yID0gcmVxdWlyZSgnLi9GYWJsZS1VVUlELVJhbmRvbS5qcycpXG5cbmNsYXNzIEZhYmxlVVVJRFxue1xuXHRjb25zdHJ1Y3RvcihwU2V0dGluZ3MpXG5cdHtcblx0XHQvLyBEZXRlcm1pbmUgaWYgdGhlIG1vZHVsZSBpcyBpbiBcIlJhbmRvbSBVVUlEIE1vZGVcIiB3aGljaCBtZWFucyBqdXN0IHVzZSB0aGUgcmFuZG9tIGNoYXJhY3RlciBmdW5jdGlvbiByYXRoZXIgdGhhbiB0aGUgdjQgcmFuZG9tIFVVSUQgc3BlYy5cblx0XHQvLyBOb3RlIHRoaXMgYWxsb3dzIFVVSURzIG9mIHZhcmlvdXMgbGVuZ3RocyAoaW5jbHVkaW5nIHZlcnkgc2hvcnQgb25lcykgYWx0aG91Z2ggZ3VhcmFudGVlZCB1bmlxdWVuZXNzIGdvZXMgZG93bmhpbGwgZmFzdC5cblx0XHR0aGlzLl9VVUlETW9kZVJhbmRvbSA9ICh0eXBlb2YocFNldHRpbmdzKSA9PT0gJ29iamVjdCcpICYmIChwU2V0dGluZ3MuaGFzT3duUHJvcGVydHkoJ1VVSURNb2RlUmFuZG9tJykpID8gKHBTZXR0aW5ncy5VVUlETW9kZVJhbmRvbSA9PSB0cnVlKSA6IGZhbHNlO1xuXHRcdC8vIFRoZXNlIHR3byBwcm9wZXJ0aWVzIGFyZSBvbmx5IHVzZWZ1bCBpZiB3ZSBhcmUgaW4gUmFuZG9tIG1vZGUuICBPdGhlcndpc2UgaXQgZ2VuZXJhdGVzIGEgdjQgc3BlY1xuXHRcdC8vIExlbmd0aCBmb3IgXCJSYW5kb20gVVVJRCBNb2RlXCIgaXMgc2V0IC0tIGlmIG5vdCBzZXQgaXQgdG8gOFxuXHRcdHRoaXMuX1VVSURMZW5ndGggPSAodHlwZW9mKHBTZXR0aW5ncykgPT09ICdvYmplY3QnKSAmJiAocFNldHRpbmdzLmhhc093blByb3BlcnR5KCdVVUlETGVuZ3RoJykpID8gKHBTZXR0aW5ncy5VVUlETGVuZ3RoICsgMCkgOiA4O1xuXHRcdC8vIERpY3Rpb25hcnkgZm9yIFwiUmFuZG9tIFVVSUQgTW9kZVwiXG5cdFx0dGhpcy5fVVVJRFJhbmRvbURpY3Rpb25hcnkgPSAodHlwZW9mKHBTZXR0aW5ncykgPT09ICdvYmplY3QnKSAmJiAocFNldHRpbmdzLmhhc093blByb3BlcnR5KCdVVUlERGljdGlvbmFyeScpKSA/IChwU2V0dGluZ3MuVVVJRERpY3Rpb25hcnkgKyAwKSA6ICcwMTIzNDU2Nzg5YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWic7XG5cblx0XHR0aGlzLnJhbmRvbUJ5dGVHZW5lcmF0b3IgPSBuZXcgbGliUmFuZG9tQnl0ZUdlbmVyYXRvcigpO1xuXG5cdFx0Ly8gTG9va3VwIHRhYmxlIGZvciBoZXggY29kZXNcblx0XHR0aGlzLl9IZXhMb29rdXAgPSBbXTtcblx0XHRmb3IgKGxldCBpID0gMDsgaSA8IDI1NjsgKytpKVxuXHRcdHtcblx0XHRcdHRoaXMuX0hleExvb2t1cFtpXSA9IChpICsgMHgxMDApLnRvU3RyaW5nKDE2KS5zdWJzdHIoMSk7XG5cdFx0fVxuXHR9XG5cblx0Ly8gQWRhcHRlZCBmcm9tIG5vZGUtdXVpZCAoaHR0cHM6Ly9naXRodWIuY29tL2tlbGVrdGl2L25vZGUtdXVpZClcblx0Ynl0ZXNUb1VVSUQocEJ1ZmZlcilcblx0e1xuXHRcdGxldCBpID0gMDtcblx0XHQvLyBqb2luIHVzZWQgdG8gZml4IG1lbW9yeSBpc3N1ZSBjYXVzZWQgYnkgY29uY2F0ZW5hdGlvbjogaHR0cHM6Ly9idWdzLmNocm9taXVtLm9yZy9wL3Y4L2lzc3Vlcy9kZXRhaWw/aWQ9MzE3NSNjNFxuXHRcdHJldHVybiAoW1xuXHRcdFx0XHRcdHRoaXMuX0hleExvb2t1cFtwQnVmZmVyW2krK11dLCB0aGlzLl9IZXhMb29rdXBbcEJ1ZmZlcltpKytdXSwgXG5cdFx0XHRcdFx0dGhpcy5fSGV4TG9va3VwW3BCdWZmZXJbaSsrXV0sIHRoaXMuX0hleExvb2t1cFtwQnVmZmVyW2krK11dLCAnLScsXG5cdFx0XHRcdFx0dGhpcy5fSGV4TG9va3VwW3BCdWZmZXJbaSsrXV0sIHRoaXMuX0hleExvb2t1cFtwQnVmZmVyW2krK11dLCAnLScsXG5cdFx0XHRcdFx0dGhpcy5fSGV4TG9va3VwW3BCdWZmZXJbaSsrXV0sIHRoaXMuX0hleExvb2t1cFtwQnVmZmVyW2krK11dLCAnLScsXG5cdFx0XHRcdFx0dGhpcy5fSGV4TG9va3VwW3BCdWZmZXJbaSsrXV0sIHRoaXMuX0hleExvb2t1cFtwQnVmZmVyW2krK11dLCAnLScsXG5cdFx0XHRcdFx0dGhpcy5fSGV4TG9va3VwW3BCdWZmZXJbaSsrXV0sIHRoaXMuX0hleExvb2t1cFtwQnVmZmVyW2krK11dLCB0aGlzLl9IZXhMb29rdXBbcEJ1ZmZlcltpKytdXSwgdGhpcy5fSGV4TG9va3VwW3BCdWZmZXJbaSsrXV0sIHRoaXMuX0hleExvb2t1cFtwQnVmZmVyW2krK11dLCB0aGlzLl9IZXhMb29rdXBbcEJ1ZmZlcltpKytdXVxuXHRcdFx0XHRdKS5qb2luKCcnKTtcblx0fVxuXG5cdC8vIEFkYXB0ZWQgZnJvbSBub2RlLXV1aWQgKGh0dHBzOi8vZ2l0aHViLmNvbS9rZWxla3Rpdi9ub2RlLXV1aWQpXG5cdGdlbmVyYXRlVVVJRHY0KClcblx0e1xuXHRcdGxldCB0bXBCdWZmZXIgPSBuZXcgQXJyYXkoMTYpO1xuXHRcdHZhciB0bXBSYW5kb21CeXRlcyA9IHRoaXMucmFuZG9tQnl0ZUdlbmVyYXRvci5nZW5lcmF0ZSgpO1xuXG5cdFx0Ly8gUGVyIDQuNCwgc2V0IGJpdHMgZm9yIHZlcnNpb24gYW5kIGBjbG9ja19zZXFfaGlfYW5kX3Jlc2VydmVkYFxuXHRcdHRtcFJhbmRvbUJ5dGVzWzZdID0gKHRtcFJhbmRvbUJ5dGVzWzZdICYgMHgwZikgfCAweDQwO1xuXHRcdHRtcFJhbmRvbUJ5dGVzWzhdID0gKHRtcFJhbmRvbUJ5dGVzWzhdICYgMHgzZikgfCAweDgwO1xuXG5cdFx0cmV0dXJuIHRoaXMuYnl0ZXNUb1VVSUQodG1wUmFuZG9tQnl0ZXMpO1xuXHR9XG5cblx0Ly8gU2ltcGxlIHJhbmRvbSBVVUlEIGdlbmVyYXRpb25cblx0Z2VuZXJhdGVSYW5kb20oKVxuXHR7XG5cdFx0bGV0IHRtcFVVSUQgPSAnJztcblxuXHRcdGZvciAobGV0IGkgPSAwOyBpIDwgdGhpcy5fVVVJRExlbmd0aDsgaSsrKVxuXHRcdHtcblx0XHRcdHRtcFVVSUQgKz0gdGhpcy5fVVVJRFJhbmRvbURpY3Rpb25hcnkuY2hhckF0KE1hdGguZmxvb3IoTWF0aC5yYW5kb20oKSAqICh0aGlzLl9VVUlEUmFuZG9tRGljdGlvbmFyeS5sZW5ndGgtMSkpKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gdG1wVVVJRDtcblx0fVxuXG5cdC8vIEFkYXB0ZWQgZnJvbSBub2RlLXV1aWQgKGh0dHBzOi8vZ2l0aHViLmNvbS9rZWxla3Rpdi9ub2RlLXV1aWQpXG5cdGdldFVVSUQoKVxuXHR7XG5cdFx0aWYgKHRoaXMuX1VVSURNb2RlUmFuZG9tKVxuXHRcdHtcblx0XHRcdHJldHVybiB0aGlzLmdlbmVyYXRlUmFuZG9tKCk7XG5cdFx0fVxuXHRcdGVsc2Vcblx0XHR7XG5cdFx0XHRyZXR1cm4gdGhpcy5nZW5lcmF0ZVVVSUR2NCgpO1xuXHRcdH1cblx0fVxufVxuXG4vLyBUaGlzIGlzIGZvciBiYWNrd2FyZHMgY29tcGF0aWJpbGl0eVxuZnVuY3Rpb24gYXV0b0NvbnN0cnVjdChwU2V0dGluZ3MpXG57XG5cdHJldHVybiBuZXcgRmFibGVVVUlEKHBTZXR0aW5ncyk7XG59XG5cblxubW9kdWxlLmV4cG9ydHMgPSB7bmV3OmF1dG9Db25zdHJ1Y3QsIEZhYmxlVVVJRDpGYWJsZVVVSUR9O1xuIiwiXCJ1c2Ugc3RyaWN0XCI7XG5cbi8qKlxuICogbWF0Y2hBbGxcbiAqIEdldCBhbGwgdGhlIG1hdGNoZXMgZm9yIGEgcmVndWxhciBleHByZXNzaW9uIGluIGEgc3RyaW5nLlxuICpcbiAqIEBuYW1lIG1hdGNoQWxsXG4gKiBAZnVuY3Rpb25cbiAqIEBwYXJhbSB7U3RyaW5nfSBzIFRoZSBpbnB1dCBzdHJpbmcuXG4gKiBAcGFyYW0ge1JlZ0V4cH0gciBUaGUgcmVndWxhciBleHByZXNzaW9uLlxuICogQHJldHVybiB7T2JqZWN0fSBBbiBvYmplY3QgY29udGFpbmluZyB0aGUgZm9sbG93aW5nIGZpZWxkczpcbiAqXG4gKiAgLSBgaW5wdXRgIChTdHJpbmcpOiBUaGUgaW5wdXQgc3RyaW5nLlxuICogIC0gYHJlZ2V4YCAoUmVnRXhwKTogVGhlIHJlZ3VsYXIgZXhwcmVzc2lvbi5cbiAqICAtIGBuZXh0YCAoRnVuY3Rpb24pOiBHZXQgdGhlIG5leHQgbWF0Y2guXG4gKiAgLSBgdG9BcnJheWAgKEZ1bmN0aW9uKTogR2V0IGFsbCB0aGUgbWF0Y2hlcy5cbiAqICAtIGByZXNldGAgKEZ1bmN0aW9uKTogUmVzZXQgdGhlIGluZGV4LlxuICovXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIG1hdGNoQWxsKHMsIHIpIHtcbiAgICByZXR1cm4ge1xuICAgICAgICBpbnB1dDogcyxcbiAgICAgICAgcmVnZXg6IHJcblxuICAgICAgICAvKipcbiAgICAgICAgICogbmV4dFxuICAgICAgICAgKiBHZXQgdGhlIG5leHQgbWF0Y2ggaW4gc2luZ2xlIGdyb3VwIG1hdGNoLlxuICAgICAgICAgKlxuICAgICAgICAgKiBAbmFtZSBuZXh0XG4gICAgICAgICAqIEBmdW5jdGlvblxuICAgICAgICAgKiBAcmV0dXJuIHtTdHJpbmd8bnVsbH0gVGhlIG1hdGNoZWQgc25pcHBldC5cbiAgICAgICAgICovXG4gICAgICAgICwgbmV4dDogZnVuY3Rpb24gbmV4dCgpIHtcbiAgICAgICAgICAgIHZhciBjID0gdGhpcy5uZXh0UmF3KCk7XG4gICAgICAgICAgICBpZiAoYykge1xuICAgICAgICAgICAgICAgIGZvciAodmFyIGkgPSAxOyBpIDwgYy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgICAgICBpZiAoY1tpXSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGNbaV07XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfVxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBuZXh0UmF3XG4gICAgICAgICAqIEdldCB0aGUgbmV4dCBtYXRjaCBpbiByYXcgcmVnZXggb3V0cHV0LiBVc2VmdWxsIHRvIGdldCBhbm90aGVyIGdyb3VwIG1hdGNoLlxuICAgICAgICAgKlxuICAgICAgICAgKiBAbmFtZSBuZXh0UmF3XG4gICAgICAgICAqIEBmdW5jdGlvblxuICAgICAgICAgKiBAcmV0dXJucyB7QXJyYXl8bnVsbH0gVGhlIG1hdGNoZWQgc25pcHBldFxuICAgICAgICAgKi9cbiAgICAgICAgLFxuICAgICAgICBuZXh0UmF3OiBmdW5jdGlvbiBuZXh0UmF3KCkge1xuICAgICAgICAgICAgdmFyIGMgPSB0aGlzLnJlZ2V4LmV4ZWModGhpcy5pbnB1dCk7XG4gICAgICAgICAgICByZXR1cm4gYztcbiAgICAgICAgfVxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiB0b0FycmF5XG4gICAgICAgICAqIEdldCBhbGwgdGhlIG1hdGNoZXMuXG4gICAgICAgICAqXG4gICAgICAgICAqIEBuYW1lIHRvQXJyYXlcbiAgICAgICAgICogQGZ1bmN0aW9uXG4gICAgICAgICAqIEByZXR1cm4ge0FycmF5fSBUaGUgbWF0Y2hlZCBzbmlwcGV0cy5cbiAgICAgICAgICovXG4gICAgICAgICxcbiAgICAgICAgdG9BcnJheTogZnVuY3Rpb24gdG9BcnJheSgpIHtcbiAgICAgICAgICAgIHZhciByZXMgPSBbXSxcbiAgICAgICAgICAgICAgICBjID0gbnVsbDtcblxuICAgICAgICAgICAgd2hpbGUgKGMgPSB0aGlzLm5leHQoKSkge1xuICAgICAgICAgICAgICAgIHJlcy5wdXNoKGMpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gcmVzO1xuICAgICAgICB9XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIHJlc2V0XG4gICAgICAgICAqIFJlc2V0IHRoZSBpbmRleC5cbiAgICAgICAgICpcbiAgICAgICAgICogQG5hbWUgcmVzZXRcbiAgICAgICAgICogQGZ1bmN0aW9uXG4gICAgICAgICAqIEBwYXJhbSB7TnVtYmVyfSBpIFRoZSBuZXcgaW5kZXggKGRlZmF1bHQ6IGAwYCkuXG4gICAgICAgICAqIEByZXR1cm4ge051bWJlcn0gVGhlIG5ldyBpbmRleC5cbiAgICAgICAgICovXG4gICAgICAgICxcbiAgICAgICAgcmVzZXQ6IGZ1bmN0aW9uIHJlc2V0KGkpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnJlZ2V4Lmxhc3RJbmRleCA9IGkgfHwgMDtcbiAgICAgICAgfVxuICAgIH07XG59OyIsIi8vIHNoaW0gZm9yIHVzaW5nIHByb2Nlc3MgaW4gYnJvd3NlclxudmFyIHByb2Nlc3MgPSBtb2R1bGUuZXhwb3J0cyA9IHt9O1xuXG4vLyBjYWNoZWQgZnJvbSB3aGF0ZXZlciBnbG9iYWwgaXMgcHJlc2VudCBzbyB0aGF0IHRlc3QgcnVubmVycyB0aGF0IHN0dWIgaXRcbi8vIGRvbid0IGJyZWFrIHRoaW5ncy4gIEJ1dCB3ZSBuZWVkIHRvIHdyYXAgaXQgaW4gYSB0cnkgY2F0Y2ggaW4gY2FzZSBpdCBpc1xuLy8gd3JhcHBlZCBpbiBzdHJpY3QgbW9kZSBjb2RlIHdoaWNoIGRvZXNuJ3QgZGVmaW5lIGFueSBnbG9iYWxzLiAgSXQncyBpbnNpZGUgYVxuLy8gZnVuY3Rpb24gYmVjYXVzZSB0cnkvY2F0Y2hlcyBkZW9wdGltaXplIGluIGNlcnRhaW4gZW5naW5lcy5cblxudmFyIGNhY2hlZFNldFRpbWVvdXQ7XG52YXIgY2FjaGVkQ2xlYXJUaW1lb3V0O1xuXG5mdW5jdGlvbiBkZWZhdWx0U2V0VGltb3V0KCkge1xuICAgIHRocm93IG5ldyBFcnJvcignc2V0VGltZW91dCBoYXMgbm90IGJlZW4gZGVmaW5lZCcpO1xufVxuZnVuY3Rpb24gZGVmYXVsdENsZWFyVGltZW91dCAoKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdjbGVhclRpbWVvdXQgaGFzIG5vdCBiZWVuIGRlZmluZWQnKTtcbn1cbihmdW5jdGlvbiAoKSB7XG4gICAgdHJ5IHtcbiAgICAgICAgaWYgKHR5cGVvZiBzZXRUaW1lb3V0ID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICBjYWNoZWRTZXRUaW1lb3V0ID0gc2V0VGltZW91dDtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNhY2hlZFNldFRpbWVvdXQgPSBkZWZhdWx0U2V0VGltb3V0O1xuICAgICAgICB9XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgICBjYWNoZWRTZXRUaW1lb3V0ID0gZGVmYXVsdFNldFRpbW91dDtcbiAgICB9XG4gICAgdHJ5IHtcbiAgICAgICAgaWYgKHR5cGVvZiBjbGVhclRpbWVvdXQgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICAgIGNhY2hlZENsZWFyVGltZW91dCA9IGNsZWFyVGltZW91dDtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNhY2hlZENsZWFyVGltZW91dCA9IGRlZmF1bHRDbGVhclRpbWVvdXQ7XG4gICAgICAgIH1cbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIGNhY2hlZENsZWFyVGltZW91dCA9IGRlZmF1bHRDbGVhclRpbWVvdXQ7XG4gICAgfVxufSAoKSlcbmZ1bmN0aW9uIHJ1blRpbWVvdXQoZnVuKSB7XG4gICAgaWYgKGNhY2hlZFNldFRpbWVvdXQgPT09IHNldFRpbWVvdXQpIHtcbiAgICAgICAgLy9ub3JtYWwgZW52aXJvbWVudHMgaW4gc2FuZSBzaXR1YXRpb25zXG4gICAgICAgIHJldHVybiBzZXRUaW1lb3V0KGZ1biwgMCk7XG4gICAgfVxuICAgIC8vIGlmIHNldFRpbWVvdXQgd2Fzbid0IGF2YWlsYWJsZSBidXQgd2FzIGxhdHRlciBkZWZpbmVkXG4gICAgaWYgKChjYWNoZWRTZXRUaW1lb3V0ID09PSBkZWZhdWx0U2V0VGltb3V0IHx8ICFjYWNoZWRTZXRUaW1lb3V0KSAmJiBzZXRUaW1lb3V0KSB7XG4gICAgICAgIGNhY2hlZFNldFRpbWVvdXQgPSBzZXRUaW1lb3V0O1xuICAgICAgICByZXR1cm4gc2V0VGltZW91dChmdW4sIDApO1xuICAgIH1cbiAgICB0cnkge1xuICAgICAgICAvLyB3aGVuIHdoZW4gc29tZWJvZHkgaGFzIHNjcmV3ZWQgd2l0aCBzZXRUaW1lb3V0IGJ1dCBubyBJLkUuIG1hZGRuZXNzXG4gICAgICAgIHJldHVybiBjYWNoZWRTZXRUaW1lb3V0KGZ1biwgMCk7XG4gICAgfSBjYXRjaChlKXtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIC8vIFdoZW4gd2UgYXJlIGluIEkuRS4gYnV0IHRoZSBzY3JpcHQgaGFzIGJlZW4gZXZhbGVkIHNvIEkuRS4gZG9lc24ndCB0cnVzdCB0aGUgZ2xvYmFsIG9iamVjdCB3aGVuIGNhbGxlZCBub3JtYWxseVxuICAgICAgICAgICAgcmV0dXJuIGNhY2hlZFNldFRpbWVvdXQuY2FsbChudWxsLCBmdW4sIDApO1xuICAgICAgICB9IGNhdGNoKGUpe1xuICAgICAgICAgICAgLy8gc2FtZSBhcyBhYm92ZSBidXQgd2hlbiBpdCdzIGEgdmVyc2lvbiBvZiBJLkUuIHRoYXQgbXVzdCBoYXZlIHRoZSBnbG9iYWwgb2JqZWN0IGZvciAndGhpcycsIGhvcGZ1bGx5IG91ciBjb250ZXh0IGNvcnJlY3Qgb3RoZXJ3aXNlIGl0IHdpbGwgdGhyb3cgYSBnbG9iYWwgZXJyb3JcbiAgICAgICAgICAgIHJldHVybiBjYWNoZWRTZXRUaW1lb3V0LmNhbGwodGhpcywgZnVuLCAwKTtcbiAgICAgICAgfVxuICAgIH1cblxuXG59XG5mdW5jdGlvbiBydW5DbGVhclRpbWVvdXQobWFya2VyKSB7XG4gICAgaWYgKGNhY2hlZENsZWFyVGltZW91dCA9PT0gY2xlYXJUaW1lb3V0KSB7XG4gICAgICAgIC8vbm9ybWFsIGVudmlyb21lbnRzIGluIHNhbmUgc2l0dWF0aW9uc1xuICAgICAgICByZXR1cm4gY2xlYXJUaW1lb3V0KG1hcmtlcik7XG4gICAgfVxuICAgIC8vIGlmIGNsZWFyVGltZW91dCB3YXNuJ3QgYXZhaWxhYmxlIGJ1dCB3YXMgbGF0dGVyIGRlZmluZWRcbiAgICBpZiAoKGNhY2hlZENsZWFyVGltZW91dCA9PT0gZGVmYXVsdENsZWFyVGltZW91dCB8fCAhY2FjaGVkQ2xlYXJUaW1lb3V0KSAmJiBjbGVhclRpbWVvdXQpIHtcbiAgICAgICAgY2FjaGVkQ2xlYXJUaW1lb3V0ID0gY2xlYXJUaW1lb3V0O1xuICAgICAgICByZXR1cm4gY2xlYXJUaW1lb3V0KG1hcmtlcik7XG4gICAgfVxuICAgIHRyeSB7XG4gICAgICAgIC8vIHdoZW4gd2hlbiBzb21lYm9keSBoYXMgc2NyZXdlZCB3aXRoIHNldFRpbWVvdXQgYnV0IG5vIEkuRS4gbWFkZG5lc3NcbiAgICAgICAgcmV0dXJuIGNhY2hlZENsZWFyVGltZW91dChtYXJrZXIpO1xuICAgIH0gY2F0Y2ggKGUpe1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgLy8gV2hlbiB3ZSBhcmUgaW4gSS5FLiBidXQgdGhlIHNjcmlwdCBoYXMgYmVlbiBldmFsZWQgc28gSS5FLiBkb2Vzbid0ICB0cnVzdCB0aGUgZ2xvYmFsIG9iamVjdCB3aGVuIGNhbGxlZCBub3JtYWxseVxuICAgICAgICAgICAgcmV0dXJuIGNhY2hlZENsZWFyVGltZW91dC5jYWxsKG51bGwsIG1hcmtlcik7XG4gICAgICAgIH0gY2F0Y2ggKGUpe1xuICAgICAgICAgICAgLy8gc2FtZSBhcyBhYm92ZSBidXQgd2hlbiBpdCdzIGEgdmVyc2lvbiBvZiBJLkUuIHRoYXQgbXVzdCBoYXZlIHRoZSBnbG9iYWwgb2JqZWN0IGZvciAndGhpcycsIGhvcGZ1bGx5IG91ciBjb250ZXh0IGNvcnJlY3Qgb3RoZXJ3aXNlIGl0IHdpbGwgdGhyb3cgYSBnbG9iYWwgZXJyb3IuXG4gICAgICAgICAgICAvLyBTb21lIHZlcnNpb25zIG9mIEkuRS4gaGF2ZSBkaWZmZXJlbnQgcnVsZXMgZm9yIGNsZWFyVGltZW91dCB2cyBzZXRUaW1lb3V0XG4gICAgICAgICAgICByZXR1cm4gY2FjaGVkQ2xlYXJUaW1lb3V0LmNhbGwodGhpcywgbWFya2VyKTtcbiAgICAgICAgfVxuICAgIH1cblxuXG5cbn1cbnZhciBxdWV1ZSA9IFtdO1xudmFyIGRyYWluaW5nID0gZmFsc2U7XG52YXIgY3VycmVudFF1ZXVlO1xudmFyIHF1ZXVlSW5kZXggPSAtMTtcblxuZnVuY3Rpb24gY2xlYW5VcE5leHRUaWNrKCkge1xuICAgIGlmICghZHJhaW5pbmcgfHwgIWN1cnJlbnRRdWV1ZSkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIGRyYWluaW5nID0gZmFsc2U7XG4gICAgaWYgKGN1cnJlbnRRdWV1ZS5sZW5ndGgpIHtcbiAgICAgICAgcXVldWUgPSBjdXJyZW50UXVldWUuY29uY2F0KHF1ZXVlKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICBxdWV1ZUluZGV4ID0gLTE7XG4gICAgfVxuICAgIGlmIChxdWV1ZS5sZW5ndGgpIHtcbiAgICAgICAgZHJhaW5RdWV1ZSgpO1xuICAgIH1cbn1cblxuZnVuY3Rpb24gZHJhaW5RdWV1ZSgpIHtcbiAgICBpZiAoZHJhaW5pbmcpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB2YXIgdGltZW91dCA9IHJ1blRpbWVvdXQoY2xlYW5VcE5leHRUaWNrKTtcbiAgICBkcmFpbmluZyA9IHRydWU7XG5cbiAgICB2YXIgbGVuID0gcXVldWUubGVuZ3RoO1xuICAgIHdoaWxlKGxlbikge1xuICAgICAgICBjdXJyZW50UXVldWUgPSBxdWV1ZTtcbiAgICAgICAgcXVldWUgPSBbXTtcbiAgICAgICAgd2hpbGUgKCsrcXVldWVJbmRleCA8IGxlbikge1xuICAgICAgICAgICAgaWYgKGN1cnJlbnRRdWV1ZSkge1xuICAgICAgICAgICAgICAgIGN1cnJlbnRRdWV1ZVtxdWV1ZUluZGV4XS5ydW4oKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBxdWV1ZUluZGV4ID0gLTE7XG4gICAgICAgIGxlbiA9IHF1ZXVlLmxlbmd0aDtcbiAgICB9XG4gICAgY3VycmVudFF1ZXVlID0gbnVsbDtcbiAgICBkcmFpbmluZyA9IGZhbHNlO1xuICAgIHJ1bkNsZWFyVGltZW91dCh0aW1lb3V0KTtcbn1cblxucHJvY2Vzcy5uZXh0VGljayA9IGZ1bmN0aW9uIChmdW4pIHtcbiAgICB2YXIgYXJncyA9IG5ldyBBcnJheShhcmd1bWVudHMubGVuZ3RoIC0gMSk7XG4gICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPiAxKSB7XG4gICAgICAgIGZvciAodmFyIGkgPSAxOyBpIDwgYXJndW1lbnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBhcmdzW2kgLSAxXSA9IGFyZ3VtZW50c1tpXTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBxdWV1ZS5wdXNoKG5ldyBJdGVtKGZ1biwgYXJncykpO1xuICAgIGlmIChxdWV1ZS5sZW5ndGggPT09IDEgJiYgIWRyYWluaW5nKSB7XG4gICAgICAgIHJ1blRpbWVvdXQoZHJhaW5RdWV1ZSk7XG4gICAgfVxufTtcblxuLy8gdjggbGlrZXMgcHJlZGljdGlibGUgb2JqZWN0c1xuZnVuY3Rpb24gSXRlbShmdW4sIGFycmF5KSB7XG4gICAgdGhpcy5mdW4gPSBmdW47XG4gICAgdGhpcy5hcnJheSA9IGFycmF5O1xufVxuSXRlbS5wcm90b3R5cGUucnVuID0gZnVuY3Rpb24gKCkge1xuICAgIHRoaXMuZnVuLmFwcGx5KG51bGwsIHRoaXMuYXJyYXkpO1xufTtcbnByb2Nlc3MudGl0bGUgPSAnYnJvd3Nlcic7XG5wcm9jZXNzLmJyb3dzZXIgPSB0cnVlO1xucHJvY2Vzcy5lbnYgPSB7fTtcbnByb2Nlc3MuYXJndiA9IFtdO1xucHJvY2Vzcy52ZXJzaW9uID0gJyc7IC8vIGVtcHR5IHN0cmluZyB0byBhdm9pZCByZWdleHAgaXNzdWVzXG5wcm9jZXNzLnZlcnNpb25zID0ge307XG5cbmZ1bmN0aW9uIG5vb3AoKSB7fVxuXG5wcm9jZXNzLm9uID0gbm9vcDtcbnByb2Nlc3MuYWRkTGlzdGVuZXIgPSBub29wO1xucHJvY2Vzcy5vbmNlID0gbm9vcDtcbnByb2Nlc3Mub2ZmID0gbm9vcDtcbnByb2Nlc3MucmVtb3ZlTGlzdGVuZXIgPSBub29wO1xucHJvY2Vzcy5yZW1vdmVBbGxMaXN0ZW5lcnMgPSBub29wO1xucHJvY2Vzcy5lbWl0ID0gbm9vcDtcbnByb2Nlc3MucHJlcGVuZExpc3RlbmVyID0gbm9vcDtcbnByb2Nlc3MucHJlcGVuZE9uY2VMaXN0ZW5lciA9IG5vb3A7XG5cbnByb2Nlc3MubGlzdGVuZXJzID0gZnVuY3Rpb24gKG5hbWUpIHsgcmV0dXJuIFtdIH1cblxucHJvY2Vzcy5iaW5kaW5nID0gZnVuY3Rpb24gKG5hbWUpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ3Byb2Nlc3MuYmluZGluZyBpcyBub3Qgc3VwcG9ydGVkJyk7XG59O1xuXG5wcm9jZXNzLmN3ZCA9IGZ1bmN0aW9uICgpIHsgcmV0dXJuICcvJyB9O1xucHJvY2Vzcy5jaGRpciA9IGZ1bmN0aW9uIChkaXIpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ3Byb2Nlc3MuY2hkaXIgaXMgbm90IHN1cHBvcnRlZCcpO1xufTtcbnByb2Nlc3MudW1hc2sgPSBmdW5jdGlvbigpIHsgcmV0dXJuIDA7IH07XG4iLCIvLyAjIyMjIyBQYXJ0IG9mIHRoZSAqKltyZXRvbGRdKGh0dHBzOi8vc3RldmVudmVsb3pvLmdpdGh1Yi5pby9yZXRvbGQvKSoqIHN5c3RlbVxuLyoqXG4qIEBsaWNlbnNlIE1JVFxuKiBAYXV0aG9yIDxzdGV2ZW5AdmVsb3pvLmNvbT5cbiovXG5jb25zdCBsaWJGYWJsZVNldHRpbmdzID0gcmVxdWlyZSgnZmFibGUtc2V0dGluZ3MnKS5GYWJsZVNldHRpbmdzO1xuY29uc3QgbGliRmFibGVVVUlEID0gcmVxdWlyZSgnZmFibGUtdXVpZCcpLkZhYmxlVVVJRDtcbmNvbnN0IGxpYkZhYmxlTG9nID0gcmVxdWlyZSgnZmFibGUtbG9nJykuRmFibGVMb2c7XG5cblxuLyoqXG4qIEZhYmxlIEFwcGxpY2F0aW9uIFNlcnZpY2VzIFN1cHBvcnQgTGlicmFyeVxuKlxuKiBAY2xhc3MgRmFibGVcbiovXG5jbGFzcyBGYWJsZVxue1xuXHRjb25zdHJ1Y3RvcihwU2V0dGluZ3MpXG5cdHtcblx0XHRsZXQgdG1wU2V0dGluZ3MgPSBuZXcgbGliRmFibGVTZXR0aW5ncyhwU2V0dGluZ3MpO1xuXG5cdFx0dGhpcy5zZXR0aW5nc01hbmFnZXIgPSB0bXBTZXR0aW5ncztcblxuXHRcdC8vIEluc3RhbnRpYXRlIHRoZSBVVUlEIGdlbmVyYXRvclxuXHRcdHRoaXMubGliVVVJRCA9IG5ldyBsaWJGYWJsZVVVSUQodGhpcy5zZXR0aW5nc01hbmFnZXIuc2V0dGluZ3MpO1xuXG5cdFx0dGhpcy5sb2cgPSBuZXcgbGliRmFibGVMb2codGhpcy5zZXR0aW5nc01hbmFnZXIuc2V0dGluZ3MpO1xuXHRcdHRoaXMubG9nLmluaXRpYWxpemUoKTtcblx0fVxuXG5cdGdldCBzZXR0aW5ncygpXG5cdHtcblx0XHRyZXR1cm4gdGhpcy5zZXR0aW5nc01hbmFnZXIuc2V0dGluZ3M7XG5cdH1cblxuXHRnZXQgZmFibGUoKVxuXHR7XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH1cblxuXHRnZXRVVUlEKClcblx0e1xuXHRcdHJldHVybiB0aGlzLmxpYlVVSUQuZ2V0VVVJRCgpO1xuXHR9XG59XG5cbi8vIFRoaXMgaXMgZm9yIGJhY2t3YXJkcyBjb21wYXRpYmlsaXR5XG5mdW5jdGlvbiBhdXRvQ29uc3RydWN0KHBTZXR0aW5ncylcbntcblx0cmV0dXJuIG5ldyBGYWJsZShwU2V0dGluZ3MpO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHtuZXc6YXV0b0NvbnN0cnVjdCwgRmFibGU6RmFibGV9OyJdfQ==
1099
+ queue.push(new Item(fun, args));
1100
+ if (queue.length === 1 && !draining) {
1101
+ runTimeout(drainQueue);
1102
+ }
1103
+ };
1104
+
1105
+ // v8 likes predictible objects
1106
+ function Item(fun, array) {
1107
+ this.fun = fun;
1108
+ this.array = array;
1109
+ }
1110
+ Item.prototype.run = function () {
1111
+ this.fun.apply(null, this.array);
1112
+ };
1113
+ process.title = 'browser';
1114
+ process.browser = true;
1115
+ process.env = {};
1116
+ process.argv = [];
1117
+ process.version = ''; // empty string to avoid regexp issues
1118
+ process.versions = {};
1119
+ function noop() {}
1120
+ process.on = noop;
1121
+ process.addListener = noop;
1122
+ process.once = noop;
1123
+ process.off = noop;
1124
+ process.removeListener = noop;
1125
+ process.removeAllListeners = noop;
1126
+ process.emit = noop;
1127
+ process.prependListener = noop;
1128
+ process.prependOnceListener = noop;
1129
+ process.listeners = function (name) {
1130
+ return [];
1131
+ };
1132
+ process.binding = function (name) {
1133
+ throw new Error('process.binding is not supported');
1134
+ };
1135
+ process.cwd = function () {
1136
+ return '/';
1137
+ };
1138
+ process.chdir = function (dir) {
1139
+ throw new Error('process.chdir is not supported');
1140
+ };
1141
+ process.umask = function () {
1142
+ return 0;
1143
+ };
1144
+ }, {}],
1145
+ 15: [function (require, module, exports) {
1146
+ /**
1147
+ * Simple browser shim loader - assign the npm module to a window global automatically
1148
+ *
1149
+ * @license MIT
1150
+ * @author <steven@velozo.com>
1151
+ */
1152
+ var libNPMModuleWrapper = require('./Fable.js');
1153
+ if (typeof window === 'object' && !window.hasOwnProperty('Fable')) {
1154
+ window.Fable = libNPMModuleWrapper;
1155
+ }
1156
+ module.exports = libNPMModuleWrapper;
1157
+ }, {
1158
+ "./Fable.js": 16
1159
+ }],
1160
+ 16: [function (require, module, exports) {
1161
+ // ##### Part of the **[retold](https://stevenvelozo.github.io/retold/)** system
1162
+ /**
1163
+ * @license MIT
1164
+ * @author <steven@velozo.com>
1165
+ */
1166
+ const libFableSettings = require('fable-settings').FableSettings;
1167
+ const libFableUUID = require('fable-uuid').FableUUID;
1168
+ const libFableLog = require('fable-log').FableLog;
1169
+
1170
+ /**
1171
+ * Fable Application Services Support Library
1172
+ *
1173
+ * @class Fable
1174
+ */
1175
+ class Fable {
1176
+ constructor(pSettings) {
1177
+ let tmpSettings = new libFableSettings(pSettings);
1178
+ this.settingsManager = tmpSettings;
1179
+
1180
+ // Instantiate the UUID generator
1181
+ this.libUUID = new libFableUUID(this.settingsManager.settings);
1182
+ this.log = new libFableLog(this.settingsManager.settings);
1183
+ this.log.initialize();
1184
+ }
1185
+ get settings() {
1186
+ return this.settingsManager.settings;
1187
+ }
1188
+ get fable() {
1189
+ return this;
1190
+ }
1191
+ getUUID() {
1192
+ return this.libUUID.getUUID();
1193
+ }
1194
+ }
1195
+
1196
+ // This is for backwards compatibility
1197
+ function autoConstruct(pSettings) {
1198
+ return new Fable(pSettings);
1199
+ }
1200
+ module.exports = {
1201
+ new: autoConstruct,
1202
+ Fable: Fable
1203
+ };
1204
+ }, {
1205
+ "fable-log": 5,
1206
+ "fable-settings": 8,
1207
+ "fable-uuid": 10
1208
+ }]
1209
+ }, {}, [15])(15);
1210
+ });