fable 2.0.5 → 3.0.2

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