Initial commit
[yaffs-website] / node_modules / postcss / lib / node.js
1 'use strict';
2
3 exports.__esModule = true;
4
5 var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
6
7 var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
8
9 var _cssSyntaxError = require('./css-syntax-error');
10
11 var _cssSyntaxError2 = _interopRequireDefault(_cssSyntaxError);
12
13 var _stringifier = require('./stringifier');
14
15 var _stringifier2 = _interopRequireDefault(_stringifier);
16
17 var _stringify = require('./stringify');
18
19 var _stringify2 = _interopRequireDefault(_stringify);
20
21 var _warnOnce = require('./warn-once');
22
23 var _warnOnce2 = _interopRequireDefault(_warnOnce);
24
25 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
26
27 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
28
29 var cloneNode = function cloneNode(obj, parent) {
30     var cloned = new obj.constructor();
31
32     for (var i in obj) {
33         if (!obj.hasOwnProperty(i)) continue;
34         var value = obj[i];
35         var type = typeof value === 'undefined' ? 'undefined' : _typeof(value);
36
37         if (i === 'parent' && type === 'object') {
38             if (parent) cloned[i] = parent;
39         } else if (i === 'source') {
40             cloned[i] = value;
41         } else if (value instanceof Array) {
42             cloned[i] = value.map(function (j) {
43                 return cloneNode(j, cloned);
44             });
45         } else if (i !== 'before' && i !== 'after' && i !== 'between' && i !== 'semicolon') {
46             if (type === 'object' && value !== null) value = cloneNode(value);
47             cloned[i] = value;
48         }
49     }
50
51     return cloned;
52 };
53
54 /**
55  * All node classes inherit the following common methods.
56  *
57  * @abstract
58  */
59
60 var Node = function () {
61
62     /**
63      * @param {object} [defaults] - value for node properties
64      */
65     function Node() {
66         var defaults = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
67
68         _classCallCheck(this, Node);
69
70         this.raws = {};
71         if ((typeof defaults === 'undefined' ? 'undefined' : _typeof(defaults)) !== 'object' && typeof defaults !== 'undefined') {
72             throw new Error('PostCSS nodes constructor accepts object, not ' + JSON.stringify(defaults));
73         }
74         for (var name in defaults) {
75             this[name] = defaults[name];
76         }
77     }
78
79     /**
80      * Returns a CssSyntaxError instance containing the original position
81      * of the node in the source, showing line and column numbers and also
82      * a small excerpt to facilitate debugging.
83      *
84      * If present, an input source map will be used to get the original position
85      * of the source, even from a previous compilation step
86      * (e.g., from Sass compilation).
87      *
88      * This method produces very useful error messages.
89      *
90      * @param {string} message     - error description
91      * @param {object} [opts]      - options
92      * @param {string} opts.plugin - plugin name that created this error.
93      *                               PostCSS will set it automatically.
94      * @param {string} opts.word   - a word inside a node’s string that should
95      *                               be highlighted as the source of the error
96      * @param {number} opts.index  - an index inside a node’s string that should
97      *                               be highlighted as the source of the error
98      *
99      * @return {CssSyntaxError} error object to throw it
100      *
101      * @example
102      * if ( !variables[name] ) {
103      *   throw decl.error('Unknown variable ' + name, { word: name });
104      *   // CssSyntaxError: postcss-vars:a.sass:4:3: Unknown variable $black
105      *   //   color: $black
106      *   // a
107      *   //          ^
108      *   //   background: white
109      * }
110      */
111
112
113     Node.prototype.error = function error(message) {
114         var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
115
116         if (this.source) {
117             var pos = this.positionBy(opts);
118             return this.source.input.error(message, pos.line, pos.column, opts);
119         } else {
120             return new _cssSyntaxError2.default(message);
121         }
122     };
123
124     /**
125      * This method is provided as a convenience wrapper for {@link Result#warn}.
126      *
127      * @param {Result} result      - the {@link Result} instance
128      *                               that will receive the warning
129      * @param {string} text        - warning message
130      * @param {object} [opts]      - options
131      * @param {string} opts.plugin - plugin name that created this warning.
132      *                               PostCSS will set it automatically.
133      * @param {string} opts.word   - a word inside a node’s string that should
134      *                               be highlighted as the source of the warning
135      * @param {number} opts.index  - an index inside a node’s string that should
136      *                               be highlighted as the source of the warning
137      *
138      * @return {Warning} created warning object
139      *
140      * @example
141      * const plugin = postcss.plugin('postcss-deprecated', () => {
142      *   return (root, result) => {
143      *     root.walkDecls('bad', decl => {
144      *       decl.warn(result, 'Deprecated property bad');
145      *     });
146      *   };
147      * });
148      */
149
150
151     Node.prototype.warn = function warn(result, text, opts) {
152         var data = { node: this };
153         for (var i in opts) {
154             data[i] = opts[i];
155         }return result.warn(text, data);
156     };
157
158     /**
159      * Removes the node from its parent and cleans the parent properties
160      * from the node and its children.
161      *
162      * @example
163      * if ( decl.prop.match(/^-webkit-/) ) {
164      *   decl.remove();
165      * }
166      *
167      * @return {Node} node to make calls chain
168      */
169
170
171     Node.prototype.remove = function remove() {
172         if (this.parent) {
173             this.parent.removeChild(this);
174         }
175         this.parent = undefined;
176         return this;
177     };
178
179     /**
180      * Returns a CSS string representing the node.
181      *
182      * @param {stringifier|syntax} [stringifier] - a syntax to use
183      *                                             in string generation
184      *
185      * @return {string} CSS string of this node
186      *
187      * @example
188      * postcss.rule({ selector: 'a' }).toString() //=> "a {}"
189      */
190
191
192     Node.prototype.toString = function toString() {
193         var stringifier = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _stringify2.default;
194
195         if (stringifier.stringify) stringifier = stringifier.stringify;
196         var result = '';
197         stringifier(this, function (i) {
198             result += i;
199         });
200         return result;
201     };
202
203     /**
204      * Returns a clone of the node.
205      *
206      * The resulting cloned node and its (cloned) children will have
207      * a clean parent and code style properties.
208      *
209      * @param {object} [overrides] - new properties to override in the clone.
210      *
211      * @example
212      * const cloned = decl.clone({ prop: '-moz-' + decl.prop });
213      * cloned.raws.before  //=> undefined
214      * cloned.parent       //=> undefined
215      * cloned.toString()   //=> -moz-transform: scale(0)
216      *
217      * @return {Node} clone of the node
218      */
219
220
221     Node.prototype.clone = function clone() {
222         var overrides = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
223
224         var cloned = cloneNode(this);
225         for (var name in overrides) {
226             cloned[name] = overrides[name];
227         }
228         return cloned;
229     };
230
231     /**
232      * Shortcut to clone the node and insert the resulting cloned node
233      * before the current node.
234      *
235      * @param {object} [overrides] - new properties to override in the clone.
236      *
237      * @example
238      * decl.cloneBefore({ prop: '-moz-' + decl.prop });
239      *
240      * @return {Node} - new node
241      */
242
243
244     Node.prototype.cloneBefore = function cloneBefore() {
245         var overrides = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
246
247         var cloned = this.clone(overrides);
248         this.parent.insertBefore(this, cloned);
249         return cloned;
250     };
251
252     /**
253      * Shortcut to clone the node and insert the resulting cloned node
254      * after the current node.
255      *
256      * @param {object} [overrides] - new properties to override in the clone.
257      *
258      * @return {Node} - new node
259      */
260
261
262     Node.prototype.cloneAfter = function cloneAfter() {
263         var overrides = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
264
265         var cloned = this.clone(overrides);
266         this.parent.insertAfter(this, cloned);
267         return cloned;
268     };
269
270     /**
271      * Inserts node(s) before the current node and removes the current node.
272      *
273      * @param {...Node} nodes - node(s) to replace current one
274      *
275      * @example
276      * if ( atrule.name == 'mixin' ) {
277      *   atrule.replaceWith(mixinRules[atrule.params]);
278      * }
279      *
280      * @return {Node} current node to methods chain
281      */
282
283
284     Node.prototype.replaceWith = function replaceWith() {
285         if (this.parent) {
286             for (var _len = arguments.length, nodes = Array(_len), _key = 0; _key < _len; _key++) {
287                 nodes[_key] = arguments[_key];
288             }
289
290             for (var _iterator = nodes, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) {
291                 var _ref;
292
293                 if (_isArray) {
294                     if (_i >= _iterator.length) break;
295                     _ref = _iterator[_i++];
296                 } else {
297                     _i = _iterator.next();
298                     if (_i.done) break;
299                     _ref = _i.value;
300                 }
301
302                 var node = _ref;
303
304                 this.parent.insertBefore(this, node);
305             }
306
307             this.remove();
308         }
309
310         return this;
311     };
312
313     /**
314      * Removes the node from its current parent and inserts it
315      * at the end of `newParent`.
316      *
317      * This will clean the `before` and `after` code {@link Node#raws} data
318      * from the node and replace them with the indentation style of `newParent`.
319      * It will also clean the `between` property
320      * if `newParent` is in another {@link Root}.
321      *
322      * @param {Container} newParent - container node where the current node
323      *                                will be moved
324      *
325      * @example
326      * atrule.moveTo(atrule.root());
327      *
328      * @return {Node} current node to methods chain
329      */
330
331
332     Node.prototype.moveTo = function moveTo(newParent) {
333         this.cleanRaws(this.root() === newParent.root());
334         this.remove();
335         newParent.append(this);
336         return this;
337     };
338
339     /**
340      * Removes the node from its current parent and inserts it into
341      * a new parent before `otherNode`.
342      *
343      * This will also clean the node’s code style properties just as it would
344      * in {@link Node#moveTo}.
345      *
346      * @param {Node} otherNode - node that will be before current node
347      *
348      * @return {Node} current node to methods chain
349      */
350
351
352     Node.prototype.moveBefore = function moveBefore(otherNode) {
353         this.cleanRaws(this.root() === otherNode.root());
354         this.remove();
355         otherNode.parent.insertBefore(otherNode, this);
356         return this;
357     };
358
359     /**
360      * Removes the node from its current parent and inserts it into
361      * a new parent after `otherNode`.
362      *
363      * This will also clean the node’s code style properties just as it would
364      * in {@link Node#moveTo}.
365      *
366      * @param {Node} otherNode - node that will be after current node
367      *
368      * @return {Node} current node to methods chain
369      */
370
371
372     Node.prototype.moveAfter = function moveAfter(otherNode) {
373         this.cleanRaws(this.root() === otherNode.root());
374         this.remove();
375         otherNode.parent.insertAfter(otherNode, this);
376         return this;
377     };
378
379     /**
380      * Returns the next child of the node’s parent.
381      * Returns `undefined` if the current node is the last child.
382      *
383      * @return {Node|undefined} next node
384      *
385      * @example
386      * if ( comment.text === 'delete next' ) {
387      *   const next = comment.next();
388      *   if ( next ) {
389      *     next.remove();
390      *   }
391      * }
392      */
393
394
395     Node.prototype.next = function next() {
396         var index = this.parent.index(this);
397         return this.parent.nodes[index + 1];
398     };
399
400     /**
401      * Returns the previous child of the node’s parent.
402      * Returns `undefined` if the current node is the first child.
403      *
404      * @return {Node|undefined} previous node
405      *
406      * @example
407      * const annotation = decl.prev();
408      * if ( annotation.type == 'comment' ) {
409      *  readAnnotation(annotation.text);
410      * }
411      */
412
413
414     Node.prototype.prev = function prev() {
415         var index = this.parent.index(this);
416         return this.parent.nodes[index - 1];
417     };
418
419     Node.prototype.toJSON = function toJSON() {
420         var fixed = {};
421
422         for (var name in this) {
423             if (!this.hasOwnProperty(name)) continue;
424             if (name === 'parent') continue;
425             var value = this[name];
426
427             if (value instanceof Array) {
428                 fixed[name] = value.map(function (i) {
429                     if ((typeof i === 'undefined' ? 'undefined' : _typeof(i)) === 'object' && i.toJSON) {
430                         return i.toJSON();
431                     } else {
432                         return i;
433                     }
434                 });
435             } else if ((typeof value === 'undefined' ? 'undefined' : _typeof(value)) === 'object' && value.toJSON) {
436                 fixed[name] = value.toJSON();
437             } else {
438                 fixed[name] = value;
439             }
440         }
441
442         return fixed;
443     };
444
445     /**
446      * Returns a {@link Node#raws} value. If the node is missing
447      * the code style property (because the node was manually built or cloned),
448      * PostCSS will try to autodetect the code style property by looking
449      * at other nodes in the tree.
450      *
451      * @param {string} prop          - name of code style property
452      * @param {string} [defaultType] - name of default value, it can be missed
453      *                                 if the value is the same as prop
454      *
455      * @example
456      * const root = postcss.parse('a { background: white }');
457      * root.nodes[0].append({ prop: 'color', value: 'black' });
458      * root.nodes[0].nodes[1].raws.before   //=> undefined
459      * root.nodes[0].nodes[1].raw('before') //=> ' '
460      *
461      * @return {string} code style value
462      */
463
464
465     Node.prototype.raw = function raw(prop, defaultType) {
466         var str = new _stringifier2.default();
467         return str.raw(this, prop, defaultType);
468     };
469
470     /**
471      * Finds the Root instance of the node’s tree.
472      *
473      * @example
474      * root.nodes[0].nodes[0].root() === root
475      *
476      * @return {Root} root parent
477      */
478
479
480     Node.prototype.root = function root() {
481         var result = this;
482         while (result.parent) {
483             result = result.parent;
484         }return result;
485     };
486
487     Node.prototype.cleanRaws = function cleanRaws(keepBetween) {
488         delete this.raws.before;
489         delete this.raws.after;
490         if (!keepBetween) delete this.raws.between;
491     };
492
493     Node.prototype.positionInside = function positionInside(index) {
494         var string = this.toString();
495         var column = this.source.start.column;
496         var line = this.source.start.line;
497
498         for (var i = 0; i < index; i++) {
499             if (string[i] === '\n') {
500                 column = 1;
501                 line += 1;
502             } else {
503                 column += 1;
504             }
505         }
506
507         return { line: line, column: column };
508     };
509
510     Node.prototype.positionBy = function positionBy(opts) {
511         var pos = this.source.start;
512         if (opts.index) {
513             pos = this.positionInside(opts.index);
514         } else if (opts.word) {
515             var index = this.toString().indexOf(opts.word);
516             if (index !== -1) pos = this.positionInside(index);
517         }
518         return pos;
519     };
520
521     Node.prototype.removeSelf = function removeSelf() {
522         (0, _warnOnce2.default)('Node#removeSelf is deprecated. Use Node#remove.');
523         return this.remove();
524     };
525
526     Node.prototype.replace = function replace(nodes) {
527         (0, _warnOnce2.default)('Node#replace is deprecated. Use Node#replaceWith');
528         return this.replaceWith(nodes);
529     };
530
531     Node.prototype.style = function style(own, detect) {
532         (0, _warnOnce2.default)('Node#style() is deprecated. Use Node#raw()');
533         return this.raw(own, detect);
534     };
535
536     Node.prototype.cleanStyles = function cleanStyles(keepBetween) {
537         (0, _warnOnce2.default)('Node#cleanStyles() is deprecated. Use Node#cleanRaws()');
538         return this.cleanRaws(keepBetween);
539     };
540
541     _createClass(Node, [{
542         key: 'before',
543         get: function get() {
544             (0, _warnOnce2.default)('Node#before is deprecated. Use Node#raws.before');
545             return this.raws.before;
546         },
547         set: function set(val) {
548             (0, _warnOnce2.default)('Node#before is deprecated. Use Node#raws.before');
549             this.raws.before = val;
550         }
551     }, {
552         key: 'between',
553         get: function get() {
554             (0, _warnOnce2.default)('Node#between is deprecated. Use Node#raws.between');
555             return this.raws.between;
556         },
557         set: function set(val) {
558             (0, _warnOnce2.default)('Node#between is deprecated. Use Node#raws.between');
559             this.raws.between = val;
560         }
561
562         /**
563          * @memberof Node#
564          * @member {string} type - String representing the node’s type.
565          *                         Possible values are `root`, `atrule`, `rule`,
566          *                         `decl`, or `comment`.
567          *
568          * @example
569          * postcss.decl({ prop: 'color', value: 'black' }).type //=> 'decl'
570          */
571
572         /**
573          * @memberof Node#
574          * @member {Container} parent - the node’s parent node.
575          *
576          * @example
577          * root.nodes[0].parent == root;
578          */
579
580         /**
581          * @memberof Node#
582          * @member {source} source - the input source of the node
583          *
584          * The property is used in source map generation.
585          *
586          * If you create a node manually (e.g., with `postcss.decl()`),
587          * that node will not have a `source` property and will be absent
588          * from the source map. For this reason, the plugin developer should
589          * consider cloning nodes to create new ones (in which case the new node’s
590          * source will reference the original, cloned node) or setting
591          * the `source` property manually.
592          *
593          * ```js
594          * // Bad
595          * const prefixed = postcss.decl({
596          *   prop: '-moz-' + decl.prop,
597          *   value: decl.value
598          * });
599          *
600          * // Good
601          * const prefixed = decl.clone({ prop: '-moz-' + decl.prop });
602          * ```
603          *
604          * ```js
605          * if ( atrule.name == 'add-link' ) {
606          *   const rule = postcss.rule({ selector: 'a', source: atrule.source });
607          *   atrule.parent.insertBefore(atrule, rule);
608          * }
609          * ```
610          *
611          * @example
612          * decl.source.input.from //=> '/home/ai/a.sass'
613          * decl.source.start      //=> { line: 10, column: 2 }
614          * decl.source.end        //=> { line: 10, column: 12 }
615          */
616
617         /**
618          * @memberof Node#
619          * @member {object} raws - Information to generate byte-to-byte equal
620          *                         node string as it was in the origin input.
621          *
622          * Every parser saves its own properties,
623          * but the default CSS parser uses:
624          *
625          * * `before`: the space symbols before the node. It also stores `*`
626          *   and `_` symbols before the declaration (IE hack).
627          * * `after`: the space symbols after the last child of the node
628          *   to the end of the node.
629          * * `between`: the symbols between the property and value
630          *   for declarations, selector and `{` for rules, or last parameter
631          *   and `{` for at-rules.
632          * * `semicolon`: contains true if the last child has
633          *   an (optional) semicolon.
634          * * `afterName`: the space between the at-rule name and its parameters.
635          * * `left`: the space symbols between `/*` and the comment’s text.
636          * * `right`: the space symbols between the comment’s text
637          *   and <code>*&#47;</code>.
638          * * `important`: the content of the important statement,
639          *   if it is not just `!important`.
640          *
641          * PostCSS cleans selectors, declaration values and at-rule parameters
642          * from comments and extra spaces, but it stores origin content in raws
643          * properties. As such, if you don’t change a declaration’s value,
644          * PostCSS will use the raw value with comments.
645          *
646          * @example
647          * const root = postcss.parse('a {\n  color:black\n}')
648          * root.first.first.raws //=> { before: '\n  ', between: ':' }
649          */
650
651     }]);
652
653     return Node;
654 }();
655
656 exports.default = Node;
657
658 /**
659  * @typedef {object} position
660  * @property {number} line   - source line in file
661  * @property {number} column - source column in file
662  */
663
664 /**
665  * @typedef {object} source
666  * @property {Input} input    - {@link Input} with input file
667  * @property {position} start - The starting position of the node’s source
668  * @property {position} end   - The ending position of the node’s source
669  */
670
671 module.exports = exports['default'];
672 //# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGUuZXM2Il0sIm5hbWVzIjpbImNsb25lTm9kZSIsIm9iaiIsInBhcmVudCIsImNsb25lZCIsImNvbnN0cnVjdG9yIiwiaSIsImhhc093blByb3BlcnR5IiwidmFsdWUiLCJ0eXBlIiwiQXJyYXkiLCJtYXAiLCJqIiwiTm9kZSIsImRlZmF1bHRzIiwicmF3cyIsIkVycm9yIiwiSlNPTiIsInN0cmluZ2lmeSIsIm5hbWUiLCJlcnJvciIsIm1lc3NhZ2UiLCJvcHRzIiwic291cmNlIiwicG9zIiwicG9zaXRpb25CeSIsImlucHV0IiwibGluZSIsImNvbHVtbiIsIndhcm4iLCJyZXN1bHQiLCJ0ZXh0IiwiZGF0YSIsIm5vZGUiLCJyZW1vdmUiLCJyZW1vdmVDaGlsZCIsInVuZGVmaW5lZCIsInRvU3RyaW5nIiwic3RyaW5naWZpZXIiLCJjbG9uZSIsIm92ZXJyaWRlcyIsImNsb25lQmVmb3JlIiwiaW5zZXJ0QmVmb3JlIiwiY2xvbmVBZnRlciIsImluc2VydEFmdGVyIiwicmVwbGFjZVdpdGgiLCJub2RlcyIsIm1vdmVUbyIsIm5ld1BhcmVudCIsImNsZWFuUmF3cyIsInJvb3QiLCJhcHBlbmQiLCJtb3ZlQmVmb3JlIiwib3RoZXJOb2RlIiwibW92ZUFmdGVyIiwibmV4dCIsImluZGV4IiwicHJldiIsInRvSlNPTiIsImZpeGVkIiwicmF3IiwicHJvcCIsImRlZmF1bHRUeXBlIiwic3RyIiwia2VlcEJldHdlZW4iLCJiZWZvcmUiLCJhZnRlciIsImJldHdlZW4iLCJwb3NpdGlvbkluc2lkZSIsInN0cmluZyIsInN0YXJ0Iiwid29yZCIsImluZGV4T2YiLCJyZW1vdmVTZWxmIiwicmVwbGFjZSIsInN0eWxlIiwib3duIiwiZGV0ZWN0IiwiY2xlYW5TdHlsZXMiLCJ2YWwiXSwibWFwcGluZ3MiOiI7Ozs7Ozs7O0FBQUE7Ozs7QUFDQTs7OztBQUNBOzs7O0FBQ0E7Ozs7Ozs7O0FBRUEsSUFBSUEsWUFBWSxTQUFaQSxTQUFZLENBQVVDLEdBQVYsRUFBZUMsTUFB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Ozs7Ozs7OztBQVFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBcUNBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7a0JBb0NXbEUsSTs7QUFFZjs7Ozs7O0FBTUEiLCJmaWxlIjoibm9kZS5qcyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBDc3NTeW50YXhFcnJvciBmcm9tICcuL2Nzcy1zeW50YXgtZXJyb3InO1xuaW1wb3J0IFN0cmluZ2lmaWVyICAgIGZyb20gJy4vc3RyaW5naWZpZXInO1xuaW1wb3J0IHN0cmluZ2lmeSAgICAgIGZyb20gJy4vc3RyaW5naWZ5JztcbmltcG9ydCB3YXJuT25jZSAgICAgICBmcm9tICcuL3dhcm4tb25jZSc7XG5cbmxldCBjbG9uZU5vZGUgPSBmdW5jdGlvbiAob2JqLCBwYXJlbnQpIHtcbiAgICBsZXQgY2xvbmVkID0gbmV3IG9iai5jb25zdHJ1Y3RvcigpO1xuXG4gICAgZm9yICggbGV0IGkgaW4gb2JqICkge1xuICAgICAgICBpZiAoICFvYmouaGFzT3duUHJvcGVydHkoaSkgKSBjb250aW51ZTtcbiAgICAgICAgbGV0IHZhbHVlID0gb2JqW2ldO1xuICAgICAgICBsZXQgdHlwZSAgPSB0eXBlb2YgdmFsdWU7XG5cbiAgICAgICAgaWYgKCBpID09PSAncGFyZW50JyAmJiB0eXBlID09PSAnb2JqZWN0JyApIHtcbiAgICAgICAgICAgIGlmIChwYXJlbnQpIGNsb25lZFtpXSA9IHBhcmVudDtcbiAgICAgICAgfSBlbHNlIGlmICggaSA9PT0gJ3NvdXJjZScgKSB7XG4gICAgICAgICAgICBjbG9uZWRbaV0gPSB2YWx1ZTtcbiAgICAgICAgfSBlbHNlIGlmICggdmFsdWUgaW5zdGFuY2VvZiBBcnJheSApIHtcbiAgICAgICAgICAgIGNsb25lZFtpXSA9IHZhbHVlLm1hcCggaiA9PiBjbG9uZU5vZGUoaiwgY2xvbmVkKSApO1xuICAgICAgICB9IGVsc2UgaWYgKCBpICE9PSAnYmVmb3JlJyAgJiYgaSAhPT0gJ2FmdGVyJyAmJlxuICAgICAgICAgICAgICAgICAgICBpICE9PSAnYmV0d2VlbicgJiYgaSAhPT0gJ3NlbWljb2xvbicgKSB7XG4gICAgICAgICAgICBpZiAoIHR5cGUgPT09ICdvYmplY3QnICYmIHZhbHVlICE9PSBudWxsICkgdmFsdWUgPSBjbG9uZU5vZGUodmFsdWUpO1xuICAgICAgICAgICAgY2xvbmVkW2ldID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gY2xvbmVkO1xufTtcblxuLyoqXG4gKiBBbGwgbm9kZSBjbGFzc2VzIGluaGVyaXQgdGhlIGZvbGxvd2luZyBjb21tb24gbWV0aG9kcy5cbiAqXG4gKiBAYWJzdHJhY3RcbiAqL1xuY2xhc3MgTm9kZSB7XG5cbiAgICAvKipcbiAgICAgKiBAcGFyYW0ge29iamVjdH0gW2RlZmF1bHRzXSAtIHZhbHVlIGZvciBub2RlIHByb3BlcnRpZXNcbiAgICAgKi9cbiAgICBjb25zdHJ1Y3RvcihkZWZhdWx0cyA9IHsgfSkge1xuICAgICAgICB0aGlzLnJhd3MgPSB7IH07XG4gICAgICAgIGlmICggdHlwZW9mIGRlZmF1bHRzICE9PSAnb2JqZWN0JyAmJiB0eXBlb2YgZGVmYXVsdHMgIT09ICd1bmRlZmluZWQnICkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICAgICAgICdQb3N0Q1NTIG5vZGVzIGNvbnN0cnVjdG9yIGFjY2VwdHMgb2JqZWN0LCBub3QgJyArXG4gICAgICAgICAgICAgICAgSlNPTi5zdHJpbmdpZnkoZGVmYXVsdHMpKTtcbiAgICAgICAgfVxuICAgICAgICBmb3IgKCBsZXQgbmFtZSBpbiBkZWZhdWx0cyApIHtcbiAgICAgICAgICAgIHRoaXNbbmFtZV0gPSBkZWZhdWx0c1tuYW1lXTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgYSBDc3NTeW50YXhFcnJvciBpbnN0YW5jZSBjb250YWluaW5nIHRoZSBvcmlnaW5hbCBwb3NpdGlvblxuICAgICAqIG9mIHRoZSBub2RlIGluIHRoZSBzb3VyY2UsIHNob3dpbmcgbGluZSBhbmQgY29sdW1uIG51bWJlcnMgYW5kIGFsc29cbiAgICAgKiBhIHNtYWxsIGV4Y2VycHQgdG8gZmFjaWxpdGF0ZSBkZWJ1Z2dpbmcuXG4gICAgICpcbiAgICAgKiBJZiBwcmVzZW50LCBhbiBpbnB1dCBzb3VyY2UgbWFwIHdpbGwgYmUgdXNlZCB0byBnZXQgdGhlIG9yaWdpbmFsIHBvc2l0aW9uXG4gICAgICogb2YgdGhlIHNvdXJjZSwgZXZlbiBmcm9tIGEgcHJldmlvdXMgY29tcGlsYXRpb24gc3RlcFxuICAgICAqIChlLmcuLCBmcm9tIFNhc3MgY29tcGlsYXRpb24pLlxuICAgICAqXG4gICAgICogVGhpcyBtZXRob2QgcHJvZHVjZXMgdmVyeSB1c2VmdWwgZXJyb3IgbWVzc2FnZXMuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gbWVzc2FnZSAgICAgLSBlcnJvciBkZXNjcmlwdGlvblxuICAgICAqIEBwYXJhbSB7b2JqZWN0fSBbb3B0c10gICAgICAtIG9wdGlvbnNcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gb3B0cy5wbHVnaW4gLSBwbHVnaW4gbmFtZSB0aGF0IGNyZWF0ZWQgdGhpcyBlcnJvci5cbiAgICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBQb3N0Q1NTIHdpbGwgc2V0IGl0IGF1dG9tYXRpY2FsbHkuXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IG9wdHMud29yZCAgIC0gYSB3b3JkIGluc2lkZSBhIG5vZGXigJlzIHN0cmluZyB0aGF0IHNob3VsZFxuICAgICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJlIGhpZ2hsaWdodGVkIGFzIHRoZSBzb3VyY2Ugb2YgdGhlIGVycm9yXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IG9wdHMuaW5kZXggIC0gYW4gaW5kZXggaW5zaWRlIGEgbm9kZeKAmXMgc3RyaW5nIHRoYXQgc2hvdWxkXG4gICAgICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmUgaGlnaGxpZ2h0ZWQgYXMgdGhlIHNvdXJjZSBvZiB0aGUgZXJyb3JcbiAgICAgKlxuICAgICAqIEByZXR1cm4ge0Nzc1N5bnRheEVycm9yfSBlcnJvciBvYmplY3QgdG8gdGhyb3cgaXRcbiAgICAgKlxuICAgICAqIEBleGFtcGxlXG4gICAgICogaWYgKCAhdmFyaWFibGVzW25hbWVdICkge1xuICAgICAqICAgdGhyb3cgZGVjbC5lcnJvcignVW5rbm93biB2YXJpYWJsZSAnICsgbmFtZSwgeyB3b3JkOiBuYW1lIH0pO1xuICAgICAqICAgLy8gQ3NzU3ludGF4RXJyb3I6IHBvc3Rjc3MtdmFyczphLnNhc3M6NDozOiBVbmtub3duIHZhcmlhYmxlICRibGFja1xuICAgICAqICAgLy8gICBjb2xvcjogJGJsYWNrXG4gICAgICogICAvLyBhXG4gICAgICogICAvLyAgICAgICAgICBeXG4gICAgICogICAvLyAgIGJhY2tncm91bmQ6IHdoaXRlXG4gICAgICogfVxuICAgICAqL1xuICAgIGVycm9yKG1lc3NhZ2UsIG9wdHMgPSB7IH0pIHtcbiAgICAgICAgaWYgKCB0aGlzLnNvdXJjZSApIHtcbiAgICAgICAgICAgIGxldCBwb3MgPSB0aGlzLnBvc2l0aW9uQnkob3B0cyk7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5zb3VyY2UuaW5wdXQuZXJyb3IobWVzc2FnZSwgcG9zLmxpbmUsIHBvcy5jb2x1bW4sIG9wdHMpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIG5ldyBDc3NTeW50YXhFcnJvcihtZXNzYWdlKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFRoaXMgbWV0aG9kIGlzIHByb3ZpZGVkIGFzIGEgY29udmVuaWVuY2Ugd3JhcHBlciBmb3Ige0BsaW5rIFJlc3VsdCN3YXJufS5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7UmVzdWx0fSByZXN1bHQgICAgICAtIHRoZSB7QGxpbmsgUmVzdWx0fSBpbnN0YW5jZVxuICAgICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoYXQgd2lsbCByZWNlaXZlIHRoZSB3YXJuaW5nXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IHRleHQgICAgICAgIC0gd2FybmluZyBtZXNzYWdlXG4gICAgICogQHBhcmFtIHtvYmplY3R9IFtvcHRzXSAgICAgIC0gb3B0aW9uc1xuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBvcHRzLnBsdWdpbiAtIHBsdWdpbiBuYW1lIHRoYXQgY3JlYXRlZCB0aGlzIHdhcm5pbmcuXG4gICAgICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUG9zdENTUyB3aWxsIHNldCBpdCBhdXRvbWF0aWNhbGx5LlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBvcHRzLndvcmQgICAtIGEgd29yZCBpbnNpZGUgYSBub2Rl4oCZcyBzdHJpbmcgdGhhdCBzaG91bGRcbiAgICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiZSBoaWdobGlnaHRlZCBhcyB0aGUgc291cmNlIG9mIHRoZSB3YXJuaW5nXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IG9wdHMuaW5kZXggIC0gYW4gaW5kZXggaW5zaWRlIGEgbm9kZeKAmXMgc3RyaW5nIHRoYXQgc2hvdWxkXG4gICAgICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmUgaGlnaGxpZ2h0ZWQgYXMgdGhlIHNvdXJjZSBvZiB0aGUgd2FybmluZ1xuICAgICAqXG4gICAgICogQHJldHVybiB7V2FybmluZ30gY3JlYXRlZCB3YXJuaW5nIG9iamVjdFxuICAgICAqXG4gICAgICogQGV4YW1wbGVcbiAgICAgKiBjb25zdCBwbHVnaW4gPSBwb3N0Y3NzLnBsdWdpbigncG9zdGNzcy1kZXByZWNhdGVkJywgKCkgPT4ge1xuICAgICAqICAgcmV0dXJuIChyb290LCByZXN1bHQpID0+IHtcbiAgICAgKiAgICAgcm9vdC53YWxrRGVjbHMoJ2JhZCcsIGRlY2wgPT4ge1xuICAgICAqICAgICAgIGRlY2wud2FybihyZXN1bHQsICdEZXByZWNhdGVkIHByb3BlcnR5IGJhZCcpO1xuICAgICAqICAgICB9KTtcbiAgICAgKiAgIH07XG4gICAgICogfSk7XG4gICAgICovXG4gICAgd2FybihyZXN1bHQsIHRleHQsIG9wdHMpIHtcbiAgICAgICAgbGV0IGRhdGEgPSB7IG5vZGU6IHRoaXMgfTtcbiAgICAgICAgZm9yICggbGV0IGkgaW4gb3B0cyApIGRhdGFbaV0gPSBvcHRzW2ldO1xuICAgICAgICByZXR1cm4gcmVzdWx0Lndhcm4odGV4dCwgZGF0YSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmVtb3ZlcyB0aGUgbm9kZSBmcm9tIGl0cyBwYXJlbnQgYW5kIGNsZWFucyB0aGUgcGFyZW50IHByb3BlcnRpZXNcbiAgICAgKiBmcm9tIHRoZSBub2RlIGFuZCBpdHMgY2hpbGRyZW4uXG4gICAgICpcbiAgICAgKiBAZXhhbXBsZVxuICAgICAqIGlmICggZGVjbC5wcm9wLm1hdGNoKC9eLXdlYmtpdC0vKSApIHtcbiAgICAgKiAgIGRlY2wucmVtb3ZlKCk7XG4gICAgICogfVxuICAgICAqXG4gICAgICogQHJldHVybiB7Tm9kZX0gbm9kZSB0byBtYWtlIGNhbGxzIGNoYWluXG4gICAgICovXG4gICAgcmVtb3ZlKCkge1xuICAgICAgICBpZiAoIHRoaXMucGFyZW50ICkge1xuICAgICAgICAgICAgdGhpcy5wYXJlbnQucmVtb3ZlQ2hpbGQodGhpcyk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5wYXJlbnQgPSB1bmRlZmluZWQ7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgYSBDU1Mgc3RyaW5nIHJlcHJlc2VudGluZyB0aGUgbm9kZS5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5naWZpZXJ8c3ludGF4fSBbc3RyaW5naWZpZXJdIC0gYSBzeW50YXggdG8gdXNlXG4gICAgICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbiBzdHJpbmcgZ2VuZXJhdGlvblxuICAgICAqXG4gICAgICogQHJldHVybiB7c3RyaW5nfSBDU1Mgc3RyaW5nIG9mIHRoaXMgbm9kZVxuICAgICAqXG4gICAgICogQGV4YW1wbGVcbiAgICAgKiBwb3N0Y3NzLnJ1bGUoeyBzZWxlY3RvcjogJ2EnIH0pLnRvU3RyaW5nKCkgLy89PiBcImEge31cIlxuICAgICAqL1xuICAgIHRvU3RyaW5nKHN0cmluZ2lmaWVyID0gc3RyaW5naWZ5KSB7XG4gICAgICAgIGlmICggc3RyaW5naWZpZXIuc3RyaW5naWZ5ICkgc3RyaW5naWZpZXIgPSBzdHJpbmdpZmllci5zdHJpbmdpZnk7XG4gICAgICAgIGxldCByZXN1bHQgID0gJyc7XG4gICAgICAgIHN0cmluZ2lmaWVyKHRoaXMsIGkgPT4ge1xuICAgICAgICAgICAgcmVzdWx0ICs9IGk7XG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgYSBjbG9uZSBvZiB0aGUgbm9kZS5cbiAgICAgKlxuICAgICAqIFRoZSByZXN1bHRpbmcgY2xvbmVkIG5vZGUgYW5kIGl0cyAoY2xvbmVkKSBjaGlsZHJlbiB3aWxsIGhhdmVcbiAgICAgKiBhIGNsZWFuIHBhcmVudCBhbmQgY29kZSBzdHlsZSBwcm9wZXJ0aWVzLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtvYmplY3R9IFtvdmVycmlkZXNdIC0gbmV3IHByb3BlcnRpZXMgdG8gb3ZlcnJpZGUgaW4gdGhlIGNsb25lLlxuICAgICAqXG4gICAgICogQGV4YW1wbGVcbiAgICAgKiBjb25zdCBjbG9uZWQgPSBkZWNsLmNsb25lKHsgcHJvcDogJy1tb3otJyArIGRlY2wucHJvcCB9KTtcbiAgICAgKiBjbG9uZWQucmF3cy5iZWZvcmUgIC8vPT4gdW5kZWZpbmVkXG4gICAgICogY2xvbmVkLnBhcmVudCAgICAgICAvLz0+IHVuZGVmaW5lZFxuICAgICAqIGNsb25lZC50b1N0cmluZygpICAgLy89PiAtbW96LXRyYW5zZm9ybTogc2NhbGUoMClcbiAgICAgKlxuICAgICAqIEByZXR1cm4ge05vZGV9IGNsb25lIG9mIHRoZSBub2RlXG4gICAgICovXG4gICAgY2xvbmUob3ZlcnJpZGVzID0geyB9KSB7XG4gICAgICAgIGxldCBjbG9uZWQgPSBjbG9uZU5vZGUodGhpcyk7XG4gICAgICAgIGZvciAoIGxldCBuYW1lIGluIG92ZXJyaWRlcyApIHtcbiAgICAgICAgICAgIGNsb25lZFtuYW1lXSA9IG92ZXJyaWRlc1tuYW1lXTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gY2xvbmVkO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNob3J0Y3V0IHRvIGNsb25lIHRoZSBub2RlIGFuZCBpbnNlcnQgdGhlIHJlc3VsdGluZyBjbG9uZWQgbm9kZVxuICAgICAqIGJlZm9yZSB0aGUgY3VycmVudCBub2RlLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtvYmplY3R9IFtvdmVycmlkZXNdIC0gbmV3IHByb3BlcnRpZXMgdG8gb3ZlcnJpZGUgaW4gdGhlIGNsb25lLlxuICAgICAqXG4gICAgICogQGV4YW1wbGVcbiAgICAgKiBkZWNsLmNsb25lQmVmb3JlKHsgcHJvcDogJy1tb3otJyArIGRlY2wucHJvcCB9KTtcbiAgICAgKlxuICAgICAqIEByZXR1cm4ge05vZGV9IC0gbmV3IG5vZGVcbiAgICAgKi9cbiAgICBjbG9uZUJlZm9yZShvdmVycmlkZXMgPSB7IH0pIHtcbiAgICAgICAgbGV0IGNsb25lZCA9IHRoaXMuY2xvbmUob3ZlcnJpZGVzKTtcbiAgICAgICAgdGhpcy5wYXJlbnQuaW5zZXJ0QmVmb3JlKHRoaXMsIGNsb25lZCk7XG4gICAgICAgIHJldHVybiBjbG9uZWQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2hvcnRjdXQgdG8gY2xvbmUgdGhlIG5vZGUgYW5kIGluc2VydCB0aGUgcmVzdWx0aW5nIGNsb25lZCBub2RlXG4gICAgICogYWZ0ZXIgdGhlIGN1cnJlbnQgbm9kZS5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7b2JqZWN0fSBbb3ZlcnJpZGVzXSAtIG5ldyBwcm9wZXJ0aWVzIHRvIG92ZXJyaWRlIGluIHRoZSBjbG9uZS5cbiAgICAgKlxuICAgICAqIEByZXR1cm4ge05vZGV9IC0gbmV3IG5vZGVcbiAgICAgKi9cbiAgICBjbG9uZUFmdGVyKG92ZXJyaWRlcyA9IHsgfSkge1xuICAgICAgICBsZXQgY2xvbmVkID0gdGhpcy5jbG9uZShvdmVycmlkZXMpO1xuICAgICAgICB0aGlzLnBhcmVudC5pbnNlcnRBZnRlcih0aGlzLCBjbG9uZWQpO1xuICAgICAgICByZXR1cm4gY2xvbmVkO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEluc2VydHMgbm9kZShzKSBiZWZvcmUgdGhlIGN1cnJlbnQgbm9kZSBhbmQgcmVtb3ZlcyB0aGUgY3VycmVudCBub2RlLlxuICAgICAqXG4gICAgICogQHBhcmFtIHsuLi5Ob2RlfSBub2RlcyAtIG5vZGUocykgdG8gcmVwbGFjZSBjdXJyZW50IG9uZVxuICAgICAqXG4gICAgICogQGV4YW1wbGVcbiAgICAgKiBpZiAoIGF0cnVsZS5uYW1lID09ICdtaXhpbicgKSB7XG4gICAgICogICBhdHJ1bGUucmVwbGFjZVdpdGgobWl4aW5SdWxlc1thdHJ1bGUucGFyYW1zXSk7XG4gICAgICogfVxuICAgICAqXG4gICAgICogQHJldHVybiB7Tm9kZX0gY3VycmVudCBub2RlIHRvIG1ldGhvZHMgY2hhaW5cbiAgICAgKi9cbiAgICByZXBsYWNlV2l0aCguLi5ub2Rlcykge1xuICAgICAgICBpZiAodGhpcy5wYXJlbnQpIHtcbiAgICAgICAgICAgIGZvciAobGV0IG5vZGUgb2Ygbm9kZXMpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnBhcmVudC5pbnNlcnRCZWZvcmUodGhpcywgbm9kZSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHRoaXMucmVtb3ZlKCk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZW1vdmVzIHRoZSBub2RlIGZyb20gaXRzIGN1cnJlbnQgcGFyZW50IGFuZCBpbnNlcnRzIGl0XG4gICAgICogYXQgdGhlIGVuZCBvZiBgbmV3UGFyZW50YC5cbiAgICAgKlxuICAgICAqIFRoaXMgd2lsbCBjbGVhbiB0aGUgYGJlZm9yZWAgYW5kIGBhZnRlcmAgY29kZSB7QGxpbmsgTm9kZSNyYXdzfSBkYXRhXG4gICAgICogZnJvbSB0aGUgbm9kZSBhbmQgcmVwbGFjZSB0aGVtIHdpdGggdGhlIGluZGVudGF0aW9uIHN0eWxlIG9mIGBuZXdQYXJlbnRgLlxuICAgICAqIEl0IHdpbGwgYWxzbyBjbGVhbiB0aGUgYGJldHdlZW5gIHByb3BlcnR5XG4gICAgICogaWYgYG5ld1BhcmVudGAgaXMgaW4gYW5vdGhlciB7QGxpbmsgUm9vdH0uXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge0NvbnRhaW5lcn0gbmV3UGFyZW50IC0gY29udGFpbmVyIG5vZGUgd2hlcmUgdGhlIGN1cnJlbnQgbm9kZVxuICAgICAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aWxsIGJlIG1vdmVkXG4gICAgICpcbiAgICAgKiBAZXhhbXBsZVxuICAgICAqIGF0cnVsZS5tb3ZlVG8oYXRydWxlLnJvb3QoKSk7XG4gICAgICpcbiAgICAgKiBAcmV0dXJuIHtOb2RlfSBjdXJyZW50IG5vZGUgdG8gbWV0aG9kcyBjaGFpblxuICAgICAqL1xuICAgIG1vdmVUbyhuZXdQYXJlbnQpIHtcbiAgICAgICAgdGhpcy5jbGVhblJhd3ModGhpcy5yb290KCkgPT09IG5ld1BhcmVudC5yb290KCkpO1xuICAgICAgICB0aGlzLnJlbW92ZSgpO1xuICAgICAgICBuZXdQYXJlbnQuYXBwZW5kKHRoaXMpO1xuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZW1vdmVzIHRoZSBub2RlIGZyb20gaXRzIGN1cnJlbnQgcGFyZW50IGFuZCBpbnNlcnRzIGl0IGludG9cbiAgICAgKiBhIG5ldyBwYXJlbnQgYmVmb3JlIGBvdGhlck5vZGVgLlxuICAgICAqXG4gICAgICogVGhpcyB3aWxsIGFsc28gY2xlYW4gdGhlIG5vZGXigJlzIGNvZGUgc3R5bGUgcHJvcGVydGllcyBqdXN0IGFzIGl0IHdvdWxkXG4gICAgICogaW4ge0BsaW5rIE5vZGUjbW92ZVRvfS5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7Tm9kZX0gb3RoZXJOb2RlIC0gbm9kZSB0aGF0IHdpbGwgYmUgYmVmb3JlIGN1cnJlbnQgbm9kZVxuICAgICAqXG4gICAgICogQHJldHVybiB7Tm9kZX0gY3VycmVudCBub2RlIHRvIG1ldGhvZHMgY2hhaW5cbiAgICAgKi9cbiAgICBtb3ZlQmVmb3JlKG90aGVyTm9kZSkge1xuICAgICAgICB0aGlzLmNsZWFuUmF3cyh0aGlzLnJvb3QoKSA9PT0gb3RoZXJOb2RlLnJvb3QoKSk7XG4gICAgICAgIHRoaXMucmVtb3ZlKCk7XG4gICAgICAgIG90aGVyTm9kZS5wYXJlbnQuaW5zZXJ0QmVmb3JlKG90aGVyTm9kZSwgdGhpcyk7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJlbW92ZXMgdGhlIG5vZGUgZnJvbSBpdHMgY3VycmVudCBwYXJlbnQgYW5kIGluc2VydHMgaXQgaW50b1xuICAgICAqIGEgbmV3IHBhcmVudCBhZnRlciBgb3RoZXJOb2RlYC5cbiAgICAgKlxuICAgICAqIFRoaXMgd2lsbCBhbHNvIGNsZWFuIHRoZSBub2Rl4oCZcyBjb2RlIHN0eWxlIHByb3BlcnRpZXMganVzdCBhcyBpdCB3b3VsZFxuICAgICAqIGluIHtAbGluayBOb2RlI21vdmVUb30uXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge05vZGV9IG90aGVyTm9kZSAtIG5vZGUgdGhhdCB3aWxsIGJlIGFmdGVyIGN1cnJlbnQgbm9kZVxuICAgICAqXG4gICAgICogQHJldHVybiB7Tm9kZX0gY3VycmVudCBub2RlIHRvIG1ldGhvZHMgY2hhaW5cbiAgICAgKi9cbiAgICBtb3ZlQWZ0ZXIob3RoZXJOb2RlKSB7XG4gICAgICAgIHRoaXMuY2xlYW5SYXdzKHRoaXMucm9vdCgpID09PSBvdGhlck5vZGUucm9vdCgpKTtcbiAgICAgICAgdGhpcy5yZW1vdmUoKTtcbiAgICAgICAgb3RoZXJOb2RlLnBhcmVudC5pbnNlcnRBZnRlcihvdGhlck5vZGUsIHRoaXMpO1xuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRoZSBuZXh0IGNoaWxkIG9mIHRoZSBub2Rl4oCZcyBwYXJlbnQuXG4gICAgICogUmV0dXJucyBgdW5kZWZpbmVkYCBpZiB0aGUgY3VycmVudCBub2RlIGlzIHRoZSBsYXN0IGNoaWxkLlxuICAgICAqXG4gICAgICogQHJldHVybiB7Tm9kZXx1bmRlZmluZWR9IG5leHQgbm9kZVxuICAgICAqXG4gICAgICogQGV4YW1wbGVcbiAgICAgKiBpZiAoIGNvbW1lbnQudGV4dCA9PT0gJ2RlbGV0ZSBuZXh0JyApIHtcbiAgICAgKiAgIGNvbnN0IG5leHQgPSBjb21tZW50Lm5leHQoKTtcbiAgICAgKiAgIGlmICggbmV4dCApIHtcbiAgICAgKiAgICAgbmV4dC5yZW1vdmUoKTtcbiAgICAgKiAgIH1cbiAgICAgKiB9XG4gICAgICovXG4gICAgbmV4dCgpIHtcbiAgICAgICAgbGV0IGluZGV4ID0gdGhpcy5wYXJlbnQuaW5kZXgodGhpcyk7XG4gICAgICAgIHJldHVybiB0aGlzLnBhcmVudC5ub2Rlc1tpbmRleCArIDFdO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIHByZXZpb3VzIGNoaWxkIG9mIHRoZSBub2Rl4oCZcyBwYXJlbnQuXG4gICAgICogUmV0dXJucyBgdW5kZWZpbmVkYCBpZiB0aGUgY3VycmVudCBub2RlIGlzIHRoZSBmaXJzdCBjaGlsZC5cbiAgICAgKlxuICAgICAqIEByZXR1cm4ge05vZGV8dW5kZWZpbmVkfSBwcmV2aW91cyBub2RlXG4gICAgICpcbiAgICAgKiBAZXhhbXBsZVxuICAgICAqIGNvbnN0IGFubm90YXRpb24gPSBkZWNsLnByZXYoKTtcbiAgICAgKiBpZiAoIGFubm90YXRpb24udHlwZSA9PSAnY29tbWVudCcgKSB7XG4gICAgICogIHJlYWRBbm5vdGF0aW9uKGFubm90YXRpb24udGV4dCk7XG4gICAgICogfVxuICAgICAqL1xuICAgIHByZXYoKSB7XG4gICAgICAgIGxldCBpbmRleCA9IHRoaXMucGFyZW50LmluZGV4KHRoaXMpO1xuICAgICAgICByZXR1cm4gdGhpcy5wYXJlbnQubm9kZXNbaW5kZXggLSAxXTtcbiAgICB9XG5cbiAgICB0b0pTT04oKSB7XG4gICAgICAgIGxldCBmaXhlZCA9IHsgfTtcblxuICAgICAgICBmb3IgKCBsZXQgbmFtZSBpbiB0aGlzICkge1xuICAgICAgICAgICAgaWYgKCAhdGhpcy5oYXNPd25Qcm9wZXJ0eShuYW1lKSApIGNvbnRpbnVlO1xuICAgICAgICAgICAgaWYgKCBuYW1lID09PSAncGFyZW50JyApIGNvbnRpbnVlO1xuICAgICAgICAgICAgbGV0IHZhbHVlID0gdGhpc1tuYW1lXTtcblxuICAgICAgICAgICAgaWYgKCB2YWx1ZSBpbnN0YW5jZW9mIEFycmF5ICkge1xuICAgICAgICAgICAgICAgIGZpeGVkW25hbWVdID0gdmFsdWUubWFwKCBpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCB0eXBlb2YgaSA9PT0gJ29iamVjdCcgJiYgaS50b0pTT04gKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gaS50b0pTT04oKTtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKCB0eXBlb2YgdmFsdWUgPT09ICdvYmplY3QnICYmIHZhbHVlLnRvSlNPTiApIHtcbiAgICAgICAgICAgICAgICBmaXhlZFtuYW1lXSA9IHZhbHVlLnRvSlNPTigpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBmaXhlZFtuYW1lXSA9IHZhbHVlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGZpeGVkO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgYSB7QGxpbmsgTm9kZSNyYXdzfSB2YWx1ZS4gSWYgdGhlIG5vZGUgaXMgbWlzc2luZ1xuICAgICAqIHRoZSBjb2RlIHN0eWxlIHByb3BlcnR5IChiZWNhdXNlIHRoZSBub2RlIHdhcyBtYW51YWxseSBidWlsdCBvciBjbG9uZWQpLFxuICAgICAqIFBvc3RDU1Mgd2lsbCB0cnkgdG8gYXV0b2RldGVjdCB0aGUgY29kZSBzdHlsZSBwcm9wZXJ0eSBieSBsb29raW5nXG4gICAgICogYXQgb3RoZXIgbm9kZXMgaW4gdGhlIHRyZWUuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gcHJvcCAgICAgICAgICAtIG5hbWUgb2YgY29kZSBzdHlsZSBwcm9wZXJ0eVxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBbZGVmYXVsdFR5cGVdIC0gbmFtZSBvZiBkZWZhdWx0IHZhbHVlLCBpdCBjYW4gYmUgbWlzc2VkXG4gICAgICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiB0aGUgdmFsdWUgaXMgdGhlIHNhbWUgYXMgcHJvcFxuICAgICAqXG4gICAgICogQGV4YW1wbGVcbiAgICAgKiBjb25zdCByb290ID0gcG9zdGNzcy5wYXJzZSgnYSB7IGJhY2tncm91bmQ6IHdoaXRlIH0nKTtcbiAgICAgKiByb290Lm5vZGVzWzBdLmFwcGVuZCh7IHByb3A6ICdjb2xvcicsIHZhbHVlOiAnYmxhY2snIH0pO1xuICAgICAqIHJvb3Qubm9kZXNbMF0ubm9kZXNbMV0ucmF3cy5iZWZvcmUgICAvLz0+IHVuZGVmaW5lZFxuICAgICAqIHJvb3Qubm9kZXNbMF0ubm9kZXNbMV0ucmF3KCdiZWZvcmUnKSAvLz0+ICcgJ1xuICAgICAqXG4gICAgICogQHJldHVybiB7c3RyaW5nfSBjb2RlIHN0eWxlIHZhbHVlXG4gICAgICovXG4gICAgcmF3KHByb3AsIGRlZmF1bHRUeXBlKSB7XG4gICAgICAgIGxldCBzdHIgPSBuZXcgU3RyaW5naWZpZXIoKTtcbiAgICAgICAgcmV0dXJuIHN0ci5yYXcodGhpcywgcHJvcCwgZGVmYXVsdFR5cGUpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEZpbmRzIHRoZSBSb290IGluc3RhbmNlIG9mIHRoZSBub2Rl4oCZcyB0cmVlLlxuICAgICAqXG4gICAgICogQGV4YW1wbGVcbiAgICAgKiByb290Lm5vZGVzWzBdLm5vZGVzWzBdLnJvb3QoKSA9PT0gcm9vdFxuICAgICAqXG4gICAgICogQHJldHVybiB7Um9vdH0gcm9vdCBwYXJlbnRcbiAgICAgKi9cbiAgICByb290KCkge1xuICAgICAgICBsZXQgcmVzdWx0ID0gdGhpcztcbiAgICAgICAgd2hpbGUgKCByZXN1bHQucGFyZW50ICkgcmVzdWx0ID0gcmVzdWx0LnBhcmVudDtcbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9XG5cbiAgICBjbGVhblJhd3Moa2VlcEJldHdlZW4pIHtcbiAgICAgICAgZGVsZXRlIHRoaXMucmF3cy5iZWZvcmU7XG4gICAgICAgIGRlbGV0ZSB0aGlzLnJhd3MuYWZ0ZXI7XG4gICAgICAgIGlmICggIWtlZXBCZXR3ZWVuICkgZGVsZXRlIHRoaXMucmF3cy5iZXR3ZWVuO1xuICAgIH1cblxuICAgIHBvc2l0aW9uSW5zaWRlKGluZGV4KSB7XG4gICAgICAgIGxldCBzdHJpbmcgPSB0aGlzLnRvU3RyaW5nKCk7XG4gICAgICAgIGxldCBjb2x1bW4gPSB0aGlzLnNvdXJjZS5zdGFydC5jb2x1bW47XG4gICAgICAgIGxldCBsaW5lICAgPSB0aGlzLnNvdXJjZS5zdGFydC5saW5lO1xuXG4gICAgICAgIGZvciAoIGxldCBpID0gMDsgaSA8IGluZGV4OyBpKysgKSB7XG4gICAgICAgICAgICBpZiAoIHN0cmluZ1tpXSA9PT0gJ1xcbicgKSB7XG4gICAgICAgICAgICAgICAgY29sdW1uID0gMTtcbiAgICAgICAgICAgICAgICBsaW5lICArPSAxO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBjb2x1bW4gKz0gMTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB7IGxpbmUsIGNvbHVtbiB9O1xuICAgIH1cblxuICAgIHBvc2l0aW9uQnkob3B0cykge1xuICAgICAgICBsZXQgcG9zID0gdGhpcy5zb3VyY2Uuc3RhcnQ7XG4gICAgICAgIGlmICggb3B0cy5pbmRleCApIHtcbiAgICAgICAgICAgIHBvcyA9IHRoaXMucG9zaXRpb25JbnNpZGUob3B0cy5pbmRleCk7XG4gICAgICAgIH0gZWxzZSBpZiAoIG9wdHMud29yZCApIHtcbiAgICAgICAgICAgIGxldCBpbmRleCA9IHRoaXMudG9TdHJpbmcoKS5pbmRleE9mKG9wdHMud29yZCk7XG4gICAgICAgICAgICBpZiAoIGluZGV4ICE9PSAtMSApIHBvcyA9IHRoaXMucG9zaXRpb25JbnNpZGUoaW5kZXgpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBwb3M7XG4gICAgfVxuXG4gICAgcmVtb3ZlU2VsZigpIHtcbiAgICAgICAgd2Fybk9uY2UoJ05vZGUjcmVtb3ZlU2VsZiBpcyBkZXByZWNhdGVkLiBVc2UgTm9kZSNyZW1vdmUuJyk7XG4gICAgICAgIHJldHVybiB0aGlzLnJlbW92ZSgpO1xuICAgIH1cblxuICAgIHJlcGxhY2Uobm9kZXMpIHtcbiAgICAgICAgd2Fybk9uY2UoJ05vZGUjcmVwbGFjZSBpcyBkZXByZWNhdGVkLiBVc2UgTm9kZSNyZXBsYWNlV2l0aCcpO1xuICAgICAgICByZXR1cm4gdGhpcy5yZXBsYWNlV2l0aChub2Rlcyk7XG4gICAgfVxuXG4gICAgc3R5bGUob3duLCBkZXRlY3QpIHtcbiAgICAgICAgd2Fybk9uY2UoJ05vZGUjc3R5bGUoKSBpcyBkZXByZWNhdGVkLiBVc2UgTm9kZSNyYXcoKScpO1xuICAgICAgICByZXR1cm4gdGhpcy5yYXcob3duLCBkZXRlY3QpO1xuICAgIH1cblxuICAgIGNsZWFuU3R5bGVzKGtlZXBCZXR3ZWVuKSB7XG4gICAgICAgIHdhcm5PbmNlKCdOb2RlI2NsZWFuU3R5bGVzKCkgaXMgZGVwcmVjYXRlZC4gVXNlIE5vZGUjY2xlYW5SYXdzKCknKTtcbiAgICAgICAgcmV0dXJuIHRoaXMuY2xlYW5SYXdzKGtlZXBCZXR3ZWVuKTtcbiAgICB9XG5cbiAgICBnZXQgYmVmb3JlKCkge1xuICAgICAgICB3YXJuT25jZSgnTm9kZSNiZWZvcmUgaXMgZGVwcmVjYXRlZC4gVXNlIE5vZGUjcmF3cy5iZWZvcmUnKTtcbiAgICAgICAgcmV0dXJuIHRoaXMucmF3cy5iZWZvcmU7XG4gICAgfVxuXG4gICAgc2V0IGJlZm9yZSh2YWwpIHtcbiAgICAgICAgd2Fybk9uY2UoJ05vZGUjYmVmb3JlIGlzIGRlcHJlY2F0ZWQuIFVzZSBOb2RlI3Jhd3MuYmVmb3JlJyk7XG4gICAgICAgIHRoaXMucmF3cy5iZWZvcmUgPSB2YWw7XG4gICAgfVxuXG4gICAgZ2V0IGJldHdlZW4oKSB7XG4gICAgICAgIHdhcm5PbmNlKCdOb2RlI2JldHdlZW4gaXMgZGVwcmVjYXRlZC4gVXNlIE5vZGUjcmF3cy5iZXR3ZWVuJyk7XG4gICAgICAgIHJldHVybiB0aGlzLnJhd3MuYmV0d2VlbjtcbiAgICB9XG5cbiAgICBzZXQgYmV0d2Vlbih2YWwpIHtcbiAgICAgICAgd2Fybk9uY2UoJ05vZGUjYmV0d2VlbiBpcyBkZXByZWNhdGVkLiBVc2UgTm9kZSNyYXdzLmJldHdlZW4nKTtcbiAgICAgICAgdGhpcy5yYXdzLmJldHdlZW4gPSB2YWw7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQG1lbWJlcm9mIE5vZGUjXG4gICAgICogQG1lbWJlciB7c3RyaW5nfSB0eXBlIC0gU3RyaW5nIHJlcHJlc2VudGluZyB0aGUgbm9kZeKAmXMgdHlwZS5cbiAgICAgKiAgICAgICAgICAgICAgICAgICAgICAgICBQb3NzaWJsZSB2YWx1ZXMgYXJlIGByb290YCwgYGF0cnVsZWAsIGBydWxlYCxcbiAgICAgKiAgICAgICAgICAgICAgICAgICAgICAgICBgZGVjbGAsIG9yIGBjb21tZW50YC5cbiAgICAgKlxuICAgICAqIEBleGFtcGxlXG4gICAgICogcG9zdGNzcy5kZWNsKHsgcHJvcDogJ2NvbG9yJywgdmFsdWU6ICdibGFjaycgfSkudHlwZSAvLz0+ICdkZWNsJ1xuICAgICAqL1xuXG4gICAgLyoqXG4gICAgICogQG1lbWJlcm9mIE5vZGUjXG4gICAgICogQG1lbWJlciB7Q29udGFpbmVyfSBwYXJlbnQgLSB0aGUgbm9kZeKAmXMgcGFyZW50IG5vZGUuXG4gICAgICpcbiAgICAgKiBAZXhhbXBsZVxuICAgICAqIHJvb3Qubm9kZXNbMF0ucGFyZW50ID09IHJvb3Q7XG4gICAgICovXG5cbiAgICAvKipcbiAgICAgKiBAbWVtYmVyb2YgTm9kZSNcbiAgICAgKiBAbWVtYmVyIHtzb3VyY2V9IHNvdXJjZSAtIHRoZSBpbnB1dCBzb3VyY2Ugb2YgdGhlIG5vZGVcbiAgICAgKlxuICAgICAqIFRoZSBwcm9wZXJ0eSBpcyB1c2VkIGluIHNvdXJjZSBtYXAgZ2VuZXJhdGlvbi5cbiAgICAgKlxuICAgICAqIElmIHlvdSBjcmVhdGUgYSBub2RlIG1hbnVhbGx5IChlLmcuLCB3aXRoIGBwb3N0Y3NzLmRlY2woKWApLFxuICAgICAqIHRoYXQgbm9kZSB3aWxsIG5vdCBoYXZlIGEgYHNvdXJjZWAgcHJvcGVydHkgYW5kIHdpbGwgYmUgYWJzZW50XG4gICAgICogZnJvbSB0aGUgc291cmNlIG1hcC4gRm9yIHRoaXMgcmVhc29uLCB0aGUgcGx1Z2luIGRldmVsb3BlciBzaG91bGRcbiAgICAgKiBjb25zaWRlciBjbG9uaW5nIG5vZGVzIHRvIGNyZWF0ZSBuZXcgb25lcyAoaW4gd2hpY2ggY2FzZSB0aGUgbmV3IG5vZGXigJlzXG4gICAgICogc291cmNlIHdpbGwgcmVmZXJlbmNlIHRoZSBvcmlnaW5hbCwgY2xvbmVkIG5vZGUpIG9yIHNldHRpbmdcbiAgICAgKiB0aGUgYHNvdXJjZWAgcHJvcGVydHkgbWFudWFsbHkuXG4gICAgICpcbiAgICAgKiBgYGBqc1xuICAgICAqIC8vIEJhZFxuICAgICAqIGNvbnN0IHByZWZpeGVkID0gcG9zdGNzcy5kZWNsKHtcbiAgICAgKiAgIHByb3A6ICctbW96LScgKyBkZWNsLnByb3AsXG4gICAgICogICB2YWx1ZTogZGVjbC52YWx1ZVxuICAgICAqIH0pO1xuICAgICAqXG4gICAgICogLy8gR29vZFxuICAgICAqIGNvbnN0IHByZWZpeGVkID0gZGVjbC5jbG9uZSh7IHByb3A6ICctbW96LScgKyBkZWNsLnByb3AgfSk7XG4gICAgICogYGBgXG4gICAgICpcbiAgICAgKiBgYGBqc1xuICAgICAqIGlmICggYXRydWxlLm5hbWUgPT0gJ2FkZC1saW5rJyApIHtcbiAgICAgKiAgIGNvbnN0IHJ1bGUgPSBwb3N0Y3NzLnJ1bGUoeyBzZWxlY3RvcjogJ2EnLCBzb3VyY2U6IGF0cnVsZS5zb3VyY2UgfSk7XG4gICAgICogICBhdHJ1bGUucGFyZW50Lmluc2VydEJlZm9yZShhdHJ1bGUsIHJ1bGUpO1xuICAgICAqIH1cbiAgICAgKiBgYGBcbiAgICAgKlxuICAgICAqIEBleGFtcGxlXG4gICAgICogZGVjbC5zb3VyY2UuaW5wdXQuZnJvbSAvLz0+ICcvaG9tZS9haS9hLnNhc3MnXG4gICAgICogZGVjbC5zb3VyY2Uuc3RhcnQgICAgICAvLz0+IHsgbGluZTogMTAsIGNvbHVtbjogMiB9XG4gICAgICogZGVjbC5zb3VyY2UuZW5kICAgICAgICAvLz0+IHsgbGluZTogMTAsIGNvbHVtbjogMTIgfVxuICAgICAqL1xuXG4gICAgLyoqXG4gICAgICogQG1lbWJlcm9mIE5vZGUjXG4gICAgICogQG1lbWJlciB7b2JqZWN0fSByYXdzIC0gSW5mb3JtYXRpb24gdG8gZ2VuZXJhdGUgYnl0ZS10by1ieXRlIGVxdWFsXG4gICAgICogICAgICAgICAgICAgICAgICAgICAgICAgbm9kZSBzdHJpbmcgYXMgaXQgd2FzIGluIHRoZSBvcmlnaW4gaW5wdXQuXG4gICAgICpcbiAgICAgKiBFdmVyeSBwYXJzZXIgc2F2ZXMgaXRzIG93biBwcm9wZXJ0aWVzLFxuICAgICAqIGJ1dCB0aGUgZGVmYXVsdCBDU1MgcGFyc2VyIHVzZXM6XG4gICAgICpcbiAgICAgKiAqIGBiZWZvcmVgOiB0aGUgc3BhY2Ugc3ltYm9scyBiZWZvcmUgdGhlIG5vZGUuIEl0IGFsc28gc3RvcmVzIGAqYFxuICAgICAqICAgYW5kIGBfYCBzeW1ib2xzIGJlZm9yZSB0aGUgZGVjbGFyYXRpb24gKElFIGhhY2spLlxuICAgICAqICogYGFmdGVyYDogdGhlIHNwYWNlIHN5bWJvbHMgYWZ0ZXIgdGhlIGxhc3QgY2hpbGQgb2YgdGhlIG5vZGVcbiAgICAgKiAgIHRvIHRoZSBlbmQgb2YgdGhlIG5vZGUuXG4gICAgICogKiBgYmV0d2VlbmA6IHRoZSBzeW1ib2xzIGJldHdlZW4gdGhlIHByb3BlcnR5IGFuZCB2YWx1ZVxuICAgICAqICAgZm9yIGRlY2xhcmF0aW9ucywgc2VsZWN0b3IgYW5kIGB7YCBmb3IgcnVsZXMsIG9yIGxhc3QgcGFyYW1ldGVyXG4gICAgICogICBhbmQgYHtgIGZvciBhdC1ydWxlcy5cbiAgICAgKiAqIGBzZW1pY29sb25gOiBjb250YWlucyB0cnVlIGlmIHRoZSBsYXN0IGNoaWxkIGhhc1xuICAgICAqICAgYW4gKG9wdGlvbmFsKSBzZW1pY29sb24uXG4gICAgICogKiBgYWZ0ZXJOYW1lYDogdGhlIHNwYWNlIGJldHdlZW4gdGhlIGF0LXJ1bGUgbmFtZSBhbmQgaXRzIHBhcmFtZXRlcnMuXG4gICAgICogKiBgbGVmdGA6IHRoZSBzcGFjZSBzeW1ib2xzIGJldHdlZW4gYC8qYCBhbmQgdGhlIGNvbW1lbnTigJlzIHRleHQuXG4gICAgICogKiBgcmlnaHRgOiB0aGUgc3BhY2Ugc3ltYm9scyBiZXR3ZWVuIHRoZSBjb21tZW504oCZcyB0ZXh0XG4gICAgICogICBhbmQgPGNvZGU+KiYjNDc7PC9jb2RlPi5cbiAgICAgKiAqIGBpbXBvcnRhbnRgOiB0aGUgY29udGVudCBvZiB0aGUgaW1wb3J0YW50IHN0YXRlbWVudCxcbiAgICAgKiAgIGlmIGl0IGlzIG5vdCBqdXN0IGAhaW1wb3J0YW50YC5cbiAgICAgKlxuICAgICAqIFBvc3RDU1MgY2xlYW5zIHNlbGVjdG9ycywgZGVjbGFyYXRpb24gdmFsdWVzIGFuZCBhdC1ydWxlIHBhcmFtZXRlcnNcbiAgICAgKiBmcm9tIGNvbW1lbnRzIGFuZCBleHRyYSBzcGFjZXMsIGJ1dCBpdCBzdG9yZXMgb3JpZ2luIGNvbnRlbnQgaW4gcmF3c1xuICAgICAqIHByb3BlcnRpZXMuIEFzIHN1Y2gsIGlmIHlvdSBkb27igJl0IGNoYW5nZSBhIGRlY2xhcmF0aW9u4oCZcyB2YWx1ZSxcbiAgICAgKiBQb3N0Q1NTIHdpbGwgdXNlIHRoZSByYXcgdmFsdWUgd2l0aCBjb21tZW50cy5cbiAgICAgKlxuICAgICAqIEBleGFtcGxlXG4gICAgICogY29uc3Qgcm9vdCA9IHBvc3Rjc3MucGFyc2UoJ2Ege1xcbiAgY29sb3I6YmxhY2tcXG59JylcbiAgICAgKiByb290LmZpcnN0LmZpcnN0LnJhd3MgLy89PiB7IGJlZm9yZTogJ1xcbiAgJywgYmV0d2VlbjogJzonIH1cbiAgICAgKi9cblxufVxuXG5leHBvcnQgZGVmYXVsdCBOb2RlO1xuXG4vKipcbiAqIEB0eXBlZGVmIHtvYmplY3R9IHBvc2l0aW9uXG4gKiBAcHJvcGVydHkge251bWJlcn0gbGluZSAgIC0gc291cmNlIGxpbmUgaW4gZmlsZVxuICogQHByb3BlcnR5IHtudW1iZXJ9IGNvbHVtbiAtIHNvdXJjZSBjb2x1bW4gaW4gZmlsZVxuICovXG5cbi8qKlxuICogQHR5cGVkZWYge29iamVjdH0gc291cmNlXG4gKiBAcHJvcGVydHkge0lucHV0fSBpbnB1dCAgICAtIHtAbGluayBJbnB1dH0gd2l0aCBpbnB1dCBmaWxlXG4gKiBAcHJvcGVydHkge3Bvc2l0aW9ufSBzdGFydCAtIFRoZSBzdGFydGluZyBwb3NpdGlvbiBvZiB0aGUgbm9kZeKAmXMgc291cmNlXG4gKiBAcHJvcGVydHkge3Bvc2l0aW9ufSBlbmQgICAtIFRoZSBlbmRpbmcgcG9zaXRpb24gb2YgdGhlIG5vZGXigJlzIHNvdXJjZVxuICovXG4iXX0=