<?php

use Twig\Environment;
use Twig\Error\LoaderError;
use Twig\Error\RuntimeError;
use Twig\Extension\CoreExtension;
use Twig\Extension\SandboxExtension;
use Twig\Markup;
use Twig\Sandbox\SecurityError;
use Twig\Sandbox\SecurityNotAllowedTagError;
use Twig\Sandbox\SecurityNotAllowedFilterError;
use Twig\Sandbox\SecurityNotAllowedFunctionError;
use Twig\Source;
use Twig\Template;

/* @public_path/build/vendors-node_modules_bootstrap-select_dist_js_bootstrap-select_js.js */
class __TwigTemplate_13bd8c73255d0f672f4e9955bc8b1a00a1dd2e3fd5314a04f35986775a594881 extends Template
{
    private $source;
    private $macros = [];

    public function __construct(Environment $env)
    {
        parent::__construct($env);

        $this->source = $this->getSourceContext();

        $this->parent = false;

        $this->blocks = [
        ];
    }

    protected function doDisplay(array $context, array $blocks = [])
    {
        $macros = $this->macros;
        $__internal_085b0142806202599c7fe3b329164a92397d8978207a37e79d70b8c52599e33e = $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
        $__internal_085b0142806202599c7fe3b329164a92397d8978207a37e79d70b8c52599e33e->enter($__internal_085b0142806202599c7fe3b329164a92397d8978207a37e79d70b8c52599e33e_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "template", "@public_path/build/vendors-node_modules_bootstrap-select_dist_js_bootstrap-select_js.js"));

        $__internal_319393461309892924ff6e74d6d6e64287df64b63545b994e100d4ab223aed02 = $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
        $__internal_319393461309892924ff6e74d6d6e64287df64b63545b994e100d4ab223aed02->enter($__internal_319393461309892924ff6e74d6d6e64287df64b63545b994e100d4ab223aed02_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "template", "@public_path/build/vendors-node_modules_bootstrap-select_dist_js_bootstrap-select_js.js"));

        yield "(self[\"webpackChunk\"] = self[\"webpackChunk\"] || []).push([[\"vendors-node_modules_bootstrap-select_dist_js_bootstrap-select_js\"],{

/***/ \"./node_modules/bootstrap-select/dist/js/bootstrap-select.js\":
/*!*******************************************************************!*\\
  !*** ./node_modules/bootstrap-select/dist/js/bootstrap-select.js ***!
  \\*******************************************************************/
/***/ (function(module, exports, __webpack_require__) {

var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*!
 * Bootstrap-select v1.14.0-beta2 (https://developer.snapappointments.com/bootstrap-select)
 *
 * Copyright 2012-2021 SnapAppointments, LLC
 * Licensed under MIT (https://github.com/snapappointments/bootstrap-select/blob/master/LICENSE)
 */

(function (root, factory) {
  if (root === undefined && window !== undefined) root = window;
  if (true) {
    // AMD. Register as an anonymous module unless amdModuleId is set
    !(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(/*! jquery */ \"./node_modules/jquery/dist/jquery.js\")], __WEBPACK_AMD_DEFINE_RESULT__ = (function (a0) {
      return (factory(a0));
    }).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__),
\t\t__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
  } else {}
}(this, function (jQuery) {

(function (\$) {
  'use strict';

  var DISALLOWED_ATTRIBUTES = ['sanitize', 'whiteList', 'sanitizeFn'];

  var uriAttrs = [
    'background',
    'cite',
    'href',
    'itemtype',
    'longdesc',
    'poster',
    'src',
    'xlink:href'
  ];

  var ARIA_ATTRIBUTE_PATTERN = /^aria-[\\w-]*\$/i;

  var DefaultWhitelist = {
    // Global attributes allowed on any supplied element below.
    '*': ['class', 'dir', 'id', 'lang', 'role', 'tabindex', 'style', ARIA_ATTRIBUTE_PATTERN],
    a: ['target', 'href', 'title', 'rel'],
    area: [],
    b: [],
    br: [],
    col: [],
    code: [],
    div: [],
    em: [],
    hr: [],
    h1: [],
    h2: [],
    h3: [],
    h4: [],
    h5: [],
    h6: [],
    i: [],
    img: ['src', 'alt', 'title', 'width', 'height'],
    li: [],
    ol: [],
    p: [],
    pre: [],
    s: [],
    small: [],
    span: [],
    sub: [],
    sup: [],
    strong: [],
    u: [],
    ul: []
  }

  /**
   * A pattern that recognizes a commonly useful subset of URLs that are safe.
   *
   * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
   */
  var SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file):|[^&:/?#]*(?:[/?#]|\$))/gi;

  /**
   * A pattern that matches safe data URLs. Only matches image, video and audio types.
   *
   * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
   */
  var DATA_URL_PATTERN = /^data:(?:image\\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\\/(?:mpeg|mp4|ogg|webm)|audio\\/(?:mp3|oga|ogg|opus));base64,[a-z0-9+/]+=*\$/i;

  var ParseableAttributes = ['title', 'placeholder']; // attributes to use as settings, can add others in the future

  function allowedAttribute (attr, allowedAttributeList) {
    var attrName = attr.nodeName.toLowerCase()

    if (\$.inArray(attrName, allowedAttributeList) !== -1) {
      if (\$.inArray(attrName, uriAttrs) !== -1) {
        return Boolean(attr.nodeValue.match(SAFE_URL_PATTERN) || attr.nodeValue.match(DATA_URL_PATTERN))
      }

      return true
    }

    var regExp = \$(allowedAttributeList).filter(function (index, value) {
      return value instanceof RegExp
    })

    // Check if a regular expression validates the attribute.
    for (var i = 0, l = regExp.length; i < l; i++) {
      if (attrName.match(regExp[i])) {
        return true
      }
    }

    return false
  }

  function sanitizeHtml (unsafeElements, whiteList, sanitizeFn) {
    if (sanitizeFn && typeof sanitizeFn === 'function') {
      return sanitizeFn(unsafeElements);
    }

    var whitelistKeys = Object.keys(whiteList);

    for (var i = 0, len = unsafeElements.length; i < len; i++) {
      var elements = unsafeElements[i].querySelectorAll('*');

      for (var j = 0, len2 = elements.length; j < len2; j++) {
        var el = elements[j];
        var elName = el.nodeName.toLowerCase();

        if (whitelistKeys.indexOf(elName) === -1) {
          el.parentNode.removeChild(el);

          continue;
        }

        var attributeList = [].slice.call(el.attributes);
        var whitelistedAttributes = [].concat(whiteList['*'] || [], whiteList[elName] || []);

        for (var k = 0, len3 = attributeList.length; k < len3; k++) {
          var attr = attributeList[k];

          if (!allowedAttribute(attr, whitelistedAttributes)) {
            el.removeAttribute(attr.nodeName);
          }
        }
      }
    }
  }

  function getAttributesObject (\$select) {
    var attributesObject = {},
        attrVal;

    ParseableAttributes.forEach(function (item) {
      attrVal = \$select.attr(item);
      if (attrVal) attributesObject[item] = attrVal;
    });

    // for backwards compatibility
    // (using title as placeholder is deprecated - remove in v2.0.0)
    if (!attributesObject.placeholder && attributesObject.title) {
      attributesObject.placeholder = attributesObject.title;
    }

    return attributesObject;
  }

  // Polyfill for browsers with no classList support
  // Remove in v2
  if (!('classList' in document.createElement('_'))) {
    (function (view) {
      if (!('Element' in view)) return;

      var classListProp = 'classList',
          protoProp = 'prototype',
          elemCtrProto = view.Element[protoProp],
          objCtr = Object,
          classListGetter = function () {
            var \$elem = \$(this);

            return {
              add: function (classes) {
                classes = Array.prototype.slice.call(arguments).join(' ');
                return \$elem.addClass(classes);
              },
              remove: function (classes) {
                classes = Array.prototype.slice.call(arguments).join(' ');
                return \$elem.removeClass(classes);
              },
              toggle: function (classes, force) {
                return \$elem.toggleClass(classes, force);
              },
              contains: function (classes) {
                return \$elem.hasClass(classes);
              }
            }
          };

      if (objCtr.defineProperty) {
        var classListPropDesc = {
          get: classListGetter,
          enumerable: true,
          configurable: true
        };
        try {
          objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
        } catch (ex) { // IE 8 doesn't support enumerable:true
          // adding undefined to fight this issue https://github.com/eligrey/classList.js/issues/36
          // modernie IE8-MSW7 machine has IE8 8.0.6001.18702 and is affected
          if (ex.number === undefined || ex.number === -0x7FF5EC54) {
            classListPropDesc.enumerable = false;
            objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
          }
        }
      } else if (objCtr[protoProp].__defineGetter__) {
        elemCtrProto.__defineGetter__(classListProp, classListGetter);
      }
    }(window));
  }

  var testElement = document.createElement('_');

  testElement.classList.add('c1', 'c2');

  if (!testElement.classList.contains('c2')) {
    var _add = DOMTokenList.prototype.add,
        _remove = DOMTokenList.prototype.remove;

    DOMTokenList.prototype.add = function () {
      Array.prototype.forEach.call(arguments, _add.bind(this));
    }

    DOMTokenList.prototype.remove = function () {
      Array.prototype.forEach.call(arguments, _remove.bind(this));
    }
  }

  testElement.classList.toggle('c3', false);

  // Polyfill for IE 10 and Firefox <24, where classList.toggle does not
  // support the second argument.
  if (testElement.classList.contains('c3')) {
    var _toggle = DOMTokenList.prototype.toggle;

    DOMTokenList.prototype.toggle = function (token, force) {
      if (1 in arguments && !this.contains(token) === !force) {
        return force;
      } else {
        return _toggle.call(this, token);
      }
    };
  }

  testElement = null;

  // shallow array comparison
  function isEqual (array1, array2) {
    return array1.length === array2.length && array1.every(function (element, index) {
      return element === array2[index];
    });
  };

  // <editor-fold desc=\"Shims\">
  if (!String.prototype.startsWith) {
    (function () {
      'use strict'; // needed to support `apply`/`call` with `undefined`/`null`
      var toString = {}.toString;
      var startsWith = function (search) {
        if (this == null) {
          throw new TypeError();
        }
        var string = String(this);
        if (search && toString.call(search) == '[object RegExp]') {
          throw new TypeError();
        }
        var stringLength = string.length;
        var searchString = String(search);
        var searchLength = searchString.length;
        var position = arguments.length > 1 ? arguments[1] : undefined;
        // `ToInteger`
        var pos = position ? Number(position) : 0;
        if (pos != pos) { // better `isNaN`
          pos = 0;
        }
        var start = Math.min(Math.max(pos, 0), stringLength);
        // Avoid the `indexOf` call if no match is possible
        if (searchLength + start > stringLength) {
          return false;
        }
        var index = -1;
        while (++index < searchLength) {
          if (string.charCodeAt(start + index) != searchString.charCodeAt(index)) {
            return false;
          }
        }
        return true;
      };
      if (Object.defineProperty) {
        Object.defineProperty(String.prototype, 'startsWith', {
          'value': startsWith,
          'configurable': true,
          'writable': true
        });
      } else {
        String.prototype.startsWith = startsWith;
      }
    }());
  }

  function getSelectedOptions () {
    var selectedOptions = this.selectpicker.main.data.filter(function (item) {
      if (item.selected) {
        if (this.options.hideDisabled && item.disabled) return false;
        return true;
      }

      return false;
    }, this);

    // ensure only 1 option is selected if multiple are set in the data source
    if (this.options.source.data && !this.multiple && selectedOptions.length > 1) {
      for (var i = 0; i < selectedOptions.length - 1; i++) {
        selectedOptions[i].selected = false;
      }

      selectedOptions = [ selectedOptions[selectedOptions.length - 1] ];
    }

    return selectedOptions;
  }

  // much faster than \$.val()
  function getSelectValues (selectedOptions) {
    var value = [],
        options = selectedOptions || getSelectedOptions.call(this),
        opt;

    for (var i = 0, len = options.length; i < len; i++) {
      opt = options[i];

      if (!opt.disabled) {
        value.push(opt.value === undefined ? opt.text : opt.value);
      }
    }

    if (!this.multiple) {
      return !value.length ? null : value[0];
    }

    return value;
  }

  // set data-selected on select element if the value has been programmatically selected
  // prior to initialization of bootstrap-select
  // * consider removing or replacing an alternative method *
  var valHooks = {
    useDefault: false,
    _set: \$.valHooks.select.set
  };

  \$.valHooks.select.set = function (elem, value) {
    if (value && !valHooks.useDefault) \$(elem).data('selected', true);

    return valHooks._set.apply(this, arguments);
  };

  var changedArguments = null;

  var EventIsSupported = (function () {
    try {
      new Event('change');
      return true;
    } catch (e) {
      return false;
    }
  })();

  \$.fn.triggerNative = function (eventName) {
    var el = this[0],
        event;

    if (el.dispatchEvent) { // for modern browsers & IE9+
      if (EventIsSupported) {
        // For modern browsers
        event = new Event(eventName, {
          bubbles: true
        });
      } else {
        // For IE since it doesn't support Event constructor
        event = document.createEvent('Event');
        event.initEvent(eventName, true, false);
      }

      el.dispatchEvent(event);
    }
  };
  // </editor-fold>

  function stringSearch (li, searchString, method, normalize) {
    var stringTypes = [
          'display',
          'subtext',
          'tokens'
        ],
        searchSuccess = false;

    for (var i = 0; i < stringTypes.length; i++) {
      var stringType = stringTypes[i],
          string = li[stringType];

      if (string) {
        string = string.toString();

        // Strip HTML tags. This isn't perfect, but it's much faster than any other method
        if (stringType === 'display') {
          string = string.replace(/<[^>]+>/g, '');
        }

        if (normalize) string = normalizeToBase(string);
        string = string.toUpperCase();

        if (typeof method === 'function') {
          searchSuccess = method(string, searchString);
        } else if (method === 'contains') {
          searchSuccess = string.indexOf(searchString) >= 0;
        } else {
          searchSuccess = string.startsWith(searchString);
        }

        if (searchSuccess) break;
      }
    }

    return searchSuccess;
  }

  function toInteger (value) {
    return parseInt(value, 10) || 0;
  }

  // Borrowed from Lodash (_.deburr)
  /** Used to map Latin Unicode letters to basic Latin letters. */
  var deburredLetters = {
    // Latin-1 Supplement block.
    '\\xc0': 'A',  '\\xc1': 'A', '\\xc2': 'A', '\\xc3': 'A', '\\xc4': 'A', '\\xc5': 'A',
    '\\xe0': 'a',  '\\xe1': 'a', '\\xe2': 'a', '\\xe3': 'a', '\\xe4': 'a', '\\xe5': 'a',
    '\\xc7': 'C',  '\\xe7': 'c',
    '\\xd0': 'D',  '\\xf0': 'd',
    '\\xc8': 'E',  '\\xc9': 'E', '\\xca': 'E', '\\xcb': 'E',
    '\\xe8': 'e',  '\\xe9': 'e', '\\xea': 'e', '\\xeb': 'e',
    '\\xcc': 'I',  '\\xcd': 'I', '\\xce': 'I', '\\xcf': 'I',
    '\\xec': 'i',  '\\xed': 'i', '\\xee': 'i', '\\xef': 'i',
    '\\xd1': 'N',  '\\xf1': 'n',
    '\\xd2': 'O',  '\\xd3': 'O', '\\xd4': 'O', '\\xd5': 'O', '\\xd6': 'O', '\\xd8': 'O',
    '\\xf2': 'o',  '\\xf3': 'o', '\\xf4': 'o', '\\xf5': 'o', '\\xf6': 'o', '\\xf8': 'o',
    '\\xd9': 'U',  '\\xda': 'U', '\\xdb': 'U', '\\xdc': 'U',
    '\\xf9': 'u',  '\\xfa': 'u', '\\xfb': 'u', '\\xfc': 'u',
    '\\xdd': 'Y',  '\\xfd': 'y', '\\xff': 'y',
    '\\xc6': 'Ae', '\\xe6': 'ae',
    '\\xde': 'Th', '\\xfe': 'th',
    '\\xdf': 'ss',
    // Latin Extended-A block.
    '\\u0100': 'A',  '\\u0102': 'A', '\\u0104': 'A',
    '\\u0101': 'a',  '\\u0103': 'a', '\\u0105': 'a',
    '\\u0106': 'C',  '\\u0108': 'C', '\\u010a': 'C', '\\u010c': 'C',
    '\\u0107': 'c',  '\\u0109': 'c', '\\u010b': 'c', '\\u010d': 'c',
    '\\u010e': 'D',  '\\u0110': 'D', '\\u010f': 'd', '\\u0111': 'd',
    '\\u0112': 'E',  '\\u0114': 'E', '\\u0116': 'E', '\\u0118': 'E', '\\u011a': 'E',
    '\\u0113': 'e',  '\\u0115': 'e', '\\u0117': 'e', '\\u0119': 'e', '\\u011b': 'e',
    '\\u011c': 'G',  '\\u011e': 'G', '\\u0120': 'G', '\\u0122': 'G',
    '\\u011d': 'g',  '\\u011f': 'g', '\\u0121': 'g', '\\u0123': 'g',
    '\\u0124': 'H',  '\\u0126': 'H', '\\u0125': 'h', '\\u0127': 'h',
    '\\u0128': 'I',  '\\u012a': 'I', '\\u012c': 'I', '\\u012e': 'I', '\\u0130': 'I',
    '\\u0129': 'i',  '\\u012b': 'i', '\\u012d': 'i', '\\u012f': 'i', '\\u0131': 'i',
    '\\u0134': 'J',  '\\u0135': 'j',
    '\\u0136': 'K',  '\\u0137': 'k', '\\u0138': 'k',
    '\\u0139': 'L',  '\\u013b': 'L', '\\u013d': 'L', '\\u013f': 'L', '\\u0141': 'L',
    '\\u013a': 'l',  '\\u013c': 'l', '\\u013e': 'l', '\\u0140': 'l', '\\u0142': 'l',
    '\\u0143': 'N',  '\\u0145': 'N', '\\u0147': 'N', '\\u014a': 'N',
    '\\u0144': 'n',  '\\u0146': 'n', '\\u0148': 'n', '\\u014b': 'n',
    '\\u014c': 'O',  '\\u014e': 'O', '\\u0150': 'O',
    '\\u014d': 'o',  '\\u014f': 'o', '\\u0151': 'o',
    '\\u0154': 'R',  '\\u0156': 'R', '\\u0158': 'R',
    '\\u0155': 'r',  '\\u0157': 'r', '\\u0159': 'r',
    '\\u015a': 'S',  '\\u015c': 'S', '\\u015e': 'S', '\\u0160': 'S',
    '\\u015b': 's',  '\\u015d': 's', '\\u015f': 's', '\\u0161': 's',
    '\\u0162': 'T',  '\\u0164': 'T', '\\u0166': 'T',
    '\\u0163': 't',  '\\u0165': 't', '\\u0167': 't',
    '\\u0168': 'U',  '\\u016a': 'U', '\\u016c': 'U', '\\u016e': 'U', '\\u0170': 'U', '\\u0172': 'U',
    '\\u0169': 'u',  '\\u016b': 'u', '\\u016d': 'u', '\\u016f': 'u', '\\u0171': 'u', '\\u0173': 'u',
    '\\u0174': 'W',  '\\u0175': 'w',
    '\\u0176': 'Y',  '\\u0177': 'y', '\\u0178': 'Y',
    '\\u0179': 'Z',  '\\u017b': 'Z', '\\u017d': 'Z',
    '\\u017a': 'z',  '\\u017c': 'z', '\\u017e': 'z',
    '\\u0132': 'IJ', '\\u0133': 'ij',
    '\\u0152': 'Oe', '\\u0153': 'oe',
    '\\u0149': \"'n\", '\\u017f': 's'
  };

  /** Used to match Latin Unicode letters (excluding mathematical operators). */
  var reLatin = /[\\xc0-\\xd6\\xd8-\\xf6\\xf8-\\xff\\u0100-\\u017f]/g;

  /** Used to compose unicode character classes. */
  var rsComboMarksRange = '\\\\u0300-\\\\u036f',
      reComboHalfMarksRange = '\\\\ufe20-\\\\ufe2f',
      rsComboSymbolsRange = '\\\\u20d0-\\\\u20ff',
      rsComboMarksExtendedRange = '\\\\u1ab0-\\\\u1aff',
      rsComboMarksSupplementRange = '\\\\u1dc0-\\\\u1dff',
      rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange + rsComboMarksExtendedRange + rsComboMarksSupplementRange;

  /** Used to compose unicode capture groups. */
  var rsCombo = '[' + rsComboRange + ']';

  /**
   * Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks) and
   * [combining diacritical marks for symbols](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks_for_Symbols).
   */
  var reComboMark = RegExp(rsCombo, 'g');

  function deburrLetter (key) {
    return deburredLetters[key];
  };

  function normalizeToBase (string) {
    string = string.toString();
    return string && string.replace(reLatin, deburrLetter).replace(reComboMark, '');
  }

  // List of HTML entities for escaping.
  var escapeMap = {
    '&': '&amp;',
    '<': '&lt;',
    '>': '&gt;',
    '\"': '&quot;',
    \"'\": '&#x27;',
    '`': '&#x60;'
  };

  // Functions for escaping and unescaping strings to/from HTML interpolation.
  var createEscaper = function (map) {
    var escaper = function (match) {
      return map[match];
    };
    // Regexes for identifying a key that needs to be escaped.
    var source = '(?:' + Object.keys(map).join('|') + ')';
    var testRegexp = RegExp(source);
    var replaceRegexp = RegExp(source, 'g');
    return function (string) {
      string = string == null ? '' : '' + string;
      return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string;
    };
  };

  var htmlEscape = createEscaper(escapeMap);

  /**
   * ------------------------------------------------------------------------
   * Constants
   * ------------------------------------------------------------------------
   */

  var keyCodeMap = {
    32: ' ',
    48: '0',
    49: '1',
    50: '2',
    51: '3',
    52: '4',
    53: '5',
    54: '6',
    55: '7',
    56: '8',
    57: '9',
    59: ';',
    65: 'A',
    66: 'B',
    67: 'C',
    68: 'D',
    69: 'E',
    70: 'F',
    71: 'G',
    72: 'H',
    73: 'I',
    74: 'J',
    75: 'K',
    76: 'L',
    77: 'M',
    78: 'N',
    79: 'O',
    80: 'P',
    81: 'Q',
    82: 'R',
    83: 'S',
    84: 'T',
    85: 'U',
    86: 'V',
    87: 'W',
    88: 'X',
    89: 'Y',
    90: 'Z',
    96: '0',
    97: '1',
    98: '2',
    99: '3',
    100: '4',
    101: '5',
    102: '6',
    103: '7',
    104: '8',
    105: '9'
  };

  var keyCodes = {
    ESCAPE: 27, // KeyboardEvent.which value for Escape (Esc) key
    ENTER: 13, // KeyboardEvent.which value for Enter key
    SPACE: 32, // KeyboardEvent.which value for space key
    TAB: 9, // KeyboardEvent.which value for tab key
    ARROW_UP: 38, // KeyboardEvent.which value for up arrow key
    ARROW_DOWN: 40 // KeyboardEvent.which value for down arrow key
  }

  // eslint-disable-next-line no-undef
  var Dropdown = window.Dropdown || bootstrap.Dropdown;

  function getVersion () {
    var version;

    try {
      version = \$.fn.dropdown.Constructor.VERSION;
    } catch (err) {
      version = Dropdown.VERSION;
    }

    return version;
  }

  var version = {
    success: false,
    major: '3'
  };

  try {
    version.full = (getVersion() || '').split(' ')[0].split('.');
    version.major = version.full[0];
    version.success = true;
  } catch (err) {
    // do nothing
  }

  var selectId = 0;

  var EVENT_KEY = '.bs.select';

  var classNames = {
    DISABLED: 'disabled',
    DIVIDER: 'divider',
    SHOW: 'open',
    DROPUP: 'dropup',
    MENU: 'dropdown-menu',
    MENURIGHT: 'dropdown-menu-right',
    MENULEFT: 'dropdown-menu-left',
    // to-do: replace with more advanced template/customization options
    BUTTONCLASS: 'btn-default',
    POPOVERHEADER: 'popover-title',
    ICONBASE: 'glyphicon',
    TICKICON: 'glyphicon-ok'
  }

  var Selector = {
    MENU: '.' + classNames.MENU,
    DATA_TOGGLE: 'data-toggle=\"dropdown\"'
  }

  var elementTemplates = {
    div: document.createElement('div'),
    span: document.createElement('span'),
    i: document.createElement('i'),
    subtext: document.createElement('small'),
    a: document.createElement('a'),
    li: document.createElement('li'),
    whitespace: document.createTextNode('\\u00A0'),
    fragment: document.createDocumentFragment(),
    option: document.createElement('option')
  }

  elementTemplates.selectedOption = elementTemplates.option.cloneNode(false);
  elementTemplates.selectedOption.setAttribute('selected', true);

  elementTemplates.noResults = elementTemplates.li.cloneNode(false);
  elementTemplates.noResults.className = 'no-results';

  elementTemplates.a.setAttribute('role', 'option');
  elementTemplates.a.className = 'dropdown-item';

  elementTemplates.subtext.className = 'text-muted';

  elementTemplates.text = elementTemplates.span.cloneNode(false);
  elementTemplates.text.className = 'text';

  elementTemplates.checkMark = elementTemplates.span.cloneNode(false);

  var REGEXP_ARROW = new RegExp(keyCodes.ARROW_UP + '|' + keyCodes.ARROW_DOWN);
  var REGEXP_TAB_OR_ESCAPE = new RegExp('^' + keyCodes.TAB + '\$|' + keyCodes.ESCAPE);

  var generateOption = {
    li: function (content, classes, optgroup) {
      var li = elementTemplates.li.cloneNode(false);

      if (content) {
        if (content.nodeType === 1 || content.nodeType === 11) {
          li.appendChild(content);
        } else {
          li.innerHTML = content;
        }
      }

      if (typeof classes !== 'undefined' && classes !== '') li.className = classes;
      if (typeof optgroup !== 'undefined' && optgroup !== null) li.classList.add('optgroup-' + optgroup);

      return li;
    },

    a: function (text, classes, inline) {
      var a = elementTemplates.a.cloneNode(true);

      if (text) {
        if (text.nodeType === 11) {
          a.appendChild(text);
        } else {
          a.insertAdjacentHTML('beforeend', text);
        }
      }

      if (typeof classes !== 'undefined' && classes !== '') a.classList.add.apply(a.classList, classes.split(/\\s+/));
      if (inline) a.setAttribute('style', inline);

      return a;
    },

    text: function (options, useFragment) {
      var textElement = elementTemplates.text.cloneNode(false),
          subtextElement,
          iconElement;

      if (options.content) {
        textElement.innerHTML = options.content;
      } else {
        textElement.textContent = options.text;

        if (options.icon) {
          var whitespace = elementTemplates.whitespace.cloneNode(false);

          // need to use <i> for icons in the button to prevent a breaking change
          // note: switch to span in next major release
          iconElement = (useFragment === true ? elementTemplates.i : elementTemplates.span).cloneNode(false);
          iconElement.className = this.options.iconBase + ' ' + options.icon;

          elementTemplates.fragment.appendChild(iconElement);
          elementTemplates.fragment.appendChild(whitespace);
        }

        if (options.subtext) {
          subtextElement = elementTemplates.subtext.cloneNode(false);
          subtextElement.textContent = options.subtext;
          textElement.appendChild(subtextElement);
        }
      }

      if (useFragment === true) {
        while (textElement.childNodes.length > 0) {
          elementTemplates.fragment.appendChild(textElement.childNodes[0]);
        }
      } else {
        elementTemplates.fragment.appendChild(textElement);
      }

      return elementTemplates.fragment;
    },

    label: function (options) {
      var textElement = elementTemplates.text.cloneNode(false),
          subtextElement,
          iconElement;

      textElement.innerHTML = options.display;

      if (options.icon) {
        var whitespace = elementTemplates.whitespace.cloneNode(false);

        iconElement = elementTemplates.span.cloneNode(false);
        iconElement.className = this.options.iconBase + ' ' + options.icon;

        elementTemplates.fragment.appendChild(iconElement);
        elementTemplates.fragment.appendChild(whitespace);
      }

      if (options.subtext) {
        subtextElement = elementTemplates.subtext.cloneNode(false);
        subtextElement.textContent = options.subtext;
        textElement.appendChild(subtextElement);
      }

      elementTemplates.fragment.appendChild(textElement);

      return elementTemplates.fragment;
    }
  }

  var getOptionData = {
    fromOption: function (option, type) {
      var value;

      switch (type) {
        case 'divider':
          value = option.getAttribute('data-divider') === 'true';
          break;

        case 'text':
          value = option.textContent;
          break;

        case 'label':
          value = option.label;
          break;

        case 'style':
          value = option.style.cssText;
          break;

        case 'content':
        case 'tokens':
        case 'subtext':
        case 'icon':
          value = option.getAttribute('data-' + type);
          break;
      }

      return value;
    },
    fromDataSource: function (option, type) {
      var value;

      switch (type) {
        case 'text':
        case 'label':
          value = option.text || option.value || '';
          break;

        case 'divider':
        case 'style':
        case 'content':
        case 'tokens':
        case 'subtext':
        case 'icon':
          value = option[type];
          break;
      }

      return value;
    }
  }

  function showNoResults (searchMatch, searchValue) {
    if (!searchMatch.length) {
      elementTemplates.noResults.innerHTML = this.options.noneResultsText.replace('{0}', '\"' + htmlEscape(searchValue) + '\"');
      this.\$menuInner[0].firstChild.appendChild(elementTemplates.noResults);
    }
  }

  function filterHidden (item) {
    return !(item.hidden || this.options.hideDisabled && item.disabled);
  }

  var Selectpicker = function (element, options) {
    var that = this;

    // bootstrap-select has been initialized - revert valHooks.select.set back to its original function
    if (!valHooks.useDefault) {
      \$.valHooks.select.set = valHooks._set;
      valHooks.useDefault = true;
    }

    this.\$element = \$(element);
    this.\$newElement = null;
    this.\$button = null;
    this.\$menu = null;
    this.options = options;
    this.selectpicker = {
      main: {
        optionQueue: elementTemplates.fragment.cloneNode(false)
      },
      search: {},
      current: {}, // current changes if a search is in progress
      view: {},
      isSearching: false,
      keydown: {
        keyHistory: '',
        resetKeyHistory: {
          start: function () {
            return setTimeout(function () {
              that.selectpicker.keydown.keyHistory = '';
            }, 800);
          }
        }
      }
    };

    this.sizeInfo = {};

    // Format window padding
    var winPad = this.options.windowPadding;
    if (typeof winPad === 'number') {
      this.options.windowPadding = [winPad, winPad, winPad, winPad];
    }

    // Expose public methods
    this.val = Selectpicker.prototype.val;
    this.render = Selectpicker.prototype.render;
    this.refresh = Selectpicker.prototype.refresh;
    this.setStyle = Selectpicker.prototype.setStyle;
    this.selectAll = Selectpicker.prototype.selectAll;
    this.deselectAll = Selectpicker.prototype.deselectAll;
    this.destroy = Selectpicker.prototype.destroy;
    this.remove = Selectpicker.prototype.remove;
    this.show = Selectpicker.prototype.show;
    this.hide = Selectpicker.prototype.hide;

    this.init();
  };

  Selectpicker.VERSION = '1.14.0-beta2';

  // part of this is duplicated in i18n/defaults-en_US.js. Make sure to update both.
  Selectpicker.DEFAULTS = {
    noneSelectedText: 'Nothing selected',
    noneResultsText: 'No results matched {0}',
    countSelectedText: function (numSelected, numTotal) {
      return (numSelected == 1) ? '{0} item selected' : '{0} items selected';
    },
    maxOptionsText: function (numAll, numGroup) {
      return [
        (numAll == 1) ? 'Limit reached ({n} item max)' : 'Limit reached ({n} items max)',
        (numGroup == 1) ? 'Group limit reached ({n} item max)' : 'Group limit reached ({n} items max)'
      ];
    },
    selectAllText: 'Select All',
    deselectAllText: 'Deselect All',
    source: {},
    chunkSize: 40,
    doneButton: false,
    doneButtonText: 'Close',
    multipleSeparator: ', ',
    styleBase: 'btn',
    style: classNames.BUTTONCLASS,
    size: 'auto',
    title: null,
    placeholder: null,
    allowClear: false,
    selectedTextFormat: 'values',
    width: false,
    container: false,
    hideDisabled: false,
    showSubtext: false,
    showIcon: true,
    showContent: true,
    dropupAuto: true,
    header: false,
    liveSearch: false,
    liveSearchPlaceholder: null,
    liveSearchNormalize: false,
    liveSearchStyle: 'contains',
    actionsBox: false,
    iconBase: classNames.ICONBASE,
    tickIcon: classNames.TICKICON,
    showTick: false,
    template: {
      caret: '<span class=\"caret\"></span>'
    },
    maxOptions: false,
    mobile: false,
    selectOnTab: false,
    dropdownAlignRight: false,
    windowPadding: 0,
    virtualScroll: 600,
    display: false,
    sanitize: true,
    sanitizeFn: null,
    whiteList: DefaultWhitelist
  };

  Selectpicker.prototype = {

    constructor: Selectpicker,

    init: function () {
      var that = this,
          id = this.\$element.attr('id'),
          element = this.\$element[0],
          form = element.form;

      selectId++;
      this.selectId = 'bs-select-' + selectId;

      element.classList.add('bs-select-hidden');

      this.multiple = this.\$element.prop('multiple');
      this.autofocus = this.\$element.prop('autofocus');

      if (element.classList.contains('show-tick')) {
        this.options.showTick = true;
      }

      this.\$newElement = this.createDropdown();

      this.\$element
        .after(this.\$newElement)
        .prependTo(this.\$newElement);

      // ensure select is associated with form element if it got unlinked after moving it inside newElement
      if (form && element.form === null) {
        if (!form.id) form.id = 'form-' + this.selectId;
        element.setAttribute('form', form.id);
      }

      this.\$button = this.\$newElement.children('button');
      if (this.options.allowClear) this.\$clearButton = this.\$button.children('.bs-select-clear-selected');
      this.\$menu = this.\$newElement.children(Selector.MENU);
      this.\$menuInner = this.\$menu.children('.inner');
      this.\$searchbox = this.\$menu.find('input');

      element.classList.remove('bs-select-hidden');

      this.fetchData(function () {
        that.render(true);
        that.buildList();

        requestAnimationFrame(function () {
          that.\$element.trigger('loaded' + EVENT_KEY);
        });
      });

      this.fetchData(function () {
        that.render(true);
        that.buildList();

        requestAnimationFrame(function () {
          that.\$element.trigger('loaded' + EVENT_KEY);
        });
      });

      if (this.options.dropdownAlignRight === true) this.\$menu[0].classList.add(classNames.MENURIGHT);

      if (typeof id !== 'undefined') {
        this.\$button.attr('data-id', id);
      }

      this.checkDisabled();
      this.clickListener();

      if (version.major > 4) this.dropdown = new Dropdown(this.\$button[0]);

      if (this.options.liveSearch) {
        this.liveSearchListener();
        this.focusedParent = this.\$searchbox[0];
      } else {
        this.focusedParent = this.\$menuInner[0];
      }

      this.setStyle();
      this.setWidth();
      if (this.options.container) {
        this.selectPosition();
      } else {
        this.\$element.on('hide' + EVENT_KEY, function () {
          if (that.isVirtual()) {
            // empty menu on close
            var menuInner = that.\$menuInner[0],
                emptyMenu = menuInner.firstChild.cloneNode(false);

            // replace the existing UL with an empty one - this is faster than \$.empty() or innerHTML = ''
            menuInner.replaceChild(emptyMenu, menuInner.firstChild);
            menuInner.scrollTop = 0;
          }
        });
      }
      this.\$menu.data('this', this);
      this.\$newElement.data('this', this);
      if (this.options.mobile) this.mobile();

      this.\$newElement.on({
        'hide.bs.dropdown': function (e) {
          that.\$element.trigger('hide' + EVENT_KEY, e);
        },
        'hidden.bs.dropdown': function (e) {
          that.\$element.trigger('hidden' + EVENT_KEY, e);
        },
        'show.bs.dropdown': function (e) {
          that.\$element.trigger('show' + EVENT_KEY, e);
        },
        'shown.bs.dropdown': function (e) {
          that.\$element.trigger('shown' + EVENT_KEY, e);
        }
      });

      if (element.hasAttribute('required')) {
        this.\$element.on('invalid' + EVENT_KEY, function () {
          that.\$button[0].classList.add('bs-invalid');

          that.\$element
            .on('shown' + EVENT_KEY + '.invalid', function () {
              that.\$element
                .val(that.\$element.val()) // set the value to hide the validation message in Chrome when menu is opened
                .off('shown' + EVENT_KEY + '.invalid');
            })
            .on('rendered' + EVENT_KEY, function () {
              // if select is no longer invalid, remove the bs-invalid class
              if (this.validity.valid) that.\$button[0].classList.remove('bs-invalid');
              that.\$element.off('rendered' + EVENT_KEY);
            });

          that.\$button.on('blur' + EVENT_KEY, function () {
            that.\$element.trigger('focus').trigger('blur');
            that.\$button.off('blur' + EVENT_KEY);
          });
        });
      }

      if (form) {
        \$(form).on('reset' + EVENT_KEY, function () {
          requestAnimationFrame(function () {
            that.render();
          });
        });
      }
    },

    createDropdown: function () {
      // Options
      // If we are multiple or showTick option is set, then add the show-tick class
      var showTick = (this.multiple || this.options.showTick) ? ' show-tick' : '',
          multiselectable = this.multiple ? ' aria-multiselectable=\"true\"' : '',
          inputGroup = '',
          autofocus = this.autofocus ? ' autofocus' : '';

      if (version.major < 4 && this.\$element.parent().hasClass('input-group')) {
        inputGroup = ' input-group-btn';
      }

      // Elements
      var drop,
          header = '',
          searchbox = '',
          actionsbox = '',
          donebutton = '',
          clearButton = '';

      if (this.options.header) {
        header =
          '<div class=\"' + classNames.POPOVERHEADER + '\">' +
            '<button type=\"button\" class=\"close\" aria-hidden=\"true\">&times;</button>' +
              this.options.header +
          '</div>';
      }

      if (this.options.liveSearch) {
        searchbox =
          '<div class=\"bs-searchbox\">' +
            '<input type=\"search\" class=\"form-control\" autocomplete=\"off\"' +
              (
                this.options.liveSearchPlaceholder === null ? ''
                :
                ' placeholder=\"' + htmlEscape(this.options.liveSearchPlaceholder) + '\"'
              ) +
              ' role=\"combobox\" aria-label=\"Search\" aria-controls=\"' + this.selectId + '\" aria-autocomplete=\"list\">' +
          '</div>';
      }

      if (this.multiple && this.options.actionsBox) {
        actionsbox =
          '<div class=\"bs-actionsbox\">' +
            '<div class=\"btn-group btn-group-sm\">' +
              '<button type=\"button\" class=\"actions-btn bs-select-all btn ' + classNames.BUTTONCLASS + '\">' +
                this.options.selectAllText +
              '</button>' +
              '<button type=\"button\" class=\"actions-btn bs-deselect-all btn ' + classNames.BUTTONCLASS + '\">' +
                this.options.deselectAllText +
              '</button>' +
            '</div>' +
          '</div>';
      }

      if (this.multiple && this.options.doneButton) {
        donebutton =
          '<div class=\"bs-donebutton\">' +
            '<div class=\"btn-group\">' +
              '<button type=\"button\" class=\"btn btn-sm ' + classNames.BUTTONCLASS + '\">' +
                this.options.doneButtonText +
              '</button>' +
            '</div>' +
          '</div>';
      }

      if (this.options.allowClear) {
        clearButton = '<span class=\"close bs-select-clear-selected\" title=\"' + this.options.deselectAllText + '\"><span>&times;</span>';
      }

      drop =
        '<div class=\"dropdown bootstrap-select' + showTick + inputGroup + '\">' +
          '<button type=\"button\" tabindex=\"-1\" class=\"' +
            this.options.styleBase +
            ' dropdown-toggle\" ' +
            (this.options.display === 'static' ? 'data-display=\"static\"' : '') +
            Selector.DATA_TOGGLE +
            autofocus +
            ' role=\"combobox\" aria-owns=\"' +
            this.selectId +
            '\" aria-haspopup=\"listbox\" aria-expanded=\"false\">' +
            '<div class=\"filter-option\">' +
              '<div class=\"filter-option-inner\">' +
                '<div class=\"filter-option-inner-inner\">&nbsp;</div>' +
              '</div> ' +
            '</div>' +
            clearButton +
            '</span>' +
            (
              version.major >= '4' ? ''
              :
              '<span class=\"bs-caret\">' +
                this.options.template.caret +
              '</span>'
            ) +
          '</button>' +
          '<div class=\"' + classNames.MENU + ' ' + (version.major >= '4' ? '' : classNames.SHOW) + '\">' +
            header +
            searchbox +
            actionsbox +
            '<div class=\"inner ' + classNames.SHOW + '\" role=\"listbox\" id=\"' + this.selectId + '\" tabindex=\"-1\" ' + multiselectable + '>' +
                '<ul class=\"' + classNames.MENU + ' inner ' + (version.major >= '4' ? classNames.SHOW : '') + '\" role=\"presentation\">' +
                '</ul>' +
            '</div>' +
            donebutton +
          '</div>' +
        '</div>';

      return \$(drop);
    },

    setPositionData: function () {
      this.selectpicker.view.canHighlight = [];
      this.selectpicker.view.size = 0;
      this.selectpicker.view.firstHighlightIndex = false;

      for (var i = 0; i < this.selectpicker.current.data.length; i++) {
        var li = this.selectpicker.current.data[i],
            canHighlight = true;

        if (li.type === 'divider') {
          canHighlight = false;
          li.height = this.sizeInfo.dividerHeight;
        } else if (li.type === 'optgroup-label') {
          canHighlight = false;
          li.height = this.sizeInfo.dropdownHeaderHeight;
        } else {
          li.height = this.sizeInfo.liHeight;
        }

        if (li.disabled) canHighlight = false;

        this.selectpicker.view.canHighlight.push(canHighlight);

        if (canHighlight) {
          this.selectpicker.view.size++;
          li.posinset = this.selectpicker.view.size;
          if (this.selectpicker.view.firstHighlightIndex === false) this.selectpicker.view.firstHighlightIndex = i;
        }

        li.position = (i === 0 ? 0 : this.selectpicker.current.data[i - 1].position) + li.height;
      }
    },

    isVirtual: function () {
      return (this.options.virtualScroll !== false) && (this.selectpicker.main.data.length >= this.options.virtualScroll) || this.options.virtualScroll === true;
    },

    createView: function (isSearching, setSize, refresh) {
      var that = this,
          scrollTop = 0,
          active = [],
          selected,
          prevActive;

      this.selectpicker.isSearching = isSearching;
      this.selectpicker.current = isSearching ? this.selectpicker.search : this.selectpicker.main;

      this.setPositionData();

      if (setSize) {
        if (refresh) {
          scrollTop = this.\$menuInner[0].scrollTop;
        } else if (!that.multiple) {
          var element = that.\$element[0],
              selectedIndex = (element.options[element.selectedIndex] || {}).liIndex;

          if (typeof selectedIndex === 'number' && that.options.size !== false) {
            var selectedData = that.selectpicker.main.data[selectedIndex],
                position = selectedData && selectedData.position;

            if (position) {
              scrollTop = position - ((that.sizeInfo.menuInnerHeight + that.sizeInfo.liHeight) / 2);
            }
          }
        }
      }

      scroll(scrollTop, true);

      this.\$menuInner.off('scroll.createView').on('scroll.createView', function (e, updateValue) {
        if (!that.noScroll) scroll(this.scrollTop, updateValue);
        that.noScroll = false;
      });

      function scroll (scrollTop, init) {
        var size = that.selectpicker.current.data.length,
            chunks = [],
            chunkSize,
            chunkCount,
            firstChunk,
            lastChunk,
            currentChunk,
            prevPositions,
            positionIsDifferent,
            previousElements,
            menuIsDifferent = true,
            isVirtual = that.isVirtual();

        that.selectpicker.view.scrollTop = scrollTop;

        chunkSize = that.options.chunkSize; // number of options in a chunk
        chunkCount = Math.ceil(size / chunkSize) || 1; // number of chunks

        for (var i = 0; i < chunkCount; i++) {
          var endOfChunk = (i + 1) * chunkSize;

          if (i === chunkCount - 1) {
            endOfChunk = size;
          }

          chunks[i] = [
            (i) * chunkSize + (!i ? 0 : 1),
            endOfChunk
          ];

          if (!size) break;

          if (currentChunk === undefined && scrollTop - 1 <= that.selectpicker.current.data[endOfChunk - 1].position - that.sizeInfo.menuInnerHeight) {
            currentChunk = i;
          }
        }

        if (currentChunk === undefined) currentChunk = 0;

        prevPositions = [that.selectpicker.view.position0, that.selectpicker.view.position1];

        // always display previous, current, and next chunks
        firstChunk = Math.max(0, currentChunk - 1);
        lastChunk = Math.min(chunkCount - 1, currentChunk + 1);

        that.selectpicker.view.position0 = isVirtual === false ? 0 : (Math.max(0, chunks[firstChunk][0]) || 0);
        that.selectpicker.view.position1 = isVirtual === false ? size : (Math.min(size, chunks[lastChunk][1]) || 0);

        positionIsDifferent = prevPositions[0] !== that.selectpicker.view.position0 || prevPositions[1] !== that.selectpicker.view.position1;

        if (that.activeIndex !== undefined) {
          prevActive = (that.selectpicker.main.data[that.prevActiveIndex] || {}).element;
          active = (that.selectpicker.main.data[that.activeIndex] || {}).element;
          selected = (that.selectpicker.main.data[that.selectedIndex] || {}).element;

          if (init) {
            if (that.activeIndex !== that.selectedIndex) {
              that.defocusItem(active);
            }
            that.activeIndex = undefined;
          }

          if (that.activeIndex && that.activeIndex !== that.selectedIndex) {
            that.defocusItem(selected);
          }
        }

        if (that.prevActiveIndex !== undefined && that.prevActiveIndex !== that.activeIndex && that.prevActiveIndex !== that.selectedIndex) {
          that.defocusItem(prevActive);
        }

        if (init || positionIsDifferent) {
          previousElements = that.selectpicker.view.visibleElements ? that.selectpicker.view.visibleElements.slice() : [];

          if (isVirtual === false) {
            that.selectpicker.view.visibleElements = that.selectpicker.current.elements;
          } else {
            that.selectpicker.view.visibleElements = that.selectpicker.current.elements.slice(that.selectpicker.view.position0, that.selectpicker.view.position1);
          }

          that.setOptionStatus();

          // if searching, check to make sure the list has actually been updated before updating DOM
          // this prevents unnecessary repaints
          if (isSearching || (isVirtual === false && init)) menuIsDifferent = !isEqual(previousElements, that.selectpicker.view.visibleElements);

          // if virtual scroll is disabled and not searching,
          // menu should never need to be updated more than once
          if ((init || isVirtual === true) && menuIsDifferent) {
            var menuInner = that.\$menuInner[0],
                menuFragment = document.createDocumentFragment(),
                emptyMenu = menuInner.firstChild.cloneNode(false),
                marginTop,
                marginBottom,
                elements = that.selectpicker.view.visibleElements,
                toSanitize = [];

            // replace the existing UL with an empty one - this is faster than \$.empty()
            menuInner.replaceChild(emptyMenu, menuInner.firstChild);

            for (var i = 0, visibleElementsLen = elements.length; i < visibleElementsLen; i++) {
              var element = elements[i],
                  elText,
                  elementData;

              if (that.options.sanitize) {
                elText = element.lastChild;

                if (elText) {
                  elementData = that.selectpicker.current.data[i + that.selectpicker.view.position0];

                  if (elementData && elementData.content && !elementData.sanitized) {
                    toSanitize.push(elText);
                    elementData.sanitized = true;
                  }
                }
              }

              menuFragment.appendChild(element);
            }

            if (that.options.sanitize && toSanitize.length) {
              sanitizeHtml(toSanitize, that.options.whiteList, that.options.sanitizeFn);
            }

            if (isVirtual === true) {
              marginTop = (that.selectpicker.view.position0 === 0 ? 0 : that.selectpicker.current.data[that.selectpicker.view.position0 - 1].position);
              marginBottom = (that.selectpicker.view.position1 > size - 1 ? 0 : that.selectpicker.current.data[size - 1].position - that.selectpicker.current.data[that.selectpicker.view.position1 - 1].position);

              menuInner.firstChild.style.marginTop = marginTop + 'px';
              menuInner.firstChild.style.marginBottom = marginBottom + 'px';
            } else {
              menuInner.firstChild.style.marginTop = 0;
              menuInner.firstChild.style.marginBottom = 0;
            }

            menuInner.firstChild.appendChild(menuFragment);

            // if an option is encountered that is wider than the current menu width, update the menu width accordingly
            // switch to ResizeObserver with increased browser support
            if (isVirtual === true && that.sizeInfo.hasScrollBar) {
              var menuInnerInnerWidth = menuInner.firstChild.offsetWidth;

              if (init && menuInnerInnerWidth < that.sizeInfo.menuInnerInnerWidth && that.sizeInfo.totalMenuWidth > that.sizeInfo.selectWidth) {
                menuInner.firstChild.style.minWidth = that.sizeInfo.menuInnerInnerWidth + 'px';
              } else if (menuInnerInnerWidth > that.sizeInfo.menuInnerInnerWidth) {
                // set to 0 to get actual width of menu
                that.\$menu[0].style.minWidth = 0;

                var actualMenuWidth = menuInner.firstChild.offsetWidth;

                if (actualMenuWidth > that.sizeInfo.menuInnerInnerWidth) {
                  that.sizeInfo.menuInnerInnerWidth = actualMenuWidth;
                  menuInner.firstChild.style.minWidth = that.sizeInfo.menuInnerInnerWidth + 'px';
                }

                // reset to default CSS styling
                that.\$menu[0].style.minWidth = '';
              }
            }
          }

          if ((!isSearching && that.options.source.load || isSearching && that.options.source.search) && currentChunk === chunkCount - 1) {
            that.fetchData(function () {
              that.render();
              that.buildList(size, isSearching);
              that.setPositionData();
              scroll(scrollTop);
            }, isSearching ? 'search' : 'load', currentChunk + 1, isSearching ? that.selectpicker.search.previousValue : undefined);
          }
        }

        that.prevActiveIndex = that.activeIndex;

        if (!that.options.liveSearch) {
          that.\$menuInner.trigger('focus');
        } else if (isSearching && init) {
          var index = 0,
              newActive;

          if (!that.selectpicker.view.canHighlight[index]) {
            index = 1 + that.selectpicker.view.canHighlight.slice(1).indexOf(true);
          }

          newActive = that.selectpicker.view.visibleElements[index];

          that.defocusItem(that.selectpicker.view.currentActive);

          that.activeIndex = (that.selectpicker.current.data[index] || {}).index;

          that.focusItem(newActive);
        }
      }

      \$(window)
        .off('resize' + EVENT_KEY + '.' + this.selectId + '.createView')
        .on('resize' + EVENT_KEY + '.' + this.selectId + '.createView', function () {
          var isActive = that.\$newElement.hasClass(classNames.SHOW);

          if (isActive) scroll(that.\$menuInner[0].scrollTop);
        });
    },

    focusItem: function (li, liData, noStyle) {
      if (li) {
        liData = liData || this.selectpicker.main.data[this.activeIndex];
        var a = li.firstChild;

        if (a) {
          a.setAttribute('aria-setsize', this.selectpicker.view.size);
          a.setAttribute('aria-posinset', liData.posinset);

          if (noStyle !== true) {
            this.focusedParent.setAttribute('aria-activedescendant', a.id);
            li.classList.add('active');
            a.classList.add('active');
          }
        }
      }
    },

    defocusItem: function (li) {
      if (li) {
        li.classList.remove('active');
        if (li.firstChild) li.firstChild.classList.remove('active');
      }
    },

    setPlaceholder: function () {
      var that = this,
          updateIndex = false;

      if ((this.options.placeholder || this.options.allowClear) && !this.multiple) {
        if (!this.selectpicker.view.titleOption) this.selectpicker.view.titleOption = document.createElement('option');

        // this option doesn't create a new <li> element, but does add a new option at the start,
        // so startIndex should increase to prevent having to check every option for the bs-title-option class
        updateIndex = true;

        var element = this.\$element[0],
            selectTitleOption = false,
            titleNotAppended = !this.selectpicker.view.titleOption.parentNode,
            selectedIndex = element.selectedIndex,
            selectedOption = element.options[selectedIndex],
            firstSelectable = element.querySelector('select > *:not(:disabled)'),
            firstSelectableIndex = firstSelectable ? firstSelectable.index : 0,
            navigation = window.performance && window.performance.getEntriesByType('navigation'),
            // Safari doesn't support getEntriesByType('navigation') - fall back to performance.navigation
            isNotBackForward = (navigation && navigation.length) ? navigation[0].type !== 'back_forward' : window.performance.navigation.type !== 2;

        if (titleNotAppended) {
          // Use native JS to prepend option (faster)
          this.selectpicker.view.titleOption.className = 'bs-title-option';
          this.selectpicker.view.titleOption.value = '';

          // Check if selected or data-selected attribute is already set on an option. If not, select the titleOption option.
          // the selected item may have been changed by user or programmatically before the bootstrap select plugin runs,
          // if so, the select will have the data-selected attribute
          selectTitleOption = !selectedOption || (selectedIndex === firstSelectableIndex && selectedOption.defaultSelected === false && this.\$element.data('selected') === undefined);
        }

        if (titleNotAppended || this.selectpicker.view.titleOption.index !== 0) {
          element.insertBefore(this.selectpicker.view.titleOption, element.firstChild);
        }

        // Set selected *after* appending to select,
        // otherwise the option doesn't get selected in IE
        // set using selectedIndex, as setting the selected attr to true here doesn't work in IE11
        if (selectTitleOption && isNotBackForward) {
          element.selectedIndex = 0;
        } else if (document.readyState !== 'complete') {
          // if navigation type is back_forward, there's a chance the select will have its value set by BFCache
          // wait for that value to be set, then run render again
          window.addEventListener('pageshow', function () {
            if (that.selectpicker.view.displayedValue !== element.value) that.render();
          });
        }
      }

      return updateIndex;
    },

    fetchData: function (callback, type, page, searchValue) {
      type = type || 'data';

      var that = this,
          data = this.options.source[type],
          builtData;

      if (data) {
        this.options.virtualScroll = true;

        if (typeof data === 'function') {
          data.call(
            this,
            function (data) {
              builtData = that.buildData(data, type);
              callback.call(that, builtData);
            },
            page,
            searchValue
          );
        } else if (Array.isArray(data)) {
          builtData = that.buildData(data, type);
          callback.call(that, builtData);
        }
      } else {
        builtData = this.buildData(false, type);
        callback.call(that, builtData);
      }
    },

    buildData: function (data, type) {
      var dataGetter = data === false ? getOptionData.fromOption : getOptionData.fromDataSource;

      var optionSelector = ':not([hidden]):not([data-hidden=\"true\"])',
          mainData = [],
          startLen = 0,
          optID = 0,
          startIndex = this.setPlaceholder() && !data ? 1 : 0; // append the titleOption if necessary and skip the first option in the loop

      if (type === 'load') {
        startLen = this.selectpicker.main.data.length;
      } else if (type === 'search') {
        startLen = this.selectpicker.search.data.length;
      }

      if (this.options.hideDisabled) optionSelector += ':not(:disabled)';

      var selectOptions = data ? data.filter(filterHidden, this) : this.\$element[0].querySelectorAll('select > *' + optionSelector);

      function addDivider (config) {
        var previousData = mainData[mainData.length - 1];

        // ensure optgroup doesn't create back-to-back dividers
        if (
          previousData &&
          previousData.type === 'divider' &&
          (previousData.optID || config.optID)
        ) {
          return;
        }

        config = config || {};
        config.type = 'divider';

        mainData.push(config);
      }

      function addOption (item, config) {
        config = config || {};

        config.divider = dataGetter(item, 'divider');

        if (config.divider === true) {
          addDivider({
            optID: config.optID
          });
        } else {
          var liIndex = mainData.length + startLen,
              cssText = dataGetter(item, 'style'),
              inlineStyle = cssText ? htmlEscape(cssText) : '',
              optionClass = (item.className || '') + (config.optgroupClass || '');

          if (config.optID) optionClass = 'opt ' + optionClass;

          config.optionClass = optionClass.trim();
          config.inlineStyle = inlineStyle;

          config.text = dataGetter(item, 'text');
          config.content = dataGetter(item, 'content');
          config.tokens = dataGetter(item, 'tokens');
          config.subtext = dataGetter(item, 'subtext');
          config.icon = dataGetter(item, 'icon');

          config.display = config.content || config.text;
          config.value = item.value === undefined ? item.text : item.value;
          config.type = 'option';
          config.index = liIndex;

          config.option = !item.option ? item : item.option; // reference option element if it exists
          config.option.liIndex = liIndex;
          config.selected = !!item.selected;
          config.disabled = config.disabled || !!item.disabled;

          mainData.push(config);
        }
      }

      function addOptgroup (index, selectOptions) {
        var optgroup = selectOptions[index],
            // skip placeholder option
            previous = index - 1 < startIndex ? false : selectOptions[index - 1],
            next = selectOptions[index + 1],
            options = data ? optgroup.children.filter(filterHidden, this) : optgroup.querySelectorAll('option' + optionSelector);

        if (!options.length) return;

        var config = {
              display: htmlEscape(dataGetter(item, 'label')),
              subtext: dataGetter(optgroup, 'subtext'),
              icon: dataGetter(optgroup, 'icon'),
              type: 'optgroup-label',
              optgroupClass: ' ' + (optgroup.className || '')
            },
            headerIndex,
            lastIndex;

        optID++;

        if (previous) {
          addDivider({ optID: optID });
        }

        config.optID = optID;

        mainData.push(config);

        for (var j = 0, len = options.length; j < len; j++) {
          var option = options[j];

          if (j === 0) {
            headerIndex = mainData.length - 1;
            lastIndex = headerIndex + len;
          }

          addOption(option, {
            headerIndex: headerIndex,
            lastIndex: lastIndex,
            optID: config.optID,
            optgroupClass: config.optgroupClass,
            disabled: optgroup.disabled
          });
        }

        if (next) {
          addDivider({ optID: optID });
        }
      }

      for (var len = selectOptions.length, i = startIndex; i < len; i++) {
        var item = selectOptions[i],
            children = item.children;

        if (children && children.length) {
          addOptgroup.call(this, startIndex, selectOptions);
        } else {
          addOption.call(this, item, {});
        }
      }

      switch (type) {
        case 'data': {
          this.selectpicker.main.data = this.selectpicker.current.data = mainData;
          break;
        }
        case 'load': {
          Array.prototype.push.apply(this.selectpicker.main.data, mainData);
          this.selectpicker.current.data = this.selectpicker.main.data;
          break;
        }
        case 'search': {
          Array.prototype.push.apply(this.selectpicker.search.data, mainData);
          break;
        }
      }

      return mainData;
    },

    buildList: function (size, searching) {
      var that = this,
          selectData = searching ? this.selectpicker.search.data : this.selectpicker.main.data,
          mainElements = [],
          widestOptionLength = 0;

      if ((that.options.showTick || that.multiple) && !elementTemplates.checkMark.parentNode) {
        elementTemplates.checkMark.className = this.options.iconBase + ' ' + that.options.tickIcon + ' check-mark';
        elementTemplates.a.appendChild(elementTemplates.checkMark);
      }

      function buildElement (mainElements, item) {
        var liElement,
            combinedLength = 0;

        switch (item.type) {
          case 'divider':
            liElement = generateOption.li(
              false,
              classNames.DIVIDER,
              (item.optID ? item.optID + 'div' : undefined)
            );

            break;

          case 'option':
            liElement = generateOption.li(
              generateOption.a(
                generateOption.text.call(that, item),
                item.optionClass,
                item.inlineStyle
              ),
              '',
              item.optID
            );

            if (liElement.firstChild) {
              liElement.firstChild.id = that.selectId + '-' + item.index;
            }

            break;

          case 'optgroup-label':
            liElement = generateOption.li(
              generateOption.label.call(that, item),
              'dropdown-header' + item.optgroupClass,
              item.optID
            );

            break;
        }

        item.element = liElement;
        mainElements.push(liElement);

        // count the number of characters in the option - not perfect, but should work in most cases
        if (item.display) combinedLength += item.display.length;
        if (item.subtext) combinedLength += item.subtext.length;
        // if there is an icon, ensure this option's width is checked
        if (item.icon) combinedLength += 1;

        if (combinedLength > widestOptionLength) {
          widestOptionLength = combinedLength;

          // guess which option is the widest
          // use this when calculating menu width
          // not perfect, but it's fast, and the width will be updating accordingly when scrolling
          that.selectpicker.view.widestOption = mainElements[mainElements.length - 1];
        }
      }

      var startIndex = size || 0;

      for (var len = selectData.length, i = startIndex; i < len; i++) {
        var item = selectData[i];

        buildElement(mainElements, item);
      }

      if (size) {
        if (searching) {
          Array.prototype.push.apply(this.selectpicker.search.elements, mainElements);
        } else {
          Array.prototype.push.apply(this.selectpicker.main.elements, mainElements);
          this.selectpicker.current.elements = this.selectpicker.main.elements;
        }
      } else {
        if (searching) {
          this.selectpicker.search.elements = mainElements;
        } else {
          this.selectpicker.main.elements = this.selectpicker.current.elements = mainElements;
        }
      }
    },

    findLis: function () {
      return this.\$menuInner.find('.inner > li');
    },

    render: function (init) {
      var that = this,
          element = this.\$element[0],
          // ensure titleOption is appended and selected (if necessary) before getting selectedOptions
          placeholderSelected = this.setPlaceholder() && element.selectedIndex === 0,
          selectedOptions = getSelectedOptions.call(this),
          selectedCount = selectedOptions.length,
          selectedValues = getSelectValues.call(this, selectedOptions),
          button = this.\$button[0],
          buttonInner = button.querySelector('.filter-option-inner-inner'),
          multipleSeparator = document.createTextNode(this.options.multipleSeparator),
          titleFragment = elementTemplates.fragment.cloneNode(false),
          showCount,
          countMax,
          hasContent = false;

      function createSelected (item) {
        if (item.selected) {
          that.createOption(item, true);
        } else if (item.children && item.children.length) {
          item.children.map(createSelected);
        }
      }

      // create selected option elements to ensure select value is correct
      if (this.options.source.data && init) {
        selectedOptions.map(createSelected);
        element.appendChild(this.selectpicker.main.optionQueue);

        if (placeholderSelected) placeholderSelected = element.selectedIndex === 0;
      }

      button.classList.toggle('bs-placeholder', that.multiple ? !selectedCount : !selectedValues && selectedValues !== 0);

      if (!that.multiple && selectedOptions.length === 1) {
        that.selectpicker.view.displayedValue = selectedValues;
      }

      if (this.options.selectedTextFormat === 'static') {
        titleFragment = generateOption.text.call(this, { text: this.options.placeholder }, true);
      } else {
        showCount = this.multiple && this.options.selectedTextFormat.indexOf('count') !== -1 && selectedCount > 1;

        // determine if the number of selected options will be shown (showCount === true)
        if (showCount) {
          countMax = this.options.selectedTextFormat.split('>');
          showCount = (countMax.length > 1 && selectedCount > countMax[1]) || (countMax.length === 1 && selectedCount >= 2);
        }

        // only loop through all selected options if the count won't be shown
        if (showCount === false) {
          if (!placeholderSelected) {
            for (var selectedIndex = 0; selectedIndex < selectedCount; selectedIndex++) {
              if (selectedIndex < 50) {
                var option = selectedOptions[selectedIndex],
                    titleOptions = {};

                if (option) {
                  if (this.multiple && selectedIndex > 0) {
                    titleFragment.appendChild(multipleSeparator.cloneNode(false));
                  }

                  if (option.title) {
                    titleOptions.text = option.title;
                  } else if (option.content && that.options.showContent) {
                    titleOptions.content = option.content.toString();
                    hasContent = true;
                  } else {
                    if (that.options.showIcon) {
                      titleOptions.icon = option.icon;
                    }
                    if (that.options.showSubtext && !that.multiple && option.subtext) titleOptions.subtext = ' ' + option.subtext;
                    titleOptions.text = option.text.trim();
                  }

                  titleFragment.appendChild(generateOption.text.call(this, titleOptions, true));
                }
              } else {
                break;
              }
            }

            // add ellipsis
            if (selectedCount > 49) {
              titleFragment.appendChild(document.createTextNode('...'));
            }
          }
        } else {
          var optionSelector = ':not([hidden]):not([data-hidden=\"true\"]):not([data-divider=\"true\"])';
          if (this.options.hideDisabled) optionSelector += ':not(:disabled)';

          // If this is a multiselect, and selectedTextFormat is count, then show 1 of 2 selected, etc.
          var totalCount = this.\$element[0].querySelectorAll('select > option' + optionSelector + ', optgroup' + optionSelector + ' option' + optionSelector).length,
              tr8nText = (typeof this.options.countSelectedText === 'function') ? this.options.countSelectedText(selectedCount, totalCount) : this.options.countSelectedText;

          titleFragment = generateOption.text.call(this, {
            text: tr8nText.replace('{0}', selectedCount.toString()).replace('{1}', totalCount.toString())
          }, true);
        }
      }

      // If the select doesn't have a title, then use the default, or if nothing is set at all, use noneSelectedText
      if (!titleFragment.childNodes.length) {
        titleFragment = generateOption.text.call(this, {
          text: this.options.placeholder ? this.options.placeholder : this.options.noneSelectedText
        }, true);
      }

      // if the select has a title, apply it to the button, and if not, apply titleFragment text
      // strip all HTML tags and trim the result, then unescape any escaped tags
      button.title = titleFragment.textContent.replace(/<[^>]*>?/g, '').trim();

      if (this.options.sanitize && hasContent) {
        sanitizeHtml([titleFragment], that.options.whiteList, that.options.sanitizeFn);
      }

      buttonInner.innerHTML = '';
      buttonInner.appendChild(titleFragment);

      if (version.major < 4 && this.\$newElement[0].classList.contains('bs3-has-addon')) {
        var filterExpand = button.querySelector('.filter-expand'),
            clone = buttonInner.cloneNode(true);

        clone.className = 'filter-expand';

        if (filterExpand) {
          button.replaceChild(clone, filterExpand);
        } else {
          button.appendChild(clone);
        }
      }

      this.\$element.trigger('rendered' + EVENT_KEY);
    },

    /**
     * @param [style]
     * @param [status]
     */
    setStyle: function (newStyle, status) {
      var button = this.\$button[0],
          newElement = this.\$newElement[0],
          style = this.options.style.trim(),
          buttonClass;

      if (this.\$element.attr('class')) {
        this.\$newElement.addClass(this.\$element.attr('class').replace(/selectpicker|mobile-device|bs-select-hidden|validate\\[.*\\]/gi, ''));
      }

      if (version.major < 4) {
        newElement.classList.add('bs3');

        if (newElement.parentNode.classList && newElement.parentNode.classList.contains('input-group') &&
            (newElement.previousElementSibling || newElement.nextElementSibling) &&
            (newElement.previousElementSibling || newElement.nextElementSibling).classList.contains('input-group-addon')
        ) {
          newElement.classList.add('bs3-has-addon');
        }
      }

      if (newStyle) {
        buttonClass = newStyle.trim();
      } else {
        buttonClass = style;
      }

      if (status == 'add') {
        if (buttonClass) button.classList.add.apply(button.classList, buttonClass.split(' '));
      } else if (status == 'remove') {
        if (buttonClass) button.classList.remove.apply(button.classList, buttonClass.split(' '));
      } else {
        if (style) button.classList.remove.apply(button.classList, style.split(' '));
        if (buttonClass) button.classList.add.apply(button.classList, buttonClass.split(' '));
      }
    },

    liHeight: function (refresh) {
      if (!refresh && (this.options.size === false || Object.keys(this.sizeInfo).length)) return;

      var newElement = elementTemplates.div.cloneNode(false),
          menu = elementTemplates.div.cloneNode(false),
          menuInner = elementTemplates.div.cloneNode(false),
          menuInnerInner = document.createElement('ul'),
          divider = elementTemplates.li.cloneNode(false),
          dropdownHeader = elementTemplates.li.cloneNode(false),
          li,
          a = elementTemplates.a.cloneNode(false),
          text = elementTemplates.span.cloneNode(false),
          header = this.options.header && this.\$menu.find('.' + classNames.POPOVERHEADER).length > 0 ? this.\$menu.find('.' + classNames.POPOVERHEADER)[0].cloneNode(true) : null,
          search = this.options.liveSearch ? elementTemplates.div.cloneNode(false) : null,
          actions = this.options.actionsBox && this.multiple && this.\$menu.find('.bs-actionsbox').length > 0 ? this.\$menu.find('.bs-actionsbox')[0].cloneNode(true) : null,
          doneButton = this.options.doneButton && this.multiple && this.\$menu.find('.bs-donebutton').length > 0 ? this.\$menu.find('.bs-donebutton')[0].cloneNode(true) : null,
          firstOption = this.\$element[0].options[0];

      this.sizeInfo.selectWidth = this.\$newElement[0].offsetWidth;

      text.className = 'text';
      a.className = 'dropdown-item ' + (firstOption ? firstOption.className : '');
      newElement.className = this.\$menu[0].parentNode.className + ' ' + classNames.SHOW;
      newElement.style.width = 0; // ensure button width doesn't affect natural width of menu when calculating
      if (this.options.width === 'auto') menu.style.minWidth = 0;
      menu.className = classNames.MENU + ' ' + classNames.SHOW;
      menuInner.className = 'inner ' + classNames.SHOW;
      menuInnerInner.className = classNames.MENU + ' inner ' + (version.major >= '4' ? classNames.SHOW : '');
      divider.className = classNames.DIVIDER;
      dropdownHeader.className = 'dropdown-header';

      text.appendChild(document.createTextNode('\\u200b'));

      if (this.selectpicker.current.data.length) {
        for (var i = 0; i < this.selectpicker.current.data.length; i++) {
          var data = this.selectpicker.current.data[i];
          if (data.type === 'option') {
            li = data.element;
            break;
          }
        }
      } else {
        li = elementTemplates.li.cloneNode(false);
        a.appendChild(text);
        li.appendChild(a);
      }

      dropdownHeader.appendChild(text.cloneNode(true));

      if (this.selectpicker.view.widestOption) {
        menuInnerInner.appendChild(this.selectpicker.view.widestOption.cloneNode(true));
      }

      menuInnerInner.appendChild(li);
      menuInnerInner.appendChild(divider);
      menuInnerInner.appendChild(dropdownHeader);
      if (header) menu.appendChild(header);
      if (search) {
        var input = document.createElement('input');
        search.className = 'bs-searchbox';
        input.className = 'form-control';
        search.appendChild(input);
        menu.appendChild(search);
      }
      if (actions) menu.appendChild(actions);
      menuInner.appendChild(menuInnerInner);
      menu.appendChild(menuInner);
      if (doneButton) menu.appendChild(doneButton);
      newElement.appendChild(menu);

      document.body.appendChild(newElement);

      var liHeight = li.offsetHeight,
          dropdownHeaderHeight = dropdownHeader ? dropdownHeader.offsetHeight : 0,
          headerHeight = header ? header.offsetHeight : 0,
          searchHeight = search ? search.offsetHeight : 0,
          actionsHeight = actions ? actions.offsetHeight : 0,
          doneButtonHeight = doneButton ? doneButton.offsetHeight : 0,
          dividerHeight = \$(divider).outerHeight(true),
          menuStyle = window.getComputedStyle(menu),
          menuWidth = menu.offsetWidth,
          menuPadding = {
            vert: toInteger(menuStyle.paddingTop) +
                  toInteger(menuStyle.paddingBottom) +
                  toInteger(menuStyle.borderTopWidth) +
                  toInteger(menuStyle.borderBottomWidth),
            horiz: toInteger(menuStyle.paddingLeft) +
                  toInteger(menuStyle.paddingRight) +
                  toInteger(menuStyle.borderLeftWidth) +
                  toInteger(menuStyle.borderRightWidth)
          },
          menuExtras = {
            vert: menuPadding.vert +
                  toInteger(menuStyle.marginTop) +
                  toInteger(menuStyle.marginBottom) + 2,
            horiz: menuPadding.horiz +
                  toInteger(menuStyle.marginLeft) +
                  toInteger(menuStyle.marginRight) + 2
          },
          scrollBarWidth;

      menuInner.style.overflowY = 'scroll';

      scrollBarWidth = menu.offsetWidth - menuWidth;

      document.body.removeChild(newElement);

      this.sizeInfo.liHeight = liHeight;
      this.sizeInfo.dropdownHeaderHeight = dropdownHeaderHeight;
      this.sizeInfo.headerHeight = headerHeight;
      this.sizeInfo.searchHeight = searchHeight;
      this.sizeInfo.actionsHeight = actionsHeight;
      this.sizeInfo.doneButtonHeight = doneButtonHeight;
      this.sizeInfo.dividerHeight = dividerHeight;
      this.sizeInfo.menuPadding = menuPadding;
      this.sizeInfo.menuExtras = menuExtras;
      this.sizeInfo.menuWidth = menuWidth;
      this.sizeInfo.menuInnerInnerWidth = menuWidth - menuPadding.horiz;
      this.sizeInfo.totalMenuWidth = this.sizeInfo.menuWidth;
      this.sizeInfo.scrollBarWidth = scrollBarWidth;
      this.sizeInfo.selectHeight = this.\$newElement[0].offsetHeight;

      this.setPositionData();
    },

    getSelectPosition: function () {
      var that = this,
          \$window = \$(window),
          pos = that.\$newElement.offset(),
          \$container = \$(that.options.container),
          containerPos;

      if (that.options.container && \$container.length && !\$container.is('body')) {
        containerPos = \$container.offset();
        containerPos.top += parseInt(\$container.css('borderTopWidth'));
        containerPos.left += parseInt(\$container.css('borderLeftWidth'));
      } else {
        containerPos = { top: 0, left: 0 };
      }

      var winPad = that.options.windowPadding;

      this.sizeInfo.selectOffsetTop = pos.top - containerPos.top - \$window.scrollTop();
      this.sizeInfo.selectOffsetBot = \$window.height() - this.sizeInfo.selectOffsetTop - this.sizeInfo.selectHeight - containerPos.top - winPad[2];
      this.sizeInfo.selectOffsetLeft = pos.left - containerPos.left - \$window.scrollLeft();
      this.sizeInfo.selectOffsetRight = \$window.width() - this.sizeInfo.selectOffsetLeft - this.sizeInfo.selectWidth - containerPos.left - winPad[1];
      this.sizeInfo.selectOffsetTop -= winPad[0];
      this.sizeInfo.selectOffsetLeft -= winPad[3];
    },

    setMenuSize: function (isAuto) {
      this.getSelectPosition();

      var selectWidth = this.sizeInfo.selectWidth,
          liHeight = this.sizeInfo.liHeight,
          headerHeight = this.sizeInfo.headerHeight,
          searchHeight = this.sizeInfo.searchHeight,
          actionsHeight = this.sizeInfo.actionsHeight,
          doneButtonHeight = this.sizeInfo.doneButtonHeight,
          divHeight = this.sizeInfo.dividerHeight,
          menuPadding = this.sizeInfo.menuPadding,
          menuInnerHeight,
          menuHeight,
          divLength = 0,
          minHeight,
          _minHeight,
          maxHeight,
          menuInnerMinHeight,
          estimate,
          isDropup;

      if (this.options.dropupAuto) {
        // Get the estimated height of the menu without scrollbars.
        // This is useful for smaller menus, where there might be plenty of room
        // below the button without setting dropup, but we can't know
        // the exact height of the menu until createView is called later
        estimate = liHeight * this.selectpicker.current.data.length + menuPadding.vert;

        isDropup = this.sizeInfo.selectOffsetTop - this.sizeInfo.selectOffsetBot > this.sizeInfo.menuExtras.vert && estimate + this.sizeInfo.menuExtras.vert + 50 > this.sizeInfo.selectOffsetBot;

        // ensure dropup doesn't change while searching (so menu doesn't bounce back and forth)
        if (this.selectpicker.isSearching === true) {
          isDropup = this.selectpicker.dropup;
        }

        this.\$newElement.toggleClass(classNames.DROPUP, isDropup);
        this.selectpicker.dropup = isDropup;
      }

      if (this.options.size === 'auto') {
        _minHeight = this.selectpicker.current.data.length > 3 ? this.sizeInfo.liHeight * 3 + this.sizeInfo.menuExtras.vert - 2 : 0;
        menuHeight = this.sizeInfo.selectOffsetBot - this.sizeInfo.menuExtras.vert;
        minHeight = _minHeight + headerHeight + searchHeight + actionsHeight + doneButtonHeight;
        menuInnerMinHeight = Math.max(_minHeight - menuPadding.vert, 0);

        if (this.\$newElement.hasClass(classNames.DROPUP)) {
          menuHeight = this.sizeInfo.selectOffsetTop - this.sizeInfo.menuExtras.vert;
        }

        maxHeight = menuHeight;
        menuInnerHeight = menuHeight - headerHeight - searchHeight - actionsHeight - doneButtonHeight - menuPadding.vert;
      } else if (this.options.size && this.options.size != 'auto' && this.selectpicker.current.elements.length > this.options.size) {
        for (var i = 0; i < this.options.size; i++) {
          if (this.selectpicker.current.data[i].type === 'divider') divLength++;
        }

        menuHeight = liHeight * this.options.size + divLength * divHeight + menuPadding.vert;
        menuInnerHeight = menuHeight - menuPadding.vert;
        maxHeight = menuHeight + headerHeight + searchHeight + actionsHeight + doneButtonHeight;
        minHeight = menuInnerMinHeight = '';
      }

      this.\$menu.css({
        'max-height': maxHeight + 'px',
        'overflow': 'hidden',
        'min-height': minHeight + 'px'
      });

      this.\$menuInner.css({
        'max-height': menuInnerHeight + 'px',
        'overflow-y': 'auto',
        'min-height': menuInnerMinHeight + 'px'
      });

      // ensure menuInnerHeight is always a positive number to prevent issues calculating chunkSize in createView
      this.sizeInfo.menuInnerHeight = Math.max(menuInnerHeight, 1);

      if (this.selectpicker.current.data.length && this.selectpicker.current.data[this.selectpicker.current.data.length - 1].position > this.sizeInfo.menuInnerHeight) {
        this.sizeInfo.hasScrollBar = true;
        this.sizeInfo.totalMenuWidth = this.sizeInfo.menuWidth + this.sizeInfo.scrollBarWidth;
      }

      if (this.options.dropdownAlignRight === 'auto') {
        this.\$menu.toggleClass(classNames.MENURIGHT, this.sizeInfo.selectOffsetLeft > this.sizeInfo.selectOffsetRight && this.sizeInfo.selectOffsetRight < (this.sizeInfo.totalMenuWidth - selectWidth));
      }

      if (this.dropdown && this.dropdown._popper) this.dropdown._popper.update();
    },

    setSize: function (refresh) {
      this.liHeight(refresh);

      if (this.options.header) this.\$menu.css('padding-top', 0);

      if (this.options.size !== false) {
        var that = this,
            \$window = \$(window);

        this.setMenuSize();

        if (this.options.liveSearch) {
          this.\$searchbox
            .off('input.setMenuSize propertychange.setMenuSize')
            .on('input.setMenuSize propertychange.setMenuSize', function () {
              return that.setMenuSize();
            });
        }

        if (this.options.size === 'auto') {
          \$window
            .off('resize' + EVENT_KEY + '.' + this.selectId + '.setMenuSize' + ' scroll' + EVENT_KEY + '.' + this.selectId + '.setMenuSize')
            .on('resize' + EVENT_KEY + '.' + this.selectId + '.setMenuSize' + ' scroll' + EVENT_KEY + '.' + this.selectId + '.setMenuSize', function () {
              return that.setMenuSize();
            });
        } else if (this.options.size && this.options.size != 'auto' && this.selectpicker.current.elements.length > this.options.size) {
          \$window.off('resize' + EVENT_KEY + '.' + this.selectId + '.setMenuSize' + ' scroll' + EVENT_KEY + '.' + this.selectId + '.setMenuSize');
        }
      }

      this.createView(false, true, refresh);
    },

    setWidth: function () {
      var that = this;

      if (this.options.width === 'auto') {
        requestAnimationFrame(function () {
          that.\$menu.css('min-width', '0');

          that.\$element.on('loaded' + EVENT_KEY, function () {
            that.liHeight();
            that.setMenuSize();

            // Get correct width if element is hidden
            var \$selectClone = that.\$newElement.clone().appendTo('body'),
                btnWidth = \$selectClone.css('width', 'auto').children('button').outerWidth();

            \$selectClone.remove();

            // Set width to whatever's larger, button title or longest option
            that.sizeInfo.selectWidth = Math.max(that.sizeInfo.totalMenuWidth, btnWidth);
            that.\$newElement.css('width', that.sizeInfo.selectWidth + 'px');
          });
        });
      } else if (this.options.width === 'fit') {
        // Remove inline min-width so width can be changed from 'auto'
        this.\$menu.css('min-width', '');
        this.\$newElement.css('width', '').addClass('fit-width');
      } else if (this.options.width) {
        // Remove inline min-width so width can be changed from 'auto'
        this.\$menu.css('min-width', '');
        this.\$newElement.css('width', this.options.width);
      } else {
        // Remove inline min-width/width so width can be changed
        this.\$menu.css('min-width', '');
        this.\$newElement.css('width', '');
      }
      // Remove fit-width class if width is changed programmatically
      if (this.\$newElement.hasClass('fit-width') && this.options.width !== 'fit') {
        this.\$newElement[0].classList.remove('fit-width');
      }
    },

    selectPosition: function () {
      this.\$bsContainer = \$('<div class=\"bs-container\" />');

      var that = this,
          \$container = \$(this.options.container),
          pos,
          containerPos,
          actualHeight,
          getPlacement = function (\$element) {
            var containerPosition = {},
                // fall back to dropdown's default display setting if display is not manually set
                display = that.options.display || (
                  // Bootstrap 3 doesn't have \$.fn.dropdown.Constructor.Default
                  \$.fn.dropdown.Constructor.Default ? \$.fn.dropdown.Constructor.Default.display
                  : false
                );

            that.\$bsContainer.addClass(\$element.attr('class').replace(/form-control|fit-width/gi, '')).toggleClass(classNames.DROPUP, \$element.hasClass(classNames.DROPUP));
            pos = \$element.offset();

            if (!\$container.is('body')) {
              containerPos = \$container.offset();
              containerPos.top += parseInt(\$container.css('borderTopWidth')) - \$container.scrollTop();
              containerPos.left += parseInt(\$container.css('borderLeftWidth')) - \$container.scrollLeft();
            } else {
              containerPos = { top: 0, left: 0 };
            }

            actualHeight = \$element.hasClass(classNames.DROPUP) ? 0 : \$element[0].offsetHeight;

            // Bootstrap 4+ uses Popper for menu positioning
            if (version.major < 4 || display === 'static') {
              containerPosition.top = pos.top - containerPos.top + actualHeight;
              containerPosition.left = pos.left - containerPos.left;
            }

            containerPosition.width = \$element[0].offsetWidth;

            that.\$bsContainer.css(containerPosition);
          };

      this.\$button.on('click.bs.dropdown.data-api', function () {
        if (that.isDisabled()) {
          return;
        }

        getPlacement(that.\$newElement);

        that.\$bsContainer
          .appendTo(that.options.container)
          .toggleClass(classNames.SHOW, !that.\$button.hasClass(classNames.SHOW))
          .append(that.\$menu);
      });

      \$(window)
        .off('resize' + EVENT_KEY + '.' + this.selectId + ' scroll' + EVENT_KEY + '.' + this.selectId)
        .on('resize' + EVENT_KEY + '.' + this.selectId + ' scroll' + EVENT_KEY + '.' + this.selectId, function () {
          var isActive = that.\$newElement.hasClass(classNames.SHOW);

          if (isActive) getPlacement(that.\$newElement);
        });

      this.\$element.on('hide' + EVENT_KEY, function () {
        that.\$menu.data('height', that.\$menu.height());
        that.\$bsContainer.detach();
      });
    },

    createOption: function (data, init) {
      var optionData = !data.option ? data : data.option;

      if (optionData && optionData.nodeType !== 1) {
        var option = (init ? elementTemplates.selectedOption : elementTemplates.option).cloneNode(true);
        if (optionData.value !== undefined) option.value = optionData.value;
        option.textContent = optionData.text;

        option.selected = true;

        if (optionData.liIndex !== undefined) {
          option.liIndex = optionData.liIndex;
        } else if (!init) {
          option.liIndex = data.index;
        }

        data.option = option;

        this.selectpicker.main.optionQueue.appendChild(option);
      }
    },

    setOptionStatus: function (selectedOnly) {
      var that = this;

      that.noScroll = false;

      if (that.selectpicker.view.visibleElements && that.selectpicker.view.visibleElements.length) {
        for (var i = 0; i < that.selectpicker.view.visibleElements.length; i++) {
          var liData = that.selectpicker.current.data[i + that.selectpicker.view.position0],
              option = liData.option;

          if (option) {
            if (selectedOnly !== true) {
              that.setDisabled(liData);
            }

            that.setSelected(liData);
          }
        }

        // append optionQueue (documentFragment with option elements for select options)
        if (this.options.source.data) this.\$element[0].appendChild(this.selectpicker.main.optionQueue);
      }
    },

    /**
     * @param {number} index - the index of the option that is being changed
     * @param {boolean} selected - true if the option is being selected, false if being deselected
     */
    setSelected: function (liData, selected) {
      selected = selected === undefined ? liData.selected : selected;

      var index = liData.index,
          li = liData.element,
          activeIndexIsSet = this.activeIndex !== undefined,
          thisIsActive = this.activeIndex === index,
          prevActive,
          a,
          // if current option is already active
          // OR
          // if the current option is being selected, it's NOT multiple, and
          // activeIndex is undefined:
          //  - when the menu is first being opened, OR
          //  - after a search has been performed, OR
          //  - when retainActive is false when selecting a new option (i.e. index of the newly selected option is not the same as the current activeIndex)
          keepActive = thisIsActive || (selected && !this.multiple && !activeIndexIsSet);

      if (!li) return;

      if (selected !== undefined) {
        liData.selected = selected;
        if (liData.option) liData.option.selected = selected;
      }

      if (selected && this.options.source.data) {
        this.createOption(liData, false);
      }

      a = li.firstChild;

      if (selected) {
        this.selectedIndex = index;
      }

      li.classList.toggle('selected', selected);

      if (keepActive) {
        this.focusItem(li, liData);
        this.selectpicker.view.currentActive = li;
        this.activeIndex = index;
      } else {
        this.defocusItem(li);
      }

      if (a) {
        a.classList.toggle('selected', selected);

        if (selected) {
          a.setAttribute('aria-selected', true);
        } else {
          if (this.multiple) {
            a.setAttribute('aria-selected', false);
          } else {
            a.removeAttribute('aria-selected');
          }
        }
      }

      if (!keepActive && !activeIndexIsSet && selected && this.prevActiveIndex !== undefined) {
        prevActive = this.selectpicker.main.elements[this.prevActiveIndex];

        this.defocusItem(prevActive);
      }
    },

    /**
     * @param {number} index - the index of the option that is being disabled
     * @param {boolean} disabled - true if the option is being disabled, false if being enabled
     */
    setDisabled: function (liData) {
      var disabled = liData.disabled,
          li = liData.element,
          a;

      if (!li) return;

      a = li.firstChild;

      li.classList.toggle(classNames.DISABLED, disabled);

      if (a) {
        if (version.major >= '4') a.classList.toggle(classNames.DISABLED, disabled);

        if (disabled) {
          a.setAttribute('aria-disabled', disabled);
          a.setAttribute('tabindex', -1);
        } else {
          a.removeAttribute('aria-disabled');
          a.setAttribute('tabindex', 0);
        }
      }
    },

    isDisabled: function () {
      return this.\$element[0].disabled;
    },

    checkDisabled: function () {
      if (this.isDisabled()) {
        this.\$newElement[0].classList.add(classNames.DISABLED);
        this.\$button.addClass(classNames.DISABLED).attr('aria-disabled', true);
      } else {
        if (this.\$button[0].classList.contains(classNames.DISABLED)) {
          this.\$newElement[0].classList.remove(classNames.DISABLED);
          this.\$button.removeClass(classNames.DISABLED).attr('aria-disabled', false);
        }
      }
    },

    clickListener: function () {
      var that = this,
          \$document = \$(document);

      \$document.data('spaceSelect', false);

      this.\$button.on('keyup', function (e) {
        if (/(32)/.test(e.keyCode.toString(10)) && \$document.data('spaceSelect')) {
          e.preventDefault();
          \$document.data('spaceSelect', false);
        }
      });

      this.\$newElement.on('show.bs.dropdown', function () {
        if (!that.dropdown && version.major === '4') {
          that.dropdown = that.\$button.data('bs.dropdown');
          that.dropdown._menu = that.\$menu[0];
        }
      });

      function clearSelection (e) {
        if (that.multiple) {
          that.deselectAll();
        } else {
          var element = that.\$element[0],
              prevValue = element.value,
              prevIndex = element.selectedIndex,
              prevOption = element.options[prevIndex],
              prevData = prevOption ? that.selectpicker.main.data[prevOption.liIndex] : false;

          if (prevData) {
            that.setSelected(prevData, false);
          }

          element.selectedIndex = 0;

          changedArguments = [prevIndex, false, prevValue];
          that.\$element.triggerNative('change');
        }

        // remove selected styling if menu is open
        if (that.\$newElement.hasClass(classNames.SHOW)) {
          if (that.options.liveSearch) {
            that.\$searchbox.trigger('focus');
          }

          that.createView(false);
        }
      }

      this.\$button.on('click.bs.dropdown.data-api', function (e) {
        if (that.options.allowClear) {
          var target = e.target,
              clearButton = that.\$clearButton[0];

          // IE doesn't support event listeners on child elements of buttons
          if (/MSIE|Trident/.test(window.navigator.userAgent)) {
            target = document.elementFromPoint(e.clientX, e.clientY);
          }

          if (target === clearButton || target.parentElement === clearButton) {
            e.stopImmediatePropagation();
            clearSelection(e);
          }
        }

        if (!that.\$newElement.hasClass(classNames.SHOW)) {
          that.setSize();
        }
      });

      function setFocus () {
        if (that.options.liveSearch) {
          that.\$searchbox.trigger('focus');
        } else {
          that.\$menuInner.trigger('focus');
        }
      }

      function checkPopperExists () {
        if (that.dropdown && that.dropdown._popper && that.dropdown._popper.state) {
          setFocus();
        } else {
          requestAnimationFrame(checkPopperExists);
        }
      }

      this.\$element.on('shown' + EVENT_KEY, function () {
        if (that.\$menuInner[0].scrollTop !== that.selectpicker.view.scrollTop) {
          that.\$menuInner[0].scrollTop = that.selectpicker.view.scrollTop;
        }

        if (version.major > 3) {
          requestAnimationFrame(checkPopperExists);
        } else {
          setFocus();
        }
      });

      // ensure posinset and setsize are correct before selecting an option via a click
      this.\$menuInner.on('mouseenter', 'li a', function (e) {
        var hoverLi = this.parentElement,
            position0 = that.isVirtual() ? that.selectpicker.view.position0 : 0,
            index = Array.prototype.indexOf.call(hoverLi.parentElement.children, hoverLi),
            hoverData = that.selectpicker.current.data[index + position0];

        that.focusItem(hoverLi, hoverData, true);
      });

      this.\$menuInner.on('click', 'li a', function (e, retainActive) {
        var \$this = \$(this),
            element = that.\$element[0],
            position0 = that.isVirtual() ? that.selectpicker.view.position0 : 0,
            clickedData = that.selectpicker.current.data[\$this.parent().index() + position0],
            clickedIndex = clickedData.index,
            prevValue = getSelectValues.call(that),
            prevIndex = element.selectedIndex,
            prevOption = element.options[prevIndex],
            prevData = prevOption ? that.selectpicker.main.data[prevOption.liIndex] : false,
            triggerChange = true;

        // Don't close on multi choice menu
        if (that.multiple && that.options.maxOptions !== 1) {
          e.stopPropagation();
        }

        e.preventDefault();

        // Don't run if the select is disabled
        if (!that.isDisabled() && !\$this.parent().hasClass(classNames.DISABLED)) {
          var option = clickedData.option,
              \$option = \$(option),
              state = option.selected,
              \$optgroup = \$option.parent('optgroup'),
              \$optgroupOptions = \$optgroup.find('option'),
              maxOptions = that.options.maxOptions,
              maxOptionsGrp = \$optgroup.data('maxOptions') || false;

          if (clickedIndex === that.activeIndex) retainActive = true;

          if (!retainActive) {
            that.prevActiveIndex = that.activeIndex;
            that.activeIndex = undefined;
          }

          if (!that.multiple) { // Deselect previous option if not multi select
            if (prevData) that.setSelected(prevData, false);
            that.setSelected(clickedData, true);
          } else { // Toggle the clicked option if multi select.
            that.setSelected(clickedData, !state);
            that.focusedParent.focus();

            if (maxOptions !== false || maxOptionsGrp !== false) {
              var maxReached = maxOptions < getSelectedOptions.call(that).length,
                  maxReachedGrp = maxOptionsGrp < \$optgroup.find('option:selected').length;

              if ((maxOptions && maxReached) || (maxOptionsGrp && maxReachedGrp)) {
                if (maxOptions && maxOptions == 1) {
                  element.selectedIndex = -1;
                  option.selected = true;
                  that.setOptionStatus(true);
                } else if (maxOptionsGrp && maxOptionsGrp == 1) {
                  for (var i = 0; i < \$optgroupOptions.length; i++) {
                    var _option = \$optgroupOptions[i];
                    _option.selected = false;
                    that.setSelected(_option.liIndex, false);
                  }

                  option.selected = true;
                  that.setSelected(clickedIndex, true);
                } else {
                  var maxOptionsText = typeof that.options.maxOptionsText === 'string' ? [that.options.maxOptionsText, that.options.maxOptionsText] : that.options.maxOptionsText,
                      maxOptionsArr = typeof maxOptionsText === 'function' ? maxOptionsText(maxOptions, maxOptionsGrp) : maxOptionsText,
                      maxTxt = maxOptionsArr[0].replace('{n}', maxOptions),
                      maxTxtGrp = maxOptionsArr[1].replace('{n}', maxOptionsGrp),
                      \$notify = \$('<div class=\"notify\"></div>');
                  // If {var} is set in array, replace it
                  /** @deprecated */
                  if (maxOptionsArr[2]) {
                    maxTxt = maxTxt.replace('{var}', maxOptionsArr[2][maxOptions > 1 ? 0 : 1]);
                    maxTxtGrp = maxTxtGrp.replace('{var}', maxOptionsArr[2][maxOptionsGrp > 1 ? 0 : 1]);
                  }

                  option.selected = false;

                  that.\$menu.append(\$notify);

                  if (maxOptions && maxReached) {
                    \$notify.append(\$('<div>' + maxTxt + '</div>'));
                    triggerChange = false;
                    that.\$element.trigger('maxReached' + EVENT_KEY);
                  }

                  if (maxOptionsGrp && maxReachedGrp) {
                    \$notify.append(\$('<div>' + maxTxtGrp + '</div>'));
                    triggerChange = false;
                    that.\$element.trigger('maxReachedGrp' + EVENT_KEY);
                  }

                  setTimeout(function () {
                    that.setSelected(clickedIndex, false);
                  }, 10);

                  \$notify[0].classList.add('fadeOut');

                  setTimeout(function () {
                    \$notify.remove();
                  }, 1050);
                }
              }
            }
          }

          if (that.options.source.data) that.\$element[0].appendChild(that.selectpicker.main.optionQueue);

          if (!that.multiple || (that.multiple && that.options.maxOptions === 1)) {
            that.\$button.trigger('focus');
          } else if (that.options.liveSearch) {
            that.\$searchbox.trigger('focus');
          }

          // Trigger select 'change'
          if (triggerChange) {
            if (that.multiple || prevIndex !== element.selectedIndex) {
              // \$option.prop('selected') is current option state (selected/unselected). prevValue is the value of the select prior to being changed.
              changedArguments = [option.index, \$option.prop('selected'), prevValue];
              that.\$element
                .triggerNative('change');
            }
          }
        }
      });

      this.\$menu.on('click', 'li.' + classNames.DISABLED + ' a, .' + classNames.POPOVERHEADER + ', .' + classNames.POPOVERHEADER + ' :not(.close)', function (e) {
        if (e.currentTarget == this) {
          e.preventDefault();
          e.stopPropagation();
          if (that.options.liveSearch && !\$(e.target).hasClass('close')) {
            that.\$searchbox.trigger('focus');
          } else {
            that.\$button.trigger('focus');
          }
        }
      });

      this.\$menuInner.on('click', '.divider, .dropdown-header', function (e) {
        e.preventDefault();
        e.stopPropagation();
        if (that.options.liveSearch) {
          that.\$searchbox.trigger('focus');
        } else {
          that.\$button.trigger('focus');
        }
      });

      this.\$menu.on('click', '.' + classNames.POPOVERHEADER + ' .close', function () {
        that.\$button.trigger('click');
      });

      this.\$searchbox.on('click', function (e) {
        e.stopPropagation();
      });

      this.\$menu.on('click', '.actions-btn', function (e) {
        if (that.options.liveSearch) {
          that.\$searchbox.trigger('focus');
        } else {
          that.\$button.trigger('focus');
        }

        e.preventDefault();
        e.stopPropagation();

        if (\$(this).hasClass('bs-select-all')) {
          that.selectAll();
        } else {
          that.deselectAll();
        }
      });

      this.\$button
        .on('focus' + EVENT_KEY, function (e) {
          var tabindex = that.\$element[0].getAttribute('tabindex');

          // only change when button is actually focused
          if (tabindex !== undefined && e.originalEvent && e.originalEvent.isTrusted) {
            // apply select element's tabindex to ensure correct order is followed when tabbing to the next element
            this.setAttribute('tabindex', tabindex);
            // set element's tabindex to -1 to allow for reverse tabbing
            that.\$element[0].setAttribute('tabindex', -1);
            that.selectpicker.view.tabindex = tabindex;
          }
        })
        .on('blur' + EVENT_KEY, function (e) {
          // revert everything to original tabindex
          if (that.selectpicker.view.tabindex !== undefined && e.originalEvent && e.originalEvent.isTrusted) {
            that.\$element[0].setAttribute('tabindex', that.selectpicker.view.tabindex);
            this.setAttribute('tabindex', -1);
            that.selectpicker.view.tabindex = undefined;
          }
        });

      this.\$element
        .on('change' + EVENT_KEY, function () {
          that.render();
          that.\$element.trigger('changed' + EVENT_KEY, changedArguments);
          changedArguments = null;
        })
        .on('focus' + EVENT_KEY, function () {
          if (!that.options.mobile) that.\$button[0].focus();
        });
    },

    liveSearchListener: function () {
      var that = this;

      this.\$button.on('click.bs.dropdown.data-api', function () {
        if (!!that.\$searchbox.val()) {
          that.\$searchbox.val('');
          that.selectpicker.search.previousValue = undefined;
        }
      });

      this.\$searchbox.on('click.bs.dropdown.data-api focus.bs.dropdown.data-api touchend.bs.dropdown.data-api', function (e) {
        e.stopPropagation();
      });

      this.\$searchbox.on('input propertychange', function () {
        var searchValue = that.\$searchbox[0].value;

        that.selectpicker.search.elements = [];
        that.selectpicker.search.data = [];

        if (searchValue) {
          if (that.options.source.search) {
            that.fetchData(function (builtData) {
              that.render();
              that.buildList(undefined, true);
              that.createView(true);
              showNoResults.call(that, builtData, searchValue);
            }, 'search', 0, searchValue);
          } else {
            var i,
                searchMatch = [],
                q = searchValue.toUpperCase(),
                cache = {},
                cacheArr = [],
                searchStyle = that._searchStyle(),
                normalizeSearch = that.options.liveSearchNormalize;

            if (normalizeSearch) q = normalizeToBase(q);

            for (var i = 0; i < that.selectpicker.main.data.length; i++) {
              var li = that.selectpicker.main.data[i];

              if (!cache[i]) {
                cache[i] = stringSearch(li, q, searchStyle, normalizeSearch);
              }

              if (cache[i] && li.headerIndex !== undefined && cacheArr.indexOf(li.headerIndex) === -1) {
                if (li.headerIndex > 0) {
                  cache[li.headerIndex - 1] = true;
                  cacheArr.push(li.headerIndex - 1);
                }

                cache[li.headerIndex] = true;
                cacheArr.push(li.headerIndex);

                cache[li.lastIndex + 1] = true;
              }

              if (cache[i] && li.type !== 'optgroup-label') cacheArr.push(i);
            }

            for (var i = 0, cacheLen = cacheArr.length; i < cacheLen; i++) {
              var index = cacheArr[i],
                  prevIndex = cacheArr[i - 1],
                  li = that.selectpicker.main.data[index],
                  liPrev = that.selectpicker.main.data[prevIndex];

              if (li.type !== 'divider' || (li.type === 'divider' && liPrev && liPrev.type !== 'divider' && cacheLen - 1 !== i)) {
                that.selectpicker.search.data.push(li);
                searchMatch.push(that.selectpicker.main.elements[index]);
              }
            }

            that.activeIndex = undefined;
            that.noScroll = true;
            that.\$menuInner.scrollTop(0);
            that.selectpicker.search.elements = searchMatch;
            that.createView(true);
            showNoResults.call(that, searchMatch, searchValue);
          }
        } else if (that.selectpicker.search.previousValue) { // for IE11 (#2402)
          that.\$menuInner.scrollTop(0);
          that.createView(false);
        }

        that.selectpicker.search.previousValue =  searchValue;
      });
    },

    _searchStyle: function () {
      return this.options.liveSearchStyle || 'contains';
    },

    val: function (value) {
      var element = this.\$element[0];

      if (typeof value !== 'undefined') {
        var selectedOptions = getSelectedOptions.call(this),
            prevValue = getSelectValues.call(this, selectedOptions);

        changedArguments = [null, null, prevValue];

        if (!Array.isArray(value)) value = [ value ];

        value.map(String);

        for (var i = 0; i < selectedOptions.length; i++) {
          var item = selectedOptions[i];

          if (item && value.indexOf(String(item.value)) === -1) {
            this.setSelected(item, false);
          }
        }

        // only update selected value if it matches an existing option
        this.selectpicker.main.data.filter(function (item) {
          if (value.indexOf(String(item.value)) !== -1) {
            this.setSelected(item, true);
            return true;
          }

          return false;
        }, this);

        if (this.options.source.data) element.appendChild(this.selectpicker.main.optionQueue);

        this.\$element.trigger('changed' + EVENT_KEY, changedArguments);

        if (this.\$newElement.hasClass(classNames.SHOW)) {
          if (this.multiple) {
            this.setOptionStatus(true);
          } else {
            var liSelectedIndex = (element.options[element.selectedIndex] || {}).liIndex;

            if (typeof liSelectedIndex === 'number') {
              this.setSelected(this.selectedIndex, false);
              this.setSelected(liSelectedIndex, true);
            }
          }
        }

        this.render();

        changedArguments = null;

        return this.\$element;
      } else {
        return this.\$element.val();
      }
    },

    changeAll: function (status) {
      if (!this.multiple) return;
      if (typeof status === 'undefined') status = true;

      var element = this.\$element[0],
          previousSelected = 0,
          currentSelected = 0,
          prevValue = getSelectValues.call(this);

      element.classList.add('bs-select-hidden');

      for (var i = 0, data = this.selectpicker.current.data, len = data.length; i < len; i++) {
        var liData = data[i],
            option = liData.option;

        if (option && !liData.disabled && liData.type !== 'divider') {
          if (liData.selected) previousSelected++;
          option.selected = status;
          liData.selected = status;
          if (status === true) currentSelected++;
        }
      }

      element.classList.remove('bs-select-hidden');

      if (previousSelected === currentSelected) return;

      this.setOptionStatus();

      changedArguments = [null, null, prevValue];

      this.\$element
        .triggerNative('change');
    },

    selectAll: function () {
      return this.changeAll(true);
    },

    deselectAll: function () {
      return this.changeAll(false);
    },

    toggle: function (e, state) {
      var isActive,
          triggerClick = state === undefined;

      e = e || window.event;

      if (e) e.stopPropagation();

      if (triggerClick === false) {
        isActive = this.\$newElement[0].classList.contains(classNames.SHOW);
        triggerClick = state === true && isActive === false || state === false && isActive === true;
      }

      if (triggerClick) this.\$button.trigger('click.bs.dropdown.data-api');
    },

    open: function (e) {
      this.toggle(e, true);
    },

    close: function (e) {
      this.toggle(e, false);
    },

    keydown: function (e) {
      var \$this = \$(this),
          isToggle = \$this.hasClass('dropdown-toggle'),
          \$parent = isToggle ? \$this.closest('.dropdown') : \$this.closest(Selector.MENU),
          that = \$parent.data('this'),
          \$items = that.findLis(),
          index,
          isActive,
          liActive,
          activeLi,
          offset,
          updateScroll = false,
          downOnTab = e.which === keyCodes.TAB && !isToggle && !that.options.selectOnTab,
          isArrowKey = REGEXP_ARROW.test(e.which) || downOnTab,
          scrollTop = that.\$menuInner[0].scrollTop,
          isVirtual = that.isVirtual(),
          position0 = isVirtual === true ? that.selectpicker.view.position0 : 0;

      // do nothing if a function key is pressed
      if (e.which >= 112 && e.which <= 123) return;

      isActive = that.\$menu.hasClass(classNames.SHOW);

      if (
        !isActive &&
        (
          isArrowKey ||
          (e.which >= 48 && e.which <= 57) ||
          (e.which >= 96 && e.which <= 105) ||
          (e.which >= 65 && e.which <= 90)
        )
      ) {
        that.\$button.trigger('click.bs.dropdown.data-api');

        if (that.options.liveSearch) {
          that.\$searchbox.trigger('focus');
          return;
        }
      }

      if (e.which === keyCodes.ESCAPE && isActive) {
        e.preventDefault();
        that.\$button.trigger('click.bs.dropdown.data-api').trigger('focus');
      }

      if (isArrowKey) { // if up or down
        if (!\$items.length) return;

        liActive = that.selectpicker.main.elements[that.activeIndex];
        index = liActive ? Array.prototype.indexOf.call(liActive.parentElement.children, liActive) : -1;

        if (index !== -1) {
          that.defocusItem(liActive);
        }

        if (e.which === keyCodes.ARROW_UP) { // up
          if (index !== -1) index--;
          if (index + position0 < 0) index += \$items.length;

          if (!that.selectpicker.view.canHighlight[index + position0]) {
            index = that.selectpicker.view.canHighlight.slice(0, index + position0).lastIndexOf(true) - position0;
            if (index === -1) index = \$items.length - 1;
          }
        } else if (e.which === keyCodes.ARROW_DOWN || downOnTab) { // down
          index++;
          if (index + position0 >= that.selectpicker.view.canHighlight.length) index = that.selectpicker.view.firstHighlightIndex;

          if (!that.selectpicker.view.canHighlight[index + position0]) {
            index = index + 1 + that.selectpicker.view.canHighlight.slice(index + position0 + 1).indexOf(true);
          }
        }

        e.preventDefault();

        var liActiveIndex = position0 + index;

        if (e.which === keyCodes.ARROW_UP) { // up
          // scroll to bottom and highlight last option
          if (position0 === 0 && index === \$items.length - 1) {
            that.\$menuInner[0].scrollTop = that.\$menuInner[0].scrollHeight;

            liActiveIndex = that.selectpicker.current.elements.length - 1;
          } else {
            activeLi = that.selectpicker.current.data[liActiveIndex];
            offset = activeLi.position - activeLi.height;

            updateScroll = offset < scrollTop;
          }
        } else if (e.which === keyCodes.ARROW_DOWN || downOnTab) { // down
          // scroll to top and highlight first option
          if (index === that.selectpicker.view.firstHighlightIndex) {
            that.\$menuInner[0].scrollTop = 0;

            liActiveIndex = that.selectpicker.view.firstHighlightIndex;
          } else {
            activeLi = that.selectpicker.current.data[liActiveIndex];
            offset = activeLi.position - that.sizeInfo.menuInnerHeight;

            updateScroll = offset > scrollTop;
          }
        }

        liActive = that.selectpicker.current.elements[liActiveIndex];

        that.activeIndex = that.selectpicker.current.data[liActiveIndex].index;

        that.focusItem(liActive);

        that.selectpicker.view.currentActive = liActive;

        if (updateScroll) that.\$menuInner[0].scrollTop = offset;

        if (that.options.liveSearch) {
          that.\$searchbox.trigger('focus');
        } else {
          \$this.trigger('focus');
        }
      } else if (
        (!\$this.is('input') && !REGEXP_TAB_OR_ESCAPE.test(e.which)) ||
        (e.which === keyCodes.SPACE && that.selectpicker.keydown.keyHistory)
      ) {
        var searchMatch,
            matches = [],
            keyHistory;

        e.preventDefault();

        that.selectpicker.keydown.keyHistory += keyCodeMap[e.which];

        if (that.selectpicker.keydown.resetKeyHistory.cancel) clearTimeout(that.selectpicker.keydown.resetKeyHistory.cancel);
        that.selectpicker.keydown.resetKeyHistory.cancel = that.selectpicker.keydown.resetKeyHistory.start();

        keyHistory = that.selectpicker.keydown.keyHistory;

        // if all letters are the same, set keyHistory to just the first character when searching
        if (/^(.)\\1+\$/.test(keyHistory)) {
          keyHistory = keyHistory.charAt(0);
        }

        // find matches
        for (var i = 0; i < that.selectpicker.current.data.length; i++) {
          var li = that.selectpicker.current.data[i],
              hasMatch;

          hasMatch = stringSearch(li, keyHistory, 'startsWith', true);

          if (hasMatch && that.selectpicker.view.canHighlight[i]) {
            matches.push(li.index);
          }
        }

        if (matches.length) {
          var matchIndex = 0;

          \$items.removeClass('active').find('a').removeClass('active');

          // either only one key has been pressed or they are all the same key
          if (keyHistory.length === 1) {
            matchIndex = matches.indexOf(that.activeIndex);

            if (matchIndex === -1 || matchIndex === matches.length - 1) {
              matchIndex = 0;
            } else {
              matchIndex++;
            }
          }

          searchMatch = matches[matchIndex];

          activeLi = that.selectpicker.main.data[searchMatch];

          if (scrollTop - activeLi.position > 0) {
            offset = activeLi.position - activeLi.height;
            updateScroll = true;
          } else {
            offset = activeLi.position - that.sizeInfo.menuInnerHeight;
            // if the option is already visible at the current scroll position, just keep it the same
            updateScroll = activeLi.position > scrollTop + that.sizeInfo.menuInnerHeight;
          }

          liActive = that.selectpicker.main.elements[searchMatch];

          that.activeIndex = matches[matchIndex];

          that.focusItem(liActive);

          if (liActive) liActive.firstChild.focus();

          if (updateScroll) that.\$menuInner[0].scrollTop = offset;

          \$this.trigger('focus');
        }
      }

      // Select focused option if \"Enter\", \"Spacebar\" or \"Tab\" (when selectOnTab is true) are pressed inside the menu.
      if (
        isActive &&
        (
          (e.which === keyCodes.SPACE && !that.selectpicker.keydown.keyHistory) ||
          e.which === keyCodes.ENTER ||
          (e.which === keyCodes.TAB && that.options.selectOnTab)
        )
      ) {
        if (e.which !== keyCodes.SPACE) e.preventDefault();

        if (!that.options.liveSearch || e.which !== keyCodes.SPACE) {
          that.\$menuInner.find('.active a').trigger('click', true); // retain active class
          \$this.trigger('focus');

          if (!that.options.liveSearch) {
            // Prevent screen from scrolling if the user hits the spacebar
            e.preventDefault();
            // Fixes spacebar selection of dropdown items in FF & IE
            \$(document).data('spaceSelect', true);
          }
        }
      }
    },

    mobile: function () {
      // ensure mobile is set to true if mobile function is called after init
      this.options.mobile = true;
      this.\$element[0].classList.add('mobile-device');
    },

    refresh: function () {
      var that = this;
      // update options if data attributes have been changed
      var config = \$.extend({}, this.options, getAttributesObject(this.\$element), this.\$element.data()); // in this order on refresh, as user may change attributes on select, and options object is not passed on refresh
      this.options = config;

      if (this.options.source.data) {
        this.render();
        this.buildList();
      } else {
        this.fetchData(function () {
          that.render();
          that.buildList();
        });
      }

      this.checkDisabled();
      this.setStyle();
      this.setWidth();

      this.setSize(true);

      this.\$element.trigger('refreshed' + EVENT_KEY);
    },

    hide: function () {
      this.\$newElement.hide();
    },

    show: function () {
      this.\$newElement.show();
    },

    remove: function () {
      this.\$newElement.remove();
      this.\$element.remove();
    },

    destroy: function () {
      this.\$newElement.before(this.\$element).remove();

      if (this.\$bsContainer) {
        this.\$bsContainer.remove();
      } else {
        this.\$menu.remove();
      }

      if (this.selectpicker.view.titleOption && this.selectpicker.view.titleOption.parentNode) {
        this.selectpicker.view.titleOption.parentNode.removeChild(this.selectpicker.view.titleOption);
      }

      this.\$element
        .off(EVENT_KEY)
        .removeData('selectpicker')
        .removeClass('bs-select-hidden selectpicker');

      \$(window).off(EVENT_KEY + '.' + this.selectId);
    }
  };

  // SELECTPICKER PLUGIN DEFINITION
  // ==============================
  function Plugin (option) {
    // get the args of the outer function..
    var args = arguments;
    // The arguments of the function are explicitly re-defined from the argument list, because the shift causes them
    // to get lost/corrupted in android 2.3 and IE9 #715 #775
    var _option = option;

    [].shift.apply(args);

    // if the version was not set successfully
    if (!version.success) {
      // try to retreive it again
      try {
        version.full = (getVersion() || '').split(' ')[0].split('.');
      } catch (err) {
        // fall back to use BootstrapVersion if set
        if (Selectpicker.BootstrapVersion) {
          version.full = Selectpicker.BootstrapVersion.split(' ')[0].split('.');
        } else {
          version.full = [version.major, '0', '0'];

          console.warn(
            'There was an issue retrieving Bootstrap\\'s version. ' +
            'Ensure Bootstrap is being loaded before bootstrap-select and there is no namespace collision. ' +
            'If loading Bootstrap asynchronously, the version may need to be manually specified via \$.fn.selectpicker.Constructor.BootstrapVersion.',
            err
          );
        }
      }

      version.major = version.full[0];
      version.success = true;
    }

    if (version.major >= '4') {
      // some defaults need to be changed if using Bootstrap 4
      // check to see if they have already been manually changed before forcing them to update
      var toUpdate = [];

      if (Selectpicker.DEFAULTS.style === classNames.BUTTONCLASS) toUpdate.push({ name: 'style', className: 'BUTTONCLASS' });
      if (Selectpicker.DEFAULTS.iconBase === classNames.ICONBASE) toUpdate.push({ name: 'iconBase', className: 'ICONBASE' });
      if (Selectpicker.DEFAULTS.tickIcon === classNames.TICKICON) toUpdate.push({ name: 'tickIcon', className: 'TICKICON' });

      classNames.DIVIDER = 'dropdown-divider';
      classNames.SHOW = 'show';
      classNames.BUTTONCLASS = 'btn-light';
      classNames.POPOVERHEADER = 'popover-header';
      classNames.ICONBASE = '';
      classNames.TICKICON = 'bs-ok-default';

      for (var i = 0; i < toUpdate.length; i++) {
        var option = toUpdate[i];
        Selectpicker.DEFAULTS[option.name] = classNames[option.className];
      }
    }

    if (version.major > '4') {
      Selector.DATA_TOGGLE = 'data-bs-toggle=\"dropdown\"'
    }

    var value;
    var chain = this.each(function () {
      var \$this = \$(this);
      if (\$this.is('select')) {
        var data = \$this.data('selectpicker'),
            options = typeof _option == 'object' && _option;

        // for backwards compatibility
        // (using title as placeholder is deprecated - remove in v2.0.0)
        if (options.title) options.placeholder = options.title;

        if (!data) {
          var dataAttributes = \$this.data();

          for (var dataAttr in dataAttributes) {
            if (Object.prototype.hasOwnProperty.call(dataAttributes, dataAttr) && \$.inArray(dataAttr, DISALLOWED_ATTRIBUTES) !== -1) {
              delete dataAttributes[dataAttr];
            }
          }

          var config = \$.extend({}, Selectpicker.DEFAULTS, \$.fn.selectpicker.defaults || {}, getAttributesObject(\$this), dataAttributes, options); // this is correct order on initial render
          config.template = \$.extend({}, Selectpicker.DEFAULTS.template, (\$.fn.selectpicker.defaults ? \$.fn.selectpicker.defaults.template : {}), dataAttributes.template, options.template);
          \$this.data('selectpicker', (data = new Selectpicker(this, config)));
        } else if (options) {
          for (var i in options) {
            if (Object.prototype.hasOwnProperty.call(options, i)) {
              data.options[i] = options[i];
            }
          }
        }

        if (typeof _option == 'string') {
          if (data[_option] instanceof Function) {
            value = data[_option].apply(data, args);
          } else {
            value = data.options[_option];
          }
        }
      }
    });

    if (typeof value !== 'undefined') {
      // noinspection JSUnusedAssignment
      return value;
    } else {
      return chain;
    }
  }

  var old = \$.fn.selectpicker;
  \$.fn.selectpicker = Plugin;
  \$.fn.selectpicker.Constructor = Selectpicker;

  // SELECTPICKER NO CONFLICT
  // ========================
  \$.fn.selectpicker.noConflict = function () {
    \$.fn.selectpicker = old;
    return this;
  };

  // get Bootstrap's keydown event handler for either Bootstrap 4 or Bootstrap 3
  function keydownHandler () {
    if (version.major < 5) {
      if (\$.fn.dropdown) {
        // wait to define until function is called in case Bootstrap isn't loaded yet
        var bootstrapKeydown = \$.fn.dropdown.Constructor._dataApiKeydownHandler || \$.fn.dropdown.Constructor.prototype.keydown;
        return bootstrapKeydown.apply(this, arguments);
      }
    } else {
      return Dropdown.dataApiKeydownHandler;
    }
  }

  \$(document)
    .off('keydown.bs.dropdown.data-api')
    .on('keydown.bs.dropdown.data-api', ':not(.bootstrap-select) > [' + Selector.DATA_TOGGLE + ']', keydownHandler)
    .on('keydown.bs.dropdown.data-api', ':not(.bootstrap-select) > .dropdown-menu', keydownHandler)
    .on('keydown' + EVENT_KEY, '.bootstrap-select [' + Selector.DATA_TOGGLE + '], .bootstrap-select [role=\"listbox\"], .bootstrap-select .bs-searchbox input', Selectpicker.prototype.keydown)
    .on('focusin.modal', '.bootstrap-select [' + Selector.DATA_TOGGLE + '], .bootstrap-select [role=\"listbox\"], .bootstrap-select .bs-searchbox input', function (e) {
      e.stopPropagation();
    });

  // SELECTPICKER DATA-API
  // =====================
  document.addEventListener('DOMContentLoaded', function () {
    \$('.selectpicker').each(function () {
      var \$selectpicker = \$(this);
      Plugin.call(\$selectpicker, \$selectpicker.data());
    })
  });
})(jQuery);


}));
//# sourceMappingURL=bootstrap-select.js.map

/***/ })

}]);
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vLi9ub2RlX21vZHVsZXMvYm9vdHN0cmFwLXNlbGVjdC9kaXN0L2pzL2Jvb3RzdHJhcC1zZWxlY3QuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLE1BQU0sSUFBMEM7QUFDaEQ7QUFDQSxJQUFJLGlDQUFPLENBQUMseUVBQVEsQ0FBQyxtQ0FBRTtBQUN2QjtBQUNBLEtBQUs7QUFBQSxrR0FBQztBQUNOLEdBQUcsTUFBTSxFQU9OO0FBQ0gsQ0FBQzs7QUFFRDtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHVJQUF1STs7QUFFdkkscURBQXFEOztBQUVyRDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQSxzQ0FBc0MsT0FBTztBQUM3QztBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBLGdEQUFnRCxTQUFTO0FBQ3pEOztBQUVBLDZDQUE2QyxVQUFVO0FBQ3ZEO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsb0RBQW9ELFVBQVU7QUFDOUQ7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSw2QkFBNkI7QUFDN0I7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxlQUFlO0FBQ2Y7QUFDQTtBQUNBO0FBQ0EsZUFBZTtBQUNmO0FBQ0E7QUFDQSxlQUFlO0FBQ2Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUyxhQUFhO0FBQ3RCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsbUJBQW1CO0FBQ25CLHVCQUF1QjtBQUN2QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EseUJBQXlCO0FBQ3pCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1QsT0FBTztBQUNQO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0EscUJBQXFCLGdDQUFnQztBQUNyRDtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLHlDQUF5QyxTQUFTO0FBQ2xEOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7O0FBRUEsMkJBQTJCO0FBQzNCO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNULE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxtQkFBbUIsd0JBQXdCO0FBQzNDO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQSxTQUFTO0FBQ1Q7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxlQUFlO0FBQ2YsY0FBYztBQUNkLGNBQWM7QUFDZCxnQkFBZ0I7QUFDaEIsZ0JBQWdCO0FBQ2hCLGdCQUFnQjtBQUNoQjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLE9BQU87QUFDUDs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTs7QUFFQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxLQUFLO0FBQ0w7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLG9GQUFvRixFQUFFO0FBQ3RGO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1AsZ0JBQWdCO0FBQ2hCLGlCQUFpQjtBQUNqQixjQUFjO0FBQ2Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsMENBQTBDLEVBQUU7QUFDNUM7QUFDQSxvQ0FBb0MsRUFBRSxvQkFBb0IsRUFBRTtBQUM1RCxLQUFLO0FBQ0w7QUFDQTtBQUNBLHlDQUF5QyxFQUFFLCtCQUErQixFQUFFO0FBQzVFLGlEQUFpRCxFQUFFLHFDQUFxQyxFQUFFO0FBQzFGO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQSxjQUFjO0FBQ2Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsU0FBUztBQUNULE9BQU87O0FBRVA7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxTQUFTO0FBQ1QsT0FBTzs7QUFFUDs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0EsT0FBTzs7QUFFUDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7O0FBRWI7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYLFNBQVM7QUFDVDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWCxTQUFTO0FBQ1Q7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSwyRUFBMkU7QUFDM0U7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLDhIQUE4SDtBQUM5SDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDhEQUE4RDtBQUM5RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxxQkFBcUIsMkNBQTJDO0FBQ2hFO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBLDJFQUEyRTs7QUFFM0U7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxPQUFPOztBQUVQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBLDJDQUEyQztBQUMzQyxzREFBc0Q7O0FBRXRELHVCQUF1QixnQkFBZ0I7QUFDdkM7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0EsK0VBQStFO0FBQy9FLHVFQUF1RTtBQUN2RSwyRUFBMkU7O0FBRTNFO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsV0FBVztBQUNYO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsaUVBQWlFLHdCQUF3QjtBQUN6RjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLGVBQWU7QUFDZjtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSx5RUFBeUU7O0FBRXpFO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLFNBQVM7QUFDVCxLQUFLOztBQUVMO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7QUFDQTs7QUFFQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSw4REFBOEQ7O0FBRTlEO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsNERBQTREO0FBQzVEO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBOztBQUVBOztBQUVBO0FBQ0Esc0JBQXNCLGVBQWU7QUFDckM7O0FBRUE7O0FBRUE7O0FBRUEsNkNBQTZDLFNBQVM7QUFDdEQ7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYOztBQUVBO0FBQ0Esc0JBQXNCLGVBQWU7QUFDckM7QUFDQTs7QUFFQSwwREFBMEQsU0FBUztBQUNuRTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxTQUFTO0FBQ1QsdUNBQXVDO0FBQ3ZDO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBLHVEQUF1RCxTQUFTO0FBQ2hFOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSx3REFBd0QsaUNBQWlDO0FBQ3pGLE9BQU87QUFDUDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLHVDQUF1QywrQkFBK0I7QUFDdEU7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxtQkFBbUI7QUFDbkI7QUFDQTtBQUNBLG1CQUFtQjtBQUNuQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLGVBQWU7QUFDZjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLHFDQUFxQyxFQUFFLHVDQUF1QyxFQUFFO0FBQ2hGLFdBQVc7QUFDWDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxpQ0FBaUM7QUFDakM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0EsdUJBQXVCLDJDQUEyQztBQUNsRTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1Asd0JBQXdCO0FBQ3hCOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLE9BQU87QUFDUCx1QkFBdUIsdUJBQXVCO0FBQzlDO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87O0FBRVA7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPOztBQUVQO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2IsU0FBUztBQUNUO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1gsU0FBUztBQUNULE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esc0NBQXNDO0FBQ3RDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiLDhCQUE4QjtBQUM5Qjs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPOztBQUVQO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsU0FBUzs7QUFFVDtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1AsS0FBSzs7QUFFTDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBOztBQUVBOztBQUVBO0FBQ0EsdUJBQXVCLG1EQUFtRDtBQUMxRTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0EsZUFBZSxPQUFPO0FBQ3RCLGVBQWUsUUFBUTtBQUN2QjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBLGVBQWUsT0FBTztBQUN0QixlQUFlLFFBQVE7QUFDdkI7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPOztBQUVQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPOztBQUVQO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxPQUFPOztBQUVQO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQSxPQUFPOztBQUVQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLE9BQU87O0FBRVA7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsK0JBQStCO0FBQy9CO0FBQ0E7QUFDQSxXQUFXLE9BQU87QUFDbEI7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGlCQUFpQjtBQUNqQixpQ0FBaUMsNkJBQTZCO0FBQzlEO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxpQkFBaUI7QUFDakI7QUFDQTtBQUNBLDBEQUEwRCxFQUFFO0FBQzVELDZEQUE2RCxFQUFFO0FBQy9EO0FBQ0EseUJBQXlCLElBQUk7QUFDN0I7QUFDQTtBQUNBLDhDQUE4QyxJQUFJO0FBQ2xELG9EQUFvRCxJQUFJO0FBQ3hEOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsbUJBQW1COztBQUVuQjs7QUFFQTtBQUNBO0FBQ0EsbUJBQW1CO0FBQ25CO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87O0FBRVA7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYO0FBQ0E7QUFDQTtBQUNBLE9BQU87O0FBRVA7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0EsT0FBTzs7QUFFUDtBQUNBO0FBQ0EsT0FBTzs7QUFFUDtBQUNBO0FBQ0EsT0FBTzs7QUFFUDtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBLE9BQU87O0FBRVA7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTOztBQUVUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBLFNBQVM7QUFDVCxLQUFLOztBQUVMO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87O0FBRVA7QUFDQTtBQUNBLE9BQU87O0FBRVA7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiLFdBQVc7QUFDWDtBQUNBO0FBQ0E7QUFDQSwwQkFBMEI7QUFDMUI7QUFDQTtBQUNBOztBQUVBOztBQUVBLDJCQUEyQix3Q0FBd0M7QUFDbkU7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsdURBQXVELGNBQWM7QUFDckU7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVMsbURBQW1EO0FBQzVEO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLE9BQU87QUFDUCxLQUFLOztBQUVMO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHVCQUF1Qiw0QkFBNEI7QUFDbkQ7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsU0FBUzs7QUFFVDs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1gsK0VBQStFOztBQUUvRTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBLCtFQUErRSxTQUFTO0FBQ3hGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSx1QkFBdUI7QUFDdkI7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsNENBQTRDO0FBQzVDO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTLHlEQUF5RDtBQUNsRTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLDRDQUE0QztBQUM1QztBQUNBO0FBQ0E7O0FBRUE7QUFDQSxXQUFXO0FBQ1g7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsU0FBUyx5REFBeUQ7QUFDbEU7QUFDQTtBQUNBOztBQUVBO0FBQ0EsV0FBVztBQUNYO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLHVCQUF1QiwyQ0FBMkM7QUFDbEU7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsbUVBQW1FO0FBQ25FOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQSw4QkFBOEIsMEVBQTBFO0FBQ3hHOztBQUVBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxpRkFBaUYsMENBQTBDO0FBQzNILGlGQUFpRiwwQ0FBMEM7QUFDM0gsaUZBQWlGLDBDQUEwQzs7QUFFM0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLHFCQUFxQixxQkFBcUI7QUFDMUM7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLGtDQUFrQyx5REFBeUQsdURBQXVEO0FBQ2xKLHVDQUF1Qyx3R0FBd0c7QUFDL0k7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0wsR0FBRztBQUNILENBQUM7OztBQUdELENBQUM7QUFDRCw0QyIsImZpbGUiOiJ2ZW5kb3JzLW5vZGVfbW9kdWxlc19ib290c3RyYXAtc2VsZWN0X2Rpc3RfanNfYm9vdHN0cmFwLXNlbGVjdF9qcy5qcyIsInNvdXJjZXNDb250ZW50IjpbIi8qIVxyXG4gKiBCb290c3RyYXAtc2VsZWN0IHYxLjE0LjAtYmV0YTIgKGh0dHBzOi8vZGV2ZWxvcGVyLnNuYXBhcHBvaW50bWVudHMuY29tL2Jvb3RzdHJhcC1zZWxlY3QpXHJcbiAqXHJcbiAqIENvcHlyaWdodCAyMDEyLTIwMjEgU25hcEFwcG9pbnRtZW50cywgTExDXHJcbiAqIExpY2Vuc2VkIHVuZGVyIE1JVCAoaHR0cHM6Ly9naXRodWIuY29tL3NuYXBhcHBvaW50bWVudHMvYm9vdHN0cmFwLXNlbGVjdC9ibG9iL21hc3Rlci9MSUNFTlNFKVxyXG4gKi9cclxuXHJcbihmdW5jdGlvbiAocm9vdCwgZmFjdG9yeSkge1xyXG4gIGlmIChyb290ID09PSB1bmRlZmluZWQgJiYgd2luZG93ICE9PSB1bmRlZmluZWQpIHJvb3QgPSB3aW5kb3c7XHJcbiAgaWYgKHR5cGVvZiBkZWZpbmUgPT09ICdmdW5jdGlvbicgJiYgZGVmaW5lLmFtZCkge1xyXG4gICAgLy8gQU1ELiBSZWdpc3RlciBhcyBhbiBhbm9ueW1vdXMgbW9kdWxlIHVubGVzcyBhbWRNb2R1bGVJZCBpcyBzZXRcclxuICAgIGRlZmluZShbXCJqcXVlcnlcIl0sIGZ1bmN0aW9uIChhMCkge1xyXG4gICAgICByZXR1cm4gKGZhY3RvcnkoYTApKTtcclxuICAgIH0pO1xyXG4gIH0gZWxzZSBpZiAodHlwZW9mIG1vZHVsZSA9PT0gJ29iamVjdCcgJiYgbW9kdWxlLmV4cG9ydHMpIHtcclxuICAgIC8vIE5vZGUuIERvZXMgbm90IHdvcmsgd2l0aCBzdHJpY3QgQ29tbW9uSlMsIGJ1dFxyXG4gICAgLy8gb25seSBDb21tb25KUy1saWtlIGVudmlyb25tZW50cyB0aGF0IHN1cHBvcnQgbW9kdWxlLmV4cG9ydHMsXHJcbiAgICAvLyBsaWtlIE5vZGUuXHJcbiAgICBtb2R1bGUuZXhwb3J0cyA9IGZhY3RvcnkocmVxdWlyZShcImpxdWVyeVwiKSk7XHJcbiAgfSBlbHNlIHtcclxuICAgIGZhY3Rvcnkocm9vdFtcImpRdWVyeVwiXSk7XHJcbiAgfVxyXG59KHRoaXMsIGZ1bmN0aW9uIChqUXVlcnkpIHtcclxuXHJcbihmdW5jdGlvbiAoJCkge1xyXG4gICd1c2Ugc3RyaWN0JztcclxuXHJcbiAgdmFyIERJU0FMTE9XRURfQVRUUklCVVRFUyA9IFsnc2FuaXRpemUnLCAnd2hpdGVMaXN0JywgJ3Nhbml0aXplRm4nXTtcclxuXHJcbiAgdmFyIHVyaUF0dHJzID0gW1xyXG4gICAgJ2JhY2tncm91bmQnLFxyXG4gICAgJ2NpdGUnLFxyXG4gICAgJ2hyZWYnLFxyXG4gICAgJ2l0ZW10eXBlJyxcclxuICAgICdsb25nZGVzYycsXHJcbiAgICAncG9zdGVyJyxcclxuICAgICdzcmMnLFxyXG4gICAgJ3hsaW5rOmhyZWYnXHJcbiAgXTtcclxuXHJcbiAgdmFyIEFSSUFfQVRUUklCVVRFX1BBVFRFUk4gPSAvXmFyaWEtW1xcdy1dKiQvaTtcclxuXHJcbiAgdmFyIERlZmF1bHRXaGl0ZWxpc3QgPSB7XHJcbiAgICAvLyBHbG9iYWwgYXR0cmlidXRlcyBhbGxvd2VkIG9uIGFueSBzdXBwbGllZCBlbGVtZW50IGJlbG93LlxyXG4gICAgJyonOiBbJ2NsYXNzJywgJ2RpcicsICdpZCcsICdsYW5nJywgJ3JvbGUnLCAndGFiaW5kZXgnLCAnc3R5bGUnLCBBUklBX0FUVFJJQlVURV9QQVRURVJOXSxcclxuICAgIGE6IFsndGFyZ2V0JywgJ2hyZWYnLCAndGl0bGUnLCAncmVsJ10sXHJcbiAgICBhcmVhOiBbXSxcclxuICAgIGI6IFtdLFxyXG4gICAgYnI6IFtdLFxyXG4gICAgY29sOiBbXSxcclxuICAgIGNvZGU6IFtdLFxyXG4gICAgZGl2OiBbXSxcclxuICAgIGVtOiBbXSxcclxuICAgIGhyOiBbXSxcclxuICAgIGgxOiBbXSxcclxuICAgIGgyOiBbXSxcclxuICAgIGgzOiBbXSxcclxuICAgIGg0OiBbXSxcclxuICAgIGg1OiBbXSxcclxuICAgIGg2OiBbXSxcclxuICAgIGk6IFtdLFxyXG4gICAgaW1nOiBbJ3NyYycsICdhbHQnLCAndGl0bGUnLCAnd2lkdGgnLCAnaGVpZ2h0J10sXHJcbiAgICBsaTogW10sXHJcbiAgICBvbDogW10sXHJcbiAgICBwOiBbXSxcclxuICAgIHByZTogW10sXHJcbiAgICBzOiBbXSxcclxuICAgIHNtYWxsOiBbXSxcclxuICAgIHNwYW46IFtdLFxyXG4gICAgc3ViOiBbXSxcclxuICAgIHN1cDogW10sXHJcbiAgICBzdHJvbmc6IFtdLFxyXG4gICAgdTogW10sXHJcbiAgICB1bDogW11cclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEEgcGF0dGVybiB0aGF0IHJlY29nbml6ZXMgYSBjb21tb25seSB1c2VmdWwgc3Vic2V0IG9mIFVSTHMgdGhhdCBhcmUgc2FmZS5cclxuICAgKlxyXG4gICAqIFNob3V0b3V0IHRvIEFuZ3VsYXIgNyBodHRwczovL2dpdGh1Yi5jb20vYW5ndWxhci9hbmd1bGFyL2Jsb2IvNy4yLjQvcGFja2FnZXMvY29yZS9zcmMvc2FuaXRpemF0aW9uL3VybF9zYW5pdGl6ZXIudHNcclxuICAgKi9cclxuICB2YXIgU0FGRV9VUkxfUEFUVEVSTiA9IC9eKD86KD86aHR0cHM/fG1haWx0b3xmdHB8dGVsfGZpbGUpOnxbXiY6Lz8jXSooPzpbLz8jXXwkKSkvZ2k7XHJcblxyXG4gIC8qKlxyXG4gICAqIEEgcGF0dGVybiB0aGF0IG1hdGNoZXMgc2FmZSBkYXRhIFVSTHMuIE9ubHkgbWF0Y2hlcyBpbWFnZSwgdmlkZW8gYW5kIGF1ZGlvIHR5cGVzLlxyXG4gICAqXHJcbiAgICogU2hvdXRvdXQgdG8gQW5ndWxhciA3IGh0dHBzOi8vZ2l0aHViLmNvbS9hbmd1bGFyL2FuZ3VsYXIvYmxvYi83LjIuNC9wYWNrYWdlcy9jb3JlL3NyYy9zYW5pdGl6YXRpb24vdXJsX3Nhbml0aXplci50c1xyXG4gICAqL1xyXG4gIHZhciBEQVRBX1VSTF9QQVRURVJOID0gL15kYXRhOig/OmltYWdlXFwvKD86Ym1wfGdpZnxqcGVnfGpwZ3xwbmd8dGlmZnx3ZWJwKXx2aWRlb1xcLyg/Om1wZWd8bXA0fG9nZ3x3ZWJtKXxhdWRpb1xcLyg/Om1wM3xvZ2F8b2dnfG9wdXMpKTtiYXNlNjQsW2EtejAtOSsvXSs9KiQvaTtcclxuXHJcbiAgdmFyIFBhcnNlYWJsZUF0dHJpYnV0ZXMgPSBbJ3RpdGxlJywgJ3BsYWNlaG9sZGVyJ107IC8vIGF0dHJpYnV0ZXMgdG8gdXNlIGFzIHNldHRpbmdzLCBjYW4gYWRkIG90aGVycyBpbiB0aGUgZnV0dXJlXHJcblxyXG4gIGZ1bmN0aW9uIGFsbG93ZWRBdHRyaWJ1dGUgKGF0dHIsIGFsbG93ZWRBdHRyaWJ1dGVMaXN0KSB7XHJcbiAgICB2YXIgYXR0ck5hbWUgPSBhdHRyLm5vZGVOYW1lLnRvTG93ZXJDYXNlKClcclxuXHJcbiAgICBpZiAoJC5pbkFycmF5KGF0dHJOYW1lLCBhbGxvd2VkQXR0cmlidXRlTGlzdCkgIT09IC0xKSB7XHJcbiAgICAgIGlmICgkLmluQXJyYXkoYXR0ck5hbWUsIHVyaUF0dHJzKSAhPT0gLTEpIHtcclxuICAgICAgICByZXR1cm4gQm9vbGVhbihhdHRyLm5vZGVWYWx1ZS5tYXRjaChTQUZFX1VSTF9QQVRURVJOKSB8fCBhdHRyLm5vZGVWYWx1ZS5tYXRjaChEQVRBX1VSTF9QQVRURVJOKSlcclxuICAgICAgfVxyXG5cclxuICAgICAgcmV0dXJuIHRydWVcclxuICAgIH1cclxuXHJcbiAgICB2YXIgcmVnRXhwID0gJChhbGxvd2VkQXR0cmlidXRlTGlzdCkuZmlsdGVyKGZ1bmN0aW9uIChpbmRleCwgdmFsdWUpIHtcclxuICAgICAgcmV0dXJuIHZhbHVlIGluc3RhbmNlb2YgUmVnRXhwXHJcbiAgICB9KVxyXG5cclxuICAgIC8vIENoZWNrIGlmIGEgcmVndWxhciBleHByZXNzaW9uIHZhbGlkYXRlcyB0aGUgYXR0cmlidXRlLlxyXG4gICAgZm9yICh2YXIgaSA9IDAsIGwgPSByZWdFeHAubGVuZ3RoOyBpIDwgbDsgaSsrKSB7XHJcbiAgICAgIGlmIChhdHRyTmFtZS5tYXRjaChyZWdFeHBbaV0pKSB7XHJcbiAgICAgICAgcmV0dXJuIHRydWVcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiBmYWxzZVxyXG4gIH1cclxuXHJcbiAgZnVuY3Rpb24gc2FuaXRpemVIdG1sICh1bnNhZmVFbGVtZW50cywgd2hpdGVMaXN0LCBzYW5pdGl6ZUZuKSB7XHJcbiAgICBpZiAoc2FuaXRpemVGbiAmJiB0eXBlb2Ygc2FuaXRpemVGbiA9PT0gJ2Z1bmN0aW9uJykge1xyXG4gICAgICByZXR1cm4gc2FuaXRpemVGbih1bnNhZmVFbGVtZW50cyk7XHJcbiAgICB9XHJcblxyXG4gICAgdmFyIHdoaXRlbGlzdEtleXMgPSBPYmplY3Qua2V5cyh3aGl0ZUxpc3QpO1xyXG5cclxuICAgIGZvciAodmFyIGkgPSAwLCBsZW4gPSB1bnNhZmVFbGVtZW50cy5sZW5ndGg7IGkgPCBsZW47IGkrKykge1xyXG4gICAgICB2YXIgZWxlbWVudHMgPSB1bnNhZmVFbGVtZW50c1tpXS5xdWVyeVNlbGVjdG9yQWxsKCcqJyk7XHJcblxyXG4gICAgICBmb3IgKHZhciBqID0gMCwgbGVuMiA9IGVsZW1lbnRzLmxlbmd0aDsgaiA8IGxlbjI7IGorKykge1xyXG4gICAgICAgIHZhciBlbCA9IGVsZW1lbnRzW2pdO1xyXG4gICAgICAgIHZhciBlbE5hbWUgPSBlbC5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpO1xyXG5cclxuICAgICAgICBpZiAod2hpdGVsaXN0S2V5cy5pbmRleE9mKGVsTmFtZSkgPT09IC0xKSB7XHJcbiAgICAgICAgICBlbC5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKGVsKTtcclxuXHJcbiAgICAgICAgICBjb250aW51ZTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHZhciBhdHRyaWJ1dGVMaXN0ID0gW10uc2xpY2UuY2FsbChlbC5hdHRyaWJ1dGVzKTtcclxuICAgICAgICB2YXIgd2hpdGVsaXN0ZWRBdHRyaWJ1dGVzID0gW10uY29uY2F0KHdoaXRlTGlzdFsnKiddIHx8IFtdLCB3aGl0ZUxpc3RbZWxOYW1lXSB8fCBbXSk7XHJcblxyXG4gICAgICAgIGZvciAodmFyIGsgPSAwLCBsZW4zID0gYXR0cmlidXRlTGlzdC5sZW5ndGg7IGsgPCBsZW4zOyBrKyspIHtcclxuICAgICAgICAgIHZhciBhdHRyID0gYXR0cmlidXRlTGlzdFtrXTtcclxuXHJcbiAgICAgICAgICBpZiAoIWFsbG93ZWRBdHRyaWJ1dGUoYXR0ciwgd2hpdGVsaXN0ZWRBdHRyaWJ1dGVzKSkge1xyXG4gICAgICAgICAgICBlbC5yZW1vdmVBdHRyaWJ1dGUoYXR0ci5ub2RlTmFtZSk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiBnZXRBdHRyaWJ1dGVzT2JqZWN0ICgkc2VsZWN0KSB7XHJcbiAgICB2YXIgYXR0cmlidXRlc09iamVjdCA9IHt9LFxyXG4gICAgICAgIGF0dHJWYWw7XHJcblxyXG4gICAgUGFyc2VhYmxlQXR0cmlidXRlcy5mb3JFYWNoKGZ1bmN0aW9uIChpdGVtKSB7XHJcbiAgICAgIGF0dHJWYWwgPSAkc2VsZWN0LmF0dHIoaXRlbSk7XHJcbiAgICAgIGlmIChhdHRyVmFsKSBhdHRyaWJ1dGVzT2JqZWN0W2l0ZW1dID0gYXR0clZhbDtcclxuICAgIH0pO1xyXG5cclxuICAgIC8vIGZvciBiYWNrd2FyZHMgY29tcGF0aWJpbGl0eVxyXG4gICAgLy8gKHVzaW5nIHRpdGxlIGFzIHBsYWNlaG9sZGVyIGlzIGRlcHJlY2F0ZWQgLSByZW1vdmUgaW4gdjIuMC4wKVxyXG4gICAgaWYgKCFhdHRyaWJ1dGVzT2JqZWN0LnBsYWNlaG9sZGVyICYmIGF0dHJpYnV0ZXNPYmplY3QudGl0bGUpIHtcclxuICAgICAgYXR0cmlidXRlc09iamVjdC5wbGFjZWhvbGRlciA9IGF0dHJpYnV0ZXNPYmplY3QudGl0bGU7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIGF0dHJpYnV0ZXNPYmplY3Q7XHJcbiAgfVxyXG5cclxuICAvLyBQb2x5ZmlsbCBmb3IgYnJvd3NlcnMgd2l0aCBubyBjbGFzc0xpc3Qgc3VwcG9ydFxyXG4gIC8vIFJlbW92ZSBpbiB2MlxyXG4gIGlmICghKCdjbGFzc0xpc3QnIGluIGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ18nKSkpIHtcclxuICAgIChmdW5jdGlvbiAodmlldykge1xyXG4gICAgICBpZiAoISgnRWxlbWVudCcgaW4gdmlldykpIHJldHVybjtcclxuXHJcbiAgICAgIHZhciBjbGFzc0xpc3RQcm9wID0gJ2NsYXNzTGlzdCcsXHJcbiAgICAgICAgICBwcm90b1Byb3AgPSAncHJvdG90eXBlJyxcclxuICAgICAgICAgIGVsZW1DdHJQcm90byA9IHZpZXcuRWxlbWVudFtwcm90b1Byb3BdLFxyXG4gICAgICAgICAgb2JqQ3RyID0gT2JqZWN0LFxyXG4gICAgICAgICAgY2xhc3NMaXN0R2V0dGVyID0gZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICB2YXIgJGVsZW0gPSAkKHRoaXMpO1xyXG5cclxuICAgICAgICAgICAgcmV0dXJuIHtcclxuICAgICAgICAgICAgICBhZGQ6IGZ1bmN0aW9uIChjbGFzc2VzKSB7XHJcbiAgICAgICAgICAgICAgICBjbGFzc2VzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzKS5qb2luKCcgJyk7XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gJGVsZW0uYWRkQ2xhc3MoY2xhc3Nlcyk7XHJcbiAgICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgICByZW1vdmU6IGZ1bmN0aW9uIChjbGFzc2VzKSB7XHJcbiAgICAgICAgICAgICAgICBjbGFzc2VzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzKS5qb2luKCcgJyk7XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gJGVsZW0ucmVtb3ZlQ2xhc3MoY2xhc3Nlcyk7XHJcbiAgICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgICB0b2dnbGU6IGZ1bmN0aW9uIChjbGFzc2VzLCBmb3JjZSkge1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuICRlbGVtLnRvZ2dsZUNsYXNzKGNsYXNzZXMsIGZvcmNlKTtcclxuICAgICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICAgIGNvbnRhaW5zOiBmdW5jdGlvbiAoY2xhc3Nlcykge1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuICRlbGVtLmhhc0NsYXNzKGNsYXNzZXMpO1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfTtcclxuXHJcbiAgICAgIGlmIChvYmpDdHIuZGVmaW5lUHJvcGVydHkpIHtcclxuICAgICAgICB2YXIgY2xhc3NMaXN0UHJvcERlc2MgPSB7XHJcbiAgICAgICAgICBnZXQ6IGNsYXNzTGlzdEdldHRlcixcclxuICAgICAgICAgIGVudW1lcmFibGU6IHRydWUsXHJcbiAgICAgICAgICBjb25maWd1cmFibGU6IHRydWVcclxuICAgICAgICB9O1xyXG4gICAgICAgIHRyeSB7XHJcbiAgICAgICAgICBvYmpDdHIuZGVmaW5lUHJvcGVydHkoZWxlbUN0clByb3RvLCBjbGFzc0xpc3RQcm9wLCBjbGFzc0xpc3RQcm9wRGVzYyk7XHJcbiAgICAgICAgfSBjYXRjaCAoZXgpIHsgLy8gSUUgOCBkb2Vzbid0IHN1cHBvcnQgZW51bWVyYWJsZTp0cnVlXHJcbiAgICAgICAgICAvLyBhZGRpbmcgdW5kZWZpbmVkIHRvIGZpZ2h0IHRoaXMgaXNzdWUgaHR0cHM6Ly9naXRodWIuY29tL2VsaWdyZXkvY2xhc3NMaXN0LmpzL2lzc3Vlcy8zNlxyXG4gICAgICAgICAgLy8gbW9kZXJuaWUgSUU4LU1TVzcgbWFjaGluZSBoYXMgSUU4IDguMC42MDAxLjE4NzAyIGFuZCBpcyBhZmZlY3RlZFxyXG4gICAgICAgICAgaWYgKGV4Lm51bWJlciA9PT0gdW5kZWZpbmVkIHx8IGV4Lm51bWJlciA9PT0gLTB4N0ZGNUVDNTQpIHtcclxuICAgICAgICAgICAgY2xhc3NMaXN0UHJvcERlc2MuZW51bWVyYWJsZSA9IGZhbHNlO1xyXG4gICAgICAgICAgICBvYmpDdHIuZGVmaW5lUHJvcGVydHkoZWxlbUN0clByb3RvLCBjbGFzc0xpc3RQcm9wLCBjbGFzc0xpc3RQcm9wRGVzYyk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9IGVsc2UgaWYgKG9iakN0cltwcm90b1Byb3BdLl9fZGVmaW5lR2V0dGVyX18pIHtcclxuICAgICAgICBlbGVtQ3RyUHJvdG8uX19kZWZpbmVHZXR0ZXJfXyhjbGFzc0xpc3RQcm9wLCBjbGFzc0xpc3RHZXR0ZXIpO1xyXG4gICAgICB9XHJcbiAgICB9KHdpbmRvdykpO1xyXG4gIH1cclxuXHJcbiAgdmFyIHRlc3RFbGVtZW50ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnXycpO1xyXG5cclxuICB0ZXN0RWxlbWVudC5jbGFzc0xpc3QuYWRkKCdjMScsICdjMicpO1xyXG5cclxuICBpZiAoIXRlc3RFbGVtZW50LmNsYXNzTGlzdC5jb250YWlucygnYzInKSkge1xyXG4gICAgdmFyIF9hZGQgPSBET01Ub2tlbkxpc3QucHJvdG90eXBlLmFkZCxcclxuICAgICAgICBfcmVtb3ZlID0gRE9NVG9rZW5MaXN0LnByb3RvdHlwZS5yZW1vdmU7XHJcblxyXG4gICAgRE9NVG9rZW5MaXN0LnByb3RvdHlwZS5hZGQgPSBmdW5jdGlvbiAoKSB7XHJcbiAgICAgIEFycmF5LnByb3RvdHlwZS5mb3JFYWNoLmNhbGwoYXJndW1lbnRzLCBfYWRkLmJpbmQodGhpcykpO1xyXG4gICAgfVxyXG5cclxuICAgIERPTVRva2VuTGlzdC5wcm90b3R5cGUucmVtb3ZlID0gZnVuY3Rpb24gKCkge1xyXG4gICAgICBBcnJheS5wcm90b3R5cGUuZm9yRWFjaC5jYWxsKGFyZ3VtZW50cywgX3JlbW92ZS5iaW5kKHRoaXMpKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHRlc3RFbGVtZW50LmNsYXNzTGlzdC50b2dnbGUoJ2MzJywgZmFsc2UpO1xyXG5cclxuICAvLyBQb2x5ZmlsbCBmb3IgSUUgMTAgYW5kIEZpcmVmb3ggPDI0LCB3aGVyZSBjbGFzc0xpc3QudG9nZ2xlIGRvZXMgbm90XHJcbiAgLy8gc3VwcG9ydCB0aGUgc2Vjb25kIGFyZ3VtZW50LlxyXG4gIGlmICh0ZXN0RWxlbWVudC5jbGFzc0xpc3QuY29udGFpbnMoJ2MzJykpIHtcclxuICAgIHZhciBfdG9nZ2xlID0gRE9NVG9rZW5MaXN0LnByb3RvdHlwZS50b2dnbGU7XHJcblxyXG4gICAgRE9NVG9rZW5MaXN0LnByb3RvdHlwZS50b2dnbGUgPSBmdW5jdGlvbiAodG9rZW4sIGZvcmNlKSB7XHJcbiAgICAgIGlmICgxIGluIGFyZ3VtZW50cyAmJiAhdGhpcy5jb250YWlucyh0b2tlbikgPT09ICFmb3JjZSkge1xyXG4gICAgICAgIHJldHVybiBmb3JjZTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICByZXR1cm4gX3RvZ2dsZS5jYWxsKHRoaXMsIHRva2VuKTtcclxuICAgICAgfVxyXG4gICAgfTtcclxuICB9XHJcblxyXG4gIHRlc3RFbGVtZW50ID0gbnVsbDtcclxuXHJcbiAgLy8gc2hhbGxvdyBhcnJheSBjb21wYXJpc29uXHJcbiAgZnVuY3Rpb24gaXNFcXVhbCAoYXJyYXkxLCBhcnJheTIpIHtcclxuICAgIHJldHVybiBhcnJheTEubGVuZ3RoID09PSBhcnJheTIubGVuZ3RoICYmIGFycmF5MS5ldmVyeShmdW5jdGlvbiAoZWxlbWVudCwgaW5kZXgpIHtcclxuICAgICAgcmV0dXJuIGVsZW1lbnQgPT09IGFycmF5MltpbmRleF07XHJcbiAgICB9KTtcclxuICB9O1xyXG5cclxuICAvLyA8ZWRpdG9yLWZvbGQgZGVzYz1cIlNoaW1zXCI+XHJcbiAgaWYgKCFTdHJpbmcucHJvdG90eXBlLnN0YXJ0c1dpdGgpIHtcclxuICAgIChmdW5jdGlvbiAoKSB7XHJcbiAgICAgICd1c2Ugc3RyaWN0JzsgLy8gbmVlZGVkIHRvIHN1cHBvcnQgYGFwcGx5YC9gY2FsbGAgd2l0aCBgdW5kZWZpbmVkYC9gbnVsbGBcclxuICAgICAgdmFyIHRvU3RyaW5nID0ge30udG9TdHJpbmc7XHJcbiAgICAgIHZhciBzdGFydHNXaXRoID0gZnVuY3Rpb24gKHNlYXJjaCkge1xyXG4gICAgICAgIGlmICh0aGlzID09IG51bGwpIHtcclxuICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgdmFyIHN0cmluZyA9IFN0cmluZyh0aGlzKTtcclxuICAgICAgICBpZiAoc2VhcmNoICYmIHRvU3RyaW5nLmNhbGwoc2VhcmNoKSA9PSAnW29iamVjdCBSZWdFeHBdJykge1xyXG4gICAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcigpO1xyXG4gICAgICAgIH1cclxuICAgICAgICB2YXIgc3RyaW5nTGVuZ3RoID0gc3RyaW5nLmxlbmd0aDtcclxuICAgICAgICB2YXIgc2VhcmNoU3RyaW5nID0gU3RyaW5nKHNlYXJjaCk7XHJcbiAgICAgICAgdmFyIHNlYXJjaExlbmd0aCA9IHNlYXJjaFN0cmluZy5sZW5ndGg7XHJcbiAgICAgICAgdmFyIHBvc2l0aW9uID0gYXJndW1lbnRzLmxlbmd0aCA+IDEgPyBhcmd1bWVudHNbMV0gOiB1bmRlZmluZWQ7XHJcbiAgICAgICAgLy8gYFRvSW50ZWdlcmBcclxuICAgICAgICB2YXIgcG9zID0gcG9zaXRpb24gPyBOdW1iZXIocG9zaXRpb24pIDogMDtcclxuICAgICAgICBpZiAocG9zICE9IHBvcykgeyAvLyBiZXR0ZXIgYGlzTmFOYFxyXG4gICAgICAgICAgcG9zID0gMDtcclxuICAgICAgICB9XHJcbiAgICAgICAgdmFyIHN0YXJ0ID0gTWF0aC5taW4oTWF0aC5tYXgocG9zLCAwKSwgc3RyaW5nTGVuZ3RoKTtcclxuICAgICAgICAvLyBBdm9pZCB0aGUgYGluZGV4T2ZgIGNhbGwgaWYgbm8gbWF0Y2ggaXMgcG9zc2libGVcclxuICAgICAgICBpZiAoc2VhcmNoTGVuZ3RoICsgc3RhcnQgPiBzdHJpbmdMZW5ndGgpIHtcclxuICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICB9XHJcbiAgICAgICAgdmFyIGluZGV4ID0gLTE7XHJcbiAgICAgICAgd2hpbGUgKCsraW5kZXggPCBzZWFyY2hMZW5ndGgpIHtcclxuICAgICAgICAgIGlmIChzdHJpbmcuY2hhckNvZGVBdChzdGFydCArIGluZGV4KSAhPSBzZWFyY2hTdHJpbmcuY2hhckNvZGVBdChpbmRleCkpIHtcclxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgfTtcclxuICAgICAgaWYgKE9iamVjdC5kZWZpbmVQcm9wZXJ0eSkge1xyXG4gICAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShTdHJpbmcucHJvdG90eXBlLCAnc3RhcnRzV2l0aCcsIHtcclxuICAgICAgICAgICd2YWx1ZSc6IHN0YXJ0c1dpdGgsXHJcbiAgICAgICAgICAnY29uZmlndXJhYmxlJzogdHJ1ZSxcclxuICAgICAgICAgICd3cml0YWJsZSc6IHRydWVcclxuICAgICAgICB9KTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBTdHJpbmcucHJvdG90eXBlLnN0YXJ0c1dpdGggPSBzdGFydHNXaXRoO1xyXG4gICAgICB9XHJcbiAgICB9KCkpO1xyXG4gIH1cclxuXHJcbiAgZnVuY3Rpb24gZ2V0U2VsZWN0ZWRPcHRpb25zICgpIHtcclxuICAgIHZhciBzZWxlY3RlZE9wdGlvbnMgPSB0aGlzLnNlbGVjdHBpY2tlci5tYWluLmRhdGEuZmlsdGVyKGZ1bmN0aW9uIChpdGVtKSB7XHJcbiAgICAgIGlmIChpdGVtLnNlbGVjdGVkKSB7XHJcbiAgICAgICAgaWYgKHRoaXMub3B0aW9ucy5oaWRlRGlzYWJsZWQgJiYgaXRlbS5kaXNhYmxlZCkgcmV0dXJuIGZhbHNlO1xyXG4gICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICB9LCB0aGlzKTtcclxuXHJcbiAgICAvLyBlbnN1cmUgb25seSAxIG9wdGlvbiBpcyBzZWxlY3RlZCBpZiBtdWx0aXBsZSBhcmUgc2V0IGluIHRoZSBkYXRhIHNvdXJjZVxyXG4gICAgaWYgKHRoaXMub3B0aW9ucy5zb3VyY2UuZGF0YSAmJiAhdGhpcy5tdWx0aXBsZSAmJiBzZWxlY3RlZE9wdGlvbnMubGVuZ3RoID4gMSkge1xyXG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHNlbGVjdGVkT3B0aW9ucy5sZW5ndGggLSAxOyBpKyspIHtcclxuICAgICAgICBzZWxlY3RlZE9wdGlvbnNbaV0uc2VsZWN0ZWQgPSBmYWxzZTtcclxuICAgICAgfVxyXG5cclxuICAgICAgc2VsZWN0ZWRPcHRpb25zID0gWyBzZWxlY3RlZE9wdGlvbnNbc2VsZWN0ZWRPcHRpb25zLmxlbmd0aCAtIDFdIF07XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHNlbGVjdGVkT3B0aW9ucztcclxuICB9XHJcblxyXG4gIC8vIG11Y2ggZmFzdGVyIHRoYW4gJC52YWwoKVxyXG4gIGZ1bmN0aW9uIGdldFNlbGVjdFZhbHVlcyAoc2VsZWN0ZWRPcHRpb25zKSB7XHJcbiAgICB2YXIgdmFsdWUgPSBbXSxcclxuICAgICAgICBvcHRpb25zID0gc2VsZWN0ZWRPcHRpb25zIHx8IGdldFNlbGVjdGVkT3B0aW9ucy5jYWxsKHRoaXMpLFxyXG4gICAgICAgIG9wdDtcclxuXHJcbiAgICBmb3IgKHZhciBpID0gMCwgbGVuID0gb3B0aW9ucy5sZW5ndGg7IGkgPCBsZW47IGkrKykge1xyXG4gICAgICBvcHQgPSBvcHRpb25zW2ldO1xyXG5cclxuICAgICAgaWYgKCFvcHQuZGlzYWJsZWQpIHtcclxuICAgICAgICB2YWx1ZS5wdXNoKG9wdC52YWx1ZSA9PT0gdW5kZWZpbmVkID8gb3B0LnRleHQgOiBvcHQudmFsdWUpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKCF0aGlzLm11bHRpcGxlKSB7XHJcbiAgICAgIHJldHVybiAhdmFsdWUubGVuZ3RoID8gbnVsbCA6IHZhbHVlWzBdO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiB2YWx1ZTtcclxuICB9XHJcblxyXG4gIC8vIHNldCBkYXRhLXNlbGVjdGVkIG9uIHNlbGVjdCBlbGVtZW50IGlmIHRoZSB2YWx1ZSBoYXMgYmVlbiBwcm9ncmFtbWF0aWNhbGx5IHNlbGVjdGVkXHJcbiAgLy8gcHJpb3IgdG8gaW5pdGlhbGl6YXRpb24gb2YgYm9vdHN0cmFwLXNlbGVjdFxyXG4gIC8vICogY29uc2lkZXIgcmVtb3Zpbmcgb3IgcmVwbGFjaW5nIGFuIGFsdGVybmF0aXZlIG1ldGhvZCAqXHJcbiAgdmFyIHZhbEhvb2tzID0ge1xyXG4gICAgdXNlRGVmYXVsdDogZmFsc2UsXHJcbiAgICBfc2V0OiAkLnZhbEhvb2tzLnNlbGVjdC5zZXRcclxuICB9O1xyXG5cclxuICAkLnZhbEhvb2tzLnNlbGVjdC5zZXQgPSBmdW5jdGlvbiAoZWxlbSwgdmFsdWUpIHtcclxuICAgIGlmICh2YWx1ZSAmJiAhdmFsSG9va3MudXNlRGVmYXVsdCkgJChlbGVtKS5kYXRhKCdzZWxlY3RlZCcsIHRydWUpO1xyXG5cclxuICAgIHJldHVybiB2YWxIb29rcy5fc2V0LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XHJcbiAgfTtcclxuXHJcbiAgdmFyIGNoYW5nZWRBcmd1bWVudHMgPSBudWxsO1xyXG5cclxuICB2YXIgRXZlbnRJc1N1cHBvcnRlZCA9IChmdW5jdGlvbiAoKSB7XHJcbiAgICB0cnkge1xyXG4gICAgICBuZXcgRXZlbnQoJ2NoYW5nZScpO1xyXG4gICAgICByZXR1cm4gdHJ1ZTtcclxuICAgIH0gY2F0Y2ggKGUpIHtcclxuICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgfVxyXG4gIH0pKCk7XHJcblxyXG4gICQuZm4udHJpZ2dlck5hdGl2ZSA9IGZ1bmN0aW9uIChldmVudE5hbWUpIHtcclxuICAgIHZhciBlbCA9IHRoaXNbMF0sXHJcbiAgICAgICAgZXZlbnQ7XHJcblxyXG4gICAgaWYgKGVsLmRpc3BhdGNoRXZlbnQpIHsgLy8gZm9yIG1vZGVybiBicm93c2VycyAmIElFOStcclxuICAgICAgaWYgKEV2ZW50SXNTdXBwb3J0ZWQpIHtcclxuICAgICAgICAvLyBGb3IgbW9kZXJuIGJyb3dzZXJzXHJcbiAgICAgICAgZXZlbnQgPSBuZXcgRXZlbnQoZXZlbnROYW1lLCB7XHJcbiAgICAgICAgICBidWJibGVzOiB0cnVlXHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgLy8gRm9yIElFIHNpbmNlIGl0IGRvZXNuJ3Qgc3VwcG9ydCBFdmVudCBjb25zdHJ1Y3RvclxyXG4gICAgICAgIGV2ZW50ID0gZG9jdW1lbnQuY3JlYXRlRXZlbnQoJ0V2ZW50Jyk7XHJcbiAgICAgICAgZXZlbnQuaW5pdEV2ZW50KGV2ZW50TmFtZSwgdHJ1ZSwgZmFsc2UpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBlbC5kaXNwYXRjaEV2ZW50KGV2ZW50KTtcclxuICAgIH1cclxuICB9O1xyXG4gIC8vIDwvZWRpdG9yLWZvbGQ+XHJcblxyXG4gIGZ1bmN0aW9uIHN0cmluZ1NlYXJjaCAobGksIHNlYXJjaFN0cmluZywgbWV0aG9kLCBub3JtYWxpemUpIHtcclxuICAgIHZhciBzdHJpbmdUeXBlcyA9IFtcclxuICAgICAgICAgICdkaXNwbGF5JyxcclxuICAgICAgICAgICdzdWJ0ZXh0JyxcclxuICAgICAgICAgICd0b2tlbnMnXHJcbiAgICAgICAgXSxcclxuICAgICAgICBzZWFyY2hTdWNjZXNzID0gZmFsc2U7XHJcblxyXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBzdHJpbmdUeXBlcy5sZW5ndGg7IGkrKykge1xyXG4gICAgICB2YXIgc3RyaW5nVHlwZSA9IHN0cmluZ1R5cGVzW2ldLFxyXG4gICAgICAgICAgc3RyaW5nID0gbGlbc3RyaW5nVHlwZV07XHJcblxyXG4gICAgICBpZiAoc3RyaW5nKSB7XHJcbiAgICAgICAgc3RyaW5nID0gc3RyaW5nLnRvU3RyaW5nKCk7XHJcblxyXG4gICAgICAgIC8vIFN0cmlwIEhUTUwgdGFncy4gVGhpcyBpc24ndCBwZXJmZWN0LCBidXQgaXQncyBtdWNoIGZhc3RlciB0aGFuIGFueSBvdGhlciBtZXRob2RcclxuICAgICAgICBpZiAoc3RyaW5nVHlwZSA9PT0gJ2Rpc3BsYXknKSB7XHJcbiAgICAgICAgICBzdHJpbmcgPSBzdHJpbmcucmVwbGFjZSgvPFtePl0rPi9nLCAnJyk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBpZiAobm9ybWFsaXplKSBzdHJpbmcgPSBub3JtYWxpemVUb0Jhc2Uoc3RyaW5nKTtcclxuICAgICAgICBzdHJpbmcgPSBzdHJpbmcudG9VcHBlckNhc2UoKTtcclxuXHJcbiAgICAgICAgaWYgKHR5cGVvZiBtZXRob2QgPT09ICdmdW5jdGlvbicpIHtcclxuICAgICAgICAgIHNlYXJjaFN1Y2Nlc3MgPSBtZXRob2Qoc3RyaW5nLCBzZWFyY2hTdHJpbmcpO1xyXG4gICAgICAgIH0gZWxzZSBpZiAobWV0aG9kID09PSAnY29udGFpbnMnKSB7XHJcbiAgICAgICAgICBzZWFyY2hTdWNjZXNzID0gc3RyaW5nLmluZGV4T2Yoc2VhcmNoU3RyaW5nKSA+PSAwO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICBzZWFyY2hTdWNjZXNzID0gc3RyaW5nLnN0YXJ0c1dpdGgoc2VhcmNoU3RyaW5nKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGlmIChzZWFyY2hTdWNjZXNzKSBicmVhaztcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiBzZWFyY2hTdWNjZXNzO1xyXG4gIH1cclxuXHJcbiAgZnVuY3Rpb24gdG9JbnRlZ2VyICh2YWx1ZSkge1xyXG4gICAgcmV0dXJuIHBhcnNlSW50KHZhbHVlLCAxMCkgfHwgMDtcclxuICB9XHJcblxyXG4gIC8vIEJvcnJvd2VkIGZyb20gTG9kYXNoIChfLmRlYnVycilcclxuICAvKiogVXNlZCB0byBtYXAgTGF0aW4gVW5pY29kZSBsZXR0ZXJzIHRvIGJhc2ljIExhdGluIGxldHRlcnMuICovXHJcbiAgdmFyIGRlYnVycmVkTGV0dGVycyA9IHtcclxuICAgIC8vIExhdGluLTEgU3VwcGxlbWVudCBibG9jay5cclxuICAgICdcXHhjMCc6ICdBJywgICdcXHhjMSc6ICdBJywgJ1xceGMyJzogJ0EnLCAnXFx4YzMnOiAnQScsICdcXHhjNCc6ICdBJywgJ1xceGM1JzogJ0EnLFxyXG4gICAgJ1xceGUwJzogJ2EnLCAgJ1xceGUxJzogJ2EnLCAnXFx4ZTInOiAnYScsICdcXHhlMyc6ICdhJywgJ1xceGU0JzogJ2EnLCAnXFx4ZTUnOiAnYScsXHJcbiAgICAnXFx4YzcnOiAnQycsICAnXFx4ZTcnOiAnYycsXHJcbiAgICAnXFx4ZDAnOiAnRCcsICAnXFx4ZjAnOiAnZCcsXHJcbiAgICAnXFx4YzgnOiAnRScsICAnXFx4YzknOiAnRScsICdcXHhjYSc6ICdFJywgJ1xceGNiJzogJ0UnLFxyXG4gICAgJ1xceGU4JzogJ2UnLCAgJ1xceGU5JzogJ2UnLCAnXFx4ZWEnOiAnZScsICdcXHhlYic6ICdlJyxcclxuICAgICdcXHhjYyc6ICdJJywgICdcXHhjZCc6ICdJJywgJ1xceGNlJzogJ0knLCAnXFx4Y2YnOiAnSScsXHJcbiAgICAnXFx4ZWMnOiAnaScsICAnXFx4ZWQnOiAnaScsICdcXHhlZSc6ICdpJywgJ1xceGVmJzogJ2knLFxyXG4gICAgJ1xceGQxJzogJ04nLCAgJ1xceGYxJzogJ24nLFxyXG4gICAgJ1xceGQyJzogJ08nLCAgJ1xceGQzJzogJ08nLCAnXFx4ZDQnOiAnTycsICdcXHhkNSc6ICdPJywgJ1xceGQ2JzogJ08nLCAnXFx4ZDgnOiAnTycsXHJcbiAgICAnXFx4ZjInOiAnbycsICAnXFx4ZjMnOiAnbycsICdcXHhmNCc6ICdvJywgJ1xceGY1JzogJ28nLCAnXFx4ZjYnOiAnbycsICdcXHhmOCc6ICdvJyxcclxuICAgICdcXHhkOSc6ICdVJywgICdcXHhkYSc6ICdVJywgJ1xceGRiJzogJ1UnLCAnXFx4ZGMnOiAnVScsXHJcbiAgICAnXFx4ZjknOiAndScsICAnXFx4ZmEnOiAndScsICdcXHhmYic6ICd1JywgJ1xceGZjJzogJ3UnLFxyXG4gICAgJ1xceGRkJzogJ1knLCAgJ1xceGZkJzogJ3knLCAnXFx4ZmYnOiAneScsXHJcbiAgICAnXFx4YzYnOiAnQWUnLCAnXFx4ZTYnOiAnYWUnLFxyXG4gICAgJ1xceGRlJzogJ1RoJywgJ1xceGZlJzogJ3RoJyxcclxuICAgICdcXHhkZic6ICdzcycsXHJcbiAgICAvLyBMYXRpbiBFeHRlbmRlZC1BIGJsb2NrLlxyXG4gICAgJ1xcdTAxMDAnOiAnQScsICAnXFx1MDEwMic6ICdBJywgJ1xcdTAxMDQnOiAnQScsXHJcbiAgICAnXFx1MDEwMSc6ICdhJywgICdcXHUwMTAzJzogJ2EnLCAnXFx1MDEwNSc6ICdhJyxcclxuICAgICdcXHUwMTA2JzogJ0MnLCAgJ1xcdTAxMDgnOiAnQycsICdcXHUwMTBhJzogJ0MnLCAnXFx1MDEwYyc6ICdDJyxcclxuICAgICdcXHUwMTA3JzogJ2MnLCAgJ1xcdTAxMDknOiAnYycsICdcXHUwMTBiJzogJ2MnLCAnXFx1MDEwZCc6ICdjJyxcclxuICAgICdcXHUwMTBlJzogJ0QnLCAgJ1xcdTAxMTAnOiAnRCcsICdcXHUwMTBmJzogJ2QnLCAnXFx1MDExMSc6ICdkJyxcclxuICAgICdcXHUwMTEyJzogJ0UnLCAgJ1xcdTAxMTQnOiAnRScsICdcXHUwMTE2JzogJ0UnLCAnXFx1MDExOCc6ICdFJywgJ1xcdTAxMWEnOiAnRScsXHJcbiAgICAnXFx1MDExMyc6ICdlJywgICdcXHUwMTE1JzogJ2UnLCAnXFx1MDExNyc6ICdlJywgJ1xcdTAxMTknOiAnZScsICdcXHUwMTFiJzogJ2UnLFxyXG4gICAgJ1xcdTAxMWMnOiAnRycsICAnXFx1MDExZSc6ICdHJywgJ1xcdTAxMjAnOiAnRycsICdcXHUwMTIyJzogJ0cnLFxyXG4gICAgJ1xcdTAxMWQnOiAnZycsICAnXFx1MDExZic6ICdnJywgJ1xcdTAxMjEnOiAnZycsICdcXHUwMTIzJzogJ2cnLFxyXG4gICAgJ1xcdTAxMjQnOiAnSCcsICAnXFx1MDEyNic6ICdIJywgJ1xcdTAxMjUnOiAnaCcsICdcXHUwMTI3JzogJ2gnLFxyXG4gICAgJ1xcdTAxMjgnOiAnSScsICAnXFx1MDEyYSc6ICdJJywgJ1xcdTAxMmMnOiAnSScsICdcXHUwMTJlJzogJ0knLCAnXFx1MDEzMCc6ICdJJyxcclxuICAgICdcXHUwMTI5JzogJ2knLCAgJ1xcdTAxMmInOiAnaScsICdcXHUwMTJkJzogJ2knLCAnXFx1MDEyZic6ICdpJywgJ1xcdTAxMzEnOiAnaScsXHJcbiAgICAnXFx1MDEzNCc6ICdKJywgICdcXHUwMTM1JzogJ2onLFxyXG4gICAgJ1xcdTAxMzYnOiAnSycsICAnXFx1MDEzNyc6ICdrJywgJ1xcdTAxMzgnOiAnaycsXHJcbiAgICAnXFx1MDEzOSc6ICdMJywgICdcXHUwMTNiJzogJ0wnLCAnXFx1MDEzZCc6ICdMJywgJ1xcdTAxM2YnOiAnTCcsICdcXHUwMTQxJzogJ0wnLFxyXG4gICAgJ1xcdTAxM2EnOiAnbCcsICAnXFx1MDEzYyc6ICdsJywgJ1xcdTAxM2UnOiAnbCcsICdcXHUwMTQwJzogJ2wnLCAnXFx1MDE0Mic6ICdsJyxcclxuICAgICdcXHUwMTQzJzogJ04nLCAgJ1xcdTAxNDUnOiAnTicsICdcXHUwMTQ3JzogJ04nLCAnXFx1MDE0YSc6ICdOJyxcclxuICAgICdcXHUwMTQ0JzogJ24nLCAgJ1xcdTAxNDYnOiAnbicsICdcXHUwMTQ4JzogJ24nLCAnXFx1MDE0Yic6ICduJyxcclxuICAgICdcXHUwMTRjJzogJ08nLCAgJ1xcdTAxNGUnOiAnTycsICdcXHUwMTUwJzogJ08nLFxyXG4gICAgJ1xcdTAxNGQnOiAnbycsICAnXFx1MDE0Zic6ICdvJywgJ1xcdTAxNTEnOiAnbycsXHJcbiAgICAnXFx1MDE1NCc6ICdSJywgICdcXHUwMTU2JzogJ1InLCAnXFx1MDE1OCc6ICdSJyxcclxuICAgICdcXHUwMTU1JzogJ3InLCAgJ1xcdTAxNTcnOiAncicsICdcXHUwMTU5JzogJ3InLFxyXG4gICAgJ1xcdTAxNWEnOiAnUycsICAnXFx1MDE1Yyc6ICdTJywgJ1xcdTAxNWUnOiAnUycsICdcXHUwMTYwJzogJ1MnLFxyXG4gICAgJ1xcdTAxNWInOiAncycsICAnXFx1MDE1ZCc6ICdzJywgJ1xcdTAxNWYnOiAncycsICdcXHUwMTYxJzogJ3MnLFxyXG4gICAgJ1xcdTAxNjInOiAnVCcsICAnXFx1MDE2NCc6ICdUJywgJ1xcdTAxNjYnOiAnVCcsXHJcbiAgICAnXFx1MDE2Myc6ICd0JywgICdcXHUwMTY1JzogJ3QnLCAnXFx1MDE2Nyc6ICd0JyxcclxuICAgICdcXHUwMTY4JzogJ1UnLCAgJ1xcdTAxNmEnOiAnVScsICdcXHUwMTZjJzogJ1UnLCAnXFx1MDE2ZSc6ICdVJywgJ1xcdTAxNzAnOiAnVScsICdcXHUwMTcyJzogJ1UnLFxyXG4gICAgJ1xcdTAxNjknOiAndScsICAnXFx1MDE2Yic6ICd1JywgJ1xcdTAxNmQnOiAndScsICdcXHUwMTZmJzogJ3UnLCAnXFx1MDE3MSc6ICd1JywgJ1xcdTAxNzMnOiAndScsXHJcbiAgICAnXFx1MDE3NCc6ICdXJywgICdcXHUwMTc1JzogJ3cnLFxyXG4gICAgJ1xcdTAxNzYnOiAnWScsICAnXFx1MDE3Nyc6ICd5JywgJ1xcdTAxNzgnOiAnWScsXHJcbiAgICAnXFx1MDE3OSc6ICdaJywgICdcXHUwMTdiJzogJ1onLCAnXFx1MDE3ZCc6ICdaJyxcclxuICAgICdcXHUwMTdhJzogJ3onLCAgJ1xcdTAxN2MnOiAneicsICdcXHUwMTdlJzogJ3onLFxyXG4gICAgJ1xcdTAxMzInOiAnSUonLCAnXFx1MDEzMyc6ICdpaicsXHJcbiAgICAnXFx1MDE1Mic6ICdPZScsICdcXHUwMTUzJzogJ29lJyxcclxuICAgICdcXHUwMTQ5JzogXCInblwiLCAnXFx1MDE3Zic6ICdzJ1xyXG4gIH07XHJcblxyXG4gIC8qKiBVc2VkIHRvIG1hdGNoIExhdGluIFVuaWNvZGUgbGV0dGVycyAoZXhjbHVkaW5nIG1hdGhlbWF0aWNhbCBvcGVyYXRvcnMpLiAqL1xyXG4gIHZhciByZUxhdGluID0gL1tcXHhjMC1cXHhkNlxceGQ4LVxceGY2XFx4ZjgtXFx4ZmZcXHUwMTAwLVxcdTAxN2ZdL2c7XHJcblxyXG4gIC8qKiBVc2VkIHRvIGNvbXBvc2UgdW5pY29kZSBjaGFyYWN0ZXIgY2xhc3Nlcy4gKi9cclxuICB2YXIgcnNDb21ib01hcmtzUmFuZ2UgPSAnXFxcXHUwMzAwLVxcXFx1MDM2ZicsXHJcbiAgICAgIHJlQ29tYm9IYWxmTWFya3NSYW5nZSA9ICdcXFxcdWZlMjAtXFxcXHVmZTJmJyxcclxuICAgICAgcnNDb21ib1N5bWJvbHNSYW5nZSA9ICdcXFxcdTIwZDAtXFxcXHUyMGZmJyxcclxuICAgICAgcnNDb21ib01hcmtzRXh0ZW5kZWRSYW5nZSA9ICdcXFxcdTFhYjAtXFxcXHUxYWZmJyxcclxuICAgICAgcnNDb21ib01hcmtzU3VwcGxlbWVudFJhbmdlID0gJ1xcXFx1MWRjMC1cXFxcdTFkZmYnLFxyXG4gICAgICByc0NvbWJvUmFuZ2UgPSByc0NvbWJvTWFya3NSYW5nZSArIHJlQ29tYm9IYWxmTWFya3NSYW5nZSArIHJzQ29tYm9TeW1ib2xzUmFuZ2UgKyByc0NvbWJvTWFya3NFeHRlbmRlZFJhbmdlICsgcnNDb21ib01hcmtzU3VwcGxlbWVudFJhbmdlO1xyXG5cclxuICAvKiogVXNlZCB0byBjb21wb3NlIHVuaWNvZGUgY2FwdHVyZSBncm91cHMuICovXHJcbiAgdmFyIHJzQ29tYm8gPSAnWycgKyByc0NvbWJvUmFuZ2UgKyAnXSc7XHJcblxyXG4gIC8qKlxyXG4gICAqIFVzZWQgdG8gbWF0Y2ggW2NvbWJpbmluZyBkaWFjcml0aWNhbCBtYXJrc10oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvQ29tYmluaW5nX0RpYWNyaXRpY2FsX01hcmtzKSBhbmRcclxuICAgKiBbY29tYmluaW5nIGRpYWNyaXRpY2FsIG1hcmtzIGZvciBzeW1ib2xzXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9Db21iaW5pbmdfRGlhY3JpdGljYWxfTWFya3NfZm9yX1N5bWJvbHMpLlxyXG4gICAqL1xyXG4gIHZhciByZUNvbWJvTWFyayA9IFJlZ0V4cChyc0NvbWJvLCAnZycpO1xyXG5cclxuICBmdW5jdGlvbiBkZWJ1cnJMZXR0ZXIgKGtleSkge1xyXG4gICAgcmV0dXJuIGRlYnVycmVkTGV0dGVyc1trZXldO1xyXG4gIH07XHJcblxyXG4gIGZ1bmN0aW9uIG5vcm1hbGl6ZVRvQmFzZSAoc3RyaW5nKSB7XHJcbiAgICBzdHJpbmcgPSBzdHJpbmcudG9TdHJpbmcoKTtcclxuICAgIHJldHVybiBzdHJpbmcgJiYgc3RyaW5nLnJlcGxhY2UocmVMYXRpbiwgZGVidXJyTGV0dGVyKS5yZXBsYWNlKHJlQ29tYm9NYXJrLCAnJyk7XHJcbiAgfVxyXG5cclxuICAvLyBMaXN0IG9mIEhUTUwgZW50aXRpZXMgZm9yIGVzY2FwaW5nLlxyXG4gIHZhciBlc2NhcGVNYXAgPSB7XHJcbiAgICAnJic6ICcmYW1wOycsXHJcbiAgICAnPCc6ICcmbHQ7JyxcclxuICAgICc+JzogJyZndDsnLFxyXG4gICAgJ1wiJzogJyZxdW90OycsXHJcbiAgICBcIidcIjogJyYjeDI3OycsXHJcbiAgICAnYCc6ICcmI3g2MDsnXHJcbiAgfTtcclxuXHJcbiAgLy8gRnVuY3Rpb25zIGZvciBlc2NhcGluZyBhbmQgdW5lc2NhcGluZyBzdHJpbmdzIHRvL2Zyb20gSFRNTCBpbnRlcnBvbGF0aW9uLlxyXG4gIHZhciBjcmVhdGVFc2NhcGVyID0gZnVuY3Rpb24gKG1hcCkge1xyXG4gICAgdmFyIGVzY2FwZXIgPSBmdW5jdGlvbiAobWF0Y2gpIHtcclxuICAgICAgcmV0dXJuIG1hcFttYXRjaF07XHJcbiAgICB9O1xyXG4gICAgLy8gUmVnZXhlcyBmb3IgaWRlbnRpZnlpbmcgYSBrZXkgdGhhdCBuZWVkcyB0byBiZSBlc2NhcGVkLlxyXG4gICAgdmFyIHNvdXJjZSA9ICcoPzonICsgT2JqZWN0LmtleXMobWFwKS5qb2luKCd8JykgKyAnKSc7XHJcbiAgICB2YXIgdGVzdFJlZ2V4cCA9IFJlZ0V4cChzb3VyY2UpO1xyXG4gICAgdmFyIHJlcGxhY2VSZWdleHAgPSBSZWdFeHAoc291cmNlLCAnZycpO1xyXG4gICAgcmV0dXJuIGZ1bmN0aW9uIChzdHJpbmcpIHtcclxuICAgICAgc3RyaW5nID0gc3RyaW5nID09IG51bGwgPyAnJyA6ICcnICsgc3RyaW5nO1xyXG4gICAgICByZXR1cm4gdGVzdFJlZ2V4cC50ZXN0KHN0cmluZykgPyBzdHJpbmcucmVwbGFjZShyZXBsYWNlUmVnZXhwLCBlc2NhcGVyKSA6IHN0cmluZztcclxuICAgIH07XHJcbiAgfTtcclxuXHJcbiAgdmFyIGh0bWxFc2NhcGUgPSBjcmVhdGVFc2NhcGVyKGVzY2FwZU1hcCk7XHJcblxyXG4gIC8qKlxyXG4gICAqIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG4gICAqIENvbnN0YW50c1xyXG4gICAqIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG4gICAqL1xyXG5cclxuICB2YXIga2V5Q29kZU1hcCA9IHtcclxuICAgIDMyOiAnICcsXHJcbiAgICA0ODogJzAnLFxyXG4gICAgNDk6ICcxJyxcclxuICAgIDUwOiAnMicsXHJcbiAgICA1MTogJzMnLFxyXG4gICAgNTI6ICc0JyxcclxuICAgIDUzOiAnNScsXHJcbiAgICA1NDogJzYnLFxyXG4gICAgNTU6ICc3JyxcclxuICAgIDU2OiAnOCcsXHJcbiAgICA1NzogJzknLFxyXG4gICAgNTk6ICc7JyxcclxuICAgIDY1OiAnQScsXHJcbiAgICA2NjogJ0InLFxyXG4gICAgNjc6ICdDJyxcclxuICAgIDY4OiAnRCcsXHJcbiAgICA2OTogJ0UnLFxyXG4gICAgNzA6ICdGJyxcclxuICAgIDcxOiAnRycsXHJcbiAgICA3MjogJ0gnLFxyXG4gICAgNzM6ICdJJyxcclxuICAgIDc0OiAnSicsXHJcbiAgICA3NTogJ0snLFxyXG4gICAgNzY6ICdMJyxcclxuICAgIDc3OiAnTScsXHJcbiAgICA3ODogJ04nLFxyXG4gICAgNzk6ICdPJyxcclxuICAgIDgwOiAnUCcsXHJcbiAgICA4MTogJ1EnLFxyXG4gICAgODI6ICdSJyxcclxuICAgIDgzOiAnUycsXHJcbiAgICA4NDogJ1QnLFxyXG4gICAgODU6ICdVJyxcclxuICAgIDg2OiAnVicsXHJcbiAgICA4NzogJ1cnLFxyXG4gICAgODg6ICdYJyxcclxuICAgIDg5OiAnWScsXHJcbiAgICA5MDogJ1onLFxyXG4gICAgOTY6ICcwJyxcclxuICAgIDk3OiAnMScsXHJcbiAgICA5ODogJzInLFxyXG4gICAgOTk6ICczJyxcclxuICAgIDEwMDogJzQnLFxyXG4gICAgMTAxOiAnNScsXHJcbiAgICAxMDI6ICc2JyxcclxuICAgIDEwMzogJzcnLFxyXG4gICAgMTA0OiAnOCcsXHJcbiAgICAxMDU6ICc5J1xyXG4gIH07XHJcblxyXG4gIHZhciBrZXlDb2RlcyA9IHtcclxuICAgIEVTQ0FQRTogMjcsIC8vIEtleWJvYXJkRXZlbnQud2hpY2ggdmFsdWUgZm9yIEVzY2FwZSAoRXNjKSBrZXlcclxuICAgIEVOVEVSOiAxMywgLy8gS2V5Ym9hcmRFdmVudC53aGljaCB2YWx1ZSBmb3IgRW50ZXIga2V5XHJcbiAgICBTUEFDRTogMzIsIC8vIEtleWJvYXJkRXZlbnQud2hpY2ggdmFsdWUgZm9yIHNwYWNlIGtleVxyXG4gICAgVEFCOiA5LCAvLyBLZXlib2FyZEV2ZW50LndoaWNoIHZhbHVlIGZvciB0YWIga2V5XHJcbiAgICBBUlJPV19VUDogMzgsIC8vIEtleWJvYXJkRXZlbnQud2hpY2ggdmFsdWUgZm9yIHVwIGFycm93IGtleVxyXG4gICAgQVJST1dfRE9XTjogNDAgLy8gS2V5Ym9hcmRFdmVudC53aGljaCB2YWx1ZSBmb3IgZG93biBhcnJvdyBrZXlcclxuICB9XHJcblxyXG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gIHZhciBEcm9wZG93biA9IHdpbmRvdy5Ecm9wZG93biB8fCBib290c3RyYXAuRHJvcGRvd247XHJcblxyXG4gIGZ1bmN0aW9uIGdldFZlcnNpb24gKCkge1xyXG4gICAgdmFyIHZlcnNpb247XHJcblxyXG4gICAgdHJ5IHtcclxuICAgICAgdmVyc2lvbiA9ICQuZm4uZHJvcGRvd24uQ29uc3RydWN0b3IuVkVSU0lPTjtcclxuICAgIH0gY2F0Y2ggKGVycikge1xyXG4gICAgICB2ZXJzaW9uID0gRHJvcGRvd24uVkVSU0lPTjtcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gdmVyc2lvbjtcclxuICB9XHJcblxyXG4gIHZhciB2ZXJzaW9uID0ge1xyXG4gICAgc3VjY2VzczogZmFsc2UsXHJcbiAgICBtYWpvcjogJzMnXHJcbiAgfTtcclxuXHJcbiAgdHJ5IHtcclxuICAgIHZlcnNpb24uZnVsbCA9IChnZXRWZXJzaW9uKCkgfHwgJycpLnNwbGl0KCcgJylbMF0uc3BsaXQoJy4nKTtcclxuICAgIHZlcnNpb24ubWFqb3IgPSB2ZXJzaW9uLmZ1bGxbMF07XHJcbiAgICB2ZXJzaW9uLnN1Y2Nlc3MgPSB0cnVlO1xyXG4gIH0gY2F0Y2ggKGVycikge1xyXG4gICAgLy8gZG8gbm90aGluZ1xyXG4gIH1cclxuXHJcbiAgdmFyIHNlbGVjdElkID0gMDtcclxuXHJcbiAgdmFyIEVWRU5UX0tFWSA9ICcuYnMuc2VsZWN0JztcclxuXHJcbiAgdmFyIGNsYXNzTmFtZXMgPSB7XHJcbiAgICBESVNBQkxFRDogJ2Rpc2FibGVkJyxcclxuICAgIERJVklERVI6ICdkaXZpZGVyJyxcclxuICAgIFNIT1c6ICdvcGVuJyxcclxuICAgIERST1BVUDogJ2Ryb3B1cCcsXHJcbiAgICBNRU5VOiAnZHJvcGRvd24tbWVudScsXHJcbiAgICBNRU5VUklHSFQ6ICdkcm9wZG93bi1tZW51LXJpZ2h0JyxcclxuICAgIE1FTlVMRUZUOiAnZHJvcGRvd24tbWVudS1sZWZ0JyxcclxuICAgIC8vIHRvLWRvOiByZXBsYWNlIHdpdGggbW9yZSBhZHZhbmNlZCB0ZW1wbGF0ZS9jdXN0b21pemF0aW9uIG9wdGlvbnNcclxuICAgIEJVVFRPTkNMQVNTOiAnYnRuLWRlZmF1bHQnLFxyXG4gICAgUE9QT1ZFUkhFQURFUjogJ3BvcG92ZXItdGl0bGUnLFxyXG4gICAgSUNPTkJBU0U6ICdnbHlwaGljb24nLFxyXG4gICAgVElDS0lDT046ICdnbHlwaGljb24tb2snXHJcbiAgfVxyXG5cclxuICB2YXIgU2VsZWN0b3IgPSB7XHJcbiAgICBNRU5VOiAnLicgKyBjbGFzc05hbWVzLk1FTlUsXHJcbiAgICBEQVRBX1RPR0dMRTogJ2RhdGEtdG9nZ2xlPVwiZHJvcGRvd25cIidcclxuICB9XHJcblxyXG4gIHZhciBlbGVtZW50VGVtcGxhdGVzID0ge1xyXG4gICAgZGl2OiBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKSxcclxuICAgIHNwYW46IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3NwYW4nKSxcclxuICAgIGk6IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2knKSxcclxuICAgIHN1YnRleHQ6IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3NtYWxsJyksXHJcbiAgICBhOiBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdhJyksXHJcbiAgICBsaTogZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnbGknKSxcclxuICAgIHdoaXRlc3BhY2U6IGRvY3VtZW50LmNyZWF0ZVRleHROb2RlKCdcXHUwMEEwJyksXHJcbiAgICBmcmFnbWVudDogZG9jdW1lbnQuY3JlYXRlRG9jdW1lbnRGcmFnbWVudCgpLFxyXG4gICAgb3B0aW9uOiBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdvcHRpb24nKVxyXG4gIH1cclxuXHJcbiAgZWxlbWVudFRlbXBsYXRlcy5zZWxlY3RlZE9wdGlvbiA9IGVsZW1lbnRUZW1wbGF0ZXMub3B0aW9uLmNsb25lTm9kZShmYWxzZSk7XHJcbiAgZWxlbWVudFRlbXBsYXRlcy5zZWxlY3RlZE9wdGlvbi5zZXRBdHRyaWJ1dGUoJ3NlbGVjdGVkJywgdHJ1ZSk7XHJcblxyXG4gIGVsZW1lbnRUZW1wbGF0ZXMubm9SZXN1bHRzID0gZWxlbWVudFRlbXBsYXRlcy5saS5jbG9uZU5vZGUoZmFsc2UpO1xyXG4gIGVsZW1lbnRUZW1wbGF0ZXMubm9SZXN1bHRzLmNsYXNzTmFtZSA9ICduby1yZXN1bHRzJztcclxuXHJcbiAgZWxlbWVudFRlbXBsYXRlcy5hLnNldEF0dHJpYnV0ZSgncm9sZScsICdvcHRpb24nKTtcclxuICBlbGVtZW50VGVtcGxhdGVzLmEuY2xhc3NOYW1lID0gJ2Ryb3Bkb3duLWl0ZW0nO1xyXG5cclxuICBlbGVtZW50VGVtcGxhdGVzLnN1YnRleHQuY2xhc3NOYW1lID0gJ3RleHQtbXV0ZWQnO1xyXG5cclxuICBlbGVtZW50VGVtcGxhdGVzLnRleHQgPSBlbGVtZW50VGVtcGxhdGVzLnNwYW4uY2xvbmVOb2RlKGZhbHNlKTtcclxuICBlbGVtZW50VGVtcGxhdGVzLnRleHQuY2xhc3NOYW1lID0gJ3RleHQnO1xyXG5cclxuICBlbGVtZW50VGVtcGxhdGVzLmNoZWNrTWFyayA9IGVsZW1lbnRUZW1wbGF0ZXMuc3Bhbi5jbG9uZU5vZGUoZmFsc2UpO1xyXG5cclxuICB2YXIgUkVHRVhQX0FSUk9XID0gbmV3IFJlZ0V4cChrZXlDb2Rlcy5BUlJPV19VUCArICd8JyArIGtleUNvZGVzLkFSUk9XX0RPV04pO1xyXG4gIHZhciBSRUdFWFBfVEFCX09SX0VTQ0FQRSA9IG5ldyBSZWdFeHAoJ14nICsga2V5Q29kZXMuVEFCICsgJyR8JyArIGtleUNvZGVzLkVTQ0FQRSk7XHJcblxyXG4gIHZhciBnZW5lcmF0ZU9wdGlvbiA9IHtcclxuICAgIGxpOiBmdW5jdGlvbiAoY29udGVudCwgY2xhc3Nlcywgb3B0Z3JvdXApIHtcclxuICAgICAgdmFyIGxpID0gZWxlbWVudFRlbXBsYXRlcy5saS5jbG9uZU5vZGUoZmFsc2UpO1xyXG5cclxuICAgICAgaWYgKGNvbnRlbnQpIHtcclxuICAgICAgICBpZiAoY29udGVudC5ub2RlVHlwZSA9PT0gMSB8fCBjb250ZW50Lm5vZGVUeXBlID09PSAxMSkge1xyXG4gICAgICAgICAgbGkuYXBwZW5kQ2hpbGQoY29udGVudCk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIGxpLmlubmVySFRNTCA9IGNvbnRlbnQ7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAodHlwZW9mIGNsYXNzZXMgIT09ICd1bmRlZmluZWQnICYmIGNsYXNzZXMgIT09ICcnKSBsaS5jbGFzc05hbWUgPSBjbGFzc2VzO1xyXG4gICAgICBpZiAodHlwZW9mIG9wdGdyb3VwICE9PSAndW5kZWZpbmVkJyAmJiBvcHRncm91cCAhPT0gbnVsbCkgbGkuY2xhc3NMaXN0LmFkZCgnb3B0Z3JvdXAtJyArIG9wdGdyb3VwKTtcclxuXHJcbiAgICAgIHJldHVybiBsaTtcclxuICAgIH0sXHJcblxyXG4gICAgYTogZnVuY3Rpb24gKHRleHQsIGNsYXNzZXMsIGlubGluZSkge1xyXG4gICAgICB2YXIgYSA9IGVsZW1lbnRUZW1wbGF0ZXMuYS5jbG9uZU5vZGUodHJ1ZSk7XHJcblxyXG4gICAgICBpZiAodGV4dCkge1xyXG4gICAgICAgIGlmICh0ZXh0Lm5vZGVUeXBlID09PSAxMSkge1xyXG4gICAgICAgICAgYS5hcHBlbmRDaGlsZCh0ZXh0KTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgYS5pbnNlcnRBZGphY2VudEhUTUwoJ2JlZm9yZWVuZCcsIHRleHQpO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKHR5cGVvZiBjbGFzc2VzICE9PSAndW5kZWZpbmVkJyAmJiBjbGFzc2VzICE9PSAnJykgYS5jbGFzc0xpc3QuYWRkLmFwcGx5KGEuY2xhc3NMaXN0LCBjbGFzc2VzLnNwbGl0KC9cXHMrLykpO1xyXG4gICAgICBpZiAoaW5saW5lKSBhLnNldEF0dHJpYnV0ZSgnc3R5bGUnLCBpbmxpbmUpO1xyXG5cclxuICAgICAgcmV0dXJuIGE7XHJcbiAgICB9LFxyXG5cclxuICAgIHRleHQ6IGZ1bmN0aW9uIChvcHRpb25zLCB1c2VGcmFnbWVudCkge1xyXG4gICAgICB2YXIgdGV4dEVsZW1lbnQgPSBlbGVtZW50VGVtcGxhdGVzLnRleHQuY2xvbmVOb2RlKGZhbHNlKSxcclxuICAgICAgICAgIHN1YnRleHRFbGVtZW50LFxyXG4gICAgICAgICAgaWNvbkVsZW1lbnQ7XHJcblxyXG4gICAgICBpZiAob3B0aW9ucy5jb250ZW50KSB7XHJcbiAgICAgICAgdGV4dEVsZW1lbnQuaW5uZXJIVE1MID0gb3B0aW9ucy5jb250ZW50O1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHRleHRFbGVtZW50LnRleHRDb250ZW50ID0gb3B0aW9ucy50ZXh0O1xyXG5cclxuICAgICAgICBpZiAob3B0aW9ucy5pY29uKSB7XHJcbiAgICAgICAgICB2YXIgd2hpdGVzcGFjZSA9IGVsZW1lbnRUZW1wbGF0ZXMud2hpdGVzcGFjZS5jbG9uZU5vZGUoZmFsc2UpO1xyXG5cclxuICAgICAgICAgIC8vIG5lZWQgdG8gdXNlIDxpPiBmb3IgaWNvbnMgaW4gdGhlIGJ1dHRvbiB0byBwcmV2ZW50IGEgYnJlYWtpbmcgY2hhbmdlXHJcbiAgICAgICAgICAvLyBub3RlOiBzd2l0Y2ggdG8gc3BhbiBpbiBuZXh0IG1ham9yIHJlbGVhc2VcclxuICAgICAgICAgIGljb25FbGVtZW50ID0gKHVzZUZyYWdtZW50ID09PSB0cnVlID8gZWxlbWVudFRlbXBsYXRlcy5pIDogZWxlbWVudFRlbXBsYXRlcy5zcGFuKS5jbG9uZU5vZGUoZmFsc2UpO1xyXG4gICAgICAgICAgaWNvbkVsZW1lbnQuY2xhc3NOYW1lID0gdGhpcy5vcHRpb25zLmljb25CYXNlICsgJyAnICsgb3B0aW9ucy5pY29uO1xyXG5cclxuICAgICAgICAgIGVsZW1lbnRUZW1wbGF0ZXMuZnJhZ21lbnQuYXBwZW5kQ2hpbGQoaWNvbkVsZW1lbnQpO1xyXG4gICAgICAgICAgZWxlbWVudFRlbXBsYXRlcy5mcmFnbWVudC5hcHBlbmRDaGlsZCh3aGl0ZXNwYWNlKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGlmIChvcHRpb25zLnN1YnRleHQpIHtcclxuICAgICAgICAgIHN1YnRleHRFbGVtZW50ID0gZWxlbWVudFRlbXBsYXRlcy5zdWJ0ZXh0LmNsb25lTm9kZShmYWxzZSk7XHJcbiAgICAgICAgICBzdWJ0ZXh0RWxlbWVudC50ZXh0Q29udGVudCA9IG9wdGlvbnMuc3VidGV4dDtcclxuICAgICAgICAgIHRleHRFbGVtZW50LmFwcGVuZENoaWxkKHN1YnRleHRFbGVtZW50KTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmICh1c2VGcmFnbWVudCA9PT0gdHJ1ZSkge1xyXG4gICAgICAgIHdoaWxlICh0ZXh0RWxlbWVudC5jaGlsZE5vZGVzLmxlbmd0aCA+IDApIHtcclxuICAgICAgICAgIGVsZW1lbnRUZW1wbGF0ZXMuZnJhZ21lbnQuYXBwZW5kQ2hpbGQodGV4dEVsZW1lbnQuY2hpbGROb2Rlc1swXSk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIGVsZW1lbnRUZW1wbGF0ZXMuZnJhZ21lbnQuYXBwZW5kQ2hpbGQodGV4dEVsZW1lbnQpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICByZXR1cm4gZWxlbWVudFRlbXBsYXRlcy5mcmFnbWVudDtcclxuICAgIH0sXHJcblxyXG4gICAgbGFiZWw6IGZ1bmN0aW9uIChvcHRpb25zKSB7XHJcbiAgICAgIHZhciB0ZXh0RWxlbWVudCA9IGVsZW1lbnRUZW1wbGF0ZXMudGV4dC5jbG9uZU5vZGUoZmFsc2UpLFxyXG4gICAgICAgICAgc3VidGV4dEVsZW1lbnQsXHJcbiAgICAgICAgICBpY29uRWxlbWVudDtcclxuXHJcbiAgICAgIHRleHRFbGVtZW50LmlubmVySFRNTCA9IG9wdGlvbnMuZGlzcGxheTtcclxuXHJcbiAgICAgIGlmIChvcHRpb25zLmljb24pIHtcclxuICAgICAgICB2YXIgd2hpdGVzcGFjZSA9IGVsZW1lbnRUZW1wbGF0ZXMud2hpdGVzcGFjZS5jbG9uZU5vZGUoZmFsc2UpO1xyXG5cclxuICAgICAgICBpY29uRWxlbWVudCA9IGVsZW1lbnRUZW1wbGF0ZXMuc3Bhbi5jbG9uZU5vZGUoZmFsc2UpO1xyXG4gICAgICAgIGljb25FbGVtZW50LmNsYXNzTmFtZSA9IHRoaXMub3B0aW9ucy5pY29uQmFzZSArICcgJyArIG9wdGlvbnMuaWNvbjtcclxuXHJcbiAgICAgICAgZWxlbWVudFRlbXBsYXRlcy5mcmFnbWVudC5hcHBlbmRDaGlsZChpY29uRWxlbWVudCk7XHJcbiAgICAgICAgZWxlbWVudFRlbXBsYXRlcy5mcmFnbWVudC5hcHBlbmRDaGlsZCh3aGl0ZXNwYWNlKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKG9wdGlvbnMuc3VidGV4dCkge1xyXG4gICAgICAgIHN1YnRleHRFbGVtZW50ID0gZWxlbWVudFRlbXBsYXRlcy5zdWJ0ZXh0LmNsb25lTm9kZShmYWxzZSk7XHJcbiAgICAgICAgc3VidGV4dEVsZW1lbnQudGV4dENvbnRlbnQgPSBvcHRpb25zLnN1YnRleHQ7XHJcbiAgICAgICAgdGV4dEVsZW1lbnQuYXBwZW5kQ2hpbGQoc3VidGV4dEVsZW1lbnQpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBlbGVtZW50VGVtcGxhdGVzLmZyYWdtZW50LmFwcGVuZENoaWxkKHRleHRFbGVtZW50KTtcclxuXHJcbiAgICAgIHJldHVybiBlbGVtZW50VGVtcGxhdGVzLmZyYWdtZW50O1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgdmFyIGdldE9wdGlvbkRhdGEgPSB7XHJcbiAgICBmcm9tT3B0aW9uOiBmdW5jdGlvbiAob3B0aW9uLCB0eXBlKSB7XHJcbiAgICAgIHZhciB2YWx1ZTtcclxuXHJcbiAgICAgIHN3aXRjaCAodHlwZSkge1xyXG4gICAgICAgIGNhc2UgJ2RpdmlkZXInOlxyXG4gICAgICAgICAgdmFsdWUgPSBvcHRpb24uZ2V0QXR0cmlidXRlKCdkYXRhLWRpdmlkZXInKSA9PT0gJ3RydWUnO1xyXG4gICAgICAgICAgYnJlYWs7XHJcblxyXG4gICAgICAgIGNhc2UgJ3RleHQnOlxyXG4gICAgICAgICAgdmFsdWUgPSBvcHRpb24udGV4dENvbnRlbnQ7XHJcbiAgICAgICAgICBicmVhaztcclxuXHJcbiAgICAgICAgY2FzZSAnbGFiZWwnOlxyXG4gICAgICAgICAgdmFsdWUgPSBvcHRpb24ubGFiZWw7XHJcbiAgICAgICAgICBicmVhaztcclxuXHJcbiAgICAgICAgY2FzZSAnc3R5bGUnOlxyXG4gICAgICAgICAgdmFsdWUgPSBvcHRpb24uc3R5bGUuY3NzVGV4dDtcclxuICAgICAgICAgIGJyZWFrO1xyXG5cclxuICAgICAgICBjYXNlICdjb250ZW50JzpcclxuICAgICAgICBjYXNlICd0b2tlbnMnOlxyXG4gICAgICAgIGNhc2UgJ3N1YnRleHQnOlxyXG4gICAgICAgIGNhc2UgJ2ljb24nOlxyXG4gICAgICAgICAgdmFsdWUgPSBvcHRpb24uZ2V0QXR0cmlidXRlKCdkYXRhLScgKyB0eXBlKTtcclxuICAgICAgICAgIGJyZWFrO1xyXG4gICAgICB9XHJcblxyXG4gICAgICByZXR1cm4gdmFsdWU7XHJcbiAgICB9LFxyXG4gICAgZnJvbURhdGFTb3VyY2U6IGZ1bmN0aW9uIChvcHRpb24sIHR5cGUpIHtcclxuICAgICAgdmFyIHZhbHVlO1xyXG5cclxuICAgICAgc3dpdGNoICh0eXBlKSB7XHJcbiAgICAgICAgY2FzZSAndGV4dCc6XHJcbiAgICAgICAgY2FzZSAnbGFiZWwnOlxyXG4gICAgICAgICAgdmFsdWUgPSBvcHRpb24udGV4dCB8fCBvcHRpb24udmFsdWUgfHwgJyc7XHJcbiAgICAgICAgICBicmVhaztcclxuXHJcbiAgICAgICAgY2FzZSAnZGl2aWRlcic6XHJcbiAgICAgICAgY2FzZSAnc3R5bGUnOlxyXG4gICAgICAgIGNhc2UgJ2NvbnRlbnQnOlxyXG4gICAgICAgIGNhc2UgJ3Rva2Vucyc6XHJcbiAgICAgICAgY2FzZSAnc3VidGV4dCc6XHJcbiAgICAgICAgY2FzZSAnaWNvbic6XHJcbiAgICAgICAgICB2YWx1ZSA9IG9wdGlvblt0eXBlXTtcclxuICAgICAgICAgIGJyZWFrO1xyXG4gICAgICB9XHJcblxyXG4gICAgICByZXR1cm4gdmFsdWU7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiBzaG93Tm9SZXN1bHRzIChzZWFyY2hNYXRjaCwgc2VhcmNoVmFsdWUpIHtcclxuICAgIGlmICghc2VhcmNoTWF0Y2gubGVuZ3RoKSB7XHJcbiAgICAgIGVsZW1lbnRUZW1wbGF0ZXMubm9SZXN1bHRzLmlubmVySFRNTCA9IHRoaXMub3B0aW9ucy5ub25lUmVzdWx0c1RleHQucmVwbGFjZSgnezB9JywgJ1wiJyArIGh0bWxFc2NhcGUoc2VhcmNoVmFsdWUpICsgJ1wiJyk7XHJcbiAgICAgIHRoaXMuJG1lbnVJbm5lclswXS5maXJzdENoaWxkLmFwcGVuZENoaWxkKGVsZW1lbnRUZW1wbGF0ZXMubm9SZXN1bHRzKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIGZ1bmN0aW9uIGZpbHRlckhpZGRlbiAoaXRlbSkge1xyXG4gICAgcmV0dXJuICEoaXRlbS5oaWRkZW4gfHwgdGhpcy5vcHRpb25zLmhpZGVEaXNhYmxlZCAmJiBpdGVtLmRpc2FibGVkKTtcclxuICB9XHJcblxyXG4gIHZhciBTZWxlY3RwaWNrZXIgPSBmdW5jdGlvbiAoZWxlbWVudCwgb3B0aW9ucykge1xyXG4gICAgdmFyIHRoYXQgPSB0aGlzO1xyXG5cclxuICAgIC8vIGJvb3RzdHJhcC1zZWxlY3QgaGFzIGJlZW4gaW5pdGlhbGl6ZWQgLSByZXZlcnQgdmFsSG9va3Muc2VsZWN0LnNldCBiYWNrIHRvIGl0cyBvcmlnaW5hbCBmdW5jdGlvblxyXG4gICAgaWYgKCF2YWxIb29rcy51c2VEZWZhdWx0KSB7XHJcbiAgICAgICQudmFsSG9va3Muc2VsZWN0LnNldCA9IHZhbEhvb2tzLl9zZXQ7XHJcbiAgICAgIHZhbEhvb2tzLnVzZURlZmF1bHQgPSB0cnVlO1xyXG4gICAgfVxyXG5cclxuICAgIHRoaXMuJGVsZW1lbnQgPSAkKGVsZW1lbnQpO1xyXG4gICAgdGhpcy4kbmV3RWxlbWVudCA9IG51bGw7XHJcbiAgICB0aGlzLiRidXR0b24gPSBudWxsO1xyXG4gICAgdGhpcy4kbWVudSA9IG51bGw7XHJcbiAgICB0aGlzLm9wdGlvbnMgPSBvcHRpb25zO1xyXG4gICAgdGhpcy5zZWxlY3RwaWNrZXIgPSB7XHJcbiAgICAgIG1haW46IHtcclxuICAgICAgICBvcHRpb25RdWV1ZTogZWxlbWVudFRlbXBsYXRlcy5mcmFnbWVudC5jbG9uZU5vZGUoZmFsc2UpXHJcbiAgICAgIH0sXHJcbiAgICAgIHNlYXJjaDoge30sXHJcbiAgICAgIGN1cnJlbnQ6IHt9LCAvLyBjdXJyZW50IGNoYW5nZXMgaWYgYSBzZWFyY2ggaXMgaW4gcHJvZ3Jlc3NcclxuICAgICAgdmlldzoge30sXHJcbiAgICAgIGlzU2VhcmNoaW5nOiBmYWxzZSxcclxuICAgICAga2V5ZG93bjoge1xyXG4gICAgICAgIGtleUhpc3Rvcnk6ICcnLFxyXG4gICAgICAgIHJlc2V0S2V5SGlzdG9yeToge1xyXG4gICAgICAgICAgc3RhcnQ6IGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgcmV0dXJuIHNldFRpbWVvdXQoZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICAgIHRoYXQuc2VsZWN0cGlja2VyLmtleWRvd24ua2V5SGlzdG9yeSA9ICcnO1xyXG4gICAgICAgICAgICB9LCA4MDApO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfTtcclxuXHJcbiAgICB0aGlzLnNpemVJbmZvID0ge307XHJcblxyXG4gICAgLy8gRm9ybWF0IHdpbmRvdyBwYWRkaW5nXHJcbiAgICB2YXIgd2luUGFkID0gdGhpcy5vcHRpb25zLndpbmRvd1BhZGRpbmc7XHJcbiAgICBpZiAodHlwZW9mIHdpblBhZCA9PT0gJ251bWJlcicpIHtcclxuICAgICAgdGhpcy5vcHRpb25zLndpbmRvd1BhZGRpbmcgPSBbd2luUGFkLCB3aW5QYWQsIHdpblBhZCwgd2luUGFkXTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBFeHBvc2UgcHVibGljIG1ldGhvZHNcclxuICAgIHRoaXMudmFsID0gU2VsZWN0cGlja2VyLnByb3RvdHlwZS52YWw7XHJcbiAgICB0aGlzLnJlbmRlciA9IFNlbGVjdHBpY2tlci5wcm90b3R5cGUucmVuZGVyO1xyXG4gICAgdGhpcy5yZWZyZXNoID0gU2VsZWN0cGlja2VyLnByb3RvdHlwZS5yZWZyZXNoO1xyXG4gICAgdGhpcy5zZXRTdHlsZSA9IFNlbGVjdHBpY2tlci5wcm90b3R5cGUuc2V0U3R5bGU7XHJcbiAgICB0aGlzLnNlbGVjdEFsbCA9IFNlbGVjdHBpY2tlci5wcm90b3R5cGUuc2VsZWN0QWxsO1xyXG4gICAgdGhpcy5kZXNlbGVjdEFsbCA9IFNlbGVjdHBpY2tlci5wcm90b3R5cGUuZGVzZWxlY3RBbGw7XHJcbiAgICB0aGlzLmRlc3Ryb3kgPSBTZWxlY3RwaWNrZXIucHJvdG90eXBlLmRlc3Ryb3k7XHJcbiAgICB0aGlzLnJlbW92ZSA9IFNlbGVjdHBpY2tlci5wcm90b3R5cGUucmVtb3ZlO1xyXG4gICAgdGhpcy5zaG93ID0gU2VsZWN0cGlja2VyLnByb3RvdHlwZS5zaG93O1xyXG4gICAgdGhpcy5oaWRlID0gU2VsZWN0cGlja2VyLnByb3RvdHlwZS5oaWRlO1xyXG5cclxuICAgIHRoaXMuaW5pdCgpO1xyXG4gIH07XHJcblxyXG4gIFNlbGVjdHBpY2tlci5WRVJTSU9OID0gJzEuMTQuMC1iZXRhMic7XHJcblxyXG4gIC8vIHBhcnQgb2YgdGhpcyBpcyBkdXBsaWNhdGVkIGluIGkxOG4vZGVmYXVsdHMtZW5fVVMuanMuIE1ha2Ugc3VyZSB0byB1cGRhdGUgYm90aC5cclxuICBTZWxlY3RwaWNrZXIuREVGQVVMVFMgPSB7XHJcbiAgICBub25lU2VsZWN0ZWRUZXh0OiAnTm90aGluZyBzZWxlY3RlZCcsXHJcbiAgICBub25lUmVzdWx0c1RleHQ6ICdObyByZXN1bHRzIG1hdGNoZWQgezB9JyxcclxuICAgIGNvdW50U2VsZWN0ZWRUZXh0OiBmdW5jdGlvbiAobnVtU2VsZWN0ZWQsIG51bVRvdGFsKSB7XHJcbiAgICAgIHJldHVybiAobnVtU2VsZWN0ZWQgPT0gMSkgPyAnezB9IGl0ZW0gc2VsZWN0ZWQnIDogJ3swfSBpdGVtcyBzZWxlY3RlZCc7XHJcbiAgICB9LFxyXG4gICAgbWF4T3B0aW9uc1RleHQ6IGZ1bmN0aW9uIChudW1BbGwsIG51bUdyb3VwKSB7XHJcbiAgICAgIHJldHVybiBbXHJcbiAgICAgICAgKG51bUFsbCA9PSAxKSA/ICdMaW1pdCByZWFjaGVkICh7bn0gaXRlbSBtYXgpJyA6ICdMaW1pdCByZWFjaGVkICh7bn0gaXRlbXMgbWF4KScsXHJcbiAgICAgICAgKG51bUdyb3VwID09IDEpID8gJ0dyb3VwIGxpbWl0IHJlYWNoZWQgKHtufSBpdGVtIG1heCknIDogJ0dyb3VwIGxpbWl0IHJlYWNoZWQgKHtufSBpdGVtcyBtYXgpJ1xyXG4gICAgICBdO1xyXG4gICAgfSxcclxuICAgIHNlbGVjdEFsbFRleHQ6ICdTZWxlY3QgQWxsJyxcclxuICAgIGRlc2VsZWN0QWxsVGV4dDogJ0Rlc2VsZWN0IEFsbCcsXHJcbiAgICBzb3VyY2U6IHt9LFxyXG4gICAgY2h1bmtTaXplOiA0MCxcclxuICAgIGRvbmVCdXR0b246IGZhbHNlLFxyXG4gICAgZG9uZUJ1dHRvblRleHQ6ICdDbG9zZScsXHJcbiAgICBtdWx0aXBsZVNlcGFyYXRvcjogJywgJyxcclxuICAgIHN0eWxlQmFzZTogJ2J0bicsXHJcbiAgICBzdHlsZTogY2xhc3NOYW1lcy5CVVRUT05DTEFTUyxcclxuICAgIHNpemU6ICdhdXRvJyxcclxuICAgIHRpdGxlOiBudWxsLFxyXG4gICAgcGxhY2Vob2xkZXI6IG51bGwsXHJcbiAgICBhbGxvd0NsZWFyOiBmYWxzZSxcclxuICAgIHNlbGVjdGVkVGV4dEZvcm1hdDogJ3ZhbHVlcycsXHJcbiAgICB3aWR0aDogZmFsc2UsXHJcbiAgICBjb250YWluZXI6IGZhbHNlLFxyXG4gICAgaGlkZURpc2FibGVkOiBmYWxzZSxcclxuICAgIHNob3dTdWJ0ZXh0OiBmYWxzZSxcclxuICAgIHNob3dJY29uOiB0cnVlLFxyXG4gICAgc2hvd0NvbnRlbnQ6IHRydWUsXHJcbiAgICBkcm9wdXBBdXRvOiB0cnVlLFxyXG4gICAgaGVhZGVyOiBmYWxzZSxcclxuICAgIGxpdmVTZWFyY2g6IGZhbHNlLFxyXG4gICAgbGl2ZVNlYXJjaFBsYWNlaG9sZGVyOiBudWxsLFxyXG4gICAgbGl2ZVNlYXJjaE5vcm1hbGl6ZTogZmFsc2UsXHJcbiAgICBsaXZlU2VhcmNoU3R5bGU6ICdjb250YWlucycsXHJcbiAgICBhY3Rpb25zQm94OiBmYWxzZSxcclxuICAgIGljb25CYXNlOiBjbGFzc05hbWVzLklDT05CQVNFLFxyXG4gICAgdGlja0ljb246IGNsYXNzTmFtZXMuVElDS0lDT04sXHJcbiAgICBzaG93VGljazogZmFsc2UsXHJcbiAgICB0ZW1wbGF0ZToge1xyXG4gICAgICBjYXJldDogJzxzcGFuIGNsYXNzPVwiY2FyZXRcIj48L3NwYW4+J1xyXG4gICAgfSxcclxuICAgIG1heE9wdGlvbnM6IGZhbHNlLFxyXG4gICAgbW9iaWxlOiBmYWxzZSxcclxuICAgIHNlbGVjdE9uVGFiOiBmYWxzZSxcclxuICAgIGRyb3Bkb3duQWxpZ25SaWdodDogZmFsc2UsXHJcbiAgICB3aW5kb3dQYWRkaW5nOiAwLFxyXG4gICAgdmlydHVhbFNjcm9sbDogNjAwLFxyXG4gICAgZGlzcGxheTogZmFsc2UsXHJcbiAgICBzYW5pdGl6ZTogdHJ1ZSxcclxuICAgIHNhbml0aXplRm46IG51bGwsXHJcbiAgICB3aGl0ZUxpc3Q6IERlZmF1bHRXaGl0ZWxpc3RcclxuICB9O1xyXG5cclxuICBTZWxlY3RwaWNrZXIucHJvdG90eXBlID0ge1xyXG5cclxuICAgIGNvbnN0cnVjdG9yOiBTZWxlY3RwaWNrZXIsXHJcblxyXG4gICAgaW5pdDogZnVuY3Rpb24gKCkge1xyXG4gICAgICB2YXIgdGhhdCA9IHRoaXMsXHJcbiAgICAgICAgICBpZCA9IHRoaXMuJGVsZW1lbnQuYXR0cignaWQnKSxcclxuICAgICAgICAgIGVsZW1lbnQgPSB0aGlzLiRlbGVtZW50WzBdLFxyXG4gICAgICAgICAgZm9ybSA9IGVsZW1lbnQuZm9ybTtcclxuXHJcbiAgICAgIHNlbGVjdElkKys7XHJcbiAgICAgIHRoaXMuc2VsZWN0SWQgPSAnYnMtc2VsZWN0LScgKyBzZWxlY3RJZDtcclxuXHJcbiAgICAgIGVsZW1lbnQuY2xhc3NMaXN0LmFkZCgnYnMtc2VsZWN0LWhpZGRlbicpO1xyXG5cclxuICAgICAgdGhpcy5tdWx0aXBsZSA9IHRoaXMuJGVsZW1lbnQucHJvcCgnbXVsdGlwbGUnKTtcclxuICAgICAgdGhpcy5hdXRvZm9jdXMgPSB0aGlzLiRlbGVtZW50LnByb3AoJ2F1dG9mb2N1cycpO1xyXG5cclxuICAgICAgaWYgKGVsZW1lbnQuY2xhc3NMaXN0LmNvbnRhaW5zKCdzaG93LXRpY2snKSkge1xyXG4gICAgICAgIHRoaXMub3B0aW9ucy5zaG93VGljayA9IHRydWU7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHRoaXMuJG5ld0VsZW1lbnQgPSB0aGlzLmNyZWF0ZURyb3Bkb3duKCk7XHJcblxyXG4gICAgICB0aGlzLiRlbGVtZW50XHJcbiAgICAgICAgLmFmdGVyKHRoaXMuJG5ld0VsZW1lbnQpXHJcbiAgICAgICAgLnByZXBlbmRUbyh0aGlzLiRuZXdFbGVtZW50KTtcclxuXHJcbiAgICAgIC8vIGVuc3VyZSBzZWxlY3QgaXMgYXNzb2NpYXRlZCB3aXRoIGZvcm0gZWxlbWVudCBpZiBpdCBnb3QgdW5saW5rZWQgYWZ0ZXIgbW92aW5nIGl0IGluc2lkZSBuZXdFbGVtZW50XHJcbiAgICAgIGlmIChmb3JtICYmIGVsZW1lbnQuZm9ybSA9PT0gbnVsbCkge1xyXG4gICAgICAgIGlmICghZm9ybS5pZCkgZm9ybS5pZCA9ICdmb3JtLScgKyB0aGlzLnNlbGVjdElkO1xyXG4gICAgICAgIGVsZW1lbnQuc2V0QXR0cmlidXRlKCdmb3JtJywgZm9ybS5pZCk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHRoaXMuJGJ1dHRvbiA9IHRoaXMuJG5ld0VsZW1lbnQuY2hpbGRyZW4oJ2J1dHRvbicpO1xyXG4gICAgICBpZiAodGhpcy5vcHRpb25zLmFsbG93Q2xlYXIpIHRoaXMuJGNsZWFyQnV0dG9uID0gdGhpcy4kYnV0dG9uLmNoaWxkcmVuKCcuYnMtc2VsZWN0LWNsZWFyLXNlbGVjdGVkJyk7XHJcbiAgICAgIHRoaXMuJG1lbnUgPSB0aGlzLiRuZXdFbGVtZW50LmNoaWxkcmVuKFNlbGVjdG9yLk1FTlUpO1xyXG4gICAgICB0aGlzLiRtZW51SW5uZXIgPSB0aGlzLiRtZW51LmNoaWxkcmVuKCcuaW5uZXInKTtcclxuICAgICAgdGhpcy4kc2VhcmNoYm94ID0gdGhpcy4kbWVudS5maW5kKCdpbnB1dCcpO1xyXG5cclxuICAgICAgZWxlbWVudC5jbGFzc0xpc3QucmVtb3ZlKCdicy1zZWxlY3QtaGlkZGVuJyk7XHJcblxyXG4gICAgICB0aGlzLmZldGNoRGF0YShmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgdGhhdC5yZW5kZXIodHJ1ZSk7XHJcbiAgICAgICAgdGhhdC5idWlsZExpc3QoKTtcclxuXHJcbiAgICAgICAgcmVxdWVzdEFuaW1hdGlvbkZyYW1lKGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgIHRoYXQuJGVsZW1lbnQudHJpZ2dlcignbG9hZGVkJyArIEVWRU5UX0tFWSk7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgdGhpcy5mZXRjaERhdGEoZnVuY3Rpb24gKCkge1xyXG4gICAgICAgIHRoYXQucmVuZGVyKHRydWUpO1xyXG4gICAgICAgIHRoYXQuYnVpbGRMaXN0KCk7XHJcblxyXG4gICAgICAgIHJlcXVlc3RBbmltYXRpb25GcmFtZShmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICB0aGF0LiRlbGVtZW50LnRyaWdnZXIoJ2xvYWRlZCcgKyBFVkVOVF9LRVkpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9KTtcclxuXHJcbiAgICAgIGlmICh0aGlzLm9wdGlvbnMuZHJvcGRvd25BbGlnblJpZ2h0ID09PSB0cnVlKSB0aGlzLiRtZW51WzBdLmNsYXNzTGlzdC5hZGQoY2xhc3NOYW1lcy5NRU5VUklHSFQpO1xyXG5cclxuICAgICAgaWYgKHR5cGVvZiBpZCAhPT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgICB0aGlzLiRidXR0b24uYXR0cignZGF0YS1pZCcsIGlkKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgdGhpcy5jaGVja0Rpc2FibGVkKCk7XHJcbiAgICAgIHRoaXMuY2xpY2tMaXN0ZW5lcigpO1xyXG5cclxuICAgICAgaWYgKHZlcnNpb24ubWFqb3IgPiA0KSB0aGlzLmRyb3Bkb3duID0gbmV3IERyb3Bkb3duKHRoaXMuJGJ1dHRvblswXSk7XHJcblxyXG4gICAgICBpZiAodGhpcy5vcHRpb25zLmxpdmVTZWFyY2gpIHtcclxuICAgICAgICB0aGlzLmxpdmVTZWFyY2hMaXN0ZW5lcigpO1xyXG4gICAgICAgIHRoaXMuZm9jdXNlZFBhcmVudCA9IHRoaXMuJHNlYXJjaGJveFswXTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICB0aGlzLmZvY3VzZWRQYXJlbnQgPSB0aGlzLiRtZW51SW5uZXJbMF07XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHRoaXMuc2V0U3R5bGUoKTtcclxuICAgICAgdGhpcy5zZXRXaWR0aCgpO1xyXG4gICAgICBpZiAodGhpcy5vcHRpb25zLmNvbnRhaW5lcikge1xyXG4gICAgICAgIHRoaXMuc2VsZWN0UG9zaXRpb24oKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICB0aGlzLiRlbGVtZW50Lm9uKCdoaWRlJyArIEVWRU5UX0tFWSwgZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgaWYgKHRoYXQuaXNWaXJ0dWFsKCkpIHtcclxuICAgICAgICAgICAgLy8gZW1wdHkgbWVudSBvbiBjbG9zZVxyXG4gICAgICAgICAgICB2YXIgbWVudUlubmVyID0gdGhhdC4kbWVudUlubmVyWzBdLFxyXG4gICAgICAgICAgICAgICAgZW1wdHlNZW51ID0gbWVudUlubmVyLmZpcnN0Q2hpbGQuY2xvbmVOb2RlKGZhbHNlKTtcclxuXHJcbiAgICAgICAgICAgIC8vIHJlcGxhY2UgdGhlIGV4aXN0aW5nIFVMIHdpdGggYW4gZW1wdHkgb25lIC0gdGhpcyBpcyBmYXN0ZXIgdGhhbiAkLmVtcHR5KCkgb3IgaW5uZXJIVE1MID0gJydcclxuICAgICAgICAgICAgbWVudUlubmVyLnJlcGxhY2VDaGlsZChlbXB0eU1lbnUsIG1lbnVJbm5lci5maXJzdENoaWxkKTtcclxuICAgICAgICAgICAgbWVudUlubmVyLnNjcm9sbFRvcCA9IDA7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH1cclxuICAgICAgdGhpcy4kbWVudS5kYXRhKCd0aGlzJywgdGhpcyk7XHJcbiAgICAgIHRoaXMuJG5ld0VsZW1lbnQuZGF0YSgndGhpcycsIHRoaXMpO1xyXG4gICAgICBpZiAodGhpcy5vcHRpb25zLm1vYmlsZSkgdGhpcy5tb2JpbGUoKTtcclxuXHJcbiAgICAgIHRoaXMuJG5ld0VsZW1lbnQub24oe1xyXG4gICAgICAgICdoaWRlLmJzLmRyb3Bkb3duJzogZnVuY3Rpb24gKGUpIHtcclxuICAgICAgICAgIHRoYXQuJGVsZW1lbnQudHJpZ2dlcignaGlkZScgKyBFVkVOVF9LRVksIGUpO1xyXG4gICAgICAgIH0sXHJcbiAgICAgICAgJ2hpZGRlbi5icy5kcm9wZG93bic6IGZ1bmN0aW9uIChlKSB7XHJcbiAgICAgICAgICB0aGF0LiRlbGVtZW50LnRyaWdnZXIoJ2hpZGRlbicgKyBFVkVOVF9LRVksIGUpO1xyXG4gICAgICAgIH0sXHJcbiAgICAgICAgJ3Nob3cuYnMuZHJvcGRvd24nOiBmdW5jdGlvbiAoZSkge1xyXG4gICAgICAgICAgdGhhdC4kZWxlbWVudC50cmlnZ2VyKCdzaG93JyArIEVWRU5UX0tFWSwgZSk7XHJcbiAgICAgICAgfSxcclxuICAgICAgICAnc2hvd24uYnMuZHJvcGRvd24nOiBmdW5jdGlvbiAoZSkge1xyXG4gICAgICAgICAgdGhhdC4kZWxlbWVudC50cmlnZ2VyKCdzaG93bicgKyBFVkVOVF9LRVksIGUpO1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcblxyXG4gICAgICBpZiAoZWxlbWVudC5oYXNBdHRyaWJ1dGUoJ3JlcXVpcmVkJykpIHtcclxuICAgICAgICB0aGlzLiRlbGVtZW50Lm9uKCdpbnZhbGlkJyArIEVWRU5UX0tFWSwgZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgdGhhdC4kYnV0dG9uWzBdLmNsYXNzTGlzdC5hZGQoJ2JzLWludmFsaWQnKTtcclxuXHJcbiAgICAgICAgICB0aGF0LiRlbGVtZW50XHJcbiAgICAgICAgICAgIC5vbignc2hvd24nICsgRVZFTlRfS0VZICsgJy5pbnZhbGlkJywgZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICAgIHRoYXQuJGVsZW1lbnRcclxuICAgICAgICAgICAgICAgIC52YWwodGhhdC4kZWxlbWVudC52YWwoKSkgLy8gc2V0IHRoZSB2YWx1ZSB0byBoaWRlIHRoZSB2YWxpZGF0aW9uIG1lc3NhZ2UgaW4gQ2hyb21lIHdoZW4gbWVudSBpcyBvcGVuZWRcclxuICAgICAgICAgICAgICAgIC5vZmYoJ3Nob3duJyArIEVWRU5UX0tFWSArICcuaW52YWxpZCcpO1xyXG4gICAgICAgICAgICB9KVxyXG4gICAgICAgICAgICAub24oJ3JlbmRlcmVkJyArIEVWRU5UX0tFWSwgZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICAgIC8vIGlmIHNlbGVjdCBpcyBubyBsb25nZXIgaW52YWxpZCwgcmVtb3ZlIHRoZSBicy1pbnZhbGlkIGNsYXNzXHJcbiAgICAgICAgICAgICAgaWYgKHRoaXMudmFsaWRpdHkudmFsaWQpIHRoYXQuJGJ1dHRvblswXS5jbGFzc0xpc3QucmVtb3ZlKCdicy1pbnZhbGlkJyk7XHJcbiAgICAgICAgICAgICAgdGhhdC4kZWxlbWVudC5vZmYoJ3JlbmRlcmVkJyArIEVWRU5UX0tFWSk7XHJcbiAgICAgICAgICAgIH0pO1xyXG5cclxuICAgICAgICAgIHRoYXQuJGJ1dHRvbi5vbignYmx1cicgKyBFVkVOVF9LRVksIGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgdGhhdC4kZWxlbWVudC50cmlnZ2VyKCdmb2N1cycpLnRyaWdnZXIoJ2JsdXInKTtcclxuICAgICAgICAgICAgdGhhdC4kYnV0dG9uLm9mZignYmx1cicgKyBFVkVOVF9LRVkpO1xyXG4gICAgICAgICAgfSk7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmIChmb3JtKSB7XHJcbiAgICAgICAgJChmb3JtKS5vbigncmVzZXQnICsgRVZFTlRfS0VZLCBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICByZXF1ZXN0QW5pbWF0aW9uRnJhbWUoZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICB0aGF0LnJlbmRlcigpO1xyXG4gICAgICAgICAgfSk7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH1cclxuICAgIH0sXHJcblxyXG4gICAgY3JlYXRlRHJvcGRvd246IGZ1bmN0aW9uICgpIHtcclxuICAgICAgLy8gT3B0aW9uc1xyXG4gICAgICAvLyBJZiB3ZSBhcmUgbXVsdGlwbGUgb3Igc2hvd1RpY2sgb3B0aW9uIGlzIHNldCwgdGhlbiBhZGQgdGhlIHNob3ctdGljayBjbGFzc1xyXG4gICAgICB2YXIgc2hvd1RpY2sgPSAodGhpcy5tdWx0aXBsZSB8fCB0aGlzLm9wdGlvbnMuc2hvd1RpY2spID8gJyBzaG93LXRpY2snIDogJycsXHJcbiAgICAgICAgICBtdWx0aXNlbGVjdGFibGUgPSB0aGlzLm11bHRpcGxlID8gJyBhcmlhLW11bHRpc2VsZWN0YWJsZT1cInRydWVcIicgOiAnJyxcclxuICAgICAgICAgIGlucHV0R3JvdXAgPSAnJyxcclxuICAgICAgICAgIGF1dG9mb2N1cyA9IHRoaXMuYXV0b2ZvY3VzID8gJyBhdXRvZm9jdXMnIDogJyc7XHJcblxyXG4gICAgICBpZiAodmVyc2lvbi5tYWpvciA8IDQgJiYgdGhpcy4kZWxlbWVudC5wYXJlbnQoKS5oYXNDbGFzcygnaW5wdXQtZ3JvdXAnKSkge1xyXG4gICAgICAgIGlucHV0R3JvdXAgPSAnIGlucHV0LWdyb3VwLWJ0bic7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIEVsZW1lbnRzXHJcbiAgICAgIHZhciBkcm9wLFxyXG4gICAgICAgICAgaGVhZGVyID0gJycsXHJcbiAgICAgICAgICBzZWFyY2hib3ggPSAnJyxcclxuICAgICAgICAgIGFjdGlvbnNib3ggPSAnJyxcclxuICAgICAgICAgIGRvbmVidXR0b24gPSAnJyxcclxuICAgICAgICAgIGNsZWFyQnV0dG9uID0gJyc7XHJcblxyXG4gICAgICBpZiAodGhpcy5vcHRpb25zLmhlYWRlcikge1xyXG4gICAgICAgIGhlYWRlciA9XHJcbiAgICAgICAgICAnPGRpdiBjbGFzcz1cIicgKyBjbGFzc05hbWVzLlBPUE9WRVJIRUFERVIgKyAnXCI+JyArXHJcbiAgICAgICAgICAgICc8YnV0dG9uIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cImNsb3NlXCIgYXJpYS1oaWRkZW49XCJ0cnVlXCI+JnRpbWVzOzwvYnV0dG9uPicgK1xyXG4gICAgICAgICAgICAgIHRoaXMub3B0aW9ucy5oZWFkZXIgK1xyXG4gICAgICAgICAgJzwvZGl2Pic7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmICh0aGlzLm9wdGlvbnMubGl2ZVNlYXJjaCkge1xyXG4gICAgICAgIHNlYXJjaGJveCA9XHJcbiAgICAgICAgICAnPGRpdiBjbGFzcz1cImJzLXNlYXJjaGJveFwiPicgK1xyXG4gICAgICAgICAgICAnPGlucHV0IHR5cGU9XCJzZWFyY2hcIiBjbGFzcz1cImZvcm0tY29udHJvbFwiIGF1dG9jb21wbGV0ZT1cIm9mZlwiJyArXHJcbiAgICAgICAgICAgICAgKFxyXG4gICAgICAgICAgICAgICAgdGhpcy5vcHRpb25zLmxpdmVTZWFyY2hQbGFjZWhvbGRlciA9PT0gbnVsbCA/ICcnXHJcbiAgICAgICAgICAgICAgICA6XHJcbiAgICAgICAgICAgICAgICAnIHBsYWNlaG9sZGVyPVwiJyArIGh0bWxFc2NhcGUodGhpcy5vcHRpb25zLmxpdmVTZWFyY2hQbGFjZWhvbGRlcikgKyAnXCInXHJcbiAgICAgICAgICAgICAgKSArXHJcbiAgICAgICAgICAgICAgJyByb2xlPVwiY29tYm9ib3hcIiBhcmlhLWxhYmVsPVwiU2VhcmNoXCIgYXJpYS1jb250cm9scz1cIicgKyB0aGlzLnNlbGVjdElkICsgJ1wiIGFyaWEtYXV0b2NvbXBsZXRlPVwibGlzdFwiPicgK1xyXG4gICAgICAgICAgJzwvZGl2Pic7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmICh0aGlzLm11bHRpcGxlICYmIHRoaXMub3B0aW9ucy5hY3Rpb25zQm94KSB7XHJcbiAgICAgICAgYWN0aW9uc2JveCA9XHJcbiAgICAgICAgICAnPGRpdiBjbGFzcz1cImJzLWFjdGlvbnNib3hcIj4nICtcclxuICAgICAgICAgICAgJzxkaXYgY2xhc3M9XCJidG4tZ3JvdXAgYnRuLWdyb3VwLXNtXCI+JyArXHJcbiAgICAgICAgICAgICAgJzxidXR0b24gdHlwZT1cImJ1dHRvblwiIGNsYXNzPVwiYWN0aW9ucy1idG4gYnMtc2VsZWN0LWFsbCBidG4gJyArIGNsYXNzTmFtZXMuQlVUVE9OQ0xBU1MgKyAnXCI+JyArXHJcbiAgICAgICAgICAgICAgICB0aGlzLm9wdGlvbnMuc2VsZWN0QWxsVGV4dCArXHJcbiAgICAgICAgICAgICAgJzwvYnV0dG9uPicgK1xyXG4gICAgICAgICAgICAgICc8YnV0dG9uIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cImFjdGlvbnMtYnRuIGJzLWRlc2VsZWN0LWFsbCBidG4gJyArIGNsYXNzTmFtZXMuQlVUVE9OQ0xBU1MgKyAnXCI+JyArXHJcbiAgICAgICAgICAgICAgICB0aGlzLm9wdGlvbnMuZGVzZWxlY3RBbGxUZXh0ICtcclxuICAgICAgICAgICAgICAnPC9idXR0b24+JyArXHJcbiAgICAgICAgICAgICc8L2Rpdj4nICtcclxuICAgICAgICAgICc8L2Rpdj4nO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAodGhpcy5tdWx0aXBsZSAmJiB0aGlzLm9wdGlvbnMuZG9uZUJ1dHRvbikge1xyXG4gICAgICAgIGRvbmVidXR0b24gPVxyXG4gICAgICAgICAgJzxkaXYgY2xhc3M9XCJicy1kb25lYnV0dG9uXCI+JyArXHJcbiAgICAgICAgICAgICc8ZGl2IGNsYXNzPVwiYnRuLWdyb3VwXCI+JyArXHJcbiAgICAgICAgICAgICAgJzxidXR0b24gdHlwZT1cImJ1dHRvblwiIGNsYXNzPVwiYnRuIGJ0bi1zbSAnICsgY2xhc3NOYW1lcy5CVVRUT05DTEFTUyArICdcIj4nICtcclxuICAgICAgICAgICAgICAgIHRoaXMub3B0aW9ucy5kb25lQnV0dG9uVGV4dCArXHJcbiAgICAgICAgICAgICAgJzwvYnV0dG9uPicgK1xyXG4gICAgICAgICAgICAnPC9kaXY+JyArXHJcbiAgICAgICAgICAnPC9kaXY+JztcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKHRoaXMub3B0aW9ucy5hbGxvd0NsZWFyKSB7XHJcbiAgICAgICAgY2xlYXJCdXR0b24gPSAnPHNwYW4gY2xhc3M9XCJjbG9zZSBicy1zZWxlY3QtY2xlYXItc2VsZWN0ZWRcIiB0aXRsZT1cIicgKyB0aGlzLm9wdGlvbnMuZGVzZWxlY3RBbGxUZXh0ICsgJ1wiPjxzcGFuPiZ0aW1lczs8L3NwYW4+JztcclxuICAgICAgfVxyXG5cclxuICAgICAgZHJvcCA9XHJcbiAgICAgICAgJzxkaXYgY2xhc3M9XCJkcm9wZG93biBib290c3RyYXAtc2VsZWN0JyArIHNob3dUaWNrICsgaW5wdXRHcm91cCArICdcIj4nICtcclxuICAgICAgICAgICc8YnV0dG9uIHR5cGU9XCJidXR0b25cIiB0YWJpbmRleD1cIi0xXCIgY2xhc3M9XCInICtcclxuICAgICAgICAgICAgdGhpcy5vcHRpb25zLnN0eWxlQmFzZSArXHJcbiAgICAgICAgICAgICcgZHJvcGRvd24tdG9nZ2xlXCIgJyArXHJcbiAgICAgICAgICAgICh0aGlzLm9wdGlvbnMuZGlzcGxheSA9PT0gJ3N0YXRpYycgPyAnZGF0YS1kaXNwbGF5PVwic3RhdGljXCInIDogJycpICtcclxuICAgICAgICAgICAgU2VsZWN0b3IuREFUQV9UT0dHTEUgK1xyXG4gICAgICAgICAgICBhdXRvZm9jdXMgK1xyXG4gICAgICAgICAgICAnIHJvbGU9XCJjb21ib2JveFwiIGFyaWEtb3ducz1cIicgK1xyXG4gICAgICAgICAgICB0aGlzLnNlbGVjdElkICtcclxuICAgICAgICAgICAgJ1wiIGFyaWEtaGFzcG9wdXA9XCJsaXN0Ym94XCIgYXJpYS1leHBhbmRlZD1cImZhbHNlXCI+JyArXHJcbiAgICAgICAgICAgICc8ZGl2IGNsYXNzPVwiZmlsdGVyLW9wdGlvblwiPicgK1xyXG4gICAgICAgICAgICAgICc8ZGl2IGNsYXNzPVwiZmlsdGVyLW9wdGlvbi1pbm5lclwiPicgK1xyXG4gICAgICAgICAgICAgICAgJzxkaXYgY2xhc3M9XCJmaWx0ZXItb3B0aW9uLWlubmVyLWlubmVyXCI+Jm5ic3A7PC9kaXY+JyArXHJcbiAgICAgICAgICAgICAgJzwvZGl2PiAnICtcclxuICAgICAgICAgICAgJzwvZGl2PicgK1xyXG4gICAgICAgICAgICBjbGVhckJ1dHRvbiArXHJcbiAgICAgICAgICAgICc8L3NwYW4+JyArXHJcbiAgICAgICAgICAgIChcclxuICAgICAgICAgICAgICB2ZXJzaW9uLm1ham9yID49ICc0JyA/ICcnXHJcbiAgICAgICAgICAgICAgOlxyXG4gICAgICAgICAgICAgICc8c3BhbiBjbGFzcz1cImJzLWNhcmV0XCI+JyArXHJcbiAgICAgICAgICAgICAgICB0aGlzLm9wdGlvbnMudGVtcGxhdGUuY2FyZXQgK1xyXG4gICAgICAgICAgICAgICc8L3NwYW4+J1xyXG4gICAgICAgICAgICApICtcclxuICAgICAgICAgICc8L2J1dHRvbj4nICtcclxuICAgICAgICAgICc8ZGl2IGNsYXNzPVwiJyArIGNsYXNzTmFtZXMuTUVOVSArICcgJyArICh2ZXJzaW9uLm1ham9yID49ICc0JyA/ICcnIDogY2xhc3NOYW1lcy5TSE9XKSArICdcIj4nICtcclxuICAgICAgICAgICAgaGVhZGVyICtcclxuICAgICAgICAgICAgc2VhcmNoYm94ICtcclxuICAgICAgICAgICAgYWN0aW9uc2JveCArXHJcbiAgICAgICAgICAgICc8ZGl2IGNsYXNzPVwiaW5uZXIgJyArIGNsYXNzTmFtZXMuU0hPVyArICdcIiByb2xlPVwibGlzdGJveFwiIGlkPVwiJyArIHRoaXMuc2VsZWN0SWQgKyAnXCIgdGFiaW5kZXg9XCItMVwiICcgKyBtdWx0aXNlbGVjdGFibGUgKyAnPicgK1xyXG4gICAgICAgICAgICAgICAgJzx1bCBjbGFzcz1cIicgKyBjbGFzc05hbWVzLk1FTlUgKyAnIGlubmVyICcgKyAodmVyc2lvbi5tYWpvciA+PSAnNCcgPyBjbGFzc05hbWVzLlNIT1cgOiAnJykgKyAnXCIgcm9sZT1cInByZXNlbnRhdGlvblwiPicgK1xyXG4gICAgICAgICAgICAgICAgJzwvdWw+JyArXHJcbiAgICAgICAgICAgICc8L2Rpdj4nICtcclxuICAgICAgICAgICAgZG9uZWJ1dHRvbiArXHJcbiAgICAgICAgICAnPC9kaXY+JyArXHJcbiAgICAgICAgJzwvZGl2Pic7XHJcblxyXG4gICAgICByZXR1cm4gJChkcm9wKTtcclxuICAgIH0sXHJcblxyXG4gICAgc2V0UG9zaXRpb25EYXRhOiBmdW5jdGlvbiAoKSB7XHJcbiAgICAgIHRoaXMuc2VsZWN0cGlja2VyLnZpZXcuY2FuSGlnaGxpZ2h0ID0gW107XHJcbiAgICAgIHRoaXMuc2VsZWN0cGlja2VyLnZpZXcuc2l6ZSA9IDA7XHJcbiAgICAgIHRoaXMuc2VsZWN0cGlja2VyLnZpZXcuZmlyc3RIaWdobGlnaHRJbmRleCA9IGZhbHNlO1xyXG5cclxuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLnNlbGVjdHBpY2tlci5jdXJyZW50LmRhdGEubGVuZ3RoOyBpKyspIHtcclxuICAgICAgICB2YXIgbGkgPSB0aGlzLnNlbGVjdHBpY2tlci5jdXJyZW50LmRhdGFbaV0sXHJcbiAgICAgICAgICAgIGNhbkhpZ2hsaWdodCA9IHRydWU7XHJcblxyXG4gICAgICAgIGlmIChsaS50eXBlID09PSAnZGl2aWRlcicpIHtcclxuICAgICAgICAgIGNhbkhpZ2hsaWdodCA9IGZhbHNlO1xyXG4gICAgICAgICAgbGkuaGVpZ2h0ID0gdGhpcy5zaXplSW5mby5kaXZpZGVySGVpZ2h0O1xyXG4gICAgICAgIH0gZWxzZSBpZiAobGkudHlwZSA9PT0gJ29wdGdyb3VwLWxhYmVsJykge1xyXG4gICAgICAgICAgY2FuSGlnaGxpZ2h0ID0gZmFsc2U7XHJcbiAgICAgICAgICBsaS5oZWlnaHQgPSB0aGlzLnNpemVJbmZvLmRyb3Bkb3duSGVhZGVySGVpZ2h0O1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICBsaS5oZWlnaHQgPSB0aGlzLnNpemVJbmZvLmxpSGVpZ2h0O1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgaWYgKGxpLmRpc2FibGVkKSBjYW5IaWdobGlnaHQgPSBmYWxzZTtcclxuXHJcbiAgICAgICAgdGhpcy5zZWxlY3RwaWNrZXIudmlldy5jYW5IaWdobGlnaHQucHVzaChjYW5IaWdobGlnaHQpO1xyXG5cclxuICAgICAgICBpZiAoY2FuSGlnaGxpZ2h0KSB7XHJcbiAgICAgICAgICB0aGlzLnNlbGVjdHBpY2tlci52aWV3LnNpemUrKztcclxuICAgICAgICAgIGxpLnBvc2luc2V0ID0gdGhpcy5zZWxlY3RwaWNrZXIudmlldy5zaXplO1xyXG4gICAgICAgICAgaWYgKHRoaXMuc2VsZWN0cGlja2VyLnZpZXcuZmlyc3RIaWdobGlnaHRJbmRleCA9PT0gZmFsc2UpIHRoaXMuc2VsZWN0cGlja2VyLnZpZXcuZmlyc3RIaWdobGlnaHRJbmRleCA9IGk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBsaS5wb3NpdGlvbiA9IChpID09PSAwID8gMCA6IHRoaXMuc2VsZWN0cGlja2VyLmN1cnJlbnQuZGF0YVtpIC0gMV0ucG9zaXRpb24pICsgbGkuaGVpZ2h0O1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG5cclxuICAgIGlzVmlydHVhbDogZnVuY3Rpb24gKCkge1xyXG4gICAgICByZXR1cm4gKHRoaXMub3B0aW9ucy52aXJ0dWFsU2Nyb2xsICE9PSBmYWxzZSkgJiYgKHRoaXMuc2VsZWN0cGlja2VyLm1haW4uZGF0YS5sZW5ndGggPj0gdGhpcy5vcHRpb25zLnZpcnR1YWxTY3JvbGwpIHx8IHRoaXMub3B0aW9ucy52aXJ0dWFsU2Nyb2xsID09PSB0cnVlO1xyXG4gICAgfSxcclxuXHJcbiAgICBjcmVhdGVWaWV3OiBmdW5jdGlvbiAoaXNTZWFyY2hpbmcsIHNldFNpemUsIHJlZnJlc2gpIHtcclxuICAgICAgdmFyIHRoYXQgPSB0aGlzLFxyXG4gICAgICAgICAgc2Nyb2xsVG9wID0gMCxcclxuICAgICAgICAgIGFjdGl2ZSA9IFtdLFxyXG4gICAgICAgICAgc2VsZWN0ZWQsXHJcbiAgICAgICAgICBwcmV2QWN0aXZlO1xyXG5cclxuICAgICAgdGhpcy5zZWxlY3RwaWNrZXIuaXNTZWFyY2hpbmcgPSBpc1NlYXJjaGluZztcclxuICAgICAgdGhpcy5zZWxlY3RwaWNrZXIuY3VycmVudCA9IGlzU2VhcmNoaW5nID8gdGhpcy5zZWxlY3RwaWNrZXIuc2VhcmNoIDogdGhpcy5zZWxlY3RwaWNrZXIubWFpbjtcclxuXHJcbiAgICAgIHRoaXMuc2V0UG9zaXRpb25EYXRhKCk7XHJcblxyXG4gICAgICBpZiAoc2V0U2l6ZSkge1xyXG4gICAgICAgIGlmIChyZWZyZXNoKSB7XHJcbiAgICAgICAgICBzY3JvbGxUb3AgPSB0aGlzLiRtZW51SW5uZXJbMF0uc2Nyb2xsVG9wO1xyXG4gICAgICAgIH0gZWxzZSBpZiAoIXRoYXQubXVsdGlwbGUpIHtcclxuICAgICAgICAgIHZhciBlbGVtZW50ID0gdGhhdC4kZWxlbWVudFswXSxcclxuICAgICAgICAgICAgICBzZWxlY3RlZEluZGV4ID0gKGVsZW1lbnQub3B0aW9uc1tlbGVtZW50LnNlbGVjdGVkSW5kZXhdIHx8IHt9KS5saUluZGV4O1xyXG5cclxuICAgICAgICAgIGlmICh0eXBlb2Ygc2VsZWN0ZWRJbmRleCA9PT0gJ251bWJlcicgJiYgdGhhdC5vcHRpb25zLnNpemUgIT09IGZhbHNlKSB7XHJcbiAgICAgICAgICAgIHZhciBzZWxlY3RlZERhdGEgPSB0aGF0LnNlbGVjdHBpY2tlci5tYWluLmRhdGFbc2VsZWN0ZWRJbmRleF0sXHJcbiAgICAgICAgICAgICAgICBwb3NpdGlvbiA9IHNlbGVjdGVkRGF0YSAmJiBzZWxlY3RlZERhdGEucG9zaXRpb247XHJcblxyXG4gICAgICAgICAgICBpZiAocG9zaXRpb24pIHtcclxuICAgICAgICAgICAgICBzY3JvbGxUb3AgPSBwb3NpdGlvbiAtICgodGhhdC5zaXplSW5mby5tZW51SW5uZXJIZWlnaHQgKyB0aGF0LnNpemVJbmZvLmxpSGVpZ2h0KSAvIDIpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICBzY3JvbGwoc2Nyb2xsVG9wLCB0cnVlKTtcclxuXHJcbiAgICAgIHRoaXMuJG1lbnVJbm5lci5vZmYoJ3Njcm9sbC5jcmVhdGVWaWV3Jykub24oJ3Njcm9sbC5jcmVhdGVWaWV3JywgZnVuY3Rpb24gKGUsIHVwZGF0ZVZhbHVlKSB7XHJcbiAgICAgICAgaWYgKCF0aGF0Lm5vU2Nyb2xsKSBzY3JvbGwodGhpcy5zY3JvbGxUb3AsIHVwZGF0ZVZhbHVlKTtcclxuICAgICAgICB0aGF0Lm5vU2Nyb2xsID0gZmFsc2U7XHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgZnVuY3Rpb24gc2Nyb2xsIChzY3JvbGxUb3AsIGluaXQpIHtcclxuICAgICAgICB2YXIgc2l6ZSA9IHRoYXQuc2VsZWN0cGlja2VyLmN1cnJlbnQuZGF0YS5sZW5ndGgsXHJcbiAgICAgICAgICAgIGNodW5rcyA9IFtdLFxyXG4gICAgICAgICAgICBjaHVua1NpemUsXHJcbiAgICAgICAgICAgIGNodW5rQ291bnQsXHJcbiAgICAgICAgICAgIGZpcnN0Q2h1bmssXHJcbiAgICAgICAgICAgIGxhc3RDaHVuayxcclxuICAgICAgICAgICAgY3VycmVudENodW5rLFxyXG4gICAgICAgICAgICBwcmV2UG9zaXRpb25zLFxyXG4gICAgICAgICAgICBwb3NpdGlvbklzRGlmZmVyZW50LFxyXG4gICAgICAgICAgICBwcmV2aW91c0VsZW1lbnRzLFxyXG4gICAgICAgICAgICBtZW51SXNEaWZmZXJlbnQgPSB0cnVlLFxyXG4gICAgICAgICAgICBpc1ZpcnR1YWwgPSB0aGF0LmlzVmlydHVhbCgpO1xyXG5cclxuICAgICAgICB0aGF0LnNlbGVjdHBpY2tlci52aWV3LnNjcm9sbFRvcCA9IHNjcm9sbFRvcDtcclxuXHJcbiAgICAgICAgY2h1bmtTaXplID0gdGhhdC5vcHRpb25zLmNodW5rU2l6ZTsgLy8gbnVtYmVyIG9mIG9wdGlvbnMgaW4gYSBjaHVua1xyXG4gICAgICAgIGNodW5rQ291bnQgPSBNYXRoLmNlaWwoc2l6ZSAvIGNodW5rU2l6ZSkgfHwgMTsgLy8gbnVtYmVyIG9mIGNodW5rc1xyXG5cclxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGNodW5rQ291bnQ7IGkrKykge1xyXG4gICAgICAgICAgdmFyIGVuZE9mQ2h1bmsgPSAoaSArIDEpICogY2h1bmtTaXplO1xyXG5cclxuICAgICAgICAgIGlmIChpID09PSBjaHVua0NvdW50IC0gMSkge1xyXG4gICAgICAgICAgICBlbmRPZkNodW5rID0gc2l6ZTtcclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICBjaHVua3NbaV0gPSBbXHJcbiAgICAgICAgICAgIChpKSAqIGNodW5rU2l6ZSArICghaSA/IDAgOiAxKSxcclxuICAgICAgICAgICAgZW5kT2ZDaHVua1xyXG4gICAgICAgICAgXTtcclxuXHJcbiAgICAgICAgICBpZiAoIXNpemUpIGJyZWFrO1xyXG5cclxuICAgICAgICAgIGlmIChjdXJyZW50Q2h1bmsgPT09IHVuZGVmaW5lZCAmJiBzY3JvbGxUb3AgLSAxIDw9IHRoYXQuc2VsZWN0cGlja2VyLmN1cnJlbnQuZGF0YVtlbmRPZkNodW5rIC0gMV0ucG9zaXRpb24gLSB0aGF0LnNpemVJbmZvLm1lbnVJbm5lckhlaWdodCkge1xyXG4gICAgICAgICAgICBjdXJyZW50Q2h1bmsgPSBpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgaWYgKGN1cnJlbnRDaHVuayA9PT0gdW5kZWZpbmVkKSBjdXJyZW50Q2h1bmsgPSAwO1xyXG5cclxuICAgICAgICBwcmV2UG9zaXRpb25zID0gW3RoYXQuc2VsZWN0cGlja2VyLnZpZXcucG9zaXRpb24wLCB0aGF0LnNlbGVjdHBpY2tlci52aWV3LnBvc2l0aW9uMV07XHJcblxyXG4gICAgICAgIC8vIGFsd2F5cyBkaXNwbGF5IHByZXZpb3VzLCBjdXJyZW50LCBhbmQgbmV4dCBjaHVua3NcclxuICAgICAgICBmaXJzdENodW5rID0gTWF0aC5tYXgoMCwgY3VycmVudENodW5rIC0gMSk7XHJcbiAgICAgICAgbGFzdENodW5rID0gTWF0aC5taW4oY2h1bmtDb3VudCAtIDEsIGN1cnJlbnRDaHVuayArIDEpO1xyXG5cclxuICAgICAgICB0aGF0LnNlbGVjdHBpY2tlci52aWV3LnBvc2l0aW9uMCA9IGlzVmlydHVhbCA9PT0gZmFsc2UgPyAwIDogKE1hdGgubWF4KDAsIGNodW5rc1tmaXJzdENodW5rXVswXSkgfHwgMCk7XHJcbiAgICAgICAgdGhhdC5zZWxlY3RwaWNrZXIudmlldy5wb3NpdGlvbjEgPSBpc1ZpcnR1YWwgPT09IGZhbHNlID8gc2l6ZSA6IChNYXRoLm1pbihzaXplLCBjaHVua3NbbGFzdENodW5rXVsxXSkgfHwgMCk7XHJcblxyXG4gICAgICAgIHBvc2l0aW9uSXNEaWZmZXJlbnQgPSBwcmV2UG9zaXRpb25zWzBdICE9PSB0aGF0LnNlbGVjdHBpY2tlci52aWV3LnBvc2l0aW9uMCB8fCBwcmV2UG9zaXRpb25zWzFdICE9PSB0aGF0LnNlbGVjdHBpY2tlci52aWV3LnBvc2l0aW9uMTtcclxuXHJcbiAgICAgICAgaWYgKHRoYXQuYWN0aXZlSW5kZXggIT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgICAgcHJldkFjdGl2ZSA9ICh0aGF0LnNlbGVjdHBpY2tlci5tYWluLmRhdGFbdGhhdC5wcmV2QWN0aXZlSW5kZXhdIHx8IHt9KS5lbGVtZW50O1xyXG4gICAgICAgICAgYWN0aXZlID0gKHRoYXQuc2VsZWN0cGlja2VyLm1haW4uZGF0YVt0aGF0LmFjdGl2ZUluZGV4XSB8fCB7fSkuZWxlbWVudDtcclxuICAgICAgICAgIHNlbGVjdGVkID0gKHRoYXQuc2VsZWN0cGlja2VyLm1haW4uZGF0YVt0aGF0LnNlbGVjdGVkSW5kZXhdIHx8IHt9KS5lbGVtZW50O1xyXG5cclxuICAgICAgICAgIGlmIChpbml0KSB7XHJcbiAgICAgICAgICAgIGlmICh0aGF0LmFjdGl2ZUluZGV4ICE9PSB0aGF0LnNlbGVjdGVkSW5kZXgpIHtcclxuICAgICAgICAgICAgICB0aGF0LmRlZm9jdXNJdGVtKGFjdGl2ZSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgdGhhdC5hY3RpdmVJbmRleCA9IHVuZGVmaW5lZDtcclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICBpZiAodGhhdC5hY3RpdmVJbmRleCAmJiB0aGF0LmFjdGl2ZUluZGV4ICE9PSB0aGF0LnNlbGVjdGVkSW5kZXgpIHtcclxuICAgICAgICAgICAgdGhhdC5kZWZvY3VzSXRlbShzZWxlY3RlZCk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBpZiAodGhhdC5wcmV2QWN0aXZlSW5kZXggIT09IHVuZGVmaW5lZCAmJiB0aGF0LnByZXZBY3RpdmVJbmRleCAhPT0gdGhhdC5hY3RpdmVJbmRleCAmJiB0aGF0LnByZXZBY3RpdmVJbmRleCAhPT0gdGhhdC5zZWxlY3RlZEluZGV4KSB7XHJcbiAgICAgICAgICB0aGF0LmRlZm9jdXNJdGVtKHByZXZBY3RpdmUpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgaWYgKGluaXQgfHwgcG9zaXRpb25Jc0RpZmZlcmVudCkge1xyXG4gICAgICAgICAgcHJldmlvdXNFbGVtZW50cyA9IHRoYXQuc2VsZWN0cGlja2VyLnZpZXcudmlzaWJsZUVsZW1lbnRzID8gdGhhdC5zZWxlY3RwaWNrZXIudmlldy52aXNpYmxlRWxlbWVudHMuc2xpY2UoKSA6IFtdO1xyXG5cclxuICAgICAgICAgIGlmIChpc1ZpcnR1YWwgPT09IGZhbHNlKSB7XHJcbiAgICAgICAgICAgIHRoYXQuc2VsZWN0cGlja2VyLnZpZXcudmlzaWJsZUVsZW1lbnRzID0gdGhhdC5zZWxlY3RwaWNrZXIuY3VycmVudC5lbGVtZW50cztcclxuICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIHRoYXQuc2VsZWN0cGlja2VyLnZpZXcudmlzaWJsZUVsZW1lbnRzID0gdGhhdC5zZWxlY3RwaWNrZXIuY3VycmVudC5lbGVtZW50cy5zbGljZSh0aGF0LnNlbGVjdHBpY2tlci52aWV3LnBvc2l0aW9uMCwgdGhhdC5zZWxlY3RwaWNrZXIudmlldy5wb3NpdGlvbjEpO1xyXG4gICAgICAgICAgfVxyXG5cclxuICAgICAgICAgIHRoYXQuc2V0T3B0aW9uU3RhdHVzKCk7XHJcblxyXG4gICAgICAgICAgLy8gaWYgc2VhcmNoaW5nLCBjaGVjayB0byBtYWtlIHN1cmUgdGhlIGxpc3QgaGFzIGFjdHVhbGx5IGJlZW4gdXBkYXRlZCBiZWZvcmUgdXBkYXRpbmcgRE9NXHJcbiAgICAgICAgICAvLyB0aGlzIHByZXZlbnRzIHVubmVjZXNzYXJ5IHJlcGFpbnRzXHJcbiAgICAgICAgICBpZiAoaXNTZWFyY2hpbmcgfHwgKGlzVmlydHVhbCA9PT0gZmFsc2UgJiYgaW5pdCkpIG1lbnVJc0RpZmZlcmVudCA9ICFpc0VxdWFsKHByZXZpb3VzRWxlbWVudHMsIHRoYXQuc2VsZWN0cGlja2VyLnZpZXcudmlzaWJsZUVsZW1lbnRzKTtcclxuXHJcbiAgICAgICAgICAvLyBpZiB2aXJ0dWFsIHNjcm9sbCBpcyBkaXNhYmxlZCBhbmQgbm90IHNlYXJjaGluZyxcclxuICAgICAgICAgIC8vIG1lbnUgc2hvdWxkIG5ldmVyIG5lZWQgdG8gYmUgdXBkYXRlZCBtb3JlIHRoYW4gb25jZVxyXG4gICAgICAgICAgaWYgKChpbml0IHx8IGlzVmlydHVhbCA9PT0gdHJ1ZSkgJiYgbWVudUlzRGlmZmVyZW50KSB7XHJcbiAgICAgICAgICAgIHZhciBtZW51SW5uZXIgPSB0aGF0LiRtZW51SW5uZXJbMF0sXHJcbiAgICAgICAgICAgICAgICBtZW51RnJhZ21lbnQgPSBkb2N1bWVudC5jcmVhdGVEb2N1bWVudEZyYWdtZW50KCksXHJcbiAgICAgICAgICAgICAgICBlbXB0eU1lbnUgPSBtZW51SW5uZXIuZmlyc3RDaGlsZC5jbG9uZU5vZGUoZmFsc2UpLFxyXG4gICAgICAgICAgICAgICAgbWFyZ2luVG9wLFxyXG4gICAgICAgICAgICAgICAgbWFyZ2luQm90dG9tLFxyXG4gICAgICAgICAgICAgICAgZWxlbWVudHMgPSB0aGF0LnNlbGVjdHBpY2tlci52aWV3LnZpc2libGVFbGVtZW50cyxcclxuICAgICAgICAgICAgICAgIHRvU2FuaXRpemUgPSBbXTtcclxuXHJcbiAgICAgICAgICAgIC8vIHJlcGxhY2UgdGhlIGV4aXN0aW5nIFVMIHdpdGggYW4gZW1wdHkgb25lIC0gdGhpcyBpcyBmYXN0ZXIgdGhhbiAkLmVtcHR5KClcclxuICAgICAgICAgICAgbWVudUlubmVyLnJlcGxhY2VDaGlsZChlbXB0eU1lbnUsIG1lbnVJbm5lci5maXJzdENoaWxkKTtcclxuXHJcbiAgICAgICAgICAgIGZvciAodmFyIGkgPSAwLCB2aXNpYmxlRWxlbWVudHNMZW4gPSBlbGVtZW50cy5sZW5ndGg7IGkgPCB2aXNpYmxlRWxlbWVudHNMZW47IGkrKykge1xyXG4gICAgICAgICAgICAgIHZhciBlbGVtZW50ID0gZWxlbWVudHNbaV0sXHJcbiAgICAgICAgICAgICAgICAgIGVsVGV4dCxcclxuICAgICAgICAgICAgICAgICAgZWxlbWVudERhdGE7XHJcblxyXG4gICAgICAgICAgICAgIGlmICh0aGF0Lm9wdGlvbnMuc2FuaXRpemUpIHtcclxuICAgICAgICAgICAgICAgIGVsVGV4dCA9IGVsZW1lbnQubGFzdENoaWxkO1xyXG5cclxuICAgICAgICAgICAgICAgIGlmIChlbFRleHQpIHtcclxuICAgICAgICAgICAgICAgICAgZWxlbWVudERhdGEgPSB0aGF0LnNlbGVjdHBpY2tlci5jdXJyZW50LmRhdGFbaSArIHRoYXQuc2VsZWN0cGlja2VyLnZpZXcucG9zaXRpb24wXTtcclxuXHJcbiAgICAgICAgICAgICAgICAgIGlmIChlbGVtZW50RGF0YSAmJiBlbGVtZW50RGF0YS5jb250ZW50ICYmICFlbGVtZW50RGF0YS5zYW5pdGl6ZWQpIHtcclxuICAgICAgICAgICAgICAgICAgICB0b1Nhbml0aXplLnB1c2goZWxUZXh0KTtcclxuICAgICAgICAgICAgICAgICAgICBlbGVtZW50RGF0YS5zYW5pdGl6ZWQgPSB0cnVlO1xyXG4gICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICBtZW51RnJhZ21lbnQuYXBwZW5kQ2hpbGQoZWxlbWVudCk7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIGlmICh0aGF0Lm9wdGlvbnMuc2FuaXRpemUgJiYgdG9TYW5pdGl6ZS5sZW5ndGgpIHtcclxuICAgICAgICAgICAgICBzYW5pdGl6ZUh0bWwodG9TYW5pdGl6ZSwgdGhhdC5vcHRpb25zLndoaXRlTGlzdCwgdGhhdC5vcHRpb25zLnNhbml0aXplRm4pO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICBpZiAoaXNWaXJ0dWFsID09PSB0cnVlKSB7XHJcbiAgICAgICAgICAgICAgbWFyZ2luVG9wID0gKHRoYXQuc2VsZWN0cGlja2VyLnZpZXcucG9zaXRpb24wID09PSAwID8gMCA6IHRoYXQuc2VsZWN0cGlja2VyLmN1cnJlbnQuZGF0YVt0aGF0LnNlbGVjdHBpY2tlci52aWV3LnBvc2l0aW9uMCAtIDFdLnBvc2l0aW9uKTtcclxuICAgICAgICAgICAgICBtYXJnaW5Cb3R0b20gPSAodGhhdC5zZWxlY3RwaWNrZXIudmlldy5wb3NpdGlvbjEgPiBzaXplIC0gMSA/IDAgOiB0aGF0LnNlbGVjdHBpY2tlci5jdXJyZW50LmRhdGFbc2l6ZSAtIDFdLnBvc2l0aW9uIC0gdGhhdC5zZWxlY3RwaWNrZXIuY3VycmVudC5kYXRhW3RoYXQuc2VsZWN0cGlja2VyLnZpZXcucG9zaXRpb24xIC0gMV0ucG9zaXRpb24pO1xyXG5cclxuICAgICAgICAgICAgICBtZW51SW5uZXIuZmlyc3RDaGlsZC5zdHlsZS5tYXJnaW5Ub3AgPSBtYXJnaW5Ub3AgKyAncHgnO1xyXG4gICAgICAgICAgICAgIG1lbnVJbm5lci5maXJzdENoaWxkLnN0eWxlLm1hcmdpbkJvdHRvbSA9IG1hcmdpbkJvdHRvbSArICdweCc7XHJcbiAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgbWVudUlubmVyLmZpcnN0Q2hpbGQuc3R5bGUubWFyZ2luVG9wID0gMDtcclxuICAgICAgICAgICAgICBtZW51SW5uZXIuZmlyc3RDaGlsZC5zdHlsZS5tYXJnaW5Cb3R0b20gPSAwO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICBtZW51SW5uZXIuZmlyc3RDaGlsZC5hcHBlbmRDaGlsZChtZW51RnJhZ21lbnQpO1xyXG5cclxuICAgICAgICAgICAgLy8gaWYgYW4gb3B0aW9uIGlzIGVuY291bnRlcmVkIHRoYXQgaXMgd2lkZXIgdGhhbiB0aGUgY3VycmVudCBtZW51IHdpZHRoLCB1cGRhdGUgdGhlIG1lbnUgd2lkdGggYWNjb3JkaW5nbHlcclxuICAgICAgICAgICAgLy8gc3dpdGNoIHRvIFJlc2l6ZU9ic2VydmVyIHdpdGggaW5jcmVhc2VkIGJyb3dzZXIgc3VwcG9ydFxyXG4gICAgICAgICAgICBpZiAoaXNWaXJ0dWFsID09PSB0cnVlICYmIHRoYXQuc2l6ZUluZm8uaGFzU2Nyb2xsQmFyKSB7XHJcbiAgICAgICAgICAgICAgdmFyIG1lbnVJbm5lcklubmVyV2lkdGggPSBtZW51SW5uZXIuZmlyc3RDaGlsZC5vZmZzZXRXaWR0aDtcclxuXHJcbiAgICAgICAgICAgICAgaWYgKGluaXQgJiYgbWVudUlubmVySW5uZXJXaWR0aCA8IHRoYXQuc2l6ZUluZm8ubWVudUlubmVySW5uZXJXaWR0aCAmJiB0aGF0LnNpemVJbmZvLnRvdGFsTWVudVdpZHRoID4gdGhhdC5zaXplSW5mby5zZWxlY3RXaWR0aCkge1xyXG4gICAgICAgICAgICAgICAgbWVudUlubmVyLmZpcnN0Q2hpbGQuc3R5bGUubWluV2lkdGggPSB0aGF0LnNpemVJbmZvLm1lbnVJbm5lcklubmVyV2lkdGggKyAncHgnO1xyXG4gICAgICAgICAgICAgIH0gZWxzZSBpZiAobWVudUlubmVySW5uZXJXaWR0aCA+IHRoYXQuc2l6ZUluZm8ubWVudUlubmVySW5uZXJXaWR0aCkge1xyXG4gICAgICAgICAgICAgICAgLy8gc2V0IHRvIDAgdG8gZ2V0IGFjdHVhbCB3aWR0aCBvZiBtZW51XHJcbiAgICAgICAgICAgICAgICB0aGF0LiRtZW51WzBdLnN0eWxlLm1pbldpZHRoID0gMDtcclxuXHJcbiAgICAgICAgICAgICAgICB2YXIgYWN0dWFsTWVudVdpZHRoID0gbWVudUlubmVyLmZpcnN0Q2hpbGQub2Zmc2V0V2lkdGg7XHJcblxyXG4gICAgICAgICAgICAgICAgaWYgKGFjdHVhbE1lbnVXaWR0aCA+IHRoYXQuc2l6ZUluZm8ubWVudUlubmVySW5uZXJXaWR0aCkge1xyXG4gICAgICAgICAgICAgICAgICB0aGF0LnNpemVJbmZvLm1lbnVJbm5lcklubmVyV2lkdGggPSBhY3R1YWxNZW51V2lkdGg7XHJcbiAgICAgICAgICAgICAgICAgIG1lbnVJbm5lci5maXJzdENoaWxkLnN0eWxlLm1pbldpZHRoID0gdGhhdC5zaXplSW5mby5tZW51SW5uZXJJbm5lcldpZHRoICsgJ3B4JztcclxuICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICAvLyByZXNldCB0byBkZWZhdWx0IENTUyBzdHlsaW5nXHJcbiAgICAgICAgICAgICAgICB0aGF0LiRtZW51WzBdLnN0eWxlLm1pbldpZHRoID0gJyc7XHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgaWYgKCghaXNTZWFyY2hpbmcgJiYgdGhhdC5vcHRpb25zLnNvdXJjZS5sb2FkIHx8IGlzU2VhcmNoaW5nICYmIHRoYXQub3B0aW9ucy5zb3VyY2Uuc2VhcmNoKSAmJiBjdXJyZW50Q2h1bmsgPT09IGNodW5rQ291bnQgLSAxKSB7XHJcbiAgICAgICAgICAgIHRoYXQuZmV0Y2hEYXRhKGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgICB0aGF0LnJlbmRlcigpO1xyXG4gICAgICAgICAgICAgIHRoYXQuYnVpbGRMaXN0KHNpemUsIGlzU2VhcmNoaW5nKTtcclxuICAgICAgICAgICAgICB0aGF0LnNldFBvc2l0aW9uRGF0YSgpO1xyXG4gICAgICAgICAgICAgIHNjcm9sbChzY3JvbGxUb3ApO1xyXG4gICAgICAgICAgICB9LCBpc1NlYXJjaGluZyA/ICdzZWFyY2gnIDogJ2xvYWQnLCBjdXJyZW50Q2h1bmsgKyAxLCBpc1NlYXJjaGluZyA/IHRoYXQuc2VsZWN0cGlja2VyLnNlYXJjaC5wcmV2aW91c1ZhbHVlIDogdW5kZWZpbmVkKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHRoYXQucHJldkFjdGl2ZUluZGV4ID0gdGhhdC5hY3RpdmVJbmRleDtcclxuXHJcbiAgICAgICAgaWYgKCF0aGF0Lm9wdGlvbnMubGl2ZVNlYXJjaCkge1xyXG4gICAgICAgICAgdGhhdC4kbWVudUlubmVyLnRyaWdnZXIoJ2ZvY3VzJyk7XHJcbiAgICAgICAgfSBlbHNlIGlmIChpc1NlYXJjaGluZyAmJiBpbml0KSB7XHJcbiAgICAgICAgICB2YXIgaW5kZXggPSAwLFxyXG4gICAgICAgICAgICAgIG5ld0FjdGl2ZTtcclxuXHJcbiAgICAgICAgICBpZiAoIXRoYXQuc2VsZWN0cGlja2VyLnZpZXcuY2FuSGlnaGxpZ2h0W2luZGV4XSkge1xyXG4gICAgICAgICAgICBpbmRleCA9IDEgKyB0aGF0LnNlbGVjdHBpY2tlci52aWV3LmNhbkhpZ2hsaWdodC5zbGljZSgxKS5pbmRleE9mKHRydWUpO1xyXG4gICAgICAgICAgfVxyXG5cclxuICAgICAgICAgIG5ld0FjdGl2ZSA9IHRoYXQuc2VsZWN0cGlja2VyLnZpZXcudmlzaWJsZUVsZW1lbnRzW2luZGV4XTtcclxuXHJcbiAgICAgICAgICB0aGF0LmRlZm9jdXNJdGVtKHRoYXQuc2VsZWN0cGlja2VyLnZpZXcuY3VycmVudEFjdGl2ZSk7XHJcblxyXG4gICAgICAgICAgdGhhdC5hY3RpdmVJbmRleCA9ICh0aGF0LnNlbGVjdHBpY2tlci5jdXJyZW50LmRhdGFbaW5kZXhdIHx8IHt9KS5pbmRleDtcclxuXHJcbiAgICAgICAgICB0aGF0LmZvY3VzSXRlbShuZXdBY3RpdmUpO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgJCh3aW5kb3cpXHJcbiAgICAgICAgLm9mZigncmVzaXplJyArIEVWRU5UX0tFWSArICcuJyArIHRoaXMuc2VsZWN0SWQgKyAnLmNyZWF0ZVZpZXcnKVxyXG4gICAgICAgIC5vbigncmVzaXplJyArIEVWRU5UX0tFWSArICcuJyArIHRoaXMuc2VsZWN0SWQgKyAnLmNyZWF0ZVZpZXcnLCBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICB2YXIgaXNBY3RpdmUgPSB0aGF0LiRuZXdFbGVtZW50Lmhhc0NsYXNzKGNsYXNzTmFtZXMuU0hPVyk7XHJcblxyXG4gICAgICAgICAgaWYgKGlzQWN0aXZlKSBzY3JvbGwodGhhdC4kbWVudUlubmVyWzBdLnNjcm9sbFRvcCk7XHJcbiAgICAgICAgfSk7XHJcbiAgICB9LFxyXG5cclxuICAgIGZvY3VzSXRlbTogZnVuY3Rpb24gKGxpLCBsaURhdGEsIG5vU3R5bGUpIHtcclxuICAgICAgaWYgKGxpKSB7XHJcbiAgICAgICAgbGlEYXRhID0gbGlEYXRhIHx8IHRoaXMuc2VsZWN0cGlja2VyLm1haW4uZGF0YVt0aGlzLmFjdGl2ZUluZGV4XTtcclxuICAgICAgICB2YXIgYSA9IGxpLmZpcnN0Q2hpbGQ7XHJcblxyXG4gICAgICAgIGlmIChhKSB7XHJcbiAgICAgICAgICBhLnNldEF0dHJpYnV0ZSgnYXJpYS1zZXRzaXplJywgdGhpcy5zZWxlY3RwaWNrZXIudmlldy5zaXplKTtcclxuICAgICAgICAgIGEuc2V0QXR0cmlidXRlKCdhcmlhLXBvc2luc2V0JywgbGlEYXRhLnBvc2luc2V0KTtcclxuXHJcbiAgICAgICAgICBpZiAobm9TdHlsZSAhPT0gdHJ1ZSkge1xyXG4gICAgICAgICAgICB0aGlzLmZvY3VzZWRQYXJlbnQuc2V0QXR0cmlidXRlKCdhcmlhLWFjdGl2ZWRlc2NlbmRhbnQnLCBhLmlkKTtcclxuICAgICAgICAgICAgbGkuY2xhc3NMaXN0LmFkZCgnYWN0aXZlJyk7XHJcbiAgICAgICAgICAgIGEuY2xhc3NMaXN0LmFkZCgnYWN0aXZlJyk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9LFxyXG5cclxuICAgIGRlZm9jdXNJdGVtOiBmdW5jdGlvbiAobGkpIHtcclxuICAgICAgaWYgKGxpKSB7XHJcbiAgICAgICAgbGkuY2xhc3NMaXN0LnJlbW92ZSgnYWN0aXZlJyk7XHJcbiAgICAgICAgaWYgKGxpLmZpcnN0Q2hpbGQpIGxpLmZpcnN0Q2hpbGQuY2xhc3NMaXN0LnJlbW92ZSgnYWN0aXZlJyk7XHJcbiAgICAgIH1cclxuICAgIH0sXHJcblxyXG4gICAgc2V0UGxhY2Vob2xkZXI6IGZ1bmN0aW9uICgpIHtcclxuICAgICAgdmFyIHRoYXQgPSB0aGlzLFxyXG4gICAgICAgICAgdXBkYXRlSW5kZXggPSBmYWxzZTtcclxuXHJcbiAgICAgIGlmICgodGhpcy5vcHRpb25zLnBsYWNlaG9sZGVyIHx8IHRoaXMub3B0aW9ucy5hbGxvd0NsZWFyKSAmJiAhdGhpcy5tdWx0aXBsZSkge1xyXG4gICAgICAgIGlmICghdGhpcy5zZWxlY3RwaWNrZXIudmlldy50aXRsZU9wdGlvbikgdGhpcy5zZWxlY3RwaWNrZXIudmlldy50aXRsZU9wdGlvbiA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ29wdGlvbicpO1xyXG5cclxuICAgICAgICAvLyB0aGlzIG9wdGlvbiBkb2Vzbid0IGNyZWF0ZSBhIG5ldyA8bGk+IGVsZW1lbnQsIGJ1dCBkb2VzIGFkZCBhIG5ldyBvcHRpb24gYXQgdGhlIHN0YXJ0LFxyXG4gICAgICAgIC8vIHNvIHN0YXJ0SW5kZXggc2hvdWxkIGluY3JlYXNlIHRvIHByZXZlbnQgaGF2aW5nIHRvIGNoZWNrIGV2ZXJ5IG9wdGlvbiBmb3IgdGhlIGJzLXRpdGxlLW9wdGlvbiBjbGFzc1xyXG4gICAgICAgIHVwZGF0ZUluZGV4ID0gdHJ1ZTtcclxuXHJcbiAgICAgICAgdmFyIGVsZW1lbnQgPSB0aGlzLiRlbGVtZW50WzBdLFxyXG4gICAgICAgICAgICBzZWxlY3RUaXRsZU9wdGlvbiA9IGZhbHNlLFxyXG4gICAgICAgICAgICB0aXRsZU5vdEFwcGVuZGVkID0gIXRoaXMuc2VsZWN0cGlja2VyLnZpZXcudGl0bGVPcHRpb24ucGFyZW50Tm9kZSxcclxuICAgICAgICAgICAgc2VsZWN0ZWRJbmRleCA9IGVsZW1lbnQuc2VsZWN0ZWRJbmRleCxcclxuICAgICAgICAgICAgc2VsZWN0ZWRPcHRpb24gPSBlbGVtZW50Lm9wdGlvbnNbc2VsZWN0ZWRJbmRleF0sXHJcbiAgICAgICAgICAgIGZpcnN0U2VsZWN0YWJsZSA9IGVsZW1lbnQucXVlcnlTZWxlY3Rvcignc2VsZWN0ID4gKjpub3QoOmRpc2FibGVkKScpLFxyXG4gICAgICAgICAgICBmaXJzdFNlbGVjdGFibGVJbmRleCA9IGZpcnN0U2VsZWN0YWJsZSA/IGZpcnN0U2VsZWN0YWJsZS5pbmRleCA6IDAsXHJcbiAgICAgICAgICAgIG5hdmlnYXRpb24gPSB3aW5kb3cucGVyZm9ybWFuY2UgJiYgd2luZG93LnBlcmZvcm1hbmNlLmdldEVudHJpZXNCeVR5cGUoJ25hdmlnYXRpb24nKSxcclxuICAgICAgICAgICAgLy8gU2FmYXJpIGRvZXNuJ3Qgc3VwcG9ydCBnZXRFbnRyaWVzQnlUeXBlKCduYXZpZ2F0aW9uJykgLSBmYWxsIGJhY2sgdG8gcGVyZm9ybWFuY2UubmF2aWdhdGlvblxyXG4gICAgICAgICAgICBpc05vdEJhY2tGb3J3YXJkID0gKG5hdmlnYXRpb24gJiYgbmF2aWdhdGlvbi5sZW5ndGgpID8gbmF2aWdhdGlvblswXS50eXBlICE9PSAnYmFja19mb3J3YXJkJyA6IHdpbmRvdy5wZXJmb3JtYW5jZS5uYXZpZ2F0aW9uLnR5cGUgIT09IDI7XHJcblxyXG4gICAgICAgIGlmICh0aXRsZU5vdEFwcGVuZGVkKSB7XHJcbiAgICAgICAgICAvLyBVc2UgbmF0aXZlIEpTIHRvIHByZXBlbmQgb3B0aW9uIChmYXN0ZXIpXHJcbiAgICAgICAgICB0aGlzLnNlbGVjdHBpY2tlci52aWV3LnRpdGxlT3B0aW9uLmNsYXNzTmFtZSA9ICdicy10aXRsZS1vcHRpb24nO1xyXG4gICAgICAgICAgdGhpcy5zZWxlY3RwaWNrZXIudmlldy50aXRsZU9wdGlvbi52YWx1ZSA9ICcnO1xyXG5cclxuICAgICAgICAgIC8vIENoZWNrIGlmIHNlbGVjdGVkIG9yIGRhdGEtc2VsZWN0ZWQgYXR0cmlidXRlIGlzIGFscmVhZHkgc2V0IG9uIGFuIG9wdGlvbi4gSWYgbm90LCBzZWxlY3QgdGhlIHRpdGxlT3B0aW9uIG9wdGlvbi5cclxuICAgICAgICAgIC8vIHRoZSBzZWxlY3RlZCBpdGVtIG1heSBoYXZlIGJlZW4gY2hhbmdlZCBieSB1c2VyIG9yIHByb2dyYW1tYXRpY2FsbHkgYmVmb3JlIHRoZSBib290c3RyYXAgc2VsZWN0IHBsdWdpbiBydW5zLFxyXG4gICAgICAgICAgLy8gaWYgc28sIHRoZSBzZWxlY3Qgd2lsbCBoYXZlIHRoZSBkYXRhLXNlbGVjdGVkIGF0dHJpYnV0ZVxyXG4gICAgICAgICAgc2VsZWN0VGl0bGVPcHRpb24gPSAhc2VsZWN0ZWRPcHRpb24gfHwgKHNlbGVjdGVkSW5kZXggPT09IGZpcnN0U2VsZWN0YWJsZUluZGV4ICYmIHNlbGVjdGVkT3B0aW9uLmRlZmF1bHRTZWxlY3RlZCA9PT0gZmFsc2UgJiYgdGhpcy4kZWxlbWVudC5kYXRhKCdzZWxlY3RlZCcpID09PSB1bmRlZmluZWQpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgaWYgKHRpdGxlTm90QXBwZW5kZWQgfHwgdGhpcy5zZWxlY3RwaWNrZXIudmlldy50aXRsZU9wdGlvbi5pbmRleCAhPT0gMCkge1xyXG4gICAgICAgICAgZWxlbWVudC5pbnNlcnRCZWZvcmUodGhpcy5zZWxlY3RwaWNrZXIudmlldy50aXRsZU9wdGlvbiwgZWxlbWVudC5maXJzdENoaWxkKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIFNldCBzZWxlY3RlZCAqYWZ0ZXIqIGFwcGVuZGluZyB0byBzZWxlY3QsXHJcbiAgICAgICAgLy8gb3RoZXJ3aXNlIHRoZSBvcHRpb24gZG9lc24ndCBnZXQgc2VsZWN0ZWQgaW4gSUVcclxuICAgICAgICAvLyBzZXQgdXNpbmcgc2VsZWN0ZWRJbmRleCwgYXMgc2V0dGluZyB0aGUgc2VsZWN0ZWQgYXR0ciB0byB0cnVlIGhlcmUgZG9lc24ndCB3b3JrIGluIElFMTFcclxuICAgICAgICBpZiAoc2VsZWN0VGl0bGVPcHRpb24gJiYgaXNOb3RCYWNrRm9yd2FyZCkge1xyXG4gICAgICAgICAgZWxlbWVudC5zZWxlY3RlZEluZGV4ID0gMDtcclxuICAgICAgICB9IGVsc2UgaWYgKGRvY3VtZW50LnJlYWR5U3RhdGUgIT09ICdjb21wbGV0ZScpIHtcclxuICAgICAgICAgIC8vIGlmIG5hdmlnYXRpb24gdHlwZSBpcyBiYWNrX2ZvcndhcmQsIHRoZXJlJ3MgYSBjaGFuY2UgdGhlIHNlbGVjdCB3aWxsIGhhdmUgaXRzIHZhbHVlIHNldCBieSBCRkNhY2hlXHJcbiAgICAgICAgICAvLyB3YWl0IGZvciB0aGF0IHZhbHVlIHRvIGJlIHNldCwgdGhlbiBydW4gcmVuZGVyIGFnYWluXHJcbiAgICAgICAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcigncGFnZXNob3cnLCBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgIGlmICh0aGF0LnNlbGVjdHBpY2tlci52aWV3LmRpc3BsYXllZFZhbHVlICE9PSBlbGVtZW50LnZhbHVlKSB0aGF0LnJlbmRlcigpO1xyXG4gICAgICAgICAgfSk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICByZXR1cm4gdXBkYXRlSW5kZXg7XHJcbiAgICB9LFxyXG5cclxuICAgIGZldGNoRGF0YTogZnVuY3Rpb24gKGNhbGxiYWNrLCB0eXBlLCBwYWdlLCBzZWFyY2hWYWx1ZSkge1xyXG4gICAgICB0eXBlID0gdHlwZSB8fCAnZGF0YSc7XHJcblxyXG4gICAgICB2YXIgdGhhdCA9IHRoaXMsXHJcbiAgICAgICAgICBkYXRhID0gdGhpcy5vcHRpb25zLnNvdXJjZVt0eXBlXSxcclxuICAgICAgICAgIGJ1aWx0RGF0YTtcclxuXHJcbiAgICAgIGlmIChkYXRhKSB7XHJcbiAgICAgICAgdGhpcy5vcHRpb25zLnZpcnR1YWxTY3JvbGwgPSB0cnVlO1xyXG5cclxuICAgICAgICBpZiAodHlwZW9mIGRhdGEgPT09ICdmdW5jdGlvbicpIHtcclxuICAgICAgICAgIGRhdGEuY2FsbChcclxuICAgICAgICAgICAgdGhpcyxcclxuICAgICAgICAgICAgZnVuY3Rpb24gKGRhdGEpIHtcclxuICAgICAgICAgICAgICBidWlsdERhdGEgPSB0aGF0LmJ1aWxkRGF0YShkYXRhLCB0eXBlKTtcclxuICAgICAgICAgICAgICBjYWxsYmFjay5jYWxsKHRoYXQsIGJ1aWx0RGF0YSk7XHJcbiAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgIHBhZ2UsXHJcbiAgICAgICAgICAgIHNlYXJjaFZhbHVlXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH0gZWxzZSBpZiAoQXJyYXkuaXNBcnJheShkYXRhKSkge1xyXG4gICAgICAgICAgYnVpbHREYXRhID0gdGhhdC5idWlsZERhdGEoZGF0YSwgdHlwZSk7XHJcbiAgICAgICAgICBjYWxsYmFjay5jYWxsKHRoYXQsIGJ1aWx0RGF0YSk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIGJ1aWx0RGF0YSA9IHRoaXMuYnVpbGREYXRhKGZhbHNlLCB0eXBlKTtcclxuICAgICAgICBjYWxsYmFjay5jYWxsKHRoYXQsIGJ1aWx0RGF0YSk7XHJcbiAgICAgIH1cclxuICAgIH0sXHJcblxyXG4gICAgYnVpbGREYXRhOiBmdW5jdGlvbiAoZGF0YSwgdHlwZSkge1xyXG4gICAgICB2YXIgZGF0YUdldHRlciA9IGRhdGEgPT09IGZhbHNlID8gZ2V0T3B0aW9uRGF0YS5mcm9tT3B0aW9uIDogZ2V0T3B0aW9uRGF0YS5mcm9tRGF0YVNvdXJjZTtcclxuXHJcbiAgICAgIHZhciBvcHRpb25TZWxlY3RvciA9ICc6bm90KFtoaWRkZW5dKTpub3QoW2RhdGEtaGlkZGVuPVwidHJ1ZVwiXSknLFxyXG4gICAgICAgICAgbWFpbkRhdGEgPSBbXSxcclxuICAgICAgICAgIHN0YXJ0TGVuID0gMCxcclxuICAgICAgICAgIG9wdElEID0gMCxcclxuICAgICAgICAgIHN0YXJ0SW5kZXggPSB0aGlzLnNldFBsYWNlaG9sZGVyKCkgJiYgIWRhdGEgPyAxIDogMDsgLy8gYXBwZW5kIHRoZSB0aXRsZU9wdGlvbiBpZiBuZWNlc3NhcnkgYW5kIHNraXAgdGhlIGZpcnN0IG9wdGlvbiBpbiB0aGUgbG9vcFxyXG5cclxuICAgICAgaWYgKHR5cGUgPT09ICdsb2FkJykge1xyXG4gICAgICAgIHN0YXJ0TGVuID0gdGhpcy5zZWxlY3RwaWNrZXIubWFpbi5kYXRhLmxlbmd0aDtcclxuICAgICAgfSBlbHNlIGlmICh0eXBlID09PSAnc2VhcmNoJykge1xyXG4gICAgICAgIHN0YXJ0TGVuID0gdGhpcy5zZWxlY3RwaWNrZXIuc2VhcmNoLmRhdGEubGVuZ3RoO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAodGhpcy5vcHRpb25zLmhpZGVEaXNhYmxlZCkgb3B0aW9uU2VsZWN0b3IgKz0gJzpub3QoOmRpc2FibGVkKSc7XHJcblxyXG4gICAgICB2YXIgc2VsZWN0T3B0aW9ucyA9IGRhdGEgPyBkYXRhLmZpbHRlcihmaWx0ZXJIaWRkZW4sIHRoaXMpIDogdGhpcy4kZWxlbWVudFswXS5xdWVyeVNlbGVjdG9yQWxsKCdzZWxlY3QgPiAqJyArIG9wdGlvblNlbGVjdG9yKTtcclxuXHJcbiAgICAgIGZ1bmN0aW9uIGFkZERpdmlkZXIgKGNvbmZpZykge1xyXG4gICAgICAgIHZhciBwcmV2aW91c0RhdGEgPSBtYWluRGF0YVttYWluRGF0YS5sZW5ndGggLSAxXTtcclxuXHJcbiAgICAgICAgLy8gZW5zdXJlIG9wdGdyb3VwIGRvZXNuJ3QgY3JlYXRlIGJhY2stdG8tYmFjayBkaXZpZGVyc1xyXG4gICAgICAgIGlmIChcclxuICAgICAgICAgIHByZXZpb3VzRGF0YSAmJlxyXG4gICAgICAgICAgcHJldmlvdXNEYXRhLnR5cGUgPT09ICdkaXZpZGVyJyAmJlxyXG4gICAgICAgICAgKHByZXZpb3VzRGF0YS5vcHRJRCB8fCBjb25maWcub3B0SUQpXHJcbiAgICAgICAgKSB7XHJcbiAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBjb25maWcgPSBjb25maWcgfHwge307XHJcbiAgICAgICAgY29uZmlnLnR5cGUgPSAnZGl2aWRlcic7XHJcblxyXG4gICAgICAgIG1haW5EYXRhLnB1c2goY29uZmlnKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgZnVuY3Rpb24gYWRkT3B0aW9uIChpdGVtLCBjb25maWcpIHtcclxuICAgICAgICBjb25maWcgPSBjb25maWcgfHwge307XHJcblxyXG4gICAgICAgIGNvbmZpZy5kaXZpZGVyID0gZGF0YUdldHRlcihpdGVtLCAnZGl2aWRlcicpO1xyXG5cclxuICAgICAgICBpZiAoY29uZmlnLmRpdmlkZXIgPT09IHRydWUpIHtcclxuICAgICAgICAgIGFkZERpdmlkZXIoe1xyXG4gICAgICAgICAgICBvcHRJRDogY29uZmlnLm9wdElEXHJcbiAgICAgICAgICB9KTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgdmFyIGxpSW5kZXggPSBtYWluRGF0YS5sZW5ndGggKyBzdGFydExlbixcclxuICAgICAgICAgICAgICBjc3NUZXh0ID0gZGF0YUdldHRlcihpdGVtLCAnc3R5bGUnKSxcclxuICAgICAgICAgICAgICBpbmxpbmVTdHlsZSA9IGNzc1RleHQgPyBodG1sRXNjYXBlKGNzc1RleHQpIDogJycsXHJcbiAgICAgICAgICAgICAgb3B0aW9uQ2xhc3MgPSAoaXRlbS5jbGFzc05hbWUgfHwgJycpICsgKGNvbmZpZy5vcHRncm91cENsYXNzIHx8ICcnKTtcclxuXHJcbiAgICAgICAgICBpZiAoY29uZmlnLm9wdElEKSBvcHRpb25DbGFzcyA9ICdvcHQgJyArIG9wdGlvbkNsYXNzO1xyXG5cclxuICAgICAgICAgIGNvbmZpZy5vcHRpb25DbGFzcyA9IG9wdGlvbkNsYXNzLnRyaW0oKTtcclxuICAgICAgICAgIGNvbmZpZy5pbmxpbmVTdHlsZSA9IGlubGluZVN0eWxlO1xyXG5cclxuICAgICAgICAgIGNvbmZpZy50ZXh0ID0gZGF0YUdldHRlcihpdGVtLCAndGV4dCcpO1xyXG4gICAgICAgICAgY29uZmlnLmNvbnRlbnQgPSBkYXRhR2V0dGVyKGl0ZW0sICdjb250ZW50Jyk7XHJcbiAgICAgICAgICBjb25maWcudG9rZW5zID0gZGF0YUdldHRlcihpdGVtLCAndG9rZW5zJyk7XHJcbiAgICAgICAgICBjb25maWcuc3VidGV4dCA9IGRhdGFHZXR0ZXIoaXRlbSwgJ3N1YnRleHQnKTtcclxuICAgICAgICAgIGNvbmZpZy5pY29uID0gZGF0YUdldHRlcihpdGVtLCAnaWNvbicpO1xyXG5cclxuICAgICAgICAgIGNvbmZpZy5kaXNwbGF5ID0gY29uZmlnLmNvbnRlbnQgfHwgY29uZmlnLnRleHQ7XHJcbiAgICAgICAgICBjb25maWcudmFsdWUgPSBpdGVtLnZhbHVlID09PSB1bmRlZmluZWQgPyBpdGVtLnRleHQgOiBpdGVtLnZhbHVlO1xyXG4gICAgICAgICAgY29uZmlnLnR5cGUgPSAnb3B0aW9uJztcclxuICAgICAgICAgIGNvbmZpZy5pbmRleCA9IGxpSW5kZXg7XHJcblxyXG4gICAgICAgICAgY29uZmlnLm9wdGlvbiA9ICFpdGVtLm9wdGlvbiA/IGl0ZW0gOiBpdGVtLm9wdGlvbjsgLy8gcmVmZXJlbmNlIG9wdGlvbiBlbGVtZW50IGlmIGl0IGV4aXN0c1xyXG4gICAgICAgICAgY29uZmlnLm9wdGlvbi5saUluZGV4ID0gbGlJbmRleDtcclxuICAgICAgICAgIGNvbmZpZy5zZWxlY3RlZCA9ICEhaXRlbS5zZWxlY3RlZDtcclxuICAgICAgICAgIGNvbmZpZy5kaXNhYmxlZCA9IGNvbmZpZy5kaXNhYmxlZCB8fCAhIWl0ZW0uZGlzYWJsZWQ7XHJcblxyXG4gICAgICAgICAgbWFpbkRhdGEucHVzaChjb25maWcpO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgZnVuY3Rpb24gYWRkT3B0Z3JvdXAgKGluZGV4LCBzZWxlY3RPcHRpb25zKSB7XHJcbiAgICAgICAgdmFyIG9wdGdyb3VwID0gc2VsZWN0T3B0aW9uc1tpbmRleF0sXHJcbiAgICAgICAgICAgIC8vIHNraXAgcGxhY2Vob2xkZXIgb3B0aW9uXHJcbiAgICAgICAgICAgIHByZXZpb3VzID0gaW5kZXggLSAxIDwgc3RhcnRJbmRleCA/IGZhbHNlIDogc2VsZWN0T3B0aW9uc1tpbmRleCAtIDFdLFxyXG4gICAgICAgICAgICBuZXh0ID0gc2VsZWN0T3B0aW9uc1tpbmRleCArIDFdLFxyXG4gICAgICAgICAgICBvcHRpb25zID0gZGF0YSA/IG9wdGdyb3VwLmNoaWxkcmVuLmZpbHRlcihmaWx0ZXJIaWRkZW4sIHRoaXMpIDogb3B0Z3JvdXAucXVlcnlTZWxlY3RvckFsbCgnb3B0aW9uJyArIG9wdGlvblNlbGVjdG9yKTtcclxuXHJcbiAgICAgICAgaWYgKCFvcHRpb25zLmxlbmd0aCkgcmV0dXJuO1xyXG5cclxuICAgICAgICB2YXIgY29uZmlnID0ge1xyXG4gICAgICAgICAgICAgIGRpc3BsYXk6IGh0bWxFc2NhcGUoZGF0YUdldHRlcihpdGVtLCAnbGFiZWwnKSksXHJcbiAgICAgICAgICAgICAgc3VidGV4dDogZGF0YUdldHRlcihvcHRncm91cCwgJ3N1YnRleHQnKSxcclxuICAgICAgICAgICAgICBpY29uOiBkYXRhR2V0dGVyKG9wdGdyb3VwLCAnaWNvbicpLFxyXG4gICAgICAgICAgICAgIHR5cGU6ICdvcHRncm91cC1sYWJlbCcsXHJcbiAgICAgICAgICAgICAgb3B0Z3JvdXBDbGFzczogJyAnICsgKG9wdGdyb3VwLmNsYXNzTmFtZSB8fCAnJylcclxuICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgaGVhZGVySW5kZXgsXHJcbiAgICAgICAgICAgIGxhc3RJbmRleDtcclxuXHJcbiAgICAgICAgb3B0SUQrKztcclxuXHJcbiAgICAgICAgaWYgKHByZXZpb3VzKSB7XHJcbiAgICAgICAgICBhZGREaXZpZGVyKHsgb3B0SUQ6IG9wdElEIH0pO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgY29uZmlnLm9wdElEID0gb3B0SUQ7XHJcblxyXG4gICAgICAgIG1haW5EYXRhLnB1c2goY29uZmlnKTtcclxuXHJcbiAgICAgICAgZm9yICh2YXIgaiA9IDAsIGxlbiA9IG9wdGlvbnMubGVuZ3RoOyBqIDwgbGVuOyBqKyspIHtcclxuICAgICAgICAgIHZhciBvcHRpb24gPSBvcHRpb25zW2pdO1xyXG5cclxuICAgICAgICAgIGlmIChqID09PSAwKSB7XHJcbiAgICAgICAgICAgIGhlYWRlckluZGV4ID0gbWFpbkRhdGEubGVuZ3RoIC0gMTtcclxuICAgICAgICAgICAgbGFzdEluZGV4ID0gaGVhZGVySW5kZXggKyBsZW47XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgYWRkT3B0aW9uKG9wdGlvbiwge1xyXG4gICAgICAgICAgICBoZWFkZXJJbmRleDogaGVhZGVySW5kZXgsXHJcbiAgICAgICAgICAgIGxhc3RJbmRleDogbGFzdEluZGV4LFxyXG4gICAgICAgICAgICBvcHRJRDogY29uZmlnLm9wdElELFxyXG4gICAgICAgICAgICBvcHRncm91cENsYXNzOiBjb25maWcub3B0Z3JvdXBDbGFzcyxcclxuICAgICAgICAgICAgZGlzYWJsZWQ6IG9wdGdyb3VwLmRpc2FibGVkXHJcbiAgICAgICAgICB9KTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGlmIChuZXh0KSB7XHJcbiAgICAgICAgICBhZGREaXZpZGVyKHsgb3B0SUQ6IG9wdElEIH0pO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgZm9yICh2YXIgbGVuID0gc2VsZWN0T3B0aW9ucy5sZW5ndGgsIGkgPSBzdGFydEluZGV4OyBpIDwgbGVuOyBpKyspIHtcclxuICAgICAgICB2YXIgaXRlbSA9IHNlbGVjdE9wdGlvbnNbaV0sXHJcbiAgICAgICAgICAgIGNoaWxkcmVuID0gaXRlbS5jaGlsZHJlbjtcclxuXHJcbiAgICAgICAgaWYgKGNoaWxkcmVuICYmIGNoaWxkcmVuLmxlbmd0aCkge1xyXG4gICAgICAgICAgYWRkT3B0Z3JvdXAuY2FsbCh0aGlzLCBzdGFydEluZGV4LCBzZWxlY3RPcHRpb25zKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgYWRkT3B0aW9uLmNhbGwodGhpcywgaXRlbSwge30pO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgc3dpdGNoICh0eXBlKSB7XHJcbiAgICAgICAgY2FzZSAnZGF0YSc6IHtcclxuICAgICAgICAgIHRoaXMuc2VsZWN0cGlja2VyLm1haW4uZGF0YSA9IHRoaXMuc2VsZWN0cGlja2VyLmN1cnJlbnQuZGF0YSA9IG1haW5EYXRhO1xyXG4gICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGNhc2UgJ2xvYWQnOiB7XHJcbiAgICAgICAgICBBcnJheS5wcm90b3R5cGUucHVzaC5hcHBseSh0aGlzLnNlbGVjdHBpY2tlci5tYWluLmRhdGEsIG1haW5EYXRhKTtcclxuICAgICAgICAgIHRoaXMuc2VsZWN0cGlja2VyLmN1cnJlbnQuZGF0YSA9IHRoaXMuc2VsZWN0cGlja2VyLm1haW4uZGF0YTtcclxuICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgIH1cclxuICAgICAgICBjYXNlICdzZWFyY2gnOiB7XHJcbiAgICAgICAgICBBcnJheS5wcm90b3R5cGUucHVzaC5hcHBseSh0aGlzLnNlbGVjdHBpY2tlci5zZWFyY2guZGF0YSwgbWFpbkRhdGEpO1xyXG4gICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICByZXR1cm4gbWFpbkRhdGE7XHJcbiAgICB9LFxyXG5cclxuICAgIGJ1aWxkTGlzdDogZnVuY3Rpb24gKHNpemUsIHNlYXJjaGluZykge1xyXG4gICAgICB2YXIgdGhhdCA9IHRoaXMsXHJcbiAgICAgICAgICBzZWxlY3REYXRhID0gc2VhcmNoaW5nID8gdGhpcy5zZWxlY3RwaWNrZXIuc2VhcmNoLmRhdGEgOiB0aGlzLnNlbGVjdHBpY2tlci5tYWluLmRhdGEsXHJcbiAgICAgICAgICBtYWluRWxlbWVudHMgPSBbXSxcclxuICAgICAgICAgIHdpZGVzdE9wdGlvbkxlbmd0aCA9IDA7XHJcblxyXG4gICAgICBpZiAoKHRoYXQub3B0aW9ucy5zaG93VGljayB8fCB0aGF0Lm11bHRpcGxlKSAmJiAhZWxlbWVudFRlbXBsYXRlcy5jaGVja01hcmsucGFyZW50Tm9kZSkge1xyXG4gICAgICAgIGVsZW1lbnRUZW1wbGF0ZXMuY2hlY2tNYXJrLmNsYXNzTmFtZSA9IHRoaXMub3B0aW9ucy5pY29uQmFzZSArICcgJyArIHRoYXQub3B0aW9ucy50aWNrSWNvbiArICcgY2hlY2stbWFyayc7XHJcbiAgICAgICAgZWxlbWVudFRlbXBsYXRlcy5hLmFwcGVuZENoaWxkKGVsZW1lbnRUZW1wbGF0ZXMuY2hlY2tNYXJrKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgZnVuY3Rpb24gYnVpbGRFbGVtZW50IChtYWluRWxlbWVudHMsIGl0ZW0pIHtcclxuICAgICAgICB2YXIgbGlFbGVtZW50LFxyXG4gICAgICAgICAgICBjb21iaW5lZExlbmd0aCA9IDA7XHJcblxyXG4gICAgICAgIHN3aXRjaCAoaXRlbS50eXBlKSB7XHJcbiAgICAgICAgICBjYXNlICdkaXZpZGVyJzpcclxuICAgICAgICAgICAgbGlFbGVtZW50ID0gZ2VuZXJhdGVPcHRpb24ubGkoXHJcbiAgICAgICAgICAgICAgZmFsc2UsXHJcbiAgICAgICAgICAgICAgY2xhc3NOYW1lcy5ESVZJREVSLFxyXG4gICAgICAgICAgICAgIChpdGVtLm9wdElEID8gaXRlbS5vcHRJRCArICdkaXYnIDogdW5kZWZpbmVkKVxyXG4gICAgICAgICAgICApO1xyXG5cclxuICAgICAgICAgICAgYnJlYWs7XHJcblxyXG4gICAgICAgICAgY2FzZSAnb3B0aW9uJzpcclxuICAgICAgICAgICAgbGlFbGVtZW50ID0gZ2VuZXJhdGVPcHRpb24ubGkoXHJcbiAgICAgICAgICAgICAgZ2VuZXJhdGVPcHRpb24uYShcclxuICAgICAgICAgICAgICAgIGdlbmVyYXRlT3B0aW9uLnRleHQuY2FsbCh0aGF0LCBpdGVtKSxcclxuICAgICAgICAgICAgICAgIGl0ZW0ub3B0aW9uQ2xhc3MsXHJcbiAgICAgICAgICAgICAgICBpdGVtLmlubGluZVN0eWxlXHJcbiAgICAgICAgICAgICAgKSxcclxuICAgICAgICAgICAgICAnJyxcclxuICAgICAgICAgICAgICBpdGVtLm9wdElEXHJcbiAgICAgICAgICAgICk7XHJcblxyXG4gICAgICAgICAgICBpZiAobGlFbGVtZW50LmZpcnN0Q2hpbGQpIHtcclxuICAgICAgICAgICAgICBsaUVsZW1lbnQuZmlyc3RDaGlsZC5pZCA9IHRoYXQuc2VsZWN0SWQgKyAnLScgKyBpdGVtLmluZGV4O1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICBicmVhaztcclxuXHJcbiAgICAgICAgICBjYXNlICdvcHRncm91cC1sYWJlbCc6XHJcbiAgICAgICAgICAgIGxpRWxlbWVudCA9IGdlbmVyYXRlT3B0aW9uLmxpKFxyXG4gICAgICAgICAgICAgIGdlbmVyYXRlT3B0aW9uLmxhYmVsLmNhbGwodGhhdCwgaXRlbSksXHJcbiAgICAgICAgICAgICAgJ2Ryb3Bkb3duLWhlYWRlcicgKyBpdGVtLm9wdGdyb3VwQ2xhc3MsXHJcbiAgICAgICAgICAgICAgaXRlbS5vcHRJRFxyXG4gICAgICAgICAgICApO1xyXG5cclxuICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBpdGVtLmVsZW1lbnQgPSBsaUVsZW1lbnQ7XHJcbiAgICAgICAgbWFpbkVsZW1lbnRzLnB1c2gobGlFbGVtZW50KTtcclxuXHJcbiAgICAgICAgLy8gY291bnQgdGhlIG51bWJlciBvZiBjaGFyYWN0ZXJzIGluIHRoZSBvcHRpb24gLSBub3QgcGVyZmVjdCwgYnV0IHNob3VsZCB3b3JrIGluIG1vc3QgY2FzZXNcclxuICAgICAgICBpZiAoaXRlbS5kaXNwbGF5KSBjb21iaW5lZExlbmd0aCArPSBpdGVtLmRpc3BsYXkubGVuZ3RoO1xyXG4gICAgICAgIGlmIChpdGVtLnN1YnRleHQpIGNvbWJpbmVkTGVuZ3RoICs9IGl0ZW0uc3VidGV4dC5sZW5ndGg7XHJcbiAgICAgICAgLy8gaWYgdGhlcmUgaXMgYW4gaWNvbiwgZW5zdXJlIHRoaXMgb3B0aW9uJ3Mgd2lkdGggaXMgY2hlY2tlZFxyXG4gICAgICAgIGlmIChpdGVtLmljb24pIGNvbWJpbmVkTGVuZ3RoICs9IDE7XHJcblxyXG4gICAgICAgIGlmIChjb21iaW5lZExlbmd0aCA+IHdpZGVzdE9wdGlvbkxlbmd0aCkge1xyXG4gICAgICAgICAgd2lkZXN0T3B0aW9uTGVuZ3RoID0gY29tYmluZWRMZW5ndGg7XHJcblxyXG4gICAgICAgICAgLy8gZ3Vlc3Mgd2hpY2ggb3B0aW9uIGlzIHRoZSB3aWRlc3RcclxuICAgICAgICAgIC8vIHVzZSB0aGlzIHdoZW4gY2FsY3VsYXRpbmcgbWVudSB3aWR0aFxyXG4gICAgICAgICAgLy8gbm90IHBlcmZlY3QsIGJ1dCBpdCdzIGZhc3QsIGFuZCB0aGUgd2lkdGggd2lsbCBiZSB1cGRhdGluZyBhY2NvcmRpbmdseSB3aGVuIHNjcm9sbGluZ1xyXG4gICAgICAgICAgdGhhdC5zZWxlY3RwaWNrZXIudmlldy53aWRlc3RPcHRpb24gPSBtYWluRWxlbWVudHNbbWFpbkVsZW1lbnRzLmxlbmd0aCAtIDFdO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgdmFyIHN0YXJ0SW5kZXggPSBzaXplIHx8IDA7XHJcblxyXG4gICAgICBmb3IgKHZhciBsZW4gPSBzZWxlY3REYXRhLmxlbmd0aCwgaSA9IHN0YXJ0SW5kZXg7IGkgPCBsZW47IGkrKykge1xyXG4gICAgICAgIHZhciBpdGVtID0gc2VsZWN0RGF0YVtpXTtcclxuXHJcbiAgICAgICAgYnVpbGRFbGVtZW50KG1haW5FbGVtZW50cywgaXRlbSk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmIChzaXplKSB7XHJcbiAgICAgICAgaWYgKHNlYXJjaGluZykge1xyXG4gICAgICAgICAgQXJyYXkucHJvdG90eXBlLnB1c2guYXBwbHkodGhpcy5zZWxlY3RwaWNrZXIuc2VhcmNoLmVsZW1lbnRzLCBtYWluRWxlbWVudHMpO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICBBcnJheS5wcm90b3R5cGUucHVzaC5hcHBseSh0aGlzLnNlbGVjdHBpY2tlci5tYWluLmVsZW1lbnRzLCBtYWluRWxlbWVudHMpO1xyXG4gICAgICAgICAgdGhpcy5zZWxlY3RwaWNrZXIuY3VycmVudC5lbGVtZW50cyA9IHRoaXMuc2VsZWN0cGlja2VyLm1haW4uZWxlbWVudHM7XHJcbiAgICAgICAgfVxyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIGlmIChzZWFyY2hpbmcpIHtcclxuICAgICAgICAgIHRoaXMuc2VsZWN0cGlja2VyLnNlYXJjaC5lbGVtZW50cyA9IG1haW5FbGVtZW50cztcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgdGhpcy5zZWxlY3RwaWNrZXIubWFpbi5lbGVtZW50cyA9IHRoaXMuc2VsZWN0cGlja2VyLmN1cnJlbnQuZWxlbWVudHMgPSBtYWluRWxlbWVudHM7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9LFxyXG5cclxuICAgIGZpbmRMaXM6IGZ1bmN0aW9uICgpIHtcclxuICAgICAgcmV0dXJuIHRoaXMuJG1lbnVJbm5lci5maW5kKCcuaW5uZXIgPiBsaScpO1xyXG4gICAgfSxcclxuXHJcbiAgICByZW5kZXI6IGZ1bmN0aW9uIChpbml0KSB7XHJcbiAgICAgIHZhciB0aGF0ID0gdGhpcyxcclxuICAgICAgICAgIGVsZW1lbnQgPSB0aGlzLiRlbGVtZW50WzBdLFxyXG4gICAgICAgICAgLy8gZW5zdXJlIHRpdGxlT3B0aW9uIGlzIGFwcGVuZGVkIGFuZCBzZWxlY3RlZCAoaWYgbmVjZXNzYXJ5KSBiZWZvcmUgZ2V0dGluZyBzZWxlY3RlZE9wdGlvbnNcclxuICAgICAgICAgIHBsYWNlaG9sZGVyU2VsZWN0ZWQgPSB0aGlzLnNldFBsYWNlaG9sZGVyKCkgJiYgZWxlbWVudC5zZWxlY3RlZEluZGV4ID09PSAwLFxyXG4gICAgICAgICAgc2VsZWN0ZWRPcHRpb25zID0gZ2V0U2VsZWN0ZWRPcHRpb25zLmNhbGwodGhpcyksXHJcbiAgICAgICAgICBzZWxlY3RlZENvdW50ID0gc2VsZWN0ZWRPcHRpb25zLmxlbmd0aCxcclxuICAgICAgICAgIHNlbGVjdGVkVmFsdWVzID0gZ2V0U2VsZWN0VmFsdWVzLmNhbGwodGhpcywgc2VsZWN0ZWRPcHRpb25zKSxcclxuICAgICAgICAgIGJ1dHRvbiA9IHRoaXMuJGJ1dHRvblswXSxcclxuICAgICAgICAgIGJ1dHRvbklubmVyID0gYnV0dG9uLnF1ZXJ5U2VsZWN0b3IoJy5maWx0ZXItb3B0aW9uLWlubmVyLWlubmVyJyksXHJcbiAgICAgICAgICBtdWx0aXBsZVNlcGFyYXRvciA9IGRvY3VtZW50LmNyZWF0ZVRleHROb2RlKHRoaXMub3B0aW9ucy5tdWx0aXBsZVNlcGFyYXRvciksXHJcbiAgICAgICAgICB0aXRsZUZyYWdtZW50ID0gZWxlbWVudFRlbXBsYXRlcy5mcmFnbWVudC5jbG9uZU5vZGUoZmFsc2UpLFxyXG4gICAgICAgICAgc2hvd0NvdW50LFxyXG4gICAgICAgICAgY291bnRNYXgsXHJcbiAgICAgICAgICBoYXNDb250ZW50ID0gZmFsc2U7XHJcblxyXG4gICAgICBmdW5jdGlvbiBjcmVhdGVTZWxlY3RlZCAoaXRlbSkge1xyXG4gICAgICAgIGlmIChpdGVtLnNlbGVjdGVkKSB7XHJcbiAgICAgICAgICB0aGF0LmNyZWF0ZU9wdGlvbihpdGVtLCB0cnVlKTtcclxuICAgICAgICB9IGVsc2UgaWYgKGl0ZW0uY2hpbGRyZW4gJiYgaXRlbS5jaGlsZHJlbi5sZW5ndGgpIHtcclxuICAgICAgICAgIGl0ZW0uY2hpbGRyZW4ubWFwKGNyZWF0ZVNlbGVjdGVkKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIGNyZWF0ZSBzZWxlY3RlZCBvcHRpb24gZWxlbWVudHMgdG8gZW5zdXJlIHNlbGVjdCB2YWx1ZSBpcyBjb3JyZWN0XHJcbiAgICAgIGlmICh0aGlzLm9wdGlvbnMuc291cmNlLmRhdGEgJiYgaW5pdCkge1xyXG4gICAgICAgIHNlbGVjdGVkT3B0aW9ucy5tYXAoY3JlYXRlU2VsZWN0ZWQpO1xyXG4gICAgICAgIGVsZW1lbnQuYXBwZW5kQ2hpbGQodGhpcy5zZWxlY3RwaWNrZXIubWFpbi5vcHRpb25RdWV1ZSk7XHJcblxyXG4gICAgICAgIGlmIChwbGFjZWhvbGRlclNlbGVjdGVkKSBwbGFjZWhvbGRlclNlbGVjdGVkID0gZWxlbWVudC5zZWxlY3RlZEluZGV4ID09PSAwO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBidXR0b24uY2xhc3NMaXN0LnRvZ2dsZSgnYnMtcGxhY2Vob2xkZXInLCB0aGF0Lm11bHRpcGxlID8gIXNlbGVjdGVkQ291bnQgOiAhc2VsZWN0ZWRWYWx1ZXMgJiYgc2VsZWN0ZWRWYWx1ZXMgIT09IDApO1xyXG5cclxuICAgICAgaWYgKCF0aGF0Lm11bHRpcGxlICYmIHNlbGVjdGVkT3B0aW9ucy5sZW5ndGggPT09IDEpIHtcclxuICAgICAgICB0aGF0LnNlbGVjdHBpY2tlci52aWV3LmRpc3BsYXllZFZhbHVlID0gc2VsZWN0ZWRWYWx1ZXM7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmICh0aGlzLm9wdGlvbnMuc2VsZWN0ZWRUZXh0Rm9ybWF0ID09PSAnc3RhdGljJykge1xyXG4gICAgICAgIHRpdGxlRnJhZ21lbnQgPSBnZW5lcmF0ZU9wdGlvbi50ZXh0LmNhbGwodGhpcywgeyB0ZXh0OiB0aGlzLm9wdGlvbnMucGxhY2Vob2xkZXIgfSwgdHJ1ZSk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgc2hvd0NvdW50ID0gdGhpcy5tdWx0aXBsZSAmJiB0aGlzLm9wdGlvbnMuc2VsZWN0ZWRUZXh0Rm9ybWF0LmluZGV4T2YoJ2NvdW50JykgIT09IC0xICYmIHNlbGVjdGVkQ291bnQgPiAxO1xyXG5cclxuICAgICAgICAvLyBkZXRlcm1pbmUgaWYgdGhlIG51bWJlciBvZiBzZWxlY3RlZCBvcHRpb25zIHdpbGwgYmUgc2hvd24gKHNob3dDb3VudCA9PT0gdHJ1ZSlcclxuICAgICAgICBpZiAoc2hvd0NvdW50KSB7XHJcbiAgICAgICAgICBjb3VudE1heCA9IHRoaXMub3B0aW9ucy5zZWxlY3RlZFRleHRGb3JtYXQuc3BsaXQoJz4nKTtcclxuICAgICAgICAgIHNob3dDb3VudCA9IChjb3VudE1heC5sZW5ndGggPiAxICYmIHNlbGVjdGVkQ291bnQgPiBjb3VudE1heFsxXSkgfHwgKGNvdW50TWF4Lmxlbmd0aCA9PT0gMSAmJiBzZWxlY3RlZENvdW50ID49IDIpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gb25seSBsb29wIHRocm91Z2ggYWxsIHNlbGVjdGVkIG9wdGlvbnMgaWYgdGhlIGNvdW50IHdvbid0IGJlIHNob3duXHJcbiAgICAgICAgaWYgKHNob3dDb3VudCA9PT0gZmFsc2UpIHtcclxuICAgICAgICAgIGlmICghcGxhY2Vob2xkZXJTZWxlY3RlZCkge1xyXG4gICAgICAgICAgICBmb3IgKHZhciBzZWxlY3RlZEluZGV4ID0gMDsgc2VsZWN0ZWRJbmRleCA8IHNlbGVjdGVkQ291bnQ7IHNlbGVjdGVkSW5kZXgrKykge1xyXG4gICAgICAgICAgICAgIGlmIChzZWxlY3RlZEluZGV4IDwgNTApIHtcclxuICAgICAgICAgICAgICAgIHZhciBvcHRpb24gPSBzZWxlY3RlZE9wdGlvbnNbc2VsZWN0ZWRJbmRleF0sXHJcbiAgICAgICAgICAgICAgICAgICAgdGl0bGVPcHRpb25zID0ge307XHJcblxyXG4gICAgICAgICAgICAgICAgaWYgKG9wdGlvbikge1xyXG4gICAgICAgICAgICAgICAgICBpZiAodGhpcy5tdWx0aXBsZSAmJiBzZWxlY3RlZEluZGV4ID4gMCkge1xyXG4gICAgICAgICAgICAgICAgICAgIHRpdGxlRnJhZ21lbnQuYXBwZW5kQ2hpbGQobXVsdGlwbGVTZXBhcmF0b3IuY2xvbmVOb2RlKGZhbHNlKSk7XHJcbiAgICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICAgIGlmIChvcHRpb24udGl0bGUpIHtcclxuICAgICAgICAgICAgICAgICAgICB0aXRsZU9wdGlvbnMudGV4dCA9IG9wdGlvbi50aXRsZTtcclxuICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmIChvcHRpb24uY29udGVudCAmJiB0aGF0Lm9wdGlvbnMuc2hvd0NvbnRlbnQpIHtcclxuICAgICAgICAgICAgICAgICAgICB0aXRsZU9wdGlvbnMuY29udGVudCA9IG9wdGlvbi5jb250ZW50LnRvU3RyaW5nKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgaGFzQ29udGVudCA9IHRydWU7XHJcbiAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKHRoYXQub3B0aW9ucy5zaG93SWNvbikge1xyXG4gICAgICAgICAgICAgICAgICAgICAgdGl0bGVPcHRpb25zLmljb24gPSBvcHRpb24uaWNvbjtcclxuICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKHRoYXQub3B0aW9ucy5zaG93U3VidGV4dCAmJiAhdGhhdC5tdWx0aXBsZSAmJiBvcHRpb24uc3VidGV4dCkgdGl0bGVPcHRpb25zLnN1YnRleHQgPSAnICcgKyBvcHRpb24uc3VidGV4dDtcclxuICAgICAgICAgICAgICAgICAgICB0aXRsZU9wdGlvbnMudGV4dCA9IG9wdGlvbi50ZXh0LnRyaW0oKTtcclxuICAgICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgICAgdGl0bGVGcmFnbWVudC5hcHBlbmRDaGlsZChnZW5lcmF0ZU9wdGlvbi50ZXh0LmNhbGwodGhpcywgdGl0bGVPcHRpb25zLCB0cnVlKSk7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLy8gYWRkIGVsbGlwc2lzXHJcbiAgICAgICAgICAgIGlmIChzZWxlY3RlZENvdW50ID4gNDkpIHtcclxuICAgICAgICAgICAgICB0aXRsZUZyYWdtZW50LmFwcGVuZENoaWxkKGRvY3VtZW50LmNyZWF0ZVRleHROb2RlKCcuLi4nKSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH1cclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgdmFyIG9wdGlvblNlbGVjdG9yID0gJzpub3QoW2hpZGRlbl0pOm5vdChbZGF0YS1oaWRkZW49XCJ0cnVlXCJdKTpub3QoW2RhdGEtZGl2aWRlcj1cInRydWVcIl0pJztcclxuICAgICAgICAgIGlmICh0aGlzLm9wdGlvbnMuaGlkZURpc2FibGVkKSBvcHRpb25TZWxlY3RvciArPSAnOm5vdCg6ZGlzYWJsZWQpJztcclxuXHJcbiAgICAgICAgICAvLyBJZiB0aGlzIGlzIGEgbXVsdGlzZWxlY3QsIGFuZCBzZWxlY3RlZFRleHRGb3JtYXQgaXMgY291bnQsIHRoZW4gc2hvdyAxIG9mIDIgc2VsZWN0ZWQsIGV0Yy5cclxuICAgICAgICAgIHZhciB0b3RhbENvdW50ID0gdGhpcy4kZWxlbWVudFswXS5xdWVyeVNlbGVjdG9yQWxsKCdzZWxlY3QgPiBvcHRpb24nICsgb3B0aW9uU2VsZWN0b3IgKyAnLCBvcHRncm91cCcgKyBvcHRpb25TZWxlY3RvciArICcgb3B0aW9uJyArIG9wdGlvblNlbGVjdG9yKS5sZW5ndGgsXHJcbiAgICAgICAgICAgICAgdHI4blRleHQgPSAodHlwZW9mIHRoaXMub3B0aW9ucy5jb3VudFNlbGVjdGVkVGV4dCA9PT0gJ2Z1bmN0aW9uJykgPyB0aGlzLm9wdGlvbnMuY291bnRTZWxlY3RlZFRleHQoc2VsZWN0ZWRDb3VudCwgdG90YWxDb3VudCkgOiB0aGlzLm9wdGlvbnMuY291bnRTZWxlY3RlZFRleHQ7XHJcblxyXG4gICAgICAgICAgdGl0bGVGcmFnbWVudCA9IGdlbmVyYXRlT3B0aW9uLnRleHQuY2FsbCh0aGlzLCB7XHJcbiAgICAgICAgICAgIHRleHQ6IHRyOG5UZXh0LnJlcGxhY2UoJ3swfScsIHNlbGVjdGVkQ291bnQudG9TdHJpbmcoKSkucmVwbGFjZSgnezF9JywgdG90YWxDb3VudC50b1N0cmluZygpKVxyXG4gICAgICAgICAgfSwgdHJ1ZSk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBJZiB0aGUgc2VsZWN0IGRvZXNuJ3QgaGF2ZSBhIHRpdGxlLCB0aGVuIHVzZSB0aGUgZGVmYXVsdCwgb3IgaWYgbm90aGluZyBpcyBzZXQgYXQgYWxsLCB1c2Ugbm9uZVNlbGVjdGVkVGV4dFxyXG4gICAgICBpZiAoIXRpdGxlRnJhZ21lbnQuY2hpbGROb2Rlcy5sZW5ndGgpIHtcclxuICAgICAgICB0aXRsZUZyYWdtZW50ID0gZ2VuZXJhdGVPcHRpb24udGV4dC5jYWxsKHRoaXMsIHtcclxuICAgICAgICAgIHRleHQ6IHRoaXMub3B0aW9ucy5wbGFjZWhvbGRlciA/IHRoaXMub3B0aW9ucy5wbGFjZWhvbGRlciA6IHRoaXMub3B0aW9ucy5ub25lU2VsZWN0ZWRUZXh0XHJcbiAgICAgICAgfSwgdHJ1ZSk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIGlmIHRoZSBzZWxlY3QgaGFzIGEgdGl0bGUsIGFwcGx5IGl0IHRvIHRoZSBidXR0b24sIGFuZCBpZiBub3QsIGFwcGx5IHRpdGxlRnJhZ21lbnQgdGV4dFxyXG4gICAgICAvLyBzdHJpcCBhbGwgSFRNTCB0YWdzIGFuZCB0cmltIHRoZSByZXN1bHQsIHRoZW4gdW5lc2NhcGUgYW55IGVzY2FwZWQgdGFnc1xyXG4gICAgICBidXR0b24udGl0bGUgPSB0aXRsZUZyYWdtZW50LnRleHRDb250ZW50LnJlcGxhY2UoLzxbXj5dKj4/L2csICcnKS50cmltKCk7XHJcblxyXG4gICAgICBpZiAodGhpcy5vcHRpb25zLnNhbml0aXplICYmIGhhc0NvbnRlbnQpIHtcclxuICAgICAgICBzYW5pdGl6ZUh0bWwoW3RpdGxlRnJhZ21lbnRdLCB0aGF0Lm9wdGlvbnMud2hpdGVMaXN0LCB0aGF0Lm9wdGlvbnMuc2FuaXRpemVGbik7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGJ1dHRvbklubmVyLmlubmVySFRNTCA9ICcnO1xyXG4gICAgICBidXR0b25Jbm5lci5hcHBlbmRDaGlsZCh0aXRsZUZyYWdtZW50KTtcclxuXHJcbiAgICAgIGlmICh2ZXJzaW9uLm1ham9yIDwgNCAmJiB0aGlzLiRuZXdFbGVtZW50WzBdLmNsYXNzTGlzdC5jb250YWlucygnYnMzLWhhcy1hZGRvbicpKSB7XHJcbiAgICAgICAgdmFyIGZpbHRlckV4cGFuZCA9IGJ1dHRvbi5xdWVyeVNlbGVjdG9yKCcuZmlsdGVyLWV4cGFuZCcpLFxyXG4gICAgICAgICAgICBjbG9uZSA9IGJ1dHRvbklubmVyLmNsb25lTm9kZSh0cnVlKTtcclxuXHJcbiAgICAgICAgY2xvbmUuY2xhc3NOYW1lID0gJ2ZpbHRlci1leHBhbmQnO1xyXG5cclxuICAgICAgICBpZiAoZmlsdGVyRXhwYW5kKSB7XHJcbiAgICAgICAgICBidXR0b24ucmVwbGFjZUNoaWxkKGNsb25lLCBmaWx0ZXJFeHBhbmQpO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICBidXR0b24uYXBwZW5kQ2hpbGQoY2xvbmUpO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgdGhpcy4kZWxlbWVudC50cmlnZ2VyKCdyZW5kZXJlZCcgKyBFVkVOVF9LRVkpO1xyXG4gICAgfSxcclxuXHJcbiAgICAvKipcclxuICAgICAqIEBwYXJhbSBbc3R5bGVdXHJcbiAgICAgKiBAcGFyYW0gW3N0YXR1c11cclxuICAgICAqL1xyXG4gICAgc2V0U3R5bGU6IGZ1bmN0aW9uIChuZXdTdHlsZSwgc3RhdHVzKSB7XHJcbiAgICAgIHZhciBidXR0b24gPSB0aGlzLiRidXR0b25bMF0sXHJcbiAgICAgICAgICBuZXdFbGVtZW50ID0gdGhpcy4kbmV3RWxlbWVudFswXSxcclxuICAgICAgICAgIHN0eWxlID0gdGhpcy5vcHRpb25zLnN0eWxlLnRyaW0oKSxcclxuICAgICAgICAgIGJ1dHRvbkNsYXNzO1xyXG5cclxuICAgICAgaWYgKHRoaXMuJGVsZW1lbnQuYXR0cignY2xhc3MnKSkge1xyXG4gICAgICAgIHRoaXMuJG5ld0VsZW1lbnQuYWRkQ2xhc3ModGhpcy4kZWxlbWVudC5hdHRyKCdjbGFzcycpLnJlcGxhY2UoL3NlbGVjdHBpY2tlcnxtb2JpbGUtZGV2aWNlfGJzLXNlbGVjdC1oaWRkZW58dmFsaWRhdGVcXFsuKlxcXS9naSwgJycpKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKHZlcnNpb24ubWFqb3IgPCA0KSB7XHJcbiAgICAgICAgbmV3RWxlbWVudC5jbGFzc0xpc3QuYWRkKCdiczMnKTtcclxuXHJcbiAgICAgICAgaWYgKG5ld0VsZW1lbnQucGFyZW50Tm9kZS5jbGFzc0xpc3QgJiYgbmV3RWxlbWVudC5wYXJlbnROb2RlLmNsYXNzTGlzdC5jb250YWlucygnaW5wdXQtZ3JvdXAnKSAmJlxyXG4gICAgICAgICAgICAobmV3RWxlbWVudC5wcmV2aW91c0VsZW1lbnRTaWJsaW5nIHx8IG5ld0VsZW1lbnQubmV4dEVsZW1lbnRTaWJsaW5nKSAmJlxyXG4gICAgICAgICAgICAobmV3RWxlbWVudC5wcmV2aW91c0VsZW1lbnRTaWJsaW5nIHx8IG5ld0VsZW1lbnQubmV4dEVsZW1lbnRTaWJsaW5nKS5jbGFzc0xpc3QuY29udGFpbnMoJ2lucHV0LWdyb3VwLWFkZG9uJylcclxuICAgICAgICApIHtcclxuICAgICAgICAgIG5ld0VsZW1lbnQuY2xhc3NMaXN0LmFkZCgnYnMzLWhhcy1hZGRvbicpO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKG5ld1N0eWxlKSB7XHJcbiAgICAgICAgYnV0dG9uQ2xhc3MgPSBuZXdTdHlsZS50cmltKCk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgYnV0dG9uQ2xhc3MgPSBzdHlsZTtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKHN0YXR1cyA9PSAnYWRkJykge1xyXG4gICAgICAgIGlmIChidXR0b25DbGFzcykgYnV0dG9uLmNsYXNzTGlzdC5hZGQuYXBwbHkoYnV0dG9uLmNsYXNzTGlzdCwgYnV0dG9uQ2xhc3Muc3BsaXQoJyAnKSk7XHJcbiAgICAgIH0gZWxzZSBpZiAoc3RhdHVzID09ICdyZW1vdmUnKSB7XHJcbiAgICAgICAgaWYgKGJ1dHRvbkNsYXNzKSBidXR0b24uY2xhc3NMaXN0LnJlbW92ZS5hcHBseShidXR0b24uY2xhc3NMaXN0LCBidXR0b25DbGFzcy5zcGxpdCgnICcpKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBpZiAoc3R5bGUpIGJ1dHRvbi5jbGFzc0xpc3QucmVtb3ZlLmFwcGx5KGJ1dHRvbi5jbGFzc0xpc3QsIHN0eWxlLnNwbGl0KCcgJykpO1xyXG4gICAgICAgIGlmIChidXR0b25DbGFzcykgYnV0dG9uLmNsYXNzTGlzdC5hZGQuYXBwbHkoYnV0dG9uLmNsYXNzTGlzdCwgYnV0dG9uQ2xhc3Muc3BsaXQoJyAnKSk7XHJcbiAgICAgIH1cclxuICAgIH0sXHJcblxyXG4gICAgbGlIZWlnaHQ6IGZ1bmN0aW9uIChyZWZyZXNoKSB7XHJcbiAgICAgIGlmICghcmVmcmVzaCAmJiAodGhpcy5vcHRpb25zLnNpemUgPT09IGZhbHNlIHx8IE9iamVjdC5rZXlzKHRoaXMuc2l6ZUluZm8pLmxlbmd0aCkpIHJldHVybjtcclxuXHJcbiAgICAgIHZhciBuZXdFbGVtZW50ID0gZWxlbWVudFRlbXBsYXRlcy5kaXYuY2xvbmVOb2RlKGZhbHNlKSxcclxuICAgICAgICAgIG1lbnUgPSBlbGVtZW50VGVtcGxhdGVzLmRpdi5jbG9uZU5vZGUoZmFsc2UpLFxyXG4gICAgICAgICAgbWVudUlubmVyID0gZWxlbWVudFRlbXBsYXRlcy5kaXYuY2xvbmVOb2RlKGZhbHNlKSxcclxuICAgICAgICAgIG1lbnVJbm5lcklubmVyID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgndWwnKSxcclxuICAgICAgICAgIGRpdmlkZXIgPSBlbGVtZW50VGVtcGxhdGVzLmxpLmNsb25lTm9kZShmYWxzZSksXHJcbiAgICAgICAgICBkcm9wZG93bkhlYWRlciA9IGVsZW1lbnRUZW1wbGF0ZXMubGkuY2xvbmVOb2RlKGZhbHNlKSxcclxuICAgICAgICAgIGxpLFxyXG4gICAgICAgICAgYSA9IGVsZW1lbnRUZW1wbGF0ZXMuYS5jbG9uZU5vZGUoZmFsc2UpLFxyXG4gICAgICAgICAgdGV4dCA9IGVsZW1lbnRUZW1wbGF0ZXMuc3Bhbi5jbG9uZU5vZGUoZmFsc2UpLFxyXG4gICAgICAgICAgaGVhZGVyID0gdGhpcy5vcHRpb25zLmhlYWRlciAmJiB0aGlzLiRtZW51LmZpbmQoJy4nICsgY2xhc3NOYW1lcy5QT1BPVkVSSEVBREVSKS5sZW5ndGggPiAwID8gdGhpcy4kbWVudS5maW5kKCcuJyArIGNsYXNzTmFtZXMuUE9QT1ZFUkhFQURFUilbMF0uY2xvbmVOb2RlKHRydWUpIDogbnVsbCxcclxuICAgICAgICAgIHNlYXJjaCA9IHRoaXMub3B0aW9ucy5saXZlU2VhcmNoID8gZWxlbWVudFRlbXBsYXRlcy5kaXYuY2xvbmVOb2RlKGZhbHNlKSA6IG51bGwsXHJcbiAgICAgICAgICBhY3Rpb25zID0gdGhpcy5vcHRpb25zLmFjdGlvbnNCb3ggJiYgdGhpcy5tdWx0aXBsZSAmJiB0aGlzLiRtZW51LmZpbmQoJy5icy1hY3Rpb25zYm94JykubGVuZ3RoID4gMCA/IHRoaXMuJG1lbnUuZmluZCgnLmJzLWFjdGlvbnNib3gnKVswXS5jbG9uZU5vZGUodHJ1ZSkgOiBudWxsLFxyXG4gICAgICAgICAgZG9uZUJ1dHRvbiA9IHRoaXMub3B0aW9ucy5kb25lQnV0dG9uICYmIHRoaXMubXVsdGlwbGUgJiYgdGhpcy4kbWVudS5maW5kKCcuYnMtZG9uZWJ1dHRvbicpLmxlbmd0aCA+IDAgPyB0aGlzLiRtZW51LmZpbmQoJy5icy1kb25lYnV0dG9uJylbMF0uY2xvbmVOb2RlKHRydWUpIDogbnVsbCxcclxuICAgICAgICAgIGZpcnN0T3B0aW9uID0gdGhpcy4kZWxlbWVudFswXS5vcHRpb25zWzBdO1xyXG5cclxuICAgICAgdGhpcy5zaXplSW5mby5zZWxlY3RXaWR0aCA9IHRoaXMuJG5ld0VsZW1lbnRbMF0ub2Zmc2V0V2lkdGg7XHJcblxyXG4gICAgICB0ZXh0LmNsYXNzTmFtZSA9ICd0ZXh0JztcclxuICAgICAgYS5jbGFzc05hbWUgPSAnZHJvcGRvd24taXRlbSAnICsgKGZpcnN0T3B0aW9uID8gZmlyc3RPcHRpb24uY2xhc3NOYW1lIDogJycpO1xyXG4gICAgICBuZXdFbGVtZW50LmNsYXNzTmFtZSA9IHRoaXMuJG1lbnVbMF0ucGFyZW50Tm9kZS5jbGFzc05hbWUgKyAnICcgKyBjbGFzc05hbWVzLlNIT1c7XHJcbiAgICAgIG5ld0VsZW1lbnQuc3R5bGUud2lkdGggPSAwOyAvLyBlbnN1cmUgYnV0dG9uIHdpZHRoIGRvZXNuJ3QgYWZmZWN0IG5hdHVyYWwgd2lkdGggb2YgbWVudSB3aGVuIGNhbGN1bGF0aW5nXHJcbiAgICAgIGlmICh0aGlzLm9wdGlvbnMud2lkdGggPT09ICdhdXRvJykgbWVudS5zdHlsZS5taW5XaWR0aCA9IDA7XHJcbiAgICAgIG1lbnUuY2xhc3NOYW1lID0gY2xhc3NOYW1lcy5NRU5VICsgJyAnICsgY2xhc3NOYW1lcy5TSE9XO1xyXG4gICAgICBtZW51SW5uZXIuY2xhc3NOYW1lID0gJ2lubmVyICcgKyBjbGFzc05hbWVzLlNIT1c7XHJcbiAgICAgIG1lbnVJbm5lcklubmVyLmNsYXNzTmFtZSA9IGNsYXNzTmFtZXMuTUVOVSArICcgaW5uZXIgJyArICh2ZXJzaW9uLm1ham9yID49ICc0JyA/IGNsYXNzTmFtZXMuU0hPVyA6ICcnKTtcclxuICAgICAgZGl2aWRlci5jbGFzc05hbWUgPSBjbGFzc05hbWVzLkRJVklERVI7XHJcbiAgICAgIGRyb3Bkb3duSGVhZGVyLmNsYXNzTmFtZSA9ICdkcm9wZG93bi1oZWFkZXInO1xyXG5cclxuICAgICAgdGV4dC5hcHBlbmRDaGlsZChkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZSgnXFx1MjAwYicpKTtcclxuXHJcbiAgICAgIGlmICh0aGlzLnNlbGVjdHBpY2tlci5jdXJyZW50LmRhdGEubGVuZ3RoKSB7XHJcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLnNlbGVjdHBpY2tlci5jdXJyZW50LmRhdGEubGVuZ3RoOyBpKyspIHtcclxuICAgICAgICAgIHZhciBkYXRhID0gdGhpcy5zZWxlY3RwaWNrZXIuY3VycmVudC5kYXRhW2ldO1xyXG4gICAgICAgICAgaWYgKGRhdGEudHlwZSA9PT0gJ29wdGlvbicpIHtcclxuICAgICAgICAgICAgbGkgPSBkYXRhLmVsZW1lbnQ7XHJcbiAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBsaSA9IGVsZW1lbnRUZW1wbGF0ZXMubGkuY2xvbmVOb2RlKGZhbHNlKTtcclxuICAgICAgICBhLmFwcGVuZENoaWxkKHRleHQpO1xyXG4gICAgICAgIGxpLmFwcGVuZENoaWxkKGEpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBkcm9wZG93bkhlYWRlci5hcHBlbmRDaGlsZCh0ZXh0LmNsb25lTm9kZSh0cnVlKSk7XHJcblxyXG4gICAgICBpZiAodGhpcy5zZWxlY3RwaWNrZXIudmlldy53aWRlc3RPcHRpb24pIHtcclxuICAgICAgICBtZW51SW5uZXJJbm5lci5hcHBlbmRDaGlsZCh0aGlzLnNlbGVjdHBpY2tlci52aWV3LndpZGVzdE9wdGlvbi5jbG9uZU5vZGUodHJ1ZSkpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBtZW51SW5uZXJJbm5lci5hcHBlbmRDaGlsZChsaSk7XHJcbiAgICAgIG1lbnVJbm5lcklubmVyLmFwcGVuZENoaWxkKGRpdmlkZXIpO1xyXG4gICAgICBtZW51SW5uZXJJbm5lci5hcHBlbmRDaGlsZChkcm9wZG93bkhlYWRlcik7XHJcbiAgICAgIGlmIChoZWFkZXIpIG1lbnUuYXBwZW5kQ2hpbGQoaGVhZGVyKTtcclxuICAgICAgaWYgKHNlYXJjaCkge1xyXG4gICAgICAgIHZhciBpbnB1dCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2lucHV0Jyk7XHJcbiAgICAgICAgc2VhcmNoLmNsYXNzTmFtZSA9ICdicy1zZWFyY2hib3gnO1xyXG4gICAgICAgIGlucHV0LmNsYXNzTmFtZSA9ICdmb3JtLWNvbnRyb2wnO1xyXG4gICAgICAgIHNlYXJjaC5hcHBlbmRDaGlsZChpbnB1dCk7XHJcbiAgICAgICAgbWVudS5hcHBlbmRDaGlsZChzZWFyY2gpO1xyXG4gICAgICB9XHJcbiAgICAgIGlmIChhY3Rpb25zKSBtZW51LmFwcGVuZENoaWxkKGFjdGlvbnMpO1xyXG4gICAgICBtZW51SW5uZXIuYXBwZW5kQ2hpbGQobWVudUlubmVySW5uZXIpO1xyXG4gICAgICBtZW51LmFwcGVuZENoaWxkKG1lbnVJbm5lcik7XHJcbiAgICAgIGlmIChkb25lQnV0dG9uKSBtZW51LmFwcGVuZENoaWxkKGRvbmVCdXR0b24pO1xyXG4gICAgICBuZXdFbGVtZW50LmFwcGVuZENoaWxkKG1lbnUpO1xyXG5cclxuICAgICAgZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChuZXdFbGVtZW50KTtcclxuXHJcbiAgICAgIHZhciBsaUhlaWdodCA9IGxpLm9mZnNldEhlaWdodCxcclxuICAgICAgICAgIGRyb3Bkb3duSGVhZGVySGVpZ2h0ID0gZHJvcGRvd25IZWFkZXIgPyBkcm9wZG93bkhlYWRlci5vZmZzZXRIZWlnaHQgOiAwLFxyXG4gICAgICAgICAgaGVhZGVySGVpZ2h0ID0gaGVhZGVyID8gaGVhZGVyLm9mZnNldEhlaWdodCA6IDAsXHJcbiAgICAgICAgICBzZWFyY2hIZWlnaHQgPSBzZWFyY2ggPyBzZWFyY2gub2Zmc2V0SGVpZ2h0IDogMCxcclxuICAgICAgICAgIGFjdGlvbnNIZWlnaHQgPSBhY3Rpb25zID8gYWN0aW9ucy5vZmZzZXRIZWlnaHQgOiAwLFxyXG4gICAgICAgICAgZG9uZUJ1dHRvbkhlaWdodCA9IGRvbmVCdXR0b24gPyBkb25lQnV0dG9uLm9mZnNldEhlaWdodCA6IDAsXHJcbiAgICAgICAgICBkaXZpZGVySGVpZ2h0ID0gJChkaXZpZGVyKS5vdXRlckhlaWdodCh0cnVlKSxcclxuICAgICAgICAgIG1lbnVTdHlsZSA9IHdpbmRvdy5nZXRDb21wdXRlZFN0eWxlKG1lbnUpLFxyXG4gICAgICAgICAgbWVudVdpZHRoID0gbWVudS5vZmZzZXRXaWR0aCxcclxuICAgICAgICAgIG1lbnVQYWRkaW5nID0ge1xyXG4gICAgICAgICAgICB2ZXJ0OiB0b0ludGVnZXIobWVudVN0eWxlLnBhZGRpbmdUb3ApICtcclxuICAgICAgICAgICAgICAgICAgdG9JbnRlZ2VyKG1lbnVTdHlsZS5wYWRkaW5nQm90dG9tKSArXHJcbiAgICAgICAgICAgICAgICAgIHRvSW50ZWdlcihtZW51U3R5bGUuYm9yZGVyVG9wV2lkdGgpICtcclxuICAgICAgICAgICAgICAgICAgdG9JbnRlZ2VyKG1lbnVTdHlsZS5ib3JkZXJCb3R0b21XaWR0aCksXHJcbiAgICAgICAgICAgIGhvcml6OiB0b0ludGVnZXIobWVudVN0eWxlLnBhZGRpbmdMZWZ0KSArXHJcbiAgICAgICAgICAgICAgICAgIHRvSW50ZWdlcihtZW51U3R5bGUucGFkZGluZ1JpZ2h0KSArXHJcbiAgICAgICAgICAgICAgICAgIHRvSW50ZWdlcihtZW51U3R5bGUuYm9yZGVyTGVmdFdpZHRoKSArXHJcbiAgICAgICAgICAgICAgICAgIHRvSW50ZWdlcihtZW51U3R5bGUuYm9yZGVyUmlnaHRXaWR0aClcclxuICAgICAgICAgIH0sXHJcbiAgICAgICAgICBtZW51RXh0cmFzID0ge1xyXG4gICAgICAgICAgICB2ZXJ0OiBtZW51UGFkZGluZy52ZXJ0ICtcclxuICAgICAgICAgICAgICAgICAgdG9JbnRlZ2VyKG1lbnVTdHlsZS5tYXJnaW5Ub3ApICtcclxuICAgICAgICAgICAgICAgICAgdG9JbnRlZ2VyKG1lbnVTdHlsZS5tYXJnaW5Cb3R0b20pICsgMixcclxuICAgICAgICAgICAgaG9yaXo6IG1lbnVQYWRkaW5nLmhvcml6ICtcclxuICAgICAgICAgICAgICAgICAgdG9JbnRlZ2VyKG1lbnVTdHlsZS5tYXJnaW5MZWZ0KSArXHJcbiAgICAgICAgICAgICAgICAgIHRvSW50ZWdlcihtZW51U3R5bGUubWFyZ2luUmlnaHQpICsgMlxyXG4gICAgICAgICAgfSxcclxuICAgICAgICAgIHNjcm9sbEJhcldpZHRoO1xyXG5cclxuICAgICAgbWVudUlubmVyLnN0eWxlLm92ZXJmbG93WSA9ICdzY3JvbGwnO1xyXG5cclxuICAgICAgc2Nyb2xsQmFyV2lkdGggPSBtZW51Lm9mZnNldFdpZHRoIC0gbWVudVdpZHRoO1xyXG5cclxuICAgICAgZG9jdW1lbnQuYm9keS5yZW1vdmVDaGlsZChuZXdFbGVtZW50KTtcclxuXHJcbiAgICAgIHRoaXMuc2l6ZUluZm8ubGlIZWlnaHQgPSBsaUhlaWdodDtcclxuICAgICAgdGhpcy5zaXplSW5mby5kcm9wZG93bkhlYWRlckhlaWdodCA9IGRyb3Bkb3duSGVhZGVySGVpZ2h0O1xyXG4gICAgICB0aGlzLnNpemVJbmZvLmhlYWRlckhlaWdodCA9IGhlYWRlckhlaWdodDtcclxuICAgICAgdGhpcy5zaXplSW5mby5zZWFyY2hIZWlnaHQgPSBzZWFyY2hIZWlnaHQ7XHJcbiAgICAgIHRoaXMuc2l6ZUluZm8uYWN0aW9uc0hlaWdodCA9IGFjdGlvbnNIZWlnaHQ7XHJcbiAgICAgIHRoaXMuc2l6ZUluZm8uZG9uZUJ1dHRvbkhlaWdodCA9IGRvbmVCdXR0b25IZWlnaHQ7XHJcbiAgICAgIHRoaXMuc2l6ZUluZm8uZGl2aWRlckhlaWdodCA9IGRpdmlkZXJIZWlnaHQ7XHJcbiAgICAgIHRoaXMuc2l6ZUluZm8ubWVudVBhZGRpbmcgPSBtZW51UGFkZGluZztcclxuICAgICAgdGhpcy5zaXplSW5mby5tZW51RXh0cmFzID0gbWVudUV4dHJhcztcclxuICAgICAgdGhpcy5zaXplSW5mby5tZW51V2lkdGggPSBtZW51V2lkdGg7XHJcbiAgICAgIHRoaXMuc2l6ZUluZm8ubWVudUlubmVySW5uZXJXaWR0aCA9IG1lbnVXaWR0aCAtIG1lbnVQYWRkaW5nLmhvcml6O1xyXG4gICAgICB0aGlzLnNpemVJbmZvLnRvdGFsTWVudVdpZHRoID0gdGhpcy5zaXplSW5mby5tZW51V2lkdGg7XHJcbiAgICAgIHRoaXMuc2l6ZUluZm8uc2Nyb2xsQmFyV2lkdGggPSBzY3JvbGxCYXJXaWR0aDtcclxuICAgICAgdGhpcy5zaXplSW5mby5zZWxlY3RIZWlnaHQgPSB0aGlzLiRuZXdFbGVtZW50WzBdLm9mZnNldEhlaWdodDtcclxuXHJcbiAgICAgIHRoaXMuc2V0UG9zaXRpb25EYXRhKCk7XHJcbiAgICB9LFxyXG5cclxuICAgIGdldFNlbGVjdFBvc2l0aW9uOiBmdW5jdGlvbiAoKSB7XHJcbiAgICAgIHZhciB0aGF0ID0gdGhpcyxcclxuICAgICAgICAgICR3aW5kb3cgPSAkKHdpbmRvdyksXHJcbiAgICAgICAgICBwb3MgPSB0aGF0LiRuZXdFbGVtZW50Lm9mZnNldCgpLFxyXG4gICAgICAgICAgJGNvbnRhaW5lciA9ICQodGhhdC5vcHRpb25zLmNvbnRhaW5lciksXHJcbiAgICAgICAgICBjb250YWluZXJQb3M7XHJcblxyXG4gICAgICBpZiAodGhhdC5vcHRpb25zLmNvbnRhaW5lciAmJiAkY29udGFpbmVyLmxlbmd0aCAmJiAhJGNvbnRhaW5lci5pcygnYm9keScpKSB7XHJcbiAgICAgICAgY29udGFpbmVyUG9zID0gJGNvbnRhaW5lci5vZmZzZXQoKTtcclxuICAgICAgICBjb250YWluZXJQb3MudG9wICs9IHBhcnNlSW50KCRjb250YWluZXIuY3NzKCdib3JkZXJUb3BXaWR0aCcpKTtcclxuICAgICAgICBjb250YWluZXJQb3MubGVmdCArPSBwYXJzZUludCgkY29udGFpbmVyLmNzcygnYm9yZGVyTGVmdFdpZHRoJykpO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIGNvbnRhaW5lclBvcyA9IHsgdG9wOiAwLCBsZWZ0OiAwIH07XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHZhciB3aW5QYWQgPSB0aGF0Lm9wdGlvbnMud2luZG93UGFkZGluZztcclxuXHJcbiAgICAgIHRoaXMuc2l6ZUluZm8uc2VsZWN0T2Zmc2V0VG9wID0gcG9zLnRvcCAtIGNvbnRhaW5lclBvcy50b3AgLSAkd2luZG93LnNjcm9sbFRvcCgpO1xyXG4gICAgICB0aGlzLnNpemVJbmZvLnNlbGVjdE9mZnNldEJvdCA9ICR3aW5kb3cuaGVpZ2h0KCkgLSB0aGlzLnNpemVJbmZvLnNlbGVjdE9mZnNldFRvcCAtIHRoaXMuc2l6ZUluZm8uc2VsZWN0SGVpZ2h0IC0gY29udGFpbmVyUG9zLnRvcCAtIHdpblBhZFsyXTtcclxuICAgICAgdGhpcy5zaXplSW5mby5zZWxlY3RPZmZzZXRMZWZ0ID0gcG9zLmxlZnQgLSBjb250YWluZXJQb3MubGVmdCAtICR3aW5kb3cuc2Nyb2xsTGVmdCgpO1xyXG4gICAgICB0aGlzLnNpemVJbmZvLnNlbGVjdE9mZnNldFJpZ2h0ID0gJHdpbmRvdy53aWR0aCgpIC0gdGhpcy5zaXplSW5mby5zZWxlY3RPZmZzZXRMZWZ0IC0gdGhpcy5zaXplSW5mby5zZWxlY3RXaWR0aCAtIGNvbnRhaW5lclBvcy5sZWZ0IC0gd2luUGFkWzFdO1xyXG4gICAgICB0aGlzLnNpemVJbmZvLnNlbGVjdE9mZnNldFRvcCAtPSB3aW5QYWRbMF07XHJcbiAgICAgIHRoaXMuc2l6ZUluZm8uc2VsZWN0T2Zmc2V0TGVmdCAtPSB3aW5QYWRbM107XHJcbiAgICB9LFxyXG5cclxuICAgIHNldE1lbnVTaXplOiBmdW5jdGlvbiAoaXNBdXRvKSB7XHJcbiAgICAgIHRoaXMuZ2V0U2VsZWN0UG9zaXRpb24oKTtcclxuXHJcbiAgICAgIHZhciBzZWxlY3RXaWR0aCA9IHRoaXMuc2l6ZUluZm8uc2VsZWN0V2lkdGgsXHJcbiAgICAgICAgICBsaUhlaWdodCA9IHRoaXMuc2l6ZUluZm8ubGlIZWlnaHQsXHJcbiAgICAgICAgICBoZWFkZXJIZWlnaHQgPSB0aGlzLnNpemVJbmZvLmhlYWRlckhlaWdodCxcclxuICAgICAgICAgIHNlYXJjaEhlaWdodCA9IHRoaXMuc2l6ZUluZm8uc2VhcmNoSGVpZ2h0LFxyXG4gICAgICAgICAgYWN0aW9uc0hlaWdodCA9IHRoaXMuc2l6ZUluZm8uYWN0aW9uc0hlaWdodCxcclxuICAgICAgICAgIGRvbmVCdXR0b25IZWlnaHQgPSB0aGlzLnNpemVJbmZvLmRvbmVCdXR0b25IZWlnaHQsXHJcbiAgICAgICAgICBkaXZIZWlnaHQgPSB0aGlzLnNpemVJbmZvLmRpdmlkZXJIZWlnaHQsXHJcbiAgICAgICAgICBtZW51UGFkZGluZyA9IHRoaXMuc2l6ZUluZm8ubWVudVBhZGRpbmcsXHJcbiAgICAgICAgICBtZW51SW5uZXJIZWlnaHQsXHJcbiAgICAgICAgICBtZW51SGVpZ2h0LFxyXG4gICAgICAgICAgZGl2TGVuZ3RoID0gMCxcclxuICAgICAgICAgIG1pbkhlaWdodCxcclxuICAgICAgICAgIF9taW5IZWlnaHQsXHJcbiAgICAgICAgICBtYXhIZWlnaHQsXHJcbiAgICAgICAgICBtZW51SW5uZXJNaW5IZWlnaHQsXHJcbiAgICAgICAgICBlc3RpbWF0ZSxcclxuICAgICAgICAgIGlzRHJvcHVwO1xyXG5cclxuICAgICAgaWYgKHRoaXMub3B0aW9ucy5kcm9wdXBBdXRvKSB7XHJcbiAgICAgICAgLy8gR2V0IHRoZSBlc3RpbWF0ZWQgaGVpZ2h0IG9mIHRoZSBtZW51IHdpdGhvdXQgc2Nyb2xsYmFycy5cclxuICAgICAgICAvLyBUaGlzIGlzIHVzZWZ1bCBmb3Igc21hbGxlciBtZW51cywgd2hlcmUgdGhlcmUgbWlnaHQgYmUgcGxlbnR5IG9mIHJvb21cclxuICAgICAgICAvLyBiZWxvdyB0aGUgYnV0dG9uIHdpdGhvdXQgc2V0dGluZyBkcm9wdXAsIGJ1dCB3ZSBjYW4ndCBrbm93XHJcbiAgICAgICAgLy8gdGhlIGV4YWN0IGhlaWdodCBvZiB0aGUgbWVudSB1bnRpbCBjcmVhdGVWaWV3IGlzIGNhbGxlZCBsYXRlclxyXG4gICAgICAgIGVzdGltYXRlID0gbGlIZWlnaHQgKiB0aGlzLnNlbGVjdHBpY2tlci5jdXJyZW50LmRhdGEubGVuZ3RoICsgbWVudVBhZGRpbmcudmVydDtcclxuXHJcbiAgICAgICAgaXNEcm9wdXAgPSB0aGlzLnNpemVJbmZvLnNlbGVjdE9mZnNldFRvcCAtIHRoaXMuc2l6ZUluZm8uc2VsZWN0T2Zmc2V0Qm90ID4gdGhpcy5zaXplSW5mby5tZW51RXh0cmFzLnZlcnQgJiYgZXN0aW1hdGUgKyB0aGlzLnNpemVJbmZvLm1lbnVFeHRyYXMudmVydCArIDUwID4gdGhpcy5zaXplSW5mby5zZWxlY3RPZmZzZXRCb3Q7XHJcblxyXG4gICAgICAgIC8vIGVuc3VyZSBkcm9wdXAgZG9lc24ndCBjaGFuZ2Ugd2hpbGUgc2VhcmNoaW5nIChzbyBtZW51IGRvZXNuJ3QgYm91bmNlIGJhY2sgYW5kIGZvcnRoKVxyXG4gICAgICAgIGlmICh0aGlzLnNlbGVjdHBpY2tlci5pc1NlYXJjaGluZyA9PT0gdHJ1ZSkge1xyXG4gICAgICAgICAgaXNEcm9wdXAgPSB0aGlzLnNlbGVjdHBpY2tlci5kcm9wdXA7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICB0aGlzLiRuZXdFbGVtZW50LnRvZ2dsZUNsYXNzKGNsYXNzTmFtZXMuRFJPUFVQLCBpc0Ryb3B1cCk7XHJcbiAgICAgICAgdGhpcy5zZWxlY3RwaWNrZXIuZHJvcHVwID0gaXNEcm9wdXA7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmICh0aGlzLm9wdGlvbnMuc2l6ZSA9PT0gJ2F1dG8nKSB7XHJcbiAgICAgICAgX21pbkhlaWdodCA9IHRoaXMuc2VsZWN0cGlja2VyLmN1cnJlbnQuZGF0YS5sZW5ndGggPiAzID8gdGhpcy5zaXplSW5mby5saUhlaWdodCAqIDMgKyB0aGlzLnNpemVJbmZvLm1lbnVFeHRyYXMudmVydCAtIDIgOiAwO1xyXG4gICAgICAgIG1lbnVIZWlnaHQgPSB0aGlzLnNpemVJbmZvLnNlbGVjdE9mZnNldEJvdCAtIHRoaXMuc2l6ZUluZm8ubWVudUV4dHJhcy52ZXJ0O1xyXG4gICAgICAgIG1pbkhlaWdodCA9IF9taW5IZWlnaHQgKyBoZWFkZXJIZWlnaHQgKyBzZWFyY2hIZWlnaHQgKyBhY3Rpb25zSGVpZ2h0ICsgZG9uZUJ1dHRvbkhlaWdodDtcclxuICAgICAgICBtZW51SW5uZXJNaW5IZWlnaHQgPSBNYXRoLm1heChfbWluSGVpZ2h0IC0gbWVudVBhZGRpbmcudmVydCwgMCk7XHJcblxyXG4gICAgICAgIGlmICh0aGlzLiRuZXdFbGVtZW50Lmhhc0NsYXNzKGNsYXNzTmFtZXMuRFJPUFVQKSkge1xyXG4gICAgICAgICAgbWVudUhlaWdodCA9IHRoaXMuc2l6ZUluZm8uc2VsZWN0T2Zmc2V0VG9wIC0gdGhpcy5zaXplSW5mby5tZW51RXh0cmFzLnZlcnQ7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBtYXhIZWlnaHQgPSBtZW51SGVpZ2h0O1xyXG4gICAgICAgIG1lbnVJbm5lckhlaWdodCA9IG1lbnVIZWlnaHQgLSBoZWFkZXJIZWlnaHQgLSBzZWFyY2hIZWlnaHQgLSBhY3Rpb25zSGVpZ2h0IC0gZG9uZUJ1dHRvbkhlaWdodCAtIG1lbnVQYWRkaW5nLnZlcnQ7XHJcbiAgICAgIH0gZWxzZSBpZiAodGhpcy5vcHRpb25zLnNpemUgJiYgdGhpcy5vcHRpb25zLnNpemUgIT0gJ2F1dG8nICYmIHRoaXMuc2VsZWN0cGlja2VyLmN1cnJlbnQuZWxlbWVudHMubGVuZ3RoID4gdGhpcy5vcHRpb25zLnNpemUpIHtcclxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMub3B0aW9ucy5zaXplOyBpKyspIHtcclxuICAgICAgICAgIGlmICh0aGlzLnNlbGVjdHBpY2tlci5jdXJyZW50LmRhdGFbaV0udHlwZSA9PT0gJ2RpdmlkZXInKSBkaXZMZW5ndGgrKztcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIG1lbnVIZWlnaHQgPSBsaUhlaWdodCAqIHRoaXMub3B0aW9ucy5zaXplICsgZGl2TGVuZ3RoICogZGl2SGVpZ2h0ICsgbWVudVBhZGRpbmcudmVydDtcclxuICAgICAgICBtZW51SW5uZXJIZWlnaHQgPSBtZW51SGVpZ2h0IC0gbWVudVBhZGRpbmcudmVydDtcclxuICAgICAgICBtYXhIZWlnaHQgPSBtZW51SGVpZ2h0ICsgaGVhZGVySGVpZ2h0ICsgc2VhcmNoSGVpZ2h0ICsgYWN0aW9uc0hlaWdodCArIGRvbmVCdXR0b25IZWlnaHQ7XHJcbiAgICAgICAgbWluSGVpZ2h0ID0gbWVudUlubmVyTWluSGVpZ2h0ID0gJyc7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHRoaXMuJG1lbnUuY3NzKHtcclxuICAgICAgICAnbWF4LWhlaWdodCc6IG1heEhlaWdodCArICdweCcsXHJcbiAgICAgICAgJ292ZXJmbG93JzogJ2hpZGRlbicsXHJcbiAgICAgICAgJ21pbi1oZWlnaHQnOiBtaW5IZWlnaHQgKyAncHgnXHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgdGhpcy4kbWVudUlubmVyLmNzcyh7XHJcbiAgICAgICAgJ21heC1oZWlnaHQnOiBtZW51SW5uZXJIZWlnaHQgKyAncHgnLFxyXG4gICAgICAgICdvdmVyZmxvdy15JzogJ2F1dG8nLFxyXG4gICAgICAgICdtaW4taGVpZ2h0JzogbWVudUlubmVyTWluSGVpZ2h0ICsgJ3B4J1xyXG4gICAgICB9KTtcclxuXHJcbiAgICAgIC8vIGVuc3VyZSBtZW51SW5uZXJIZWlnaHQgaXMgYWx3YXlzIGEgcG9zaXRpdmUgbnVtYmVyIHRvIHByZXZlbnQgaXNzdWVzIGNhbGN1bGF0aW5nIGNodW5rU2l6ZSBpbiBjcmVhdGVWaWV3XHJcbiAgICAgIHRoaXMuc2l6ZUluZm8ubWVudUlubmVySGVpZ2h0ID0gTWF0aC5tYXgobWVudUlubmVySGVpZ2h0LCAxKTtcclxuXHJcbiAgICAgIGlmICh0aGlzLnNlbGVjdHBpY2tlci5jdXJyZW50LmRhdGEubGVuZ3RoICYmIHRoaXMuc2VsZWN0cGlja2VyLmN1cnJlbnQuZGF0YVt0aGlzLnNlbGVjdHBpY2tlci5jdXJyZW50LmRhdGEubGVuZ3RoIC0gMV0ucG9zaXRpb24gPiB0aGlzLnNpemVJbmZvLm1lbnVJbm5lckhlaWdodCkge1xyXG4gICAgICAgIHRoaXMuc2l6ZUluZm8uaGFzU2Nyb2xsQmFyID0gdHJ1ZTtcclxuICAgICAgICB0aGlzLnNpemVJbmZvLnRvdGFsTWVudVdpZHRoID0gdGhpcy5zaXplSW5mby5tZW51V2lkdGggKyB0aGlzLnNpemVJbmZvLnNjcm9sbEJhcldpZHRoO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAodGhpcy5vcHRpb25zLmRyb3Bkb3duQWxpZ25SaWdodCA9PT0gJ2F1dG8nKSB7XHJcbiAgICAgICAgdGhpcy4kbWVudS50b2dnbGVDbGFzcyhjbGFzc05hbWVzLk1FTlVSSUdIVCwgdGhpcy5zaXplSW5mby5zZWxlY3RPZmZzZXRMZWZ0ID4gdGhpcy5zaXplSW5mby5zZWxlY3RPZmZzZXRSaWdodCAmJiB0aGlzLnNpemVJbmZvLnNlbGVjdE9mZnNldFJpZ2h0IDwgKHRoaXMuc2l6ZUluZm8udG90YWxNZW51V2lkdGggLSBzZWxlY3RXaWR0aCkpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAodGhpcy5kcm9wZG93biAmJiB0aGlzLmRyb3Bkb3duLl9wb3BwZXIpIHRoaXMuZHJvcGRvd24uX3BvcHBlci51cGRhdGUoKTtcclxuICAgIH0sXHJcblxyXG4gICAgc2V0U2l6ZTogZnVuY3Rpb24gKHJlZnJlc2gpIHtcclxuICAgICAgdGhpcy5saUhlaWdodChyZWZyZXNoKTtcclxuXHJcbiAgICAgIGlmICh0aGlzLm9wdGlvbnMuaGVhZGVyKSB0aGlzLiRtZW51LmNzcygncGFkZGluZy10b3AnLCAwKTtcclxuXHJcbiAgICAgIGlmICh0aGlzLm9wdGlvbnMuc2l6ZSAhPT0gZmFsc2UpIHtcclxuICAgICAgICB2YXIgdGhhdCA9IHRoaXMsXHJcbiAgICAgICAgICAgICR3aW5kb3cgPSAkKHdpbmRvdyk7XHJcblxyXG4gICAgICAgIHRoaXMuc2V0TWVudVNpemUoKTtcclxuXHJcbiAgICAgICAgaWYgKHRoaXMub3B0aW9ucy5saXZlU2VhcmNoKSB7XHJcbiAgICAgICAgICB0aGlzLiRzZWFyY2hib3hcclxuICAgICAgICAgICAgLm9mZignaW5wdXQuc2V0TWVudVNpemUgcHJvcGVydHljaGFuZ2Uuc2V0TWVudVNpemUnKVxyXG4gICAgICAgICAgICAub24oJ2lucHV0LnNldE1lbnVTaXplIHByb3BlcnR5Y2hhbmdlLnNldE1lbnVTaXplJywgZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICAgIHJldHVybiB0aGF0LnNldE1lbnVTaXplKCk7XHJcbiAgICAgICAgICAgIH0pO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgaWYgKHRoaXMub3B0aW9ucy5zaXplID09PSAnYXV0bycpIHtcclxuICAgICAgICAgICR3aW5kb3dcclxuICAgICAgICAgICAgLm9mZigncmVzaXplJyArIEVWRU5UX0tFWSArICcuJyArIHRoaXMuc2VsZWN0SWQgKyAnLnNldE1lbnVTaXplJyArICcgc2Nyb2xsJyArIEVWRU5UX0tFWSArICcuJyArIHRoaXMuc2VsZWN0SWQgKyAnLnNldE1lbnVTaXplJylcclxuICAgICAgICAgICAgLm9uKCdyZXNpemUnICsgRVZFTlRfS0VZICsgJy4nICsgdGhpcy5zZWxlY3RJZCArICcuc2V0TWVudVNpemUnICsgJyBzY3JvbGwnICsgRVZFTlRfS0VZICsgJy4nICsgdGhpcy5zZWxlY3RJZCArICcuc2V0TWVudVNpemUnLCBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgICAgcmV0dXJuIHRoYXQuc2V0TWVudVNpemUoKTtcclxuICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgfSBlbHNlIGlmICh0aGlzLm9wdGlvbnMuc2l6ZSAmJiB0aGlzLm9wdGlvbnMuc2l6ZSAhPSAnYXV0bycgJiYgdGhpcy5zZWxlY3RwaWNrZXIuY3VycmVudC5lbGVtZW50cy5sZW5ndGggPiB0aGlzLm9wdGlvbnMuc2l6ZSkge1xyXG4gICAgICAgICAgJHdpbmRvdy5vZmYoJ3Jlc2l6ZScgKyBFVkVOVF9LRVkgKyAnLicgKyB0aGlzLnNlbGVjdElkICsgJy5zZXRNZW51U2l6ZScgKyAnIHNjcm9sbCcgKyBFVkVOVF9LRVkgKyAnLicgKyB0aGlzLnNlbGVjdElkICsgJy5zZXRNZW51U2l6ZScpO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgdGhpcy5jcmVhdGVWaWV3KGZhbHNlLCB0cnVlLCByZWZyZXNoKTtcclxuICAgIH0sXHJcblxyXG4gICAgc2V0V2lkdGg6IGZ1bmN0aW9uICgpIHtcclxuICAgICAgdmFyIHRoYXQgPSB0aGlzO1xyXG5cclxuICAgICAgaWYgKHRoaXMub3B0aW9ucy53aWR0aCA9PT0gJ2F1dG8nKSB7XHJcbiAgICAgICAgcmVxdWVzdEFuaW1hdGlvbkZyYW1lKGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgIHRoYXQuJG1lbnUuY3NzKCdtaW4td2lkdGgnLCAnMCcpO1xyXG5cclxuICAgICAgICAgIHRoYXQuJGVsZW1lbnQub24oJ2xvYWRlZCcgKyBFVkVOVF9LRVksIGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgdGhhdC5saUhlaWdodCgpO1xyXG4gICAgICAgICAgICB0aGF0LnNldE1lbnVTaXplKCk7XHJcblxyXG4gICAgICAgICAgICAvLyBHZXQgY29ycmVjdCB3aWR0aCBpZiBlbGVtZW50IGlzIGhpZGRlblxyXG4gICAgICAgICAgICB2YXIgJHNlbGVjdENsb25lID0gdGhhdC4kbmV3RWxlbWVudC5jbG9uZSgpLmFwcGVuZFRvKCdib2R5JyksXHJcbiAgICAgICAgICAgICAgICBidG5XaWR0aCA9ICRzZWxlY3RDbG9uZS5jc3MoJ3dpZHRoJywgJ2F1dG8nKS5jaGlsZHJlbignYnV0dG9uJykub3V0ZXJXaWR0aCgpO1xyXG5cclxuICAgICAgICAgICAgJHNlbGVjdENsb25lLnJlbW92ZSgpO1xyXG5cclxuICAgICAgICAgICAgLy8gU2V0IHdpZHRoIHRvIHdoYXRldmVyJ3MgbGFyZ2VyLCBidXR0b24gdGl0bGUgb3IgbG9uZ2VzdCBvcHRpb25cclxuICAgICAgICAgICAgdGhhdC5zaXplSW5mby5zZWxlY3RXaWR0aCA9IE1hdGgubWF4KHRoYXQuc2l6ZUluZm8udG90YWxNZW51V2lkdGgsIGJ0bldpZHRoKTtcclxuICAgICAgICAgICAgdGhhdC4kbmV3RWxlbWVudC5jc3MoJ3dpZHRoJywgdGhhdC5zaXplSW5mby5zZWxlY3RXaWR0aCArICdweCcpO1xyXG4gICAgICAgICAgfSk7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH0gZWxzZSBpZiAodGhpcy5vcHRpb25zLndpZHRoID09PSAnZml0Jykge1xyXG4gICAgICAgIC8vIFJlbW92ZSBpbmxpbmUgbWluLXdpZHRoIHNvIHdpZHRoIGNhbiBiZSBjaGFuZ2VkIGZyb20gJ2F1dG8nXHJcbiAgICAgICAgdGhpcy4kbWVudS5jc3MoJ21pbi13aWR0aCcsICcnKTtcclxuICAgICAgICB0aGlzLiRuZXdFbGVtZW50LmNzcygnd2lkdGgnLCAnJykuYWRkQ2xhc3MoJ2ZpdC13aWR0aCcpO1xyXG4gICAgICB9IGVsc2UgaWYgKHRoaXMub3B0aW9ucy53aWR0aCkge1xyXG4gICAgICAgIC8vIFJlbW92ZSBpbmxpbmUgbWluLXdpZHRoIHNvIHdpZHRoIGNhbiBiZSBjaGFuZ2VkIGZyb20gJ2F1dG8nXHJcbiAgICAgICAgdGhpcy4kbWVudS5jc3MoJ21pbi13aWR0aCcsICcnKTtcclxuICAgICAgICB0aGlzLiRuZXdFbGVtZW50LmNzcygnd2lkdGgnLCB0aGlzLm9wdGlvbnMud2lkdGgpO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIC8vIFJlbW92ZSBpbmxpbmUgbWluLXdpZHRoL3dpZHRoIHNvIHdpZHRoIGNhbiBiZSBjaGFuZ2VkXHJcbiAgICAgICAgdGhpcy4kbWVudS5jc3MoJ21pbi13aWR0aCcsICcnKTtcclxuICAgICAgICB0aGlzLiRuZXdFbGVtZW50LmNzcygnd2lkdGgnLCAnJyk7XHJcbiAgICAgIH1cclxuICAgICAgLy8gUmVtb3ZlIGZpdC13aWR0aCBjbGFzcyBpZiB3aWR0aCBpcyBjaGFuZ2VkIHByb2dyYW1tYXRpY2FsbHlcclxuICAgICAgaWYgKHRoaXMuJG5ld0VsZW1lbnQuaGFzQ2xhc3MoJ2ZpdC13aWR0aCcpICYmIHRoaXMub3B0aW9ucy53aWR0aCAhPT0gJ2ZpdCcpIHtcclxuICAgICAgICB0aGlzLiRuZXdFbGVtZW50WzBdLmNsYXNzTGlzdC5yZW1vdmUoJ2ZpdC13aWR0aCcpO1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG5cclxuICAgIHNlbGVjdFBvc2l0aW9uOiBmdW5jdGlvbiAoKSB7XHJcbiAgICAgIHRoaXMuJGJzQ29udGFpbmVyID0gJCgnPGRpdiBjbGFzcz1cImJzLWNvbnRhaW5lclwiIC8+Jyk7XHJcblxyXG4gICAgICB2YXIgdGhhdCA9IHRoaXMsXHJcbiAgICAgICAgICAkY29udGFpbmVyID0gJCh0aGlzLm9wdGlvbnMuY29udGFpbmVyKSxcclxuICAgICAgICAgIHBvcyxcclxuICAgICAgICAgIGNvbnRhaW5lclBvcyxcclxuICAgICAgICAgIGFjdHVhbEhlaWdodCxcclxuICAgICAgICAgIGdldFBsYWNlbWVudCA9IGZ1bmN0aW9uICgkZWxlbWVudCkge1xyXG4gICAgICAgICAgICB2YXIgY29udGFpbmVyUG9zaXRpb24gPSB7fSxcclxuICAgICAgICAgICAgICAgIC8vIGZhbGwgYmFjayB0byBkcm9wZG93bidzIGRlZmF1bHQgZGlzcGxheSBzZXR0aW5nIGlmIGRpc3BsYXkgaXMgbm90IG1hbnVhbGx5IHNldFxyXG4gICAgICAgICAgICAgICAgZGlzcGxheSA9IHRoYXQub3B0aW9ucy5kaXNwbGF5IHx8IChcclxuICAgICAgICAgICAgICAgICAgLy8gQm9vdHN0cmFwIDMgZG9lc24ndCBoYXZlICQuZm4uZHJvcGRvd24uQ29uc3RydWN0b3IuRGVmYXVsdFxyXG4gICAgICAgICAgICAgICAgICAkLmZuLmRyb3Bkb3duLkNvbnN0cnVjdG9yLkRlZmF1bHQgPyAkLmZuLmRyb3Bkb3duLkNvbnN0cnVjdG9yLkRlZmF1bHQuZGlzcGxheVxyXG4gICAgICAgICAgICAgICAgICA6IGZhbHNlXHJcbiAgICAgICAgICAgICAgICApO1xyXG5cclxuICAgICAgICAgICAgdGhhdC4kYnNDb250YWluZXIuYWRkQ2xhc3MoJGVsZW1lbnQuYXR0cignY2xhc3MnKS5yZXBsYWNlKC9mb3JtLWNvbnRyb2x8Zml0LXdpZHRoL2dpLCAnJykpLnRvZ2dsZUNsYXNzKGNsYXNzTmFtZXMuRFJPUFVQLCAkZWxlbWVudC5oYXNDbGFzcyhjbGFzc05hbWVzLkRST1BVUCkpO1xyXG4gICAgICAgICAgICBwb3MgPSAkZWxlbWVudC5vZmZzZXQoKTtcclxuXHJcbiAgICAgICAgICAgIGlmICghJGNvbnRhaW5lci5pcygnYm9keScpKSB7XHJcbiAgICAgICAgICAgICAgY29udGFpbmVyUG9zID0gJGNvbnRhaW5lci5vZmZzZXQoKTtcclxuICAgICAgICAgICAgICBjb250YWluZXJQb3MudG9wICs9IHBhcnNlSW50KCRjb250YWluZXIuY3NzKCdib3JkZXJUb3BXaWR0aCcpKSAtICRjb250YWluZXIuc2Nyb2xsVG9wKCk7XHJcbiAgICAgICAgICAgICAgY29udGFpbmVyUG9zLmxlZnQgKz0gcGFyc2VJbnQoJGNvbnRhaW5lci5jc3MoJ2JvcmRlckxlZnRXaWR0aCcpKSAtICRjb250YWluZXIuc2Nyb2xsTGVmdCgpO1xyXG4gICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgIGNvbnRhaW5lclBvcyA9IHsgdG9wOiAwLCBsZWZ0OiAwIH07XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIGFjdHVhbEhlaWdodCA9ICRlbGVtZW50Lmhhc0NsYXNzKGNsYXNzTmFtZXMuRFJPUFVQKSA/IDAgOiAkZWxlbWVudFswXS5vZmZzZXRIZWlnaHQ7XHJcblxyXG4gICAgICAgICAgICAvLyBCb290c3RyYXAgNCsgdXNlcyBQb3BwZXIgZm9yIG1lbnUgcG9zaXRpb25pbmdcclxuICAgICAgICAgICAgaWYgKHZlcnNpb24ubWFqb3IgPCA0IHx8IGRpc3BsYXkgPT09ICdzdGF0aWMnKSB7XHJcbiAgICAgICAgICAgICAgY29udGFpbmVyUG9zaXRpb24udG9wID0gcG9zLnRvcCAtIGNvbnRhaW5lclBvcy50b3AgKyBhY3R1YWxIZWlnaHQ7XHJcbiAgICAgICAgICAgICAgY29udGFpbmVyUG9zaXRpb24ubGVmdCA9IHBvcy5sZWZ0IC0gY29udGFpbmVyUG9zLmxlZnQ7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIGNvbnRhaW5lclBvc2l0aW9uLndpZHRoID0gJGVsZW1lbnRbMF0ub2Zmc2V0V2lkdGg7XHJcblxyXG4gICAgICAgICAgICB0aGF0LiRic0NvbnRhaW5lci5jc3MoY29udGFpbmVyUG9zaXRpb24pO1xyXG4gICAgICAgICAgfTtcclxuXHJcbiAgICAgIHRoaXMuJGJ1dHRvbi5vbignY2xpY2suYnMuZHJvcGRvd24uZGF0YS1hcGknLCBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgaWYgKHRoYXQuaXNEaXNhYmxlZCgpKSB7XHJcbiAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBnZXRQbGFjZW1lbnQodGhhdC4kbmV3RWxlbWVudCk7XHJcblxyXG4gICAgICAgIHRoYXQuJGJzQ29udGFpbmVyXHJcbiAgICAgICAgICAuYXBwZW5kVG8odGhhdC5vcHRpb25zLmNvbnRhaW5lcilcclxuICAgICAgICAgIC50b2dnbGVDbGFzcyhjbGFzc05hbWVzLlNIT1csICF0aGF0LiRidXR0b24uaGFzQ2xhc3MoY2xhc3NOYW1lcy5TSE9XKSlcclxuICAgICAgICAgIC5hcHBlbmQodGhhdC4kbWVudSk7XHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgJCh3aW5kb3cpXHJcbiAgICAgICAgLm9mZigncmVzaXplJyArIEVWRU5UX0tFWSArICcuJyArIHRoaXMuc2VsZWN0SWQgKyAnIHNjcm9sbCcgKyBFVkVOVF9LRVkgKyAnLicgKyB0aGlzLnNlbGVjdElkKVxyXG4gICAgICAgIC5vbigncmVzaXplJyArIEVWRU5UX0tFWSArICcuJyArIHRoaXMuc2VsZWN0SWQgKyAnIHNjcm9sbCcgKyBFVkVOVF9LRVkgKyAnLicgKyB0aGlzLnNlbGVjdElkLCBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICB2YXIgaXNBY3RpdmUgPSB0aGF0LiRuZXdFbGVtZW50Lmhhc0NsYXNzKGNsYXNzTmFtZXMuU0hPVyk7XHJcblxyXG4gICAgICAgICAgaWYgKGlzQWN0aXZlKSBnZXRQbGFjZW1lbnQodGhhdC4kbmV3RWxlbWVudCk7XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICB0aGlzLiRlbGVtZW50Lm9uKCdoaWRlJyArIEVWRU5UX0tFWSwgZnVuY3Rpb24gKCkge1xyXG4gICAgICAgIHRoYXQuJG1lbnUuZGF0YSgnaGVpZ2h0JywgdGhhdC4kbWVudS5oZWlnaHQoKSk7XHJcbiAgICAgICAgdGhhdC4kYnNDb250YWluZXIuZGV0YWNoKCk7XHJcbiAgICAgIH0pO1xyXG4gICAgfSxcclxuXHJcbiAgICBjcmVhdGVPcHRpb246IGZ1bmN0aW9uIChkYXRhLCBpbml0KSB7XHJcbiAgICAgIHZhciBvcHRpb25EYXRhID0gIWRhdGEub3B0aW9uID8gZGF0YSA6IGRhdGEub3B0aW9uO1xyXG5cclxuICAgICAgaWYgKG9wdGlvbkRhdGEgJiYgb3B0aW9uRGF0YS5ub2RlVHlwZSAhPT0gMSkge1xyXG4gICAgICAgIHZhciBvcHRpb24gPSAoaW5pdCA/IGVsZW1lbnRUZW1wbGF0ZXMuc2VsZWN0ZWRPcHRpb24gOiBlbGVtZW50VGVtcGxhdGVzLm9wdGlvbikuY2xvbmVOb2RlKHRydWUpO1xyXG4gICAgICAgIGlmIChvcHRpb25EYXRhLnZhbHVlICE9PSB1bmRlZmluZWQpIG9wdGlvbi52YWx1ZSA9IG9wdGlvbkRhdGEudmFsdWU7XHJcbiAgICAgICAgb3B0aW9uLnRleHRDb250ZW50ID0gb3B0aW9uRGF0YS50ZXh0O1xyXG5cclxuICAgICAgICBvcHRpb24uc2VsZWN0ZWQgPSB0cnVlO1xyXG5cclxuICAgICAgICBpZiAob3B0aW9uRGF0YS5saUluZGV4ICE9PSB1bmRlZmluZWQpIHtcclxuICAgICAgICAgIG9wdGlvbi5saUluZGV4ID0gb3B0aW9uRGF0YS5saUluZGV4O1xyXG4gICAgICAgIH0gZWxzZSBpZiAoIWluaXQpIHtcclxuICAgICAgICAgIG9wdGlvbi5saUluZGV4ID0gZGF0YS5pbmRleDtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGRhdGEub3B0aW9uID0gb3B0aW9uO1xyXG5cclxuICAgICAgICB0aGlzLnNlbGVjdHBpY2tlci5tYWluLm9wdGlvblF1ZXVlLmFwcGVuZENoaWxkKG9wdGlvbik7XHJcbiAgICAgIH1cclxuICAgIH0sXHJcblxyXG4gICAgc2V0T3B0aW9uU3RhdHVzOiBmdW5jdGlvbiAoc2VsZWN0ZWRPbmx5KSB7XHJcbiAgICAgIHZhciB0aGF0ID0gdGhpcztcclxuXHJcbiAgICAgIHRoYXQubm9TY3JvbGwgPSBmYWxzZTtcclxuXHJcbiAgICAgIGlmICh0aGF0LnNlbGVjdHBpY2tlci52aWV3LnZpc2libGVFbGVtZW50cyAmJiB0aGF0LnNlbGVjdHBpY2tlci52aWV3LnZpc2libGVFbGVtZW50cy5sZW5ndGgpIHtcclxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoYXQuc2VsZWN0cGlja2VyLnZpZXcudmlzaWJsZUVsZW1lbnRzLmxlbmd0aDsgaSsrKSB7XHJcbiAgICAgICAgICB2YXIgbGlEYXRhID0gdGhhdC5zZWxlY3RwaWNrZXIuY3VycmVudC5kYXRhW2kgKyB0aGF0LnNlbGVjdHBpY2tlci52aWV3LnBvc2l0aW9uMF0sXHJcbiAgICAgICAgICAgICAgb3B0aW9uID0gbGlEYXRhLm9wdGlvbjtcclxuXHJcbiAgICAgICAgICBpZiAob3B0aW9uKSB7XHJcbiAgICAgICAgICAgIGlmIChzZWxlY3RlZE9ubHkgIT09IHRydWUpIHtcclxuICAgICAgICAgICAgICB0aGF0LnNldERpc2FibGVkKGxpRGF0YSk7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIHRoYXQuc2V0U2VsZWN0ZWQobGlEYXRhKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIGFwcGVuZCBvcHRpb25RdWV1ZSAoZG9jdW1lbnRGcmFnbWVudCB3aXRoIG9wdGlvbiBlbGVtZW50cyBmb3Igc2VsZWN0IG9wdGlvbnMpXHJcbiAgICAgICAgaWYgKHRoaXMub3B0aW9ucy5zb3VyY2UuZGF0YSkgdGhpcy4kZWxlbWVudFswXS5hcHBlbmRDaGlsZCh0aGlzLnNlbGVjdHBpY2tlci5tYWluLm9wdGlvblF1ZXVlKTtcclxuICAgICAgfVxyXG4gICAgfSxcclxuXHJcbiAgICAvKipcclxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBpbmRleCAtIHRoZSBpbmRleCBvZiB0aGUgb3B0aW9uIHRoYXQgaXMgYmVpbmcgY2hhbmdlZFxyXG4gICAgICogQHBhcmFtIHtib29sZWFufSBzZWxlY3RlZCAtIHRydWUgaWYgdGhlIG9wdGlvbiBpcyBiZWluZyBzZWxlY3RlZCwgZmFsc2UgaWYgYmVpbmcgZGVzZWxlY3RlZFxyXG4gICAgICovXHJcbiAgICBzZXRTZWxlY3RlZDogZnVuY3Rpb24gKGxpRGF0YSwgc2VsZWN0ZWQpIHtcclxuICAgICAgc2VsZWN0ZWQgPSBzZWxlY3RlZCA9PT0gdW5kZWZpbmVkID8gbGlEYXRhLnNlbGVjdGVkIDogc2VsZWN0ZWQ7XHJcblxyXG4gICAgICB2YXIgaW5kZXggPSBsaURhdGEuaW5kZXgsXHJcbiAgICAgICAgICBsaSA9IGxpRGF0YS5lbGVtZW50LFxyXG4gICAgICAgICAgYWN0aXZlSW5kZXhJc1NldCA9IHRoaXMuYWN0aXZlSW5kZXggIT09IHVuZGVmaW5lZCxcclxuICAgICAgICAgIHRoaXNJc0FjdGl2ZSA9IHRoaXMuYWN0aXZlSW5kZXggPT09IGluZGV4LFxyXG4gICAgICAgICAgcHJldkFjdGl2ZSxcclxuICAgICAgICAgIGEsXHJcbiAgICAgICAgICAvLyBpZiBjdXJyZW50IG9wdGlvbiBpcyBhbHJlYWR5IGFjdGl2ZVxyXG4gICAgICAgICAgLy8gT1JcclxuICAgICAgICAgIC8vIGlmIHRoZSBjdXJyZW50IG9wdGlvbiBpcyBiZWluZyBzZWxlY3RlZCwgaXQncyBOT1QgbXVsdGlwbGUsIGFuZFxyXG4gICAgICAgICAgLy8gYWN0aXZlSW5kZXggaXMgdW5kZWZpbmVkOlxyXG4gICAgICAgICAgLy8gIC0gd2hlbiB0aGUgbWVudSBpcyBmaXJzdCBiZWluZyBvcGVuZWQsIE9SXHJcbiAgICAgICAgICAvLyAgLSBhZnRlciBhIHNlYXJjaCBoYXMgYmVlbiBwZXJmb3JtZWQsIE9SXHJcbiAgICAgICAgICAvLyAgLSB3aGVuIHJldGFpbkFjdGl2ZSBpcyBmYWxzZSB3aGVuIHNlbGVjdGluZyBhIG5ldyBvcHRpb24gKGkuZS4gaW5kZXggb2YgdGhlIG5ld2x5IHNlbGVjdGVkIG9wdGlvbiBpcyBub3QgdGhlIHNhbWUgYXMgdGhlIGN1cnJlbnQgYWN0aXZlSW5kZXgpXHJcbiAgICAgICAgICBrZWVwQWN0aXZlID0gdGhpc0lzQWN0aXZlIHx8IChzZWxlY3RlZCAmJiAhdGhpcy5tdWx0aXBsZSAmJiAhYWN0aXZlSW5kZXhJc1NldCk7XHJcblxyXG4gICAgICBpZiAoIWxpKSByZXR1cm47XHJcblxyXG4gICAgICBpZiAoc2VsZWN0ZWQgIT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgIGxpRGF0YS5zZWxlY3RlZCA9IHNlbGVjdGVkO1xyXG4gICAgICAgIGlmIChsaURhdGEub3B0aW9uKSBsaURhdGEub3B0aW9uLnNlbGVjdGVkID0gc2VsZWN0ZWQ7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmIChzZWxlY3RlZCAmJiB0aGlzLm9wdGlvbnMuc291cmNlLmRhdGEpIHtcclxuICAgICAgICB0aGlzLmNyZWF0ZU9wdGlvbihsaURhdGEsIGZhbHNlKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgYSA9IGxpLmZpcnN0Q2hpbGQ7XHJcblxyXG4gICAgICBpZiAoc2VsZWN0ZWQpIHtcclxuICAgICAgICB0aGlzLnNlbGVjdGVkSW5kZXggPSBpbmRleDtcclxuICAgICAgfVxyXG5cclxuICAgICAgbGkuY2xhc3NMaXN0LnRvZ2dsZSgnc2VsZWN0ZWQnLCBzZWxlY3RlZCk7XHJcblxyXG4gICAgICBpZiAoa2VlcEFjdGl2ZSkge1xyXG4gICAgICAgIHRoaXMuZm9jdXNJdGVtKGxpLCBsaURhdGEpO1xyXG4gICAgICAgIHRoaXMuc2VsZWN0cGlja2VyLnZpZXcuY3VycmVudEFjdGl2ZSA9IGxpO1xyXG4gICAgICAgIHRoaXMuYWN0aXZlSW5kZXggPSBpbmRleDtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICB0aGlzLmRlZm9jdXNJdGVtKGxpKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKGEpIHtcclxuICAgICAgICBhLmNsYXNzTGlzdC50b2dnbGUoJ3NlbGVjdGVkJywgc2VsZWN0ZWQpO1xyXG5cclxuICAgICAgICBpZiAoc2VsZWN0ZWQpIHtcclxuICAgICAgICAgIGEuc2V0QXR0cmlidXRlKCdhcmlhLXNlbGVjdGVkJywgdHJ1ZSk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIGlmICh0aGlzLm11bHRpcGxlKSB7XHJcbiAgICAgICAgICAgIGEuc2V0QXR0cmlidXRlKCdhcmlhLXNlbGVjdGVkJywgZmFsc2UpO1xyXG4gICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgYS5yZW1vdmVBdHRyaWJ1dGUoJ2FyaWEtc2VsZWN0ZWQnKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmICgha2VlcEFjdGl2ZSAmJiAhYWN0aXZlSW5kZXhJc1NldCAmJiBzZWxlY3RlZCAmJiB0aGlzLnByZXZBY3RpdmVJbmRleCAhPT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgICAgcHJldkFjdGl2ZSA9IHRoaXMuc2VsZWN0cGlja2VyLm1haW4uZWxlbWVudHNbdGhpcy5wcmV2QWN0aXZlSW5kZXhdO1xyXG5cclxuICAgICAgICB0aGlzLmRlZm9jdXNJdGVtKHByZXZBY3RpdmUpO1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG5cclxuICAgIC8qKlxyXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IGluZGV4IC0gdGhlIGluZGV4IG9mIHRoZSBvcHRpb24gdGhhdCBpcyBiZWluZyBkaXNhYmxlZFxyXG4gICAgICogQHBhcmFtIHtib29sZWFufSBkaXNhYmxlZCAtIHRydWUgaWYgdGhlIG9wdGlvbiBpcyBiZWluZyBkaXNhYmxlZCwgZmFsc2UgaWYgYmVpbmcgZW5hYmxlZFxyXG4gICAgICovXHJcbiAgICBzZXREaXNhYmxlZDogZnVuY3Rpb24gKGxpRGF0YSkge1xyXG4gICAgICB2YXIgZGlzYWJsZWQgPSBsaURhdGEuZGlzYWJsZWQsXHJcbiAgICAgICAgICBsaSA9IGxpRGF0YS5lbGVtZW50LFxyXG4gICAgICAgICAgYTtcclxuXHJcbiAgICAgIGlmICghbGkpIHJldHVybjtcclxuXHJcbiAgICAgIGEgPSBsaS5maXJzdENoaWxkO1xyXG5cclxuICAgICAgbGkuY2xhc3NMaXN0LnRvZ2dsZShjbGFzc05hbWVzLkRJU0FCTEVELCBkaXNhYmxlZCk7XHJcblxyXG4gICAgICBpZiAoYSkge1xyXG4gICAgICAgIGlmICh2ZXJzaW9uLm1ham9yID49ICc0JykgYS5jbGFzc0xpc3QudG9nZ2xlKGNsYXNzTmFtZXMuRElTQUJMRUQsIGRpc2FibGVkKTtcclxuXHJcbiAgICAgICAgaWYgKGRpc2FibGVkKSB7XHJcbiAgICAgICAgICBhLnNldEF0dHJpYnV0ZSgnYXJpYS1kaXNhYmxlZCcsIGRpc2FibGVkKTtcclxuICAgICAgICAgIGEuc2V0QXR0cmlidXRlKCd0YWJpbmRleCcsIC0xKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgYS5yZW1vdmVBdHRyaWJ1dGUoJ2FyaWEtZGlzYWJsZWQnKTtcclxuICAgICAgICAgIGEuc2V0QXR0cmlidXRlKCd0YWJpbmRleCcsIDApO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfSxcclxuXHJcbiAgICBpc0Rpc2FibGVkOiBmdW5jdGlvbiAoKSB7XHJcbiAgICAgIHJldHVybiB0aGlzLiRlbGVtZW50WzBdLmRpc2FibGVkO1xyXG4gICAgfSxcclxuXHJcbiAgICBjaGVja0Rpc2FibGVkOiBmdW5jdGlvbiAoKSB7XHJcbiAgICAgIGlmICh0aGlzLmlzRGlzYWJsZWQoKSkge1xyXG4gICAgICAgIHRoaXMuJG5ld0VsZW1lbnRbMF0uY2xhc3NMaXN0LmFkZChjbGFzc05hbWVzLkRJU0FCTEVEKTtcclxuICAgICAgICB0aGlzLiRidXR0b24uYWRkQ2xhc3MoY2xhc3NOYW1lcy5ESVNBQkxFRCkuYXR0cignYXJpYS1kaXNhYmxlZCcsIHRydWUpO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIGlmICh0aGlzLiRidXR0b25bMF0uY2xhc3NMaXN0LmNvbnRhaW5zKGNsYXNzTmFtZXMuRElTQUJMRUQpKSB7XHJcbiAgICAgICAgICB0aGlzLiRuZXdFbGVtZW50WzBdLmNsYXNzTGlzdC5yZW1vdmUoY2xhc3NOYW1lcy5ESVNBQkxFRCk7XHJcbiAgICAgICAgICB0aGlzLiRidXR0b24ucmVtb3ZlQ2xhc3MoY2xhc3NOYW1lcy5ESVNBQkxFRCkuYXR0cignYXJpYS1kaXNhYmxlZCcsIGZhbHNlKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH0sXHJcblxyXG4gICAgY2xpY2tMaXN0ZW5lcjogZnVuY3Rpb24gKCkge1xyXG4gICAgICB2YXIgdGhhdCA9IHRoaXMsXHJcbiAgICAgICAgICAkZG9jdW1lbnQgPSAkKGRvY3VtZW50KTtcclxuXHJcbiAgICAgICRkb2N1bWVudC5kYXRhKCdzcGFjZVNlbGVjdCcsIGZhbHNlKTtcclxuXHJcbiAgICAgIHRoaXMuJGJ1dHRvbi5vbigna2V5dXAnLCBmdW5jdGlvbiAoZSkge1xyXG4gICAgICAgIGlmICgvKDMyKS8udGVzdChlLmtleUNvZGUudG9TdHJpbmcoMTApKSAmJiAkZG9jdW1lbnQuZGF0YSgnc3BhY2VTZWxlY3QnKSkge1xyXG4gICAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xyXG4gICAgICAgICAgJGRvY3VtZW50LmRhdGEoJ3NwYWNlU2VsZWN0JywgZmFsc2UpO1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcblxyXG4gICAgICB0aGlzLiRuZXdFbGVtZW50Lm9uKCdzaG93LmJzLmRyb3Bkb3duJywgZnVuY3Rpb24gKCkge1xyXG4gICAgICAgIGlmICghdGhhdC5kcm9wZG93biAmJiB2ZXJzaW9uLm1ham9yID09PSAnNCcpIHtcclxuICAgICAgICAgIHRoYXQuZHJvcGRvd24gPSB0aGF0LiRidXR0b24uZGF0YSgnYnMuZHJvcGRvd24nKTtcclxuICAgICAgICAgIHRoYXQuZHJvcGRvd24uX21lbnUgPSB0aGF0LiRtZW51WzBdO1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcblxyXG4gICAgICBmdW5jdGlvbiBjbGVhclNlbGVjdGlvbiAoZSkge1xyXG4gICAgICAgIGlmICh0aGF0Lm11bHRpcGxlKSB7XHJcbiAgICAgICAgICB0aGF0LmRlc2VsZWN0QWxsKCk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIHZhciBlbGVtZW50ID0gdGhhdC4kZWxlbWVudFswXSxcclxuICAgICAgICAgICAgICBwcmV2VmFsdWUgPSBlbGVtZW50LnZhbHVlLFxyXG4gICAgICAgICAgICAgIHByZXZJbmRleCA9IGVsZW1lbnQuc2VsZWN0ZWRJbmRleCxcclxuICAgICAgICAgICAgICBwcmV2T3B0aW9uID0gZWxlbWVudC5vcHRpb25zW3ByZXZJbmRleF0sXHJcbiAgICAgICAgICAgICAgcHJldkRhdGEgPSBwcmV2T3B0aW9uID8gdGhhdC5zZWxlY3RwaWNrZXIubWFpbi5kYXRhW3ByZXZPcHRpb24ubGlJbmRleF0gOiBmYWxzZTtcclxuXHJcbiAgICAgICAgICBpZiAocHJldkRhdGEpIHtcclxuICAgICAgICAgICAgdGhhdC5zZXRTZWxlY3RlZChwcmV2RGF0YSwgZmFsc2UpO1xyXG4gICAgICAgICAgfVxyXG5cclxuICAgICAgICAgIGVsZW1lbnQuc2VsZWN0ZWRJbmRleCA9IDA7XHJcblxyXG4gICAgICAgICAgY2hhbmdlZEFyZ3VtZW50cyA9IFtwcmV2SW5kZXgsIGZhbHNlLCBwcmV2VmFsdWVdO1xyXG4gICAgICAgICAgdGhhdC4kZWxlbWVudC50cmlnZ2VyTmF0aXZlKCdjaGFuZ2UnKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIHJlbW92ZSBzZWxlY3RlZCBzdHlsaW5nIGlmIG1lbnUgaXMgb3BlblxyXG4gICAgICAgIGlmICh0aGF0LiRuZXdFbGVtZW50Lmhhc0NsYXNzKGNsYXNzTmFtZXMuU0hPVykpIHtcclxuICAgICAgICAgIGlmICh0aGF0Lm9wdGlvbnMubGl2ZVNlYXJjaCkge1xyXG4gICAgICAgICAgICB0aGF0LiRzZWFyY2hib3gudHJpZ2dlcignZm9jdXMnKTtcclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICB0aGF0LmNyZWF0ZVZpZXcoZmFsc2UpO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgdGhpcy4kYnV0dG9uLm9uKCdjbGljay5icy5kcm9wZG93bi5kYXRhLWFwaScsIGZ1bmN0aW9uIChlKSB7XHJcbiAgICAgICAgaWYgKHRoYXQub3B0aW9ucy5hbGxvd0NsZWFyKSB7XHJcbiAgICAgICAgICB2YXIgdGFyZ2V0ID0gZS50YXJnZXQsXHJcbiAgICAgICAgICAgICAgY2xlYXJCdXR0b24gPSB0aGF0LiRjbGVhckJ1dHRvblswXTtcclxuXHJcbiAgICAgICAgICAvLyBJRSBkb2Vzbid0IHN1cHBvcnQgZXZlbnQgbGlzdGVuZXJzIG9uIGNoaWxkIGVsZW1lbnRzIG9mIGJ1dHRvbnNcclxuICAgICAgICAgIGlmICgvTVNJRXxUcmlkZW50Ly50ZXN0KHdpbmRvdy5uYXZpZ2F0b3IudXNlckFnZW50KSkge1xyXG4gICAgICAgICAgICB0YXJnZXQgPSBkb2N1bWVudC5lbGVtZW50RnJvbVBvaW50KGUuY2xpZW50WCwgZS5jbGllbnRZKTtcclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICBpZiAodGFyZ2V0ID09PSBjbGVhckJ1dHRvbiB8fCB0YXJnZXQucGFyZW50RWxlbWVudCA9PT0gY2xlYXJCdXR0b24pIHtcclxuICAgICAgICAgICAgZS5zdG9wSW1tZWRpYXRlUHJvcGFnYXRpb24oKTtcclxuICAgICAgICAgICAgY2xlYXJTZWxlY3Rpb24oZSk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBpZiAoIXRoYXQuJG5ld0VsZW1lbnQuaGFzQ2xhc3MoY2xhc3NOYW1lcy5TSE9XKSkge1xyXG4gICAgICAgICAgdGhhdC5zZXRTaXplKCk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9KTtcclxuXHJcbiAgICAgIGZ1bmN0aW9uIHNldEZvY3VzICgpIHtcclxuICAgICAgICBpZiAodGhhdC5vcHRpb25zLmxpdmVTZWFyY2gpIHtcclxuICAgICAgICAgIHRoYXQuJHNlYXJjaGJveC50cmlnZ2VyKCdmb2N1cycpO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICB0aGF0LiRtZW51SW5uZXIudHJpZ2dlcignZm9jdXMnKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGZ1bmN0aW9uIGNoZWNrUG9wcGVyRXhpc3RzICgpIHtcclxuICAgICAgICBpZiAodGhhdC5kcm9wZG93biAmJiB0aGF0LmRyb3Bkb3duLl9wb3BwZXIgJiYgdGhhdC5kcm9wZG93bi5fcG9wcGVyLnN0YXRlKSB7XHJcbiAgICAgICAgICBzZXRGb2N1cygpO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICByZXF1ZXN0QW5pbWF0aW9uRnJhbWUoY2hlY2tQb3BwZXJFeGlzdHMpO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgdGhpcy4kZWxlbWVudC5vbignc2hvd24nICsgRVZFTlRfS0VZLCBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgaWYgKHRoYXQuJG1lbnVJbm5lclswXS5zY3JvbGxUb3AgIT09IHRoYXQuc2VsZWN0cGlja2VyLnZpZXcuc2Nyb2xsVG9wKSB7XHJcbiAgICAgICAgICB0aGF0LiRtZW51SW5uZXJbMF0uc2Nyb2xsVG9wID0gdGhhdC5zZWxlY3RwaWNrZXIudmlldy5zY3JvbGxUb3A7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBpZiAodmVyc2lvbi5tYWpvciA+IDMpIHtcclxuICAgICAgICAgIHJlcXVlc3RBbmltYXRpb25GcmFtZShjaGVja1BvcHBlckV4aXN0cyk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIHNldEZvY3VzKCk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9KTtcclxuXHJcbiAgICAgIC8vIGVuc3VyZSBwb3NpbnNldCBhbmQgc2V0c2l6ZSBhcmUgY29ycmVjdCBiZWZvcmUgc2VsZWN0aW5nIGFuIG9wdGlvbiB2aWEgYSBjbGlja1xyXG4gICAgICB0aGlzLiRtZW51SW5uZXIub24oJ21vdXNlZW50ZXInLCAnbGkgYScsIGZ1bmN0aW9uIChlKSB7XHJcbiAgICAgICAgdmFyIGhvdmVyTGkgPSB0aGlzLnBhcmVudEVsZW1lbnQsXHJcbiAgICAgICAgICAgIHBvc2l0aW9uMCA9IHRoYXQuaXNWaXJ0dWFsKCkgPyB0aGF0LnNlbGVjdHBpY2tlci52aWV3LnBvc2l0aW9uMCA6IDAsXHJcbiAgICAgICAgICAgIGluZGV4ID0gQXJyYXkucHJvdG90eXBlLmluZGV4T2YuY2FsbChob3ZlckxpLnBhcmVudEVsZW1lbnQuY2hpbGRyZW4sIGhvdmVyTGkpLFxyXG4gICAgICAgICAgICBob3ZlckRhdGEgPSB0aGF0LnNlbGVjdHBpY2tlci5jdXJyZW50LmRhdGFbaW5kZXggKyBwb3NpdGlvbjBdO1xyXG5cclxuICAgICAgICB0aGF0LmZvY3VzSXRlbShob3ZlckxpLCBob3ZlckRhdGEsIHRydWUpO1xyXG4gICAgICB9KTtcclxuXHJcbiAgICAgIHRoaXMuJG1lbnVJbm5lci5vbignY2xpY2snLCAnbGkgYScsIGZ1bmN0aW9uIChlLCByZXRhaW5BY3RpdmUpIHtcclxuICAgICAgICB2YXIgJHRoaXMgPSAkKHRoaXMpLFxyXG4gICAgICAgICAgICBlbGVtZW50ID0gdGhhdC4kZWxlbWVudFswXSxcclxuICAgICAgICAgICAgcG9zaXRpb24wID0gdGhhdC5pc1ZpcnR1YWwoKSA/IHRoYXQuc2VsZWN0cGlja2VyLnZpZXcucG9zaXRpb24wIDogMCxcclxuICAgICAgICAgICAgY2xpY2tlZERhdGEgPSB0aGF0LnNlbGVjdHBpY2tlci5jdXJyZW50LmRhdGFbJHRoaXMucGFyZW50KCkuaW5kZXgoKSArIHBvc2l0aW9uMF0sXHJcbiAgICAgICAgICAgIGNsaWNrZWRJbmRleCA9IGNsaWNrZWREYXRhLmluZGV4LFxyXG4gICAgICAgICAgICBwcmV2VmFsdWUgPSBnZXRTZWxlY3RWYWx1ZXMuY2FsbCh0aGF0KSxcclxuICAgICAgICAgICAgcHJldkluZGV4ID0gZWxlbWVudC5zZWxlY3RlZEluZGV4LFxyXG4gICAgICAgICAgICBwcmV2T3B0aW9uID0gZWxlbWVudC5vcHRpb25zW3ByZXZJbmRleF0sXHJcbiAgICAgICAgICAgIHByZXZEYXRhID0gcHJldk9wdGlvbiA/IHRoYXQuc2VsZWN0cGlja2VyLm1haW4uZGF0YVtwcmV2T3B0aW9uLmxpSW5kZXhdIDogZmFsc2UsXHJcbiAgICAgICAgICAgIHRyaWdnZXJDaGFuZ2UgPSB0cnVlO1xyXG5cclxuICAgICAgICAvLyBEb24ndCBjbG9zZSBvbiBtdWx0aSBjaG9pY2UgbWVudVxyXG4gICAgICAgIGlmICh0aGF0Lm11bHRpcGxlICYmIHRoYXQub3B0aW9ucy5tYXhPcHRpb25zICE9PSAxKSB7XHJcbiAgICAgICAgICBlLnN0b3BQcm9wYWdhdGlvbigpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xyXG5cclxuICAgICAgICAvLyBEb24ndCBydW4gaWYgdGhlIHNlbGVjdCBpcyBkaXNhYmxlZFxyXG4gICAgICAgIGlmICghdGhhdC5pc0Rpc2FibGVkKCkgJiYgISR0aGlzLnBhcmVudCgpLmhhc0NsYXNzKGNsYXNzTmFtZXMuRElTQUJMRUQpKSB7XHJcbiAgICAgICAgICB2YXIgb3B0aW9uID0gY2xpY2tlZERhdGEub3B0aW9uLFxyXG4gICAgICAgICAgICAgICRvcHRpb24gPSAkKG9wdGlvbiksXHJcbiAgICAgICAgICAgICAgc3RhdGUgPSBvcHRpb24uc2VsZWN0ZWQsXHJcbiAgICAgICAgICAgICAgJG9wdGdyb3VwID0gJG9wdGlvbi5wYXJlbnQoJ29wdGdyb3VwJyksXHJcbiAgICAgICAgICAgICAgJG9wdGdyb3VwT3B0aW9ucyA9ICRvcHRncm91cC5maW5kKCdvcHRpb24nKSxcclxuICAgICAgICAgICAgICBtYXhPcHRpb25zID0gdGhhdC5vcHRpb25zLm1heE9wdGlvbnMsXHJcbiAgICAgICAgICAgICAgbWF4T3B0aW9uc0dycCA9ICRvcHRncm91cC5kYXRhKCdtYXhPcHRpb25zJykgfHwgZmFsc2U7XHJcblxyXG4gICAgICAgICAgaWYgKGNsaWNrZWRJbmRleCA9PT0gdGhhdC5hY3RpdmVJbmRleCkgcmV0YWluQWN0aXZlID0gdHJ1ZTtcclxuXHJcbiAgICAgICAgICBpZiAoIXJldGFpbkFjdGl2ZSkge1xyXG4gICAgICAgICAgICB0aGF0LnByZXZBY3RpdmVJbmRleCA9IHRoYXQuYWN0aXZlSW5kZXg7XHJcbiAgICAgICAgICAgIHRoYXQuYWN0aXZlSW5kZXggPSB1bmRlZmluZWQ7XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgaWYgKCF0aGF0Lm11bHRpcGxlKSB7IC8vIERlc2VsZWN0IHByZXZpb3VzIG9wdGlvbiBpZiBub3QgbXVsdGkgc2VsZWN0XHJcbiAgICAgICAgICAgIGlmIChwcmV2RGF0YSkgdGhhdC5zZXRTZWxlY3RlZChwcmV2RGF0YSwgZmFsc2UpO1xyXG4gICAgICAgICAgICB0aGF0LnNldFNlbGVjdGVkKGNsaWNrZWREYXRhLCB0cnVlKTtcclxuICAgICAgICAgIH0gZWxzZSB7IC8vIFRvZ2dsZSB0aGUgY2xpY2tlZCBvcHRpb24gaWYgbXVsdGkgc2VsZWN0LlxyXG4gICAgICAgICAgICB0aGF0LnNldFNlbGVjdGVkKGNsaWNrZWREYXRhLCAhc3RhdGUpO1xyXG4gICAgICAgICAgICB0aGF0LmZvY3VzZWRQYXJlbnQuZm9jdXMoKTtcclxuXHJcbiAgICAgICAgICAgIGlmIChtYXhPcHRpb25zICE9PSBmYWxzZSB8fCBtYXhPcHRpb25zR3JwICE9PSBmYWxzZSkge1xyXG4gICAgICAgICAgICAgIHZhciBtYXhSZWFjaGVkID0gbWF4T3B0aW9ucyA8IGdldFNlbGVjdGVkT3B0aW9ucy5jYWxsKHRoYXQpLmxlbmd0aCxcclxuICAgICAgICAgICAgICAgICAgbWF4UmVhY2hlZEdycCA9IG1heE9wdGlvbnNHcnAgPCAkb3B0Z3JvdXAuZmluZCgnb3B0aW9uOnNlbGVjdGVkJykubGVuZ3RoO1xyXG5cclxuICAgICAgICAgICAgICBpZiAoKG1heE9wdGlvbnMgJiYgbWF4UmVhY2hlZCkgfHwgKG1heE9wdGlvbnNHcnAgJiYgbWF4UmVhY2hlZEdycCkpIHtcclxuICAgICAgICAgICAgICAgIGlmIChtYXhPcHRpb25zICYmIG1heE9wdGlvbnMgPT0gMSkge1xyXG4gICAgICAgICAgICAgICAgICBlbGVtZW50LnNlbGVjdGVkSW5kZXggPSAtMTtcclxuICAgICAgICAgICAgICAgICAgb3B0aW9uLnNlbGVjdGVkID0gdHJ1ZTtcclxuICAgICAgICAgICAgICAgICAgdGhhdC5zZXRPcHRpb25TdGF0dXModHJ1ZSk7XHJcbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKG1heE9wdGlvbnNHcnAgJiYgbWF4T3B0aW9uc0dycCA9PSAxKSB7XHJcbiAgICAgICAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgJG9wdGdyb3VwT3B0aW9ucy5sZW5ndGg7IGkrKykge1xyXG4gICAgICAgICAgICAgICAgICAgIHZhciBfb3B0aW9uID0gJG9wdGdyb3VwT3B0aW9uc1tpXTtcclxuICAgICAgICAgICAgICAgICAgICBfb3B0aW9uLnNlbGVjdGVkID0gZmFsc2U7XHJcbiAgICAgICAgICAgICAgICAgICAgdGhhdC5zZXRTZWxlY3RlZChfb3B0aW9uLmxpSW5kZXgsIGZhbHNlKTtcclxuICAgICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgICAgb3B0aW9uLnNlbGVjdGVkID0gdHJ1ZTtcclxuICAgICAgICAgICAgICAgICAgdGhhdC5zZXRTZWxlY3RlZChjbGlja2VkSW5kZXgsIHRydWUpO1xyXG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgICAgdmFyIG1heE9wdGlvbnNUZXh0ID0gdHlwZW9mIHRoYXQub3B0aW9ucy5tYXhPcHRpb25zVGV4dCA9PT0gJ3N0cmluZycgPyBbdGhhdC5vcHRpb25zLm1heE9wdGlvbnNUZXh0LCB0aGF0Lm9wdGlvbnMubWF4T3B0aW9uc1RleHRdIDogdGhhdC5vcHRpb25zLm1heE9wdGlvbnNUZXh0LFxyXG4gICAgICAgICAgICAgICAgICAgICAgbWF4T3B0aW9uc0FyciA9IHR5cGVvZiBtYXhPcHRpb25zVGV4dCA9PT0gJ2Z1bmN0aW9uJyA/IG1heE9wdGlvbnNUZXh0KG1heE9wdGlvbnMsIG1heE9wdGlvbnNHcnApIDogbWF4T3B0aW9uc1RleHQsXHJcbiAgICAgICAgICAgICAgICAgICAgICBtYXhUeHQgPSBtYXhPcHRpb25zQXJyWzBdLnJlcGxhY2UoJ3tufScsIG1heE9wdGlvbnMpLFxyXG4gICAgICAgICAgICAgICAgICAgICAgbWF4VHh0R3JwID0gbWF4T3B0aW9uc0FyclsxXS5yZXBsYWNlKCd7bn0nLCBtYXhPcHRpb25zR3JwKSxcclxuICAgICAgICAgICAgICAgICAgICAgICRub3RpZnkgPSAkKCc8ZGl2IGNsYXNzPVwibm90aWZ5XCI+PC9kaXY+Jyk7XHJcbiAgICAgICAgICAgICAgICAgIC8vIElmIHt2YXJ9IGlzIHNldCBpbiBhcnJheSwgcmVwbGFjZSBpdFxyXG4gICAgICAgICAgICAgICAgICAvKiogQGRlcHJlY2F0ZWQgKi9cclxuICAgICAgICAgICAgICAgICAgaWYgKG1heE9wdGlvbnNBcnJbMl0pIHtcclxuICAgICAgICAgICAgICAgICAgICBtYXhUeHQgPSBtYXhUeHQucmVwbGFjZSgne3Zhcn0nLCBtYXhPcHRpb25zQXJyWzJdW21heE9wdGlvbnMgPiAxID8gMCA6IDFdKTtcclxuICAgICAgICAgICAgICAgICAgICBtYXhUeHRHcnAgPSBtYXhUeHRHcnAucmVwbGFjZSgne3Zhcn0nLCBtYXhPcHRpb25zQXJyWzJdW21heE9wdGlvbnNHcnAgPiAxID8gMCA6IDFdKTtcclxuICAgICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgICAgb3B0aW9uLnNlbGVjdGVkID0gZmFsc2U7XHJcblxyXG4gICAgICAgICAgICAgICAgICB0aGF0LiRtZW51LmFwcGVuZCgkbm90aWZ5KTtcclxuXHJcbiAgICAgICAgICAgICAgICAgIGlmIChtYXhPcHRpb25zICYmIG1heFJlYWNoZWQpIHtcclxuICAgICAgICAgICAgICAgICAgICAkbm90aWZ5LmFwcGVuZCgkKCc8ZGl2PicgKyBtYXhUeHQgKyAnPC9kaXY+JykpO1xyXG4gICAgICAgICAgICAgICAgICAgIHRyaWdnZXJDaGFuZ2UgPSBmYWxzZTtcclxuICAgICAgICAgICAgICAgICAgICB0aGF0LiRlbGVtZW50LnRyaWdnZXIoJ21heFJlYWNoZWQnICsgRVZFTlRfS0VZKTtcclxuICAgICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgICAgaWYgKG1heE9wdGlvbnNHcnAgJiYgbWF4UmVhY2hlZEdycCkge1xyXG4gICAgICAgICAgICAgICAgICAgICRub3RpZnkuYXBwZW5kKCQoJzxkaXY+JyArIG1heFR4dEdycCArICc8L2Rpdj4nKSk7XHJcbiAgICAgICAgICAgICAgICAgICAgdHJpZ2dlckNoYW5nZSA9IGZhbHNlO1xyXG4gICAgICAgICAgICAgICAgICAgIHRoYXQuJGVsZW1lbnQudHJpZ2dlcignbWF4UmVhY2hlZEdycCcgKyBFVkVOVF9LRVkpO1xyXG4gICAgICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgICAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgICAgICAgICB0aGF0LnNldFNlbGVjdGVkKGNsaWNrZWRJbmRleCwgZmFsc2UpO1xyXG4gICAgICAgICAgICAgICAgICB9LCAxMCk7XHJcblxyXG4gICAgICAgICAgICAgICAgICAkbm90aWZ5WzBdLmNsYXNzTGlzdC5hZGQoJ2ZhZGVPdXQnKTtcclxuXHJcbiAgICAgICAgICAgICAgICAgIHNldFRpbWVvdXQoZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICAgICAgICAgICRub3RpZnkucmVtb3ZlKCk7XHJcbiAgICAgICAgICAgICAgICAgIH0sIDEwNTApO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG5cclxuICAgICAgICAgIGlmICh0aGF0Lm9wdGlvbnMuc291cmNlLmRhdGEpIHRoYXQuJGVsZW1lbnRbMF0uYXBwZW5kQ2hpbGQodGhhdC5zZWxlY3RwaWNrZXIubWFpbi5vcHRpb25RdWV1ZSk7XHJcblxyXG4gICAgICAgICAgaWYgKCF0aGF0Lm11bHRpcGxlIHx8ICh0aGF0Lm11bHRpcGxlICYmIHRoYXQub3B0aW9ucy5tYXhPcHRpb25zID09PSAxKSkge1xyXG4gICAgICAgICAgICB0aGF0LiRidXR0b24udHJpZ2dlcignZm9jdXMnKTtcclxuICAgICAgICAgIH0gZWxzZSBpZiAodGhhdC5vcHRpb25zLmxpdmVTZWFyY2gpIHtcclxuICAgICAgICAgICAgdGhhdC4kc2VhcmNoYm94LnRyaWdnZXIoJ2ZvY3VzJyk7XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgLy8gVHJpZ2dlciBzZWxlY3QgJ2NoYW5nZSdcclxuICAgICAgICAgIGlmICh0cmlnZ2VyQ2hhbmdlKSB7XHJcbiAgICAgICAgICAgIGlmICh0aGF0Lm11bHRpcGxlIHx8IHByZXZJbmRleCAhPT0gZWxlbWVudC5zZWxlY3RlZEluZGV4KSB7XHJcbiAgICAgICAgICAgICAgLy8gJG9wdGlvbi5wcm9wKCdzZWxlY3RlZCcpIGlzIGN1cnJlbnQgb3B0aW9uIHN0YXRlIChzZWxlY3RlZC91bnNlbGVjdGVkKS4gcHJldlZhbHVlIGlzIHRoZSB2YWx1ZSBvZiB0aGUgc2VsZWN0IHByaW9yIHRvIGJlaW5nIGNoYW5nZWQuXHJcbiAgICAgICAgICAgICAgY2hhbmdlZEFyZ3VtZW50cyA9IFtvcHRpb24uaW5kZXgsICRvcHRpb24ucHJvcCgnc2VsZWN0ZWQnKSwgcHJldlZhbHVlXTtcclxuICAgICAgICAgICAgICB0aGF0LiRlbGVtZW50XHJcbiAgICAgICAgICAgICAgICAudHJpZ2dlck5hdGl2ZSgnY2hhbmdlJyk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgdGhpcy4kbWVudS5vbignY2xpY2snLCAnbGkuJyArIGNsYXNzTmFtZXMuRElTQUJMRUQgKyAnIGEsIC4nICsgY2xhc3NOYW1lcy5QT1BPVkVSSEVBREVSICsgJywgLicgKyBjbGFzc05hbWVzLlBPUE9WRVJIRUFERVIgKyAnIDpub3QoLmNsb3NlKScsIGZ1bmN0aW9uIChlKSB7XHJcbiAgICAgICAgaWYgKGUuY3VycmVudFRhcmdldCA9PSB0aGlzKSB7XHJcbiAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XHJcbiAgICAgICAgICBlLnN0b3BQcm9wYWdhdGlvbigpO1xyXG4gICAgICAgICAgaWYgKHRoYXQub3B0aW9ucy5saXZlU2VhcmNoICYmICEkKGUudGFyZ2V0KS5oYXNDbGFzcygnY2xvc2UnKSkge1xyXG4gICAgICAgICAgICB0aGF0LiRzZWFyY2hib3gudHJpZ2dlcignZm9jdXMnKTtcclxuICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIHRoYXQuJGJ1dHRvbi50cmlnZ2VyKCdmb2N1cycpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcblxyXG4gICAgICB0aGlzLiRtZW51SW5uZXIub24oJ2NsaWNrJywgJy5kaXZpZGVyLCAuZHJvcGRvd24taGVhZGVyJywgZnVuY3Rpb24gKGUpIHtcclxuICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XHJcbiAgICAgICAgZS5zdG9wUHJvcGFnYXRpb24oKTtcclxuICAgICAgICBpZiAodGhhdC5vcHRpb25zLmxpdmVTZWFyY2gpIHtcclxuICAgICAgICAgIHRoYXQuJHNlYXJjaGJveC50cmlnZ2VyKCdmb2N1cycpO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICB0aGF0LiRidXR0b24udHJpZ2dlcignZm9jdXMnKTtcclxuICAgICAgICB9XHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgdGhpcy4kbWVudS5vbignY2xpY2snLCAnLicgKyBjbGFzc05hbWVzLlBPUE9WRVJIRUFERVIgKyAnIC5jbG9zZScsIGZ1bmN0aW9uICgpIHtcclxuICAgICAgICB0aGF0LiRidXR0b24udHJpZ2dlcignY2xpY2snKTtcclxuICAgICAgfSk7XHJcblxyXG4gICAgICB0aGlzLiRzZWFyY2hib3gub24oJ2NsaWNrJywgZnVuY3Rpb24gKGUpIHtcclxuICAgICAgICBlLnN0b3BQcm9wYWdhdGlvbigpO1xyXG4gICAgICB9KTtcclxuXHJcbiAgICAgIHRoaXMuJG1lbnUub24oJ2NsaWNrJywgJy5hY3Rpb25zLWJ0bicsIGZ1bmN0aW9uIChlKSB7XHJcbiAgICAgICAgaWYgKHRoYXQub3B0aW9ucy5saXZlU2VhcmNoKSB7XHJcbiAgICAgICAgICB0aGF0LiRzZWFyY2hib3gudHJpZ2dlcignZm9jdXMnKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgdGhhdC4kYnV0dG9uLnRyaWdnZXIoJ2ZvY3VzJyk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XHJcbiAgICAgICAgZS5zdG9wUHJvcGFnYXRpb24oKTtcclxuXHJcbiAgICAgICAgaWYgKCQodGhpcykuaGFzQ2xhc3MoJ2JzLXNlbGVjdC1hbGwnKSkge1xyXG4gICAgICAgICAgdGhhdC5zZWxlY3RBbGwoKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgdGhhdC5kZXNlbGVjdEFsbCgpO1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcblxyXG4gICAgICB0aGlzLiRidXR0b25cclxuICAgICAgICAub24oJ2ZvY3VzJyArIEVWRU5UX0tFWSwgZnVuY3Rpb24gKGUpIHtcclxuICAgICAgICAgIHZhciB0YWJpbmRleCA9IHRoYXQuJGVsZW1lbnRbMF0uZ2V0QXR0cmlidXRlKCd0YWJpbmRleCcpO1xyXG5cclxuICAgICAgICAgIC8vIG9ubHkgY2hhbmdlIHdoZW4gYnV0dG9uIGlzIGFjdHVhbGx5IGZvY3VzZWRcclxuICAgICAgICAgIGlmICh0YWJpbmRleCAhPT0gdW5kZWZpbmVkICYmIGUub3JpZ2luYWxFdmVudCAmJiBlLm9yaWdpbmFsRXZlbnQuaXNUcnVzdGVkKSB7XHJcbiAgICAgICAgICAgIC8vIGFwcGx5IHNlbGVjdCBlbGVtZW50J3MgdGFiaW5kZXggdG8gZW5zdXJlIGNvcnJlY3Qgb3JkZXIgaXMgZm9sbG93ZWQgd2hlbiB0YWJiaW5nIHRvIHRoZSBuZXh0IGVsZW1lbnRcclxuICAgICAgICAgICAgdGhpcy5zZXRBdHRyaWJ1dGUoJ3RhYmluZGV4JywgdGFiaW5kZXgpO1xyXG4gICAgICAgICAgICAvLyBzZXQgZWxlbWVudCdzIHRhYmluZGV4IHRvIC0xIHRvIGFsbG93IGZvciByZXZlcnNlIHRhYmJpbmdcclxuICAgICAgICAgICAgdGhhdC4kZWxlbWVudFswXS5zZXRBdHRyaWJ1dGUoJ3RhYmluZGV4JywgLTEpO1xyXG4gICAgICAgICAgICB0aGF0LnNlbGVjdHBpY2tlci52aWV3LnRhYmluZGV4ID0gdGFiaW5kZXg7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSlcclxuICAgICAgICAub24oJ2JsdXInICsgRVZFTlRfS0VZLCBmdW5jdGlvbiAoZSkge1xyXG4gICAgICAgICAgLy8gcmV2ZXJ0IGV2ZXJ5dGhpbmcgdG8gb3JpZ2luYWwgdGFiaW5kZXhcclxuICAgICAgICAgIGlmICh0aGF0LnNlbGVjdHBpY2tlci52aWV3LnRhYmluZGV4ICE9PSB1bmRlZmluZWQgJiYgZS5vcmlnaW5hbEV2ZW50ICYmIGUub3JpZ2luYWxFdmVudC5pc1RydXN0ZWQpIHtcclxuICAgICAgICAgICAgdGhhdC4kZWxlbWVudFswXS5zZXRBdHRyaWJ1dGUoJ3RhYmluZGV4JywgdGhhdC5zZWxlY3RwaWNrZXIudmlldy50YWJpbmRleCk7XHJcbiAgICAgICAgICAgIHRoaXMuc2V0QXR0cmlidXRlKCd0YWJpbmRleCcsIC0xKTtcclxuICAgICAgICAgICAgdGhhdC5zZWxlY3RwaWNrZXIudmlldy50YWJpbmRleCA9IHVuZGVmaW5lZDtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgIHRoaXMuJGVsZW1lbnRcclxuICAgICAgICAub24oJ2NoYW5nZScgKyBFVkVOVF9LRVksIGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgIHRoYXQucmVuZGVyKCk7XHJcbiAgICAgICAgICB0aGF0LiRlbGVtZW50LnRyaWdnZXIoJ2NoYW5nZWQnICsgRVZFTlRfS0VZLCBjaGFuZ2VkQXJndW1lbnRzKTtcclxuICAgICAgICAgIGNoYW5nZWRBcmd1bWVudHMgPSBudWxsO1xyXG4gICAgICAgIH0pXHJcbiAgICAgICAgLm9uKCdmb2N1cycgKyBFVkVOVF9LRVksIGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgIGlmICghdGhhdC5vcHRpb25zLm1vYmlsZSkgdGhhdC4kYnV0dG9uWzBdLmZvY3VzKCk7XHJcbiAgICAgICAgfSk7XHJcbiAgICB9LFxyXG5cclxuICAgIGxpdmVTZWFyY2hMaXN0ZW5lcjogZnVuY3Rpb24gKCkge1xyXG4gICAgICB2YXIgdGhhdCA9IHRoaXM7XHJcblxyXG4gICAgICB0aGlzLiRidXR0b24ub24oJ2NsaWNrLmJzLmRyb3Bkb3duLmRhdGEtYXBpJywgZnVuY3Rpb24gKCkge1xyXG4gICAgICAgIGlmICghIXRoYXQuJHNlYXJjaGJveC52YWwoKSkge1xyXG4gICAgICAgICAgdGhhdC4kc2VhcmNoYm94LnZhbCgnJyk7XHJcbiAgICAgICAgICB0aGF0LnNlbGVjdHBpY2tlci5zZWFyY2gucHJldmlvdXNWYWx1ZSA9IHVuZGVmaW5lZDtcclxuICAgICAgICB9XHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgdGhpcy4kc2VhcmNoYm94Lm9uKCdjbGljay5icy5kcm9wZG93bi5kYXRhLWFwaSBmb2N1cy5icy5kcm9wZG93bi5kYXRhLWFwaSB0b3VjaGVuZC5icy5kcm9wZG93bi5kYXRhLWFwaScsIGZ1bmN0aW9uIChlKSB7XHJcbiAgICAgICAgZS5zdG9wUHJvcGFnYXRpb24oKTtcclxuICAgICAgfSk7XHJcblxyXG4gICAgICB0aGlzLiRzZWFyY2hib3gub24oJ2lucHV0IHByb3BlcnR5Y2hhbmdlJywgZnVuY3Rpb24gKCkge1xyXG4gICAgICAgIHZhciBzZWFyY2hWYWx1ZSA9IHRoYXQuJHNlYXJjaGJveFswXS52YWx1ZTtcclxuXHJcbiAgICAgICAgdGhhdC5zZWxlY3RwaWNrZXIuc2VhcmNoLmVsZW1lbnRzID0gW107XHJcbiAgICAgICAgdGhhdC5zZWxlY3RwaWNrZXIuc2VhcmNoLmRhdGEgPSBbXTtcclxuXHJcbiAgICAgICAgaWYgKHNlYXJjaFZhbHVlKSB7XHJcbiAgICAgICAgICBpZiAodGhhdC5vcHRpb25zLnNvdXJjZS5zZWFyY2gpIHtcclxuICAgICAgICAgICAgdGhhdC5mZXRjaERhdGEoZnVuY3Rpb24gKGJ1aWx0RGF0YSkge1xyXG4gICAgICAgICAgICAgIHRoYXQucmVuZGVyKCk7XHJcbiAgICAgICAgICAgICAgdGhhdC5idWlsZExpc3QodW5kZWZpbmVkLCB0cnVlKTtcclxuICAgICAgICAgICAgICB0aGF0LmNyZWF0ZVZpZXcodHJ1ZSk7XHJcbiAgICAgICAgICAgICAgc2hvd05vUmVzdWx0cy5jYWxsKHRoYXQsIGJ1aWx0RGF0YSwgc2VhcmNoVmFsdWUpO1xyXG4gICAgICAgICAgICB9LCAnc2VhcmNoJywgMCwgc2VhcmNoVmFsdWUpO1xyXG4gICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgdmFyIGksXHJcbiAgICAgICAgICAgICAgICBzZWFyY2hNYXRjaCA9IFtdLFxyXG4gICAgICAgICAgICAgICAgcSA9IHNlYXJjaFZhbHVlLnRvVXBwZXJDYXNlKCksXHJcbiAgICAgICAgICAgICAgICBjYWNoZSA9IHt9LFxyXG4gICAgICAgICAgICAgICAgY2FjaGVBcnIgPSBbXSxcclxuICAgICAgICAgICAgICAgIHNlYXJjaFN0eWxlID0gdGhhdC5fc2VhcmNoU3R5bGUoKSxcclxuICAgICAgICAgICAgICAgIG5vcm1hbGl6ZVNlYXJjaCA9IHRoYXQub3B0aW9ucy5saXZlU2VhcmNoTm9ybWFsaXplO1xyXG5cclxuICAgICAgICAgICAgaWYgKG5vcm1hbGl6ZVNlYXJjaCkgcSA9IG5vcm1hbGl6ZVRvQmFzZShxKTtcclxuXHJcbiAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhhdC5zZWxlY3RwaWNrZXIubWFpbi5kYXRhLmxlbmd0aDsgaSsrKSB7XHJcbiAgICAgICAgICAgICAgdmFyIGxpID0gdGhhdC5zZWxlY3RwaWNrZXIubWFpbi5kYXRhW2ldO1xyXG5cclxuICAgICAgICAgICAgICBpZiAoIWNhY2hlW2ldKSB7XHJcbiAgICAgICAgICAgICAgICBjYWNoZVtpXSA9IHN0cmluZ1NlYXJjaChsaSwgcSwgc2VhcmNoU3R5bGUsIG5vcm1hbGl6ZVNlYXJjaCk7XHJcbiAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICBpZiAoY2FjaGVbaV0gJiYgbGkuaGVhZGVySW5kZXggIT09IHVuZGVmaW5lZCAmJiBjYWNoZUFyci5pbmRleE9mKGxpLmhlYWRlckluZGV4KSA9PT0gLTEpIHtcclxuICAgICAgICAgICAgICAgIGlmIChsaS5oZWFkZXJJbmRleCA+IDApIHtcclxuICAgICAgICAgICAgICAgICAgY2FjaGVbbGkuaGVhZGVySW5kZXggLSAxXSA9IHRydWU7XHJcbiAgICAgICAgICAgICAgICAgIGNhY2hlQXJyLnB1c2gobGkuaGVhZGVySW5kZXggLSAxKTtcclxuICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICBjYWNoZVtsaS5oZWFkZXJJbmRleF0gPSB0cnVlO1xyXG4gICAgICAgICAgICAgICAgY2FjaGVBcnIucHVzaChsaS5oZWFkZXJJbmRleCk7XHJcblxyXG4gICAgICAgICAgICAgICAgY2FjaGVbbGkubGFzdEluZGV4ICsgMV0gPSB0cnVlO1xyXG4gICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgaWYgKGNhY2hlW2ldICYmIGxpLnR5cGUgIT09ICdvcHRncm91cC1sYWJlbCcpIGNhY2hlQXJyLnB1c2goaSk7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIGZvciAodmFyIGkgPSAwLCBjYWNoZUxlbiA9IGNhY2hlQXJyLmxlbmd0aDsgaSA8IGNhY2hlTGVuOyBpKyspIHtcclxuICAgICAgICAgICAgICB2YXIgaW5kZXggPSBjYWNoZUFycltpXSxcclxuICAgICAgICAgICAgICAgICAgcHJldkluZGV4ID0gY2FjaGVBcnJbaSAtIDFdLFxyXG4gICAgICAgICAgICAgICAgICBsaSA9IHRoYXQuc2VsZWN0cGlja2VyLm1haW4uZGF0YVtpbmRleF0sXHJcbiAgICAgICAgICAgICAgICAgIGxpUHJldiA9IHRoYXQuc2VsZWN0cGlja2VyLm1haW4uZGF0YVtwcmV2SW5kZXhdO1xyXG5cclxuICAgICAgICAgICAgICBpZiAobGkudHlwZSAhPT0gJ2RpdmlkZXInIHx8IChsaS50eXBlID09PSAnZGl2aWRlcicgJiYgbGlQcmV2ICYmIGxpUHJldi50eXBlICE9PSAnZGl2aWRlcicgJiYgY2FjaGVMZW4gLSAxICE9PSBpKSkge1xyXG4gICAgICAgICAgICAgICAgdGhhdC5zZWxlY3RwaWNrZXIuc2VhcmNoLmRhdGEucHVzaChsaSk7XHJcbiAgICAgICAgICAgICAgICBzZWFyY2hNYXRjaC5wdXNoKHRoYXQuc2VsZWN0cGlja2VyLm1haW4uZWxlbWVudHNbaW5kZXhdKTtcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIHRoYXQuYWN0aXZlSW5kZXggPSB1bmRlZmluZWQ7XHJcbiAgICAgICAgICAgIHRoYXQubm9TY3JvbGwgPSB0cnVlO1xyXG4gICAgICAgICAgICB0aGF0LiRtZW51SW5uZXIuc2Nyb2xsVG9wKDApO1xyXG4gICAgICAgICAgICB0aGF0LnNlbGVjdHBpY2tlci5zZWFyY2guZWxlbWVudHMgPSBzZWFyY2hNYXRjaDtcclxuICAgICAgICAgICAgdGhhdC5jcmVhdGVWaWV3KHRydWUpO1xyXG4gICAgICAgICAgICBzaG93Tm9SZXN1bHRzLmNhbGwodGhhdCwgc2VhcmNoTWF0Y2gsIHNlYXJjaFZhbHVlKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9IGVsc2UgaWYgKHRoYXQuc2VsZWN0cGlja2VyLnNlYXJjaC5wcmV2aW91c1ZhbHVlKSB7IC8vIGZvciBJRTExICgjMjQwMilcclxuICAgICAgICAgIHRoYXQuJG1lbnVJbm5lci5zY3JvbGxUb3AoMCk7XHJcbiAgICAgICAgICB0aGF0LmNyZWF0ZVZpZXcoZmFsc2UpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgdGhhdC5zZWxlY3RwaWNrZXIuc2VhcmNoLnByZXZpb3VzVmFsdWUgPSAgc2VhcmNoVmFsdWU7XHJcbiAgICAgIH0pO1xyXG4gICAgfSxcclxuXHJcbiAgICBfc2VhcmNoU3R5bGU6IGZ1bmN0aW9uICgpIHtcclxuICAgICAgcmV0dXJuIHRoaXMub3B0aW9ucy5saXZlU2VhcmNoU3R5bGUgfHwgJ2NvbnRhaW5zJztcclxuICAgIH0sXHJcblxyXG4gICAgdmFsOiBmdW5jdGlvbiAodmFsdWUpIHtcclxuICAgICAgdmFyIGVsZW1lbnQgPSB0aGlzLiRlbGVtZW50WzBdO1xyXG5cclxuICAgICAgaWYgKHR5cGVvZiB2YWx1ZSAhPT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgICB2YXIgc2VsZWN0ZWRPcHRpb25zID0gZ2V0U2VsZWN0ZWRPcHRpb25zLmNhbGwodGhpcyksXHJcbiAgICAgICAgICAgIHByZXZWYWx1ZSA9IGdldFNlbGVjdFZhbHVlcy5jYWxsKHRoaXMsIHNlbGVjdGVkT3B0aW9ucyk7XHJcblxyXG4gICAgICAgIGNoYW5nZWRBcmd1bWVudHMgPSBbbnVsbCwgbnVsbCwgcHJldlZhbHVlXTtcclxuXHJcbiAgICAgICAgaWYgKCFBcnJheS5pc0FycmF5KHZhbHVlKSkgdmFsdWUgPSBbIHZhbHVlIF07XHJcblxyXG4gICAgICAgIHZhbHVlLm1hcChTdHJpbmcpO1xyXG5cclxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHNlbGVjdGVkT3B0aW9ucy5sZW5ndGg7IGkrKykge1xyXG4gICAgICAgICAgdmFyIGl0ZW0gPSBzZWxlY3RlZE9wdGlvbnNbaV07XHJcblxyXG4gICAgICAgICAgaWYgKGl0ZW0gJiYgdmFsdWUuaW5kZXhPZihTdHJpbmcoaXRlbS52YWx1ZSkpID09PSAtMSkge1xyXG4gICAgICAgICAgICB0aGlzLnNldFNlbGVjdGVkKGl0ZW0sIGZhbHNlKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIG9ubHkgdXBkYXRlIHNlbGVjdGVkIHZhbHVlIGlmIGl0IG1hdGNoZXMgYW4gZXhpc3Rpbmcgb3B0aW9uXHJcbiAgICAgICAgdGhpcy5zZWxlY3RwaWNrZXIubWFpbi5kYXRhLmZpbHRlcihmdW5jdGlvbiAoaXRlbSkge1xyXG4gICAgICAgICAgaWYgKHZhbHVlLmluZGV4T2YoU3RyaW5nKGl0ZW0udmFsdWUpKSAhPT0gLTEpIHtcclxuICAgICAgICAgICAgdGhpcy5zZXRTZWxlY3RlZChpdGVtLCB0cnVlKTtcclxuICAgICAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICAgIH0sIHRoaXMpO1xyXG5cclxuICAgICAgICBpZiAodGhpcy5vcHRpb25zLnNvdXJjZS5kYXRhKSBlbGVtZW50LmFwcGVuZENoaWxkKHRoaXMuc2VsZWN0cGlja2VyLm1haW4ub3B0aW9uUXVldWUpO1xyXG5cclxuICAgICAgICB0aGlzLiRlbGVtZW50LnRyaWdnZXIoJ2NoYW5nZWQnICsgRVZFTlRfS0VZLCBjaGFuZ2VkQXJndW1lbnRzKTtcclxuXHJcbiAgICAgICAgaWYgKHRoaXMuJG5ld0VsZW1lbnQuaGFzQ2xhc3MoY2xhc3NOYW1lcy5TSE9XKSkge1xyXG4gICAgICAgICAgaWYgKHRoaXMubXVsdGlwbGUpIHtcclxuICAgICAgICAgICAgdGhpcy5zZXRPcHRpb25TdGF0dXModHJ1ZSk7XHJcbiAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICB2YXIgbGlTZWxlY3RlZEluZGV4ID0gKGVsZW1lbnQub3B0aW9uc1tlbGVtZW50LnNlbGVjdGVkSW5kZXhdIHx8IHt9KS5saUluZGV4O1xyXG5cclxuICAgICAgICAgICAgaWYgKHR5cGVvZiBsaVNlbGVjdGVkSW5kZXggPT09ICdudW1iZXInKSB7XHJcbiAgICAgICAgICAgICAgdGhpcy5zZXRTZWxlY3RlZCh0aGlzLnNlbGVjdGVkSW5kZXgsIGZhbHNlKTtcclxuICAgICAgICAgICAgICB0aGlzLnNldFNlbGVjdGVkKGxpU2VsZWN0ZWRJbmRleCwgdHJ1ZSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHRoaXMucmVuZGVyKCk7XHJcblxyXG4gICAgICAgIGNoYW5nZWRBcmd1bWVudHMgPSBudWxsO1xyXG5cclxuICAgICAgICByZXR1cm4gdGhpcy4kZWxlbWVudDtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICByZXR1cm4gdGhpcy4kZWxlbWVudC52YWwoKTtcclxuICAgICAgfVxyXG4gICAgfSxcclxuXHJcbiAgICBjaGFuZ2VBbGw6IGZ1bmN0aW9uIChzdGF0dXMpIHtcclxuICAgICAgaWYgKCF0aGlzLm11bHRpcGxlKSByZXR1cm47XHJcbiAgICAgIGlmICh0eXBlb2Ygc3RhdHVzID09PSAndW5kZWZpbmVkJykgc3RhdHVzID0gdHJ1ZTtcclxuXHJcbiAgICAgIHZhciBlbGVtZW50ID0gdGhpcy4kZWxlbWVudFswXSxcclxuICAgICAgICAgIHByZXZpb3VzU2VsZWN0ZWQgPSAwLFxyXG4gICAgICAgICAgY3VycmVudFNlbGVjdGVkID0gMCxcclxuICAgICAgICAgIHByZXZWYWx1ZSA9IGdldFNlbGVjdFZhbHVlcy5jYWxsKHRoaXMpO1xyXG5cclxuICAgICAgZWxlbWVudC5jbGFzc0xpc3QuYWRkKCdicy1zZWxlY3QtaGlkZGVuJyk7XHJcblxyXG4gICAgICBmb3IgKHZhciBpID0gMCwgZGF0YSA9IHRoaXMuc2VsZWN0cGlja2VyLmN1cnJlbnQuZGF0YSwgbGVuID0gZGF0YS5sZW5ndGg7IGkgPCBsZW47IGkrKykge1xyXG4gICAgICAgIHZhciBsaURhdGEgPSBkYXRhW2ldLFxyXG4gICAgICAgICAgICBvcHRpb24gPSBsaURhdGEub3B0aW9uO1xyXG5cclxuICAgICAgICBpZiAob3B0aW9uICYmICFsaURhdGEuZGlzYWJsZWQgJiYgbGlEYXRhLnR5cGUgIT09ICdkaXZpZGVyJykge1xyXG4gICAgICAgICAgaWYgKGxpRGF0YS5zZWxlY3RlZCkgcHJldmlvdXNTZWxlY3RlZCsrO1xyXG4gICAgICAgICAgb3B0aW9uLnNlbGVjdGVkID0gc3RhdHVzO1xyXG4gICAgICAgICAgbGlEYXRhLnNlbGVjdGVkID0gc3RhdHVzO1xyXG4gICAgICAgICAgaWYgKHN0YXR1cyA9PT0gdHJ1ZSkgY3VycmVudFNlbGVjdGVkKys7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICBlbGVtZW50LmNsYXNzTGlzdC5yZW1vdmUoJ2JzLXNlbGVjdC1oaWRkZW4nKTtcclxuXHJcbiAgICAgIGlmIChwcmV2aW91c1NlbGVjdGVkID09PSBjdXJyZW50U2VsZWN0ZWQpIHJldHVybjtcclxuXHJcbiAgICAgIHRoaXMuc2V0T3B0aW9uU3RhdHVzKCk7XHJcblxyXG4gICAgICBjaGFuZ2VkQXJndW1lbnRzID0gW251bGwsIG51bGwsIHByZXZWYWx1ZV07XHJcblxyXG4gICAgICB0aGlzLiRlbGVtZW50XHJcbiAgICAgICAgLnRyaWdnZXJOYXRpdmUoJ2NoYW5nZScpO1xyXG4gICAgfSxcclxuXHJcbiAgICBzZWxlY3RBbGw6IGZ1bmN0aW9uICgpIHtcclxuICAgICAgcmV0dXJuIHRoaXMuY2hhbmdlQWxsKHRydWUpO1xyXG4gICAgfSxcclxuXHJcbiAgICBkZXNlbGVjdEFsbDogZnVuY3Rpb24gKCkge1xyXG4gICAgICByZXR1cm4gdGhpcy5jaGFuZ2VBbGwoZmFsc2UpO1xyXG4gICAgfSxcclxuXHJcbiAgICB0b2dnbGU6IGZ1bmN0aW9uIChlLCBzdGF0ZSkge1xyXG4gICAgICB2YXIgaXNBY3RpdmUsXHJcbiAgICAgICAgICB0cmlnZ2VyQ2xpY2sgPSBzdGF0ZSA9PT0gdW5kZWZpbmVkO1xyXG5cclxuICAgICAgZSA9IGUgfHwgd2luZG93LmV2ZW50O1xyXG5cclxuICAgICAgaWYgKGUpIGUuc3RvcFByb3BhZ2F0aW9uKCk7XHJcblxyXG4gICAgICBpZiAodHJpZ2dlckNsaWNrID09PSBmYWxzZSkge1xyXG4gICAgICAgIGlzQWN0aXZlID0gdGhpcy4kbmV3RWxlbWVudFswXS5jbGFzc0xpc3QuY29udGFpbnMoY2xhc3NOYW1lcy5TSE9XKTtcclxuICAgICAgICB0cmlnZ2VyQ2xpY2sgPSBzdGF0ZSA9PT0gdHJ1ZSAmJiBpc0FjdGl2ZSA9PT0gZmFsc2UgfHwgc3RhdGUgPT09IGZhbHNlICYmIGlzQWN0aXZlID09PSB0cnVlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAodHJpZ2dlckNsaWNrKSB0aGlzLiRidXR0b24udHJpZ2dlcignY2xpY2suYnMuZHJvcGRvd24uZGF0YS1hcGknKTtcclxuICAgIH0sXHJcblxyXG4gICAgb3BlbjogZnVuY3Rpb24gKGUpIHtcclxuICAgICAgdGhpcy50b2dnbGUoZSwgdHJ1ZSk7XHJcbiAgICB9LFxyXG5cclxuICAgIGNsb3NlOiBmdW5jdGlvbiAoZSkge1xyXG4gICAgICB0aGlzLnRvZ2dsZShlLCBmYWxzZSk7XHJcbiAgICB9LFxyXG5cclxuICAgIGtleWRvd246IGZ1bmN0aW9uIChlKSB7XHJcbiAgICAgIHZhciAkdGhpcyA9ICQodGhpcyksXHJcbiAgICAgICAgICBpc1RvZ2dsZSA9ICR0aGlzLmhhc0NsYXNzKCdkcm9wZG93bi10b2dnbGUnKSxcclxuICAgICAgICAgICRwYXJlbnQgPSBpc1RvZ2dsZSA/ICR0aGlzLmNsb3Nlc3QoJy5kcm9wZG93bicpIDogJHRoaXMuY2xvc2VzdChTZWxlY3Rvci5NRU5VKSxcclxuICAgICAgICAgIHRoYXQgPSAkcGFyZW50LmRhdGEoJ3RoaXMnKSxcclxuICAgICAgICAgICRpdGVtcyA9IHRoYXQuZmluZExpcygpLFxyXG4gICAgICAgICAgaW5kZXgsXHJcbiAgICAgICAgICBpc0FjdGl2ZSxcclxuICAgICAgICAgIGxpQWN0aXZlLFxyXG4gICAgICAgICAgYWN0aXZlTGksXHJcbiAgICAgICAgICBvZmZzZXQsXHJcbiAgICAgICAgICB1cGRhdGVTY3JvbGwgPSBmYWxzZSxcclxuICAgICAgICAgIGRvd25PblRhYiA9IGUud2hpY2ggPT09IGtleUNvZGVzLlRBQiAmJiAhaXNUb2dnbGUgJiYgIXRoYXQub3B0aW9ucy5zZWxlY3RPblRhYixcclxuICAgICAgICAgIGlzQXJyb3dLZXkgPSBSRUdFWFBfQVJST1cudGVzdChlLndoaWNoKSB8fCBkb3duT25UYWIsXHJcbiAgICAgICAgICBzY3JvbGxUb3AgPSB0aGF0LiRtZW51SW5uZXJbMF0uc2Nyb2xsVG9wLFxyXG4gICAgICAgICAgaXNWaXJ0dWFsID0gdGhhdC5pc1ZpcnR1YWwoKSxcclxuICAgICAgICAgIHBvc2l0aW9uMCA9IGlzVmlydHVhbCA9PT0gdHJ1ZSA/IHRoYXQuc2VsZWN0cGlja2VyLnZpZXcucG9zaXRpb24wIDogMDtcclxuXHJcbiAgICAgIC8vIGRvIG5vdGhpbmcgaWYgYSBmdW5jdGlvbiBrZXkgaXMgcHJlc3NlZFxyXG4gICAgICBpZiAoZS53aGljaCA+PSAxMTIgJiYgZS53aGljaCA8PSAxMjMpIHJldHVybjtcclxuXHJcbiAgICAgIGlzQWN0aXZlID0gdGhhdC4kbWVudS5oYXNDbGFzcyhjbGFzc05hbWVzLlNIT1cpO1xyXG5cclxuICAgICAgaWYgKFxyXG4gICAgICAgICFpc0FjdGl2ZSAmJlxyXG4gICAgICAgIChcclxuICAgICAgICAgIGlzQXJyb3dLZXkgfHxcclxuICAgICAgICAgIChlLndoaWNoID49IDQ4ICYmIGUud2hpY2ggPD0gNTcpIHx8XHJcbiAgICAgICAgICAoZS53aGljaCA+PSA5NiAmJiBlLndoaWNoIDw9IDEwNSkgfHxcclxuICAgICAgICAgIChlLndoaWNoID49IDY1ICYmIGUud2hpY2ggPD0gOTApXHJcbiAgICAgICAgKVxyXG4gICAgICApIHtcclxuICAgICAgICB0aGF0LiRidXR0b24udHJpZ2dlcignY2xpY2suYnMuZHJvcGRvd24uZGF0YS1hcGknKTtcclxuXHJcbiAgICAgICAgaWYgKHRoYXQub3B0aW9ucy5saXZlU2VhcmNoKSB7XHJcbiAgICAgICAgICB0aGF0LiRzZWFyY2hib3gudHJpZ2dlcignZm9jdXMnKTtcclxuICAgICAgICAgIHJldHVybjtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmIChlLndoaWNoID09PSBrZXlDb2Rlcy5FU0NBUEUgJiYgaXNBY3RpdmUpIHtcclxuICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XHJcbiAgICAgICAgdGhhdC4kYnV0dG9uLnRyaWdnZXIoJ2NsaWNrLmJzLmRyb3Bkb3duLmRhdGEtYXBpJykudHJpZ2dlcignZm9jdXMnKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKGlzQXJyb3dLZXkpIHsgLy8gaWYgdXAgb3IgZG93blxyXG4gICAgICAgIGlmICghJGl0ZW1zLmxlbmd0aCkgcmV0dXJuO1xyXG5cclxuICAgICAgICBsaUFjdGl2ZSA9IHRoYXQuc2VsZWN0cGlja2VyLm1haW4uZWxlbWVudHNbdGhhdC5hY3RpdmVJbmRleF07XHJcbiAgICAgICAgaW5kZXggPSBsaUFjdGl2ZSA/IEFycmF5LnByb3RvdHlwZS5pbmRleE9mLmNhbGwobGlBY3RpdmUucGFyZW50RWxlbWVudC5jaGlsZHJlbiwgbGlBY3RpdmUpIDogLTE7XHJcblxyXG4gICAgICAgIGlmIChpbmRleCAhPT0gLTEpIHtcclxuICAgICAgICAgIHRoYXQuZGVmb2N1c0l0ZW0obGlBY3RpdmUpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgaWYgKGUud2hpY2ggPT09IGtleUNvZGVzLkFSUk9XX1VQKSB7IC8vIHVwXHJcbiAgICAgICAgICBpZiAoaW5kZXggIT09IC0xKSBpbmRleC0tO1xyXG4gICAgICAgICAgaWYgKGluZGV4ICsgcG9zaXRpb24wIDwgMCkgaW5kZXggKz0gJGl0ZW1zLmxlbmd0aDtcclxuXHJcbiAgICAgICAgICBpZiAoIXRoYXQuc2VsZWN0cGlja2VyLnZpZXcuY2FuSGlnaGxpZ2h0W2luZGV4ICsgcG9zaXRpb24wXSkge1xyXG4gICAgICAgICAgICBpbmRleCA9IHRoYXQuc2VsZWN0cGlja2VyLnZpZXcuY2FuSGlnaGxpZ2h0LnNsaWNlKDAsIGluZGV4ICsgcG9zaXRpb24wKS5sYXN0SW5kZXhPZih0cnVlKSAtIHBvc2l0aW9uMDtcclxuICAgICAgICAgICAgaWYgKGluZGV4ID09PSAtMSkgaW5kZXggPSAkaXRlbXMubGVuZ3RoIC0gMTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9IGVsc2UgaWYgKGUud2hpY2ggPT09IGtleUNvZGVzLkFSUk9XX0RPV04gfHwgZG93bk9uVGFiKSB7IC8vIGRvd25cclxuICAgICAgICAgIGluZGV4Kys7XHJcbiAgICAgICAgICBpZiAoaW5kZXggKyBwb3NpdGlvbjAgPj0gdGhhdC5zZWxlY3RwaWNrZXIudmlldy5jYW5IaWdobGlnaHQubGVuZ3RoKSBpbmRleCA9IHRoYXQuc2VsZWN0cGlja2VyLnZpZXcuZmlyc3RIaWdobGlnaHRJbmRleDtcclxuXHJcbiAgICAgICAgICBpZiAoIXRoYXQuc2VsZWN0cGlja2VyLnZpZXcuY2FuSGlnaGxpZ2h0W2luZGV4ICsgcG9zaXRpb24wXSkge1xyXG4gICAgICAgICAgICBpbmRleCA9IGluZGV4ICsgMSArIHRoYXQuc2VsZWN0cGlja2VyLnZpZXcuY2FuSGlnaGxpZ2h0LnNsaWNlKGluZGV4ICsgcG9zaXRpb24wICsgMSkuaW5kZXhPZih0cnVlKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcclxuXHJcbiAgICAgICAgdmFyIGxpQWN0aXZlSW5kZXggPSBwb3NpdGlvbjAgKyBpbmRleDtcclxuXHJcbiAgICAgICAgaWYgKGUud2hpY2ggPT09IGtleUNvZGVzLkFSUk9XX1VQKSB7IC8vIHVwXHJcbiAgICAgICAgICAvLyBzY3JvbGwgdG8gYm90dG9tIGFuZCBoaWdobGlnaHQgbGFzdCBvcHRpb25cclxuICAgICAgICAgIGlmIChwb3NpdGlvbjAgPT09IDAgJiYgaW5kZXggPT09ICRpdGVtcy5sZW5ndGggLSAxKSB7XHJcbiAgICAgICAgICAgIHRoYXQuJG1lbnVJbm5lclswXS5zY3JvbGxUb3AgPSB0aGF0LiRtZW51SW5uZXJbMF0uc2Nyb2xsSGVpZ2h0O1xyXG5cclxuICAgICAgICAgICAgbGlBY3RpdmVJbmRleCA9IHRoYXQuc2VsZWN0cGlja2VyLmN1cnJlbnQuZWxlbWVudHMubGVuZ3RoIC0gMTtcclxuICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIGFjdGl2ZUxpID0gdGhhdC5zZWxlY3RwaWNrZXIuY3VycmVudC5kYXRhW2xpQWN0aXZlSW5kZXhdO1xyXG4gICAgICAgICAgICBvZmZzZXQgPSBhY3RpdmVMaS5wb3NpdGlvbiAtIGFjdGl2ZUxpLmhlaWdodDtcclxuXHJcbiAgICAgICAgICAgIHVwZGF0ZVNjcm9sbCA9IG9mZnNldCA8IHNjcm9sbFRvcDtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9IGVsc2UgaWYgKGUud2hpY2ggPT09IGtleUNvZGVzLkFSUk9XX0RPV04gfHwgZG93bk9uVGFiKSB7IC8vIGRvd25cclxuICAgICAgICAgIC8vIHNjcm9sbCB0byB0b3AgYW5kIGhpZ2hsaWdodCBmaXJzdCBvcHRpb25cclxuICAgICAgICAgIGlmIChpbmRleCA9PT0gdGhhdC5zZWxlY3RwaWNrZXIudmlldy5maXJzdEhpZ2hsaWdodEluZGV4KSB7XHJcbiAgICAgICAgICAgIHRoYXQuJG1lbnVJbm5lclswXS5zY3JvbGxUb3AgPSAwO1xyXG5cclxuICAgICAgICAgICAgbGlBY3RpdmVJbmRleCA9IHRoYXQuc2VsZWN0cGlja2VyLnZpZXcuZmlyc3RIaWdobGlnaHRJbmRleDtcclxuICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIGFjdGl2ZUxpID0gdGhhdC5zZWxlY3RwaWNrZXIuY3VycmVudC5kYXRhW2xpQWN0aXZlSW5kZXhdO1xyXG4gICAgICAgICAgICBvZmZzZXQgPSBhY3RpdmVMaS5wb3NpdGlvbiAtIHRoYXQuc2l6ZUluZm8ubWVudUlubmVySGVpZ2h0O1xyXG5cclxuICAgICAgICAgICAgdXBkYXRlU2Nyb2xsID0gb2Zmc2V0ID4gc2Nyb2xsVG9wO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgbGlBY3RpdmUgPSB0aGF0LnNlbGVjdHBpY2tlci5jdXJyZW50LmVsZW1lbnRzW2xpQWN0aXZlSW5kZXhdO1xyXG5cclxuICAgICAgICB0aGF0LmFjdGl2ZUluZGV4ID0gdGhhdC5zZWxlY3RwaWNrZXIuY3VycmVudC5kYXRhW2xpQWN0aXZlSW5kZXhdLmluZGV4O1xyXG5cclxuICAgICAgICB0aGF0LmZvY3VzSXRlbShsaUFjdGl2ZSk7XHJcblxyXG4gICAgICAgIHRoYXQuc2VsZWN0cGlja2VyLnZpZXcuY3VycmVudEFjdGl2ZSA9IGxpQWN0aXZlO1xyXG5cclxuICAgICAgICBpZiAodXBkYXRlU2Nyb2xsKSB0aGF0LiRtZW51SW5uZXJbMF0uc2Nyb2xsVG9wID0gb2Zmc2V0O1xyXG5cclxuICAgICAgICBpZiAodGhhdC5vcHRpb25zLmxpdmVTZWFyY2gpIHtcclxuICAgICAgICAgIHRoYXQuJHNlYXJjaGJveC50cmlnZ2VyKCdmb2N1cycpO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAkdGhpcy50cmlnZ2VyKCdmb2N1cycpO1xyXG4gICAgICAgIH1cclxuICAgICAgfSBlbHNlIGlmIChcclxuICAgICAgICAoISR0aGlzLmlzKCdpbnB1dCcpICYmICFSRUdFWFBfVEFCX09SX0VTQ0FQRS50ZXN0KGUud2hpY2gpKSB8fFxyXG4gICAgICAgIChlLndoaWNoID09PSBrZXlDb2Rlcy5TUEFDRSAmJiB0aGF0LnNlbGVjdHBpY2tlci5rZXlkb3duLmtleUhpc3RvcnkpXHJcbiAgICAgICkge1xyXG4gICAgICAgIHZhciBzZWFyY2hNYXRjaCxcclxuICAgICAgICAgICAgbWF0Y2hlcyA9IFtdLFxyXG4gICAgICAgICAgICBrZXlIaXN0b3J5O1xyXG5cclxuICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XHJcblxyXG4gICAgICAgIHRoYXQuc2VsZWN0cGlja2VyLmtleWRvd24ua2V5SGlzdG9yeSArPSBrZXlDb2RlTWFwW2Uud2hpY2hdO1xyXG5cclxuICAgICAgICBpZiAodGhhdC5zZWxlY3RwaWNrZXIua2V5ZG93bi5yZXNldEtleUhpc3RvcnkuY2FuY2VsKSBjbGVhclRpbWVvdXQodGhhdC5zZWxlY3RwaWNrZXIua2V5ZG93bi5yZXNldEtleUhpc3RvcnkuY2FuY2VsKTtcclxuICAgICAgICB0aGF0LnNlbGVjdHBpY2tlci5rZXlkb3duLnJlc2V0S2V5SGlzdG9yeS5jYW5jZWwgPSB0aGF0LnNlbGVjdHBpY2tlci5rZXlkb3duLnJlc2V0S2V5SGlzdG9yeS5zdGFydCgpO1xyXG5cclxuICAgICAgICBrZXlIaXN0b3J5ID0gdGhhdC5zZWxlY3RwaWNrZXIua2V5ZG93bi5rZXlIaXN0b3J5O1xyXG5cclxuICAgICAgICAvLyBpZiBhbGwgbGV0dGVycyBhcmUgdGhlIHNhbWUsIHNldCBrZXlIaXN0b3J5IHRvIGp1c3QgdGhlIGZpcnN0IGNoYXJhY3RlciB3aGVuIHNlYXJjaGluZ1xyXG4gICAgICAgIGlmICgvXiguKVxcMSskLy50ZXN0KGtleUhpc3RvcnkpKSB7XHJcbiAgICAgICAgICBrZXlIaXN0b3J5ID0ga2V5SGlzdG9yeS5jaGFyQXQoMCk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBmaW5kIG1hdGNoZXNcclxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoYXQuc2VsZWN0cGlja2VyLmN1cnJlbnQuZGF0YS5sZW5ndGg7IGkrKykge1xyXG4gICAgICAgICAgdmFyIGxpID0gdGhhdC5zZWxlY3RwaWNrZXIuY3VycmVudC5kYXRhW2ldLFxyXG4gICAgICAgICAgICAgIGhhc01hdGNoO1xyXG5cclxuICAgICAgICAgIGhhc01hdGNoID0gc3RyaW5nU2VhcmNoKGxpLCBrZXlIaXN0b3J5LCAnc3RhcnRzV2l0aCcsIHRydWUpO1xyXG5cclxuICAgICAgICAgIGlmIChoYXNNYXRjaCAmJiB0aGF0LnNlbGVjdHBpY2tlci52aWV3LmNhbkhpZ2hsaWdodFtpXSkge1xyXG4gICAgICAgICAgICBtYXRjaGVzLnB1c2gobGkuaW5kZXgpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgaWYgKG1hdGNoZXMubGVuZ3RoKSB7XHJcbiAgICAgICAgICB2YXIgbWF0Y2hJbmRleCA9IDA7XHJcblxyXG4gICAgICAgICAgJGl0ZW1zLnJlbW92ZUNsYXNzKCdhY3RpdmUnKS5maW5kKCdhJykucmVtb3ZlQ2xhc3MoJ2FjdGl2ZScpO1xyXG5cclxuICAgICAgICAgIC8vIGVpdGhlciBvbmx5IG9uZSBrZXkgaGFzIGJlZW4gcHJlc3NlZCBvciB0aGV5IGFyZSBhbGwgdGhlIHNhbWUga2V5XHJcbiAgICAgICAgICBpZiAoa2V5SGlzdG9yeS5sZW5ndGggPT09IDEpIHtcclxuICAgICAgICAgICAgbWF0Y2hJbmRleCA9IG1hdGNoZXMuaW5kZXhPZih0aGF0LmFjdGl2ZUluZGV4KTtcclxuXHJcbiAgICAgICAgICAgIGlmIChtYXRjaEluZGV4ID09PSAtMSB8fCBtYXRjaEluZGV4ID09PSBtYXRjaGVzLmxlbmd0aCAtIDEpIHtcclxuICAgICAgICAgICAgICBtYXRjaEluZGV4ID0gMDtcclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICBtYXRjaEluZGV4Kys7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICBzZWFyY2hNYXRjaCA9IG1hdGNoZXNbbWF0Y2hJbmRleF07XHJcblxyXG4gICAgICAgICAgYWN0aXZlTGkgPSB0aGF0LnNlbGVjdHBpY2tlci5tYWluLmRhdGFbc2VhcmNoTWF0Y2hdO1xyXG5cclxuICAgICAgICAgIGlmIChzY3JvbGxUb3AgLSBhY3RpdmVMaS5wb3NpdGlvbiA+IDApIHtcclxuICAgICAgICAgICAgb2Zmc2V0ID0gYWN0aXZlTGkucG9zaXRpb24gLSBhY3RpdmVMaS5oZWlnaHQ7XHJcbiAgICAgICAgICAgIHVwZGF0ZVNjcm9sbCA9IHRydWU7XHJcbiAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICBvZmZzZXQgPSBhY3RpdmVMaS5wb3NpdGlvbiAtIHRoYXQuc2l6ZUluZm8ubWVudUlubmVySGVpZ2h0O1xyXG4gICAgICAgICAgICAvLyBpZiB0aGUgb3B0aW9uIGlzIGFscmVhZHkgdmlzaWJsZSBhdCB0aGUgY3VycmVudCBzY3JvbGwgcG9zaXRpb24sIGp1c3Qga2VlcCBpdCB0aGUgc2FtZVxyXG4gICAgICAgICAgICB1cGRhdGVTY3JvbGwgPSBhY3RpdmVMaS5wb3NpdGlvbiA+IHNjcm9sbFRvcCArIHRoYXQuc2l6ZUluZm8ubWVudUlubmVySGVpZ2h0O1xyXG4gICAgICAgICAgfVxyXG5cclxuICAgICAgICAgIGxpQWN0aXZlID0gdGhhdC5zZWxlY3RwaWNrZXIubWFpbi5lbGVtZW50c1tzZWFyY2hNYXRjaF07XHJcblxyXG4gICAgICAgICAgdGhhdC5hY3RpdmVJbmRleCA9IG1hdGNoZXNbbWF0Y2hJbmRleF07XHJcblxyXG4gICAgICAgICAgdGhhdC5mb2N1c0l0ZW0obGlBY3RpdmUpO1xyXG5cclxuICAgICAgICAgIGlmIChsaUFjdGl2ZSkgbGlBY3RpdmUuZmlyc3RDaGlsZC5mb2N1cygpO1xyXG5cclxuICAgICAgICAgIGlmICh1cGRhdGVTY3JvbGwpIHRoYXQuJG1lbnVJbm5lclswXS5zY3JvbGxUb3AgPSBvZmZzZXQ7XHJcblxyXG4gICAgICAgICAgJHRoaXMudHJpZ2dlcignZm9jdXMnKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIFNlbGVjdCBmb2N1c2VkIG9wdGlvbiBpZiBcIkVudGVyXCIsIFwiU3BhY2ViYXJcIiBvciBcIlRhYlwiICh3aGVuIHNlbGVjdE9uVGFiIGlzIHRydWUpIGFyZSBwcmVzc2VkIGluc2lkZSB0aGUgbWVudS5cclxuICAgICAgaWYgKFxyXG4gICAgICAgIGlzQWN0aXZlICYmXHJcbiAgICAgICAgKFxyXG4gICAgICAgICAgKGUud2hpY2ggPT09IGtleUNvZGVzLlNQQUNFICYmICF0aGF0LnNlbGVjdHBpY2tlci5rZXlkb3duLmtleUhpc3RvcnkpIHx8XHJcbiAgICAgICAgICBlLndoaWNoID09PSBrZXlDb2Rlcy5FTlRFUiB8fFxyXG4gICAgICAgICAgKGUud2hpY2ggPT09IGtleUNvZGVzLlRBQiAmJiB0aGF0Lm9wdGlvbnMuc2VsZWN0T25UYWIpXHJcbiAgICAgICAgKVxyXG4gICAgICApIHtcclxuICAgICAgICBpZiAoZS53aGljaCAhPT0ga2V5Q29kZXMuU1BBQ0UpIGUucHJldmVudERlZmF1bHQoKTtcclxuXHJcbiAgICAgICAgaWYgKCF0aGF0Lm9wdGlvbnMubGl2ZVNlYXJjaCB8fCBlLndoaWNoICE9PSBrZXlDb2Rlcy5TUEFDRSkge1xyXG4gICAgICAgICAgdGhhdC4kbWVudUlubmVyLmZpbmQoJy5hY3RpdmUgYScpLnRyaWdnZXIoJ2NsaWNrJywgdHJ1ZSk7IC8vIHJldGFpbiBhY3RpdmUgY2xhc3NcclxuICAgICAgICAgICR0aGlzLnRyaWdnZXIoJ2ZvY3VzJyk7XHJcblxyXG4gICAgICAgICAgaWYgKCF0aGF0Lm9wdGlvbnMubGl2ZVNlYXJjaCkge1xyXG4gICAgICAgICAgICAvLyBQcmV2ZW50IHNjcmVlbiBmcm9tIHNjcm9sbGluZyBpZiB0aGUgdXNlciBoaXRzIHRoZSBzcGFjZWJhclxyXG4gICAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XHJcbiAgICAgICAgICAgIC8vIEZpeGVzIHNwYWNlYmFyIHNlbGVjdGlvbiBvZiBkcm9wZG93biBpdGVtcyBpbiBGRiAmIElFXHJcbiAgICAgICAgICAgICQoZG9jdW1lbnQpLmRhdGEoJ3NwYWNlU2VsZWN0JywgdHJ1ZSk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9LFxyXG5cclxuICAgIG1vYmlsZTogZnVuY3Rpb24gKCkge1xyXG4gICAgICAvLyBlbnN1cmUgbW9iaWxlIGlzIHNldCB0byB0cnVlIGlmIG1vYmlsZSBmdW5jdGlvbiBpcyBjYWxsZWQgYWZ0ZXIgaW5pdFxyXG4gICAgICB0aGlzLm9wdGlvbnMubW9iaWxlID0gdHJ1ZTtcclxuICAgICAgdGhpcy4kZWxlbWVudFswXS5jbGFzc0xpc3QuYWRkKCdtb2JpbGUtZGV2aWNlJyk7XHJcbiAgICB9LFxyXG5cclxuICAgIHJlZnJlc2g6IGZ1bmN0aW9uICgpIHtcclxuICAgICAgdmFyIHRoYXQgPSB0aGlzO1xyXG4gICAgICAvLyB1cGRhdGUgb3B0aW9ucyBpZiBkYXRhIGF0dHJpYnV0ZXMgaGF2ZSBiZWVuIGNoYW5nZWRcclxuICAgICAgdmFyIGNvbmZpZyA9ICQuZXh0ZW5kKHt9LCB0aGlzLm9wdGlvbnMsIGdldEF0dHJpYnV0ZXNPYmplY3QodGhpcy4kZWxlbWVudCksIHRoaXMuJGVsZW1lbnQuZGF0YSgpKTsgLy8gaW4gdGhpcyBvcmRlciBvbiByZWZyZXNoLCBhcyB1c2VyIG1heSBjaGFuZ2UgYXR0cmlidXRlcyBvbiBzZWxlY3QsIGFuZCBvcHRpb25zIG9iamVjdCBpcyBub3QgcGFzc2VkIG9uIHJlZnJlc2hcclxuICAgICAgdGhpcy5vcHRpb25zID0gY29uZmlnO1xyXG5cclxuICAgICAgaWYgKHRoaXMub3B0aW9ucy5zb3VyY2UuZGF0YSkge1xyXG4gICAgICAgIHRoaXMucmVuZGVyKCk7XHJcbiAgICAgICAgdGhpcy5idWlsZExpc3QoKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICB0aGlzLmZldGNoRGF0YShmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICB0aGF0LnJlbmRlcigpO1xyXG4gICAgICAgICAgdGhhdC5idWlsZExpc3QoKTtcclxuICAgICAgICB9KTtcclxuICAgICAgfVxyXG5cclxuICAgICAgdGhpcy5jaGVja0Rpc2FibGVkKCk7XHJcbiAgICAgIHRoaXMuc2V0U3R5bGUoKTtcclxuICAgICAgdGhpcy5zZXRXaWR0aCgpO1xyXG5cclxuICAgICAgdGhpcy5zZXRTaXplKHRydWUpO1xyXG5cclxuICAgICAgdGhpcy4kZWxlbWVudC50cmlnZ2VyKCdyZWZyZXNoZWQnICsgRVZFTlRfS0VZKTtcclxuICAgIH0sXHJcblxyXG4gICAgaGlkZTogZnVuY3Rpb24gKCkge1xyXG4gICAgICB0aGlzLiRuZXdFbGVtZW50LmhpZGUoKTtcclxuICAgIH0sXHJcblxyXG4gICAgc2hvdzogZnVuY3Rpb24gKCkge1xyXG4gICAgICB0aGlzLiRuZXdFbGVtZW50LnNob3coKTtcclxuICAgIH0sXHJcblxyXG4gICAgcmVtb3ZlOiBmdW5jdGlvbiAoKSB7XHJcbiAgICAgIHRoaXMuJG5ld0VsZW1lbnQucmVtb3ZlKCk7XHJcbiAgICAgIHRoaXMuJGVsZW1lbnQucmVtb3ZlKCk7XHJcbiAgICB9LFxyXG5cclxuICAgIGRlc3Ryb3k6IGZ1bmN0aW9uICgpIHtcclxuICAgICAgdGhpcy4kbmV3RWxlbWVudC5iZWZvcmUodGhpcy4kZWxlbWVudCkucmVtb3ZlKCk7XHJcblxyXG4gICAgICBpZiAodGhpcy4kYnNDb250YWluZXIpIHtcclxuICAgICAgICB0aGlzLiRic0NvbnRhaW5lci5yZW1vdmUoKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICB0aGlzLiRtZW51LnJlbW92ZSgpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAodGhpcy5zZWxlY3RwaWNrZXIudmlldy50aXRsZU9wdGlvbiAmJiB0aGlzLnNlbGVjdHBpY2tlci52aWV3LnRpdGxlT3B0aW9uLnBhcmVudE5vZGUpIHtcclxuICAgICAgICB0aGlzLnNlbGVjdHBpY2tlci52aWV3LnRpdGxlT3B0aW9uLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQodGhpcy5zZWxlY3RwaWNrZXIudmlldy50aXRsZU9wdGlvbik7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHRoaXMuJGVsZW1lbnRcclxuICAgICAgICAub2ZmKEVWRU5UX0tFWSlcclxuICAgICAgICAucmVtb3ZlRGF0YSgnc2VsZWN0cGlja2VyJylcclxuICAgICAgICAucmVtb3ZlQ2xhc3MoJ2JzLXNlbGVjdC1oaWRkZW4gc2VsZWN0cGlja2VyJyk7XHJcblxyXG4gICAgICAkKHdpbmRvdykub2ZmKEVWRU5UX0tFWSArICcuJyArIHRoaXMuc2VsZWN0SWQpO1xyXG4gICAgfVxyXG4gIH07XHJcblxyXG4gIC8vIFNFTEVDVFBJQ0tFUiBQTFVHSU4gREVGSU5JVElPTlxyXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxyXG4gIGZ1bmN0aW9uIFBsdWdpbiAob3B0aW9uKSB7XHJcbiAgICAvLyBnZXQgdGhlIGFyZ3Mgb2YgdGhlIG91dGVyIGZ1bmN0aW9uLi5cclxuICAgIHZhciBhcmdzID0gYXJndW1lbnRzO1xyXG4gICAgLy8gVGhlIGFyZ3VtZW50cyBvZiB0aGUgZnVuY3Rpb24gYXJlIGV4cGxpY2l0bHkgcmUtZGVmaW5lZCBmcm9tIHRoZSBhcmd1bWVudCBsaXN0LCBiZWNhdXNlIHRoZSBzaGlmdCBjYXVzZXMgdGhlbVxyXG4gICAgLy8gdG8gZ2V0IGxvc3QvY29ycnVwdGVkIGluIGFuZHJvaWQgMi4zIGFuZCBJRTkgIzcxNSAjNzc1XHJcbiAgICB2YXIgX29wdGlvbiA9IG9wdGlvbjtcclxuXHJcbiAgICBbXS5zaGlmdC5hcHBseShhcmdzKTtcclxuXHJcbiAgICAvLyBpZiB0aGUgdmVyc2lvbiB3YXMgbm90IHNldCBzdWNjZXNzZnVsbHlcclxuICAgIGlmICghdmVyc2lvbi5zdWNjZXNzKSB7XHJcbiAgICAgIC8vIHRyeSB0byByZXRyZWl2ZSBpdCBhZ2FpblxyXG4gICAgICB0cnkge1xyXG4gICAgICAgIHZlcnNpb24uZnVsbCA9IChnZXRWZXJzaW9uKCkgfHwgJycpLnNwbGl0KCcgJylbMF0uc3BsaXQoJy4nKTtcclxuICAgICAgfSBjYXRjaCAoZXJyKSB7XHJcbiAgICAgICAgLy8gZmFsbCBiYWNrIHRvIHVzZSBCb290c3RyYXBWZXJzaW9uIGlmIHNldFxyXG4gICAgICAgIGlmIChTZWxlY3RwaWNrZXIuQm9vdHN0cmFwVmVyc2lvbikge1xyXG4gICAgICAgICAgdmVyc2lvbi5mdWxsID0gU2VsZWN0cGlja2VyLkJvb3RzdHJhcFZlcnNpb24uc3BsaXQoJyAnKVswXS5zcGxpdCgnLicpO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICB2ZXJzaW9uLmZ1bGwgPSBbdmVyc2lvbi5tYWpvciwgJzAnLCAnMCddO1xyXG5cclxuICAgICAgICAgIGNvbnNvbGUud2FybihcclxuICAgICAgICAgICAgJ1RoZXJlIHdhcyBhbiBpc3N1ZSByZXRyaWV2aW5nIEJvb3RzdHJhcFxcJ3MgdmVyc2lvbi4gJyArXHJcbiAgICAgICAgICAgICdFbnN1cmUgQm9vdHN0cmFwIGlzIGJlaW5nIGxvYWRlZCBiZWZvcmUgYm9vdHN0cmFwLXNlbGVjdCBhbmQgdGhlcmUgaXMgbm8gbmFtZXNwYWNlIGNvbGxpc2lvbi4gJyArXHJcbiAgICAgICAgICAgICdJZiBsb2FkaW5nIEJvb3RzdHJhcCBhc3luY2hyb25vdXNseSwgdGhlIHZlcnNpb24gbWF5IG5lZWQgdG8gYmUgbWFudWFsbHkgc3BlY2lmaWVkIHZpYSAkLmZuLnNlbGVjdHBpY2tlci5Db25zdHJ1Y3Rvci5Cb290c3RyYXBWZXJzaW9uLicsXHJcbiAgICAgICAgICAgIGVyclxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHZlcnNpb24ubWFqb3IgPSB2ZXJzaW9uLmZ1bGxbMF07XHJcbiAgICAgIHZlcnNpb24uc3VjY2VzcyA9IHRydWU7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHZlcnNpb24ubWFqb3IgPj0gJzQnKSB7XHJcbiAgICAgIC8vIHNvbWUgZGVmYXVsdHMgbmVlZCB0byBiZSBjaGFuZ2VkIGlmIHVzaW5nIEJvb3RzdHJhcCA0XHJcbiAgICAgIC8vIGNoZWNrIHRvIHNlZSBpZiB0aGV5IGhhdmUgYWxyZWFkeSBiZWVuIG1hbnVhbGx5IGNoYW5nZWQgYmVmb3JlIGZvcmNpbmcgdGhlbSB0byB1cGRhdGVcclxuICAgICAgdmFyIHRvVXBkYXRlID0gW107XHJcblxyXG4gICAgICBpZiAoU2VsZWN0cGlja2VyLkRFRkFVTFRTLnN0eWxlID09PSBjbGFzc05hbWVzLkJVVFRPTkNMQVNTKSB0b1VwZGF0ZS5wdXNoKHsgbmFtZTogJ3N0eWxlJywgY2xhc3NOYW1lOiAnQlVUVE9OQ0xBU1MnIH0pO1xyXG4gICAgICBpZiAoU2VsZWN0cGlja2VyLkRFRkFVTFRTLmljb25CYXNlID09PSBjbGFzc05hbWVzLklDT05CQVNFKSB0b1VwZGF0ZS5wdXNoKHsgbmFtZTogJ2ljb25CYXNlJywgY2xhc3NOYW1lOiAnSUNPTkJBU0UnIH0pO1xyXG4gICAgICBpZiAoU2VsZWN0cGlja2VyLkRFRkFVTFRTLnRpY2tJY29uID09PSBjbGFzc05hbWVzLlRJQ0tJQ09OKSB0b1VwZGF0ZS5wdXNoKHsgbmFtZTogJ3RpY2tJY29uJywgY2xhc3NOYW1lOiAnVElDS0lDT04nIH0pO1xyXG5cclxuICAgICAgY2xhc3NOYW1lcy5ESVZJREVSID0gJ2Ryb3Bkb3duLWRpdmlkZXInO1xyXG4gICAgICBjbGFzc05hbWVzLlNIT1cgPSAnc2hvdyc7XHJcbiAgICAgIGNsYXNzTmFtZXMuQlVUVE9OQ0xBU1MgPSAnYnRuLWxpZ2h0JztcclxuICAgICAgY2xhc3NOYW1lcy5QT1BPVkVSSEVBREVSID0gJ3BvcG92ZXItaGVhZGVyJztcclxuICAgICAgY2xhc3NOYW1lcy5JQ09OQkFTRSA9ICcnO1xyXG4gICAgICBjbGFzc05hbWVzLlRJQ0tJQ09OID0gJ2JzLW9rLWRlZmF1bHQnO1xyXG5cclxuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0b1VwZGF0ZS5sZW5ndGg7IGkrKykge1xyXG4gICAgICAgIHZhciBvcHRpb24gPSB0b1VwZGF0ZVtpXTtcclxuICAgICAgICBTZWxlY3RwaWNrZXIuREVGQVVMVFNbb3B0aW9uLm5hbWVdID0gY2xhc3NOYW1lc1tvcHRpb24uY2xhc3NOYW1lXTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIGlmICh2ZXJzaW9uLm1ham9yID4gJzQnKSB7XHJcbiAgICAgIFNlbGVjdG9yLkRBVEFfVE9HR0xFID0gJ2RhdGEtYnMtdG9nZ2xlPVwiZHJvcGRvd25cIidcclxuICAgIH1cclxuXHJcbiAgICB2YXIgdmFsdWU7XHJcbiAgICB2YXIgY2hhaW4gPSB0aGlzLmVhY2goZnVuY3Rpb24gKCkge1xyXG4gICAgICB2YXIgJHRoaXMgPSAkKHRoaXMpO1xyXG4gICAgICBpZiAoJHRoaXMuaXMoJ3NlbGVjdCcpKSB7XHJcbiAgICAgICAgdmFyIGRhdGEgPSAkdGhpcy5kYXRhKCdzZWxlY3RwaWNrZXInKSxcclxuICAgICAgICAgICAgb3B0aW9ucyA9IHR5cGVvZiBfb3B0aW9uID09ICdvYmplY3QnICYmIF9vcHRpb247XHJcblxyXG4gICAgICAgIC8vIGZvciBiYWNrd2FyZHMgY29tcGF0aWJpbGl0eVxyXG4gICAgICAgIC8vICh1c2luZyB0aXRsZSBhcyBwbGFjZWhvbGRlciBpcyBkZXByZWNhdGVkIC0gcmVtb3ZlIGluIHYyLjAuMClcclxuICAgICAgICBpZiAob3B0aW9ucy50aXRsZSkgb3B0aW9ucy5wbGFjZWhvbGRlciA9IG9wdGlvbnMudGl0bGU7XHJcblxyXG4gICAgICAgIGlmICghZGF0YSkge1xyXG4gICAgICAgICAgdmFyIGRhdGFBdHRyaWJ1dGVzID0gJHRoaXMuZGF0YSgpO1xyXG5cclxuICAgICAgICAgIGZvciAodmFyIGRhdGFBdHRyIGluIGRhdGFBdHRyaWJ1dGVzKSB7XHJcbiAgICAgICAgICAgIGlmIChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoZGF0YUF0dHJpYnV0ZXMsIGRhdGFBdHRyKSAmJiAkLmluQXJyYXkoZGF0YUF0dHIsIERJU0FMTE9XRURfQVRUUklCVVRFUykgIT09IC0xKSB7XHJcbiAgICAgICAgICAgICAgZGVsZXRlIGRhdGFBdHRyaWJ1dGVzW2RhdGFBdHRyXTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG5cclxuICAgICAgICAgIHZhciBjb25maWcgPSAkLmV4dGVuZCh7fSwgU2VsZWN0cGlja2VyLkRFRkFVTFRTLCAkLmZuLnNlbGVjdHBpY2tlci5kZWZhdWx0cyB8fCB7fSwgZ2V0QXR0cmlidXRlc09iamVjdCgkdGhpcyksIGRhdGFBdHRyaWJ1dGVzLCBvcHRpb25zKTsgLy8gdGhpcyBpcyBjb3JyZWN0IG9yZGVyIG9uIGluaXRpYWwgcmVuZGVyXHJcbiAgICAgICAgICBjb25maWcudGVtcGxhdGUgPSAkLmV4dGVuZCh7fSwgU2VsZWN0cGlja2VyLkRFRkFVTFRTLnRlbXBsYXRlLCAoJC5mbi5zZWxlY3RwaWNrZXIuZGVmYXVsdHMgPyAkLmZuLnNlbGVjdHBpY2tlci5kZWZhdWx0cy50ZW1wbGF0ZSA6IHt9KSwgZGF0YUF0dHJpYnV0ZXMudGVtcGxhdGUsIG9wdGlvbnMudGVtcGxhdGUpO1xyXG4gICAgICAgICAgJHRoaXMuZGF0YSgnc2VsZWN0cGlja2VyJywgKGRhdGEgPSBuZXcgU2VsZWN0cGlja2VyKHRoaXMsIGNvbmZpZykpKTtcclxuICAgICAgICB9IGVsc2UgaWYgKG9wdGlvbnMpIHtcclxuICAgICAgICAgIGZvciAodmFyIGkgaW4gb3B0aW9ucykge1xyXG4gICAgICAgICAgICBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9wdGlvbnMsIGkpKSB7XHJcbiAgICAgICAgICAgICAgZGF0YS5vcHRpb25zW2ldID0gb3B0aW9uc1tpXTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgaWYgKHR5cGVvZiBfb3B0aW9uID09ICdzdHJpbmcnKSB7XHJcbiAgICAgICAgICBpZiAoZGF0YVtfb3B0aW9uXSBpbnN0YW5jZW9mIEZ1bmN0aW9uKSB7XHJcbiAgICAgICAgICAgIHZhbHVlID0gZGF0YVtfb3B0aW9uXS5hcHBseShkYXRhLCBhcmdzKTtcclxuICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIHZhbHVlID0gZGF0YS5vcHRpb25zW19vcHRpb25dO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfSk7XHJcblxyXG4gICAgaWYgKHR5cGVvZiB2YWx1ZSAhPT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgLy8gbm9pbnNwZWN0aW9uIEpTVW51c2VkQXNzaWdubWVudFxyXG4gICAgICByZXR1cm4gdmFsdWU7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICByZXR1cm4gY2hhaW47XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICB2YXIgb2xkID0gJC5mbi5zZWxlY3RwaWNrZXI7XHJcbiAgJC5mbi5zZWxlY3RwaWNrZXIgPSBQbHVnaW47XHJcbiAgJC5mbi5zZWxlY3RwaWNrZXIuQ29uc3RydWN0b3IgPSBTZWxlY3RwaWNrZXI7XHJcblxyXG4gIC8vIFNFTEVDVFBJQ0tFUiBOTyBDT05GTElDVFxyXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PVxyXG4gICQuZm4uc2VsZWN0cGlja2VyLm5vQ29uZmxpY3QgPSBmdW5jdGlvbiAoKSB7XHJcbiAgICAkLmZuLnNlbGVjdHBpY2tlciA9IG9sZDtcclxuICAgIHJldHVybiB0aGlzO1xyXG4gIH07XHJcblxyXG4gIC8vIGdldCBCb290c3RyYXAncyBrZXlkb3duIGV2ZW50IGhhbmRsZXIgZm9yIGVpdGhlciBCb290c3RyYXAgNCBvciBCb290c3RyYXAgM1xyXG4gIGZ1bmN0aW9uIGtleWRvd25IYW5kbGVyICgpIHtcclxuICAgIGlmICh2ZXJzaW9uLm1ham9yIDwgNSkge1xyXG4gICAgICBpZiAoJC5mbi5kcm9wZG93bikge1xyXG4gICAgICAgIC8vIHdhaXQgdG8gZGVmaW5lIHVudGlsIGZ1bmN0aW9uIGlzIGNhbGxlZCBpbiBjYXNlIEJvb3RzdHJhcCBpc24ndCBsb2FkZWQgeWV0XHJcbiAgICAgICAgdmFyIGJvb3RzdHJhcEtleWRvd24gPSAkLmZuLmRyb3Bkb3duLkNvbnN0cnVjdG9yLl9kYXRhQXBpS2V5ZG93bkhhbmRsZXIgfHwgJC5mbi5kcm9wZG93bi5Db25zdHJ1Y3Rvci5wcm90b3R5cGUua2V5ZG93bjtcclxuICAgICAgICByZXR1cm4gYm9vdHN0cmFwS2V5ZG93bi5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xyXG4gICAgICB9XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICByZXR1cm4gRHJvcGRvd24uZGF0YUFwaUtleWRvd25IYW5kbGVyO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgJChkb2N1bWVudClcclxuICAgIC5vZmYoJ2tleWRvd24uYnMuZHJvcGRvd24uZGF0YS1hcGknKVxyXG4gICAgLm9uKCdrZXlkb3duLmJzLmRyb3Bkb3duLmRhdGEtYXBpJywgJzpub3QoLmJvb3RzdHJhcC1zZWxlY3QpID4gWycgKyBTZWxlY3Rvci5EQVRBX1RPR0dMRSArICddJywga2V5ZG93bkhhbmRsZXIpXHJcbiAgICAub24oJ2tleWRvd24uYnMuZHJvcGRvd24uZGF0YS1hcGknLCAnOm5vdCguYm9vdHN0cmFwLXNlbGVjdCkgPiAuZHJvcGRvd24tbWVudScsIGtleWRvd25IYW5kbGVyKVxyXG4gICAgLm9uKCdrZXlkb3duJyArIEVWRU5UX0tFWSwgJy5ib290c3RyYXAtc2VsZWN0IFsnICsgU2VsZWN0b3IuREFUQV9UT0dHTEUgKyAnXSwgLmJvb3RzdHJhcC1zZWxlY3QgW3JvbGU9XCJsaXN0Ym94XCJdLCAuYm9vdHN0cmFwLXNlbGVjdCAuYnMtc2VhcmNoYm94IGlucHV0JywgU2VsZWN0cGlja2VyLnByb3RvdHlwZS5rZXlkb3duKVxyXG4gICAgLm9uKCdmb2N1c2luLm1vZGFsJywgJy5ib290c3RyYXAtc2VsZWN0IFsnICsgU2VsZWN0b3IuREFUQV9UT0dHTEUgKyAnXSwgLmJvb3RzdHJhcC1zZWxlY3QgW3JvbGU9XCJsaXN0Ym94XCJdLCAuYm9vdHN0cmFwLXNlbGVjdCAuYnMtc2VhcmNoYm94IGlucHV0JywgZnVuY3Rpb24gKGUpIHtcclxuICAgICAgZS5zdG9wUHJvcGFnYXRpb24oKTtcclxuICAgIH0pO1xyXG5cclxuICAvLyBTRUxFQ1RQSUNLRVIgREFUQS1BUElcclxuICAvLyA9PT09PT09PT09PT09PT09PT09PT1cclxuICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCdET01Db250ZW50TG9hZGVkJywgZnVuY3Rpb24gKCkge1xyXG4gICAgJCgnLnNlbGVjdHBpY2tlcicpLmVhY2goZnVuY3Rpb24gKCkge1xyXG4gICAgICB2YXIgJHNlbGVjdHBpY2tlciA9ICQodGhpcyk7XHJcbiAgICAgIFBsdWdpbi5jYWxsKCRzZWxlY3RwaWNrZXIsICRzZWxlY3RwaWNrZXIuZGF0YSgpKTtcclxuICAgIH0pXHJcbiAgfSk7XHJcbn0pKGpRdWVyeSk7XHJcblxyXG5cclxufSkpO1xuLy8jIHNvdXJjZU1hcHBpbmdVUkw9Ym9vdHN0cmFwLXNlbGVjdC5qcy5tYXAiXSwic291cmNlUm9vdCI6IiJ9";
        
        $__internal_085b0142806202599c7fe3b329164a92397d8978207a37e79d70b8c52599e33e->leave($__internal_085b0142806202599c7fe3b329164a92397d8978207a37e79d70b8c52599e33e_prof);

        
        $__internal_319393461309892924ff6e74d6d6e64287df64b63545b994e100d4ab223aed02->leave($__internal_319393461309892924ff6e74d6d6e64287df64b63545b994e100d4ab223aed02_prof);

        return; yield '';
    }

    /**
     * @codeCoverageIgnore
     */
    public function getTemplateName()
    {
        return "@public_path/build/vendors-node_modules_bootstrap-select_dist_js_bootstrap-select_js.js";
    }

    /**
     * @codeCoverageIgnore
     */
    public function getDebugInfo()
    {
        return array ();
    }

    public function getSourceContext()
    {
        return new Source("(self[\"webpackChunk\"] = self[\"webpackChunk\"] || []).push([[\"vendors-node_modules_bootstrap-select_dist_js_bootstrap-select_js\"],{

/***/ \"./node_modules/bootstrap-select/dist/js/bootstrap-select.js\":
/*!*******************************************************************!*\\
  !*** ./node_modules/bootstrap-select/dist/js/bootstrap-select.js ***!
  \\*******************************************************************/
/***/ (function(module, exports, __webpack_require__) {

var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*!
 * Bootstrap-select v1.14.0-beta2 (https://developer.snapappointments.com/bootstrap-select)
 *
 * Copyright 2012-2021 SnapAppointments, LLC
 * Licensed under MIT (https://github.com/snapappointments/bootstrap-select/blob/master/LICENSE)
 */

(function (root, factory) {
  if (root === undefined && window !== undefined) root = window;
  if (true) {
    // AMD. Register as an anonymous module unless amdModuleId is set
    !(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(/*! jquery */ \"./node_modules/jquery/dist/jquery.js\")], __WEBPACK_AMD_DEFINE_RESULT__ = (function (a0) {
      return (factory(a0));
    }).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__),
\t\t__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
  } else {}
}(this, function (jQuery) {

(function (\$) {
  'use strict';

  var DISALLOWED_ATTRIBUTES = ['sanitize', 'whiteList', 'sanitizeFn'];

  var uriAttrs = [
    'background',
    'cite',
    'href',
    'itemtype',
    'longdesc',
    'poster',
    'src',
    'xlink:href'
  ];

  var ARIA_ATTRIBUTE_PATTERN = /^aria-[\\w-]*\$/i;

  var DefaultWhitelist = {
    // Global attributes allowed on any supplied element below.
    '*': ['class', 'dir', 'id', 'lang', 'role', 'tabindex', 'style', ARIA_ATTRIBUTE_PATTERN],
    a: ['target', 'href', 'title', 'rel'],
    area: [],
    b: [],
    br: [],
    col: [],
    code: [],
    div: [],
    em: [],
    hr: [],
    h1: [],
    h2: [],
    h3: [],
    h4: [],
    h5: [],
    h6: [],
    i: [],
    img: ['src', 'alt', 'title', 'width', 'height'],
    li: [],
    ol: [],
    p: [],
    pre: [],
    s: [],
    small: [],
    span: [],
    sub: [],
    sup: [],
    strong: [],
    u: [],
    ul: []
  }

  /**
   * A pattern that recognizes a commonly useful subset of URLs that are safe.
   *
   * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
   */
  var SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file):|[^&:/?#]*(?:[/?#]|\$))/gi;

  /**
   * A pattern that matches safe data URLs. Only matches image, video and audio types.
   *
   * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
   */
  var DATA_URL_PATTERN = /^data:(?:image\\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\\/(?:mpeg|mp4|ogg|webm)|audio\\/(?:mp3|oga|ogg|opus));base64,[a-z0-9+/]+=*\$/i;

  var ParseableAttributes = ['title', 'placeholder']; // attributes to use as settings, can add others in the future

  function allowedAttribute (attr, allowedAttributeList) {
    var attrName = attr.nodeName.toLowerCase()

    if (\$.inArray(attrName, allowedAttributeList) !== -1) {
      if (\$.inArray(attrName, uriAttrs) !== -1) {
        return Boolean(attr.nodeValue.match(SAFE_URL_PATTERN) || attr.nodeValue.match(DATA_URL_PATTERN))
      }

      return true
    }

    var regExp = \$(allowedAttributeList).filter(function (index, value) {
      return value instanceof RegExp
    })

    // Check if a regular expression validates the attribute.
    for (var i = 0, l = regExp.length; i < l; i++) {
      if (attrName.match(regExp[i])) {
        return true
      }
    }

    return false
  }

  function sanitizeHtml (unsafeElements, whiteList, sanitizeFn) {
    if (sanitizeFn && typeof sanitizeFn === 'function') {
      return sanitizeFn(unsafeElements);
    }

    var whitelistKeys = Object.keys(whiteList);

    for (var i = 0, len = unsafeElements.length; i < len; i++) {
      var elements = unsafeElements[i].querySelectorAll('*');

      for (var j = 0, len2 = elements.length; j < len2; j++) {
        var el = elements[j];
        var elName = el.nodeName.toLowerCase();

        if (whitelistKeys.indexOf(elName) === -1) {
          el.parentNode.removeChild(el);

          continue;
        }

        var attributeList = [].slice.call(el.attributes);
        var whitelistedAttributes = [].concat(whiteList['*'] || [], whiteList[elName] || []);

        for (var k = 0, len3 = attributeList.length; k < len3; k++) {
          var attr = attributeList[k];

          if (!allowedAttribute(attr, whitelistedAttributes)) {
            el.removeAttribute(attr.nodeName);
          }
        }
      }
    }
  }

  function getAttributesObject (\$select) {
    var attributesObject = {},
        attrVal;

    ParseableAttributes.forEach(function (item) {
      attrVal = \$select.attr(item);
      if (attrVal) attributesObject[item] = attrVal;
    });

    // for backwards compatibility
    // (using title as placeholder is deprecated - remove in v2.0.0)
    if (!attributesObject.placeholder && attributesObject.title) {
      attributesObject.placeholder = attributesObject.title;
    }

    return attributesObject;
  }

  // Polyfill for browsers with no classList support
  // Remove in v2
  if (!('classList' in document.createElement('_'))) {
    (function (view) {
      if (!('Element' in view)) return;

      var classListProp = 'classList',
          protoProp = 'prototype',
          elemCtrProto = view.Element[protoProp],
          objCtr = Object,
          classListGetter = function () {
            var \$elem = \$(this);

            return {
              add: function (classes) {
                classes = Array.prototype.slice.call(arguments).join(' ');
                return \$elem.addClass(classes);
              },
              remove: function (classes) {
                classes = Array.prototype.slice.call(arguments).join(' ');
                return \$elem.removeClass(classes);
              },
              toggle: function (classes, force) {
                return \$elem.toggleClass(classes, force);
              },
              contains: function (classes) {
                return \$elem.hasClass(classes);
              }
            }
          };

      if (objCtr.defineProperty) {
        var classListPropDesc = {
          get: classListGetter,
          enumerable: true,
          configurable: true
        };
        try {
          objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
        } catch (ex) { // IE 8 doesn't support enumerable:true
          // adding undefined to fight this issue https://github.com/eligrey/classList.js/issues/36
          // modernie IE8-MSW7 machine has IE8 8.0.6001.18702 and is affected
          if (ex.number === undefined || ex.number === -0x7FF5EC54) {
            classListPropDesc.enumerable = false;
            objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
          }
        }
      } else if (objCtr[protoProp].__defineGetter__) {
        elemCtrProto.__defineGetter__(classListProp, classListGetter);
      }
    }(window));
  }

  var testElement = document.createElement('_');

  testElement.classList.add('c1', 'c2');

  if (!testElement.classList.contains('c2')) {
    var _add = DOMTokenList.prototype.add,
        _remove = DOMTokenList.prototype.remove;

    DOMTokenList.prototype.add = function () {
      Array.prototype.forEach.call(arguments, _add.bind(this));
    }

    DOMTokenList.prototype.remove = function () {
      Array.prototype.forEach.call(arguments, _remove.bind(this));
    }
  }

  testElement.classList.toggle('c3', false);

  // Polyfill for IE 10 and Firefox <24, where classList.toggle does not
  // support the second argument.
  if (testElement.classList.contains('c3')) {
    var _toggle = DOMTokenList.prototype.toggle;

    DOMTokenList.prototype.toggle = function (token, force) {
      if (1 in arguments && !this.contains(token) === !force) {
        return force;
      } else {
        return _toggle.call(this, token);
      }
    };
  }

  testElement = null;

  // shallow array comparison
  function isEqual (array1, array2) {
    return array1.length === array2.length && array1.every(function (element, index) {
      return element === array2[index];
    });
  };

  // <editor-fold desc=\"Shims\">
  if (!String.prototype.startsWith) {
    (function () {
      'use strict'; // needed to support `apply`/`call` with `undefined`/`null`
      var toString = {}.toString;
      var startsWith = function (search) {
        if (this == null) {
          throw new TypeError();
        }
        var string = String(this);
        if (search && toString.call(search) == '[object RegExp]') {
          throw new TypeError();
        }
        var stringLength = string.length;
        var searchString = String(search);
        var searchLength = searchString.length;
        var position = arguments.length > 1 ? arguments[1] : undefined;
        // `ToInteger`
        var pos = position ? Number(position) : 0;
        if (pos != pos) { // better `isNaN`
          pos = 0;
        }
        var start = Math.min(Math.max(pos, 0), stringLength);
        // Avoid the `indexOf` call if no match is possible
        if (searchLength + start > stringLength) {
          return false;
        }
        var index = -1;
        while (++index < searchLength) {
          if (string.charCodeAt(start + index) != searchString.charCodeAt(index)) {
            return false;
          }
        }
        return true;
      };
      if (Object.defineProperty) {
        Object.defineProperty(String.prototype, 'startsWith', {
          'value': startsWith,
          'configurable': true,
          'writable': true
        });
      } else {
        String.prototype.startsWith = startsWith;
      }
    }());
  }

  function getSelectedOptions () {
    var selectedOptions = this.selectpicker.main.data.filter(function (item) {
      if (item.selected) {
        if (this.options.hideDisabled && item.disabled) return false;
        return true;
      }

      return false;
    }, this);

    // ensure only 1 option is selected if multiple are set in the data source
    if (this.options.source.data && !this.multiple && selectedOptions.length > 1) {
      for (var i = 0; i < selectedOptions.length - 1; i++) {
        selectedOptions[i].selected = false;
      }

      selectedOptions = [ selectedOptions[selectedOptions.length - 1] ];
    }

    return selectedOptions;
  }

  // much faster than \$.val()
  function getSelectValues (selectedOptions) {
    var value = [],
        options = selectedOptions || getSelectedOptions.call(this),
        opt;

    for (var i = 0, len = options.length; i < len; i++) {
      opt = options[i];

      if (!opt.disabled) {
        value.push(opt.value === undefined ? opt.text : opt.value);
      }
    }

    if (!this.multiple) {
      return !value.length ? null : value[0];
    }

    return value;
  }

  // set data-selected on select element if the value has been programmatically selected
  // prior to initialization of bootstrap-select
  // * consider removing or replacing an alternative method *
  var valHooks = {
    useDefault: false,
    _set: \$.valHooks.select.set
  };

  \$.valHooks.select.set = function (elem, value) {
    if (value && !valHooks.useDefault) \$(elem).data('selected', true);

    return valHooks._set.apply(this, arguments);
  };

  var changedArguments = null;

  var EventIsSupported = (function () {
    try {
      new Event('change');
      return true;
    } catch (e) {
      return false;
    }
  })();

  \$.fn.triggerNative = function (eventName) {
    var el = this[0],
        event;

    if (el.dispatchEvent) { // for modern browsers & IE9+
      if (EventIsSupported) {
        // For modern browsers
        event = new Event(eventName, {
          bubbles: true
        });
      } else {
        // For IE since it doesn't support Event constructor
        event = document.createEvent('Event');
        event.initEvent(eventName, true, false);
      }

      el.dispatchEvent(event);
    }
  };
  // </editor-fold>

  function stringSearch (li, searchString, method, normalize) {
    var stringTypes = [
          'display',
          'subtext',
          'tokens'
        ],
        searchSuccess = false;

    for (var i = 0; i < stringTypes.length; i++) {
      var stringType = stringTypes[i],
          string = li[stringType];

      if (string) {
        string = string.toString();

        // Strip HTML tags. This isn't perfect, but it's much faster than any other method
        if (stringType === 'display') {
          string = string.replace(/<[^>]+>/g, '');
        }

        if (normalize) string = normalizeToBase(string);
        string = string.toUpperCase();

        if (typeof method === 'function') {
          searchSuccess = method(string, searchString);
        } else if (method === 'contains') {
          searchSuccess = string.indexOf(searchString) >= 0;
        } else {
          searchSuccess = string.startsWith(searchString);
        }

        if (searchSuccess) break;
      }
    }

    return searchSuccess;
  }

  function toInteger (value) {
    return parseInt(value, 10) || 0;
  }

  // Borrowed from Lodash (_.deburr)
  /** Used to map Latin Unicode letters to basic Latin letters. */
  var deburredLetters = {
    // Latin-1 Supplement block.
    '\\xc0': 'A',  '\\xc1': 'A', '\\xc2': 'A', '\\xc3': 'A', '\\xc4': 'A', '\\xc5': 'A',
    '\\xe0': 'a',  '\\xe1': 'a', '\\xe2': 'a', '\\xe3': 'a', '\\xe4': 'a', '\\xe5': 'a',
    '\\xc7': 'C',  '\\xe7': 'c',
    '\\xd0': 'D',  '\\xf0': 'd',
    '\\xc8': 'E',  '\\xc9': 'E', '\\xca': 'E', '\\xcb': 'E',
    '\\xe8': 'e',  '\\xe9': 'e', '\\xea': 'e', '\\xeb': 'e',
    '\\xcc': 'I',  '\\xcd': 'I', '\\xce': 'I', '\\xcf': 'I',
    '\\xec': 'i',  '\\xed': 'i', '\\xee': 'i', '\\xef': 'i',
    '\\xd1': 'N',  '\\xf1': 'n',
    '\\xd2': 'O',  '\\xd3': 'O', '\\xd4': 'O', '\\xd5': 'O', '\\xd6': 'O', '\\xd8': 'O',
    '\\xf2': 'o',  '\\xf3': 'o', '\\xf4': 'o', '\\xf5': 'o', '\\xf6': 'o', '\\xf8': 'o',
    '\\xd9': 'U',  '\\xda': 'U', '\\xdb': 'U', '\\xdc': 'U',
    '\\xf9': 'u',  '\\xfa': 'u', '\\xfb': 'u', '\\xfc': 'u',
    '\\xdd': 'Y',  '\\xfd': 'y', '\\xff': 'y',
    '\\xc6': 'Ae', '\\xe6': 'ae',
    '\\xde': 'Th', '\\xfe': 'th',
    '\\xdf': 'ss',
    // Latin Extended-A block.
    '\\u0100': 'A',  '\\u0102': 'A', '\\u0104': 'A',
    '\\u0101': 'a',  '\\u0103': 'a', '\\u0105': 'a',
    '\\u0106': 'C',  '\\u0108': 'C', '\\u010a': 'C', '\\u010c': 'C',
    '\\u0107': 'c',  '\\u0109': 'c', '\\u010b': 'c', '\\u010d': 'c',
    '\\u010e': 'D',  '\\u0110': 'D', '\\u010f': 'd', '\\u0111': 'd',
    '\\u0112': 'E',  '\\u0114': 'E', '\\u0116': 'E', '\\u0118': 'E', '\\u011a': 'E',
    '\\u0113': 'e',  '\\u0115': 'e', '\\u0117': 'e', '\\u0119': 'e', '\\u011b': 'e',
    '\\u011c': 'G',  '\\u011e': 'G', '\\u0120': 'G', '\\u0122': 'G',
    '\\u011d': 'g',  '\\u011f': 'g', '\\u0121': 'g', '\\u0123': 'g',
    '\\u0124': 'H',  '\\u0126': 'H', '\\u0125': 'h', '\\u0127': 'h',
    '\\u0128': 'I',  '\\u012a': 'I', '\\u012c': 'I', '\\u012e': 'I', '\\u0130': 'I',
    '\\u0129': 'i',  '\\u012b': 'i', '\\u012d': 'i', '\\u012f': 'i', '\\u0131': 'i',
    '\\u0134': 'J',  '\\u0135': 'j',
    '\\u0136': 'K',  '\\u0137': 'k', '\\u0138': 'k',
    '\\u0139': 'L',  '\\u013b': 'L', '\\u013d': 'L', '\\u013f': 'L', '\\u0141': 'L',
    '\\u013a': 'l',  '\\u013c': 'l', '\\u013e': 'l', '\\u0140': 'l', '\\u0142': 'l',
    '\\u0143': 'N',  '\\u0145': 'N', '\\u0147': 'N', '\\u014a': 'N',
    '\\u0144': 'n',  '\\u0146': 'n', '\\u0148': 'n', '\\u014b': 'n',
    '\\u014c': 'O',  '\\u014e': 'O', '\\u0150': 'O',
    '\\u014d': 'o',  '\\u014f': 'o', '\\u0151': 'o',
    '\\u0154': 'R',  '\\u0156': 'R', '\\u0158': 'R',
    '\\u0155': 'r',  '\\u0157': 'r', '\\u0159': 'r',
    '\\u015a': 'S',  '\\u015c': 'S', '\\u015e': 'S', '\\u0160': 'S',
    '\\u015b': 's',  '\\u015d': 's', '\\u015f': 's', '\\u0161': 's',
    '\\u0162': 'T',  '\\u0164': 'T', '\\u0166': 'T',
    '\\u0163': 't',  '\\u0165': 't', '\\u0167': 't',
    '\\u0168': 'U',  '\\u016a': 'U', '\\u016c': 'U', '\\u016e': 'U', '\\u0170': 'U', '\\u0172': 'U',
    '\\u0169': 'u',  '\\u016b': 'u', '\\u016d': 'u', '\\u016f': 'u', '\\u0171': 'u', '\\u0173': 'u',
    '\\u0174': 'W',  '\\u0175': 'w',
    '\\u0176': 'Y',  '\\u0177': 'y', '\\u0178': 'Y',
    '\\u0179': 'Z',  '\\u017b': 'Z', '\\u017d': 'Z',
    '\\u017a': 'z',  '\\u017c': 'z', '\\u017e': 'z',
    '\\u0132': 'IJ', '\\u0133': 'ij',
    '\\u0152': 'Oe', '\\u0153': 'oe',
    '\\u0149': \"'n\", '\\u017f': 's'
  };

  /** Used to match Latin Unicode letters (excluding mathematical operators). */
  var reLatin = /[\\xc0-\\xd6\\xd8-\\xf6\\xf8-\\xff\\u0100-\\u017f]/g;

  /** Used to compose unicode character classes. */
  var rsComboMarksRange = '\\\\u0300-\\\\u036f',
      reComboHalfMarksRange = '\\\\ufe20-\\\\ufe2f',
      rsComboSymbolsRange = '\\\\u20d0-\\\\u20ff',
      rsComboMarksExtendedRange = '\\\\u1ab0-\\\\u1aff',
      rsComboMarksSupplementRange = '\\\\u1dc0-\\\\u1dff',
      rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange + rsComboMarksExtendedRange + rsComboMarksSupplementRange;

  /** Used to compose unicode capture groups. */
  var rsCombo = '[' + rsComboRange + ']';

  /**
   * Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks) and
   * [combining diacritical marks for symbols](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks_for_Symbols).
   */
  var reComboMark = RegExp(rsCombo, 'g');

  function deburrLetter (key) {
    return deburredLetters[key];
  };

  function normalizeToBase (string) {
    string = string.toString();
    return string && string.replace(reLatin, deburrLetter).replace(reComboMark, '');
  }

  // List of HTML entities for escaping.
  var escapeMap = {
    '&': '&amp;',
    '<': '&lt;',
    '>': '&gt;',
    '\"': '&quot;',
    \"'\": '&#x27;',
    '`': '&#x60;'
  };

  // Functions for escaping and unescaping strings to/from HTML interpolation.
  var createEscaper = function (map) {
    var escaper = function (match) {
      return map[match];
    };
    // Regexes for identifying a key that needs to be escaped.
    var source = '(?:' + Object.keys(map).join('|') + ')';
    var testRegexp = RegExp(source);
    var replaceRegexp = RegExp(source, 'g');
    return function (string) {
      string = string == null ? '' : '' + string;
      return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string;
    };
  };

  var htmlEscape = createEscaper(escapeMap);

  /**
   * ------------------------------------------------------------------------
   * Constants
   * ------------------------------------------------------------------------
   */

  var keyCodeMap = {
    32: ' ',
    48: '0',
    49: '1',
    50: '2',
    51: '3',
    52: '4',
    53: '5',
    54: '6',
    55: '7',
    56: '8',
    57: '9',
    59: ';',
    65: 'A',
    66: 'B',
    67: 'C',
    68: 'D',
    69: 'E',
    70: 'F',
    71: 'G',
    72: 'H',
    73: 'I',
    74: 'J',
    75: 'K',
    76: 'L',
    77: 'M',
    78: 'N',
    79: 'O',
    80: 'P',
    81: 'Q',
    82: 'R',
    83: 'S',
    84: 'T',
    85: 'U',
    86: 'V',
    87: 'W',
    88: 'X',
    89: 'Y',
    90: 'Z',
    96: '0',
    97: '1',
    98: '2',
    99: '3',
    100: '4',
    101: '5',
    102: '6',
    103: '7',
    104: '8',
    105: '9'
  };

  var keyCodes = {
    ESCAPE: 27, // KeyboardEvent.which value for Escape (Esc) key
    ENTER: 13, // KeyboardEvent.which value for Enter key
    SPACE: 32, // KeyboardEvent.which value for space key
    TAB: 9, // KeyboardEvent.which value for tab key
    ARROW_UP: 38, // KeyboardEvent.which value for up arrow key
    ARROW_DOWN: 40 // KeyboardEvent.which value for down arrow key
  }

  // eslint-disable-next-line no-undef
  var Dropdown = window.Dropdown || bootstrap.Dropdown;

  function getVersion () {
    var version;

    try {
      version = \$.fn.dropdown.Constructor.VERSION;
    } catch (err) {
      version = Dropdown.VERSION;
    }

    return version;
  }

  var version = {
    success: false,
    major: '3'
  };

  try {
    version.full = (getVersion() || '').split(' ')[0].split('.');
    version.major = version.full[0];
    version.success = true;
  } catch (err) {
    // do nothing
  }

  var selectId = 0;

  var EVENT_KEY = '.bs.select';

  var classNames = {
    DISABLED: 'disabled',
    DIVIDER: 'divider',
    SHOW: 'open',
    DROPUP: 'dropup',
    MENU: 'dropdown-menu',
    MENURIGHT: 'dropdown-menu-right',
    MENULEFT: 'dropdown-menu-left',
    // to-do: replace with more advanced template/customization options
    BUTTONCLASS: 'btn-default',
    POPOVERHEADER: 'popover-title',
    ICONBASE: 'glyphicon',
    TICKICON: 'glyphicon-ok'
  }

  var Selector = {
    MENU: '.' + classNames.MENU,
    DATA_TOGGLE: 'data-toggle=\"dropdown\"'
  }

  var elementTemplates = {
    div: document.createElement('div'),
    span: document.createElement('span'),
    i: document.createElement('i'),
    subtext: document.createElement('small'),
    a: document.createElement('a'),
    li: document.createElement('li'),
    whitespace: document.createTextNode('\\u00A0'),
    fragment: document.createDocumentFragment(),
    option: document.createElement('option')
  }

  elementTemplates.selectedOption = elementTemplates.option.cloneNode(false);
  elementTemplates.selectedOption.setAttribute('selected', true);

  elementTemplates.noResults = elementTemplates.li.cloneNode(false);
  elementTemplates.noResults.className = 'no-results';

  elementTemplates.a.setAttribute('role', 'option');
  elementTemplates.a.className = 'dropdown-item';

  elementTemplates.subtext.className = 'text-muted';

  elementTemplates.text = elementTemplates.span.cloneNode(false);
  elementTemplates.text.className = 'text';

  elementTemplates.checkMark = elementTemplates.span.cloneNode(false);

  var REGEXP_ARROW = new RegExp(keyCodes.ARROW_UP + '|' + keyCodes.ARROW_DOWN);
  var REGEXP_TAB_OR_ESCAPE = new RegExp('^' + keyCodes.TAB + '\$|' + keyCodes.ESCAPE);

  var generateOption = {
    li: function (content, classes, optgroup) {
      var li = elementTemplates.li.cloneNode(false);

      if (content) {
        if (content.nodeType === 1 || content.nodeType === 11) {
          li.appendChild(content);
        } else {
          li.innerHTML = content;
        }
      }

      if (typeof classes !== 'undefined' && classes !== '') li.className = classes;
      if (typeof optgroup !== 'undefined' && optgroup !== null) li.classList.add('optgroup-' + optgroup);

      return li;
    },

    a: function (text, classes, inline) {
      var a = elementTemplates.a.cloneNode(true);

      if (text) {
        if (text.nodeType === 11) {
          a.appendChild(text);
        } else {
          a.insertAdjacentHTML('beforeend', text);
        }
      }

      if (typeof classes !== 'undefined' && classes !== '') a.classList.add.apply(a.classList, classes.split(/\\s+/));
      if (inline) a.setAttribute('style', inline);

      return a;
    },

    text: function (options, useFragment) {
      var textElement = elementTemplates.text.cloneNode(false),
          subtextElement,
          iconElement;

      if (options.content) {
        textElement.innerHTML = options.content;
      } else {
        textElement.textContent = options.text;

        if (options.icon) {
          var whitespace = elementTemplates.whitespace.cloneNode(false);

          // need to use <i> for icons in the button to prevent a breaking change
          // note: switch to span in next major release
          iconElement = (useFragment === true ? elementTemplates.i : elementTemplates.span).cloneNode(false);
          iconElement.className = this.options.iconBase + ' ' + options.icon;

          elementTemplates.fragment.appendChild(iconElement);
          elementTemplates.fragment.appendChild(whitespace);
        }

        if (options.subtext) {
          subtextElement = elementTemplates.subtext.cloneNode(false);
          subtextElement.textContent = options.subtext;
          textElement.appendChild(subtextElement);
        }
      }

      if (useFragment === true) {
        while (textElement.childNodes.length > 0) {
          elementTemplates.fragment.appendChild(textElement.childNodes[0]);
        }
      } else {
        elementTemplates.fragment.appendChild(textElement);
      }

      return elementTemplates.fragment;
    },

    label: function (options) {
      var textElement = elementTemplates.text.cloneNode(false),
          subtextElement,
          iconElement;

      textElement.innerHTML = options.display;

      if (options.icon) {
        var whitespace = elementTemplates.whitespace.cloneNode(false);

        iconElement = elementTemplates.span.cloneNode(false);
        iconElement.className = this.options.iconBase + ' ' + options.icon;

        elementTemplates.fragment.appendChild(iconElement);
        elementTemplates.fragment.appendChild(whitespace);
      }

      if (options.subtext) {
        subtextElement = elementTemplates.subtext.cloneNode(false);
        subtextElement.textContent = options.subtext;
        textElement.appendChild(subtextElement);
      }

      elementTemplates.fragment.appendChild(textElement);

      return elementTemplates.fragment;
    }
  }

  var getOptionData = {
    fromOption: function (option, type) {
      var value;

      switch (type) {
        case 'divider':
          value = option.getAttribute('data-divider') === 'true';
          break;

        case 'text':
          value = option.textContent;
          break;

        case 'label':
          value = option.label;
          break;

        case 'style':
          value = option.style.cssText;
          break;

        case 'content':
        case 'tokens':
        case 'subtext':
        case 'icon':
          value = option.getAttribute('data-' + type);
          break;
      }

      return value;
    },
    fromDataSource: function (option, type) {
      var value;

      switch (type) {
        case 'text':
        case 'label':
          value = option.text || option.value || '';
          break;

        case 'divider':
        case 'style':
        case 'content':
        case 'tokens':
        case 'subtext':
        case 'icon':
          value = option[type];
          break;
      }

      return value;
    }
  }

  function showNoResults (searchMatch, searchValue) {
    if (!searchMatch.length) {
      elementTemplates.noResults.innerHTML = this.options.noneResultsText.replace('{0}', '\"' + htmlEscape(searchValue) + '\"');
      this.\$menuInner[0].firstChild.appendChild(elementTemplates.noResults);
    }
  }

  function filterHidden (item) {
    return !(item.hidden || this.options.hideDisabled && item.disabled);
  }

  var Selectpicker = function (element, options) {
    var that = this;

    // bootstrap-select has been initialized - revert valHooks.select.set back to its original function
    if (!valHooks.useDefault) {
      \$.valHooks.select.set = valHooks._set;
      valHooks.useDefault = true;
    }

    this.\$element = \$(element);
    this.\$newElement = null;
    this.\$button = null;
    this.\$menu = null;
    this.options = options;
    this.selectpicker = {
      main: {
        optionQueue: elementTemplates.fragment.cloneNode(false)
      },
      search: {},
      current: {}, // current changes if a search is in progress
      view: {},
      isSearching: false,
      keydown: {
        keyHistory: '',
        resetKeyHistory: {
          start: function () {
            return setTimeout(function () {
              that.selectpicker.keydown.keyHistory = '';
            }, 800);
          }
        }
      }
    };

    this.sizeInfo = {};

    // Format window padding
    var winPad = this.options.windowPadding;
    if (typeof winPad === 'number') {
      this.options.windowPadding = [winPad, winPad, winPad, winPad];
    }

    // Expose public methods
    this.val = Selectpicker.prototype.val;
    this.render = Selectpicker.prototype.render;
    this.refresh = Selectpicker.prototype.refresh;
    this.setStyle = Selectpicker.prototype.setStyle;
    this.selectAll = Selectpicker.prototype.selectAll;
    this.deselectAll = Selectpicker.prototype.deselectAll;
    this.destroy = Selectpicker.prototype.destroy;
    this.remove = Selectpicker.prototype.remove;
    this.show = Selectpicker.prototype.show;
    this.hide = Selectpicker.prototype.hide;

    this.init();
  };

  Selectpicker.VERSION = '1.14.0-beta2';

  // part of this is duplicated in i18n/defaults-en_US.js. Make sure to update both.
  Selectpicker.DEFAULTS = {
    noneSelectedText: 'Nothing selected',
    noneResultsText: 'No results matched {0}',
    countSelectedText: function (numSelected, numTotal) {
      return (numSelected == 1) ? '{0} item selected' : '{0} items selected';
    },
    maxOptionsText: function (numAll, numGroup) {
      return [
        (numAll == 1) ? 'Limit reached ({n} item max)' : 'Limit reached ({n} items max)',
        (numGroup == 1) ? 'Group limit reached ({n} item max)' : 'Group limit reached ({n} items max)'
      ];
    },
    selectAllText: 'Select All',
    deselectAllText: 'Deselect All',
    source: {},
    chunkSize: 40,
    doneButton: false,
    doneButtonText: 'Close',
    multipleSeparator: ', ',
    styleBase: 'btn',
    style: classNames.BUTTONCLASS,
    size: 'auto',
    title: null,
    placeholder: null,
    allowClear: false,
    selectedTextFormat: 'values',
    width: false,
    container: false,
    hideDisabled: false,
    showSubtext: false,
    showIcon: true,
    showContent: true,
    dropupAuto: true,
    header: false,
    liveSearch: false,
    liveSearchPlaceholder: null,
    liveSearchNormalize: false,
    liveSearchStyle: 'contains',
    actionsBox: false,
    iconBase: classNames.ICONBASE,
    tickIcon: classNames.TICKICON,
    showTick: false,
    template: {
      caret: '<span class=\"caret\"></span>'
    },
    maxOptions: false,
    mobile: false,
    selectOnTab: false,
    dropdownAlignRight: false,
    windowPadding: 0,
    virtualScroll: 600,
    display: false,
    sanitize: true,
    sanitizeFn: null,
    whiteList: DefaultWhitelist
  };

  Selectpicker.prototype = {

    constructor: Selectpicker,

    init: function () {
      var that = this,
          id = this.\$element.attr('id'),
          element = this.\$element[0],
          form = element.form;

      selectId++;
      this.selectId = 'bs-select-' + selectId;

      element.classList.add('bs-select-hidden');

      this.multiple = this.\$element.prop('multiple');
      this.autofocus = this.\$element.prop('autofocus');

      if (element.classList.contains('show-tick')) {
        this.options.showTick = true;
      }

      this.\$newElement = this.createDropdown();

      this.\$element
        .after(this.\$newElement)
        .prependTo(this.\$newElement);

      // ensure select is associated with form element if it got unlinked after moving it inside newElement
      if (form && element.form === null) {
        if (!form.id) form.id = 'form-' + this.selectId;
        element.setAttribute('form', form.id);
      }

      this.\$button = this.\$newElement.children('button');
      if (this.options.allowClear) this.\$clearButton = this.\$button.children('.bs-select-clear-selected');
      this.\$menu = this.\$newElement.children(Selector.MENU);
      this.\$menuInner = this.\$menu.children('.inner');
      this.\$searchbox = this.\$menu.find('input');

      element.classList.remove('bs-select-hidden');

      this.fetchData(function () {
        that.render(true);
        that.buildList();

        requestAnimationFrame(function () {
          that.\$element.trigger('loaded' + EVENT_KEY);
        });
      });

      this.fetchData(function () {
        that.render(true);
        that.buildList();

        requestAnimationFrame(function () {
          that.\$element.trigger('loaded' + EVENT_KEY);
        });
      });

      if (this.options.dropdownAlignRight === true) this.\$menu[0].classList.add(classNames.MENURIGHT);

      if (typeof id !== 'undefined') {
        this.\$button.attr('data-id', id);
      }

      this.checkDisabled();
      this.clickListener();

      if (version.major > 4) this.dropdown = new Dropdown(this.\$button[0]);

      if (this.options.liveSearch) {
        this.liveSearchListener();
        this.focusedParent = this.\$searchbox[0];
      } else {
        this.focusedParent = this.\$menuInner[0];
      }

      this.setStyle();
      this.setWidth();
      if (this.options.container) {
        this.selectPosition();
      } else {
        this.\$element.on('hide' + EVENT_KEY, function () {
          if (that.isVirtual()) {
            // empty menu on close
            var menuInner = that.\$menuInner[0],
                emptyMenu = menuInner.firstChild.cloneNode(false);

            // replace the existing UL with an empty one - this is faster than \$.empty() or innerHTML = ''
            menuInner.replaceChild(emptyMenu, menuInner.firstChild);
            menuInner.scrollTop = 0;
          }
        });
      }
      this.\$menu.data('this', this);
      this.\$newElement.data('this', this);
      if (this.options.mobile) this.mobile();

      this.\$newElement.on({
        'hide.bs.dropdown': function (e) {
          that.\$element.trigger('hide' + EVENT_KEY, e);
        },
        'hidden.bs.dropdown': function (e) {
          that.\$element.trigger('hidden' + EVENT_KEY, e);
        },
        'show.bs.dropdown': function (e) {
          that.\$element.trigger('show' + EVENT_KEY, e);
        },
        'shown.bs.dropdown': function (e) {
          that.\$element.trigger('shown' + EVENT_KEY, e);
        }
      });

      if (element.hasAttribute('required')) {
        this.\$element.on('invalid' + EVENT_KEY, function () {
          that.\$button[0].classList.add('bs-invalid');

          that.\$element
            .on('shown' + EVENT_KEY + '.invalid', function () {
              that.\$element
                .val(that.\$element.val()) // set the value to hide the validation message in Chrome when menu is opened
                .off('shown' + EVENT_KEY + '.invalid');
            })
            .on('rendered' + EVENT_KEY, function () {
              // if select is no longer invalid, remove the bs-invalid class
              if (this.validity.valid) that.\$button[0].classList.remove('bs-invalid');
              that.\$element.off('rendered' + EVENT_KEY);
            });

          that.\$button.on('blur' + EVENT_KEY, function () {
            that.\$element.trigger('focus').trigger('blur');
            that.\$button.off('blur' + EVENT_KEY);
          });
        });
      }

      if (form) {
        \$(form).on('reset' + EVENT_KEY, function () {
          requestAnimationFrame(function () {
            that.render();
          });
        });
      }
    },

    createDropdown: function () {
      // Options
      // If we are multiple or showTick option is set, then add the show-tick class
      var showTick = (this.multiple || this.options.showTick) ? ' show-tick' : '',
          multiselectable = this.multiple ? ' aria-multiselectable=\"true\"' : '',
          inputGroup = '',
          autofocus = this.autofocus ? ' autofocus' : '';

      if (version.major < 4 && this.\$element.parent().hasClass('input-group')) {
        inputGroup = ' input-group-btn';
      }

      // Elements
      var drop,
          header = '',
          searchbox = '',
          actionsbox = '',
          donebutton = '',
          clearButton = '';

      if (this.options.header) {
        header =
          '<div class=\"' + classNames.POPOVERHEADER + '\">' +
            '<button type=\"button\" class=\"close\" aria-hidden=\"true\">&times;</button>' +
              this.options.header +
          '</div>';
      }

      if (this.options.liveSearch) {
        searchbox =
          '<div class=\"bs-searchbox\">' +
            '<input type=\"search\" class=\"form-control\" autocomplete=\"off\"' +
              (
                this.options.liveSearchPlaceholder === null ? ''
                :
                ' placeholder=\"' + htmlEscape(this.options.liveSearchPlaceholder) + '\"'
              ) +
              ' role=\"combobox\" aria-label=\"Search\" aria-controls=\"' + this.selectId + '\" aria-autocomplete=\"list\">' +
          '</div>';
      }

      if (this.multiple && this.options.actionsBox) {
        actionsbox =
          '<div class=\"bs-actionsbox\">' +
            '<div class=\"btn-group btn-group-sm\">' +
              '<button type=\"button\" class=\"actions-btn bs-select-all btn ' + classNames.BUTTONCLASS + '\">' +
                this.options.selectAllText +
              '</button>' +
              '<button type=\"button\" class=\"actions-btn bs-deselect-all btn ' + classNames.BUTTONCLASS + '\">' +
                this.options.deselectAllText +
              '</button>' +
            '</div>' +
          '</div>';
      }

      if (this.multiple && this.options.doneButton) {
        donebutton =
          '<div class=\"bs-donebutton\">' +
            '<div class=\"btn-group\">' +
              '<button type=\"button\" class=\"btn btn-sm ' + classNames.BUTTONCLASS + '\">' +
                this.options.doneButtonText +
              '</button>' +
            '</div>' +
          '</div>';
      }

      if (this.options.allowClear) {
        clearButton = '<span class=\"close bs-select-clear-selected\" title=\"' + this.options.deselectAllText + '\"><span>&times;</span>';
      }

      drop =
        '<div class=\"dropdown bootstrap-select' + showTick + inputGroup + '\">' +
          '<button type=\"button\" tabindex=\"-1\" class=\"' +
            this.options.styleBase +
            ' dropdown-toggle\" ' +
            (this.options.display === 'static' ? 'data-display=\"static\"' : '') +
            Selector.DATA_TOGGLE +
            autofocus +
            ' role=\"combobox\" aria-owns=\"' +
            this.selectId +
            '\" aria-haspopup=\"listbox\" aria-expanded=\"false\">' +
            '<div class=\"filter-option\">' +
              '<div class=\"filter-option-inner\">' +
                '<div class=\"filter-option-inner-inner\">&nbsp;</div>' +
              '</div> ' +
            '</div>' +
            clearButton +
            '</span>' +
            (
              version.major >= '4' ? ''
              :
              '<span class=\"bs-caret\">' +
                this.options.template.caret +
              '</span>'
            ) +
          '</button>' +
          '<div class=\"' + classNames.MENU + ' ' + (version.major >= '4' ? '' : classNames.SHOW) + '\">' +
            header +
            searchbox +
            actionsbox +
            '<div class=\"inner ' + classNames.SHOW + '\" role=\"listbox\" id=\"' + this.selectId + '\" tabindex=\"-1\" ' + multiselectable + '>' +
                '<ul class=\"' + classNames.MENU + ' inner ' + (version.major >= '4' ? classNames.SHOW : '') + '\" role=\"presentation\">' +
                '</ul>' +
            '</div>' +
            donebutton +
          '</div>' +
        '</div>';

      return \$(drop);
    },

    setPositionData: function () {
      this.selectpicker.view.canHighlight = [];
      this.selectpicker.view.size = 0;
      this.selectpicker.view.firstHighlightIndex = false;

      for (var i = 0; i < this.selectpicker.current.data.length; i++) {
        var li = this.selectpicker.current.data[i],
            canHighlight = true;

        if (li.type === 'divider') {
          canHighlight = false;
          li.height = this.sizeInfo.dividerHeight;
        } else if (li.type === 'optgroup-label') {
          canHighlight = false;
          li.height = this.sizeInfo.dropdownHeaderHeight;
        } else {
          li.height = this.sizeInfo.liHeight;
        }

        if (li.disabled) canHighlight = false;

        this.selectpicker.view.canHighlight.push(canHighlight);

        if (canHighlight) {
          this.selectpicker.view.size++;
          li.posinset = this.selectpicker.view.size;
          if (this.selectpicker.view.firstHighlightIndex === false) this.selectpicker.view.firstHighlightIndex = i;
        }

        li.position = (i === 0 ? 0 : this.selectpicker.current.data[i - 1].position) + li.height;
      }
    },

    isVirtual: function () {
      return (this.options.virtualScroll !== false) && (this.selectpicker.main.data.length >= this.options.virtualScroll) || this.options.virtualScroll === true;
    },

    createView: function (isSearching, setSize, refresh) {
      var that = this,
          scrollTop = 0,
          active = [],
          selected,
          prevActive;

      this.selectpicker.isSearching = isSearching;
      this.selectpicker.current = isSearching ? this.selectpicker.search : this.selectpicker.main;

      this.setPositionData();

      if (setSize) {
        if (refresh) {
          scrollTop = this.\$menuInner[0].scrollTop;
        } else if (!that.multiple) {
          var element = that.\$element[0],
              selectedIndex = (element.options[element.selectedIndex] || {}).liIndex;

          if (typeof selectedIndex === 'number' && that.options.size !== false) {
            var selectedData = that.selectpicker.main.data[selectedIndex],
                position = selectedData && selectedData.position;

            if (position) {
              scrollTop = position - ((that.sizeInfo.menuInnerHeight + that.sizeInfo.liHeight) / 2);
            }
          }
        }
      }

      scroll(scrollTop, true);

      this.\$menuInner.off('scroll.createView').on('scroll.createView', function (e, updateValue) {
        if (!that.noScroll) scroll(this.scrollTop, updateValue);
        that.noScroll = false;
      });

      function scroll (scrollTop, init) {
        var size = that.selectpicker.current.data.length,
            chunks = [],
            chunkSize,
            chunkCount,
            firstChunk,
            lastChunk,
            currentChunk,
            prevPositions,
            positionIsDifferent,
            previousElements,
            menuIsDifferent = true,
            isVirtual = that.isVirtual();

        that.selectpicker.view.scrollTop = scrollTop;

        chunkSize = that.options.chunkSize; // number of options in a chunk
        chunkCount = Math.ceil(size / chunkSize) || 1; // number of chunks

        for (var i = 0; i < chunkCount; i++) {
          var endOfChunk = (i + 1) * chunkSize;

          if (i === chunkCount - 1) {
            endOfChunk = size;
          }

          chunks[i] = [
            (i) * chunkSize + (!i ? 0 : 1),
            endOfChunk
          ];

          if (!size) break;

          if (currentChunk === undefined && scrollTop - 1 <= that.selectpicker.current.data[endOfChunk - 1].position - that.sizeInfo.menuInnerHeight) {
            currentChunk = i;
          }
        }

        if (currentChunk === undefined) currentChunk = 0;

        prevPositions = [that.selectpicker.view.position0, that.selectpicker.view.position1];

        // always display previous, current, and next chunks
        firstChunk = Math.max(0, currentChunk - 1);
        lastChunk = Math.min(chunkCount - 1, currentChunk + 1);

        that.selectpicker.view.position0 = isVirtual === false ? 0 : (Math.max(0, chunks[firstChunk][0]) || 0);
        that.selectpicker.view.position1 = isVirtual === false ? size : (Math.min(size, chunks[lastChunk][1]) || 0);

        positionIsDifferent = prevPositions[0] !== that.selectpicker.view.position0 || prevPositions[1] !== that.selectpicker.view.position1;

        if (that.activeIndex !== undefined) {
          prevActive = (that.selectpicker.main.data[that.prevActiveIndex] || {}).element;
          active = (that.selectpicker.main.data[that.activeIndex] || {}).element;
          selected = (that.selectpicker.main.data[that.selectedIndex] || {}).element;

          if (init) {
            if (that.activeIndex !== that.selectedIndex) {
              that.defocusItem(active);
            }
            that.activeIndex = undefined;
          }

          if (that.activeIndex && that.activeIndex !== that.selectedIndex) {
            that.defocusItem(selected);
          }
        }

        if (that.prevActiveIndex !== undefined && that.prevActiveIndex !== that.activeIndex && that.prevActiveIndex !== that.selectedIndex) {
          that.defocusItem(prevActive);
        }

        if (init || positionIsDifferent) {
          previousElements = that.selectpicker.view.visibleElements ? that.selectpicker.view.visibleElements.slice() : [];

          if (isVirtual === false) {
            that.selectpicker.view.visibleElements = that.selectpicker.current.elements;
          } else {
            that.selectpicker.view.visibleElements = that.selectpicker.current.elements.slice(that.selectpicker.view.position0, that.selectpicker.view.position1);
          }

          that.setOptionStatus();

          // if searching, check to make sure the list has actually been updated before updating DOM
          // this prevents unnecessary repaints
          if (isSearching || (isVirtual === false && init)) menuIsDifferent = !isEqual(previousElements, that.selectpicker.view.visibleElements);

          // if virtual scroll is disabled and not searching,
          // menu should never need to be updated more than once
          if ((init || isVirtual === true) && menuIsDifferent) {
            var menuInner = that.\$menuInner[0],
                menuFragment = document.createDocumentFragment(),
                emptyMenu = menuInner.firstChild.cloneNode(false),
                marginTop,
                marginBottom,
                elements = that.selectpicker.view.visibleElements,
                toSanitize = [];

            // replace the existing UL with an empty one - this is faster than \$.empty()
            menuInner.replaceChild(emptyMenu, menuInner.firstChild);

            for (var i = 0, visibleElementsLen = elements.length; i < visibleElementsLen; i++) {
              var element = elements[i],
                  elText,
                  elementData;

              if (that.options.sanitize) {
                elText = element.lastChild;

                if (elText) {
                  elementData = that.selectpicker.current.data[i + that.selectpicker.view.position0];

                  if (elementData && elementData.content && !elementData.sanitized) {
                    toSanitize.push(elText);
                    elementData.sanitized = true;
                  }
                }
              }

              menuFragment.appendChild(element);
            }

            if (that.options.sanitize && toSanitize.length) {
              sanitizeHtml(toSanitize, that.options.whiteList, that.options.sanitizeFn);
            }

            if (isVirtual === true) {
              marginTop = (that.selectpicker.view.position0 === 0 ? 0 : that.selectpicker.current.data[that.selectpicker.view.position0 - 1].position);
              marginBottom = (that.selectpicker.view.position1 > size - 1 ? 0 : that.selectpicker.current.data[size - 1].position - that.selectpicker.current.data[that.selectpicker.view.position1 - 1].position);

              menuInner.firstChild.style.marginTop = marginTop + 'px';
              menuInner.firstChild.style.marginBottom = marginBottom + 'px';
            } else {
              menuInner.firstChild.style.marginTop = 0;
              menuInner.firstChild.style.marginBottom = 0;
            }

            menuInner.firstChild.appendChild(menuFragment);

            // if an option is encountered that is wider than the current menu width, update the menu width accordingly
            // switch to ResizeObserver with increased browser support
            if (isVirtual === true && that.sizeInfo.hasScrollBar) {
              var menuInnerInnerWidth = menuInner.firstChild.offsetWidth;

              if (init && menuInnerInnerWidth < that.sizeInfo.menuInnerInnerWidth && that.sizeInfo.totalMenuWidth > that.sizeInfo.selectWidth) {
                menuInner.firstChild.style.minWidth = that.sizeInfo.menuInnerInnerWidth + 'px';
              } else if (menuInnerInnerWidth > that.sizeInfo.menuInnerInnerWidth) {
                // set to 0 to get actual width of menu
                that.\$menu[0].style.minWidth = 0;

                var actualMenuWidth = menuInner.firstChild.offsetWidth;

                if (actualMenuWidth > that.sizeInfo.menuInnerInnerWidth) {
                  that.sizeInfo.menuInnerInnerWidth = actualMenuWidth;
                  menuInner.firstChild.style.minWidth = that.sizeInfo.menuInnerInnerWidth + 'px';
                }

                // reset to default CSS styling
                that.\$menu[0].style.minWidth = '';
              }
            }
          }

          if ((!isSearching && that.options.source.load || isSearching && that.options.source.search) && currentChunk === chunkCount - 1) {
            that.fetchData(function () {
              that.render();
              that.buildList(size, isSearching);
              that.setPositionData();
              scroll(scrollTop);
            }, isSearching ? 'search' : 'load', currentChunk + 1, isSearching ? that.selectpicker.search.previousValue : undefined);
          }
        }

        that.prevActiveIndex = that.activeIndex;

        if (!that.options.liveSearch) {
          that.\$menuInner.trigger('focus');
        } else if (isSearching && init) {
          var index = 0,
              newActive;

          if (!that.selectpicker.view.canHighlight[index]) {
            index = 1 + that.selectpicker.view.canHighlight.slice(1).indexOf(true);
          }

          newActive = that.selectpicker.view.visibleElements[index];

          that.defocusItem(that.selectpicker.view.currentActive);

          that.activeIndex = (that.selectpicker.current.data[index] || {}).index;

          that.focusItem(newActive);
        }
      }

      \$(window)
        .off('resize' + EVENT_KEY + '.' + this.selectId + '.createView')
        .on('resize' + EVENT_KEY + '.' + this.selectId + '.createView', function () {
          var isActive = that.\$newElement.hasClass(classNames.SHOW);

          if (isActive) scroll(that.\$menuInner[0].scrollTop);
        });
    },

    focusItem: function (li, liData, noStyle) {
      if (li) {
        liData = liData || this.selectpicker.main.data[this.activeIndex];
        var a = li.firstChild;

        if (a) {
          a.setAttribute('aria-setsize', this.selectpicker.view.size);
          a.setAttribute('aria-posinset', liData.posinset);

          if (noStyle !== true) {
            this.focusedParent.setAttribute('aria-activedescendant', a.id);
            li.classList.add('active');
            a.classList.add('active');
          }
        }
      }
    },

    defocusItem: function (li) {
      if (li) {
        li.classList.remove('active');
        if (li.firstChild) li.firstChild.classList.remove('active');
      }
    },

    setPlaceholder: function () {
      var that = this,
          updateIndex = false;

      if ((this.options.placeholder || this.options.allowClear) && !this.multiple) {
        if (!this.selectpicker.view.titleOption) this.selectpicker.view.titleOption = document.createElement('option');

        // this option doesn't create a new <li> element, but does add a new option at the start,
        // so startIndex should increase to prevent having to check every option for the bs-title-option class
        updateIndex = true;

        var element = this.\$element[0],
            selectTitleOption = false,
            titleNotAppended = !this.selectpicker.view.titleOption.parentNode,
            selectedIndex = element.selectedIndex,
            selectedOption = element.options[selectedIndex],
            firstSelectable = element.querySelector('select > *:not(:disabled)'),
            firstSelectableIndex = firstSelectable ? firstSelectable.index : 0,
            navigation = window.performance && window.performance.getEntriesByType('navigation'),
            // Safari doesn't support getEntriesByType('navigation') - fall back to performance.navigation
            isNotBackForward = (navigation && navigation.length) ? navigation[0].type !== 'back_forward' : window.performance.navigation.type !== 2;

        if (titleNotAppended) {
          // Use native JS to prepend option (faster)
          this.selectpicker.view.titleOption.className = 'bs-title-option';
          this.selectpicker.view.titleOption.value = '';

          // Check if selected or data-selected attribute is already set on an option. If not, select the titleOption option.
          // the selected item may have been changed by user or programmatically before the bootstrap select plugin runs,
          // if so, the select will have the data-selected attribute
          selectTitleOption = !selectedOption || (selectedIndex === firstSelectableIndex && selectedOption.defaultSelected === false && this.\$element.data('selected') === undefined);
        }

        if (titleNotAppended || this.selectpicker.view.titleOption.index !== 0) {
          element.insertBefore(this.selectpicker.view.titleOption, element.firstChild);
        }

        // Set selected *after* appending to select,
        // otherwise the option doesn't get selected in IE
        // set using selectedIndex, as setting the selected attr to true here doesn't work in IE11
        if (selectTitleOption && isNotBackForward) {
          element.selectedIndex = 0;
        } else if (document.readyState !== 'complete') {
          // if navigation type is back_forward, there's a chance the select will have its value set by BFCache
          // wait for that value to be set, then run render again
          window.addEventListener('pageshow', function () {
            if (that.selectpicker.view.displayedValue !== element.value) that.render();
          });
        }
      }

      return updateIndex;
    },

    fetchData: function (callback, type, page, searchValue) {
      type = type || 'data';

      var that = this,
          data = this.options.source[type],
          builtData;

      if (data) {
        this.options.virtualScroll = true;

        if (typeof data === 'function') {
          data.call(
            this,
            function (data) {
              builtData = that.buildData(data, type);
              callback.call(that, builtData);
            },
            page,
            searchValue
          );
        } else if (Array.isArray(data)) {
          builtData = that.buildData(data, type);
          callback.call(that, builtData);
        }
      } else {
        builtData = this.buildData(false, type);
        callback.call(that, builtData);
      }
    },

    buildData: function (data, type) {
      var dataGetter = data === false ? getOptionData.fromOption : getOptionData.fromDataSource;

      var optionSelector = ':not([hidden]):not([data-hidden=\"true\"])',
          mainData = [],
          startLen = 0,
          optID = 0,
          startIndex = this.setPlaceholder() && !data ? 1 : 0; // append the titleOption if necessary and skip the first option in the loop

      if (type === 'load') {
        startLen = this.selectpicker.main.data.length;
      } else if (type === 'search') {
        startLen = this.selectpicker.search.data.length;
      }

      if (this.options.hideDisabled) optionSelector += ':not(:disabled)';

      var selectOptions = data ? data.filter(filterHidden, this) : this.\$element[0].querySelectorAll('select > *' + optionSelector);

      function addDivider (config) {
        var previousData = mainData[mainData.length - 1];

        // ensure optgroup doesn't create back-to-back dividers
        if (
          previousData &&
          previousData.type === 'divider' &&
          (previousData.optID || config.optID)
        ) {
          return;
        }

        config = config || {};
        config.type = 'divider';

        mainData.push(config);
      }

      function addOption (item, config) {
        config = config || {};

        config.divider = dataGetter(item, 'divider');

        if (config.divider === true) {
          addDivider({
            optID: config.optID
          });
        } else {
          var liIndex = mainData.length + startLen,
              cssText = dataGetter(item, 'style'),
              inlineStyle = cssText ? htmlEscape(cssText) : '',
              optionClass = (item.className || '') + (config.optgroupClass || '');

          if (config.optID) optionClass = 'opt ' + optionClass;

          config.optionClass = optionClass.trim();
          config.inlineStyle = inlineStyle;

          config.text = dataGetter(item, 'text');
          config.content = dataGetter(item, 'content');
          config.tokens = dataGetter(item, 'tokens');
          config.subtext = dataGetter(item, 'subtext');
          config.icon = dataGetter(item, 'icon');

          config.display = config.content || config.text;
          config.value = item.value === undefined ? item.text : item.value;
          config.type = 'option';
          config.index = liIndex;

          config.option = !item.option ? item : item.option; // reference option element if it exists
          config.option.liIndex = liIndex;
          config.selected = !!item.selected;
          config.disabled = config.disabled || !!item.disabled;

          mainData.push(config);
        }
      }

      function addOptgroup (index, selectOptions) {
        var optgroup = selectOptions[index],
            // skip placeholder option
            previous = index - 1 < startIndex ? false : selectOptions[index - 1],
            next = selectOptions[index + 1],
            options = data ? optgroup.children.filter(filterHidden, this) : optgroup.querySelectorAll('option' + optionSelector);

        if (!options.length) return;

        var config = {
              display: htmlEscape(dataGetter(item, 'label')),
              subtext: dataGetter(optgroup, 'subtext'),
              icon: dataGetter(optgroup, 'icon'),
              type: 'optgroup-label',
              optgroupClass: ' ' + (optgroup.className || '')
            },
            headerIndex,
            lastIndex;

        optID++;

        if (previous) {
          addDivider({ optID: optID });
        }

        config.optID = optID;

        mainData.push(config);

        for (var j = 0, len = options.length; j < len; j++) {
          var option = options[j];

          if (j === 0) {
            headerIndex = mainData.length - 1;
            lastIndex = headerIndex + len;
          }

          addOption(option, {
            headerIndex: headerIndex,
            lastIndex: lastIndex,
            optID: config.optID,
            optgroupClass: config.optgroupClass,
            disabled: optgroup.disabled
          });
        }

        if (next) {
          addDivider({ optID: optID });
        }
      }

      for (var len = selectOptions.length, i = startIndex; i < len; i++) {
        var item = selectOptions[i],
            children = item.children;

        if (children && children.length) {
          addOptgroup.call(this, startIndex, selectOptions);
        } else {
          addOption.call(this, item, {});
        }
      }

      switch (type) {
        case 'data': {
          this.selectpicker.main.data = this.selectpicker.current.data = mainData;
          break;
        }
        case 'load': {
          Array.prototype.push.apply(this.selectpicker.main.data, mainData);
          this.selectpicker.current.data = this.selectpicker.main.data;
          break;
        }
        case 'search': {
          Array.prototype.push.apply(this.selectpicker.search.data, mainData);
          break;
        }
      }

      return mainData;
    },

    buildList: function (size, searching) {
      var that = this,
          selectData = searching ? this.selectpicker.search.data : this.selectpicker.main.data,
          mainElements = [],
          widestOptionLength = 0;

      if ((that.options.showTick || that.multiple) && !elementTemplates.checkMark.parentNode) {
        elementTemplates.checkMark.className = this.options.iconBase + ' ' + that.options.tickIcon + ' check-mark';
        elementTemplates.a.appendChild(elementTemplates.checkMark);
      }

      function buildElement (mainElements, item) {
        var liElement,
            combinedLength = 0;

        switch (item.type) {
          case 'divider':
            liElement = generateOption.li(
              false,
              classNames.DIVIDER,
              (item.optID ? item.optID + 'div' : undefined)
            );

            break;

          case 'option':
            liElement = generateOption.li(
              generateOption.a(
                generateOption.text.call(that, item),
                item.optionClass,
                item.inlineStyle
              ),
              '',
              item.optID
            );

            if (liElement.firstChild) {
              liElement.firstChild.id = that.selectId + '-' + item.index;
            }

            break;

          case 'optgroup-label':
            liElement = generateOption.li(
              generateOption.label.call(that, item),
              'dropdown-header' + item.optgroupClass,
              item.optID
            );

            break;
        }

        item.element = liElement;
        mainElements.push(liElement);

        // count the number of characters in the option - not perfect, but should work in most cases
        if (item.display) combinedLength += item.display.length;
        if (item.subtext) combinedLength += item.subtext.length;
        // if there is an icon, ensure this option's width is checked
        if (item.icon) combinedLength += 1;

        if (combinedLength > widestOptionLength) {
          widestOptionLength = combinedLength;

          // guess which option is the widest
          // use this when calculating menu width
          // not perfect, but it's fast, and the width will be updating accordingly when scrolling
          that.selectpicker.view.widestOption = mainElements[mainElements.length - 1];
        }
      }

      var startIndex = size || 0;

      for (var len = selectData.length, i = startIndex; i < len; i++) {
        var item = selectData[i];

        buildElement(mainElements, item);
      }

      if (size) {
        if (searching) {
          Array.prototype.push.apply(this.selectpicker.search.elements, mainElements);
        } else {
          Array.prototype.push.apply(this.selectpicker.main.elements, mainElements);
          this.selectpicker.current.elements = this.selectpicker.main.elements;
        }
      } else {
        if (searching) {
          this.selectpicker.search.elements = mainElements;
        } else {
          this.selectpicker.main.elements = this.selectpicker.current.elements = mainElements;
        }
      }
    },

    findLis: function () {
      return this.\$menuInner.find('.inner > li');
    },

    render: function (init) {
      var that = this,
          element = this.\$element[0],
          // ensure titleOption is appended and selected (if necessary) before getting selectedOptions
          placeholderSelected = this.setPlaceholder() && element.selectedIndex === 0,
          selectedOptions = getSelectedOptions.call(this),
          selectedCount = selectedOptions.length,
          selectedValues = getSelectValues.call(this, selectedOptions),
          button = this.\$button[0],
          buttonInner = button.querySelector('.filter-option-inner-inner'),
          multipleSeparator = document.createTextNode(this.options.multipleSeparator),
          titleFragment = elementTemplates.fragment.cloneNode(false),
          showCount,
          countMax,
          hasContent = false;

      function createSelected (item) {
        if (item.selected) {
          that.createOption(item, true);
        } else if (item.children && item.children.length) {
          item.children.map(createSelected);
        }
      }

      // create selected option elements to ensure select value is correct
      if (this.options.source.data && init) {
        selectedOptions.map(createSelected);
        element.appendChild(this.selectpicker.main.optionQueue);

        if (placeholderSelected) placeholderSelected = element.selectedIndex === 0;
      }

      button.classList.toggle('bs-placeholder', that.multiple ? !selectedCount : !selectedValues && selectedValues !== 0);

      if (!that.multiple && selectedOptions.length === 1) {
        that.selectpicker.view.displayedValue = selectedValues;
      }

      if (this.options.selectedTextFormat === 'static') {
        titleFragment = generateOption.text.call(this, { text: this.options.placeholder }, true);
      } else {
        showCount = this.multiple && this.options.selectedTextFormat.indexOf('count') !== -1 && selectedCount > 1;

        // determine if the number of selected options will be shown (showCount === true)
        if (showCount) {
          countMax = this.options.selectedTextFormat.split('>');
          showCount = (countMax.length > 1 && selectedCount > countMax[1]) || (countMax.length === 1 && selectedCount >= 2);
        }

        // only loop through all selected options if the count won't be shown
        if (showCount === false) {
          if (!placeholderSelected) {
            for (var selectedIndex = 0; selectedIndex < selectedCount; selectedIndex++) {
              if (selectedIndex < 50) {
                var option = selectedOptions[selectedIndex],
                    titleOptions = {};

                if (option) {
                  if (this.multiple && selectedIndex > 0) {
                    titleFragment.appendChild(multipleSeparator.cloneNode(false));
                  }

                  if (option.title) {
                    titleOptions.text = option.title;
                  } else if (option.content && that.options.showContent) {
                    titleOptions.content = option.content.toString();
                    hasContent = true;
                  } else {
                    if (that.options.showIcon) {
                      titleOptions.icon = option.icon;
                    }
                    if (that.options.showSubtext && !that.multiple && option.subtext) titleOptions.subtext = ' ' + option.subtext;
                    titleOptions.text = option.text.trim();
                  }

                  titleFragment.appendChild(generateOption.text.call(this, titleOptions, true));
                }
              } else {
                break;
              }
            }

            // add ellipsis
            if (selectedCount > 49) {
              titleFragment.appendChild(document.createTextNode('...'));
            }
          }
        } else {
          var optionSelector = ':not([hidden]):not([data-hidden=\"true\"]):not([data-divider=\"true\"])';
          if (this.options.hideDisabled) optionSelector += ':not(:disabled)';

          // If this is a multiselect, and selectedTextFormat is count, then show 1 of 2 selected, etc.
          var totalCount = this.\$element[0].querySelectorAll('select > option' + optionSelector + ', optgroup' + optionSelector + ' option' + optionSelector).length,
              tr8nText = (typeof this.options.countSelectedText === 'function') ? this.options.countSelectedText(selectedCount, totalCount) : this.options.countSelectedText;

          titleFragment = generateOption.text.call(this, {
            text: tr8nText.replace('{0}', selectedCount.toString()).replace('{1}', totalCount.toString())
          }, true);
        }
      }

      // If the select doesn't have a title, then use the default, or if nothing is set at all, use noneSelectedText
      if (!titleFragment.childNodes.length) {
        titleFragment = generateOption.text.call(this, {
          text: this.options.placeholder ? this.options.placeholder : this.options.noneSelectedText
        }, true);
      }

      // if the select has a title, apply it to the button, and if not, apply titleFragment text
      // strip all HTML tags and trim the result, then unescape any escaped tags
      button.title = titleFragment.textContent.replace(/<[^>]*>?/g, '').trim();

      if (this.options.sanitize && hasContent) {
        sanitizeHtml([titleFragment], that.options.whiteList, that.options.sanitizeFn);
      }

      buttonInner.innerHTML = '';
      buttonInner.appendChild(titleFragment);

      if (version.major < 4 && this.\$newElement[0].classList.contains('bs3-has-addon')) {
        var filterExpand = button.querySelector('.filter-expand'),
            clone = buttonInner.cloneNode(true);

        clone.className = 'filter-expand';

        if (filterExpand) {
          button.replaceChild(clone, filterExpand);
        } else {
          button.appendChild(clone);
        }
      }

      this.\$element.trigger('rendered' + EVENT_KEY);
    },

    /**
     * @param [style]
     * @param [status]
     */
    setStyle: function (newStyle, status) {
      var button = this.\$button[0],
          newElement = this.\$newElement[0],
          style = this.options.style.trim(),
          buttonClass;

      if (this.\$element.attr('class')) {
        this.\$newElement.addClass(this.\$element.attr('class').replace(/selectpicker|mobile-device|bs-select-hidden|validate\\[.*\\]/gi, ''));
      }

      if (version.major < 4) {
        newElement.classList.add('bs3');

        if (newElement.parentNode.classList && newElement.parentNode.classList.contains('input-group') &&
            (newElement.previousElementSibling || newElement.nextElementSibling) &&
            (newElement.previousElementSibling || newElement.nextElementSibling).classList.contains('input-group-addon')
        ) {
          newElement.classList.add('bs3-has-addon');
        }
      }

      if (newStyle) {
        buttonClass = newStyle.trim();
      } else {
        buttonClass = style;
      }

      if (status == 'add') {
        if (buttonClass) button.classList.add.apply(button.classList, buttonClass.split(' '));
      } else if (status == 'remove') {
        if (buttonClass) button.classList.remove.apply(button.classList, buttonClass.split(' '));
      } else {
        if (style) button.classList.remove.apply(button.classList, style.split(' '));
        if (buttonClass) button.classList.add.apply(button.classList, buttonClass.split(' '));
      }
    },

    liHeight: function (refresh) {
      if (!refresh && (this.options.size === false || Object.keys(this.sizeInfo).length)) return;

      var newElement = elementTemplates.div.cloneNode(false),
          menu = elementTemplates.div.cloneNode(false),
          menuInner = elementTemplates.div.cloneNode(false),
          menuInnerInner = document.createElement('ul'),
          divider = elementTemplates.li.cloneNode(false),
          dropdownHeader = elementTemplates.li.cloneNode(false),
          li,
          a = elementTemplates.a.cloneNode(false),
          text = elementTemplates.span.cloneNode(false),
          header = this.options.header && this.\$menu.find('.' + classNames.POPOVERHEADER).length > 0 ? this.\$menu.find('.' + classNames.POPOVERHEADER)[0].cloneNode(true) : null,
          search = this.options.liveSearch ? elementTemplates.div.cloneNode(false) : null,
          actions = this.options.actionsBox && this.multiple && this.\$menu.find('.bs-actionsbox').length > 0 ? this.\$menu.find('.bs-actionsbox')[0].cloneNode(true) : null,
          doneButton = this.options.doneButton && this.multiple && this.\$menu.find('.bs-donebutton').length > 0 ? this.\$menu.find('.bs-donebutton')[0].cloneNode(true) : null,
          firstOption = this.\$element[0].options[0];

      this.sizeInfo.selectWidth = this.\$newElement[0].offsetWidth;

      text.className = 'text';
      a.className = 'dropdown-item ' + (firstOption ? firstOption.className : '');
      newElement.className = this.\$menu[0].parentNode.className + ' ' + classNames.SHOW;
      newElement.style.width = 0; // ensure button width doesn't affect natural width of menu when calculating
      if (this.options.width === 'auto') menu.style.minWidth = 0;
      menu.className = classNames.MENU + ' ' + classNames.SHOW;
      menuInner.className = 'inner ' + classNames.SHOW;
      menuInnerInner.className = classNames.MENU + ' inner ' + (version.major >= '4' ? classNames.SHOW : '');
      divider.className = classNames.DIVIDER;
      dropdownHeader.className = 'dropdown-header';

      text.appendChild(document.createTextNode('\\u200b'));

      if (this.selectpicker.current.data.length) {
        for (var i = 0; i < this.selectpicker.current.data.length; i++) {
          var data = this.selectpicker.current.data[i];
          if (data.type === 'option') {
            li = data.element;
            break;
          }
        }
      } else {
        li = elementTemplates.li.cloneNode(false);
        a.appendChild(text);
        li.appendChild(a);
      }

      dropdownHeader.appendChild(text.cloneNode(true));

      if (this.selectpicker.view.widestOption) {
        menuInnerInner.appendChild(this.selectpicker.view.widestOption.cloneNode(true));
      }

      menuInnerInner.appendChild(li);
      menuInnerInner.appendChild(divider);
      menuInnerInner.appendChild(dropdownHeader);
      if (header) menu.appendChild(header);
      if (search) {
        var input = document.createElement('input');
        search.className = 'bs-searchbox';
        input.className = 'form-control';
        search.appendChild(input);
        menu.appendChild(search);
      }
      if (actions) menu.appendChild(actions);
      menuInner.appendChild(menuInnerInner);
      menu.appendChild(menuInner);
      if (doneButton) menu.appendChild(doneButton);
      newElement.appendChild(menu);

      document.body.appendChild(newElement);

      var liHeight = li.offsetHeight,
          dropdownHeaderHeight = dropdownHeader ? dropdownHeader.offsetHeight : 0,
          headerHeight = header ? header.offsetHeight : 0,
          searchHeight = search ? search.offsetHeight : 0,
          actionsHeight = actions ? actions.offsetHeight : 0,
          doneButtonHeight = doneButton ? doneButton.offsetHeight : 0,
          dividerHeight = \$(divider).outerHeight(true),
          menuStyle = window.getComputedStyle(menu),
          menuWidth = menu.offsetWidth,
          menuPadding = {
            vert: toInteger(menuStyle.paddingTop) +
                  toInteger(menuStyle.paddingBottom) +
                  toInteger(menuStyle.borderTopWidth) +
                  toInteger(menuStyle.borderBottomWidth),
            horiz: toInteger(menuStyle.paddingLeft) +
                  toInteger(menuStyle.paddingRight) +
                  toInteger(menuStyle.borderLeftWidth) +
                  toInteger(menuStyle.borderRightWidth)
          },
          menuExtras = {
            vert: menuPadding.vert +
                  toInteger(menuStyle.marginTop) +
                  toInteger(menuStyle.marginBottom) + 2,
            horiz: menuPadding.horiz +
                  toInteger(menuStyle.marginLeft) +
                  toInteger(menuStyle.marginRight) + 2
          },
          scrollBarWidth;

      menuInner.style.overflowY = 'scroll';

      scrollBarWidth = menu.offsetWidth - menuWidth;

      document.body.removeChild(newElement);

      this.sizeInfo.liHeight = liHeight;
      this.sizeInfo.dropdownHeaderHeight = dropdownHeaderHeight;
      this.sizeInfo.headerHeight = headerHeight;
      this.sizeInfo.searchHeight = searchHeight;
      this.sizeInfo.actionsHeight = actionsHeight;
      this.sizeInfo.doneButtonHeight = doneButtonHeight;
      this.sizeInfo.dividerHeight = dividerHeight;
      this.sizeInfo.menuPadding = menuPadding;
      this.sizeInfo.menuExtras = menuExtras;
      this.sizeInfo.menuWidth = menuWidth;
      this.sizeInfo.menuInnerInnerWidth = menuWidth - menuPadding.horiz;
      this.sizeInfo.totalMenuWidth = this.sizeInfo.menuWidth;
      this.sizeInfo.scrollBarWidth = scrollBarWidth;
      this.sizeInfo.selectHeight = this.\$newElement[0].offsetHeight;

      this.setPositionData();
    },

    getSelectPosition: function () {
      var that = this,
          \$window = \$(window),
          pos = that.\$newElement.offset(),
          \$container = \$(that.options.container),
          containerPos;

      if (that.options.container && \$container.length && !\$container.is('body')) {
        containerPos = \$container.offset();
        containerPos.top += parseInt(\$container.css('borderTopWidth'));
        containerPos.left += parseInt(\$container.css('borderLeftWidth'));
      } else {
        containerPos = { top: 0, left: 0 };
      }

      var winPad = that.options.windowPadding;

      this.sizeInfo.selectOffsetTop = pos.top - containerPos.top - \$window.scrollTop();
      this.sizeInfo.selectOffsetBot = \$window.height() - this.sizeInfo.selectOffsetTop - this.sizeInfo.selectHeight - containerPos.top - winPad[2];
      this.sizeInfo.selectOffsetLeft = pos.left - containerPos.left - \$window.scrollLeft();
      this.sizeInfo.selectOffsetRight = \$window.width() - this.sizeInfo.selectOffsetLeft - this.sizeInfo.selectWidth - containerPos.left - winPad[1];
      this.sizeInfo.selectOffsetTop -= winPad[0];
      this.sizeInfo.selectOffsetLeft -= winPad[3];
    },

    setMenuSize: function (isAuto) {
      this.getSelectPosition();

      var selectWidth = this.sizeInfo.selectWidth,
          liHeight = this.sizeInfo.liHeight,
          headerHeight = this.sizeInfo.headerHeight,
          searchHeight = this.sizeInfo.searchHeight,
          actionsHeight = this.sizeInfo.actionsHeight,
          doneButtonHeight = this.sizeInfo.doneButtonHeight,
          divHeight = this.sizeInfo.dividerHeight,
          menuPadding = this.sizeInfo.menuPadding,
          menuInnerHeight,
          menuHeight,
          divLength = 0,
          minHeight,
          _minHeight,
          maxHeight,
          menuInnerMinHeight,
          estimate,
          isDropup;

      if (this.options.dropupAuto) {
        // Get the estimated height of the menu without scrollbars.
        // This is useful for smaller menus, where there might be plenty of room
        // below the button without setting dropup, but we can't know
        // the exact height of the menu until createView is called later
        estimate = liHeight * this.selectpicker.current.data.length + menuPadding.vert;

        isDropup = this.sizeInfo.selectOffsetTop - this.sizeInfo.selectOffsetBot > this.sizeInfo.menuExtras.vert && estimate + this.sizeInfo.menuExtras.vert + 50 > this.sizeInfo.selectOffsetBot;

        // ensure dropup doesn't change while searching (so menu doesn't bounce back and forth)
        if (this.selectpicker.isSearching === true) {
          isDropup = this.selectpicker.dropup;
        }

        this.\$newElement.toggleClass(classNames.DROPUP, isDropup);
        this.selectpicker.dropup = isDropup;
      }

      if (this.options.size === 'auto') {
        _minHeight = this.selectpicker.current.data.length > 3 ? this.sizeInfo.liHeight * 3 + this.sizeInfo.menuExtras.vert - 2 : 0;
        menuHeight = this.sizeInfo.selectOffsetBot - this.sizeInfo.menuExtras.vert;
        minHeight = _minHeight + headerHeight + searchHeight + actionsHeight + doneButtonHeight;
        menuInnerMinHeight = Math.max(_minHeight - menuPadding.vert, 0);

        if (this.\$newElement.hasClass(classNames.DROPUP)) {
          menuHeight = this.sizeInfo.selectOffsetTop - this.sizeInfo.menuExtras.vert;
        }

        maxHeight = menuHeight;
        menuInnerHeight = menuHeight - headerHeight - searchHeight - actionsHeight - doneButtonHeight - menuPadding.vert;
      } else if (this.options.size && this.options.size != 'auto' && this.selectpicker.current.elements.length > this.options.size) {
        for (var i = 0; i < this.options.size; i++) {
          if (this.selectpicker.current.data[i].type === 'divider') divLength++;
        }

        menuHeight = liHeight * this.options.size + divLength * divHeight + menuPadding.vert;
        menuInnerHeight = menuHeight - menuPadding.vert;
        maxHeight = menuHeight + headerHeight + searchHeight + actionsHeight + doneButtonHeight;
        minHeight = menuInnerMinHeight = '';
      }

      this.\$menu.css({
        'max-height': maxHeight + 'px',
        'overflow': 'hidden',
        'min-height': minHeight + 'px'
      });

      this.\$menuInner.css({
        'max-height': menuInnerHeight + 'px',
        'overflow-y': 'auto',
        'min-height': menuInnerMinHeight + 'px'
      });

      // ensure menuInnerHeight is always a positive number to prevent issues calculating chunkSize in createView
      this.sizeInfo.menuInnerHeight = Math.max(menuInnerHeight, 1);

      if (this.selectpicker.current.data.length && this.selectpicker.current.data[this.selectpicker.current.data.length - 1].position > this.sizeInfo.menuInnerHeight) {
        this.sizeInfo.hasScrollBar = true;
        this.sizeInfo.totalMenuWidth = this.sizeInfo.menuWidth + this.sizeInfo.scrollBarWidth;
      }

      if (this.options.dropdownAlignRight === 'auto') {
        this.\$menu.toggleClass(classNames.MENURIGHT, this.sizeInfo.selectOffsetLeft > this.sizeInfo.selectOffsetRight && this.sizeInfo.selectOffsetRight < (this.sizeInfo.totalMenuWidth - selectWidth));
      }

      if (this.dropdown && this.dropdown._popper) this.dropdown._popper.update();
    },

    setSize: function (refresh) {
      this.liHeight(refresh);

      if (this.options.header) this.\$menu.css('padding-top', 0);

      if (this.options.size !== false) {
        var that = this,
            \$window = \$(window);

        this.setMenuSize();

        if (this.options.liveSearch) {
          this.\$searchbox
            .off('input.setMenuSize propertychange.setMenuSize')
            .on('input.setMenuSize propertychange.setMenuSize', function () {
              return that.setMenuSize();
            });
        }

        if (this.options.size === 'auto') {
          \$window
            .off('resize' + EVENT_KEY + '.' + this.selectId + '.setMenuSize' + ' scroll' + EVENT_KEY + '.' + this.selectId + '.setMenuSize')
            .on('resize' + EVENT_KEY + '.' + this.selectId + '.setMenuSize' + ' scroll' + EVENT_KEY + '.' + this.selectId + '.setMenuSize', function () {
              return that.setMenuSize();
            });
        } else if (this.options.size && this.options.size != 'auto' && this.selectpicker.current.elements.length > this.options.size) {
          \$window.off('resize' + EVENT_KEY + '.' + this.selectId + '.setMenuSize' + ' scroll' + EVENT_KEY + '.' + this.selectId + '.setMenuSize');
        }
      }

      this.createView(false, true, refresh);
    },

    setWidth: function () {
      var that = this;

      if (this.options.width === 'auto') {
        requestAnimationFrame(function () {
          that.\$menu.css('min-width', '0');

          that.\$element.on('loaded' + EVENT_KEY, function () {
            that.liHeight();
            that.setMenuSize();

            // Get correct width if element is hidden
            var \$selectClone = that.\$newElement.clone().appendTo('body'),
                btnWidth = \$selectClone.css('width', 'auto').children('button').outerWidth();

            \$selectClone.remove();

            // Set width to whatever's larger, button title or longest option
            that.sizeInfo.selectWidth = Math.max(that.sizeInfo.totalMenuWidth, btnWidth);
            that.\$newElement.css('width', that.sizeInfo.selectWidth + 'px');
          });
        });
      } else if (this.options.width === 'fit') {
        // Remove inline min-width so width can be changed from 'auto'
        this.\$menu.css('min-width', '');
        this.\$newElement.css('width', '').addClass('fit-width');
      } else if (this.options.width) {
        // Remove inline min-width so width can be changed from 'auto'
        this.\$menu.css('min-width', '');
        this.\$newElement.css('width', this.options.width);
      } else {
        // Remove inline min-width/width so width can be changed
        this.\$menu.css('min-width', '');
        this.\$newElement.css('width', '');
      }
      // Remove fit-width class if width is changed programmatically
      if (this.\$newElement.hasClass('fit-width') && this.options.width !== 'fit') {
        this.\$newElement[0].classList.remove('fit-width');
      }
    },

    selectPosition: function () {
      this.\$bsContainer = \$('<div class=\"bs-container\" />');

      var that = this,
          \$container = \$(this.options.container),
          pos,
          containerPos,
          actualHeight,
          getPlacement = function (\$element) {
            var containerPosition = {},
                // fall back to dropdown's default display setting if display is not manually set
                display = that.options.display || (
                  // Bootstrap 3 doesn't have \$.fn.dropdown.Constructor.Default
                  \$.fn.dropdown.Constructor.Default ? \$.fn.dropdown.Constructor.Default.display
                  : false
                );

            that.\$bsContainer.addClass(\$element.attr('class').replace(/form-control|fit-width/gi, '')).toggleClass(classNames.DROPUP, \$element.hasClass(classNames.DROPUP));
            pos = \$element.offset();

            if (!\$container.is('body')) {
              containerPos = \$container.offset();
              containerPos.top += parseInt(\$container.css('borderTopWidth')) - \$container.scrollTop();
              containerPos.left += parseInt(\$container.css('borderLeftWidth')) - \$container.scrollLeft();
            } else {
              containerPos = { top: 0, left: 0 };
            }

            actualHeight = \$element.hasClass(classNames.DROPUP) ? 0 : \$element[0].offsetHeight;

            // Bootstrap 4+ uses Popper for menu positioning
            if (version.major < 4 || display === 'static') {
              containerPosition.top = pos.top - containerPos.top + actualHeight;
              containerPosition.left = pos.left - containerPos.left;
            }

            containerPosition.width = \$element[0].offsetWidth;

            that.\$bsContainer.css(containerPosition);
          };

      this.\$button.on('click.bs.dropdown.data-api', function () {
        if (that.isDisabled()) {
          return;
        }

        getPlacement(that.\$newElement);

        that.\$bsContainer
          .appendTo(that.options.container)
          .toggleClass(classNames.SHOW, !that.\$button.hasClass(classNames.SHOW))
          .append(that.\$menu);
      });

      \$(window)
        .off('resize' + EVENT_KEY + '.' + this.selectId + ' scroll' + EVENT_KEY + '.' + this.selectId)
        .on('resize' + EVENT_KEY + '.' + this.selectId + ' scroll' + EVENT_KEY + '.' + this.selectId, function () {
          var isActive = that.\$newElement.hasClass(classNames.SHOW);

          if (isActive) getPlacement(that.\$newElement);
        });

      this.\$element.on('hide' + EVENT_KEY, function () {
        that.\$menu.data('height', that.\$menu.height());
        that.\$bsContainer.detach();
      });
    },

    createOption: function (data, init) {
      var optionData = !data.option ? data : data.option;

      if (optionData && optionData.nodeType !== 1) {
        var option = (init ? elementTemplates.selectedOption : elementTemplates.option).cloneNode(true);
        if (optionData.value !== undefined) option.value = optionData.value;
        option.textContent = optionData.text;

        option.selected = true;

        if (optionData.liIndex !== undefined) {
          option.liIndex = optionData.liIndex;
        } else if (!init) {
          option.liIndex = data.index;
        }

        data.option = option;

        this.selectpicker.main.optionQueue.appendChild(option);
      }
    },

    setOptionStatus: function (selectedOnly) {
      var that = this;

      that.noScroll = false;

      if (that.selectpicker.view.visibleElements && that.selectpicker.view.visibleElements.length) {
        for (var i = 0; i < that.selectpicker.view.visibleElements.length; i++) {
          var liData = that.selectpicker.current.data[i + that.selectpicker.view.position0],
              option = liData.option;

          if (option) {
            if (selectedOnly !== true) {
              that.setDisabled(liData);
            }

            that.setSelected(liData);
          }
        }

        // append optionQueue (documentFragment with option elements for select options)
        if (this.options.source.data) this.\$element[0].appendChild(this.selectpicker.main.optionQueue);
      }
    },

    /**
     * @param {number} index - the index of the option that is being changed
     * @param {boolean} selected - true if the option is being selected, false if being deselected
     */
    setSelected: function (liData, selected) {
      selected = selected === undefined ? liData.selected : selected;

      var index = liData.index,
          li = liData.element,
          activeIndexIsSet = this.activeIndex !== undefined,
          thisIsActive = this.activeIndex === index,
          prevActive,
          a,
          // if current option is already active
          // OR
          // if the current option is being selected, it's NOT multiple, and
          // activeIndex is undefined:
          //  - when the menu is first being opened, OR
          //  - after a search has been performed, OR
          //  - when retainActive is false when selecting a new option (i.e. index of the newly selected option is not the same as the current activeIndex)
          keepActive = thisIsActive || (selected && !this.multiple && !activeIndexIsSet);

      if (!li) return;

      if (selected !== undefined) {
        liData.selected = selected;
        if (liData.option) liData.option.selected = selected;
      }

      if (selected && this.options.source.data) {
        this.createOption(liData, false);
      }

      a = li.firstChild;

      if (selected) {
        this.selectedIndex = index;
      }

      li.classList.toggle('selected', selected);

      if (keepActive) {
        this.focusItem(li, liData);
        this.selectpicker.view.currentActive = li;
        this.activeIndex = index;
      } else {
        this.defocusItem(li);
      }

      if (a) {
        a.classList.toggle('selected', selected);

        if (selected) {
          a.setAttribute('aria-selected', true);
        } else {
          if (this.multiple) {
            a.setAttribute('aria-selected', false);
          } else {
            a.removeAttribute('aria-selected');
          }
        }
      }

      if (!keepActive && !activeIndexIsSet && selected && this.prevActiveIndex !== undefined) {
        prevActive = this.selectpicker.main.elements[this.prevActiveIndex];

        this.defocusItem(prevActive);
      }
    },

    /**
     * @param {number} index - the index of the option that is being disabled
     * @param {boolean} disabled - true if the option is being disabled, false if being enabled
     */
    setDisabled: function (liData) {
      var disabled = liData.disabled,
          li = liData.element,
          a;

      if (!li) return;

      a = li.firstChild;

      li.classList.toggle(classNames.DISABLED, disabled);

      if (a) {
        if (version.major >= '4') a.classList.toggle(classNames.DISABLED, disabled);

        if (disabled) {
          a.setAttribute('aria-disabled', disabled);
          a.setAttribute('tabindex', -1);
        } else {
          a.removeAttribute('aria-disabled');
          a.setAttribute('tabindex', 0);
        }
      }
    },

    isDisabled: function () {
      return this.\$element[0].disabled;
    },

    checkDisabled: function () {
      if (this.isDisabled()) {
        this.\$newElement[0].classList.add(classNames.DISABLED);
        this.\$button.addClass(classNames.DISABLED).attr('aria-disabled', true);
      } else {
        if (this.\$button[0].classList.contains(classNames.DISABLED)) {
          this.\$newElement[0].classList.remove(classNames.DISABLED);
          this.\$button.removeClass(classNames.DISABLED).attr('aria-disabled', false);
        }
      }
    },

    clickListener: function () {
      var that = this,
          \$document = \$(document);

      \$document.data('spaceSelect', false);

      this.\$button.on('keyup', function (e) {
        if (/(32)/.test(e.keyCode.toString(10)) && \$document.data('spaceSelect')) {
          e.preventDefault();
          \$document.data('spaceSelect', false);
        }
      });

      this.\$newElement.on('show.bs.dropdown', function () {
        if (!that.dropdown && version.major === '4') {
          that.dropdown = that.\$button.data('bs.dropdown');
          that.dropdown._menu = that.\$menu[0];
        }
      });

      function clearSelection (e) {
        if (that.multiple) {
          that.deselectAll();
        } else {
          var element = that.\$element[0],
              prevValue = element.value,
              prevIndex = element.selectedIndex,
              prevOption = element.options[prevIndex],
              prevData = prevOption ? that.selectpicker.main.data[prevOption.liIndex] : false;

          if (prevData) {
            that.setSelected(prevData, false);
          }

          element.selectedIndex = 0;

          changedArguments = [prevIndex, false, prevValue];
          that.\$element.triggerNative('change');
        }

        // remove selected styling if menu is open
        if (that.\$newElement.hasClass(classNames.SHOW)) {
          if (that.options.liveSearch) {
            that.\$searchbox.trigger('focus');
          }

          that.createView(false);
        }
      }

      this.\$button.on('click.bs.dropdown.data-api', function (e) {
        if (that.options.allowClear) {
          var target = e.target,
              clearButton = that.\$clearButton[0];

          // IE doesn't support event listeners on child elements of buttons
          if (/MSIE|Trident/.test(window.navigator.userAgent)) {
            target = document.elementFromPoint(e.clientX, e.clientY);
          }

          if (target === clearButton || target.parentElement === clearButton) {
            e.stopImmediatePropagation();
            clearSelection(e);
          }
        }

        if (!that.\$newElement.hasClass(classNames.SHOW)) {
          that.setSize();
        }
      });

      function setFocus () {
        if (that.options.liveSearch) {
          that.\$searchbox.trigger('focus');
        } else {
          that.\$menuInner.trigger('focus');
        }
      }

      function checkPopperExists () {
        if (that.dropdown && that.dropdown._popper && that.dropdown._popper.state) {
          setFocus();
        } else {
          requestAnimationFrame(checkPopperExists);
        }
      }

      this.\$element.on('shown' + EVENT_KEY, function () {
        if (that.\$menuInner[0].scrollTop !== that.selectpicker.view.scrollTop) {
          that.\$menuInner[0].scrollTop = that.selectpicker.view.scrollTop;
        }

        if (version.major > 3) {
          requestAnimationFrame(checkPopperExists);
        } else {
          setFocus();
        }
      });

      // ensure posinset and setsize are correct before selecting an option via a click
      this.\$menuInner.on('mouseenter', 'li a', function (e) {
        var hoverLi = this.parentElement,
            position0 = that.isVirtual() ? that.selectpicker.view.position0 : 0,
            index = Array.prototype.indexOf.call(hoverLi.parentElement.children, hoverLi),
            hoverData = that.selectpicker.current.data[index + position0];

        that.focusItem(hoverLi, hoverData, true);
      });

      this.\$menuInner.on('click', 'li a', function (e, retainActive) {
        var \$this = \$(this),
            element = that.\$element[0],
            position0 = that.isVirtual() ? that.selectpicker.view.position0 : 0,
            clickedData = that.selectpicker.current.data[\$this.parent().index() + position0],
            clickedIndex = clickedData.index,
            prevValue = getSelectValues.call(that),
            prevIndex = element.selectedIndex,
            prevOption = element.options[prevIndex],
            prevData = prevOption ? that.selectpicker.main.data[prevOption.liIndex] : false,
            triggerChange = true;

        // Don't close on multi choice menu
        if (that.multiple && that.options.maxOptions !== 1) {
          e.stopPropagation();
        }

        e.preventDefault();

        // Don't run if the select is disabled
        if (!that.isDisabled() && !\$this.parent().hasClass(classNames.DISABLED)) {
          var option = clickedData.option,
              \$option = \$(option),
              state = option.selected,
              \$optgroup = \$option.parent('optgroup'),
              \$optgroupOptions = \$optgroup.find('option'),
              maxOptions = that.options.maxOptions,
              maxOptionsGrp = \$optgroup.data('maxOptions') || false;

          if (clickedIndex === that.activeIndex) retainActive = true;

          if (!retainActive) {
            that.prevActiveIndex = that.activeIndex;
            that.activeIndex = undefined;
          }

          if (!that.multiple) { // Deselect previous option if not multi select
            if (prevData) that.setSelected(prevData, false);
            that.setSelected(clickedData, true);
          } else { // Toggle the clicked option if multi select.
            that.setSelected(clickedData, !state);
            that.focusedParent.focus();

            if (maxOptions !== false || maxOptionsGrp !== false) {
              var maxReached = maxOptions < getSelectedOptions.call(that).length,
                  maxReachedGrp = maxOptionsGrp < \$optgroup.find('option:selected').length;

              if ((maxOptions && maxReached) || (maxOptionsGrp && maxReachedGrp)) {
                if (maxOptions && maxOptions == 1) {
                  element.selectedIndex = -1;
                  option.selected = true;
                  that.setOptionStatus(true);
                } else if (maxOptionsGrp && maxOptionsGrp == 1) {
                  for (var i = 0; i < \$optgroupOptions.length; i++) {
                    var _option = \$optgroupOptions[i];
                    _option.selected = false;
                    that.setSelected(_option.liIndex, false);
                  }

                  option.selected = true;
                  that.setSelected(clickedIndex, true);
                } else {
                  var maxOptionsText = typeof that.options.maxOptionsText === 'string' ? [that.options.maxOptionsText, that.options.maxOptionsText] : that.options.maxOptionsText,
                      maxOptionsArr = typeof maxOptionsText === 'function' ? maxOptionsText(maxOptions, maxOptionsGrp) : maxOptionsText,
                      maxTxt = maxOptionsArr[0].replace('{n}', maxOptions),
                      maxTxtGrp = maxOptionsArr[1].replace('{n}', maxOptionsGrp),
                      \$notify = \$('<div class=\"notify\"></div>');
                  // If {var} is set in array, replace it
                  /** @deprecated */
                  if (maxOptionsArr[2]) {
                    maxTxt = maxTxt.replace('{var}', maxOptionsArr[2][maxOptions > 1 ? 0 : 1]);
                    maxTxtGrp = maxTxtGrp.replace('{var}', maxOptionsArr[2][maxOptionsGrp > 1 ? 0 : 1]);
                  }

                  option.selected = false;

                  that.\$menu.append(\$notify);

                  if (maxOptions && maxReached) {
                    \$notify.append(\$('<div>' + maxTxt + '</div>'));
                    triggerChange = false;
                    that.\$element.trigger('maxReached' + EVENT_KEY);
                  }

                  if (maxOptionsGrp && maxReachedGrp) {
                    \$notify.append(\$('<div>' + maxTxtGrp + '</div>'));
                    triggerChange = false;
                    that.\$element.trigger('maxReachedGrp' + EVENT_KEY);
                  }

                  setTimeout(function () {
                    that.setSelected(clickedIndex, false);
                  }, 10);

                  \$notify[0].classList.add('fadeOut');

                  setTimeout(function () {
                    \$notify.remove();
                  }, 1050);
                }
              }
            }
          }

          if (that.options.source.data) that.\$element[0].appendChild(that.selectpicker.main.optionQueue);

          if (!that.multiple || (that.multiple && that.options.maxOptions === 1)) {
            that.\$button.trigger('focus');
          } else if (that.options.liveSearch) {
            that.\$searchbox.trigger('focus');
          }

          // Trigger select 'change'
          if (triggerChange) {
            if (that.multiple || prevIndex !== element.selectedIndex) {
              // \$option.prop('selected') is current option state (selected/unselected). prevValue is the value of the select prior to being changed.
              changedArguments = [option.index, \$option.prop('selected'), prevValue];
              that.\$element
                .triggerNative('change');
            }
          }
        }
      });

      this.\$menu.on('click', 'li.' + classNames.DISABLED + ' a, .' + classNames.POPOVERHEADER + ', .' + classNames.POPOVERHEADER + ' :not(.close)', function (e) {
        if (e.currentTarget == this) {
          e.preventDefault();
          e.stopPropagation();
          if (that.options.liveSearch && !\$(e.target).hasClass('close')) {
            that.\$searchbox.trigger('focus');
          } else {
            that.\$button.trigger('focus');
          }
        }
      });

      this.\$menuInner.on('click', '.divider, .dropdown-header', function (e) {
        e.preventDefault();
        e.stopPropagation();
        if (that.options.liveSearch) {
          that.\$searchbox.trigger('focus');
        } else {
          that.\$button.trigger('focus');
        }
      });

      this.\$menu.on('click', '.' + classNames.POPOVERHEADER + ' .close', function () {
        that.\$button.trigger('click');
      });

      this.\$searchbox.on('click', function (e) {
        e.stopPropagation();
      });

      this.\$menu.on('click', '.actions-btn', function (e) {
        if (that.options.liveSearch) {
          that.\$searchbox.trigger('focus');
        } else {
          that.\$button.trigger('focus');
        }

        e.preventDefault();
        e.stopPropagation();

        if (\$(this).hasClass('bs-select-all')) {
          that.selectAll();
        } else {
          that.deselectAll();
        }
      });

      this.\$button
        .on('focus' + EVENT_KEY, function (e) {
          var tabindex = that.\$element[0].getAttribute('tabindex');

          // only change when button is actually focused
          if (tabindex !== undefined && e.originalEvent && e.originalEvent.isTrusted) {
            // apply select element's tabindex to ensure correct order is followed when tabbing to the next element
            this.setAttribute('tabindex', tabindex);
            // set element's tabindex to -1 to allow for reverse tabbing
            that.\$element[0].setAttribute('tabindex', -1);
            that.selectpicker.view.tabindex = tabindex;
          }
        })
        .on('blur' + EVENT_KEY, function (e) {
          // revert everything to original tabindex
          if (that.selectpicker.view.tabindex !== undefined && e.originalEvent && e.originalEvent.isTrusted) {
            that.\$element[0].setAttribute('tabindex', that.selectpicker.view.tabindex);
            this.setAttribute('tabindex', -1);
            that.selectpicker.view.tabindex = undefined;
          }
        });

      this.\$element
        .on('change' + EVENT_KEY, function () {
          that.render();
          that.\$element.trigger('changed' + EVENT_KEY, changedArguments);
          changedArguments = null;
        })
        .on('focus' + EVENT_KEY, function () {
          if (!that.options.mobile) that.\$button[0].focus();
        });
    },

    liveSearchListener: function () {
      var that = this;

      this.\$button.on('click.bs.dropdown.data-api', function () {
        if (!!that.\$searchbox.val()) {
          that.\$searchbox.val('');
          that.selectpicker.search.previousValue = undefined;
        }
      });

      this.\$searchbox.on('click.bs.dropdown.data-api focus.bs.dropdown.data-api touchend.bs.dropdown.data-api', function (e) {
        e.stopPropagation();
      });

      this.\$searchbox.on('input propertychange', function () {
        var searchValue = that.\$searchbox[0].value;

        that.selectpicker.search.elements = [];
        that.selectpicker.search.data = [];

        if (searchValue) {
          if (that.options.source.search) {
            that.fetchData(function (builtData) {
              that.render();
              that.buildList(undefined, true);
              that.createView(true);
              showNoResults.call(that, builtData, searchValue);
            }, 'search', 0, searchValue);
          } else {
            var i,
                searchMatch = [],
                q = searchValue.toUpperCase(),
                cache = {},
                cacheArr = [],
                searchStyle = that._searchStyle(),
                normalizeSearch = that.options.liveSearchNormalize;

            if (normalizeSearch) q = normalizeToBase(q);

            for (var i = 0; i < that.selectpicker.main.data.length; i++) {
              var li = that.selectpicker.main.data[i];

              if (!cache[i]) {
                cache[i] = stringSearch(li, q, searchStyle, normalizeSearch);
              }

              if (cache[i] && li.headerIndex !== undefined && cacheArr.indexOf(li.headerIndex) === -1) {
                if (li.headerIndex > 0) {
                  cache[li.headerIndex - 1] = true;
                  cacheArr.push(li.headerIndex - 1);
                }

                cache[li.headerIndex] = true;
                cacheArr.push(li.headerIndex);

                cache[li.lastIndex + 1] = true;
              }

              if (cache[i] && li.type !== 'optgroup-label') cacheArr.push(i);
            }

            for (var i = 0, cacheLen = cacheArr.length; i < cacheLen; i++) {
              var index = cacheArr[i],
                  prevIndex = cacheArr[i - 1],
                  li = that.selectpicker.main.data[index],
                  liPrev = that.selectpicker.main.data[prevIndex];

              if (li.type !== 'divider' || (li.type === 'divider' && liPrev && liPrev.type !== 'divider' && cacheLen - 1 !== i)) {
                that.selectpicker.search.data.push(li);
                searchMatch.push(that.selectpicker.main.elements[index]);
              }
            }

            that.activeIndex = undefined;
            that.noScroll = true;
            that.\$menuInner.scrollTop(0);
            that.selectpicker.search.elements = searchMatch;
            that.createView(true);
            showNoResults.call(that, searchMatch, searchValue);
          }
        } else if (that.selectpicker.search.previousValue) { // for IE11 (#2402)
          that.\$menuInner.scrollTop(0);
          that.createView(false);
        }

        that.selectpicker.search.previousValue =  searchValue;
      });
    },

    _searchStyle: function () {
      return this.options.liveSearchStyle || 'contains';
    },

    val: function (value) {
      var element = this.\$element[0];

      if (typeof value !== 'undefined') {
        var selectedOptions = getSelectedOptions.call(this),
            prevValue = getSelectValues.call(this, selectedOptions);

        changedArguments = [null, null, prevValue];

        if (!Array.isArray(value)) value = [ value ];

        value.map(String);

        for (var i = 0; i < selectedOptions.length; i++) {
          var item = selectedOptions[i];

          if (item && value.indexOf(String(item.value)) === -1) {
            this.setSelected(item, false);
          }
        }

        // only update selected value if it matches an existing option
        this.selectpicker.main.data.filter(function (item) {
          if (value.indexOf(String(item.value)) !== -1) {
            this.setSelected(item, true);
            return true;
          }

          return false;
        }, this);

        if (this.options.source.data) element.appendChild(this.selectpicker.main.optionQueue);

        this.\$element.trigger('changed' + EVENT_KEY, changedArguments);

        if (this.\$newElement.hasClass(classNames.SHOW)) {
          if (this.multiple) {
            this.setOptionStatus(true);
          } else {
            var liSelectedIndex = (element.options[element.selectedIndex] || {}).liIndex;

            if (typeof liSelectedIndex === 'number') {
              this.setSelected(this.selectedIndex, false);
              this.setSelected(liSelectedIndex, true);
            }
          }
        }

        this.render();

        changedArguments = null;

        return this.\$element;
      } else {
        return this.\$element.val();
      }
    },

    changeAll: function (status) {
      if (!this.multiple) return;
      if (typeof status === 'undefined') status = true;

      var element = this.\$element[0],
          previousSelected = 0,
          currentSelected = 0,
          prevValue = getSelectValues.call(this);

      element.classList.add('bs-select-hidden');

      for (var i = 0, data = this.selectpicker.current.data, len = data.length; i < len; i++) {
        var liData = data[i],
            option = liData.option;

        if (option && !liData.disabled && liData.type !== 'divider') {
          if (liData.selected) previousSelected++;
          option.selected = status;
          liData.selected = status;
          if (status === true) currentSelected++;
        }
      }

      element.classList.remove('bs-select-hidden');

      if (previousSelected === currentSelected) return;

      this.setOptionStatus();

      changedArguments = [null, null, prevValue];

      this.\$element
        .triggerNative('change');
    },

    selectAll: function () {
      return this.changeAll(true);
    },

    deselectAll: function () {
      return this.changeAll(false);
    },

    toggle: function (e, state) {
      var isActive,
          triggerClick = state === undefined;

      e = e || window.event;

      if (e) e.stopPropagation();

      if (triggerClick === false) {
        isActive = this.\$newElement[0].classList.contains(classNames.SHOW);
        triggerClick = state === true && isActive === false || state === false && isActive === true;
      }

      if (triggerClick) this.\$button.trigger('click.bs.dropdown.data-api');
    },

    open: function (e) {
      this.toggle(e, true);
    },

    close: function (e) {
      this.toggle(e, false);
    },

    keydown: function (e) {
      var \$this = \$(this),
          isToggle = \$this.hasClass('dropdown-toggle'),
          \$parent = isToggle ? \$this.closest('.dropdown') : \$this.closest(Selector.MENU),
          that = \$parent.data('this'),
          \$items = that.findLis(),
          index,
          isActive,
          liActive,
          activeLi,
          offset,
          updateScroll = false,
          downOnTab = e.which === keyCodes.TAB && !isToggle && !that.options.selectOnTab,
          isArrowKey = REGEXP_ARROW.test(e.which) || downOnTab,
          scrollTop = that.\$menuInner[0].scrollTop,
          isVirtual = that.isVirtual(),
          position0 = isVirtual === true ? that.selectpicker.view.position0 : 0;

      // do nothing if a function key is pressed
      if (e.which >= 112 && e.which <= 123) return;

      isActive = that.\$menu.hasClass(classNames.SHOW);

      if (
        !isActive &&
        (
          isArrowKey ||
          (e.which >= 48 && e.which <= 57) ||
          (e.which >= 96 && e.which <= 105) ||
          (e.which >= 65 && e.which <= 90)
        )
      ) {
        that.\$button.trigger('click.bs.dropdown.data-api');

        if (that.options.liveSearch) {
          that.\$searchbox.trigger('focus');
          return;
        }
      }

      if (e.which === keyCodes.ESCAPE && isActive) {
        e.preventDefault();
        that.\$button.trigger('click.bs.dropdown.data-api').trigger('focus');
      }

      if (isArrowKey) { // if up or down
        if (!\$items.length) return;

        liActive = that.selectpicker.main.elements[that.activeIndex];
        index = liActive ? Array.prototype.indexOf.call(liActive.parentElement.children, liActive) : -1;

        if (index !== -1) {
          that.defocusItem(liActive);
        }

        if (e.which === keyCodes.ARROW_UP) { // up
          if (index !== -1) index--;
          if (index + position0 < 0) index += \$items.length;

          if (!that.selectpicker.view.canHighlight[index + position0]) {
            index = that.selectpicker.view.canHighlight.slice(0, index + position0).lastIndexOf(true) - position0;
            if (index === -1) index = \$items.length - 1;
          }
        } else if (e.which === keyCodes.ARROW_DOWN || downOnTab) { // down
          index++;
          if (index + position0 >= that.selectpicker.view.canHighlight.length) index = that.selectpicker.view.firstHighlightIndex;

          if (!that.selectpicker.view.canHighlight[index + position0]) {
            index = index + 1 + that.selectpicker.view.canHighlight.slice(index + position0 + 1).indexOf(true);
          }
        }

        e.preventDefault();

        var liActiveIndex = position0 + index;

        if (e.which === keyCodes.ARROW_UP) { // up
          // scroll to bottom and highlight last option
          if (position0 === 0 && index === \$items.length - 1) {
            that.\$menuInner[0].scrollTop = that.\$menuInner[0].scrollHeight;

            liActiveIndex = that.selectpicker.current.elements.length - 1;
          } else {
            activeLi = that.selectpicker.current.data[liActiveIndex];
            offset = activeLi.position - activeLi.height;

            updateScroll = offset < scrollTop;
          }
        } else if (e.which === keyCodes.ARROW_DOWN || downOnTab) { // down
          // scroll to top and highlight first option
          if (index === that.selectpicker.view.firstHighlightIndex) {
            that.\$menuInner[0].scrollTop = 0;

            liActiveIndex = that.selectpicker.view.firstHighlightIndex;
          } else {
            activeLi = that.selectpicker.current.data[liActiveIndex];
            offset = activeLi.position - that.sizeInfo.menuInnerHeight;

            updateScroll = offset > scrollTop;
          }
        }

        liActive = that.selectpicker.current.elements[liActiveIndex];

        that.activeIndex = that.selectpicker.current.data[liActiveIndex].index;

        that.focusItem(liActive);

        that.selectpicker.view.currentActive = liActive;

        if (updateScroll) that.\$menuInner[0].scrollTop = offset;

        if (that.options.liveSearch) {
          that.\$searchbox.trigger('focus');
        } else {
          \$this.trigger('focus');
        }
      } else if (
        (!\$this.is('input') && !REGEXP_TAB_OR_ESCAPE.test(e.which)) ||
        (e.which === keyCodes.SPACE && that.selectpicker.keydown.keyHistory)
      ) {
        var searchMatch,
            matches = [],
            keyHistory;

        e.preventDefault();

        that.selectpicker.keydown.keyHistory += keyCodeMap[e.which];

        if (that.selectpicker.keydown.resetKeyHistory.cancel) clearTimeout(that.selectpicker.keydown.resetKeyHistory.cancel);
        that.selectpicker.keydown.resetKeyHistory.cancel = that.selectpicker.keydown.resetKeyHistory.start();

        keyHistory = that.selectpicker.keydown.keyHistory;

        // if all letters are the same, set keyHistory to just the first character when searching
        if (/^(.)\\1+\$/.test(keyHistory)) {
          keyHistory = keyHistory.charAt(0);
        }

        // find matches
        for (var i = 0; i < that.selectpicker.current.data.length; i++) {
          var li = that.selectpicker.current.data[i],
              hasMatch;

          hasMatch = stringSearch(li, keyHistory, 'startsWith', true);

          if (hasMatch && that.selectpicker.view.canHighlight[i]) {
            matches.push(li.index);
          }
        }

        if (matches.length) {
          var matchIndex = 0;

          \$items.removeClass('active').find('a').removeClass('active');

          // either only one key has been pressed or they are all the same key
          if (keyHistory.length === 1) {
            matchIndex = matches.indexOf(that.activeIndex);

            if (matchIndex === -1 || matchIndex === matches.length - 1) {
              matchIndex = 0;
            } else {
              matchIndex++;
            }
          }

          searchMatch = matches[matchIndex];

          activeLi = that.selectpicker.main.data[searchMatch];

          if (scrollTop - activeLi.position > 0) {
            offset = activeLi.position - activeLi.height;
            updateScroll = true;
          } else {
            offset = activeLi.position - that.sizeInfo.menuInnerHeight;
            // if the option is already visible at the current scroll position, just keep it the same
            updateScroll = activeLi.position > scrollTop + that.sizeInfo.menuInnerHeight;
          }

          liActive = that.selectpicker.main.elements[searchMatch];

          that.activeIndex = matches[matchIndex];

          that.focusItem(liActive);

          if (liActive) liActive.firstChild.focus();

          if (updateScroll) that.\$menuInner[0].scrollTop = offset;

          \$this.trigger('focus');
        }
      }

      // Select focused option if \"Enter\", \"Spacebar\" or \"Tab\" (when selectOnTab is true) are pressed inside the menu.
      if (
        isActive &&
        (
          (e.which === keyCodes.SPACE && !that.selectpicker.keydown.keyHistory) ||
          e.which === keyCodes.ENTER ||
          (e.which === keyCodes.TAB && that.options.selectOnTab)
        )
      ) {
        if (e.which !== keyCodes.SPACE) e.preventDefault();

        if (!that.options.liveSearch || e.which !== keyCodes.SPACE) {
          that.\$menuInner.find('.active a').trigger('click', true); // retain active class
          \$this.trigger('focus');

          if (!that.options.liveSearch) {
            // Prevent screen from scrolling if the user hits the spacebar
            e.preventDefault();
            // Fixes spacebar selection of dropdown items in FF & IE
            \$(document).data('spaceSelect', true);
          }
        }
      }
    },

    mobile: function () {
      // ensure mobile is set to true if mobile function is called after init
      this.options.mobile = true;
      this.\$element[0].classList.add('mobile-device');
    },

    refresh: function () {
      var that = this;
      // update options if data attributes have been changed
      var config = \$.extend({}, this.options, getAttributesObject(this.\$element), this.\$element.data()); // in this order on refresh, as user may change attributes on select, and options object is not passed on refresh
      this.options = config;

      if (this.options.source.data) {
        this.render();
        this.buildList();
      } else {
        this.fetchData(function () {
          that.render();
          that.buildList();
        });
      }

      this.checkDisabled();
      this.setStyle();
      this.setWidth();

      this.setSize(true);

      this.\$element.trigger('refreshed' + EVENT_KEY);
    },

    hide: function () {
      this.\$newElement.hide();
    },

    show: function () {
      this.\$newElement.show();
    },

    remove: function () {
      this.\$newElement.remove();
      this.\$element.remove();
    },

    destroy: function () {
      this.\$newElement.before(this.\$element).remove();

      if (this.\$bsContainer) {
        this.\$bsContainer.remove();
      } else {
        this.\$menu.remove();
      }

      if (this.selectpicker.view.titleOption && this.selectpicker.view.titleOption.parentNode) {
        this.selectpicker.view.titleOption.parentNode.removeChild(this.selectpicker.view.titleOption);
      }

      this.\$element
        .off(EVENT_KEY)
        .removeData('selectpicker')
        .removeClass('bs-select-hidden selectpicker');

      \$(window).off(EVENT_KEY + '.' + this.selectId);
    }
  };

  // SELECTPICKER PLUGIN DEFINITION
  // ==============================
  function Plugin (option) {
    // get the args of the outer function..
    var args = arguments;
    // The arguments of the function are explicitly re-defined from the argument list, because the shift causes them
    // to get lost/corrupted in android 2.3 and IE9 #715 #775
    var _option = option;

    [].shift.apply(args);

    // if the version was not set successfully
    if (!version.success) {
      // try to retreive it again
      try {
        version.full = (getVersion() || '').split(' ')[0].split('.');
      } catch (err) {
        // fall back to use BootstrapVersion if set
        if (Selectpicker.BootstrapVersion) {
          version.full = Selectpicker.BootstrapVersion.split(' ')[0].split('.');
        } else {
          version.full = [version.major, '0', '0'];

          console.warn(
            'There was an issue retrieving Bootstrap\\'s version. ' +
            'Ensure Bootstrap is being loaded before bootstrap-select and there is no namespace collision. ' +
            'If loading Bootstrap asynchronously, the version may need to be manually specified via \$.fn.selectpicker.Constructor.BootstrapVersion.',
            err
          );
        }
      }

      version.major = version.full[0];
      version.success = true;
    }

    if (version.major >= '4') {
      // some defaults need to be changed if using Bootstrap 4
      // check to see if they have already been manually changed before forcing them to update
      var toUpdate = [];

      if (Selectpicker.DEFAULTS.style === classNames.BUTTONCLASS) toUpdate.push({ name: 'style', className: 'BUTTONCLASS' });
      if (Selectpicker.DEFAULTS.iconBase === classNames.ICONBASE) toUpdate.push({ name: 'iconBase', className: 'ICONBASE' });
      if (Selectpicker.DEFAULTS.tickIcon === classNames.TICKICON) toUpdate.push({ name: 'tickIcon', className: 'TICKICON' });

      classNames.DIVIDER = 'dropdown-divider';
      classNames.SHOW = 'show';
      classNames.BUTTONCLASS = 'btn-light';
      classNames.POPOVERHEADER = 'popover-header';
      classNames.ICONBASE = '';
      classNames.TICKICON = 'bs-ok-default';

      for (var i = 0; i < toUpdate.length; i++) {
        var option = toUpdate[i];
        Selectpicker.DEFAULTS[option.name] = classNames[option.className];
      }
    }

    if (version.major > '4') {
      Selector.DATA_TOGGLE = 'data-bs-toggle=\"dropdown\"'
    }

    var value;
    var chain = this.each(function () {
      var \$this = \$(this);
      if (\$this.is('select')) {
        var data = \$this.data('selectpicker'),
            options = typeof _option == 'object' && _option;

        // for backwards compatibility
        // (using title as placeholder is deprecated - remove in v2.0.0)
        if (options.title) options.placeholder = options.title;

        if (!data) {
          var dataAttributes = \$this.data();

          for (var dataAttr in dataAttributes) {
            if (Object.prototype.hasOwnProperty.call(dataAttributes, dataAttr) && \$.inArray(dataAttr, DISALLOWED_ATTRIBUTES) !== -1) {
              delete dataAttributes[dataAttr];
            }
          }

          var config = \$.extend({}, Selectpicker.DEFAULTS, \$.fn.selectpicker.defaults || {}, getAttributesObject(\$this), dataAttributes, options); // this is correct order on initial render
          config.template = \$.extend({}, Selectpicker.DEFAULTS.template, (\$.fn.selectpicker.defaults ? \$.fn.selectpicker.defaults.template : {}), dataAttributes.template, options.template);
          \$this.data('selectpicker', (data = new Selectpicker(this, config)));
        } else if (options) {
          for (var i in options) {
            if (Object.prototype.hasOwnProperty.call(options, i)) {
              data.options[i] = options[i];
            }
          }
        }

        if (typeof _option == 'string') {
          if (data[_option] instanceof Function) {
            value = data[_option].apply(data, args);
          } else {
            value = data.options[_option];
          }
        }
      }
    });

    if (typeof value !== 'undefined') {
      // noinspection JSUnusedAssignment
      return value;
    } else {
      return chain;
    }
  }

  var old = \$.fn.selectpicker;
  \$.fn.selectpicker = Plugin;
  \$.fn.selectpicker.Constructor = Selectpicker;

  // SELECTPICKER NO CONFLICT
  // ========================
  \$.fn.selectpicker.noConflict = function () {
    \$.fn.selectpicker = old;
    return this;
  };

  // get Bootstrap's keydown event handler for either Bootstrap 4 or Bootstrap 3
  function keydownHandler () {
    if (version.major < 5) {
      if (\$.fn.dropdown) {
        // wait to define until function is called in case Bootstrap isn't loaded yet
        var bootstrapKeydown = \$.fn.dropdown.Constructor._dataApiKeydownHandler || \$.fn.dropdown.Constructor.prototype.keydown;
        return bootstrapKeydown.apply(this, arguments);
      }
    } else {
      return Dropdown.dataApiKeydownHandler;
    }
  }

  \$(document)
    .off('keydown.bs.dropdown.data-api')
    .on('keydown.bs.dropdown.data-api', ':not(.bootstrap-select) > [' + Selector.DATA_TOGGLE + ']', keydownHandler)
    .on('keydown.bs.dropdown.data-api', ':not(.bootstrap-select) > .dropdown-menu', keydownHandler)
    .on('keydown' + EVENT_KEY, '.bootstrap-select [' + Selector.DATA_TOGGLE + '], .bootstrap-select [role=\"listbox\"], .bootstrap-select .bs-searchbox input', Selectpicker.prototype.keydown)
    .on('focusin.modal', '.bootstrap-select [' + Selector.DATA_TOGGLE + '], .bootstrap-select [role=\"listbox\"], .bootstrap-select .bs-searchbox input', function (e) {
      e.stopPropagation();
    });

  // SELECTPICKER DATA-API
  // =====================
  document.addEventListener('DOMContentLoaded', function () {
    \$('.selectpicker').each(function () {
      var \$selectpicker = \$(this);
      Plugin.call(\$selectpicker, \$selectpicker.data());
    })
  });
})(jQuery);


}));
//# sourceMappingURL=bootstrap-select.js.map

/***/ })

}]);
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vLi9ub2RlX21vZHVsZXMvYm9vdHN0cmFwLXNlbGVjdC9kaXN0L2pzL2Jvb3RzdHJhcC1zZWxlY3QuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLE1BQU0sSUFBMEM7QUFDaEQ7QUFDQSxJQUFJLGlDQUFPLENBQUMseUVBQVEsQ0FBQyxtQ0FBRTtBQUN2QjtBQUNBLEtBQUs7QUFBQSxrR0FBQztBQUNOLEdBQUcsTUFBTSxFQU9OO0FBQ0gsQ0FBQzs7QUFFRDtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHVJQUF1STs7QUFFdkkscURBQXFEOztBQUVyRDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQSxzQ0FBc0MsT0FBTztBQUM3QztBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBLGdEQUFnRCxTQUFTO0FBQ3pEOztBQUVBLDZDQUE2QyxVQUFVO0FBQ3ZEO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsb0RBQW9ELFVBQVU7QUFDOUQ7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSw2QkFBNkI7QUFDN0I7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxlQUFlO0FBQ2Y7QUFDQTtBQUNBO0FBQ0EsZUFBZTtBQUNmO0FBQ0E7QUFDQSxlQUFlO0FBQ2Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUyxhQUFhO0FBQ3RCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsbUJBQW1CO0FBQ25CLHVCQUF1QjtBQUN2QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EseUJBQXlCO0FBQ3pCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1QsT0FBTztBQUNQO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0EscUJBQXFCLGdDQUFnQztBQUNyRDtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLHlDQUF5QyxTQUFTO0FBQ2xEOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7O0FBRUEsMkJBQTJCO0FBQzNCO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNULE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxtQkFBbUIsd0JBQXdCO0FBQzNDO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQSxTQUFTO0FBQ1Q7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxlQUFlO0FBQ2YsY0FBYztBQUNkLGNBQWM7QUFDZCxnQkFBZ0I7QUFDaEIsZ0JBQWdCO0FBQ2hCLGdCQUFnQjtBQUNoQjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLE9BQU87QUFDUDs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTs7QUFFQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxLQUFLO0FBQ0w7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLG9GQUFvRixFQUFFO0FBQ3RGO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1AsZ0JBQWdCO0FBQ2hCLGlCQUFpQjtBQUNqQixjQUFjO0FBQ2Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsMENBQTBDLEVBQUU7QUFDNUM7QUFDQSxvQ0FBb0MsRUFBRSxvQkFBb0IsRUFBRTtBQUM1RCxLQUFLO0FBQ0w7QUFDQTtBQUNBLHlDQUF5QyxFQUFFLCtCQUErQixFQUFFO0FBQzVFLGlEQUFpRCxFQUFFLHFDQUFxQyxFQUFFO0FBQzFGO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQSxjQUFjO0FBQ2Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsU0FBUztBQUNULE9BQU87O0FBRVA7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxTQUFTO0FBQ1QsT0FBTzs7QUFFUDs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0EsT0FBTzs7QUFFUDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7O0FBRWI7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYLFNBQVM7QUFDVDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWCxTQUFTO0FBQ1Q7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSwyRUFBMkU7QUFDM0U7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLDhIQUE4SDtBQUM5SDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDhEQUE4RDtBQUM5RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxxQkFBcUIsMkNBQTJDO0FBQ2hFO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBLDJFQUEyRTs7QUFFM0U7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxPQUFPOztBQUVQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBLDJDQUEyQztBQUMzQyxzREFBc0Q7O0FBRXRELHVCQUF1QixnQkFBZ0I7QUFDdkM7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0EsK0VBQStFO0FBQy9FLHVFQUF1RTtBQUN2RSwyRUFBMkU7O0FBRTNFO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsV0FBVztBQUNYO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsaUVBQWlFLHdCQUF3QjtBQUN6RjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLGVBQWU7QUFDZjtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSx5RUFBeUU7O0FBRXpFO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLFNBQVM7QUFDVCxLQUFLOztBQUVMO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7QUFDQTs7QUFFQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSw4REFBOEQ7O0FBRTlEO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsNERBQTREO0FBQzVEO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBOztBQUVBOztBQUVBO0FBQ0Esc0JBQXNCLGVBQWU7QUFDckM7O0FBRUE7O0FBRUE7O0FBRUEsNkNBQTZDLFNBQVM7QUFDdEQ7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYOztBQUVBO0FBQ0Esc0JBQXNCLGVBQWU7QUFDckM7QUFDQTs7QUFFQSwwREFBMEQsU0FBUztBQUNuRTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxTQUFTO0FBQ1QsdUNBQXVDO0FBQ3ZDO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBLHVEQUF1RCxTQUFTO0FBQ2hFOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSx3REFBd0QsaUNBQWlDO0FBQ3pGLE9BQU87QUFDUDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLHVDQUF1QywrQkFBK0I7QUFDdEU7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxtQkFBbUI7QUFDbkI7QUFDQTtBQUNBLG1CQUFtQjtBQUNuQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLGVBQWU7QUFDZjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLHFDQUFxQyxFQUFFLHVDQUF1QyxFQUFFO0FBQ2hGLFdBQVc7QUFDWDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxpQ0FBaUM7QUFDakM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0EsdUJBQXVCLDJDQUEyQztBQUNsRTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1Asd0JBQXdCO0FBQ3hCOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLE9BQU87QUFDUCx1QkFBdUIsdUJBQXVCO0FBQzlDO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87O0FBRVA7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPOztBQUVQO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2IsU0FBUztBQUNUO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1gsU0FBUztBQUNULE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esc0NBQXNDO0FBQ3RDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiLDhCQUE4QjtBQUM5Qjs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPOztBQUVQO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsU0FBUzs7QUFFVDtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1AsS0FBSzs7QUFFTDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBOztBQUVBOztBQUVBO0FBQ0EsdUJBQXVCLG1EQUFtRDtBQUMxRTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0EsZUFBZSxPQUFPO0FBQ3RCLGVBQWUsUUFBUTtBQUN2QjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBLGVBQWUsT0FBTztBQUN0QixlQUFlLFFBQVE7QUFDdkI7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPOztBQUVQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPOztBQUVQO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxPQUFPOztBQUVQO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQSxPQUFPOztBQUVQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLE9BQU87O0FBRVA7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsK0JBQStCO0FBQy9CO0FBQ0E7QUFDQSxXQUFXLE9BQU87QUFDbEI7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGlCQUFpQjtBQUNqQixpQ0FBaUMsNkJBQTZCO0FBQzlEO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxpQkFBaUI7QUFDakI7QUFDQTtBQUNBLDBEQUEwRCxFQUFFO0FBQzVELDZEQUE2RCxFQUFFO0FBQy9EO0FBQ0EseUJBQXlCLElBQUk7QUFDN0I7QUFDQTtBQUNBLDhDQUE4QyxJQUFJO0FBQ2xELG9EQUFvRCxJQUFJO0FBQ3hEOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsbUJBQW1COztBQUVuQjs7QUFFQTtBQUNBO0FBQ0EsbUJBQW1CO0FBQ25CO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87O0FBRVA7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYO0FBQ0E7QUFDQTtBQUNBLE9BQU87O0FBRVA7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0EsT0FBTzs7QUFFUDtBQUNBO0FBQ0EsT0FBTzs7QUFFUDtBQUNBO0FBQ0EsT0FBTzs7QUFFUDtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBLE9BQU87O0FBRVA7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTOztBQUVUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBLFNBQVM7QUFDVCxLQUFLOztBQUVMO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87O0FBRVA7QUFDQTtBQUNBLE9BQU87O0FBRVA7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiLFdBQVc7QUFDWDtBQUNBO0FBQ0E7QUFDQSwwQkFBMEI7QUFDMUI7QUFDQTtBQUNBOztBQUVBOztBQUVBLDJCQUEyQix3Q0FBd0M7QUFDbkU7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsdURBQXVELGNBQWM7QUFDckU7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVMsbURBQW1EO0FBQzVEO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLE9BQU87QUFDUCxLQUFLOztBQUVMO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHVCQUF1Qiw0QkFBNEI7QUFDbkQ7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsU0FBUzs7QUFFVDs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1gsK0VBQStFOztBQUUvRTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBLCtFQUErRSxTQUFTO0FBQ3hGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSx1QkFBdUI7QUFDdkI7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsNENBQTRDO0FBQzVDO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTLHlEQUF5RDtBQUNsRTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLDRDQUE0QztBQUM1QztBQUNBO0FBQ0E7O0FBRUE7QUFDQSxXQUFXO0FBQ1g7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsU0FBUyx5REFBeUQ7QUFDbEU7QUFDQTtBQUNBOztBQUVBO0FBQ0EsV0FBVztBQUNYO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLHVCQUF1QiwyQ0FBMkM7QUFDbEU7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsbUVBQW1FO0FBQ25FOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQSw4QkFBOEIsMEVBQTBFO0FBQ3hHOztBQUVBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxpRkFBaUYsMENBQTBDO0FBQzNILGlGQUFpRiwwQ0FBMEM7QUFDM0gsaUZBQWlGLDBDQUEwQzs7QUFFM0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLHFCQUFxQixxQkFBcUI7QUFDMUM7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLGtDQUFrQyx5REFBeUQsdURBQXVEO0FBQ2xKLHVDQUF1Qyx3R0FBd0c7QUFDL0k7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0wsR0FBRztBQUNILENBQUM7OztBQUdELENBQUM7QUFDRCw0QyIsImZpbGUiOiJ2ZW5kb3JzLW5vZGVfbW9kdWxlc19ib290c3RyYXAtc2VsZWN0X2Rpc3RfanNfYm9vdHN0cmFwLXNlbGVjdF9qcy5qcyIsInNvdXJjZXNDb250ZW50IjpbIi8qIVxyXG4gKiBCb290c3RyYXAtc2VsZWN0IHYxLjE0LjAtYmV0YTIgKGh0dHBzOi8vZGV2ZWxvcGVyLnNuYXBhcHBvaW50bWVudHMuY29tL2Jvb3RzdHJhcC1zZWxlY3QpXHJcbiAqXHJcbiAqIENvcHlyaWdodCAyMDEyLTIwMjEgU25hcEFwcG9pbnRtZW50cywgTExDXHJcbiAqIExpY2Vuc2VkIHVuZGVyIE1JVCAoaHR0cHM6Ly9naXRodWIuY29tL3NuYXBhcHBvaW50bWVudHMvYm9vdHN0cmFwLXNlbGVjdC9ibG9iL21hc3Rlci9MSUNFTlNFKVxyXG4gKi9cclxuXHJcbihmdW5jdGlvbiAocm9vdCwgZmFjdG9yeSkge1xyXG4gIGlmIChyb290ID09PSB1bmRlZmluZWQgJiYgd2luZG93ICE9PSB1bmRlZmluZWQpIHJvb3QgPSB3aW5kb3c7XHJcbiAgaWYgKHR5cGVvZiBkZWZpbmUgPT09ICdmdW5jdGlvbicgJiYgZGVmaW5lLmFtZCkge1xyXG4gICAgLy8gQU1ELiBSZWdpc3RlciBhcyBhbiBhbm9ueW1vdXMgbW9kdWxlIHVubGVzcyBhbWRNb2R1bGVJZCBpcyBzZXRcclxuICAgIGRlZmluZShbXCJqcXVlcnlcIl0sIGZ1bmN0aW9uIChhMCkge1xyXG4gICAgICByZXR1cm4gKGZhY3RvcnkoYTApKTtcclxuICAgIH0pO1xyXG4gIH0gZWxzZSBpZiAodHlwZW9mIG1vZHVsZSA9PT0gJ29iamVjdCcgJiYgbW9kdWxlLmV4cG9ydHMpIHtcclxuICAgIC8vIE5vZGUuIERvZXMgbm90IHdvcmsgd2l0aCBzdHJpY3QgQ29tbW9uSlMsIGJ1dFxyXG4gICAgLy8gb25seSBDb21tb25KUy1saWtlIGVudmlyb25tZW50cyB0aGF0IHN1cHBvcnQgbW9kdWxlLmV4cG9ydHMsXHJcbiAgICAvLyBsaWtlIE5vZGUuXHJcbiAgICBtb2R1bGUuZXhwb3J0cyA9IGZhY3RvcnkocmVxdWlyZShcImpxdWVyeVwiKSk7XHJcbiAgfSBlbHNlIHtcclxuICAgIGZhY3Rvcnkocm9vdFtcImpRdWVyeVwiXSk7XHJcbiAgfVxyXG59KHRoaXMsIGZ1bmN0aW9uIChqUXVlcnkpIHtcclxuXHJcbihmdW5jdGlvbiAoJCkge1xyXG4gICd1c2Ugc3RyaWN0JztcclxuXHJcbiAgdmFyIERJU0FMTE9XRURfQVRUUklCVVRFUyA9IFsnc2FuaXRpemUnLCAnd2hpdGVMaXN0JywgJ3Nhbml0aXplRm4nXTtcclxuXHJcbiAgdmFyIHVyaUF0dHJzID0gW1xyXG4gICAgJ2JhY2tncm91bmQnLFxyXG4gICAgJ2NpdGUnLFxyXG4gICAgJ2hyZWYnLFxyXG4gICAgJ2l0ZW10eXBlJyxcclxuICAgICdsb25nZGVzYycsXHJcbiAgICAncG9zdGVyJyxcclxuICAgICdzcmMnLFxyXG4gICAgJ3hsaW5rOmhyZWYnXHJcbiAgXTtcclxuXHJcbiAgdmFyIEFSSUFfQVRUUklCVVRFX1BBVFRFUk4gPSAvXmFyaWEtW1xcdy1dKiQvaTtcclxuXHJcbiAgdmFyIERlZmF1bHRXaGl0ZWxpc3QgPSB7XHJcbiAgICAvLyBHbG9iYWwgYXR0cmlidXRlcyBhbGxvd2VkIG9uIGFueSBzdXBwbGllZCBlbGVtZW50IGJlbG93LlxyXG4gICAgJyonOiBbJ2NsYXNzJywgJ2RpcicsICdpZCcsICdsYW5nJywgJ3JvbGUnLCAndGFiaW5kZXgnLCAnc3R5bGUnLCBBUklBX0FUVFJJQlVURV9QQVRURVJOXSxcclxuICAgIGE6IFsndGFyZ2V0JywgJ2hyZWYnLCAndGl0bGUnLCAncmVsJ10sXHJcbiAgICBhcmVhOiBbXSxcclxuICAgIGI6IFtdLFxyXG4gICAgYnI6IFtdLFxyXG4gICAgY29sOiBbXSxcclxuICAgIGNvZGU6IFtdLFxyXG4gICAgZGl2OiBbXSxcclxuICAgIGVtOiBbXSxcclxuICAgIGhyOiBbXSxcclxuICAgIGgxOiBbXSxcclxuICAgIGgyOiBbXSxcclxuICAgIGgzOiBbXSxcclxuICAgIGg0OiBbXSxcclxuICAgIGg1OiBbXSxcclxuICAgIGg2OiBbXSxcclxuICAgIGk6IFtdLFxyXG4gICAgaW1nOiBbJ3NyYycsICdhbHQnLCAndGl0bGUnLCAnd2lkdGgnLCAnaGVpZ2h0J10sXHJcbiAgICBsaTogW10sXHJcbiAgICBvbDogW10sXHJcbiAgICBwOiBbXSxcclxuICAgIHByZTogW10sXHJcbiAgICBzOiBbXSxcclxuICAgIHNtYWxsOiBbXSxcclxuICAgIHNwYW46IFtdLFxyXG4gICAgc3ViOiBbXSxcclxuICAgIHN1cDogW10sXHJcbiAgICBzdHJvbmc6IFtdLFxyXG4gICAgdTogW10sXHJcbiAgICB1bDogW11cclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIEEgcGF0dGVybiB0aGF0IHJlY29nbml6ZXMgYSBjb21tb25seSB1c2VmdWwgc3Vic2V0IG9mIFVSTHMgdGhhdCBhcmUgc2FmZS5cclxuICAgKlxyXG4gICAqIFNob3V0b3V0IHRvIEFuZ3VsYXIgNyBodHRwczovL2dpdGh1Yi5jb20vYW5ndWxhci9hbmd1bGFyL2Jsb2IvNy4yLjQvcGFja2FnZXMvY29yZS9zcmMvc2FuaXRpemF0aW9uL3VybF9zYW5pdGl6ZXIudHNcclxuICAgKi9cclxuICB2YXIgU0FGRV9VUkxfUEFUVEVSTiA9IC9eKD86KD86aHR0cHM/fG1haWx0b3xmdHB8dGVsfGZpbGUpOnxbXiY6Lz8jXSooPzpbLz8jXXwkKSkvZ2k7XHJcblxyXG4gIC8qKlxyXG4gICAqIEEgcGF0dGVybiB0aGF0IG1hdGNoZXMgc2FmZSBkYXRhIFVSTHMuIE9ubHkgbWF0Y2hlcyBpbWFnZSwgdmlkZW8gYW5kIGF1ZGlvIHR5cGVzLlxyXG4gICAqXHJcbiAgICogU2hvdXRvdXQgdG8gQW5ndWxhciA3IGh0dHBzOi8vZ2l0aHViLmNvbS9hbmd1bGFyL2FuZ3VsYXIvYmxvYi83LjIuNC9wYWNrYWdlcy9jb3JlL3NyYy9zYW5pdGl6YXRpb24vdXJsX3Nhbml0aXplci50c1xyXG4gICAqL1xyXG4gIHZhciBEQVRBX1VSTF9QQVRURVJOID0gL15kYXRhOig/OmltYWdlXFwvKD86Ym1wfGdpZnxqcGVnfGpwZ3xwbmd8dGlmZnx3ZWJwKXx2aWRlb1xcLyg/Om1wZWd8bXA0fG9nZ3x3ZWJtKXxhdWRpb1xcLyg/Om1wM3xvZ2F8b2dnfG9wdXMpKTtiYXNlNjQsW2EtejAtOSsvXSs9KiQvaTtcclxuXHJcbiAgdmFyIFBhcnNlYWJsZUF0dHJpYnV0ZXMgPSBbJ3RpdGxlJywgJ3BsYWNlaG9sZGVyJ107IC8vIGF0dHJpYnV0ZXMgdG8gdXNlIGFzIHNldHRpbmdzLCBjYW4gYWRkIG90aGVycyBpbiB0aGUgZnV0dXJlXHJcblxyXG4gIGZ1bmN0aW9uIGFsbG93ZWRBdHRyaWJ1dGUgKGF0dHIsIGFsbG93ZWRBdHRyaWJ1dGVMaXN0KSB7XHJcbiAgICB2YXIgYXR0ck5hbWUgPSBhdHRyLm5vZGVOYW1lLnRvTG93ZXJDYXNlKClcclxuXHJcbiAgICBpZiAoJC5pbkFycmF5KGF0dHJOYW1lLCBhbGxvd2VkQXR0cmlidXRlTGlzdCkgIT09IC0xKSB7XHJcbiAgICAgIGlmICgkLmluQXJyYXkoYXR0ck5hbWUsIHVyaUF0dHJzKSAhPT0gLTEpIHtcclxuICAgICAgICByZXR1cm4gQm9vbGVhbihhdHRyLm5vZGVWYWx1ZS5tYXRjaChTQUZFX1VSTF9QQVRURVJOKSB8fCBhdHRyLm5vZGVWYWx1ZS5tYXRjaChEQVRBX1VSTF9QQVRURVJOKSlcclxuICAgICAgfVxyXG5cclxuICAgICAgcmV0dXJuIHRydWVcclxuICAgIH1cclxuXHJcbiAgICB2YXIgcmVnRXhwID0gJChhbGxvd2VkQXR0cmlidXRlTGlzdCkuZmlsdGVyKGZ1bmN0aW9uIChpbmRleCwgdmFsdWUpIHtcclxuICAgICAgcmV0dXJuIHZhbHVlIGluc3RhbmNlb2YgUmVnRXhwXHJcbiAgICB9KVxyXG5cclxuICAgIC8vIENoZWNrIGlmIGEgcmVndWxhciBleHByZXNzaW9uIHZhbGlkYXRlcyB0aGUgYXR0cmlidXRlLlxyXG4gICAgZm9yICh2YXIgaSA9IDAsIGwgPSByZWdFeHAubGVuZ3RoOyBpIDwgbDsgaSsrKSB7XHJcbiAgICAgIGlmIChhdHRyTmFtZS5tYXRjaChyZWdFeHBbaV0pKSB7XHJcbiAgICAgICAgcmV0dXJuIHRydWVcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiBmYWxzZVxyXG4gIH1cclxuXHJcbiAgZnVuY3Rpb24gc2FuaXRpemVIdG1sICh1bnNhZmVFbGVtZW50cywgd2hpdGVMaXN0LCBzYW5pdGl6ZUZuKSB7XHJcbiAgICBpZiAoc2FuaXRpemVGbiAmJiB0eXBlb2Ygc2FuaXRpemVGbiA9PT0gJ2Z1bmN0aW9uJykge1xyXG4gICAgICByZXR1cm4gc2FuaXRpemVGbih1bnNhZmVFbGVtZW50cyk7XHJcbiAgICB9XHJcblxyXG4gICAgdmFyIHdoaXRlbGlzdEtleXMgPSBPYmplY3Qua2V5cyh3aGl0ZUxpc3QpO1xyXG5cclxuICAgIGZvciAodmFyIGkgPSAwLCBsZW4gPSB1bnNhZmVFbGVtZW50cy5sZW5ndGg7IGkgPCBsZW47IGkrKykge1xyXG4gICAgICB2YXIgZWxlbWVudHMgPSB1bnNhZmVFbGVtZW50c1tpXS5xdWVyeVNlbGVjdG9yQWxsKCcqJyk7XHJcblxyXG4gICAgICBmb3IgKHZhciBqID0gMCwgbGVuMiA9IGVsZW1lbnRzLmxlbmd0aDsgaiA8IGxlbjI7IGorKykge1xyXG4gICAgICAgIHZhciBlbCA9IGVsZW1lbnRzW2pdO1xyXG4gICAgICAgIHZhciBlbE5hbWUgPSBlbC5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpO1xyXG5cclxuICAgICAgICBpZiAod2hpdGVsaXN0S2V5cy5pbmRleE9mKGVsTmFtZSkgPT09IC0xKSB7XHJcbiAgICAgICAgICBlbC5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKGVsKTtcclxuXHJcbiAgICAgICAgICBjb250aW51ZTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHZhciBhdHRyaWJ1dGVMaXN0ID0gW10uc2xpY2UuY2FsbChlbC5hdHRyaWJ1dGVzKTtcclxuICAgICAgICB2YXIgd2hpdGVsaXN0ZWRBdHRyaWJ1dGVzID0gW10uY29uY2F0KHdoaXRlTGlzdFsnKiddIHx8IFtdLCB3aGl0ZUxpc3RbZWxOYW1lXSB8fCBbXSk7XHJcblxyXG4gICAgICAgIGZvciAodmFyIGsgPSAwLCBsZW4zID0gYXR0cmlidXRlTGlzdC5sZW5ndGg7IGsgPCBsZW4zOyBrKyspIHtcclxuICAgICAgICAgIHZhciBhdHRyID0gYXR0cmlidXRlTGlzdFtrXTtcclxuXHJcbiAgICAgICAgICBpZiAoIWFsbG93ZWRBdHRyaWJ1dGUoYXR0ciwgd2hpdGVsaXN0ZWRBdHRyaWJ1dGVzKSkge1xyXG4gICAgICAgICAgICBlbC5yZW1vdmVBdHRyaWJ1dGUoYXR0ci5ub2RlTmFtZSk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiBnZXRBdHRyaWJ1dGVzT2JqZWN0ICgkc2VsZWN0KSB7XHJcbiAgICB2YXIgYXR0cmlidXRlc09iamVjdCA9IHt9LFxyXG4gICAgICAgIGF0dHJWYWw7XHJcblxyXG4gICAgUGFyc2VhYmxlQXR0cmlidXRlcy5mb3JFYWNoKGZ1bmN0aW9uIChpdGVtKSB7XHJcbiAgICAgIGF0dHJWYWwgPSAkc2VsZWN0LmF0dHIoaXRlbSk7XHJcbiAgICAgIGlmIChhdHRyVmFsKSBhdHRyaWJ1dGVzT2JqZWN0W2l0ZW1dID0gYXR0clZhbDtcclxuICAgIH0pO1xyXG5cclxuICAgIC8vIGZvciBiYWNrd2FyZHMgY29tcGF0aWJpbGl0eVxyXG4gICAgLy8gKHVzaW5nIHRpdGxlIGFzIHBsYWNlaG9sZGVyIGlzIGRlcHJlY2F0ZWQgLSByZW1vdmUgaW4gdjIuMC4wKVxyXG4gICAgaWYgKCFhdHRyaWJ1dGVzT2JqZWN0LnBsYWNlaG9sZGVyICYmIGF0dHJpYnV0ZXNPYmplY3QudGl0bGUpIHtcclxuICAgICAgYXR0cmlidXRlc09iamVjdC5wbGFjZWhvbGRlciA9IGF0dHJpYnV0ZXNPYmplY3QudGl0bGU7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIGF0dHJpYnV0ZXNPYmplY3Q7XHJcbiAgfVxyXG5cclxuICAvLyBQb2x5ZmlsbCBmb3IgYnJvd3NlcnMgd2l0aCBubyBjbGFzc0xpc3Qgc3VwcG9ydFxyXG4gIC8vIFJlbW92ZSBpbiB2MlxyXG4gIGlmICghKCdjbGFzc0xpc3QnIGluIGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ18nKSkpIHtcclxuICAgIChmdW5jdGlvbiAodmlldykge1xyXG4gICAgICBpZiAoISgnRWxlbWVudCcgaW4gdmlldykpIHJldHVybjtcclxuXHJcbiAgICAgIHZhciBjbGFzc0xpc3RQcm9wID0gJ2NsYXNzTGlzdCcsXHJcbiAgICAgICAgICBwcm90b1Byb3AgPSAncHJvdG90eXBlJyxcclxuICAgICAgICAgIGVsZW1DdHJQcm90byA9IHZpZXcuRWxlbWVudFtwcm90b1Byb3BdLFxyXG4gICAgICAgICAgb2JqQ3RyID0gT2JqZWN0LFxyXG4gICAgICAgICAgY2xhc3NMaXN0R2V0dGVyID0gZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICB2YXIgJGVsZW0gPSAkKHRoaXMpO1xyXG5cclxuICAgICAgICAgICAgcmV0dXJuIHtcclxuICAgICAgICAgICAgICBhZGQ6IGZ1bmN0aW9uIChjbGFzc2VzKSB7XHJcbiAgICAgICAgICAgICAgICBjbGFzc2VzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzKS5qb2luKCcgJyk7XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gJGVsZW0uYWRkQ2xhc3MoY2xhc3Nlcyk7XHJcbiAgICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgICByZW1vdmU6IGZ1bmN0aW9uIChjbGFzc2VzKSB7XHJcbiAgICAgICAgICAgICAgICBjbGFzc2VzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzKS5qb2luKCcgJyk7XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gJGVsZW0ucmVtb3ZlQ2xhc3MoY2xhc3Nlcyk7XHJcbiAgICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgICB0b2dnbGU6IGZ1bmN0aW9uIChjbGFzc2VzLCBmb3JjZSkge1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuICRlbGVtLnRvZ2dsZUNsYXNzKGNsYXNzZXMsIGZvcmNlKTtcclxuICAgICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICAgIGNvbnRhaW5zOiBmdW5jdGlvbiAoY2xhc3Nlcykge1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuICRlbGVtLmhhc0NsYXNzKGNsYXNzZXMpO1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfTtcclxuXHJcbiAgICAgIGlmIChvYmpDdHIuZGVmaW5lUHJvcGVydHkpIHtcclxuICAgICAgICB2YXIgY2xhc3NMaXN0UHJvcERlc2MgPSB7XHJcbiAgICAgICAgICBnZXQ6IGNsYXNzTGlzdEdldHRlcixcclxuICAgICAgICAgIGVudW1lcmFibGU6IHRydWUsXHJcbiAgICAgICAgICBjb25maWd1cmFibGU6IHRydWVcclxuICAgICAgICB9O1xyXG4gICAgICAgIHRyeSB7XHJcbiAgICAgICAgICBvYmpDdHIuZGVmaW5lUHJvcGVydHkoZWxlbUN0clByb3RvLCBjbGFzc0xpc3RQcm9wLCBjbGFzc0xpc3RQcm9wRGVzYyk7XHJcbiAgICAgICAgfSBjYXRjaCAoZXgpIHsgLy8gSUUgOCBkb2Vzbid0IHN1cHBvcnQgZW51bWVyYWJsZTp0cnVlXHJcbiAgICAgICAgICAvLyBhZGRpbmcgdW5kZWZpbmVkIHRvIGZpZ2h0IHRoaXMgaXNzdWUgaHR0cHM6Ly9naXRodWIuY29tL2VsaWdyZXkvY2xhc3NMaXN0LmpzL2lzc3Vlcy8zNlxyXG4gICAgICAgICAgLy8gbW9kZXJuaWUgSUU4LU1TVzcgbWFjaGluZSBoYXMgSUU4IDguMC42MDAxLjE4NzAyIGFuZCBpcyBhZmZlY3RlZFxyXG4gICAgICAgICAgaWYgKGV4Lm51bWJlciA9PT0gdW5kZWZpbmVkIHx8IGV4Lm51bWJlciA9PT0gLTB4N0ZGNUVDNTQpIHtcclxuICAgICAgICAgICAgY2xhc3NMaXN0UHJvcERlc2MuZW51bWVyYWJsZSA9IGZhbHNlO1xyXG4gICAgICAgICAgICBvYmpDdHIuZGVmaW5lUHJvcGVydHkoZWxlbUN0clByb3RvLCBjbGFzc0xpc3RQcm9wLCBjbGFzc0xpc3RQcm9wRGVzYyk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9IGVsc2UgaWYgKG9iakN0cltwcm90b1Byb3BdLl9fZGVmaW5lR2V0dGVyX18pIHtcclxuICAgICAgICBlbGVtQ3RyUHJvdG8uX19kZWZpbmVHZXR0ZXJfXyhjbGFzc0xpc3RQcm9wLCBjbGFzc0xpc3RHZXR0ZXIpO1xyXG4gICAgICB9XHJcbiAgICB9KHdpbmRvdykpO1xyXG4gIH1cclxuXHJcbiAgdmFyIHRlc3RFbGVtZW50ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnXycpO1xyXG5cclxuICB0ZXN0RWxlbWVudC5jbGFzc0xpc3QuYWRkKCdjMScsICdjMicpO1xyXG5cclxuICBpZiAoIXRlc3RFbGVtZW50LmNsYXNzTGlzdC5jb250YWlucygnYzInKSkge1xyXG4gICAgdmFyIF9hZGQgPSBET01Ub2tlbkxpc3QucHJvdG90eXBlLmFkZCxcclxuICAgICAgICBfcmVtb3ZlID0gRE9NVG9rZW5MaXN0LnByb3RvdHlwZS5yZW1vdmU7XHJcblxyXG4gICAgRE9NVG9rZW5MaXN0LnByb3RvdHlwZS5hZGQgPSBmdW5jdGlvbiAoKSB7XHJcbiAgICAgIEFycmF5LnByb3RvdHlwZS5mb3JFYWNoLmNhbGwoYXJndW1lbnRzLCBfYWRkLmJpbmQodGhpcykpO1xyXG4gICAgfVxyXG5cclxuICAgIERPTVRva2VuTGlzdC5wcm90b3R5cGUucmVtb3ZlID0gZnVuY3Rpb24gKCkge1xyXG4gICAgICBBcnJheS5wcm90b3R5cGUuZm9yRWFjaC5jYWxsKGFyZ3VtZW50cywgX3JlbW92ZS5iaW5kKHRoaXMpKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHRlc3RFbGVtZW50LmNsYXNzTGlzdC50b2dnbGUoJ2MzJywgZmFsc2UpO1xyXG5cclxuICAvLyBQb2x5ZmlsbCBmb3IgSUUgMTAgYW5kIEZpcmVmb3ggPDI0LCB3aGVyZSBjbGFzc0xpc3QudG9nZ2xlIGRvZXMgbm90XHJcbiAgLy8gc3VwcG9ydCB0aGUgc2Vjb25kIGFyZ3VtZW50LlxyXG4gIGlmICh0ZXN0RWxlbWVudC5jbGFzc0xpc3QuY29udGFpbnMoJ2MzJykpIHtcclxuICAgIHZhciBfdG9nZ2xlID0gRE9NVG9rZW5MaXN0LnByb3RvdHlwZS50b2dnbGU7XHJcblxyXG4gICAgRE9NVG9rZW5MaXN0LnByb3RvdHlwZS50b2dnbGUgPSBmdW5jdGlvbiAodG9rZW4sIGZvcmNlKSB7XHJcbiAgICAgIGlmICgxIGluIGFyZ3VtZW50cyAmJiAhdGhpcy5jb250YWlucyh0b2tlbikgPT09ICFmb3JjZSkge1xyXG4gICAgICAgIHJldHVybiBmb3JjZTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICByZXR1cm4gX3RvZ2dsZS5jYWxsKHRoaXMsIHRva2VuKTtcclxuICAgICAgfVxyXG4gICAgfTtcclxuICB9XHJcblxyXG4gIHRlc3RFbGVtZW50ID0gbnVsbDtcclxuXHJcbiAgLy8gc2hhbGxvdyBhcnJheSBjb21wYXJpc29uXHJcbiAgZnVuY3Rpb24gaXNFcXVhbCAoYXJyYXkxLCBhcnJheTIpIHtcclxuICAgIHJldHVybiBhcnJheTEubGVuZ3RoID09PSBhcnJheTIubGVuZ3RoICYmIGFycmF5MS5ldmVyeShmdW5jdGlvbiAoZWxlbWVudCwgaW5kZXgpIHtcclxuICAgICAgcmV0dXJuIGVsZW1lbnQgPT09IGFycmF5MltpbmRleF07XHJcbiAgICB9KTtcclxuICB9O1xyXG5cclxuICAvLyA8ZWRpdG9yLWZvbGQgZGVzYz1cIlNoaW1zXCI+XHJcbiAgaWYgKCFTdHJpbmcucHJvdG90eXBlLnN0YXJ0c1dpdGgpIHtcclxuICAgIChmdW5jdGlvbiAoKSB7XHJcbiAgICAgICd1c2Ugc3RyaWN0JzsgLy8gbmVlZGVkIHRvIHN1cHBvcnQgYGFwcGx5YC9gY2FsbGAgd2l0aCBgdW5kZWZpbmVkYC9gbnVsbGBcclxuICAgICAgdmFyIHRvU3RyaW5nID0ge30udG9TdHJpbmc7XHJcbiAgICAgIHZhciBzdGFydHNXaXRoID0gZnVuY3Rpb24gKHNlYXJjaCkge1xyXG4gICAgICAgIGlmICh0aGlzID09IG51bGwpIHtcclxuICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgdmFyIHN0cmluZyA9IFN0cmluZyh0aGlzKTtcclxuICAgICAgICBpZiAoc2VhcmNoICYmIHRvU3RyaW5nLmNhbGwoc2VhcmNoKSA9PSAnW29iamVjdCBSZWdFeHBdJykge1xyXG4gICAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcigpO1xyXG4gICAgICAgIH1cclxuICAgICAgICB2YXIgc3RyaW5nTGVuZ3RoID0gc3RyaW5nLmxlbmd0aDtcclxuICAgICAgICB2YXIgc2VhcmNoU3RyaW5nID0gU3RyaW5nKHNlYXJjaCk7XHJcbiAgICAgICAgdmFyIHNlYXJjaExlbmd0aCA9IHNlYXJjaFN0cmluZy5sZW5ndGg7XHJcbiAgICAgICAgdmFyIHBvc2l0aW9uID0gYXJndW1lbnRzLmxlbmd0aCA+IDEgPyBhcmd1bWVudHNbMV0gOiB1bmRlZmluZWQ7XHJcbiAgICAgICAgLy8gYFRvSW50ZWdlcmBcclxuICAgICAgICB2YXIgcG9zID0gcG9zaXRpb24gPyBOdW1iZXIocG9zaXRpb24pIDogMDtcclxuICAgICAgICBpZiAocG9zICE9IHBvcykgeyAvLyBiZXR0ZXIgYGlzTmFOYFxyXG4gICAgICAgICAgcG9zID0gMDtcclxuICAgICAgICB9XHJcbiAgICAgICAgdmFyIHN0YXJ0ID0gTWF0aC5taW4oTWF0aC5tYXgocG9zLCAwKSwgc3RyaW5nTGVuZ3RoKTtcclxuICAgICAgICAvLyBBdm9pZCB0aGUgYGluZGV4T2ZgIGNhbGwgaWYgbm8gbWF0Y2ggaXMgcG9zc2libGVcclxuICAgICAgICBpZiAoc2VhcmNoTGVuZ3RoICsgc3RhcnQgPiBzdHJpbmdMZW5ndGgpIHtcclxuICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICB9XHJcbiAgICAgICAgdmFyIGluZGV4ID0gLTE7XHJcbiAgICAgICAgd2hpbGUgKCsraW5kZXggPCBzZWFyY2hMZW5ndGgpIHtcclxuICAgICAgICAgIGlmIChzdHJpbmcuY2hhckNvZGVBdChzdGFydCArIGluZGV4KSAhPSBzZWFyY2hTdHJpbmcuY2hhckNvZGVBdChpbmRleCkpIHtcclxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgfTtcclxuICAgICAgaWYgKE9iamVjdC5kZWZpbmVQcm9wZXJ0eSkge1xyXG4gICAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShTdHJpbmcucHJvdG90eXBlLCAnc3RhcnRzV2l0aCcsIHtcclxuICAgICAgICAgICd2YWx1ZSc6IHN0YXJ0c1dpdGgsXHJcbiAgICAgICAgICAnY29uZmlndXJhYmxlJzogdHJ1ZSxcclxuICAgICAgICAgICd3cml0YWJsZSc6IHRydWVcclxuICAgICAgICB9KTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBTdHJpbmcucHJvdG90eXBlLnN0YXJ0c1dpdGggPSBzdGFydHNXaXRoO1xyXG4gICAgICB9XHJcbiAgICB9KCkpO1xyXG4gIH1cclxuXHJcbiAgZnVuY3Rpb24gZ2V0U2VsZWN0ZWRPcHRpb25zICgpIHtcclxuICAgIHZhciBzZWxlY3RlZE9wdGlvbnMgPSB0aGlzLnNlbGVjdHBpY2tlci5tYWluLmRhdGEuZmlsdGVyKGZ1bmN0aW9uIChpdGVtKSB7XHJcbiAgICAgIGlmIChpdGVtLnNlbGVjdGVkKSB7XHJcbiAgICAgICAgaWYgKHRoaXMub3B0aW9ucy5oaWRlRGlzYWJsZWQgJiYgaXRlbS5kaXNhYmxlZCkgcmV0dXJuIGZhbHNlO1xyXG4gICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICB9LCB0aGlzKTtcclxuXHJcbiAgICAvLyBlbnN1cmUgb25seSAxIG9wdGlvbiBpcyBzZWxlY3RlZCBpZiBtdWx0aXBsZSBhcmUgc2V0IGluIHRoZSBkYXRhIHNvdXJjZVxyXG4gICAgaWYgKHRoaXMub3B0aW9ucy5zb3VyY2UuZGF0YSAmJiAhdGhpcy5tdWx0aXBsZSAmJiBzZWxlY3RlZE9wdGlvbnMubGVuZ3RoID4gMSkge1xyXG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHNlbGVjdGVkT3B0aW9ucy5sZW5ndGggLSAxOyBpKyspIHtcclxuICAgICAgICBzZWxlY3RlZE9wdGlvbnNbaV0uc2VsZWN0ZWQgPSBmYWxzZTtcclxuICAgICAgfVxyXG5cclxuICAgICAgc2VsZWN0ZWRPcHRpb25zID0gWyBzZWxlY3RlZE9wdGlvbnNbc2VsZWN0ZWRPcHRpb25zLmxlbmd0aCAtIDFdIF07XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHNlbGVjdGVkT3B0aW9ucztcclxuICB9XHJcblxyXG4gIC8vIG11Y2ggZmFzdGVyIHRoYW4gJC52YWwoKVxyXG4gIGZ1bmN0aW9uIGdldFNlbGVjdFZhbHVlcyAoc2VsZWN0ZWRPcHRpb25zKSB7XHJcbiAgICB2YXIgdmFsdWUgPSBbXSxcclxuICAgICAgICBvcHRpb25zID0gc2VsZWN0ZWRPcHRpb25zIHx8IGdldFNlbGVjdGVkT3B0aW9ucy5jYWxsKHRoaXMpLFxyXG4gICAgICAgIG9wdDtcclxuXHJcbiAgICBmb3IgKHZhciBpID0gMCwgbGVuID0gb3B0aW9ucy5sZW5ndGg7IGkgPCBsZW47IGkrKykge1xyXG4gICAgICBvcHQgPSBvcHRpb25zW2ldO1xyXG5cclxuICAgICAgaWYgKCFvcHQuZGlzYWJsZWQpIHtcclxuICAgICAgICB2YWx1ZS5wdXNoKG9wdC52YWx1ZSA9PT0gdW5kZWZpbmVkID8gb3B0LnRleHQgOiBvcHQudmFsdWUpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKCF0aGlzLm11bHRpcGxlKSB7XHJcbiAgICAgIHJldHVybiAhdmFsdWUubGVuZ3RoID8gbnVsbCA6IHZhbHVlWzBdO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiB2YWx1ZTtcclxuICB9XHJcblxyXG4gIC8vIHNldCBkYXRhLXNlbGVjdGVkIG9uIHNlbGVjdCBlbGVtZW50IGlmIHRoZSB2YWx1ZSBoYXMgYmVlbiBwcm9ncmFtbWF0aWNhbGx5IHNlbGVjdGVkXHJcbiAgLy8gcHJpb3IgdG8gaW5pdGlhbGl6YXRpb24gb2YgYm9vdHN0cmFwLXNlbGVjdFxyXG4gIC8vICogY29uc2lkZXIgcmVtb3Zpbmcgb3IgcmVwbGFjaW5nIGFuIGFsdGVybmF0aXZlIG1ldGhvZCAqXHJcbiAgdmFyIHZhbEhvb2tzID0ge1xyXG4gICAgdXNlRGVmYXVsdDogZmFsc2UsXHJcbiAgICBfc2V0OiAkLnZhbEhvb2tzLnNlbGVjdC5zZXRcclxuICB9O1xyXG5cclxuICAkLnZhbEhvb2tzLnNlbGVjdC5zZXQgPSBmdW5jdGlvbiAoZWxlbSwgdmFsdWUpIHtcclxuICAgIGlmICh2YWx1ZSAmJiAhdmFsSG9va3MudXNlRGVmYXVsdCkgJChlbGVtKS5kYXRhKCdzZWxlY3RlZCcsIHRydWUpO1xyXG5cclxuICAgIHJldHVybiB2YWxIb29rcy5fc2V0LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XHJcbiAgfTtcclxuXHJcbiAgdmFyIGNoYW5nZWRBcmd1bWVudHMgPSBudWxsO1xyXG5cclxuICB2YXIgRXZlbnRJc1N1cHBvcnRlZCA9IChmdW5jdGlvbiAoKSB7XHJcbiAgICB0cnkge1xyXG4gICAgICBuZXcgRXZlbnQoJ2NoYW5nZScpO1xyXG4gICAgICByZXR1cm4gdHJ1ZTtcclxuICAgIH0gY2F0Y2ggKGUpIHtcclxuICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgfVxyXG4gIH0pKCk7XHJcblxyXG4gICQuZm4udHJpZ2dlck5hdGl2ZSA9IGZ1bmN0aW9uIChldmVudE5hbWUpIHtcclxuICAgIHZhciBlbCA9IHRoaXNbMF0sXHJcbiAgICAgICAgZXZlbnQ7XHJcblxyXG4gICAgaWYgKGVsLmRpc3BhdGNoRXZlbnQpIHsgLy8gZm9yIG1vZGVybiBicm93c2VycyAmIElFOStcclxuICAgICAgaWYgKEV2ZW50SXNTdXBwb3J0ZWQpIHtcclxuICAgICAgICAvLyBGb3IgbW9kZXJuIGJyb3dzZXJzXHJcbiAgICAgICAgZXZlbnQgPSBuZXcgRXZlbnQoZXZlbnROYW1lLCB7XHJcbiAgICAgICAgICBidWJibGVzOiB0cnVlXHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgLy8gRm9yIElFIHNpbmNlIGl0IGRvZXNuJ3Qgc3VwcG9ydCBFdmVudCBjb25zdHJ1Y3RvclxyXG4gICAgICAgIGV2ZW50ID0gZG9jdW1lbnQuY3JlYXRlRXZlbnQoJ0V2ZW50Jyk7XHJcbiAgICAgICAgZXZlbnQuaW5pdEV2ZW50KGV2ZW50TmFtZSwgdHJ1ZSwgZmFsc2UpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBlbC5kaXNwYXRjaEV2ZW50KGV2ZW50KTtcclxuICAgIH1cclxuICB9O1xyXG4gIC8vIDwvZWRpdG9yLWZvbGQ+XHJcblxyXG4gIGZ1bmN0aW9uIHN0cmluZ1NlYXJjaCAobGksIHNlYXJjaFN0cmluZywgbWV0aG9kLCBub3JtYWxpemUpIHtcclxuICAgIHZhciBzdHJpbmdUeXBlcyA9IFtcclxuICAgICAgICAgICdkaXNwbGF5JyxcclxuICAgICAgICAgICdzdWJ0ZXh0JyxcclxuICAgICAgICAgICd0b2tlbnMnXHJcbiAgICAgICAgXSxcclxuICAgICAgICBzZWFyY2hTdWNjZXNzID0gZmFsc2U7XHJcblxyXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBzdHJpbmdUeXBlcy5sZW5ndGg7IGkrKykge1xyXG4gICAgICB2YXIgc3RyaW5nVHlwZSA9IHN0cmluZ1R5cGVzW2ldLFxyXG4gICAgICAgICAgc3RyaW5nID0gbGlbc3RyaW5nVHlwZV07XHJcblxyXG4gICAgICBpZiAoc3RyaW5nKSB7XHJcbiAgICAgICAgc3RyaW5nID0gc3RyaW5nLnRvU3RyaW5nKCk7XHJcblxyXG4gICAgICAgIC8vIFN0cmlwIEhUTUwgdGFncy4gVGhpcyBpc24ndCBwZXJmZWN0LCBidXQgaXQncyBtdWNoIGZhc3RlciB0aGFuIGFueSBvdGhlciBtZXRob2RcclxuICAgICAgICBpZiAoc3RyaW5nVHlwZSA9PT0gJ2Rpc3BsYXknKSB7XHJcbiAgICAgICAgICBzdHJpbmcgPSBzdHJpbmcucmVwbGFjZSgvPFtePl0rPi9nLCAnJyk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBpZiAobm9ybWFsaXplKSBzdHJpbmcgPSBub3JtYWxpemVUb0Jhc2Uoc3RyaW5nKTtcclxuICAgICAgICBzdHJpbmcgPSBzdHJpbmcudG9VcHBlckNhc2UoKTtcclxuXHJcbiAgICAgICAgaWYgKHR5cGVvZiBtZXRob2QgPT09ICdmdW5jdGlvbicpIHtcclxuICAgICAgICAgIHNlYXJjaFN1Y2Nlc3MgPSBtZXRob2Qoc3RyaW5nLCBzZWFyY2hTdHJpbmcpO1xyXG4gICAgICAgIH0gZWxzZSBpZiAobWV0aG9kID09PSAnY29udGFpbnMnKSB7XHJcbiAgICAgICAgICBzZWFyY2hTdWNjZXNzID0gc3RyaW5nLmluZGV4T2Yoc2VhcmNoU3RyaW5nKSA+PSAwO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICBzZWFyY2hTdWNjZXNzID0gc3RyaW5nLnN0YXJ0c1dpdGgoc2VhcmNoU3RyaW5nKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGlmIChzZWFyY2hTdWNjZXNzKSBicmVhaztcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiBzZWFyY2hTdWNjZXNzO1xyXG4gIH1cclxuXHJcbiAgZnVuY3Rpb24gdG9JbnRlZ2VyICh2YWx1ZSkge1xyXG4gICAgcmV0dXJuIHBhcnNlSW50KHZhbHVlLCAxMCkgfHwgMDtcclxuICB9XHJcblxyXG4gIC8vIEJvcnJvd2VkIGZyb20gTG9kYXNoIChfLmRlYnVycilcclxuICAvKiogVXNlZCB0byBtYXAgTGF0aW4gVW5pY29kZSBsZXR0ZXJzIHRvIGJhc2ljIExhdGluIGxldHRlcnMuICovXHJcbiAgdmFyIGRlYnVycmVkTGV0dGVycyA9IHtcclxuICAgIC8vIExhdGluLTEgU3VwcGxlbWVudCBibG9jay5cclxuICAgICdcXHhjMCc6ICdBJywgICdcXHhjMSc6ICdBJywgJ1xceGMyJzogJ0EnLCAnXFx4YzMnOiAnQScsICdcXHhjNCc6ICdBJywgJ1xceGM1JzogJ0EnLFxyXG4gICAgJ1xceGUwJzogJ2EnLCAgJ1xceGUxJzogJ2EnLCAnXFx4ZTInOiAnYScsICdcXHhlMyc6ICdhJywgJ1xceGU0JzogJ2EnLCAnXFx4ZTUnOiAnYScsXHJcbiAgICAnXFx4YzcnOiAnQycsICAnXFx4ZTcnOiAnYycsXHJcbiAgICAnXFx4ZDAnOiAnRCcsICAnXFx4ZjAnOiAnZCcsXHJcbiAgICAnXFx4YzgnOiAnRScsICAnXFx4YzknOiAnRScsICdcXHhjYSc6ICdFJywgJ1xceGNiJzogJ0UnLFxyXG4gICAgJ1xceGU4JzogJ2UnLCAgJ1xceGU5JzogJ2UnLCAnXFx4ZWEnOiAnZScsICdcXHhlYic6ICdlJyxcclxuICAgICdcXHhjYyc6ICdJJywgICdcXHhjZCc6ICdJJywgJ1xceGNlJzogJ0knLCAnXFx4Y2YnOiAnSScsXHJcbiAgICAnXFx4ZWMnOiAnaScsICAnXFx4ZWQnOiAnaScsICdcXHhlZSc6ICdpJywgJ1xceGVmJzogJ2knLFxyXG4gICAgJ1xceGQxJzogJ04nLCAgJ1xceGYxJzogJ24nLFxyXG4gICAgJ1xceGQyJzogJ08nLCAgJ1xceGQzJzogJ08nLCAnXFx4ZDQnOiAnTycsICdcXHhkNSc6ICdPJywgJ1xceGQ2JzogJ08nLCAnXFx4ZDgnOiAnTycsXHJcbiAgICAnXFx4ZjInOiAnbycsICAnXFx4ZjMnOiAnbycsICdcXHhmNCc6ICdvJywgJ1xceGY1JzogJ28nLCAnXFx4ZjYnOiAnbycsICdcXHhmOCc6ICdvJyxcclxuICAgICdcXHhkOSc6ICdVJywgICdcXHhkYSc6ICdVJywgJ1xceGRiJzogJ1UnLCAnXFx4ZGMnOiAnVScsXHJcbiAgICAnXFx4ZjknOiAndScsICAnXFx4ZmEnOiAndScsICdcXHhmYic6ICd1JywgJ1xceGZjJzogJ3UnLFxyXG4gICAgJ1xceGRkJzogJ1knLCAgJ1xceGZkJzogJ3knLCAnXFx4ZmYnOiAneScsXHJcbiAgICAnXFx4YzYnOiAnQWUnLCAnXFx4ZTYnOiAnYWUnLFxyXG4gICAgJ1xceGRlJzogJ1RoJywgJ1xceGZlJzogJ3RoJyxcclxuICAgICdcXHhkZic6ICdzcycsXHJcbiAgICAvLyBMYXRpbiBFeHRlbmRlZC1BIGJsb2NrLlxyXG4gICAgJ1xcdTAxMDAnOiAnQScsICAnXFx1MDEwMic6ICdBJywgJ1xcdTAxMDQnOiAnQScsXHJcbiAgICAnXFx1MDEwMSc6ICdhJywgICdcXHUwMTAzJzogJ2EnLCAnXFx1MDEwNSc6ICdhJyxcclxuICAgICdcXHUwMTA2JzogJ0MnLCAgJ1xcdTAxMDgnOiAnQycsICdcXHUwMTBhJzogJ0MnLCAnXFx1MDEwYyc6ICdDJyxcclxuICAgICdcXHUwMTA3JzogJ2MnLCAgJ1xcdTAxMDknOiAnYycsICdcXHUwMTBiJzogJ2MnLCAnXFx1MDEwZCc6ICdjJyxcclxuICAgICdcXHUwMTBlJzogJ0QnLCAgJ1xcdTAxMTAnOiAnRCcsICdcXHUwMTBmJzogJ2QnLCAnXFx1MDExMSc6ICdkJyxcclxuICAgICdcXHUwMTEyJzogJ0UnLCAgJ1xcdTAxMTQnOiAnRScsICdcXHUwMTE2JzogJ0UnLCAnXFx1MDExOCc6ICdFJywgJ1xcdTAxMWEnOiAnRScsXHJcbiAgICAnXFx1MDExMyc6ICdlJywgICdcXHUwMTE1JzogJ2UnLCAnXFx1MDExNyc6ICdlJywgJ1xcdTAxMTknOiAnZScsICdcXHUwMTFiJzogJ2UnLFxyXG4gICAgJ1xcdTAxMWMnOiAnRycsICAnXFx1MDExZSc6ICdHJywgJ1xcdTAxMjAnOiAnRycsICdcXHUwMTIyJzogJ0cnLFxyXG4gICAgJ1xcdTAxMWQnOiAnZycsICAnXFx1MDExZic6ICdnJywgJ1xcdTAxMjEnOiAnZycsICdcXHUwMTIzJzogJ2cnLFxyXG4gICAgJ1xcdTAxMjQnOiAnSCcsICAnXFx1MDEyNic6ICdIJywgJ1xcdTAxMjUnOiAnaCcsICdcXHUwMTI3JzogJ2gnLFxyXG4gICAgJ1xcdTAxMjgnOiAnSScsICAnXFx1MDEyYSc6ICdJJywgJ1xcdTAxMmMnOiAnSScsICdcXHUwMTJlJzogJ0knLCAnXFx1MDEzMCc6ICdJJyxcclxuICAgICdcXHUwMTI5JzogJ2knLCAgJ1xcdTAxMmInOiAnaScsICdcXHUwMTJkJzogJ2knLCAnXFx1MDEyZic6ICdpJywgJ1xcdTAxMzEnOiAnaScsXHJcbiAgICAnXFx1MDEzNCc6ICdKJywgICdcXHUwMTM1JzogJ2onLFxyXG4gICAgJ1xcdTAxMzYnOiAnSycsICAnXFx1MDEzNyc6ICdrJywgJ1xcdTAxMzgnOiAnaycsXHJcbiAgICAnXFx1MDEzOSc6ICdMJywgICdcXHUwMTNiJzogJ0wnLCAnXFx1MDEzZCc6ICdMJywgJ1xcdTAxM2YnOiAnTCcsICdcXHUwMTQxJzogJ0wnLFxyXG4gICAgJ1xcdTAxM2EnOiAnbCcsICAnXFx1MDEzYyc6ICdsJywgJ1xcdTAxM2UnOiAnbCcsICdcXHUwMTQwJzogJ2wnLCAnXFx1MDE0Mic6ICdsJyxcclxuICAgICdcXHUwMTQzJzogJ04nLCAgJ1xcdTAxNDUnOiAnTicsICdcXHUwMTQ3JzogJ04nLCAnXFx1MDE0YSc6ICdOJyxcclxuICAgICdcXHUwMTQ0JzogJ24nLCAgJ1xcdTAxNDYnOiAnbicsICdcXHUwMTQ4JzogJ24nLCAnXFx1MDE0Yic6ICduJyxcclxuICAgICdcXHUwMTRjJzogJ08nLCAgJ1xcdTAxNGUnOiAnTycsICdcXHUwMTUwJzogJ08nLFxyXG4gICAgJ1xcdTAxNGQnOiAnbycsICAnXFx1MDE0Zic6ICdvJywgJ1xcdTAxNTEnOiAnbycsXHJcbiAgICAnXFx1MDE1NCc6ICdSJywgICdcXHUwMTU2JzogJ1InLCAnXFx1MDE1OCc6ICdSJyxcclxuICAgICdcXHUwMTU1JzogJ3InLCAgJ1xcdTAxNTcnOiAncicsICdcXHUwMTU5JzogJ3InLFxyXG4gICAgJ1xcdTAxNWEnOiAnUycsICAnXFx1MDE1Yyc6ICdTJywgJ1xcdTAxNWUnOiAnUycsICdcXHUwMTYwJzogJ1MnLFxyXG4gICAgJ1xcdTAxNWInOiAncycsICAnXFx1MDE1ZCc6ICdzJywgJ1xcdTAxNWYnOiAncycsICdcXHUwMTYxJzogJ3MnLFxyXG4gICAgJ1xcdTAxNjInOiAnVCcsICAnXFx1MDE2NCc6ICdUJywgJ1xcdTAxNjYnOiAnVCcsXHJcbiAgICAnXFx1MDE2Myc6ICd0JywgICdcXHUwMTY1JzogJ3QnLCAnXFx1MDE2Nyc6ICd0JyxcclxuICAgICdcXHUwMTY4JzogJ1UnLCAgJ1xcdTAxNmEnOiAnVScsICdcXHUwMTZjJzogJ1UnLCAnXFx1MDE2ZSc6ICdVJywgJ1xcdTAxNzAnOiAnVScsICdcXHUwMTcyJzogJ1UnLFxyXG4gICAgJ1xcdTAxNjknOiAndScsICAnXFx1MDE2Yic6ICd1JywgJ1xcdTAxNmQnOiAndScsICdcXHUwMTZmJzogJ3UnLCAnXFx1MDE3MSc6ICd1JywgJ1xcdTAxNzMnOiAndScsXHJcbiAgICAnXFx1MDE3NCc6ICdXJywgICdcXHUwMTc1JzogJ3cnLFxyXG4gICAgJ1xcdTAxNzYnOiAnWScsICAnXFx1MDE3Nyc6ICd5JywgJ1xcdTAxNzgnOiAnWScsXHJcbiAgICAnXFx1MDE3OSc6ICdaJywgICdcXHUwMTdiJzogJ1onLCAnXFx1MDE3ZCc6ICdaJyxcclxuICAgICdcXHUwMTdhJzogJ3onLCAgJ1xcdTAxN2MnOiAneicsICdcXHUwMTdlJzogJ3onLFxyXG4gICAgJ1xcdTAxMzInOiAnSUonLCAnXFx1MDEzMyc6ICdpaicsXHJcbiAgICAnXFx1MDE1Mic6ICdPZScsICdcXHUwMTUzJzogJ29lJyxcclxuICAgICdcXHUwMTQ5JzogXCInblwiLCAnXFx1MDE3Zic6ICdzJ1xyXG4gIH07XHJcblxyXG4gIC8qKiBVc2VkIHRvIG1hdGNoIExhdGluIFVuaWNvZGUgbGV0dGVycyAoZXhjbHVkaW5nIG1hdGhlbWF0aWNhbCBvcGVyYXRvcnMpLiAqL1xyXG4gIHZhciByZUxhdGluID0gL1tcXHhjMC1cXHhkNlxceGQ4LVxceGY2XFx4ZjgtXFx4ZmZcXHUwMTAwLVxcdTAxN2ZdL2c7XHJcblxyXG4gIC8qKiBVc2VkIHRvIGNvbXBvc2UgdW5pY29kZSBjaGFyYWN0ZXIgY2xhc3Nlcy4gKi9cclxuICB2YXIgcnNDb21ib01hcmtzUmFuZ2UgPSAnXFxcXHUwMzAwLVxcXFx1MDM2ZicsXHJcbiAgICAgIHJlQ29tYm9IYWxmTWFya3NSYW5nZSA9ICdcXFxcdWZlMjAtXFxcXHVmZTJmJyxcclxuICAgICAgcnNDb21ib1N5bWJvbHNSYW5nZSA9ICdcXFxcdTIwZDAtXFxcXHUyMGZmJyxcclxuICAgICAgcnNDb21ib01hcmtzRXh0ZW5kZWRSYW5nZSA9ICdcXFxcdTFhYjAtXFxcXHUxYWZmJyxcclxuICAgICAgcnNDb21ib01hcmtzU3VwcGxlbWVudFJhbmdlID0gJ1xcXFx1MWRjMC1cXFxcdTFkZmYnLFxyXG4gICAgICByc0NvbWJvUmFuZ2UgPSByc0NvbWJvTWFya3NSYW5nZSArIHJlQ29tYm9IYWxmTWFya3NSYW5nZSArIHJzQ29tYm9TeW1ib2xzUmFuZ2UgKyByc0NvbWJvTWFya3NFeHRlbmRlZFJhbmdlICsgcnNDb21ib01hcmtzU3VwcGxlbWVudFJhbmdlO1xyXG5cclxuICAvKiogVXNlZCB0byBjb21wb3NlIHVuaWNvZGUgY2FwdHVyZSBncm91cHMuICovXHJcbiAgdmFyIHJzQ29tYm8gPSAnWycgKyByc0NvbWJvUmFuZ2UgKyAnXSc7XHJcblxyXG4gIC8qKlxyXG4gICAqIFVzZWQgdG8gbWF0Y2ggW2NvbWJpbmluZyBkaWFjcml0aWNhbCBtYXJrc10oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvQ29tYmluaW5nX0RpYWNyaXRpY2FsX01hcmtzKSBhbmRcclxuICAgKiBbY29tYmluaW5nIGRpYWNyaXRpY2FsIG1hcmtzIGZvciBzeW1ib2xzXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9Db21iaW5pbmdfRGlhY3JpdGljYWxfTWFya3NfZm9yX1N5bWJvbHMpLlxyXG4gICAqL1xyXG4gIHZhciByZUNvbWJvTWFyayA9IFJlZ0V4cChyc0NvbWJvLCAnZycpO1xyXG5cclxuICBmdW5jdGlvbiBkZWJ1cnJMZXR0ZXIgKGtleSkge1xyXG4gICAgcmV0dXJuIGRlYnVycmVkTGV0dGVyc1trZXldO1xyXG4gIH07XHJcblxyXG4gIGZ1bmN0aW9uIG5vcm1hbGl6ZVRvQmFzZSAoc3RyaW5nKSB7XHJcbiAgICBzdHJpbmcgPSBzdHJpbmcudG9TdHJpbmcoKTtcclxuICAgIHJldHVybiBzdHJpbmcgJiYgc3RyaW5nLnJlcGxhY2UocmVMYXRpbiwgZGVidXJyTGV0dGVyKS5yZXBsYWNlKHJlQ29tYm9NYXJrLCAnJyk7XHJcbiAgfVxyXG5cclxuICAvLyBMaXN0IG9mIEhUTUwgZW50aXRpZXMgZm9yIGVzY2FwaW5nLlxyXG4gIHZhciBlc2NhcGVNYXAgPSB7XHJcbiAgICAnJic6ICcmYW1wOycsXHJcbiAgICAnPCc6ICcmbHQ7JyxcclxuICAgICc+JzogJyZndDsnLFxyXG4gICAgJ1wiJzogJyZxdW90OycsXHJcbiAgICBcIidcIjogJyYjeDI3OycsXHJcbiAgICAnYCc6ICcmI3g2MDsnXHJcbiAgfTtcclxuXHJcbiAgLy8gRnVuY3Rpb25zIGZvciBlc2NhcGluZyBhbmQgdW5lc2NhcGluZyBzdHJpbmdzIHRvL2Zyb20gSFRNTCBpbnRlcnBvbGF0aW9uLlxyXG4gIHZhciBjcmVhdGVFc2NhcGVyID0gZnVuY3Rpb24gKG1hcCkge1xyXG4gICAgdmFyIGVzY2FwZXIgPSBmdW5jdGlvbiAobWF0Y2gpIHtcclxuICAgICAgcmV0dXJuIG1hcFttYXRjaF07XHJcbiAgICB9O1xyXG4gICAgLy8gUmVnZXhlcyBmb3IgaWRlbnRpZnlpbmcgYSBrZXkgdGhhdCBuZWVkcyB0byBiZSBlc2NhcGVkLlxyXG4gICAgdmFyIHNvdXJjZSA9ICcoPzonICsgT2JqZWN0LmtleXMobWFwKS5qb2luKCd8JykgKyAnKSc7XHJcbiAgICB2YXIgdGVzdFJlZ2V4cCA9IFJlZ0V4cChzb3VyY2UpO1xyXG4gICAgdmFyIHJlcGxhY2VSZWdleHAgPSBSZWdFeHAoc291cmNlLCAnZycpO1xyXG4gICAgcmV0dXJuIGZ1bmN0aW9uIChzdHJpbmcpIHtcclxuICAgICAgc3RyaW5nID0gc3RyaW5nID09IG51bGwgPyAnJyA6ICcnICsgc3RyaW5nO1xyXG4gICAgICByZXR1cm4gdGVzdFJlZ2V4cC50ZXN0KHN0cmluZykgPyBzdHJpbmcucmVwbGFjZShyZXBsYWNlUmVnZXhwLCBlc2NhcGVyKSA6IHN0cmluZztcclxuICAgIH07XHJcbiAgfTtcclxuXHJcbiAgdmFyIGh0bWxFc2NhcGUgPSBjcmVhdGVFc2NhcGVyKGVzY2FwZU1hcCk7XHJcblxyXG4gIC8qKlxyXG4gICAqIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG4gICAqIENvbnN0YW50c1xyXG4gICAqIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxyXG4gICAqL1xyXG5cclxuICB2YXIga2V5Q29kZU1hcCA9IHtcclxuICAgIDMyOiAnICcsXHJcbiAgICA0ODogJzAnLFxyXG4gICAgNDk6ICcxJyxcclxuICAgIDUwOiAnMicsXHJcbiAgICA1MTogJzMnLFxyXG4gICAgNTI6ICc0JyxcclxuICAgIDUzOiAnNScsXHJcbiAgICA1NDogJzYnLFxyXG4gICAgNTU6ICc3JyxcclxuICAgIDU2OiAnOCcsXHJcbiAgICA1NzogJzknLFxyXG4gICAgNTk6ICc7JyxcclxuICAgIDY1OiAnQScsXHJcbiAgICA2NjogJ0InLFxyXG4gICAgNjc6ICdDJyxcclxuICAgIDY4OiAnRCcsXHJcbiAgICA2OTogJ0UnLFxyXG4gICAgNzA6ICdGJyxcclxuICAgIDcxOiAnRycsXHJcbiAgICA3MjogJ0gnLFxyXG4gICAgNzM6ICdJJyxcclxuICAgIDc0OiAnSicsXHJcbiAgICA3NTogJ0snLFxyXG4gICAgNzY6ICdMJyxcclxuICAgIDc3OiAnTScsXHJcbiAgICA3ODogJ04nLFxyXG4gICAgNzk6ICdPJyxcclxuICAgIDgwOiAnUCcsXHJcbiAgICA4MTogJ1EnLFxyXG4gICAgODI6ICdSJyxcclxuICAgIDgzOiAnUycsXHJcbiAgICA4NDogJ1QnLFxyXG4gICAgODU6ICdVJyxcclxuICAgIDg2OiAnVicsXHJcbiAgICA4NzogJ1cnLFxyXG4gICAgODg6ICdYJyxcclxuICAgIDg5OiAnWScsXHJcbiAgICA5MDogJ1onLFxyXG4gICAgOTY6ICcwJyxcclxuICAgIDk3OiAnMScsXHJcbiAgICA5ODogJzInLFxyXG4gICAgOTk6ICczJyxcclxuICAgIDEwMDogJzQnLFxyXG4gICAgMTAxOiAnNScsXHJcbiAgICAxMDI6ICc2JyxcclxuICAgIDEwMzogJzcnLFxyXG4gICAgMTA0OiAnOCcsXHJcbiAgICAxMDU6ICc5J1xyXG4gIH07XHJcblxyXG4gIHZhciBrZXlDb2RlcyA9IHtcclxuICAgIEVTQ0FQRTogMjcsIC8vIEtleWJvYXJkRXZlbnQud2hpY2ggdmFsdWUgZm9yIEVzY2FwZSAoRXNjKSBrZXlcclxuICAgIEVOVEVSOiAxMywgLy8gS2V5Ym9hcmRFdmVudC53aGljaCB2YWx1ZSBmb3IgRW50ZXIga2V5XHJcbiAgICBTUEFDRTogMzIsIC8vIEtleWJvYXJkRXZlbnQud2hpY2ggdmFsdWUgZm9yIHNwYWNlIGtleVxyXG4gICAgVEFCOiA5LCAvLyBLZXlib2FyZEV2ZW50LndoaWNoIHZhbHVlIGZvciB0YWIga2V5XHJcbiAgICBBUlJPV19VUDogMzgsIC8vIEtleWJvYXJkRXZlbnQud2hpY2ggdmFsdWUgZm9yIHVwIGFycm93IGtleVxyXG4gICAgQVJST1dfRE9XTjogNDAgLy8gS2V5Ym9hcmRFdmVudC53aGljaCB2YWx1ZSBmb3IgZG93biBhcnJvdyBrZXlcclxuICB9XHJcblxyXG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gIHZhciBEcm9wZG93biA9IHdpbmRvdy5Ecm9wZG93biB8fCBib290c3RyYXAuRHJvcGRvd247XHJcblxyXG4gIGZ1bmN0aW9uIGdldFZlcnNpb24gKCkge1xyXG4gICAgdmFyIHZlcnNpb247XHJcblxyXG4gICAgdHJ5IHtcclxuICAgICAgdmVyc2lvbiA9ICQuZm4uZHJvcGRvd24uQ29uc3RydWN0b3IuVkVSU0lPTjtcclxuICAgIH0gY2F0Y2ggKGVycikge1xyXG4gICAgICB2ZXJzaW9uID0gRHJvcGRvd24uVkVSU0lPTjtcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gdmVyc2lvbjtcclxuICB9XHJcblxyXG4gIHZhciB2ZXJzaW9uID0ge1xyXG4gICAgc3VjY2VzczogZmFsc2UsXHJcbiAgICBtYWpvcjogJzMnXHJcbiAgfTtcclxuXHJcbiAgdHJ5IHtcclxuICAgIHZlcnNpb24uZnVsbCA9IChnZXRWZXJzaW9uKCkgfHwgJycpLnNwbGl0KCcgJylbMF0uc3BsaXQoJy4nKTtcclxuICAgIHZlcnNpb24ubWFqb3IgPSB2ZXJzaW9uLmZ1bGxbMF07XHJcbiAgICB2ZXJzaW9uLnN1Y2Nlc3MgPSB0cnVlO1xyXG4gIH0gY2F0Y2ggKGVycikge1xyXG4gICAgLy8gZG8gbm90aGluZ1xyXG4gIH1cclxuXHJcbiAgdmFyIHNlbGVjdElkID0gMDtcclxuXHJcbiAgdmFyIEVWRU5UX0tFWSA9ICcuYnMuc2VsZWN0JztcclxuXHJcbiAgdmFyIGNsYXNzTmFtZXMgPSB7XHJcbiAgICBESVNBQkxFRDogJ2Rpc2FibGVkJyxcclxuICAgIERJVklERVI6ICdkaXZpZGVyJyxcclxuICAgIFNIT1c6ICdvcGVuJyxcclxuICAgIERST1BVUDogJ2Ryb3B1cCcsXHJcbiAgICBNRU5VOiAnZHJvcGRvd24tbWVudScsXHJcbiAgICBNRU5VUklHSFQ6ICdkcm9wZG93bi1tZW51LXJpZ2h0JyxcclxuICAgIE1FTlVMRUZUOiAnZHJvcGRvd24tbWVudS1sZWZ0JyxcclxuICAgIC8vIHRvLWRvOiByZXBsYWNlIHdpdGggbW9yZSBhZHZhbmNlZCB0ZW1wbGF0ZS9jdXN0b21pemF0aW9uIG9wdGlvbnNcclxuICAgIEJVVFRPTkNMQVNTOiAnYnRuLWRlZmF1bHQnLFxyXG4gICAgUE9QT1ZFUkhFQURFUjogJ3BvcG92ZXItdGl0bGUnLFxyXG4gICAgSUNPTkJBU0U6ICdnbHlwaGljb24nLFxyXG4gICAgVElDS0lDT046ICdnbHlwaGljb24tb2snXHJcbiAgfVxyXG5cclxuICB2YXIgU2VsZWN0b3IgPSB7XHJcbiAgICBNRU5VOiAnLicgKyBjbGFzc05hbWVzLk1FTlUsXHJcbiAgICBEQVRBX1RPR0dMRTogJ2RhdGEtdG9nZ2xlPVwiZHJvcGRvd25cIidcclxuICB9XHJcblxyXG4gIHZhciBlbGVtZW50VGVtcGxhdGVzID0ge1xyXG4gICAgZGl2OiBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKSxcclxuICAgIHNwYW46IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3NwYW4nKSxcclxuICAgIGk6IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2knKSxcclxuICAgIHN1YnRleHQ6IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3NtYWxsJyksXHJcbiAgICBhOiBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdhJyksXHJcbiAgICBsaTogZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnbGknKSxcclxuICAgIHdoaXRlc3BhY2U6IGRvY3VtZW50LmNyZWF0ZVRleHROb2RlKCdcXHUwMEEwJyksXHJcbiAgICBmcmFnbWVudDogZG9jdW1lbnQuY3JlYXRlRG9jdW1lbnRGcmFnbWVudCgpLFxyXG4gICAgb3B0aW9uOiBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdvcHRpb24nKVxyXG4gIH1cclxuXHJcbiAgZWxlbWVudFRlbXBsYXRlcy5zZWxlY3RlZE9wdGlvbiA9IGVsZW1lbnRUZW1wbGF0ZXMub3B0aW9uLmNsb25lTm9kZShmYWxzZSk7XHJcbiAgZWxlbWVudFRlbXBsYXRlcy5zZWxlY3RlZE9wdGlvbi5zZXRBdHRyaWJ1dGUoJ3NlbGVjdGVkJywgdHJ1ZSk7XHJcblxyXG4gIGVsZW1lbnRUZW1wbGF0ZXMubm9SZXN1bHRzID0gZWxlbWVudFRlbXBsYXRlcy5saS5jbG9uZU5vZGUoZmFsc2UpO1xyXG4gIGVsZW1lbnRUZW1wbGF0ZXMubm9SZXN1bHRzLmNsYXNzTmFtZSA9ICduby1yZXN1bHRzJztcclxuXHJcbiAgZWxlbWVudFRlbXBsYXRlcy5hLnNldEF0dHJpYnV0ZSgncm9sZScsICdvcHRpb24nKTtcclxuICBlbGVtZW50VGVtcGxhdGVzLmEuY2xhc3NOYW1lID0gJ2Ryb3Bkb3duLWl0ZW0nO1xyXG5cclxuICBlbGVtZW50VGVtcGxhdGVzLnN1YnRleHQuY2xhc3NOYW1lID0gJ3RleHQtbXV0ZWQnO1xyXG5cclxuICBlbGVtZW50VGVtcGxhdGVzLnRleHQgPSBlbGVtZW50VGVtcGxhdGVzLnNwYW4uY2xvbmVOb2RlKGZhbHNlKTtcclxuICBlbGVtZW50VGVtcGxhdGVzLnRleHQuY2xhc3NOYW1lID0gJ3RleHQnO1xyXG5cclxuICBlbGVtZW50VGVtcGxhdGVzLmNoZWNrTWFyayA9IGVsZW1lbnRUZW1wbGF0ZXMuc3Bhbi5jbG9uZU5vZGUoZmFsc2UpO1xyXG5cclxuICB2YXIgUkVHRVhQX0FSUk9XID0gbmV3IFJlZ0V4cChrZXlDb2Rlcy5BUlJPV19VUCArICd8JyArIGtleUNvZGVzLkFSUk9XX0RPV04pO1xyXG4gIHZhciBSRUdFWFBfVEFCX09SX0VTQ0FQRSA9IG5ldyBSZWdFeHAoJ14nICsga2V5Q29kZXMuVEFCICsgJyR8JyArIGtleUNvZGVzLkVTQ0FQRSk7XHJcblxyXG4gIHZhciBnZW5lcmF0ZU9wdGlvbiA9IHtcclxuICAgIGxpOiBmdW5jdGlvbiAoY29udGVudCwgY2xhc3Nlcywgb3B0Z3JvdXApIHtcclxuICAgICAgdmFyIGxpID0gZWxlbWVudFRlbXBsYXRlcy5saS5jbG9uZU5vZGUoZmFsc2UpO1xyXG5cclxuICAgICAgaWYgKGNvbnRlbnQpIHtcclxuICAgICAgICBpZiAoY29udGVudC5ub2RlVHlwZSA9PT0gMSB8fCBjb250ZW50Lm5vZGVUeXBlID09PSAxMSkge1xyXG4gICAgICAgICAgbGkuYXBwZW5kQ2hpbGQoY29udGVudCk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIGxpLmlubmVySFRNTCA9IGNvbnRlbnQ7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAodHlwZW9mIGNsYXNzZXMgIT09ICd1bmRlZmluZWQnICYmIGNsYXNzZXMgIT09ICcnKSBsaS5jbGFzc05hbWUgPSBjbGFzc2VzO1xyXG4gICAgICBpZiAodHlwZW9mIG9wdGdyb3VwICE9PSAndW5kZWZpbmVkJyAmJiBvcHRncm91cCAhPT0gbnVsbCkgbGkuY2xhc3NMaXN0LmFkZCgnb3B0Z3JvdXAtJyArIG9wdGdyb3VwKTtcclxuXHJcbiAgICAgIHJldHVybiBsaTtcclxuICAgIH0sXHJcblxyXG4gICAgYTogZnVuY3Rpb24gKHRleHQsIGNsYXNzZXMsIGlubGluZSkge1xyXG4gICAgICB2YXIgYSA9IGVsZW1lbnRUZW1wbGF0ZXMuYS5jbG9uZU5vZGUodHJ1ZSk7XHJcblxyXG4gICAgICBpZiAodGV4dCkge1xyXG4gICAgICAgIGlmICh0ZXh0Lm5vZGVUeXBlID09PSAxMSkge1xyXG4gICAgICAgICAgYS5hcHBlbmRDaGlsZCh0ZXh0KTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgYS5pbnNlcnRBZGphY2VudEhUTUwoJ2JlZm9yZWVuZCcsIHRleHQpO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKHR5cGVvZiBjbGFzc2VzICE9PSAndW5kZWZpbmVkJyAmJiBjbGFzc2VzICE9PSAnJykgYS5jbGFzc0xpc3QuYWRkLmFwcGx5KGEuY2xhc3NMaXN0LCBjbGFzc2VzLnNwbGl0KC9cXHMrLykpO1xyXG4gICAgICBpZiAoaW5saW5lKSBhLnNldEF0dHJpYnV0ZSgnc3R5bGUnLCBpbmxpbmUpO1xyXG5cclxuICAgICAgcmV0dXJuIGE7XHJcbiAgICB9LFxyXG5cclxuICAgIHRleHQ6IGZ1bmN0aW9uIChvcHRpb25zLCB1c2VGcmFnbWVudCkge1xyXG4gICAgICB2YXIgdGV4dEVsZW1lbnQgPSBlbGVtZW50VGVtcGxhdGVzLnRleHQuY2xvbmVOb2RlKGZhbHNlKSxcclxuICAgICAgICAgIHN1YnRleHRFbGVtZW50LFxyXG4gICAgICAgICAgaWNvbkVsZW1lbnQ7XHJcblxyXG4gICAgICBpZiAob3B0aW9ucy5jb250ZW50KSB7XHJcbiAgICAgICAgdGV4dEVsZW1lbnQuaW5uZXJIVE1MID0gb3B0aW9ucy5jb250ZW50O1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHRleHRFbGVtZW50LnRleHRDb250ZW50ID0gb3B0aW9ucy50ZXh0O1xyXG5cclxuICAgICAgICBpZiAob3B0aW9ucy5pY29uKSB7XHJcbiAgICAgICAgICB2YXIgd2hpdGVzcGFjZSA9IGVsZW1lbnRUZW1wbGF0ZXMud2hpdGVzcGFjZS5jbG9uZU5vZGUoZmFsc2UpO1xyXG5cclxuICAgICAgICAgIC8vIG5lZWQgdG8gdXNlIDxpPiBmb3IgaWNvbnMgaW4gdGhlIGJ1dHRvbiB0byBwcmV2ZW50IGEgYnJlYWtpbmcgY2hhbmdlXHJcbiAgICAgICAgICAvLyBub3RlOiBzd2l0Y2ggdG8gc3BhbiBpbiBuZXh0IG1ham9yIHJlbGVhc2VcclxuICAgICAgICAgIGljb25FbGVtZW50ID0gKHVzZUZyYWdtZW50ID09PSB0cnVlID8gZWxlbWVudFRlbXBsYXRlcy5pIDogZWxlbWVudFRlbXBsYXRlcy5zcGFuKS5jbG9uZU5vZGUoZmFsc2UpO1xyXG4gICAgICAgICAgaWNvbkVsZW1lbnQuY2xhc3NOYW1lID0gdGhpcy5vcHRpb25zLmljb25CYXNlICsgJyAnICsgb3B0aW9ucy5pY29uO1xyXG5cclxuICAgICAgICAgIGVsZW1lbnRUZW1wbGF0ZXMuZnJhZ21lbnQuYXBwZW5kQ2hpbGQoaWNvbkVsZW1lbnQpO1xyXG4gICAgICAgICAgZWxlbWVudFRlbXBsYXRlcy5mcmFnbWVudC5hcHBlbmRDaGlsZCh3aGl0ZXNwYWNlKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGlmIChvcHRpb25zLnN1YnRleHQpIHtcclxuICAgICAgICAgIHN1YnRleHRFbGVtZW50ID0gZWxlbWVudFRlbXBsYXRlcy5zdWJ0ZXh0LmNsb25lTm9kZShmYWxzZSk7XHJcbiAgICAgICAgICBzdWJ0ZXh0RWxlbWVudC50ZXh0Q29udGVudCA9IG9wdGlvbnMuc3VidGV4dDtcclxuICAgICAgICAgIHRleHRFbGVtZW50LmFwcGVuZENoaWxkKHN1YnRleHRFbGVtZW50KTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmICh1c2VGcmFnbWVudCA9PT0gdHJ1ZSkge1xyXG4gICAgICAgIHdoaWxlICh0ZXh0RWxlbWVudC5jaGlsZE5vZGVzLmxlbmd0aCA+IDApIHtcclxuICAgICAgICAgIGVsZW1lbnRUZW1wbGF0ZXMuZnJhZ21lbnQuYXBwZW5kQ2hpbGQodGV4dEVsZW1lbnQuY2hpbGROb2Rlc1swXSk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIGVsZW1lbnRUZW1wbGF0ZXMuZnJhZ21lbnQuYXBwZW5kQ2hpbGQodGV4dEVsZW1lbnQpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICByZXR1cm4gZWxlbWVudFRlbXBsYXRlcy5mcmFnbWVudDtcclxuICAgIH0sXHJcblxyXG4gICAgbGFiZWw6IGZ1bmN0aW9uIChvcHRpb25zKSB7XHJcbiAgICAgIHZhciB0ZXh0RWxlbWVudCA9IGVsZW1lbnRUZW1wbGF0ZXMudGV4dC5jbG9uZU5vZGUoZmFsc2UpLFxyXG4gICAgICAgICAgc3VidGV4dEVsZW1lbnQsXHJcbiAgICAgICAgICBpY29uRWxlbWVudDtcclxuXHJcbiAgICAgIHRleHRFbGVtZW50LmlubmVySFRNTCA9IG9wdGlvbnMuZGlzcGxheTtcclxuXHJcbiAgICAgIGlmIChvcHRpb25zLmljb24pIHtcclxuICAgICAgICB2YXIgd2hpdGVzcGFjZSA9IGVsZW1lbnRUZW1wbGF0ZXMud2hpdGVzcGFjZS5jbG9uZU5vZGUoZmFsc2UpO1xyXG5cclxuICAgICAgICBpY29uRWxlbWVudCA9IGVsZW1lbnRUZW1wbGF0ZXMuc3Bhbi5jbG9uZU5vZGUoZmFsc2UpO1xyXG4gICAgICAgIGljb25FbGVtZW50LmNsYXNzTmFtZSA9IHRoaXMub3B0aW9ucy5pY29uQmFzZSArICcgJyArIG9wdGlvbnMuaWNvbjtcclxuXHJcbiAgICAgICAgZWxlbWVudFRlbXBsYXRlcy5mcmFnbWVudC5hcHBlbmRDaGlsZChpY29uRWxlbWVudCk7XHJcbiAgICAgICAgZWxlbWVudFRlbXBsYXRlcy5mcmFnbWVudC5hcHBlbmRDaGlsZCh3aGl0ZXNwYWNlKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKG9wdGlvbnMuc3VidGV4dCkge1xyXG4gICAgICAgIHN1YnRleHRFbGVtZW50ID0gZWxlbWVudFRlbXBsYXRlcy5zdWJ0ZXh0LmNsb25lTm9kZShmYWxzZSk7XHJcbiAgICAgICAgc3VidGV4dEVsZW1lbnQudGV4dENvbnRlbnQgPSBvcHRpb25zLnN1YnRleHQ7XHJcbiAgICAgICAgdGV4dEVsZW1lbnQuYXBwZW5kQ2hpbGQoc3VidGV4dEVsZW1lbnQpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBlbGVtZW50VGVtcGxhdGVzLmZyYWdtZW50LmFwcGVuZENoaWxkKHRleHRFbGVtZW50KTtcclxuXHJcbiAgICAgIHJldHVybiBlbGVtZW50VGVtcGxhdGVzLmZyYWdtZW50O1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgdmFyIGdldE9wdGlvbkRhdGEgPSB7XHJcbiAgICBmcm9tT3B0aW9uOiBmdW5jdGlvbiAob3B0aW9uLCB0eXBlKSB7XHJcbiAgICAgIHZhciB2YWx1ZTtcclxuXHJcbiAgICAgIHN3aXRjaCAodHlwZSkge1xyXG4gICAgICAgIGNhc2UgJ2RpdmlkZXInOlxyXG4gICAgICAgICAgdmFsdWUgPSBvcHRpb24uZ2V0QXR0cmlidXRlKCdkYXRhLWRpdmlkZXInKSA9PT0gJ3RydWUnO1xyXG4gICAgICAgICAgYnJlYWs7XHJcblxyXG4gICAgICAgIGNhc2UgJ3RleHQnOlxyXG4gICAgICAgICAgdmFsdWUgPSBvcHRpb24udGV4dENvbnRlbnQ7XHJcbiAgICAgICAgICBicmVhaztcclxuXHJcbiAgICAgICAgY2FzZSAnbGFiZWwnOlxyXG4gICAgICAgICAgdmFsdWUgPSBvcHRpb24ubGFiZWw7XHJcbiAgICAgICAgICBicmVhaztcclxuXHJcbiAgICAgICAgY2FzZSAnc3R5bGUnOlxyXG4gICAgICAgICAgdmFsdWUgPSBvcHRpb24uc3R5bGUuY3NzVGV4dDtcclxuICAgICAgICAgIGJyZWFrO1xyXG5cclxuICAgICAgICBjYXNlICdjb250ZW50JzpcclxuICAgICAgICBjYXNlICd0b2tlbnMnOlxyXG4gICAgICAgIGNhc2UgJ3N1YnRleHQnOlxyXG4gICAgICAgIGNhc2UgJ2ljb24nOlxyXG4gICAgICAgICAgdmFsdWUgPSBvcHRpb24uZ2V0QXR0cmlidXRlKCdkYXRhLScgKyB0eXBlKTtcclxuICAgICAgICAgIGJyZWFrO1xyXG4gICAgICB9XHJcblxyXG4gICAgICByZXR1cm4gdmFsdWU7XHJcbiAgICB9LFxyXG4gICAgZnJvbURhdGFTb3VyY2U6IGZ1bmN0aW9uIChvcHRpb24sIHR5cGUpIHtcclxuICAgICAgdmFyIHZhbHVlO1xyXG5cclxuICAgICAgc3dpdGNoICh0eXBlKSB7XHJcbiAgICAgICAgY2FzZSAndGV4dCc6XHJcbiAgICAgICAgY2FzZSAnbGFiZWwnOlxyXG4gICAgICAgICAgdmFsdWUgPSBvcHRpb24udGV4dCB8fCBvcHRpb24udmFsdWUgfHwgJyc7XHJcbiAgICAgICAgICBicmVhaztcclxuXHJcbiAgICAgICAgY2FzZSAnZGl2aWRlcic6XHJcbiAgICAgICAgY2FzZSAnc3R5bGUnOlxyXG4gICAgICAgIGNhc2UgJ2NvbnRlbnQnOlxyXG4gICAgICAgIGNhc2UgJ3Rva2Vucyc6XHJcbiAgICAgICAgY2FzZSAnc3VidGV4dCc6XHJcbiAgICAgICAgY2FzZSAnaWNvbic6XHJcbiAgICAgICAgICB2YWx1ZSA9IG9wdGlvblt0eXBlXTtcclxuICAgICAgICAgIGJyZWFrO1xyXG4gICAgICB9XHJcblxyXG4gICAgICByZXR1cm4gdmFsdWU7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiBzaG93Tm9SZXN1bHRzIChzZWFyY2hNYXRjaCwgc2VhcmNoVmFsdWUpIHtcclxuICAgIGlmICghc2VhcmNoTWF0Y2gubGVuZ3RoKSB7XHJcbiAgICAgIGVsZW1lbnRUZW1wbGF0ZXMubm9SZXN1bHRzLmlubmVySFRNTCA9IHRoaXMub3B0aW9ucy5ub25lUmVzdWx0c1RleHQucmVwbGFjZSgnezB9JywgJ1wiJyArIGh0bWxFc2NhcGUoc2VhcmNoVmFsdWUpICsgJ1wiJyk7XHJcbiAgICAgIHRoaXMuJG1lbnVJbm5lclswXS5maXJzdENoaWxkLmFwcGVuZENoaWxkKGVsZW1lbnRUZW1wbGF0ZXMubm9SZXN1bHRzKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIGZ1bmN0aW9uIGZpbHRlckhpZGRlbiAoaXRlbSkge1xyXG4gICAgcmV0dXJuICEoaXRlbS5oaWRkZW4gfHwgdGhpcy5vcHRpb25zLmhpZGVEaXNhYmxlZCAmJiBpdGVtLmRpc2FibGVkKTtcclxuICB9XHJcblxyXG4gIHZhciBTZWxlY3RwaWNrZXIgPSBmdW5jdGlvbiAoZWxlbWVudCwgb3B0aW9ucykge1xyXG4gICAgdmFyIHRoYXQgPSB0aGlzO1xyXG5cclxuICAgIC8vIGJvb3RzdHJhcC1zZWxlY3QgaGFzIGJlZW4gaW5pdGlhbGl6ZWQgLSByZXZlcnQgdmFsSG9va3Muc2VsZWN0LnNldCBiYWNrIHRvIGl0cyBvcmlnaW5hbCBmdW5jdGlvblxyXG4gICAgaWYgKCF2YWxIb29rcy51c2VEZWZhdWx0KSB7XHJcbiAgICAgICQudmFsSG9va3Muc2VsZWN0LnNldCA9IHZhbEhvb2tzLl9zZXQ7XHJcbiAgICAgIHZhbEhvb2tzLnVzZURlZmF1bHQgPSB0cnVlO1xyXG4gICAgfVxyXG5cclxuICAgIHRoaXMuJGVsZW1lbnQgPSAkKGVsZW1lbnQpO1xyXG4gICAgdGhpcy4kbmV3RWxlbWVudCA9IG51bGw7XHJcbiAgICB0aGlzLiRidXR0b24gPSBudWxsO1xyXG4gICAgdGhpcy4kbWVudSA9IG51bGw7XHJcbiAgICB0aGlzLm9wdGlvbnMgPSBvcHRpb25zO1xyXG4gICAgdGhpcy5zZWxlY3RwaWNrZXIgPSB7XHJcbiAgICAgIG1haW46IHtcclxuICAgICAgICBvcHRpb25RdWV1ZTogZWxlbWVudFRlbXBsYXRlcy5mcmFnbWVudC5jbG9uZU5vZGUoZmFsc2UpXHJcbiAgICAgIH0sXHJcbiAgICAgIHNlYXJjaDoge30sXHJcbiAgICAgIGN1cnJlbnQ6IHt9LCAvLyBjdXJyZW50IGNoYW5nZXMgaWYgYSBzZWFyY2ggaXMgaW4gcHJvZ3Jlc3NcclxuICAgICAgdmlldzoge30sXHJcbiAgICAgIGlzU2VhcmNoaW5nOiBmYWxzZSxcclxuICAgICAga2V5ZG93bjoge1xyXG4gICAgICAgIGtleUhpc3Rvcnk6ICcnLFxyXG4gICAgICAgIHJlc2V0S2V5SGlzdG9yeToge1xyXG4gICAgICAgICAgc3RhcnQ6IGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgcmV0dXJuIHNldFRpbWVvdXQoZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICAgIHRoYXQuc2VsZWN0cGlja2VyLmtleWRvd24ua2V5SGlzdG9yeSA9ICcnO1xyXG4gICAgICAgICAgICB9LCA4MDApO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfTtcclxuXHJcbiAgICB0aGlzLnNpemVJbmZvID0ge307XHJcblxyXG4gICAgLy8gRm9ybWF0IHdpbmRvdyBwYWRkaW5nXHJcbiAgICB2YXIgd2luUGFkID0gdGhpcy5vcHRpb25zLndpbmRvd1BhZGRpbmc7XHJcbiAgICBpZiAodHlwZW9mIHdpblBhZCA9PT0gJ251bWJlcicpIHtcclxuICAgICAgdGhpcy5vcHRpb25zLndpbmRvd1BhZGRpbmcgPSBbd2luUGFkLCB3aW5QYWQsIHdpblBhZCwgd2luUGFkXTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBFeHBvc2UgcHVibGljIG1ldGhvZHNcclxuICAgIHRoaXMudmFsID0gU2VsZWN0cGlja2VyLnByb3RvdHlwZS52YWw7XHJcbiAgICB0aGlzLnJlbmRlciA9IFNlbGVjdHBpY2tlci5wcm90b3R5cGUucmVuZGVyO1xyXG4gICAgdGhpcy5yZWZyZXNoID0gU2VsZWN0cGlja2VyLnByb3RvdHlwZS5yZWZyZXNoO1xyXG4gICAgdGhpcy5zZXRTdHlsZSA9IFNlbGVjdHBpY2tlci5wcm90b3R5cGUuc2V0U3R5bGU7XHJcbiAgICB0aGlzLnNlbGVjdEFsbCA9IFNlbGVjdHBpY2tlci5wcm90b3R5cGUuc2VsZWN0QWxsO1xyXG4gICAgdGhpcy5kZXNlbGVjdEFsbCA9IFNlbGVjdHBpY2tlci5wcm90b3R5cGUuZGVzZWxlY3RBbGw7XHJcbiAgICB0aGlzLmRlc3Ryb3kgPSBTZWxlY3RwaWNrZXIucHJvdG90eXBlLmRlc3Ryb3k7XHJcbiAgICB0aGlzLnJlbW92ZSA9IFNlbGVjdHBpY2tlci5wcm90b3R5cGUucmVtb3ZlO1xyXG4gICAgdGhpcy5zaG93ID0gU2VsZWN0cGlja2VyLnByb3RvdHlwZS5zaG93O1xyXG4gICAgdGhpcy5oaWRlID0gU2VsZWN0cGlja2VyLnByb3RvdHlwZS5oaWRlO1xyXG5cclxuICAgIHRoaXMuaW5pdCgpO1xyXG4gIH07XHJcblxyXG4gIFNlbGVjdHBpY2tlci5WRVJTSU9OID0gJzEuMTQuMC1iZXRhMic7XHJcblxyXG4gIC8vIHBhcnQgb2YgdGhpcyBpcyBkdXBsaWNhdGVkIGluIGkxOG4vZGVmYXVsdHMtZW5fVVMuanMuIE1ha2Ugc3VyZSB0byB1cGRhdGUgYm90aC5cclxuICBTZWxlY3RwaWNrZXIuREVGQVVMVFMgPSB7XHJcbiAgICBub25lU2VsZWN0ZWRUZXh0OiAnTm90aGluZyBzZWxlY3RlZCcsXHJcbiAgICBub25lUmVzdWx0c1RleHQ6ICdObyByZXN1bHRzIG1hdGNoZWQgezB9JyxcclxuICAgIGNvdW50U2VsZWN0ZWRUZXh0OiBmdW5jdGlvbiAobnVtU2VsZWN0ZWQsIG51bVRvdGFsKSB7XHJcbiAgICAgIHJldHVybiAobnVtU2VsZWN0ZWQgPT0gMSkgPyAnezB9IGl0ZW0gc2VsZWN0ZWQnIDogJ3swfSBpdGVtcyBzZWxlY3RlZCc7XHJcbiAgICB9LFxyXG4gICAgbWF4T3B0aW9uc1RleHQ6IGZ1bmN0aW9uIChudW1BbGwsIG51bUdyb3VwKSB7XHJcbiAgICAgIHJldHVybiBbXHJcbiAgICAgICAgKG51bUFsbCA9PSAxKSA/ICdMaW1pdCByZWFjaGVkICh7bn0gaXRlbSBtYXgpJyA6ICdMaW1pdCByZWFjaGVkICh7bn0gaXRlbXMgbWF4KScsXHJcbiAgICAgICAgKG51bUdyb3VwID09IDEpID8gJ0dyb3VwIGxpbWl0IHJlYWNoZWQgKHtufSBpdGVtIG1heCknIDogJ0dyb3VwIGxpbWl0IHJlYWNoZWQgKHtufSBpdGVtcyBtYXgpJ1xyXG4gICAgICBdO1xyXG4gICAgfSxcclxuICAgIHNlbGVjdEFsbFRleHQ6ICdTZWxlY3QgQWxsJyxcclxuICAgIGRlc2VsZWN0QWxsVGV4dDogJ0Rlc2VsZWN0IEFsbCcsXHJcbiAgICBzb3VyY2U6IHt9LFxyXG4gICAgY2h1bmtTaXplOiA0MCxcclxuICAgIGRvbmVCdXR0b246IGZhbHNlLFxyXG4gICAgZG9uZUJ1dHRvblRleHQ6ICdDbG9zZScsXHJcbiAgICBtdWx0aXBsZVNlcGFyYXRvcjogJywgJyxcclxuICAgIHN0eWxlQmFzZTogJ2J0bicsXHJcbiAgICBzdHlsZTogY2xhc3NOYW1lcy5CVVRUT05DTEFTUyxcclxuICAgIHNpemU6ICdhdXRvJyxcclxuICAgIHRpdGxlOiBudWxsLFxyXG4gICAgcGxhY2Vob2xkZXI6IG51bGwsXHJcbiAgICBhbGxvd0NsZWFyOiBmYWxzZSxcclxuICAgIHNlbGVjdGVkVGV4dEZvcm1hdDogJ3ZhbHVlcycsXHJcbiAgICB3aWR0aDogZmFsc2UsXHJcbiAgICBjb250YWluZXI6IGZhbHNlLFxyXG4gICAgaGlkZURpc2FibGVkOiBmYWxzZSxcclxuICAgIHNob3dTdWJ0ZXh0OiBmYWxzZSxcclxuICAgIHNob3dJY29uOiB0cnVlLFxyXG4gICAgc2hvd0NvbnRlbnQ6IHRydWUsXHJcbiAgICBkcm9wdXBBdXRvOiB0cnVlLFxyXG4gICAgaGVhZGVyOiBmYWxzZSxcclxuICAgIGxpdmVTZWFyY2g6IGZhbHNlLFxyXG4gICAgbGl2ZVNlYXJjaFBsYWNlaG9sZGVyOiBudWxsLFxyXG4gICAgbGl2ZVNlYXJjaE5vcm1hbGl6ZTogZmFsc2UsXHJcbiAgICBsaXZlU2VhcmNoU3R5bGU6ICdjb250YWlucycsXHJcbiAgICBhY3Rpb25zQm94OiBmYWxzZSxcclxuICAgIGljb25CYXNlOiBjbGFzc05hbWVzLklDT05CQVNFLFxyXG4gICAgdGlja0ljb246IGNsYXNzTmFtZXMuVElDS0lDT04sXHJcbiAgICBzaG93VGljazogZmFsc2UsXHJcbiAgICB0ZW1wbGF0ZToge1xyXG4gICAgICBjYXJldDogJzxzcGFuIGNsYXNzPVwiY2FyZXRcIj48L3NwYW4+J1xyXG4gICAgfSxcclxuICAgIG1heE9wdGlvbnM6IGZhbHNlLFxyXG4gICAgbW9iaWxlOiBmYWxzZSxcclxuICAgIHNlbGVjdE9uVGFiOiBmYWxzZSxcclxuICAgIGRyb3Bkb3duQWxpZ25SaWdodDogZmFsc2UsXHJcbiAgICB3aW5kb3dQYWRkaW5nOiAwLFxyXG4gICAgdmlydHVhbFNjcm9sbDogNjAwLFxyXG4gICAgZGlzcGxheTogZmFsc2UsXHJcbiAgICBzYW5pdGl6ZTogdHJ1ZSxcclxuICAgIHNhbml0aXplRm46IG51bGwsXHJcbiAgICB3aGl0ZUxpc3Q6IERlZmF1bHRXaGl0ZWxpc3RcclxuICB9O1xyXG5cclxuICBTZWxlY3RwaWNrZXIucHJvdG90eXBlID0ge1xyXG5cclxuICAgIGNvbnN0cnVjdG9yOiBTZWxlY3RwaWNrZXIsXHJcblxyXG4gICAgaW5pdDogZnVuY3Rpb24gKCkge1xyXG4gICAgICB2YXIgdGhhdCA9IHRoaXMsXHJcbiAgICAgICAgICBpZCA9IHRoaXMuJGVsZW1lbnQuYXR0cignaWQnKSxcclxuICAgICAgICAgIGVsZW1lbnQgPSB0aGlzLiRlbGVtZW50WzBdLFxyXG4gICAgICAgICAgZm9ybSA9IGVsZW1lbnQuZm9ybTtcclxuXHJcbiAgICAgIHNlbGVjdElkKys7XHJcbiAgICAgIHRoaXMuc2VsZWN0SWQgPSAnYnMtc2VsZWN0LScgKyBzZWxlY3RJZDtcclxuXHJcbiAgICAgIGVsZW1lbnQuY2xhc3NMaXN0LmFkZCgnYnMtc2VsZWN0LWhpZGRlbicpO1xyXG5cclxuICAgICAgdGhpcy5tdWx0aXBsZSA9IHRoaXMuJGVsZW1lbnQucHJvcCgnbXVsdGlwbGUnKTtcclxuICAgICAgdGhpcy5hdXRvZm9jdXMgPSB0aGlzLiRlbGVtZW50LnByb3AoJ2F1dG9mb2N1cycpO1xyXG5cclxuICAgICAgaWYgKGVsZW1lbnQuY2xhc3NMaXN0LmNvbnRhaW5zKCdzaG93LXRpY2snKSkge1xyXG4gICAgICAgIHRoaXMub3B0aW9ucy5zaG93VGljayA9IHRydWU7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHRoaXMuJG5ld0VsZW1lbnQgPSB0aGlzLmNyZWF0ZURyb3Bkb3duKCk7XHJcblxyXG4gICAgICB0aGlzLiRlbGVtZW50XHJcbiAgICAgICAgLmFmdGVyKHRoaXMuJG5ld0VsZW1lbnQpXHJcbiAgICAgICAgLnByZXBlbmRUbyh0aGlzLiRuZXdFbGVtZW50KTtcclxuXHJcbiAgICAgIC8vIGVuc3VyZSBzZWxlY3QgaXMgYXNzb2NpYXRlZCB3aXRoIGZvcm0gZWxlbWVudCBpZiBpdCBnb3QgdW5saW5rZWQgYWZ0ZXIgbW92aW5nIGl0IGluc2lkZSBuZXdFbGVtZW50XHJcbiAgICAgIGlmIChmb3JtICYmIGVsZW1lbnQuZm9ybSA9PT0gbnVsbCkge1xyXG4gICAgICAgIGlmICghZm9ybS5pZCkgZm9ybS5pZCA9ICdmb3JtLScgKyB0aGlzLnNlbGVjdElkO1xyXG4gICAgICAgIGVsZW1lbnQuc2V0QXR0cmlidXRlKCdmb3JtJywgZm9ybS5pZCk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHRoaXMuJGJ1dHRvbiA9IHRoaXMuJG5ld0VsZW1lbnQuY2hpbGRyZW4oJ2J1dHRvbicpO1xyXG4gICAgICBpZiAodGhpcy5vcHRpb25zLmFsbG93Q2xlYXIpIHRoaXMuJGNsZWFyQnV0dG9uID0gdGhpcy4kYnV0dG9uLmNoaWxkcmVuKCcuYnMtc2VsZWN0LWNsZWFyLXNlbGVjdGVkJyk7XHJcbiAgICAgIHRoaXMuJG1lbnUgPSB0aGlzLiRuZXdFbGVtZW50LmNoaWxkcmVuKFNlbGVjdG9yLk1FTlUpO1xyXG4gICAgICB0aGlzLiRtZW51SW5uZXIgPSB0aGlzLiRtZW51LmNoaWxkcmVuKCcuaW5uZXInKTtcclxuICAgICAgdGhpcy4kc2VhcmNoYm94ID0gdGhpcy4kbWVudS5maW5kKCdpbnB1dCcpO1xyXG5cclxuICAgICAgZWxlbWVudC5jbGFzc0xpc3QucmVtb3ZlKCdicy1zZWxlY3QtaGlkZGVuJyk7XHJcblxyXG4gICAgICB0aGlzLmZldGNoRGF0YShmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgdGhhdC5yZW5kZXIodHJ1ZSk7XHJcbiAgICAgICAgdGhhdC5idWlsZExpc3QoKTtcclxuXHJcbiAgICAgICAgcmVxdWVzdEFuaW1hdGlvbkZyYW1lKGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgIHRoYXQuJGVsZW1lbnQudHJpZ2dlcignbG9hZGVkJyArIEVWRU5UX0tFWSk7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgdGhpcy5mZXRjaERhdGEoZnVuY3Rpb24gKCkge1xyXG4gICAgICAgIHRoYXQucmVuZGVyKHRydWUpO1xyXG4gICAgICAgIHRoYXQuYnVpbGRMaXN0KCk7XHJcblxyXG4gICAgICAgIHJlcXVlc3RBbmltYXRpb25GcmFtZShmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICB0aGF0LiRlbGVtZW50LnRyaWdnZXIoJ2xvYWRlZCcgKyBFVkVOVF9LRVkpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9KTtcclxuXHJcbiAgICAgIGlmICh0aGlzLm9wdGlvbnMuZHJvcGRvd25BbGlnblJpZ2h0ID09PSB0cnVlKSB0aGlzLiRtZW51WzBdLmNsYXNzTGlzdC5hZGQoY2xhc3NOYW1lcy5NRU5VUklHSFQpO1xyXG5cclxuICAgICAgaWYgKHR5cGVvZiBpZCAhPT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgICB0aGlzLiRidXR0b24uYXR0cignZGF0YS1pZCcsIGlkKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgdGhpcy5jaGVja0Rpc2FibGVkKCk7XHJcbiAgICAgIHRoaXMuY2xpY2tMaXN0ZW5lcigpO1xyXG5cclxuICAgICAgaWYgKHZlcnNpb24ubWFqb3IgPiA0KSB0aGlzLmRyb3Bkb3duID0gbmV3IERyb3Bkb3duKHRoaXMuJGJ1dHRvblswXSk7XHJcblxyXG4gICAgICBpZiAodGhpcy5vcHRpb25zLmxpdmVTZWFyY2gpIHtcclxuICAgICAgICB0aGlzLmxpdmVTZWFyY2hMaXN0ZW5lcigpO1xyXG4gICAgICAgIHRoaXMuZm9jdXNlZFBhcmVudCA9IHRoaXMuJHNlYXJjaGJveFswXTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICB0aGlzLmZvY3VzZWRQYXJlbnQgPSB0aGlzLiRtZW51SW5uZXJbMF07XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHRoaXMuc2V0U3R5bGUoKTtcclxuICAgICAgdGhpcy5zZXRXaWR0aCgpO1xyXG4gICAgICBpZiAodGhpcy5vcHRpb25zLmNvbnRhaW5lcikge1xyXG4gICAgICAgIHRoaXMuc2VsZWN0UG9zaXRpb24oKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICB0aGlzLiRlbGVtZW50Lm9uKCdoaWRlJyArIEVWRU5UX0tFWSwgZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgaWYgKHRoYXQuaXNWaXJ0dWFsKCkpIHtcclxuICAgICAgICAgICAgLy8gZW1wdHkgbWVudSBvbiBjbG9zZVxyXG4gICAgICAgICAgICB2YXIgbWVudUlubmVyID0gdGhhdC4kbWVudUlubmVyWzBdLFxyXG4gICAgICAgICAgICAgICAgZW1wdHlNZW51ID0gbWVudUlubmVyLmZpcnN0Q2hpbGQuY2xvbmVOb2RlKGZhbHNlKTtcclxuXHJcbiAgICAgICAgICAgIC8vIHJlcGxhY2UgdGhlIGV4aXN0aW5nIFVMIHdpdGggYW4gZW1wdHkgb25lIC0gdGhpcyBpcyBmYXN0ZXIgdGhhbiAkLmVtcHR5KCkgb3IgaW5uZXJIVE1MID0gJydcclxuICAgICAgICAgICAgbWVudUlubmVyLnJlcGxhY2VDaGlsZChlbXB0eU1lbnUsIG1lbnVJbm5lci5maXJzdENoaWxkKTtcclxuICAgICAgICAgICAgbWVudUlubmVyLnNjcm9sbFRvcCA9IDA7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH1cclxuICAgICAgdGhpcy4kbWVudS5kYXRhKCd0aGlzJywgdGhpcyk7XHJcbiAgICAgIHRoaXMuJG5ld0VsZW1lbnQuZGF0YSgndGhpcycsIHRoaXMpO1xyXG4gICAgICBpZiAodGhpcy5vcHRpb25zLm1vYmlsZSkgdGhpcy5tb2JpbGUoKTtcclxuXHJcbiAgICAgIHRoaXMuJG5ld0VsZW1lbnQub24oe1xyXG4gICAgICAgICdoaWRlLmJzLmRyb3Bkb3duJzogZnVuY3Rpb24gKGUpIHtcclxuICAgICAgICAgIHRoYXQuJGVsZW1lbnQudHJpZ2dlcignaGlkZScgKyBFVkVOVF9LRVksIGUpO1xyXG4gICAgICAgIH0sXHJcbiAgICAgICAgJ2hpZGRlbi5icy5kcm9wZG93bic6IGZ1bmN0aW9uIChlKSB7XHJcbiAgICAgICAgICB0aGF0LiRlbGVtZW50LnRyaWdnZXIoJ2hpZGRlbicgKyBFVkVOVF9LRVksIGUpO1xyXG4gICAgICAgIH0sXHJcbiAgICAgICAgJ3Nob3cuYnMuZHJvcGRvd24nOiBmdW5jdGlvbiAoZSkge1xyXG4gICAgICAgICAgdGhhdC4kZWxlbWVudC50cmlnZ2VyKCdzaG93JyArIEVWRU5UX0tFWSwgZSk7XHJcbiAgICAgICAgfSxcclxuICAgICAgICAnc2hvd24uYnMuZHJvcGRvd24nOiBmdW5jdGlvbiAoZSkge1xyXG4gICAgICAgICAgdGhhdC4kZWxlbWVudC50cmlnZ2VyKCdzaG93bicgKyBFVkVOVF9LRVksIGUpO1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcblxyXG4gICAgICBpZiAoZWxlbWVudC5oYXNBdHRyaWJ1dGUoJ3JlcXVpcmVkJykpIHtcclxuICAgICAgICB0aGlzLiRlbGVtZW50Lm9uKCdpbnZhbGlkJyArIEVWRU5UX0tFWSwgZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgdGhhdC4kYnV0dG9uWzBdLmNsYXNzTGlzdC5hZGQoJ2JzLWludmFsaWQnKTtcclxuXHJcbiAgICAgICAgICB0aGF0LiRlbGVtZW50XHJcbiAgICAgICAgICAgIC5vbignc2hvd24nICsgRVZFTlRfS0VZICsgJy5pbnZhbGlkJywgZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICAgIHRoYXQuJGVsZW1lbnRcclxuICAgICAgICAgICAgICAgIC52YWwodGhhdC4kZWxlbWVudC52YWwoKSkgLy8gc2V0IHRoZSB2YWx1ZSB0byBoaWRlIHRoZSB2YWxpZGF0aW9uIG1lc3NhZ2UgaW4gQ2hyb21lIHdoZW4gbWVudSBpcyBvcGVuZWRcclxuICAgICAgICAgICAgICAgIC5vZmYoJ3Nob3duJyArIEVWRU5UX0tFWSArICcuaW52YWxpZCcpO1xyXG4gICAgICAgICAgICB9KVxyXG4gICAgICAgICAgICAub24oJ3JlbmRlcmVkJyArIEVWRU5UX0tFWSwgZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICAgIC8vIGlmIHNlbGVjdCBpcyBubyBsb25nZXIgaW52YWxpZCwgcmVtb3ZlIHRoZSBicy1pbnZhbGlkIGNsYXNzXHJcbiAgICAgICAgICAgICAgaWYgKHRoaXMudmFsaWRpdHkudmFsaWQpIHRoYXQuJGJ1dHRvblswXS5jbGFzc0xpc3QucmVtb3ZlKCdicy1pbnZhbGlkJyk7XHJcbiAgICAgICAgICAgICAgdGhhdC4kZWxlbWVudC5vZmYoJ3JlbmRlcmVkJyArIEVWRU5UX0tFWSk7XHJcbiAgICAgICAgICAgIH0pO1xyXG5cclxuICAgICAgICAgIHRoYXQuJGJ1dHRvbi5vbignYmx1cicgKyBFVkVOVF9LRVksIGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgdGhhdC4kZWxlbWVudC50cmlnZ2VyKCdmb2N1cycpLnRyaWdnZXIoJ2JsdXInKTtcclxuICAgICAgICAgICAgdGhhdC4kYnV0dG9uLm9mZignYmx1cicgKyBFVkVOVF9LRVkpO1xyXG4gICAgICAgICAgfSk7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmIChmb3JtKSB7XHJcbiAgICAgICAgJChmb3JtKS5vbigncmVzZXQnICsgRVZFTlRfS0VZLCBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICByZXF1ZXN0QW5pbWF0aW9uRnJhbWUoZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICB0aGF0LnJlbmRlcigpO1xyXG4gICAgICAgICAgfSk7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH1cclxuICAgIH0sXHJcblxyXG4gICAgY3JlYXRlRHJvcGRvd246IGZ1bmN0aW9uICgpIHtcclxuICAgICAgLy8gT3B0aW9uc1xyXG4gICAgICAvLyBJZiB3ZSBhcmUgbXVsdGlwbGUgb3Igc2hvd1RpY2sgb3B0aW9uIGlzIHNldCwgdGhlbiBhZGQgdGhlIHNob3ctdGljayBjbGFzc1xyXG4gICAgICB2YXIgc2hvd1RpY2sgPSAodGhpcy5tdWx0aXBsZSB8fCB0aGlzLm9wdGlvbnMuc2hvd1RpY2spID8gJyBzaG93LXRpY2snIDogJycsXHJcbiAgICAgICAgICBtdWx0aXNlbGVjdGFibGUgPSB0aGlzLm11bHRpcGxlID8gJyBhcmlhLW11bHRpc2VsZWN0YWJsZT1cInRydWVcIicgOiAnJyxcclxuICAgICAgICAgIGlucHV0R3JvdXAgPSAnJyxcclxuICAgICAgICAgIGF1dG9mb2N1cyA9IHRoaXMuYXV0b2ZvY3VzID8gJyBhdXRvZm9jdXMnIDogJyc7XHJcblxyXG4gICAgICBpZiAodmVyc2lvbi5tYWpvciA8IDQgJiYgdGhpcy4kZWxlbWVudC5wYXJlbnQoKS5oYXNDbGFzcygnaW5wdXQtZ3JvdXAnKSkge1xyXG4gICAgICAgIGlucHV0R3JvdXAgPSAnIGlucHV0LWdyb3VwLWJ0bic7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIEVsZW1lbnRzXHJcbiAgICAgIHZhciBkcm9wLFxyXG4gICAgICAgICAgaGVhZGVyID0gJycsXHJcbiAgICAgICAgICBzZWFyY2hib3ggPSAnJyxcclxuICAgICAgICAgIGFjdGlvbnNib3ggPSAnJyxcclxuICAgICAgICAgIGRvbmVidXR0b24gPSAnJyxcclxuICAgICAgICAgIGNsZWFyQnV0dG9uID0gJyc7XHJcblxyXG4gICAgICBpZiAodGhpcy5vcHRpb25zLmhlYWRlcikge1xyXG4gICAgICAgIGhlYWRlciA9XHJcbiAgICAgICAgICAnPGRpdiBjbGFzcz1cIicgKyBjbGFzc05hbWVzLlBPUE9WRVJIRUFERVIgKyAnXCI+JyArXHJcbiAgICAgICAgICAgICc8YnV0dG9uIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cImNsb3NlXCIgYXJpYS1oaWRkZW49XCJ0cnVlXCI+JnRpbWVzOzwvYnV0dG9uPicgK1xyXG4gICAgICAgICAgICAgIHRoaXMub3B0aW9ucy5oZWFkZXIgK1xyXG4gICAgICAgICAgJzwvZGl2Pic7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmICh0aGlzLm9wdGlvbnMubGl2ZVNlYXJjaCkge1xyXG4gICAgICAgIHNlYXJjaGJveCA9XHJcbiAgICAgICAgICAnPGRpdiBjbGFzcz1cImJzLXNlYXJjaGJveFwiPicgK1xyXG4gICAgICAgICAgICAnPGlucHV0IHR5cGU9XCJzZWFyY2hcIiBjbGFzcz1cImZvcm0tY29udHJvbFwiIGF1dG9jb21wbGV0ZT1cIm9mZlwiJyArXHJcbiAgICAgICAgICAgICAgKFxyXG4gICAgICAgICAgICAgICAgdGhpcy5vcHRpb25zLmxpdmVTZWFyY2hQbGFjZWhvbGRlciA9PT0gbnVsbCA/ICcnXHJcbiAgICAgICAgICAgICAgICA6XHJcbiAgICAgICAgICAgICAgICAnIHBsYWNlaG9sZGVyPVwiJyArIGh0bWxFc2NhcGUodGhpcy5vcHRpb25zLmxpdmVTZWFyY2hQbGFjZWhvbGRlcikgKyAnXCInXHJcbiAgICAgICAgICAgICAgKSArXHJcbiAgICAgICAgICAgICAgJyByb2xlPVwiY29tYm9ib3hcIiBhcmlhLWxhYmVsPVwiU2VhcmNoXCIgYXJpYS1jb250cm9scz1cIicgKyB0aGlzLnNlbGVjdElkICsgJ1wiIGFyaWEtYXV0b2NvbXBsZXRlPVwibGlzdFwiPicgK1xyXG4gICAgICAgICAgJzwvZGl2Pic7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmICh0aGlzLm11bHRpcGxlICYmIHRoaXMub3B0aW9ucy5hY3Rpb25zQm94KSB7XHJcbiAgICAgICAgYWN0aW9uc2JveCA9XHJcbiAgICAgICAgICAnPGRpdiBjbGFzcz1cImJzLWFjdGlvbnNib3hcIj4nICtcclxuICAgICAgICAgICAgJzxkaXYgY2xhc3M9XCJidG4tZ3JvdXAgYnRuLWdyb3VwLXNtXCI+JyArXHJcbiAgICAgICAgICAgICAgJzxidXR0b24gdHlwZT1cImJ1dHRvblwiIGNsYXNzPVwiYWN0aW9ucy1idG4gYnMtc2VsZWN0LWFsbCBidG4gJyArIGNsYXNzTmFtZXMuQlVUVE9OQ0xBU1MgKyAnXCI+JyArXHJcbiAgICAgICAgICAgICAgICB0aGlzLm9wdGlvbnMuc2VsZWN0QWxsVGV4dCArXHJcbiAgICAgICAgICAgICAgJzwvYnV0dG9uPicgK1xyXG4gICAgICAgICAgICAgICc8YnV0dG9uIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cImFjdGlvbnMtYnRuIGJzLWRlc2VsZWN0LWFsbCBidG4gJyArIGNsYXNzTmFtZXMuQlVUVE9OQ0xBU1MgKyAnXCI+JyArXHJcbiAgICAgICAgICAgICAgICB0aGlzLm9wdGlvbnMuZGVzZWxlY3RBbGxUZXh0ICtcclxuICAgICAgICAgICAgICAnPC9idXR0b24+JyArXHJcbiAgICAgICAgICAgICc8L2Rpdj4nICtcclxuICAgICAgICAgICc8L2Rpdj4nO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAodGhpcy5tdWx0aXBsZSAmJiB0aGlzLm9wdGlvbnMuZG9uZUJ1dHRvbikge1xyXG4gICAgICAgIGRvbmVidXR0b24gPVxyXG4gICAgICAgICAgJzxkaXYgY2xhc3M9XCJicy1kb25lYnV0dG9uXCI+JyArXHJcbiAgICAgICAgICAgICc8ZGl2IGNsYXNzPVwiYnRuLWdyb3VwXCI+JyArXHJcbiAgICAgICAgICAgICAgJzxidXR0b24gdHlwZT1cImJ1dHRvblwiIGNsYXNzPVwiYnRuIGJ0bi1zbSAnICsgY2xhc3NOYW1lcy5CVVRUT05DTEFTUyArICdcIj4nICtcclxuICAgICAgICAgICAgICAgIHRoaXMub3B0aW9ucy5kb25lQnV0dG9uVGV4dCArXHJcbiAgICAgICAgICAgICAgJzwvYnV0dG9uPicgK1xyXG4gICAgICAgICAgICAnPC9kaXY+JyArXHJcbiAgICAgICAgICAnPC9kaXY+JztcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKHRoaXMub3B0aW9ucy5hbGxvd0NsZWFyKSB7XHJcbiAgICAgICAgY2xlYXJCdXR0b24gPSAnPHNwYW4gY2xhc3M9XCJjbG9zZSBicy1zZWxlY3QtY2xlYXItc2VsZWN0ZWRcIiB0aXRsZT1cIicgKyB0aGlzLm9wdGlvbnMuZGVzZWxlY3RBbGxUZXh0ICsgJ1wiPjxzcGFuPiZ0aW1lczs8L3NwYW4+JztcclxuICAgICAgfVxyXG5cclxuICAgICAgZHJvcCA9XHJcbiAgICAgICAgJzxkaXYgY2xhc3M9XCJkcm9wZG93biBib290c3RyYXAtc2VsZWN0JyArIHNob3dUaWNrICsgaW5wdXRHcm91cCArICdcIj4nICtcclxuICAgICAgICAgICc8YnV0dG9uIHR5cGU9XCJidXR0b25cIiB0YWJpbmRleD1cIi0xXCIgY2xhc3M9XCInICtcclxuICAgICAgICAgICAgdGhpcy5vcHRpb25zLnN0eWxlQmFzZSArXHJcbiAgICAgICAgICAgICcgZHJvcGRvd24tdG9nZ2xlXCIgJyArXHJcbiAgICAgICAgICAgICh0aGlzLm9wdGlvbnMuZGlzcGxheSA9PT0gJ3N0YXRpYycgPyAnZGF0YS1kaXNwbGF5PVwic3RhdGljXCInIDogJycpICtcclxuICAgICAgICAgICAgU2VsZWN0b3IuREFUQV9UT0dHTEUgK1xyXG4gICAgICAgICAgICBhdXRvZm9jdXMgK1xyXG4gICAgICAgICAgICAnIHJvbGU9XCJjb21ib2JveFwiIGFyaWEtb3ducz1cIicgK1xyXG4gICAgICAgICAgICB0aGlzLnNlbGVjdElkICtcclxuICAgICAgICAgICAgJ1wiIGFyaWEtaGFzcG9wdXA9XCJsaXN0Ym94XCIgYXJpYS1leHBhbmRlZD1cImZhbHNlXCI+JyArXHJcbiAgICAgICAgICAgICc8ZGl2IGNsYXNzPVwiZmlsdGVyLW9wdGlvblwiPicgK1xyXG4gICAgICAgICAgICAgICc8ZGl2IGNsYXNzPVwiZmlsdGVyLW9wdGlvbi1pbm5lclwiPicgK1xyXG4gICAgICAgICAgICAgICAgJzxkaXYgY2xhc3M9XCJmaWx0ZXItb3B0aW9uLWlubmVyLWlubmVyXCI+Jm5ic3A7PC9kaXY+JyArXHJcbiAgICAgICAgICAgICAgJzwvZGl2PiAnICtcclxuICAgICAgICAgICAgJzwvZGl2PicgK1xyXG4gICAgICAgICAgICBjbGVhckJ1dHRvbiArXHJcbiAgICAgICAgICAgICc8L3NwYW4+JyArXHJcbiAgICAgICAgICAgIChcclxuICAgICAgICAgICAgICB2ZXJzaW9uLm1ham9yID49ICc0JyA/ICcnXHJcbiAgICAgICAgICAgICAgOlxyXG4gICAgICAgICAgICAgICc8c3BhbiBjbGFzcz1cImJzLWNhcmV0XCI+JyArXHJcbiAgICAgICAgICAgICAgICB0aGlzLm9wdGlvbnMudGVtcGxhdGUuY2FyZXQgK1xyXG4gICAgICAgICAgICAgICc8L3NwYW4+J1xyXG4gICAgICAgICAgICApICtcclxuICAgICAgICAgICc8L2J1dHRvbj4nICtcclxuICAgICAgICAgICc8ZGl2IGNsYXNzPVwiJyArIGNsYXNzTmFtZXMuTUVOVSArICcgJyArICh2ZXJzaW9uLm1ham9yID49ICc0JyA/ICcnIDogY2xhc3NOYW1lcy5TSE9XKSArICdcIj4nICtcclxuICAgICAgICAgICAgaGVhZGVyICtcclxuICAgICAgICAgICAgc2VhcmNoYm94ICtcclxuICAgICAgICAgICAgYWN0aW9uc2JveCArXHJcbiAgICAgICAgICAgICc8ZGl2IGNsYXNzPVwiaW5uZXIgJyArIGNsYXNzTmFtZXMuU0hPVyArICdcIiByb2xlPVwibGlzdGJveFwiIGlkPVwiJyArIHRoaXMuc2VsZWN0SWQgKyAnXCIgdGFiaW5kZXg9XCItMVwiICcgKyBtdWx0aXNlbGVjdGFibGUgKyAnPicgK1xyXG4gICAgICAgICAgICAgICAgJzx1bCBjbGFzcz1cIicgKyBjbGFzc05hbWVzLk1FTlUgKyAnIGlubmVyICcgKyAodmVyc2lvbi5tYWpvciA+PSAnNCcgPyBjbGFzc05hbWVzLlNIT1cgOiAnJykgKyAnXCIgcm9sZT1cInByZXNlbnRhdGlvblwiPicgK1xyXG4gICAgICAgICAgICAgICAgJzwvdWw+JyArXHJcbiAgICAgICAgICAgICc8L2Rpdj4nICtcclxuICAgICAgICAgICAgZG9uZWJ1dHRvbiArXHJcbiAgICAgICAgICAnPC9kaXY+JyArXHJcbiAgICAgICAgJzwvZGl2Pic7XHJcblxyXG4gICAgICByZXR1cm4gJChkcm9wKTtcclxuICAgIH0sXHJcblxyXG4gICAgc2V0UG9zaXRpb25EYXRhOiBmdW5jdGlvbiAoKSB7XHJcbiAgICAgIHRoaXMuc2VsZWN0cGlja2VyLnZpZXcuY2FuSGlnaGxpZ2h0ID0gW107XHJcbiAgICAgIHRoaXMuc2VsZWN0cGlja2VyLnZpZXcuc2l6ZSA9IDA7XHJcbiAgICAgIHRoaXMuc2VsZWN0cGlja2VyLnZpZXcuZmlyc3RIaWdobGlnaHRJbmRleCA9IGZhbHNlO1xyXG5cclxuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLnNlbGVjdHBpY2tlci5jdXJyZW50LmRhdGEubGVuZ3RoOyBpKyspIHtcclxuICAgICAgICB2YXIgbGkgPSB0aGlzLnNlbGVjdHBpY2tlci5jdXJyZW50LmRhdGFbaV0sXHJcbiAgICAgICAgICAgIGNhbkhpZ2hsaWdodCA9IHRydWU7XHJcblxyXG4gICAgICAgIGlmIChsaS50eXBlID09PSAnZGl2aWRlcicpIHtcclxuICAgICAgICAgIGNhbkhpZ2hsaWdodCA9IGZhbHNlO1xyXG4gICAgICAgICAgbGkuaGVpZ2h0ID0gdGhpcy5zaXplSW5mby5kaXZpZGVySGVpZ2h0O1xyXG4gICAgICAgIH0gZWxzZSBpZiAobGkudHlwZSA9PT0gJ29wdGdyb3VwLWxhYmVsJykge1xyXG4gICAgICAgICAgY2FuSGlnaGxpZ2h0ID0gZmFsc2U7XHJcbiAgICAgICAgICBsaS5oZWlnaHQgPSB0aGlzLnNpemVJbmZvLmRyb3Bkb3duSGVhZGVySGVpZ2h0O1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICBsaS5oZWlnaHQgPSB0aGlzLnNpemVJbmZvLmxpSGVpZ2h0O1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgaWYgKGxpLmRpc2FibGVkKSBjYW5IaWdobGlnaHQgPSBmYWxzZTtcclxuXHJcbiAgICAgICAgdGhpcy5zZWxlY3RwaWNrZXIudmlldy5jYW5IaWdobGlnaHQucHVzaChjYW5IaWdobGlnaHQpO1xyXG5cclxuICAgICAgICBpZiAoY2FuSGlnaGxpZ2h0KSB7XHJcbiAgICAgICAgICB0aGlzLnNlbGVjdHBpY2tlci52aWV3LnNpemUrKztcclxuICAgICAgICAgIGxpLnBvc2luc2V0ID0gdGhpcy5zZWxlY3RwaWNrZXIudmlldy5zaXplO1xyXG4gICAgICAgICAgaWYgKHRoaXMuc2VsZWN0cGlja2VyLnZpZXcuZmlyc3RIaWdobGlnaHRJbmRleCA9PT0gZmFsc2UpIHRoaXMuc2VsZWN0cGlja2VyLnZpZXcuZmlyc3RIaWdobGlnaHRJbmRleCA9IGk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBsaS5wb3NpdGlvbiA9IChpID09PSAwID8gMCA6IHRoaXMuc2VsZWN0cGlja2VyLmN1cnJlbnQuZGF0YVtpIC0gMV0ucG9zaXRpb24pICsgbGkuaGVpZ2h0O1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG5cclxuICAgIGlzVmlydHVhbDogZnVuY3Rpb24gKCkge1xyXG4gICAgICByZXR1cm4gKHRoaXMub3B0aW9ucy52aXJ0dWFsU2Nyb2xsICE9PSBmYWxzZSkgJiYgKHRoaXMuc2VsZWN0cGlja2VyLm1haW4uZGF0YS5sZW5ndGggPj0gdGhpcy5vcHRpb25zLnZpcnR1YWxTY3JvbGwpIHx8IHRoaXMub3B0aW9ucy52aXJ0dWFsU2Nyb2xsID09PSB0cnVlO1xyXG4gICAgfSxcclxuXHJcbiAgICBjcmVhdGVWaWV3OiBmdW5jdGlvbiAoaXNTZWFyY2hpbmcsIHNldFNpemUsIHJlZnJlc2gpIHtcclxuICAgICAgdmFyIHRoYXQgPSB0aGlzLFxyXG4gICAgICAgICAgc2Nyb2xsVG9wID0gMCxcclxuICAgICAgICAgIGFjdGl2ZSA9IFtdLFxyXG4gICAgICAgICAgc2VsZWN0ZWQsXHJcbiAgICAgICAgICBwcmV2QWN0aXZlO1xyXG5cclxuICAgICAgdGhpcy5zZWxlY3RwaWNrZXIuaXNTZWFyY2hpbmcgPSBpc1NlYXJjaGluZztcclxuICAgICAgdGhpcy5zZWxlY3RwaWNrZXIuY3VycmVudCA9IGlzU2VhcmNoaW5nID8gdGhpcy5zZWxlY3RwaWNrZXIuc2VhcmNoIDogdGhpcy5zZWxlY3RwaWNrZXIubWFpbjtcclxuXHJcbiAgICAgIHRoaXMuc2V0UG9zaXRpb25EYXRhKCk7XHJcblxyXG4gICAgICBpZiAoc2V0U2l6ZSkge1xyXG4gICAgICAgIGlmIChyZWZyZXNoKSB7XHJcbiAgICAgICAgICBzY3JvbGxUb3AgPSB0aGlzLiRtZW51SW5uZXJbMF0uc2Nyb2xsVG9wO1xyXG4gICAgICAgIH0gZWxzZSBpZiAoIXRoYXQubXVsdGlwbGUpIHtcclxuICAgICAgICAgIHZhciBlbGVtZW50ID0gdGhhdC4kZWxlbWVudFswXSxcclxuICAgICAgICAgICAgICBzZWxlY3RlZEluZGV4ID0gKGVsZW1lbnQub3B0aW9uc1tlbGVtZW50LnNlbGVjdGVkSW5kZXhdIHx8IHt9KS5saUluZGV4O1xyXG5cclxuICAgICAgICAgIGlmICh0eXBlb2Ygc2VsZWN0ZWRJbmRleCA9PT0gJ251bWJlcicgJiYgdGhhdC5vcHRpb25zLnNpemUgIT09IGZhbHNlKSB7XHJcbiAgICAgICAgICAgIHZhciBzZWxlY3RlZERhdGEgPSB0aGF0LnNlbGVjdHBpY2tlci5tYWluLmRhdGFbc2VsZWN0ZWRJbmRleF0sXHJcbiAgICAgICAgICAgICAgICBwb3NpdGlvbiA9IHNlbGVjdGVkRGF0YSAmJiBzZWxlY3RlZERhdGEucG9zaXRpb247XHJcblxyXG4gICAgICAgICAgICBpZiAocG9zaXRpb24pIHtcclxuICAgICAgICAgICAgICBzY3JvbGxUb3AgPSBwb3NpdGlvbiAtICgodGhhdC5zaXplSW5mby5tZW51SW5uZXJIZWlnaHQgKyB0aGF0LnNpemVJbmZvLmxpSGVpZ2h0KSAvIDIpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICBzY3JvbGwoc2Nyb2xsVG9wLCB0cnVlKTtcclxuXHJcbiAgICAgIHRoaXMuJG1lbnVJbm5lci5vZmYoJ3Njcm9sbC5jcmVhdGVWaWV3Jykub24oJ3Njcm9sbC5jcmVhdGVWaWV3JywgZnVuY3Rpb24gKGUsIHVwZGF0ZVZhbHVlKSB7XHJcbiAgICAgICAgaWYgKCF0aGF0Lm5vU2Nyb2xsKSBzY3JvbGwodGhpcy5zY3JvbGxUb3AsIHVwZGF0ZVZhbHVlKTtcclxuICAgICAgICB0aGF0Lm5vU2Nyb2xsID0gZmFsc2U7XHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgZnVuY3Rpb24gc2Nyb2xsIChzY3JvbGxUb3AsIGluaXQpIHtcclxuICAgICAgICB2YXIgc2l6ZSA9IHRoYXQuc2VsZWN0cGlja2VyLmN1cnJlbnQuZGF0YS5sZW5ndGgsXHJcbiAgICAgICAgICAgIGNodW5rcyA9IFtdLFxyXG4gICAgICAgICAgICBjaHVua1NpemUsXHJcbiAgICAgICAgICAgIGNodW5rQ291bnQsXHJcbiAgICAgICAgICAgIGZpcnN0Q2h1bmssXHJcbiAgICAgICAgICAgIGxhc3RDaHVuayxcclxuICAgICAgICAgICAgY3VycmVudENodW5rLFxyXG4gICAgICAgICAgICBwcmV2UG9zaXRpb25zLFxyXG4gICAgICAgICAgICBwb3NpdGlvbklzRGlmZmVyZW50LFxyXG4gICAgICAgICAgICBwcmV2aW91c0VsZW1lbnRzLFxyXG4gICAgICAgICAgICBtZW51SXNEaWZmZXJlbnQgPSB0cnVlLFxyXG4gICAgICAgICAgICBpc1ZpcnR1YWwgPSB0aGF0LmlzVmlydHVhbCgpO1xyXG5cclxuICAgICAgICB0aGF0LnNlbGVjdHBpY2tlci52aWV3LnNjcm9sbFRvcCA9IHNjcm9sbFRvcDtcclxuXHJcbiAgICAgICAgY2h1bmtTaXplID0gdGhhdC5vcHRpb25zLmNodW5rU2l6ZTsgLy8gbnVtYmVyIG9mIG9wdGlvbnMgaW4gYSBjaHVua1xyXG4gICAgICAgIGNodW5rQ291bnQgPSBNYXRoLmNlaWwoc2l6ZSAvIGNodW5rU2l6ZSkgfHwgMTsgLy8gbnVtYmVyIG9mIGNodW5rc1xyXG5cclxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGNodW5rQ291bnQ7IGkrKykge1xyXG4gICAgICAgICAgdmFyIGVuZE9mQ2h1bmsgPSAoaSArIDEpICogY2h1bmtTaXplO1xyXG5cclxuICAgICAgICAgIGlmIChpID09PSBjaHVua0NvdW50IC0gMSkge1xyXG4gICAgICAgICAgICBlbmRPZkNodW5rID0gc2l6ZTtcclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICBjaHVua3NbaV0gPSBbXHJcbiAgICAgICAgICAgIChpKSAqIGNodW5rU2l6ZSArICghaSA/IDAgOiAxKSxcclxuICAgICAgICAgICAgZW5kT2ZDaHVua1xyXG4gICAgICAgICAgXTtcclxuXHJcbiAgICAgICAgICBpZiAoIXNpemUpIGJyZWFrO1xyXG5cclxuICAgICAgICAgIGlmIChjdXJyZW50Q2h1bmsgPT09IHVuZGVmaW5lZCAmJiBzY3JvbGxUb3AgLSAxIDw9IHRoYXQuc2VsZWN0cGlja2VyLmN1cnJlbnQuZGF0YVtlbmRPZkNodW5rIC0gMV0ucG9zaXRpb24gLSB0aGF0LnNpemVJbmZvLm1lbnVJbm5lckhlaWdodCkge1xyXG4gICAgICAgICAgICBjdXJyZW50Q2h1bmsgPSBpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgaWYgKGN1cnJlbnRDaHVuayA9PT0gdW5kZWZpbmVkKSBjdXJyZW50Q2h1bmsgPSAwO1xyXG5cclxuICAgICAgICBwcmV2UG9zaXRpb25zID0gW3RoYXQuc2VsZWN0cGlja2VyLnZpZXcucG9zaXRpb24wLCB0aGF0LnNlbGVjdHBpY2tlci52aWV3LnBvc2l0aW9uMV07XHJcblxyXG4gICAgICAgIC8vIGFsd2F5cyBkaXNwbGF5IHByZXZpb3VzLCBjdXJyZW50LCBhbmQgbmV4dCBjaHVua3NcclxuICAgICAgICBmaXJzdENodW5rID0gTWF0aC5tYXgoMCwgY3VycmVudENodW5rIC0gMSk7XHJcbiAgICAgICAgbGFzdENodW5rID0gTWF0aC5taW4oY2h1bmtDb3VudCAtIDEsIGN1cnJlbnRDaHVuayArIDEpO1xyXG5cclxuICAgICAgICB0aGF0LnNlbGVjdHBpY2tlci52aWV3LnBvc2l0aW9uMCA9IGlzVmlydHVhbCA9PT0gZmFsc2UgPyAwIDogKE1hdGgubWF4KDAsIGNodW5rc1tmaXJzdENodW5rXVswXSkgfHwgMCk7XHJcbiAgICAgICAgdGhhdC5zZWxlY3RwaWNrZXIudmlldy5wb3NpdGlvbjEgPSBpc1ZpcnR1YWwgPT09IGZhbHNlID8gc2l6ZSA6IChNYXRoLm1pbihzaXplLCBjaHVua3NbbGFzdENodW5rXVsxXSkgfHwgMCk7XHJcblxyXG4gICAgICAgIHBvc2l0aW9uSXNEaWZmZXJlbnQgPSBwcmV2UG9zaXRpb25zWzBdICE9PSB0aGF0LnNlbGVjdHBpY2tlci52aWV3LnBvc2l0aW9uMCB8fCBwcmV2UG9zaXRpb25zWzFdICE9PSB0aGF0LnNlbGVjdHBpY2tlci52aWV3LnBvc2l0aW9uMTtcclxuXHJcbiAgICAgICAgaWYgKHRoYXQuYWN0aXZlSW5kZXggIT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgICAgcHJldkFjdGl2ZSA9ICh0aGF0LnNlbGVjdHBpY2tlci5tYWluLmRhdGFbdGhhdC5wcmV2QWN0aXZlSW5kZXhdIHx8IHt9KS5lbGVtZW50O1xyXG4gICAgICAgICAgYWN0aXZlID0gKHRoYXQuc2VsZWN0cGlja2VyLm1haW4uZGF0YVt0aGF0LmFjdGl2ZUluZGV4XSB8fCB7fSkuZWxlbWVudDtcclxuICAgICAgICAgIHNlbGVjdGVkID0gKHRoYXQuc2VsZWN0cGlja2VyLm1haW4uZGF0YVt0aGF0LnNlbGVjdGVkSW5kZXhdIHx8IHt9KS5lbGVtZW50O1xyXG5cclxuICAgICAgICAgIGlmIChpbml0KSB7XHJcbiAgICAgICAgICAgIGlmICh0aGF0LmFjdGl2ZUluZGV4ICE9PSB0aGF0LnNlbGVjdGVkSW5kZXgpIHtcclxuICAgICAgICAgICAgICB0aGF0LmRlZm9jdXNJdGVtKGFjdGl2ZSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgdGhhdC5hY3RpdmVJbmRleCA9IHVuZGVmaW5lZDtcclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICBpZiAodGhhdC5hY3RpdmVJbmRleCAmJiB0aGF0LmFjdGl2ZUluZGV4ICE9PSB0aGF0LnNlbGVjdGVkSW5kZXgpIHtcclxuICAgICAgICAgICAgdGhhdC5kZWZvY3VzSXRlbShzZWxlY3RlZCk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBpZiAodGhhdC5wcmV2QWN0aXZlSW5kZXggIT09IHVuZGVmaW5lZCAmJiB0aGF0LnByZXZBY3RpdmVJbmRleCAhPT0gdGhhdC5hY3RpdmVJbmRleCAmJiB0aGF0LnByZXZBY3RpdmVJbmRleCAhPT0gdGhhdC5zZWxlY3RlZEluZGV4KSB7XHJcbiAgICAgICAgICB0aGF0LmRlZm9jdXNJdGVtKHByZXZBY3RpdmUpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgaWYgKGluaXQgfHwgcG9zaXRpb25Jc0RpZmZlcmVudCkge1xyXG4gICAgICAgICAgcHJldmlvdXNFbGVtZW50cyA9IHRoYXQuc2VsZWN0cGlja2VyLnZpZXcudmlzaWJsZUVsZW1lbnRzID8gdGhhdC5zZWxlY3RwaWNrZXIudmlldy52aXNpYmxlRWxlbWVudHMuc2xpY2UoKSA6IFtdO1xyXG5cclxuICAgICAgICAgIGlmIChpc1ZpcnR1YWwgPT09IGZhbHNlKSB7XHJcbiAgICAgICAgICAgIHRoYXQuc2VsZWN0cGlja2VyLnZpZXcudmlzaWJsZUVsZW1lbnRzID0gdGhhdC5zZWxlY3RwaWNrZXIuY3VycmVudC5lbGVtZW50cztcclxuICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIHRoYXQuc2VsZWN0cGlja2VyLnZpZXcudmlzaWJsZUVsZW1lbnRzID0gdGhhdC5zZWxlY3RwaWNrZXIuY3VycmVudC5lbGVtZW50cy5zbGljZSh0aGF0LnNlbGVjdHBpY2tlci52aWV3LnBvc2l0aW9uMCwgdGhhdC5zZWxlY3RwaWNrZXIudmlldy5wb3NpdGlvbjEpO1xyXG4gICAgICAgICAgfVxyXG5cclxuICAgICAgICAgIHRoYXQuc2V0T3B0aW9uU3RhdHVzKCk7XHJcblxyXG4gICAgICAgICAgLy8gaWYgc2VhcmNoaW5nLCBjaGVjayB0byBtYWtlIHN1cmUgdGhlIGxpc3QgaGFzIGFjdHVhbGx5IGJlZW4gdXBkYXRlZCBiZWZvcmUgdXBkYXRpbmcgRE9NXHJcbiAgICAgICAgICAvLyB0aGlzIHByZXZlbnRzIHVubmVjZXNzYXJ5IHJlcGFpbnRzXHJcbiAgICAgICAgICBpZiAoaXNTZWFyY2hpbmcgfHwgKGlzVmlydHVhbCA9PT0gZmFsc2UgJiYgaW5pdCkpIG1lbnVJc0RpZmZlcmVudCA9ICFpc0VxdWFsKHByZXZpb3VzRWxlbWVudHMsIHRoYXQuc2VsZWN0cGlja2VyLnZpZXcudmlzaWJsZUVsZW1lbnRzKTtcclxuXHJcbiAgICAgICAgICAvLyBpZiB2aXJ0dWFsIHNjcm9sbCBpcyBkaXNhYmxlZCBhbmQgbm90IHNlYXJjaGluZyxcclxuICAgICAgICAgIC8vIG1lbnUgc2hvdWxkIG5ldmVyIG5lZWQgdG8gYmUgdXBkYXRlZCBtb3JlIHRoYW4gb25jZVxyXG4gICAgICAgICAgaWYgKChpbml0IHx8IGlzVmlydHVhbCA9PT0gdHJ1ZSkgJiYgbWVudUlzRGlmZmVyZW50KSB7XHJcbiAgICAgICAgICAgIHZhciBtZW51SW5uZXIgPSB0aGF0LiRtZW51SW5uZXJbMF0sXHJcbiAgICAgICAgICAgICAgICBtZW51RnJhZ21lbnQgPSBkb2N1bWVudC5jcmVhdGVEb2N1bWVudEZyYWdtZW50KCksXHJcbiAgICAgICAgICAgICAgICBlbXB0eU1lbnUgPSBtZW51SW5uZXIuZmlyc3RDaGlsZC5jbG9uZU5vZGUoZmFsc2UpLFxyXG4gICAgICAgICAgICAgICAgbWFyZ2luVG9wLFxyXG4gICAgICAgICAgICAgICAgbWFyZ2luQm90dG9tLFxyXG4gICAgICAgICAgICAgICAgZWxlbWVudHMgPSB0aGF0LnNlbGVjdHBpY2tlci52aWV3LnZpc2libGVFbGVtZW50cyxcclxuICAgICAgICAgICAgICAgIHRvU2FuaXRpemUgPSBbXTtcclxuXHJcbiAgICAgICAgICAgIC8vIHJlcGxhY2UgdGhlIGV4aXN0aW5nIFVMIHdpdGggYW4gZW1wdHkgb25lIC0gdGhpcyBpcyBmYXN0ZXIgdGhhbiAkLmVtcHR5KClcclxuICAgICAgICAgICAgbWVudUlubmVyLnJlcGxhY2VDaGlsZChlbXB0eU1lbnUsIG1lbnVJbm5lci5maXJzdENoaWxkKTtcclxuXHJcbiAgICAgICAgICAgIGZvciAodmFyIGkgPSAwLCB2aXNpYmxlRWxlbWVudHNMZW4gPSBlbGVtZW50cy5sZW5ndGg7IGkgPCB2aXNpYmxlRWxlbWVudHNMZW47IGkrKykge1xyXG4gICAgICAgICAgICAgIHZhciBlbGVtZW50ID0gZWxlbWVudHNbaV0sXHJcbiAgICAgICAgICAgICAgICAgIGVsVGV4dCxcclxuICAgICAgICAgICAgICAgICAgZWxlbWVudERhdGE7XHJcblxyXG4gICAgICAgICAgICAgIGlmICh0aGF0Lm9wdGlvbnMuc2FuaXRpemUpIHtcclxuICAgICAgICAgICAgICAgIGVsVGV4dCA9IGVsZW1lbnQubGFzdENoaWxkO1xyXG5cclxuICAgICAgICAgICAgICAgIGlmIChlbFRleHQpIHtcclxuICAgICAgICAgICAgICAgICAgZWxlbWVudERhdGEgPSB0aGF0LnNlbGVjdHBpY2tlci5jdXJyZW50LmRhdGFbaSArIHRoYXQuc2VsZWN0cGlja2VyLnZpZXcucG9zaXRpb24wXTtcclxuXHJcbiAgICAgICAgICAgICAgICAgIGlmIChlbGVtZW50RGF0YSAmJiBlbGVtZW50RGF0YS5jb250ZW50ICYmICFlbGVtZW50RGF0YS5zYW5pdGl6ZWQpIHtcclxuICAgICAgICAgICAgICAgICAgICB0b1Nhbml0aXplLnB1c2goZWxUZXh0KTtcclxuICAgICAgICAgICAgICAgICAgICBlbGVtZW50RGF0YS5zYW5pdGl6ZWQgPSB0cnVlO1xyXG4gICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICBtZW51RnJhZ21lbnQuYXBwZW5kQ2hpbGQoZWxlbWVudCk7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIGlmICh0aGF0Lm9wdGlvbnMuc2FuaXRpemUgJiYgdG9TYW5pdGl6ZS5sZW5ndGgpIHtcclxuICAgICAgICAgICAgICBzYW5pdGl6ZUh0bWwodG9TYW5pdGl6ZSwgdGhhdC5vcHRpb25zLndoaXRlTGlzdCwgdGhhdC5vcHRpb25zLnNhbml0aXplRm4pO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICBpZiAoaXNWaXJ0dWFsID09PSB0cnVlKSB7XHJcbiAgICAgICAgICAgICAgbWFyZ2luVG9wID0gKHRoYXQuc2VsZWN0cGlja2VyLnZpZXcucG9zaXRpb24wID09PSAwID8gMCA6IHRoYXQuc2VsZWN0cGlja2VyLmN1cnJlbnQuZGF0YVt0aGF0LnNlbGVjdHBpY2tlci52aWV3LnBvc2l0aW9uMCAtIDFdLnBvc2l0aW9uKTtcclxuICAgICAgICAgICAgICBtYXJnaW5Cb3R0b20gPSAodGhhdC5zZWxlY3RwaWNrZXIudmlldy5wb3NpdGlvbjEgPiBzaXplIC0gMSA/IDAgOiB0aGF0LnNlbGVjdHBpY2tlci5jdXJyZW50LmRhdGFbc2l6ZSAtIDFdLnBvc2l0aW9uIC0gdGhhdC5zZWxlY3RwaWNrZXIuY3VycmVudC5kYXRhW3RoYXQuc2VsZWN0cGlja2VyLnZpZXcucG9zaXRpb24xIC0gMV0ucG9zaXRpb24pO1xyXG5cclxuICAgICAgICAgICAgICBtZW51SW5uZXIuZmlyc3RDaGlsZC5zdHlsZS5tYXJnaW5Ub3AgPSBtYXJnaW5Ub3AgKyAncHgnO1xyXG4gICAgICAgICAgICAgIG1lbnVJbm5lci5maXJzdENoaWxkLnN0eWxlLm1hcmdpbkJvdHRvbSA9IG1hcmdpbkJvdHRvbSArICdweCc7XHJcbiAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgbWVudUlubmVyLmZpcnN0Q2hpbGQuc3R5bGUubWFyZ2luVG9wID0gMDtcclxuICAgICAgICAgICAgICBtZW51SW5uZXIuZmlyc3RDaGlsZC5zdHlsZS5tYXJnaW5Cb3R0b20gPSAwO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICBtZW51SW5uZXIuZmlyc3RDaGlsZC5hcHBlbmRDaGlsZChtZW51RnJhZ21lbnQpO1xyXG5cclxuICAgICAgICAgICAgLy8gaWYgYW4gb3B0aW9uIGlzIGVuY291bnRlcmVkIHRoYXQgaXMgd2lkZXIgdGhhbiB0aGUgY3VycmVudCBtZW51IHdpZHRoLCB1cGRhdGUgdGhlIG1lbnUgd2lkdGggYWNjb3JkaW5nbHlcclxuICAgICAgICAgICAgLy8gc3dpdGNoIHRvIFJlc2l6ZU9ic2VydmVyIHdpdGggaW5jcmVhc2VkIGJyb3dzZXIgc3VwcG9ydFxyXG4gICAgICAgICAgICBpZiAoaXNWaXJ0dWFsID09PSB0cnVlICYmIHRoYXQuc2l6ZUluZm8uaGFzU2Nyb2xsQmFyKSB7XHJcbiAgICAgICAgICAgICAgdmFyIG1lbnVJbm5lcklubmVyV2lkdGggPSBtZW51SW5uZXIuZmlyc3RDaGlsZC5vZmZzZXRXaWR0aDtcclxuXHJcbiAgICAgICAgICAgICAgaWYgKGluaXQgJiYgbWVudUlubmVySW5uZXJXaWR0aCA8IHRoYXQuc2l6ZUluZm8ubWVudUlubmVySW5uZXJXaWR0aCAmJiB0aGF0LnNpemVJbmZvLnRvdGFsTWVudVdpZHRoID4gdGhhdC5zaXplSW5mby5zZWxlY3RXaWR0aCkge1xyXG4gICAgICAgICAgICAgICAgbWVudUlubmVyLmZpcnN0Q2hpbGQuc3R5bGUubWluV2lkdGggPSB0aGF0LnNpemVJbmZvLm1lbnVJbm5lcklubmVyV2lkdGggKyAncHgnO1xyXG4gICAgICAgICAgICAgIH0gZWxzZSBpZiAobWVudUlubmVySW5uZXJXaWR0aCA+IHRoYXQuc2l6ZUluZm8ubWVudUlubmVySW5uZXJXaWR0aCkge1xyXG4gICAgICAgICAgICAgICAgLy8gc2V0IHRvIDAgdG8gZ2V0IGFjdHVhbCB3aWR0aCBvZiBtZW51XHJcbiAgICAgICAgICAgICAgICB0aGF0LiRtZW51WzBdLnN0eWxlLm1pbldpZHRoID0gMDtcclxuXHJcbiAgICAgICAgICAgICAgICB2YXIgYWN0dWFsTWVudVdpZHRoID0gbWVudUlubmVyLmZpcnN0Q2hpbGQub2Zmc2V0V2lkdGg7XHJcblxyXG4gICAgICAgICAgICAgICAgaWYgKGFjdHVhbE1lbnVXaWR0aCA+IHRoYXQuc2l6ZUluZm8ubWVudUlubmVySW5uZXJXaWR0aCkge1xyXG4gICAgICAgICAgICAgICAgICB0aGF0LnNpemVJbmZvLm1lbnVJbm5lcklubmVyV2lkdGggPSBhY3R1YWxNZW51V2lkdGg7XHJcbiAgICAgICAgICAgICAgICAgIG1lbnVJbm5lci5maXJzdENoaWxkLnN0eWxlLm1pbldpZHRoID0gdGhhdC5zaXplSW5mby5tZW51SW5uZXJJbm5lcldpZHRoICsgJ3B4JztcclxuICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICAvLyByZXNldCB0byBkZWZhdWx0IENTUyBzdHlsaW5nXHJcbiAgICAgICAgICAgICAgICB0aGF0LiRtZW51WzBdLnN0eWxlLm1pbldpZHRoID0gJyc7XHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgaWYgKCghaXNTZWFyY2hpbmcgJiYgdGhhdC5vcHRpb25zLnNvdXJjZS5sb2FkIHx8IGlzU2VhcmNoaW5nICYmIHRoYXQub3B0aW9ucy5zb3VyY2Uuc2VhcmNoKSAmJiBjdXJyZW50Q2h1bmsgPT09IGNodW5rQ291bnQgLSAxKSB7XHJcbiAgICAgICAgICAgIHRoYXQuZmV0Y2hEYXRhKGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgICB0aGF0LnJlbmRlcigpO1xyXG4gICAgICAgICAgICAgIHRoYXQuYnVpbGRMaXN0KHNpemUsIGlzU2VhcmNoaW5nKTtcclxuICAgICAgICAgICAgICB0aGF0LnNldFBvc2l0aW9uRGF0YSgpO1xyXG4gICAgICAgICAgICAgIHNjcm9sbChzY3JvbGxUb3ApO1xyXG4gICAgICAgICAgICB9LCBpc1NlYXJjaGluZyA/ICdzZWFyY2gnIDogJ2xvYWQnLCBjdXJyZW50Q2h1bmsgKyAxLCBpc1NlYXJjaGluZyA/IHRoYXQuc2VsZWN0cGlja2VyLnNlYXJjaC5wcmV2aW91c1ZhbHVlIDogdW5kZWZpbmVkKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHRoYXQucHJldkFjdGl2ZUluZGV4ID0gdGhhdC5hY3RpdmVJbmRleDtcclxuXHJcbiAgICAgICAgaWYgKCF0aGF0Lm9wdGlvbnMubGl2ZVNlYXJjaCkge1xyXG4gICAgICAgICAgdGhhdC4kbWVudUlubmVyLnRyaWdnZXIoJ2ZvY3VzJyk7XHJcbiAgICAgICAgfSBlbHNlIGlmIChpc1NlYXJjaGluZyAmJiBpbml0KSB7XHJcbiAgICAgICAgICB2YXIgaW5kZXggPSAwLFxyXG4gICAgICAgICAgICAgIG5ld0FjdGl2ZTtcclxuXHJcbiAgICAgICAgICBpZiAoIXRoYXQuc2VsZWN0cGlja2VyLnZpZXcuY2FuSGlnaGxpZ2h0W2luZGV4XSkge1xyXG4gICAgICAgICAgICBpbmRleCA9IDEgKyB0aGF0LnNlbGVjdHBpY2tlci52aWV3LmNhbkhpZ2hsaWdodC5zbGljZSgxKS5pbmRleE9mKHRydWUpO1xyXG4gICAgICAgICAgfVxyXG5cclxuICAgICAgICAgIG5ld0FjdGl2ZSA9IHRoYXQuc2VsZWN0cGlja2VyLnZpZXcudmlzaWJsZUVsZW1lbnRzW2luZGV4XTtcclxuXHJcbiAgICAgICAgICB0aGF0LmRlZm9jdXNJdGVtKHRoYXQuc2VsZWN0cGlja2VyLnZpZXcuY3VycmVudEFjdGl2ZSk7XHJcblxyXG4gICAgICAgICAgdGhhdC5hY3RpdmVJbmRleCA9ICh0aGF0LnNlbGVjdHBpY2tlci5jdXJyZW50LmRhdGFbaW5kZXhdIHx8IHt9KS5pbmRleDtcclxuXHJcbiAgICAgICAgICB0aGF0LmZvY3VzSXRlbShuZXdBY3RpdmUpO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgJCh3aW5kb3cpXHJcbiAgICAgICAgLm9mZigncmVzaXplJyArIEVWRU5UX0tFWSArICcuJyArIHRoaXMuc2VsZWN0SWQgKyAnLmNyZWF0ZVZpZXcnKVxyXG4gICAgICAgIC5vbigncmVzaXplJyArIEVWRU5UX0tFWSArICcuJyArIHRoaXMuc2VsZWN0SWQgKyAnLmNyZWF0ZVZpZXcnLCBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICB2YXIgaXNBY3RpdmUgPSB0aGF0LiRuZXdFbGVtZW50Lmhhc0NsYXNzKGNsYXNzTmFtZXMuU0hPVyk7XHJcblxyXG4gICAgICAgICAgaWYgKGlzQWN0aXZlKSBzY3JvbGwodGhhdC4kbWVudUlubmVyWzBdLnNjcm9sbFRvcCk7XHJcbiAgICAgICAgfSk7XHJcbiAgICB9LFxyXG5cclxuICAgIGZvY3VzSXRlbTogZnVuY3Rpb24gKGxpLCBsaURhdGEsIG5vU3R5bGUpIHtcclxuICAgICAgaWYgKGxpKSB7XHJcbiAgICAgICAgbGlEYXRhID0gbGlEYXRhIHx8IHRoaXMuc2VsZWN0cGlja2VyLm1haW4uZGF0YVt0aGlzLmFjdGl2ZUluZGV4XTtcclxuICAgICAgICB2YXIgYSA9IGxpLmZpcnN0Q2hpbGQ7XHJcblxyXG4gICAgICAgIGlmIChhKSB7XHJcbiAgICAgICAgICBhLnNldEF0dHJpYnV0ZSgnYXJpYS1zZXRzaXplJywgdGhpcy5zZWxlY3RwaWNrZXIudmlldy5zaXplKTtcclxuICAgICAgICAgIGEuc2V0QXR0cmlidXRlKCdhcmlhLXBvc2luc2V0JywgbGlEYXRhLnBvc2luc2V0KTtcclxuXHJcbiAgICAgICAgICBpZiAobm9TdHlsZSAhPT0gdHJ1ZSkge1xyXG4gICAgICAgICAgICB0aGlzLmZvY3VzZWRQYXJlbnQuc2V0QXR0cmlidXRlKCdhcmlhLWFjdGl2ZWRlc2NlbmRhbnQnLCBhLmlkKTtcclxuICAgICAgICAgICAgbGkuY2xhc3NMaXN0LmFkZCgnYWN0aXZlJyk7XHJcbiAgICAgICAgICAgIGEuY2xhc3NMaXN0LmFkZCgnYWN0aXZlJyk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9LFxyXG5cclxuICAgIGRlZm9jdXNJdGVtOiBmdW5jdGlvbiAobGkpIHtcclxuICAgICAgaWYgKGxpKSB7XHJcbiAgICAgICAgbGkuY2xhc3NMaXN0LnJlbW92ZSgnYWN0aXZlJyk7XHJcbiAgICAgICAgaWYgKGxpLmZpcnN0Q2hpbGQpIGxpLmZpcnN0Q2hpbGQuY2xhc3NMaXN0LnJlbW92ZSgnYWN0aXZlJyk7XHJcbiAgICAgIH1cclxuICAgIH0sXHJcblxyXG4gICAgc2V0UGxhY2Vob2xkZXI6IGZ1bmN0aW9uICgpIHtcclxuICAgICAgdmFyIHRoYXQgPSB0aGlzLFxyXG4gICAgICAgICAgdXBkYXRlSW5kZXggPSBmYWxzZTtcclxuXHJcbiAgICAgIGlmICgodGhpcy5vcHRpb25zLnBsYWNlaG9sZGVyIHx8IHRoaXMub3B0aW9ucy5hbGxvd0NsZWFyKSAmJiAhdGhpcy5tdWx0aXBsZSkge1xyXG4gICAgICAgIGlmICghdGhpcy5zZWxlY3RwaWNrZXIudmlldy50aXRsZU9wdGlvbikgdGhpcy5zZWxlY3RwaWNrZXIudmlldy50aXRsZU9wdGlvbiA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ29wdGlvbicpO1xyXG5cclxuICAgICAgICAvLyB0aGlzIG9wdGlvbiBkb2Vzbid0IGNyZWF0ZSBhIG5ldyA8bGk+IGVsZW1lbnQsIGJ1dCBkb2VzIGFkZCBhIG5ldyBvcHRpb24gYXQgdGhlIHN0YXJ0LFxyXG4gICAgICAgIC8vIHNvIHN0YXJ0SW5kZXggc2hvdWxkIGluY3JlYXNlIHRvIHByZXZlbnQgaGF2aW5nIHRvIGNoZWNrIGV2ZXJ5IG9wdGlvbiBmb3IgdGhlIGJzLXRpdGxlLW9wdGlvbiBjbGFzc1xyXG4gICAgICAgIHVwZGF0ZUluZGV4ID0gdHJ1ZTtcclxuXHJcbiAgICAgICAgdmFyIGVsZW1lbnQgPSB0aGlzLiRlbGVtZW50WzBdLFxyXG4gICAgICAgICAgICBzZWxlY3RUaXRsZU9wdGlvbiA9IGZhbHNlLFxyXG4gICAgICAgICAgICB0aXRsZU5vdEFwcGVuZGVkID0gIXRoaXMuc2VsZWN0cGlja2VyLnZpZXcudGl0bGVPcHRpb24ucGFyZW50Tm9kZSxcclxuICAgICAgICAgICAgc2VsZWN0ZWRJbmRleCA9IGVsZW1lbnQuc2VsZWN0ZWRJbmRleCxcclxuICAgICAgICAgICAgc2VsZWN0ZWRPcHRpb24gPSBlbGVtZW50Lm9wdGlvbnNbc2VsZWN0ZWRJbmRleF0sXHJcbiAgICAgICAgICAgIGZpcnN0U2VsZWN0YWJsZSA9IGVsZW1lbnQucXVlcnlTZWxlY3Rvcignc2VsZWN0ID4gKjpub3QoOmRpc2FibGVkKScpLFxyXG4gICAgICAgICAgICBmaXJzdFNlbGVjdGFibGVJbmRleCA9IGZpcnN0U2VsZWN0YWJsZSA/IGZpcnN0U2VsZWN0YWJsZS5pbmRleCA6IDAsXHJcbiAgICAgICAgICAgIG5hdmlnYXRpb24gPSB3aW5kb3cucGVyZm9ybWFuY2UgJiYgd2luZG93LnBlcmZvcm1hbmNlLmdldEVudHJpZXNCeVR5cGUoJ25hdmlnYXRpb24nKSxcclxuICAgICAgICAgICAgLy8gU2FmYXJpIGRvZXNuJ3Qgc3VwcG9ydCBnZXRFbnRyaWVzQnlUeXBlKCduYXZpZ2F0aW9uJykgLSBmYWxsIGJhY2sgdG8gcGVyZm9ybWFuY2UubmF2aWdhdGlvblxyXG4gICAgICAgICAgICBpc05vdEJhY2tGb3J3YXJkID0gKG5hdmlnYXRpb24gJiYgbmF2aWdhdGlvbi5sZW5ndGgpID8gbmF2aWdhdGlvblswXS50eXBlICE9PSAnYmFja19mb3J3YXJkJyA6IHdpbmRvdy5wZXJmb3JtYW5jZS5uYXZpZ2F0aW9uLnR5cGUgIT09IDI7XHJcblxyXG4gICAgICAgIGlmICh0aXRsZU5vdEFwcGVuZGVkKSB7XHJcbiAgICAgICAgICAvLyBVc2UgbmF0aXZlIEpTIHRvIHByZXBlbmQgb3B0aW9uIChmYXN0ZXIpXHJcbiAgICAgICAgICB0aGlzLnNlbGVjdHBpY2tlci52aWV3LnRpdGxlT3B0aW9uLmNsYXNzTmFtZSA9ICdicy10aXRsZS1vcHRpb24nO1xyXG4gICAgICAgICAgdGhpcy5zZWxlY3RwaWNrZXIudmlldy50aXRsZU9wdGlvbi52YWx1ZSA9ICcnO1xyXG5cclxuICAgICAgICAgIC8vIENoZWNrIGlmIHNlbGVjdGVkIG9yIGRhdGEtc2VsZWN0ZWQgYXR0cmlidXRlIGlzIGFscmVhZHkgc2V0IG9uIGFuIG9wdGlvbi4gSWYgbm90LCBzZWxlY3QgdGhlIHRpdGxlT3B0aW9uIG9wdGlvbi5cclxuICAgICAgICAgIC8vIHRoZSBzZWxlY3RlZCBpdGVtIG1heSBoYXZlIGJlZW4gY2hhbmdlZCBieSB1c2VyIG9yIHByb2dyYW1tYXRpY2FsbHkgYmVmb3JlIHRoZSBib290c3RyYXAgc2VsZWN0IHBsdWdpbiBydW5zLFxyXG4gICAgICAgICAgLy8gaWYgc28sIHRoZSBzZWxlY3Qgd2lsbCBoYXZlIHRoZSBkYXRhLXNlbGVjdGVkIGF0dHJpYnV0ZVxyXG4gICAgICAgICAgc2VsZWN0VGl0bGVPcHRpb24gPSAhc2VsZWN0ZWRPcHRpb24gfHwgKHNlbGVjdGVkSW5kZXggPT09IGZpcnN0U2VsZWN0YWJsZUluZGV4ICYmIHNlbGVjdGVkT3B0aW9uLmRlZmF1bHRTZWxlY3RlZCA9PT0gZmFsc2UgJiYgdGhpcy4kZWxlbWVudC5kYXRhKCdzZWxlY3RlZCcpID09PSB1bmRlZmluZWQpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgaWYgKHRpdGxlTm90QXBwZW5kZWQgfHwgdGhpcy5zZWxlY3RwaWNrZXIudmlldy50aXRsZU9wdGlvbi5pbmRleCAhPT0gMCkge1xyXG4gICAgICAgICAgZWxlbWVudC5pbnNlcnRCZWZvcmUodGhpcy5zZWxlY3RwaWNrZXIudmlldy50aXRsZU9wdGlvbiwgZWxlbWVudC5maXJzdENoaWxkKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIFNldCBzZWxlY3RlZCAqYWZ0ZXIqIGFwcGVuZGluZyB0byBzZWxlY3QsXHJcbiAgICAgICAgLy8gb3RoZXJ3aXNlIHRoZSBvcHRpb24gZG9lc24ndCBnZXQgc2VsZWN0ZWQgaW4gSUVcclxuICAgICAgICAvLyBzZXQgdXNpbmcgc2VsZWN0ZWRJbmRleCwgYXMgc2V0dGluZyB0aGUgc2VsZWN0ZWQgYXR0ciB0byB0cnVlIGhlcmUgZG9lc24ndCB3b3JrIGluIElFMTFcclxuICAgICAgICBpZiAoc2VsZWN0VGl0bGVPcHRpb24gJiYgaXNOb3RCYWNrRm9yd2FyZCkge1xyXG4gICAgICAgICAgZWxlbWVudC5zZWxlY3RlZEluZGV4ID0gMDtcclxuICAgICAgICB9IGVsc2UgaWYgKGRvY3VtZW50LnJlYWR5U3RhdGUgIT09ICdjb21wbGV0ZScpIHtcclxuICAgICAgICAgIC8vIGlmIG5hdmlnYXRpb24gdHlwZSBpcyBiYWNrX2ZvcndhcmQsIHRoZXJlJ3MgYSBjaGFuY2UgdGhlIHNlbGVjdCB3aWxsIGhhdmUgaXRzIHZhbHVlIHNldCBieSBCRkNhY2hlXHJcbiAgICAgICAgICAvLyB3YWl0IGZvciB0aGF0IHZhbHVlIHRvIGJlIHNldCwgdGhlbiBydW4gcmVuZGVyIGFnYWluXHJcbiAgICAgICAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcigncGFnZXNob3cnLCBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgIGlmICh0aGF0LnNlbGVjdHBpY2tlci52aWV3LmRpc3BsYXllZFZhbHVlICE9PSBlbGVtZW50LnZhbHVlKSB0aGF0LnJlbmRlcigpO1xyXG4gICAgICAgICAgfSk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICByZXR1cm4gdXBkYXRlSW5kZXg7XHJcbiAgICB9LFxyXG5cclxuICAgIGZldGNoRGF0YTogZnVuY3Rpb24gKGNhbGxiYWNrLCB0eXBlLCBwYWdlLCBzZWFyY2hWYWx1ZSkge1xyXG4gICAgICB0eXBlID0gdHlwZSB8fCAnZGF0YSc7XHJcblxyXG4gICAgICB2YXIgdGhhdCA9IHRoaXMsXHJcbiAgICAgICAgICBkYXRhID0gdGhpcy5vcHRpb25zLnNvdXJjZVt0eXBlXSxcclxuICAgICAgICAgIGJ1aWx0RGF0YTtcclxuXHJcbiAgICAgIGlmIChkYXRhKSB7XHJcbiAgICAgICAgdGhpcy5vcHRpb25zLnZpcnR1YWxTY3JvbGwgPSB0cnVlO1xyXG5cclxuICAgICAgICBpZiAodHlwZW9mIGRhdGEgPT09ICdmdW5jdGlvbicpIHtcclxuICAgICAgICAgIGRhdGEuY2FsbChcclxuICAgICAgICAgICAgdGhpcyxcclxuICAgICAgICAgICAgZnVuY3Rpb24gKGRhdGEpIHtcclxuICAgICAgICAgICAgICBidWlsdERhdGEgPSB0aGF0LmJ1aWxkRGF0YShkYXRhLCB0eXBlKTtcclxuICAgICAgICAgICAgICBjYWxsYmFjay5jYWxsKHRoYXQsIGJ1aWx0RGF0YSk7XHJcbiAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgIHBhZ2UsXHJcbiAgICAgICAgICAgIHNlYXJjaFZhbHVlXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH0gZWxzZSBpZiAoQXJyYXkuaXNBcnJheShkYXRhKSkge1xyXG4gICAgICAgICAgYnVpbHREYXRhID0gdGhhdC5idWlsZERhdGEoZGF0YSwgdHlwZSk7XHJcbiAgICAgICAgICBjYWxsYmFjay5jYWxsKHRoYXQsIGJ1aWx0RGF0YSk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIGJ1aWx0RGF0YSA9IHRoaXMuYnVpbGREYXRhKGZhbHNlLCB0eXBlKTtcclxuICAgICAgICBjYWxsYmFjay5jYWxsKHRoYXQsIGJ1aWx0RGF0YSk7XHJcbiAgICAgIH1cclxuICAgIH0sXHJcblxyXG4gICAgYnVpbGREYXRhOiBmdW5jdGlvbiAoZGF0YSwgdHlwZSkge1xyXG4gICAgICB2YXIgZGF0YUdldHRlciA9IGRhdGEgPT09IGZhbHNlID8gZ2V0T3B0aW9uRGF0YS5mcm9tT3B0aW9uIDogZ2V0T3B0aW9uRGF0YS5mcm9tRGF0YVNvdXJjZTtcclxuXHJcbiAgICAgIHZhciBvcHRpb25TZWxlY3RvciA9ICc6bm90KFtoaWRkZW5dKTpub3QoW2RhdGEtaGlkZGVuPVwidHJ1ZVwiXSknLFxyXG4gICAgICAgICAgbWFpbkRhdGEgPSBbXSxcclxuICAgICAgICAgIHN0YXJ0TGVuID0gMCxcclxuICAgICAgICAgIG9wdElEID0gMCxcclxuICAgICAgICAgIHN0YXJ0SW5kZXggPSB0aGlzLnNldFBsYWNlaG9sZGVyKCkgJiYgIWRhdGEgPyAxIDogMDsgLy8gYXBwZW5kIHRoZSB0aXRsZU9wdGlvbiBpZiBuZWNlc3NhcnkgYW5kIHNraXAgdGhlIGZpcnN0IG9wdGlvbiBpbiB0aGUgbG9vcFxyXG5cclxuICAgICAgaWYgKHR5cGUgPT09ICdsb2FkJykge1xyXG4gICAgICAgIHN0YXJ0TGVuID0gdGhpcy5zZWxlY3RwaWNrZXIubWFpbi5kYXRhLmxlbmd0aDtcclxuICAgICAgfSBlbHNlIGlmICh0eXBlID09PSAnc2VhcmNoJykge1xyXG4gICAgICAgIHN0YXJ0TGVuID0gdGhpcy5zZWxlY3RwaWNrZXIuc2VhcmNoLmRhdGEubGVuZ3RoO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAodGhpcy5vcHRpb25zLmhpZGVEaXNhYmxlZCkgb3B0aW9uU2VsZWN0b3IgKz0gJzpub3QoOmRpc2FibGVkKSc7XHJcblxyXG4gICAgICB2YXIgc2VsZWN0T3B0aW9ucyA9IGRhdGEgPyBkYXRhLmZpbHRlcihmaWx0ZXJIaWRkZW4sIHRoaXMpIDogdGhpcy4kZWxlbWVudFswXS5xdWVyeVNlbGVjdG9yQWxsKCdzZWxlY3QgPiAqJyArIG9wdGlvblNlbGVjdG9yKTtcclxuXHJcbiAgICAgIGZ1bmN0aW9uIGFkZERpdmlkZXIgKGNvbmZpZykge1xyXG4gICAgICAgIHZhciBwcmV2aW91c0RhdGEgPSBtYWluRGF0YVttYWluRGF0YS5sZW5ndGggLSAxXTtcclxuXHJcbiAgICAgICAgLy8gZW5zdXJlIG9wdGdyb3VwIGRvZXNuJ3QgY3JlYXRlIGJhY2stdG8tYmFjayBkaXZpZGVyc1xyXG4gICAgICAgIGlmIChcclxuICAgICAgICAgIHByZXZpb3VzRGF0YSAmJlxyXG4gICAgICAgICAgcHJldmlvdXNEYXRhLnR5cGUgPT09ICdkaXZpZGVyJyAmJlxyXG4gICAgICAgICAgKHByZXZpb3VzRGF0YS5vcHRJRCB8fCBjb25maWcub3B0SUQpXHJcbiAgICAgICAgKSB7XHJcbiAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBjb25maWcgPSBjb25maWcgfHwge307XHJcbiAgICAgICAgY29uZmlnLnR5cGUgPSAnZGl2aWRlcic7XHJcblxyXG4gICAgICAgIG1haW5EYXRhLnB1c2goY29uZmlnKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgZnVuY3Rpb24gYWRkT3B0aW9uIChpdGVtLCBjb25maWcpIHtcclxuICAgICAgICBjb25maWcgPSBjb25maWcgfHwge307XHJcblxyXG4gICAgICAgIGNvbmZpZy5kaXZpZGVyID0gZGF0YUdldHRlcihpdGVtLCAnZGl2aWRlcicpO1xyXG5cclxuICAgICAgICBpZiAoY29uZmlnLmRpdmlkZXIgPT09IHRydWUpIHtcclxuICAgICAgICAgIGFkZERpdmlkZXIoe1xyXG4gICAgICAgICAgICBvcHRJRDogY29uZmlnLm9wdElEXHJcbiAgICAgICAgICB9KTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgdmFyIGxpSW5kZXggPSBtYWluRGF0YS5sZW5ndGggKyBzdGFydExlbixcclxuICAgICAgICAgICAgICBjc3NUZXh0ID0gZGF0YUdldHRlcihpdGVtLCAnc3R5bGUnKSxcclxuICAgICAgICAgICAgICBpbmxpbmVTdHlsZSA9IGNzc1RleHQgPyBodG1sRXNjYXBlKGNzc1RleHQpIDogJycsXHJcbiAgICAgICAgICAgICAgb3B0aW9uQ2xhc3MgPSAoaXRlbS5jbGFzc05hbWUgfHwgJycpICsgKGNvbmZpZy5vcHRncm91cENsYXNzIHx8ICcnKTtcclxuXHJcbiAgICAgICAgICBpZiAoY29uZmlnLm9wdElEKSBvcHRpb25DbGFzcyA9ICdvcHQgJyArIG9wdGlvbkNsYXNzO1xyXG5cclxuICAgICAgICAgIGNvbmZpZy5vcHRpb25DbGFzcyA9IG9wdGlvbkNsYXNzLnRyaW0oKTtcclxuICAgICAgICAgIGNvbmZpZy5pbmxpbmVTdHlsZSA9IGlubGluZVN0eWxlO1xyXG5cclxuICAgICAgICAgIGNvbmZpZy50ZXh0ID0gZGF0YUdldHRlcihpdGVtLCAndGV4dCcpO1xyXG4gICAgICAgICAgY29uZmlnLmNvbnRlbnQgPSBkYXRhR2V0dGVyKGl0ZW0sICdjb250ZW50Jyk7XHJcbiAgICAgICAgICBjb25maWcudG9rZW5zID0gZGF0YUdldHRlcihpdGVtLCAndG9rZW5zJyk7XHJcbiAgICAgICAgICBjb25maWcuc3VidGV4dCA9IGRhdGFHZXR0ZXIoaXRlbSwgJ3N1YnRleHQnKTtcclxuICAgICAgICAgIGNvbmZpZy5pY29uID0gZGF0YUdldHRlcihpdGVtLCAnaWNvbicpO1xyXG5cclxuICAgICAgICAgIGNvbmZpZy5kaXNwbGF5ID0gY29uZmlnLmNvbnRlbnQgfHwgY29uZmlnLnRleHQ7XHJcbiAgICAgICAgICBjb25maWcudmFsdWUgPSBpdGVtLnZhbHVlID09PSB1bmRlZmluZWQgPyBpdGVtLnRleHQgOiBpdGVtLnZhbHVlO1xyXG4gICAgICAgICAgY29uZmlnLnR5cGUgPSAnb3B0aW9uJztcclxuICAgICAgICAgIGNvbmZpZy5pbmRleCA9IGxpSW5kZXg7XHJcblxyXG4gICAgICAgICAgY29uZmlnLm9wdGlvbiA9ICFpdGVtLm9wdGlvbiA/IGl0ZW0gOiBpdGVtLm9wdGlvbjsgLy8gcmVmZXJlbmNlIG9wdGlvbiBlbGVtZW50IGlmIGl0IGV4aXN0c1xyXG4gICAgICAgICAgY29uZmlnLm9wdGlvbi5saUluZGV4ID0gbGlJbmRleDtcclxuICAgICAgICAgIGNvbmZpZy5zZWxlY3RlZCA9ICEhaXRlbS5zZWxlY3RlZDtcclxuICAgICAgICAgIGNvbmZpZy5kaXNhYmxlZCA9IGNvbmZpZy5kaXNhYmxlZCB8fCAhIWl0ZW0uZGlzYWJsZWQ7XHJcblxyXG4gICAgICAgICAgbWFpbkRhdGEucHVzaChjb25maWcpO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgZnVuY3Rpb24gYWRkT3B0Z3JvdXAgKGluZGV4LCBzZWxlY3RPcHRpb25zKSB7XHJcbiAgICAgICAgdmFyIG9wdGdyb3VwID0gc2VsZWN0T3B0aW9uc1tpbmRleF0sXHJcbiAgICAgICAgICAgIC8vIHNraXAgcGxhY2Vob2xkZXIgb3B0aW9uXHJcbiAgICAgICAgICAgIHByZXZpb3VzID0gaW5kZXggLSAxIDwgc3RhcnRJbmRleCA/IGZhbHNlIDogc2VsZWN0T3B0aW9uc1tpbmRleCAtIDFdLFxyXG4gICAgICAgICAgICBuZXh0ID0gc2VsZWN0T3B0aW9uc1tpbmRleCArIDFdLFxyXG4gICAgICAgICAgICBvcHRpb25zID0gZGF0YSA/IG9wdGdyb3VwLmNoaWxkcmVuLmZpbHRlcihmaWx0ZXJIaWRkZW4sIHRoaXMpIDogb3B0Z3JvdXAucXVlcnlTZWxlY3RvckFsbCgnb3B0aW9uJyArIG9wdGlvblNlbGVjdG9yKTtcclxuXHJcbiAgICAgICAgaWYgKCFvcHRpb25zLmxlbmd0aCkgcmV0dXJuO1xyXG5cclxuICAgICAgICB2YXIgY29uZmlnID0ge1xyXG4gICAgICAgICAgICAgIGRpc3BsYXk6IGh0bWxFc2NhcGUoZGF0YUdldHRlcihpdGVtLCAnbGFiZWwnKSksXHJcbiAgICAgICAgICAgICAgc3VidGV4dDogZGF0YUdldHRlcihvcHRncm91cCwgJ3N1YnRleHQnKSxcclxuICAgICAgICAgICAgICBpY29uOiBkYXRhR2V0dGVyKG9wdGdyb3VwLCAnaWNvbicpLFxyXG4gICAgICAgICAgICAgIHR5cGU6ICdvcHRncm91cC1sYWJlbCcsXHJcbiAgICAgICAgICAgICAgb3B0Z3JvdXBDbGFzczogJyAnICsgKG9wdGdyb3VwLmNsYXNzTmFtZSB8fCAnJylcclxuICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgaGVhZGVySW5kZXgsXHJcbiAgICAgICAgICAgIGxhc3RJbmRleDtcclxuXHJcbiAgICAgICAgb3B0SUQrKztcclxuXHJcbiAgICAgICAgaWYgKHByZXZpb3VzKSB7XHJcbiAgICAgICAgICBhZGREaXZpZGVyKHsgb3B0SUQ6IG9wdElEIH0pO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgY29uZmlnLm9wdElEID0gb3B0SUQ7XHJcblxyXG4gICAgICAgIG1haW5EYXRhLnB1c2goY29uZmlnKTtcclxuXHJcbiAgICAgICAgZm9yICh2YXIgaiA9IDAsIGxlbiA9IG9wdGlvbnMubGVuZ3RoOyBqIDwgbGVuOyBqKyspIHtcclxuICAgICAgICAgIHZhciBvcHRpb24gPSBvcHRpb25zW2pdO1xyXG5cclxuICAgICAgICAgIGlmIChqID09PSAwKSB7XHJcbiAgICAgICAgICAgIGhlYWRlckluZGV4ID0gbWFpbkRhdGEubGVuZ3RoIC0gMTtcclxuICAgICAgICAgICAgbGFzdEluZGV4ID0gaGVhZGVySW5kZXggKyBsZW47XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgYWRkT3B0aW9uKG9wdGlvbiwge1xyXG4gICAgICAgICAgICBoZWFkZXJJbmRleDogaGVhZGVySW5kZXgsXHJcbiAgICAgICAgICAgIGxhc3RJbmRleDogbGFzdEluZGV4LFxyXG4gICAgICAgICAgICBvcHRJRDogY29uZmlnLm9wdElELFxyXG4gICAgICAgICAgICBvcHRncm91cENsYXNzOiBjb25maWcub3B0Z3JvdXBDbGFzcyxcclxuICAgICAgICAgICAgZGlzYWJsZWQ6IG9wdGdyb3VwLmRpc2FibGVkXHJcbiAgICAgICAgICB9KTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGlmIChuZXh0KSB7XHJcbiAgICAgICAgICBhZGREaXZpZGVyKHsgb3B0SUQ6IG9wdElEIH0pO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgZm9yICh2YXIgbGVuID0gc2VsZWN0T3B0aW9ucy5sZW5ndGgsIGkgPSBzdGFydEluZGV4OyBpIDwgbGVuOyBpKyspIHtcclxuICAgICAgICB2YXIgaXRlbSA9IHNlbGVjdE9wdGlvbnNbaV0sXHJcbiAgICAgICAgICAgIGNoaWxkcmVuID0gaXRlbS5jaGlsZHJlbjtcclxuXHJcbiAgICAgICAgaWYgKGNoaWxkcmVuICYmIGNoaWxkcmVuLmxlbmd0aCkge1xyXG4gICAgICAgICAgYWRkT3B0Z3JvdXAuY2FsbCh0aGlzLCBzdGFydEluZGV4LCBzZWxlY3RPcHRpb25zKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgYWRkT3B0aW9uLmNhbGwodGhpcywgaXRlbSwge30pO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgc3dpdGNoICh0eXBlKSB7XHJcbiAgICAgICAgY2FzZSAnZGF0YSc6IHtcclxuICAgICAgICAgIHRoaXMuc2VsZWN0cGlja2VyLm1haW4uZGF0YSA9IHRoaXMuc2VsZWN0cGlja2VyLmN1cnJlbnQuZGF0YSA9IG1haW5EYXRhO1xyXG4gICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGNhc2UgJ2xvYWQnOiB7XHJcbiAgICAgICAgICBBcnJheS5wcm90b3R5cGUucHVzaC5hcHBseSh0aGlzLnNlbGVjdHBpY2tlci5tYWluLmRhdGEsIG1haW5EYXRhKTtcclxuICAgICAgICAgIHRoaXMuc2VsZWN0cGlja2VyLmN1cnJlbnQuZGF0YSA9IHRoaXMuc2VsZWN0cGlja2VyLm1haW4uZGF0YTtcclxuICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgIH1cclxuICAgICAgICBjYXNlICdzZWFyY2gnOiB7XHJcbiAgICAgICAgICBBcnJheS5wcm90b3R5cGUucHVzaC5hcHBseSh0aGlzLnNlbGVjdHBpY2tlci5zZWFyY2guZGF0YSwgbWFpbkRhdGEpO1xyXG4gICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICByZXR1cm4gbWFpbkRhdGE7XHJcbiAgICB9LFxyXG5cclxuICAgIGJ1aWxkTGlzdDogZnVuY3Rpb24gKHNpemUsIHNlYXJjaGluZykge1xyXG4gICAgICB2YXIgdGhhdCA9IHRoaXMsXHJcbiAgICAgICAgICBzZWxlY3REYXRhID0gc2VhcmNoaW5nID8gdGhpcy5zZWxlY3RwaWNrZXIuc2VhcmNoLmRhdGEgOiB0aGlzLnNlbGVjdHBpY2tlci5tYWluLmRhdGEsXHJcbiAgICAgICAgICBtYWluRWxlbWVudHMgPSBbXSxcclxuICAgICAgICAgIHdpZGVzdE9wdGlvbkxlbmd0aCA9IDA7XHJcblxyXG4gICAgICBpZiAoKHRoYXQub3B0aW9ucy5zaG93VGljayB8fCB0aGF0Lm11bHRpcGxlKSAmJiAhZWxlbWVudFRlbXBsYXRlcy5jaGVja01hcmsucGFyZW50Tm9kZSkge1xyXG4gICAgICAgIGVsZW1lbnRUZW1wbGF0ZXMuY2hlY2tNYXJrLmNsYXNzTmFtZSA9IHRoaXMub3B0aW9ucy5pY29uQmFzZSArICcgJyArIHRoYXQub3B0aW9ucy50aWNrSWNvbiArICcgY2hlY2stbWFyayc7XHJcbiAgICAgICAgZWxlbWVudFRlbXBsYXRlcy5hLmFwcGVuZENoaWxkKGVsZW1lbnRUZW1wbGF0ZXMuY2hlY2tNYXJrKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgZnVuY3Rpb24gYnVpbGRFbGVtZW50IChtYWluRWxlbWVudHMsIGl0ZW0pIHtcclxuICAgICAgICB2YXIgbGlFbGVtZW50LFxyXG4gICAgICAgICAgICBjb21iaW5lZExlbmd0aCA9IDA7XHJcblxyXG4gICAgICAgIHN3aXRjaCAoaXRlbS50eXBlKSB7XHJcbiAgICAgICAgICBjYXNlICdkaXZpZGVyJzpcclxuICAgICAgICAgICAgbGlFbGVtZW50ID0gZ2VuZXJhdGVPcHRpb24ubGkoXHJcbiAgICAgICAgICAgICAgZmFsc2UsXHJcbiAgICAgICAgICAgICAgY2xhc3NOYW1lcy5ESVZJREVSLFxyXG4gICAgICAgICAgICAgIChpdGVtLm9wdElEID8gaXRlbS5vcHRJRCArICdkaXYnIDogdW5kZWZpbmVkKVxyXG4gICAgICAgICAgICApO1xyXG5cclxuICAgICAgICAgICAgYnJlYWs7XHJcblxyXG4gICAgICAgICAgY2FzZSAnb3B0aW9uJzpcclxuICAgICAgICAgICAgbGlFbGVtZW50ID0gZ2VuZXJhdGVPcHRpb24ubGkoXHJcbiAgICAgICAgICAgICAgZ2VuZXJhdGVPcHRpb24uYShcclxuICAgICAgICAgICAgICAgIGdlbmVyYXRlT3B0aW9uLnRleHQuY2FsbCh0aGF0LCBpdGVtKSxcclxuICAgICAgICAgICAgICAgIGl0ZW0ub3B0aW9uQ2xhc3MsXHJcbiAgICAgICAgICAgICAgICBpdGVtLmlubGluZVN0eWxlXHJcbiAgICAgICAgICAgICAgKSxcclxuICAgICAgICAgICAgICAnJyxcclxuICAgICAgICAgICAgICBpdGVtLm9wdElEXHJcbiAgICAgICAgICAgICk7XHJcblxyXG4gICAgICAgICAgICBpZiAobGlFbGVtZW50LmZpcnN0Q2hpbGQpIHtcclxuICAgICAgICAgICAgICBsaUVsZW1lbnQuZmlyc3RDaGlsZC5pZCA9IHRoYXQuc2VsZWN0SWQgKyAnLScgKyBpdGVtLmluZGV4O1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICBicmVhaztcclxuXHJcbiAgICAgICAgICBjYXNlICdvcHRncm91cC1sYWJlbCc6XHJcbiAgICAgICAgICAgIGxpRWxlbWVudCA9IGdlbmVyYXRlT3B0aW9uLmxpKFxyXG4gICAgICAgICAgICAgIGdlbmVyYXRlT3B0aW9uLmxhYmVsLmNhbGwodGhhdCwgaXRlbSksXHJcbiAgICAgICAgICAgICAgJ2Ryb3Bkb3duLWhlYWRlcicgKyBpdGVtLm9wdGdyb3VwQ2xhc3MsXHJcbiAgICAgICAgICAgICAgaXRlbS5vcHRJRFxyXG4gICAgICAgICAgICApO1xyXG5cclxuICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBpdGVtLmVsZW1lbnQgPSBsaUVsZW1lbnQ7XHJcbiAgICAgICAgbWFpbkVsZW1lbnRzLnB1c2gobGlFbGVtZW50KTtcclxuXHJcbiAgICAgICAgLy8gY291bnQgdGhlIG51bWJlciBvZiBjaGFyYWN0ZXJzIGluIHRoZSBvcHRpb24gLSBub3QgcGVyZmVjdCwgYnV0IHNob3VsZCB3b3JrIGluIG1vc3QgY2FzZXNcclxuICAgICAgICBpZiAoaXRlbS5kaXNwbGF5KSBjb21iaW5lZExlbmd0aCArPSBpdGVtLmRpc3BsYXkubGVuZ3RoO1xyXG4gICAgICAgIGlmIChpdGVtLnN1YnRleHQpIGNvbWJpbmVkTGVuZ3RoICs9IGl0ZW0uc3VidGV4dC5sZW5ndGg7XHJcbiAgICAgICAgLy8gaWYgdGhlcmUgaXMgYW4gaWNvbiwgZW5zdXJlIHRoaXMgb3B0aW9uJ3Mgd2lkdGggaXMgY2hlY2tlZFxyXG4gICAgICAgIGlmIChpdGVtLmljb24pIGNvbWJpbmVkTGVuZ3RoICs9IDE7XHJcblxyXG4gICAgICAgIGlmIChjb21iaW5lZExlbmd0aCA+IHdpZGVzdE9wdGlvbkxlbmd0aCkge1xyXG4gICAgICAgICAgd2lkZXN0T3B0aW9uTGVuZ3RoID0gY29tYmluZWRMZW5ndGg7XHJcblxyXG4gICAgICAgICAgLy8gZ3Vlc3Mgd2hpY2ggb3B0aW9uIGlzIHRoZSB3aWRlc3RcclxuICAgICAgICAgIC8vIHVzZSB0aGlzIHdoZW4gY2FsY3VsYXRpbmcgbWVudSB3aWR0aFxyXG4gICAgICAgICAgLy8gbm90IHBlcmZlY3QsIGJ1dCBpdCdzIGZhc3QsIGFuZCB0aGUgd2lkdGggd2lsbCBiZSB1cGRhdGluZyBhY2NvcmRpbmdseSB3aGVuIHNjcm9sbGluZ1xyXG4gICAgICAgICAgdGhhdC5zZWxlY3RwaWNrZXIudmlldy53aWRlc3RPcHRpb24gPSBtYWluRWxlbWVudHNbbWFpbkVsZW1lbnRzLmxlbmd0aCAtIDFdO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgdmFyIHN0YXJ0SW5kZXggPSBzaXplIHx8IDA7XHJcblxyXG4gICAgICBmb3IgKHZhciBsZW4gPSBzZWxlY3REYXRhLmxlbmd0aCwgaSA9IHN0YXJ0SW5kZXg7IGkgPCBsZW47IGkrKykge1xyXG4gICAgICAgIHZhciBpdGVtID0gc2VsZWN0RGF0YVtpXTtcclxuXHJcbiAgICAgICAgYnVpbGRFbGVtZW50KG1haW5FbGVtZW50cywgaXRlbSk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmIChzaXplKSB7XHJcbiAgICAgICAgaWYgKHNlYXJjaGluZykge1xyXG4gICAgICAgICAgQXJyYXkucHJvdG90eXBlLnB1c2guYXBwbHkodGhpcy5zZWxlY3RwaWNrZXIuc2VhcmNoLmVsZW1lbnRzLCBtYWluRWxlbWVudHMpO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICBBcnJheS5wcm90b3R5cGUucHVzaC5hcHBseSh0aGlzLnNlbGVjdHBpY2tlci5tYWluLmVsZW1lbnRzLCBtYWluRWxlbWVudHMpO1xyXG4gICAgICAgICAgdGhpcy5zZWxlY3RwaWNrZXIuY3VycmVudC5lbGVtZW50cyA9IHRoaXMuc2VsZWN0cGlja2VyLm1haW4uZWxlbWVudHM7XHJcbiAgICAgICAgfVxyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIGlmIChzZWFyY2hpbmcpIHtcclxuICAgICAgICAgIHRoaXMuc2VsZWN0cGlja2VyLnNlYXJjaC5lbGVtZW50cyA9IG1haW5FbGVtZW50cztcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgdGhpcy5zZWxlY3RwaWNrZXIubWFpbi5lbGVtZW50cyA9IHRoaXMuc2VsZWN0cGlja2VyLmN1cnJlbnQuZWxlbWVudHMgPSBtYWluRWxlbWVudHM7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9LFxyXG5cclxuICAgIGZpbmRMaXM6IGZ1bmN0aW9uICgpIHtcclxuICAgICAgcmV0dXJuIHRoaXMuJG1lbnVJbm5lci5maW5kKCcuaW5uZXIgPiBsaScpO1xyXG4gICAgfSxcclxuXHJcbiAgICByZW5kZXI6IGZ1bmN0aW9uIChpbml0KSB7XHJcbiAgICAgIHZhciB0aGF0ID0gdGhpcyxcclxuICAgICAgICAgIGVsZW1lbnQgPSB0aGlzLiRlbGVtZW50WzBdLFxyXG4gICAgICAgICAgLy8gZW5zdXJlIHRpdGxlT3B0aW9uIGlzIGFwcGVuZGVkIGFuZCBzZWxlY3RlZCAoaWYgbmVjZXNzYXJ5KSBiZWZvcmUgZ2V0dGluZyBzZWxlY3RlZE9wdGlvbnNcclxuICAgICAgICAgIHBsYWNlaG9sZGVyU2VsZWN0ZWQgPSB0aGlzLnNldFBsYWNlaG9sZGVyKCkgJiYgZWxlbWVudC5zZWxlY3RlZEluZGV4ID09PSAwLFxyXG4gICAgICAgICAgc2VsZWN0ZWRPcHRpb25zID0gZ2V0U2VsZWN0ZWRPcHRpb25zLmNhbGwodGhpcyksXHJcbiAgICAgICAgICBzZWxlY3RlZENvdW50ID0gc2VsZWN0ZWRPcHRpb25zLmxlbmd0aCxcclxuICAgICAgICAgIHNlbGVjdGVkVmFsdWVzID0gZ2V0U2VsZWN0VmFsdWVzLmNhbGwodGhpcywgc2VsZWN0ZWRPcHRpb25zKSxcclxuICAgICAgICAgIGJ1dHRvbiA9IHRoaXMuJGJ1dHRvblswXSxcclxuICAgICAgICAgIGJ1dHRvbklubmVyID0gYnV0dG9uLnF1ZXJ5U2VsZWN0b3IoJy5maWx0ZXItb3B0aW9uLWlubmVyLWlubmVyJyksXHJcbiAgICAgICAgICBtdWx0aXBsZVNlcGFyYXRvciA9IGRvY3VtZW50LmNyZWF0ZVRleHROb2RlKHRoaXMub3B0aW9ucy5tdWx0aXBsZVNlcGFyYXRvciksXHJcbiAgICAgICAgICB0aXRsZUZyYWdtZW50ID0gZWxlbWVudFRlbXBsYXRlcy5mcmFnbWVudC5jbG9uZU5vZGUoZmFsc2UpLFxyXG4gICAgICAgICAgc2hvd0NvdW50LFxyXG4gICAgICAgICAgY291bnRNYXgsXHJcbiAgICAgICAgICBoYXNDb250ZW50ID0gZmFsc2U7XHJcblxyXG4gICAgICBmdW5jdGlvbiBjcmVhdGVTZWxlY3RlZCAoaXRlbSkge1xyXG4gICAgICAgIGlmIChpdGVtLnNlbGVjdGVkKSB7XHJcbiAgICAgICAgICB0aGF0LmNyZWF0ZU9wdGlvbihpdGVtLCB0cnVlKTtcclxuICAgICAgICB9IGVsc2UgaWYgKGl0ZW0uY2hpbGRyZW4gJiYgaXRlbS5jaGlsZHJlbi5sZW5ndGgpIHtcclxuICAgICAgICAgIGl0ZW0uY2hpbGRyZW4ubWFwKGNyZWF0ZVNlbGVjdGVkKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIGNyZWF0ZSBzZWxlY3RlZCBvcHRpb24gZWxlbWVudHMgdG8gZW5zdXJlIHNlbGVjdCB2YWx1ZSBpcyBjb3JyZWN0XHJcbiAgICAgIGlmICh0aGlzLm9wdGlvbnMuc291cmNlLmRhdGEgJiYgaW5pdCkge1xyXG4gICAgICAgIHNlbGVjdGVkT3B0aW9ucy5tYXAoY3JlYXRlU2VsZWN0ZWQpO1xyXG4gICAgICAgIGVsZW1lbnQuYXBwZW5kQ2hpbGQodGhpcy5zZWxlY3RwaWNrZXIubWFpbi5vcHRpb25RdWV1ZSk7XHJcblxyXG4gICAgICAgIGlmIChwbGFjZWhvbGRlclNlbGVjdGVkKSBwbGFjZWhvbGRlclNlbGVjdGVkID0gZWxlbWVudC5zZWxlY3RlZEluZGV4ID09PSAwO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBidXR0b24uY2xhc3NMaXN0LnRvZ2dsZSgnYnMtcGxhY2Vob2xkZXInLCB0aGF0Lm11bHRpcGxlID8gIXNlbGVjdGVkQ291bnQgOiAhc2VsZWN0ZWRWYWx1ZXMgJiYgc2VsZWN0ZWRWYWx1ZXMgIT09IDApO1xyXG5cclxuICAgICAgaWYgKCF0aGF0Lm11bHRpcGxlICYmIHNlbGVjdGVkT3B0aW9ucy5sZW5ndGggPT09IDEpIHtcclxuICAgICAgICB0aGF0LnNlbGVjdHBpY2tlci52aWV3LmRpc3BsYXllZFZhbHVlID0gc2VsZWN0ZWRWYWx1ZXM7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmICh0aGlzLm9wdGlvbnMuc2VsZWN0ZWRUZXh0Rm9ybWF0ID09PSAnc3RhdGljJykge1xyXG4gICAgICAgIHRpdGxlRnJhZ21lbnQgPSBnZW5lcmF0ZU9wdGlvbi50ZXh0LmNhbGwodGhpcywgeyB0ZXh0OiB0aGlzLm9wdGlvbnMucGxhY2Vob2xkZXIgfSwgdHJ1ZSk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgc2hvd0NvdW50ID0gdGhpcy5tdWx0aXBsZSAmJiB0aGlzLm9wdGlvbnMuc2VsZWN0ZWRUZXh0Rm9ybWF0LmluZGV4T2YoJ2NvdW50JykgIT09IC0xICYmIHNlbGVjdGVkQ291bnQgPiAxO1xyXG5cclxuICAgICAgICAvLyBkZXRlcm1pbmUgaWYgdGhlIG51bWJlciBvZiBzZWxlY3RlZCBvcHRpb25zIHdpbGwgYmUgc2hvd24gKHNob3dDb3VudCA9PT0gdHJ1ZSlcclxuICAgICAgICBpZiAoc2hvd0NvdW50KSB7XHJcbiAgICAgICAgICBjb3VudE1heCA9IHRoaXMub3B0aW9ucy5zZWxlY3RlZFRleHRGb3JtYXQuc3BsaXQoJz4nKTtcclxuICAgICAgICAgIHNob3dDb3VudCA9IChjb3VudE1heC5sZW5ndGggPiAxICYmIHNlbGVjdGVkQ291bnQgPiBjb3VudE1heFsxXSkgfHwgKGNvdW50TWF4Lmxlbmd0aCA9PT0gMSAmJiBzZWxlY3RlZENvdW50ID49IDIpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gb25seSBsb29wIHRocm91Z2ggYWxsIHNlbGVjdGVkIG9wdGlvbnMgaWYgdGhlIGNvdW50IHdvbid0IGJlIHNob3duXHJcbiAgICAgICAgaWYgKHNob3dDb3VudCA9PT0gZmFsc2UpIHtcclxuICAgICAgICAgIGlmICghcGxhY2Vob2xkZXJTZWxlY3RlZCkge1xyXG4gICAgICAgICAgICBmb3IgKHZhciBzZWxlY3RlZEluZGV4ID0gMDsgc2VsZWN0ZWRJbmRleCA8IHNlbGVjdGVkQ291bnQ7IHNlbGVjdGVkSW5kZXgrKykge1xyXG4gICAgICAgICAgICAgIGlmIChzZWxlY3RlZEluZGV4IDwgNTApIHtcclxuICAgICAgICAgICAgICAgIHZhciBvcHRpb24gPSBzZWxlY3RlZE9wdGlvbnNbc2VsZWN0ZWRJbmRleF0sXHJcbiAgICAgICAgICAgICAgICAgICAgdGl0bGVPcHRpb25zID0ge307XHJcblxyXG4gICAgICAgICAgICAgICAgaWYgKG9wdGlvbikge1xyXG4gICAgICAgICAgICAgICAgICBpZiAodGhpcy5tdWx0aXBsZSAmJiBzZWxlY3RlZEluZGV4ID4gMCkge1xyXG4gICAgICAgICAgICAgICAgICAgIHRpdGxlRnJhZ21lbnQuYXBwZW5kQ2hpbGQobXVsdGlwbGVTZXBhcmF0b3IuY2xvbmVOb2RlKGZhbHNlKSk7XHJcbiAgICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICAgIGlmIChvcHRpb24udGl0bGUpIHtcclxuICAgICAgICAgICAgICAgICAgICB0aXRsZU9wdGlvbnMudGV4dCA9IG9wdGlvbi50aXRsZTtcclxuICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmIChvcHRpb24uY29udGVudCAmJiB0aGF0Lm9wdGlvbnMuc2hvd0NvbnRlbnQpIHtcclxuICAgICAgICAgICAgICAgICAgICB0aXRsZU9wdGlvbnMuY29udGVudCA9IG9wdGlvbi5jb250ZW50LnRvU3RyaW5nKCk7XHJcbiAgICAgICAgICAgICAgICAgICAgaGFzQ29udGVudCA9IHRydWU7XHJcbiAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKHRoYXQub3B0aW9ucy5zaG93SWNvbikge1xyXG4gICAgICAgICAgICAgICAgICAgICAgdGl0bGVPcHRpb25zLmljb24gPSBvcHRpb24uaWNvbjtcclxuICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKHRoYXQub3B0aW9ucy5zaG93U3VidGV4dCAmJiAhdGhhdC5tdWx0aXBsZSAmJiBvcHRpb24uc3VidGV4dCkgdGl0bGVPcHRpb25zLnN1YnRleHQgPSAnICcgKyBvcHRpb24uc3VidGV4dDtcclxuICAgICAgICAgICAgICAgICAgICB0aXRsZU9wdGlvbnMudGV4dCA9IG9wdGlvbi50ZXh0LnRyaW0oKTtcclxuICAgICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgICAgdGl0bGVGcmFnbWVudC5hcHBlbmRDaGlsZChnZW5lcmF0ZU9wdGlvbi50ZXh0LmNhbGwodGhpcywgdGl0bGVPcHRpb25zLCB0cnVlKSk7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLy8gYWRkIGVsbGlwc2lzXHJcbiAgICAgICAgICAgIGlmIChzZWxlY3RlZENvdW50ID4gNDkpIHtcclxuICAgICAgICAgICAgICB0aXRsZUZyYWdtZW50LmFwcGVuZENoaWxkKGRvY3VtZW50LmNyZWF0ZVRleHROb2RlKCcuLi4nKSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH1cclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgdmFyIG9wdGlvblNlbGVjdG9yID0gJzpub3QoW2hpZGRlbl0pOm5vdChbZGF0YS1oaWRkZW49XCJ0cnVlXCJdKTpub3QoW2RhdGEtZGl2aWRlcj1cInRydWVcIl0pJztcclxuICAgICAgICAgIGlmICh0aGlzLm9wdGlvbnMuaGlkZURpc2FibGVkKSBvcHRpb25TZWxlY3RvciArPSAnOm5vdCg6ZGlzYWJsZWQpJztcclxuXHJcbiAgICAgICAgICAvLyBJZiB0aGlzIGlzIGEgbXVsdGlzZWxlY3QsIGFuZCBzZWxlY3RlZFRleHRGb3JtYXQgaXMgY291bnQsIHRoZW4gc2hvdyAxIG9mIDIgc2VsZWN0ZWQsIGV0Yy5cclxuICAgICAgICAgIHZhciB0b3RhbENvdW50ID0gdGhpcy4kZWxlbWVudFswXS5xdWVyeVNlbGVjdG9yQWxsKCdzZWxlY3QgPiBvcHRpb24nICsgb3B0aW9uU2VsZWN0b3IgKyAnLCBvcHRncm91cCcgKyBvcHRpb25TZWxlY3RvciArICcgb3B0aW9uJyArIG9wdGlvblNlbGVjdG9yKS5sZW5ndGgsXHJcbiAgICAgICAgICAgICAgdHI4blRleHQgPSAodHlwZW9mIHRoaXMub3B0aW9ucy5jb3VudFNlbGVjdGVkVGV4dCA9PT0gJ2Z1bmN0aW9uJykgPyB0aGlzLm9wdGlvbnMuY291bnRTZWxlY3RlZFRleHQoc2VsZWN0ZWRDb3VudCwgdG90YWxDb3VudCkgOiB0aGlzLm9wdGlvbnMuY291bnRTZWxlY3RlZFRleHQ7XHJcblxyXG4gICAgICAgICAgdGl0bGVGcmFnbWVudCA9IGdlbmVyYXRlT3B0aW9uLnRleHQuY2FsbCh0aGlzLCB7XHJcbiAgICAgICAgICAgIHRleHQ6IHRyOG5UZXh0LnJlcGxhY2UoJ3swfScsIHNlbGVjdGVkQ291bnQudG9TdHJpbmcoKSkucmVwbGFjZSgnezF9JywgdG90YWxDb3VudC50b1N0cmluZygpKVxyXG4gICAgICAgICAgfSwgdHJ1ZSk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBJZiB0aGUgc2VsZWN0IGRvZXNuJ3QgaGF2ZSBhIHRpdGxlLCB0aGVuIHVzZSB0aGUgZGVmYXVsdCwgb3IgaWYgbm90aGluZyBpcyBzZXQgYXQgYWxsLCB1c2Ugbm9uZVNlbGVjdGVkVGV4dFxyXG4gICAgICBpZiAoIXRpdGxlRnJhZ21lbnQuY2hpbGROb2Rlcy5sZW5ndGgpIHtcclxuICAgICAgICB0aXRsZUZyYWdtZW50ID0gZ2VuZXJhdGVPcHRpb24udGV4dC5jYWxsKHRoaXMsIHtcclxuICAgICAgICAgIHRleHQ6IHRoaXMub3B0aW9ucy5wbGFjZWhvbGRlciA/IHRoaXMub3B0aW9ucy5wbGFjZWhvbGRlciA6IHRoaXMub3B0aW9ucy5ub25lU2VsZWN0ZWRUZXh0XHJcbiAgICAgICAgfSwgdHJ1ZSk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIGlmIHRoZSBzZWxlY3QgaGFzIGEgdGl0bGUsIGFwcGx5IGl0IHRvIHRoZSBidXR0b24sIGFuZCBpZiBub3QsIGFwcGx5IHRpdGxlRnJhZ21lbnQgdGV4dFxyXG4gICAgICAvLyBzdHJpcCBhbGwgSFRNTCB0YWdzIGFuZCB0cmltIHRoZSByZXN1bHQsIHRoZW4gdW5lc2NhcGUgYW55IGVzY2FwZWQgdGFnc1xyXG4gICAgICBidXR0b24udGl0bGUgPSB0aXRsZUZyYWdtZW50LnRleHRDb250ZW50LnJlcGxhY2UoLzxbXj5dKj4/L2csICcnKS50cmltKCk7XHJcblxyXG4gICAgICBpZiAodGhpcy5vcHRpb25zLnNhbml0aXplICYmIGhhc0NvbnRlbnQpIHtcclxuICAgICAgICBzYW5pdGl6ZUh0bWwoW3RpdGxlRnJhZ21lbnRdLCB0aGF0Lm9wdGlvbnMud2hpdGVMaXN0LCB0aGF0Lm9wdGlvbnMuc2FuaXRpemVGbik7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGJ1dHRvbklubmVyLmlubmVySFRNTCA9ICcnO1xyXG4gICAgICBidXR0b25Jbm5lci5hcHBlbmRDaGlsZCh0aXRsZUZyYWdtZW50KTtcclxuXHJcbiAgICAgIGlmICh2ZXJzaW9uLm1ham9yIDwgNCAmJiB0aGlzLiRuZXdFbGVtZW50WzBdLmNsYXNzTGlzdC5jb250YWlucygnYnMzLWhhcy1hZGRvbicpKSB7XHJcbiAgICAgICAgdmFyIGZpbHRlckV4cGFuZCA9IGJ1dHRvbi5xdWVyeVNlbGVjdG9yKCcuZmlsdGVyLWV4cGFuZCcpLFxyXG4gICAgICAgICAgICBjbG9uZSA9IGJ1dHRvbklubmVyLmNsb25lTm9kZSh0cnVlKTtcclxuXHJcbiAgICAgICAgY2xvbmUuY2xhc3NOYW1lID0gJ2ZpbHRlci1leHBhbmQnO1xyXG5cclxuICAgICAgICBpZiAoZmlsdGVyRXhwYW5kKSB7XHJcbiAgICAgICAgICBidXR0b24ucmVwbGFjZUNoaWxkKGNsb25lLCBmaWx0ZXJFeHBhbmQpO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICBidXR0b24uYXBwZW5kQ2hpbGQoY2xvbmUpO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgdGhpcy4kZWxlbWVudC50cmlnZ2VyKCdyZW5kZXJlZCcgKyBFVkVOVF9LRVkpO1xyXG4gICAgfSxcclxuXHJcbiAgICAvKipcclxuICAgICAqIEBwYXJhbSBbc3R5bGVdXHJcbiAgICAgKiBAcGFyYW0gW3N0YXR1c11cclxuICAgICAqL1xyXG4gICAgc2V0U3R5bGU6IGZ1bmN0aW9uIChuZXdTdHlsZSwgc3RhdHVzKSB7XHJcbiAgICAgIHZhciBidXR0b24gPSB0aGlzLiRidXR0b25bMF0sXHJcbiAgICAgICAgICBuZXdFbGVtZW50ID0gdGhpcy4kbmV3RWxlbWVudFswXSxcclxuICAgICAgICAgIHN0eWxlID0gdGhpcy5vcHRpb25zLnN0eWxlLnRyaW0oKSxcclxuICAgICAgICAgIGJ1dHRvbkNsYXNzO1xyXG5cclxuICAgICAgaWYgKHRoaXMuJGVsZW1lbnQuYXR0cignY2xhc3MnKSkge1xyXG4gICAgICAgIHRoaXMuJG5ld0VsZW1lbnQuYWRkQ2xhc3ModGhpcy4kZWxlbWVudC5hdHRyKCdjbGFzcycpLnJlcGxhY2UoL3NlbGVjdHBpY2tlcnxtb2JpbGUtZGV2aWNlfGJzLXNlbGVjdC1oaWRkZW58dmFsaWRhdGVcXFsuKlxcXS9naSwgJycpKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKHZlcnNpb24ubWFqb3IgPCA0KSB7XHJcbiAgICAgICAgbmV3RWxlbWVudC5jbGFzc0xpc3QuYWRkKCdiczMnKTtcclxuXHJcbiAgICAgICAgaWYgKG5ld0VsZW1lbnQucGFyZW50Tm9kZS5jbGFzc0xpc3QgJiYgbmV3RWxlbWVudC5wYXJlbnROb2RlLmNsYXNzTGlzdC5jb250YWlucygnaW5wdXQtZ3JvdXAnKSAmJlxyXG4gICAgICAgICAgICAobmV3RWxlbWVudC5wcmV2aW91c0VsZW1lbnRTaWJsaW5nIHx8IG5ld0VsZW1lbnQubmV4dEVsZW1lbnRTaWJsaW5nKSAmJlxyXG4gICAgICAgICAgICAobmV3RWxlbWVudC5wcmV2aW91c0VsZW1lbnRTaWJsaW5nIHx8IG5ld0VsZW1lbnQubmV4dEVsZW1lbnRTaWJsaW5nKS5jbGFzc0xpc3QuY29udGFpbnMoJ2lucHV0LWdyb3VwLWFkZG9uJylcclxuICAgICAgICApIHtcclxuICAgICAgICAgIG5ld0VsZW1lbnQuY2xhc3NMaXN0LmFkZCgnYnMzLWhhcy1hZGRvbicpO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKG5ld1N0eWxlKSB7XHJcbiAgICAgICAgYnV0dG9uQ2xhc3MgPSBuZXdTdHlsZS50cmltKCk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgYnV0dG9uQ2xhc3MgPSBzdHlsZTtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKHN0YXR1cyA9PSAnYWRkJykge1xyXG4gICAgICAgIGlmIChidXR0b25DbGFzcykgYnV0dG9uLmNsYXNzTGlzdC5hZGQuYXBwbHkoYnV0dG9uLmNsYXNzTGlzdCwgYnV0dG9uQ2xhc3Muc3BsaXQoJyAnKSk7XHJcbiAgICAgIH0gZWxzZSBpZiAoc3RhdHVzID09ICdyZW1vdmUnKSB7XHJcbiAgICAgICAgaWYgKGJ1dHRvbkNsYXNzKSBidXR0b24uY2xhc3NMaXN0LnJlbW92ZS5hcHBseShidXR0b24uY2xhc3NMaXN0LCBidXR0b25DbGFzcy5zcGxpdCgnICcpKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBpZiAoc3R5bGUpIGJ1dHRvbi5jbGFzc0xpc3QucmVtb3ZlLmFwcGx5KGJ1dHRvbi5jbGFzc0xpc3QsIHN0eWxlLnNwbGl0KCcgJykpO1xyXG4gICAgICAgIGlmIChidXR0b25DbGFzcykgYnV0dG9uLmNsYXNzTGlzdC5hZGQuYXBwbHkoYnV0dG9uLmNsYXNzTGlzdCwgYnV0dG9uQ2xhc3Muc3BsaXQoJyAnKSk7XHJcbiAgICAgIH1cclxuICAgIH0sXHJcblxyXG4gICAgbGlIZWlnaHQ6IGZ1bmN0aW9uIChyZWZyZXNoKSB7XHJcbiAgICAgIGlmICghcmVmcmVzaCAmJiAodGhpcy5vcHRpb25zLnNpemUgPT09IGZhbHNlIHx8IE9iamVjdC5rZXlzKHRoaXMuc2l6ZUluZm8pLmxlbmd0aCkpIHJldHVybjtcclxuXHJcbiAgICAgIHZhciBuZXdFbGVtZW50ID0gZWxlbWVudFRlbXBsYXRlcy5kaXYuY2xvbmVOb2RlKGZhbHNlKSxcclxuICAgICAgICAgIG1lbnUgPSBlbGVtZW50VGVtcGxhdGVzLmRpdi5jbG9uZU5vZGUoZmFsc2UpLFxyXG4gICAgICAgICAgbWVudUlubmVyID0gZWxlbWVudFRlbXBsYXRlcy5kaXYuY2xvbmVOb2RlKGZhbHNlKSxcclxuICAgICAgICAgIG1lbnVJbm5lcklubmVyID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgndWwnKSxcclxuICAgICAgICAgIGRpdmlkZXIgPSBlbGVtZW50VGVtcGxhdGVzLmxpLmNsb25lTm9kZShmYWxzZSksXHJcbiAgICAgICAgICBkcm9wZG93bkhlYWRlciA9IGVsZW1lbnRUZW1wbGF0ZXMubGkuY2xvbmVOb2RlKGZhbHNlKSxcclxuICAgICAgICAgIGxpLFxyXG4gICAgICAgICAgYSA9IGVsZW1lbnRUZW1wbGF0ZXMuYS5jbG9uZU5vZGUoZmFsc2UpLFxyXG4gICAgICAgICAgdGV4dCA9IGVsZW1lbnRUZW1wbGF0ZXMuc3Bhbi5jbG9uZU5vZGUoZmFsc2UpLFxyXG4gICAgICAgICAgaGVhZGVyID0gdGhpcy5vcHRpb25zLmhlYWRlciAmJiB0aGlzLiRtZW51LmZpbmQoJy4nICsgY2xhc3NOYW1lcy5QT1BPVkVSSEVBREVSKS5sZW5ndGggPiAwID8gdGhpcy4kbWVudS5maW5kKCcuJyArIGNsYXNzTmFtZXMuUE9QT1ZFUkhFQURFUilbMF0uY2xvbmVOb2RlKHRydWUpIDogbnVsbCxcclxuICAgICAgICAgIHNlYXJjaCA9IHRoaXMub3B0aW9ucy5saXZlU2VhcmNoID8gZWxlbWVudFRlbXBsYXRlcy5kaXYuY2xvbmVOb2RlKGZhbHNlKSA6IG51bGwsXHJcbiAgICAgICAgICBhY3Rpb25zID0gdGhpcy5vcHRpb25zLmFjdGlvbnNCb3ggJiYgdGhpcy5tdWx0aXBsZSAmJiB0aGlzLiRtZW51LmZpbmQoJy5icy1hY3Rpb25zYm94JykubGVuZ3RoID4gMCA/IHRoaXMuJG1lbnUuZmluZCgnLmJzLWFjdGlvbnNib3gnKVswXS5jbG9uZU5vZGUodHJ1ZSkgOiBudWxsLFxyXG4gICAgICAgICAgZG9uZUJ1dHRvbiA9IHRoaXMub3B0aW9ucy5kb25lQnV0dG9uICYmIHRoaXMubXVsdGlwbGUgJiYgdGhpcy4kbWVudS5maW5kKCcuYnMtZG9uZWJ1dHRvbicpLmxlbmd0aCA+IDAgPyB0aGlzLiRtZW51LmZpbmQoJy5icy1kb25lYnV0dG9uJylbMF0uY2xvbmVOb2RlKHRydWUpIDogbnVsbCxcclxuICAgICAgICAgIGZpcnN0T3B0aW9uID0gdGhpcy4kZWxlbWVudFswXS5vcHRpb25zWzBdO1xyXG5cclxuICAgICAgdGhpcy5zaXplSW5mby5zZWxlY3RXaWR0aCA9IHRoaXMuJG5ld0VsZW1lbnRbMF0ub2Zmc2V0V2lkdGg7XHJcblxyXG4gICAgICB0ZXh0LmNsYXNzTmFtZSA9ICd0ZXh0JztcclxuICAgICAgYS5jbGFzc05hbWUgPSAnZHJvcGRvd24taXRlbSAnICsgKGZpcnN0T3B0aW9uID8gZmlyc3RPcHRpb24uY2xhc3NOYW1lIDogJycpO1xyXG4gICAgICBuZXdFbGVtZW50LmNsYXNzTmFtZSA9IHRoaXMuJG1lbnVbMF0ucGFyZW50Tm9kZS5jbGFzc05hbWUgKyAnICcgKyBjbGFzc05hbWVzLlNIT1c7XHJcbiAgICAgIG5ld0VsZW1lbnQuc3R5bGUud2lkdGggPSAwOyAvLyBlbnN1cmUgYnV0dG9uIHdpZHRoIGRvZXNuJ3QgYWZmZWN0IG5hdHVyYWwgd2lkdGggb2YgbWVudSB3aGVuIGNhbGN1bGF0aW5nXHJcbiAgICAgIGlmICh0aGlzLm9wdGlvbnMud2lkdGggPT09ICdhdXRvJykgbWVudS5zdHlsZS5taW5XaWR0aCA9IDA7XHJcbiAgICAgIG1lbnUuY2xhc3NOYW1lID0gY2xhc3NOYW1lcy5NRU5VICsgJyAnICsgY2xhc3NOYW1lcy5TSE9XO1xyXG4gICAgICBtZW51SW5uZXIuY2xhc3NOYW1lID0gJ2lubmVyICcgKyBjbGFzc05hbWVzLlNIT1c7XHJcbiAgICAgIG1lbnVJbm5lcklubmVyLmNsYXNzTmFtZSA9IGNsYXNzTmFtZXMuTUVOVSArICcgaW5uZXIgJyArICh2ZXJzaW9uLm1ham9yID49ICc0JyA/IGNsYXNzTmFtZXMuU0hPVyA6ICcnKTtcclxuICAgICAgZGl2aWRlci5jbGFzc05hbWUgPSBjbGFzc05hbWVzLkRJVklERVI7XHJcbiAgICAgIGRyb3Bkb3duSGVhZGVyLmNsYXNzTmFtZSA9ICdkcm9wZG93bi1oZWFkZXInO1xyXG5cclxuICAgICAgdGV4dC5hcHBlbmRDaGlsZChkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZSgnXFx1MjAwYicpKTtcclxuXHJcbiAgICAgIGlmICh0aGlzLnNlbGVjdHBpY2tlci5jdXJyZW50LmRhdGEubGVuZ3RoKSB7XHJcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLnNlbGVjdHBpY2tlci5jdXJyZW50LmRhdGEubGVuZ3RoOyBpKyspIHtcclxuICAgICAgICAgIHZhciBkYXRhID0gdGhpcy5zZWxlY3RwaWNrZXIuY3VycmVudC5kYXRhW2ldO1xyXG4gICAgICAgICAgaWYgKGRhdGEudHlwZSA9PT0gJ29wdGlvbicpIHtcclxuICAgICAgICAgICAgbGkgPSBkYXRhLmVsZW1lbnQ7XHJcbiAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBsaSA9IGVsZW1lbnRUZW1wbGF0ZXMubGkuY2xvbmVOb2RlKGZhbHNlKTtcclxuICAgICAgICBhLmFwcGVuZENoaWxkKHRleHQpO1xyXG4gICAgICAgIGxpLmFwcGVuZENoaWxkKGEpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBkcm9wZG93bkhlYWRlci5hcHBlbmRDaGlsZCh0ZXh0LmNsb25lTm9kZSh0cnVlKSk7XHJcblxyXG4gICAgICBpZiAodGhpcy5zZWxlY3RwaWNrZXIudmlldy53aWRlc3RPcHRpb24pIHtcclxuICAgICAgICBtZW51SW5uZXJJbm5lci5hcHBlbmRDaGlsZCh0aGlzLnNlbGVjdHBpY2tlci52aWV3LndpZGVzdE9wdGlvbi5jbG9uZU5vZGUodHJ1ZSkpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBtZW51SW5uZXJJbm5lci5hcHBlbmRDaGlsZChsaSk7XHJcbiAgICAgIG1lbnVJbm5lcklubmVyLmFwcGVuZENoaWxkKGRpdmlkZXIpO1xyXG4gICAgICBtZW51SW5uZXJJbm5lci5hcHBlbmRDaGlsZChkcm9wZG93bkhlYWRlcik7XHJcbiAgICAgIGlmIChoZWFkZXIpIG1lbnUuYXBwZW5kQ2hpbGQoaGVhZGVyKTtcclxuICAgICAgaWYgKHNlYXJjaCkge1xyXG4gICAgICAgIHZhciBpbnB1dCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2lucHV0Jyk7XHJcbiAgICAgICAgc2VhcmNoLmNsYXNzTmFtZSA9ICdicy1zZWFyY2hib3gnO1xyXG4gICAgICAgIGlucHV0LmNsYXNzTmFtZSA9ICdmb3JtLWNvbnRyb2wnO1xyXG4gICAgICAgIHNlYXJjaC5hcHBlbmRDaGlsZChpbnB1dCk7XHJcbiAgICAgICAgbWVudS5hcHBlbmRDaGlsZChzZWFyY2gpO1xyXG4gICAgICB9XHJcbiAgICAgIGlmIChhY3Rpb25zKSBtZW51LmFwcGVuZENoaWxkKGFjdGlvbnMpO1xyXG4gICAgICBtZW51SW5uZXIuYXBwZW5kQ2hpbGQobWVudUlubmVySW5uZXIpO1xyXG4gICAgICBtZW51LmFwcGVuZENoaWxkKG1lbnVJbm5lcik7XHJcbiAgICAgIGlmIChkb25lQnV0dG9uKSBtZW51LmFwcGVuZENoaWxkKGRvbmVCdXR0b24pO1xyXG4gICAgICBuZXdFbGVtZW50LmFwcGVuZENoaWxkKG1lbnUpO1xyXG5cclxuICAgICAgZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChuZXdFbGVtZW50KTtcclxuXHJcbiAgICAgIHZhciBsaUhlaWdodCA9IGxpLm9mZnNldEhlaWdodCxcclxuICAgICAgICAgIGRyb3Bkb3duSGVhZGVySGVpZ2h0ID0gZHJvcGRvd25IZWFkZXIgPyBkcm9wZG93bkhlYWRlci5vZmZzZXRIZWlnaHQgOiAwLFxyXG4gICAgICAgICAgaGVhZGVySGVpZ2h0ID0gaGVhZGVyID8gaGVhZGVyLm9mZnNldEhlaWdodCA6IDAsXHJcbiAgICAgICAgICBzZWFyY2hIZWlnaHQgPSBzZWFyY2ggPyBzZWFyY2gub2Zmc2V0SGVpZ2h0IDogMCxcclxuICAgICAgICAgIGFjdGlvbnNIZWlnaHQgPSBhY3Rpb25zID8gYWN0aW9ucy5vZmZzZXRIZWlnaHQgOiAwLFxyXG4gICAgICAgICAgZG9uZUJ1dHRvbkhlaWdodCA9IGRvbmVCdXR0b24gPyBkb25lQnV0dG9uLm9mZnNldEhlaWdodCA6IDAsXHJcbiAgICAgICAgICBkaXZpZGVySGVpZ2h0ID0gJChkaXZpZGVyKS5vdXRlckhlaWdodCh0cnVlKSxcclxuICAgICAgICAgIG1lbnVTdHlsZSA9IHdpbmRvdy5nZXRDb21wdXRlZFN0eWxlKG1lbnUpLFxyXG4gICAgICAgICAgbWVudVdpZHRoID0gbWVudS5vZmZzZXRXaWR0aCxcclxuICAgICAgICAgIG1lbnVQYWRkaW5nID0ge1xyXG4gICAgICAgICAgICB2ZXJ0OiB0b0ludGVnZXIobWVudVN0eWxlLnBhZGRpbmdUb3ApICtcclxuICAgICAgICAgICAgICAgICAgdG9JbnRlZ2VyKG1lbnVTdHlsZS5wYWRkaW5nQm90dG9tKSArXHJcbiAgICAgICAgICAgICAgICAgIHRvSW50ZWdlcihtZW51U3R5bGUuYm9yZGVyVG9wV2lkdGgpICtcclxuICAgICAgICAgICAgICAgICAgdG9JbnRlZ2VyKG1lbnVTdHlsZS5ib3JkZXJCb3R0b21XaWR0aCksXHJcbiAgICAgICAgICAgIGhvcml6OiB0b0ludGVnZXIobWVudVN0eWxlLnBhZGRpbmdMZWZ0KSArXHJcbiAgICAgICAgICAgICAgICAgIHRvSW50ZWdlcihtZW51U3R5bGUucGFkZGluZ1JpZ2h0KSArXHJcbiAgICAgICAgICAgICAgICAgIHRvSW50ZWdlcihtZW51U3R5bGUuYm9yZGVyTGVmdFdpZHRoKSArXHJcbiAgICAgICAgICAgICAgICAgIHRvSW50ZWdlcihtZW51U3R5bGUuYm9yZGVyUmlnaHRXaWR0aClcclxuICAgICAgICAgIH0sXHJcbiAgICAgICAgICBtZW51RXh0cmFzID0ge1xyXG4gICAgICAgICAgICB2ZXJ0OiBtZW51UGFkZGluZy52ZXJ0ICtcclxuICAgICAgICAgICAgICAgICAgdG9JbnRlZ2VyKG1lbnVTdHlsZS5tYXJnaW5Ub3ApICtcclxuICAgICAgICAgICAgICAgICAgdG9JbnRlZ2VyKG1lbnVTdHlsZS5tYXJnaW5Cb3R0b20pICsgMixcclxuICAgICAgICAgICAgaG9yaXo6IG1lbnVQYWRkaW5nLmhvcml6ICtcclxuICAgICAgICAgICAgICAgICAgdG9JbnRlZ2VyKG1lbnVTdHlsZS5tYXJnaW5MZWZ0KSArXHJcbiAgICAgICAgICAgICAgICAgIHRvSW50ZWdlcihtZW51U3R5bGUubWFyZ2luUmlnaHQpICsgMlxyXG4gICAgICAgICAgfSxcclxuICAgICAgICAgIHNjcm9sbEJhcldpZHRoO1xyXG5cclxuICAgICAgbWVudUlubmVyLnN0eWxlLm92ZXJmbG93WSA9ICdzY3JvbGwnO1xyXG5cclxuICAgICAgc2Nyb2xsQmFyV2lkdGggPSBtZW51Lm9mZnNldFdpZHRoIC0gbWVudVdpZHRoO1xyXG5cclxuICAgICAgZG9jdW1lbnQuYm9keS5yZW1vdmVDaGlsZChuZXdFbGVtZW50KTtcclxuXHJcbiAgICAgIHRoaXMuc2l6ZUluZm8ubGlIZWlnaHQgPSBsaUhlaWdodDtcclxuICAgICAgdGhpcy5zaXplSW5mby5kcm9wZG93bkhlYWRlckhlaWdodCA9IGRyb3Bkb3duSGVhZGVySGVpZ2h0O1xyXG4gICAgICB0aGlzLnNpemVJbmZvLmhlYWRlckhlaWdodCA9IGhlYWRlckhlaWdodDtcclxuICAgICAgdGhpcy5zaXplSW5mby5zZWFyY2hIZWlnaHQgPSBzZWFyY2hIZWlnaHQ7XHJcbiAgICAgIHRoaXMuc2l6ZUluZm8uYWN0aW9uc0hlaWdodCA9IGFjdGlvbnNIZWlnaHQ7XHJcbiAgICAgIHRoaXMuc2l6ZUluZm8uZG9uZUJ1dHRvbkhlaWdodCA9IGRvbmVCdXR0b25IZWlnaHQ7XHJcbiAgICAgIHRoaXMuc2l6ZUluZm8uZGl2aWRlckhlaWdodCA9IGRpdmlkZXJIZWlnaHQ7XHJcbiAgICAgIHRoaXMuc2l6ZUluZm8ubWVudVBhZGRpbmcgPSBtZW51UGFkZGluZztcclxuICAgICAgdGhpcy5zaXplSW5mby5tZW51RXh0cmFzID0gbWVudUV4dHJhcztcclxuICAgICAgdGhpcy5zaXplSW5mby5tZW51V2lkdGggPSBtZW51V2lkdGg7XHJcbiAgICAgIHRoaXMuc2l6ZUluZm8ubWVudUlubmVySW5uZXJXaWR0aCA9IG1lbnVXaWR0aCAtIG1lbnVQYWRkaW5nLmhvcml6O1xyXG4gICAgICB0aGlzLnNpemVJbmZvLnRvdGFsTWVudVdpZHRoID0gdGhpcy5zaXplSW5mby5tZW51V2lkdGg7XHJcbiAgICAgIHRoaXMuc2l6ZUluZm8uc2Nyb2xsQmFyV2lkdGggPSBzY3JvbGxCYXJXaWR0aDtcclxuICAgICAgdGhpcy5zaXplSW5mby5zZWxlY3RIZWlnaHQgPSB0aGlzLiRuZXdFbGVtZW50WzBdLm9mZnNldEhlaWdodDtcclxuXHJcbiAgICAgIHRoaXMuc2V0UG9zaXRpb25EYXRhKCk7XHJcbiAgICB9LFxyXG5cclxuICAgIGdldFNlbGVjdFBvc2l0aW9uOiBmdW5jdGlvbiAoKSB7XHJcbiAgICAgIHZhciB0aGF0ID0gdGhpcyxcclxuICAgICAgICAgICR3aW5kb3cgPSAkKHdpbmRvdyksXHJcbiAgICAgICAgICBwb3MgPSB0aGF0LiRuZXdFbGVtZW50Lm9mZnNldCgpLFxyXG4gICAgICAgICAgJGNvbnRhaW5lciA9ICQodGhhdC5vcHRpb25zLmNvbnRhaW5lciksXHJcbiAgICAgICAgICBjb250YWluZXJQb3M7XHJcblxyXG4gICAgICBpZiAodGhhdC5vcHRpb25zLmNvbnRhaW5lciAmJiAkY29udGFpbmVyLmxlbmd0aCAmJiAhJGNvbnRhaW5lci5pcygnYm9keScpKSB7XHJcbiAgICAgICAgY29udGFpbmVyUG9zID0gJGNvbnRhaW5lci5vZmZzZXQoKTtcclxuICAgICAgICBjb250YWluZXJQb3MudG9wICs9IHBhcnNlSW50KCRjb250YWluZXIuY3NzKCdib3JkZXJUb3BXaWR0aCcpKTtcclxuICAgICAgICBjb250YWluZXJQb3MubGVmdCArPSBwYXJzZUludCgkY29udGFpbmVyLmNzcygnYm9yZGVyTGVmdFdpZHRoJykpO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIGNvbnRhaW5lclBvcyA9IHsgdG9wOiAwLCBsZWZ0OiAwIH07XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHZhciB3aW5QYWQgPSB0aGF0Lm9wdGlvbnMud2luZG93UGFkZGluZztcclxuXHJcbiAgICAgIHRoaXMuc2l6ZUluZm8uc2VsZWN0T2Zmc2V0VG9wID0gcG9zLnRvcCAtIGNvbnRhaW5lclBvcy50b3AgLSAkd2luZG93LnNjcm9sbFRvcCgpO1xyXG4gICAgICB0aGlzLnNpemVJbmZvLnNlbGVjdE9mZnNldEJvdCA9ICR3aW5kb3cuaGVpZ2h0KCkgLSB0aGlzLnNpemVJbmZvLnNlbGVjdE9mZnNldFRvcCAtIHRoaXMuc2l6ZUluZm8uc2VsZWN0SGVpZ2h0IC0gY29udGFpbmVyUG9zLnRvcCAtIHdpblBhZFsyXTtcclxuICAgICAgdGhpcy5zaXplSW5mby5zZWxlY3RPZmZzZXRMZWZ0ID0gcG9zLmxlZnQgLSBjb250YWluZXJQb3MubGVmdCAtICR3aW5kb3cuc2Nyb2xsTGVmdCgpO1xyXG4gICAgICB0aGlzLnNpemVJbmZvLnNlbGVjdE9mZnNldFJpZ2h0ID0gJHdpbmRvdy53aWR0aCgpIC0gdGhpcy5zaXplSW5mby5zZWxlY3RPZmZzZXRMZWZ0IC0gdGhpcy5zaXplSW5mby5zZWxlY3RXaWR0aCAtIGNvbnRhaW5lclBvcy5sZWZ0IC0gd2luUGFkWzFdO1xyXG4gICAgICB0aGlzLnNpemVJbmZvLnNlbGVjdE9mZnNldFRvcCAtPSB3aW5QYWRbMF07XHJcbiAgICAgIHRoaXMuc2l6ZUluZm8uc2VsZWN0T2Zmc2V0TGVmdCAtPSB3aW5QYWRbM107XHJcbiAgICB9LFxyXG5cclxuICAgIHNldE1lbnVTaXplOiBmdW5jdGlvbiAoaXNBdXRvKSB7XHJcbiAgICAgIHRoaXMuZ2V0U2VsZWN0UG9zaXRpb24oKTtcclxuXHJcbiAgICAgIHZhciBzZWxlY3RXaWR0aCA9IHRoaXMuc2l6ZUluZm8uc2VsZWN0V2lkdGgsXHJcbiAgICAgICAgICBsaUhlaWdodCA9IHRoaXMuc2l6ZUluZm8ubGlIZWlnaHQsXHJcbiAgICAgICAgICBoZWFkZXJIZWlnaHQgPSB0aGlzLnNpemVJbmZvLmhlYWRlckhlaWdodCxcclxuICAgICAgICAgIHNlYXJjaEhlaWdodCA9IHRoaXMuc2l6ZUluZm8uc2VhcmNoSGVpZ2h0LFxyXG4gICAgICAgICAgYWN0aW9uc0hlaWdodCA9IHRoaXMuc2l6ZUluZm8uYWN0aW9uc0hlaWdodCxcclxuICAgICAgICAgIGRvbmVCdXR0b25IZWlnaHQgPSB0aGlzLnNpemVJbmZvLmRvbmVCdXR0b25IZWlnaHQsXHJcbiAgICAgICAgICBkaXZIZWlnaHQgPSB0aGlzLnNpemVJbmZvLmRpdmlkZXJIZWlnaHQsXHJcbiAgICAgICAgICBtZW51UGFkZGluZyA9IHRoaXMuc2l6ZUluZm8ubWVudVBhZGRpbmcsXHJcbiAgICAgICAgICBtZW51SW5uZXJIZWlnaHQsXHJcbiAgICAgICAgICBtZW51SGVpZ2h0LFxyXG4gICAgICAgICAgZGl2TGVuZ3RoID0gMCxcclxuICAgICAgICAgIG1pbkhlaWdodCxcclxuICAgICAgICAgIF9taW5IZWlnaHQsXHJcbiAgICAgICAgICBtYXhIZWlnaHQsXHJcbiAgICAgICAgICBtZW51SW5uZXJNaW5IZWlnaHQsXHJcbiAgICAgICAgICBlc3RpbWF0ZSxcclxuICAgICAgICAgIGlzRHJvcHVwO1xyXG5cclxuICAgICAgaWYgKHRoaXMub3B0aW9ucy5kcm9wdXBBdXRvKSB7XHJcbiAgICAgICAgLy8gR2V0IHRoZSBlc3RpbWF0ZWQgaGVpZ2h0IG9mIHRoZSBtZW51IHdpdGhvdXQgc2Nyb2xsYmFycy5cclxuICAgICAgICAvLyBUaGlzIGlzIHVzZWZ1bCBmb3Igc21hbGxlciBtZW51cywgd2hlcmUgdGhlcmUgbWlnaHQgYmUgcGxlbnR5IG9mIHJvb21cclxuICAgICAgICAvLyBiZWxvdyB0aGUgYnV0dG9uIHdpdGhvdXQgc2V0dGluZyBkcm9wdXAsIGJ1dCB3ZSBjYW4ndCBrbm93XHJcbiAgICAgICAgLy8gdGhlIGV4YWN0IGhlaWdodCBvZiB0aGUgbWVudSB1bnRpbCBjcmVhdGVWaWV3IGlzIGNhbGxlZCBsYXRlclxyXG4gICAgICAgIGVzdGltYXRlID0gbGlIZWlnaHQgKiB0aGlzLnNlbGVjdHBpY2tlci5jdXJyZW50LmRhdGEubGVuZ3RoICsgbWVudVBhZGRpbmcudmVydDtcclxuXHJcbiAgICAgICAgaXNEcm9wdXAgPSB0aGlzLnNpemVJbmZvLnNlbGVjdE9mZnNldFRvcCAtIHRoaXMuc2l6ZUluZm8uc2VsZWN0T2Zmc2V0Qm90ID4gdGhpcy5zaXplSW5mby5tZW51RXh0cmFzLnZlcnQgJiYgZXN0aW1hdGUgKyB0aGlzLnNpemVJbmZvLm1lbnVFeHRyYXMudmVydCArIDUwID4gdGhpcy5zaXplSW5mby5zZWxlY3RPZmZzZXRCb3Q7XHJcblxyXG4gICAgICAgIC8vIGVuc3VyZSBkcm9wdXAgZG9lc24ndCBjaGFuZ2Ugd2hpbGUgc2VhcmNoaW5nIChzbyBtZW51IGRvZXNuJ3QgYm91bmNlIGJhY2sgYW5kIGZvcnRoKVxyXG4gICAgICAgIGlmICh0aGlzLnNlbGVjdHBpY2tlci5pc1NlYXJjaGluZyA9PT0gdHJ1ZSkge1xyXG4gICAgICAgICAgaXNEcm9wdXAgPSB0aGlzLnNlbGVjdHBpY2tlci5kcm9wdXA7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICB0aGlzLiRuZXdFbGVtZW50LnRvZ2dsZUNsYXNzKGNsYXNzTmFtZXMuRFJPUFVQLCBpc0Ryb3B1cCk7XHJcbiAgICAgICAgdGhpcy5zZWxlY3RwaWNrZXIuZHJvcHVwID0gaXNEcm9wdXA7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmICh0aGlzLm9wdGlvbnMuc2l6ZSA9PT0gJ2F1dG8nKSB7XHJcbiAgICAgICAgX21pbkhlaWdodCA9IHRoaXMuc2VsZWN0cGlja2VyLmN1cnJlbnQuZGF0YS5sZW5ndGggPiAzID8gdGhpcy5zaXplSW5mby5saUhlaWdodCAqIDMgKyB0aGlzLnNpemVJbmZvLm1lbnVFeHRyYXMudmVydCAtIDIgOiAwO1xyXG4gICAgICAgIG1lbnVIZWlnaHQgPSB0aGlzLnNpemVJbmZvLnNlbGVjdE9mZnNldEJvdCAtIHRoaXMuc2l6ZUluZm8ubWVudUV4dHJhcy52ZXJ0O1xyXG4gICAgICAgIG1pbkhlaWdodCA9IF9taW5IZWlnaHQgKyBoZWFkZXJIZWlnaHQgKyBzZWFyY2hIZWlnaHQgKyBhY3Rpb25zSGVpZ2h0ICsgZG9uZUJ1dHRvbkhlaWdodDtcclxuICAgICAgICBtZW51SW5uZXJNaW5IZWlnaHQgPSBNYXRoLm1heChfbWluSGVpZ2h0IC0gbWVudVBhZGRpbmcudmVydCwgMCk7XHJcblxyXG4gICAgICAgIGlmICh0aGlzLiRuZXdFbGVtZW50Lmhhc0NsYXNzKGNsYXNzTmFtZXMuRFJPUFVQKSkge1xyXG4gICAgICAgICAgbWVudUhlaWdodCA9IHRoaXMuc2l6ZUluZm8uc2VsZWN0T2Zmc2V0VG9wIC0gdGhpcy5zaXplSW5mby5tZW51RXh0cmFzLnZlcnQ7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBtYXhIZWlnaHQgPSBtZW51SGVpZ2h0O1xyXG4gICAgICAgIG1lbnVJbm5lckhlaWdodCA9IG1lbnVIZWlnaHQgLSBoZWFkZXJIZWlnaHQgLSBzZWFyY2hIZWlnaHQgLSBhY3Rpb25zSGVpZ2h0IC0gZG9uZUJ1dHRvbkhlaWdodCAtIG1lbnVQYWRkaW5nLnZlcnQ7XHJcbiAgICAgIH0gZWxzZSBpZiAodGhpcy5vcHRpb25zLnNpemUgJiYgdGhpcy5vcHRpb25zLnNpemUgIT0gJ2F1dG8nICYmIHRoaXMuc2VsZWN0cGlja2VyLmN1cnJlbnQuZWxlbWVudHMubGVuZ3RoID4gdGhpcy5vcHRpb25zLnNpemUpIHtcclxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMub3B0aW9ucy5zaXplOyBpKyspIHtcclxuICAgICAgICAgIGlmICh0aGlzLnNlbGVjdHBpY2tlci5jdXJyZW50LmRhdGFbaV0udHlwZSA9PT0gJ2RpdmlkZXInKSBkaXZMZW5ndGgrKztcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIG1lbnVIZWlnaHQgPSBsaUhlaWdodCAqIHRoaXMub3B0aW9ucy5zaXplICsgZGl2TGVuZ3RoICogZGl2SGVpZ2h0ICsgbWVudVBhZGRpbmcudmVydDtcclxuICAgICAgICBtZW51SW5uZXJIZWlnaHQgPSBtZW51SGVpZ2h0IC0gbWVudVBhZGRpbmcudmVydDtcclxuICAgICAgICBtYXhIZWlnaHQgPSBtZW51SGVpZ2h0ICsgaGVhZGVySGVpZ2h0ICsgc2VhcmNoSGVpZ2h0ICsgYWN0aW9uc0hlaWdodCArIGRvbmVCdXR0b25IZWlnaHQ7XHJcbiAgICAgICAgbWluSGVpZ2h0ID0gbWVudUlubmVyTWluSGVpZ2h0ID0gJyc7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHRoaXMuJG1lbnUuY3NzKHtcclxuICAgICAgICAnbWF4LWhlaWdodCc6IG1heEhlaWdodCArICdweCcsXHJcbiAgICAgICAgJ292ZXJmbG93JzogJ2hpZGRlbicsXHJcbiAgICAgICAgJ21pbi1oZWlnaHQnOiBtaW5IZWlnaHQgKyAncHgnXHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgdGhpcy4kbWVudUlubmVyLmNzcyh7XHJcbiAgICAgICAgJ21heC1oZWlnaHQnOiBtZW51SW5uZXJIZWlnaHQgKyAncHgnLFxyXG4gICAgICAgICdvdmVyZmxvdy15JzogJ2F1dG8nLFxyXG4gICAgICAgICdtaW4taGVpZ2h0JzogbWVudUlubmVyTWluSGVpZ2h0ICsgJ3B4J1xyXG4gICAgICB9KTtcclxuXHJcbiAgICAgIC8vIGVuc3VyZSBtZW51SW5uZXJIZWlnaHQgaXMgYWx3YXlzIGEgcG9zaXRpdmUgbnVtYmVyIHRvIHByZXZlbnQgaXNzdWVzIGNhbGN1bGF0aW5nIGNodW5rU2l6ZSBpbiBjcmVhdGVWaWV3XHJcbiAgICAgIHRoaXMuc2l6ZUluZm8ubWVudUlubmVySGVpZ2h0ID0gTWF0aC5tYXgobWVudUlubmVySGVpZ2h0LCAxKTtcclxuXHJcbiAgICAgIGlmICh0aGlzLnNlbGVjdHBpY2tlci5jdXJyZW50LmRhdGEubGVuZ3RoICYmIHRoaXMuc2VsZWN0cGlja2VyLmN1cnJlbnQuZGF0YVt0aGlzLnNlbGVjdHBpY2tlci5jdXJyZW50LmRhdGEubGVuZ3RoIC0gMV0ucG9zaXRpb24gPiB0aGlzLnNpemVJbmZvLm1lbnVJbm5lckhlaWdodCkge1xyXG4gICAgICAgIHRoaXMuc2l6ZUluZm8uaGFzU2Nyb2xsQmFyID0gdHJ1ZTtcclxuICAgICAgICB0aGlzLnNpemVJbmZvLnRvdGFsTWVudVdpZHRoID0gdGhpcy5zaXplSW5mby5tZW51V2lkdGggKyB0aGlzLnNpemVJbmZvLnNjcm9sbEJhcldpZHRoO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAodGhpcy5vcHRpb25zLmRyb3Bkb3duQWxpZ25SaWdodCA9PT0gJ2F1dG8nKSB7XHJcbiAgICAgICAgdGhpcy4kbWVudS50b2dnbGVDbGFzcyhjbGFzc05hbWVzLk1FTlVSSUdIVCwgdGhpcy5zaXplSW5mby5zZWxlY3RPZmZzZXRMZWZ0ID4gdGhpcy5zaXplSW5mby5zZWxlY3RPZmZzZXRSaWdodCAmJiB0aGlzLnNpemVJbmZvLnNlbGVjdE9mZnNldFJpZ2h0IDwgKHRoaXMuc2l6ZUluZm8udG90YWxNZW51V2lkdGggLSBzZWxlY3RXaWR0aCkpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAodGhpcy5kcm9wZG93biAmJiB0aGlzLmRyb3Bkb3duLl9wb3BwZXIpIHRoaXMuZHJvcGRvd24uX3BvcHBlci51cGRhdGUoKTtcclxuICAgIH0sXHJcblxyXG4gICAgc2V0U2l6ZTogZnVuY3Rpb24gKHJlZnJlc2gpIHtcclxuICAgICAgdGhpcy5saUhlaWdodChyZWZyZXNoKTtcclxuXHJcbiAgICAgIGlmICh0aGlzLm9wdGlvbnMuaGVhZGVyKSB0aGlzLiRtZW51LmNzcygncGFkZGluZy10b3AnLCAwKTtcclxuXHJcbiAgICAgIGlmICh0aGlzLm9wdGlvbnMuc2l6ZSAhPT0gZmFsc2UpIHtcclxuICAgICAgICB2YXIgdGhhdCA9IHRoaXMsXHJcbiAgICAgICAgICAgICR3aW5kb3cgPSAkKHdpbmRvdyk7XHJcblxyXG4gICAgICAgIHRoaXMuc2V0TWVudVNpemUoKTtcclxuXHJcbiAgICAgICAgaWYgKHRoaXMub3B0aW9ucy5saXZlU2VhcmNoKSB7XHJcbiAgICAgICAgICB0aGlzLiRzZWFyY2hib3hcclxuICAgICAgICAgICAgLm9mZignaW5wdXQuc2V0TWVudVNpemUgcHJvcGVydHljaGFuZ2Uuc2V0TWVudVNpemUnKVxyXG4gICAgICAgICAgICAub24oJ2lucHV0LnNldE1lbnVTaXplIHByb3BlcnR5Y2hhbmdlLnNldE1lbnVTaXplJywgZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICAgIHJldHVybiB0aGF0LnNldE1lbnVTaXplKCk7XHJcbiAgICAgICAgICAgIH0pO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgaWYgKHRoaXMub3B0aW9ucy5zaXplID09PSAnYXV0bycpIHtcclxuICAgICAgICAgICR3aW5kb3dcclxuICAgICAgICAgICAgLm9mZigncmVzaXplJyArIEVWRU5UX0tFWSArICcuJyArIHRoaXMuc2VsZWN0SWQgKyAnLnNldE1lbnVTaXplJyArICcgc2Nyb2xsJyArIEVWRU5UX0tFWSArICcuJyArIHRoaXMuc2VsZWN0SWQgKyAnLnNldE1lbnVTaXplJylcclxuICAgICAgICAgICAgLm9uKCdyZXNpemUnICsgRVZFTlRfS0VZICsgJy4nICsgdGhpcy5zZWxlY3RJZCArICcuc2V0TWVudVNpemUnICsgJyBzY3JvbGwnICsgRVZFTlRfS0VZICsgJy4nICsgdGhpcy5zZWxlY3RJZCArICcuc2V0TWVudVNpemUnLCBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgICAgcmV0dXJuIHRoYXQuc2V0TWVudVNpemUoKTtcclxuICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgfSBlbHNlIGlmICh0aGlzLm9wdGlvbnMuc2l6ZSAmJiB0aGlzLm9wdGlvbnMuc2l6ZSAhPSAnYXV0bycgJiYgdGhpcy5zZWxlY3RwaWNrZXIuY3VycmVudC5lbGVtZW50cy5sZW5ndGggPiB0aGlzLm9wdGlvbnMuc2l6ZSkge1xyXG4gICAgICAgICAgJHdpbmRvdy5vZmYoJ3Jlc2l6ZScgKyBFVkVOVF9LRVkgKyAnLicgKyB0aGlzLnNlbGVjdElkICsgJy5zZXRNZW51U2l6ZScgKyAnIHNjcm9sbCcgKyBFVkVOVF9LRVkgKyAnLicgKyB0aGlzLnNlbGVjdElkICsgJy5zZXRNZW51U2l6ZScpO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgdGhpcy5jcmVhdGVWaWV3KGZhbHNlLCB0cnVlLCByZWZyZXNoKTtcclxuICAgIH0sXHJcblxyXG4gICAgc2V0V2lkdGg6IGZ1bmN0aW9uICgpIHtcclxuICAgICAgdmFyIHRoYXQgPSB0aGlzO1xyXG5cclxuICAgICAgaWYgKHRoaXMub3B0aW9ucy53aWR0aCA9PT0gJ2F1dG8nKSB7XHJcbiAgICAgICAgcmVxdWVzdEFuaW1hdGlvbkZyYW1lKGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgIHRoYXQuJG1lbnUuY3NzKCdtaW4td2lkdGgnLCAnMCcpO1xyXG5cclxuICAgICAgICAgIHRoYXQuJGVsZW1lbnQub24oJ2xvYWRlZCcgKyBFVkVOVF9LRVksIGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgdGhhdC5saUhlaWdodCgpO1xyXG4gICAgICAgICAgICB0aGF0LnNldE1lbnVTaXplKCk7XHJcblxyXG4gICAgICAgICAgICAvLyBHZXQgY29ycmVjdCB3aWR0aCBpZiBlbGVtZW50IGlzIGhpZGRlblxyXG4gICAgICAgICAgICB2YXIgJHNlbGVjdENsb25lID0gdGhhdC4kbmV3RWxlbWVudC5jbG9uZSgpLmFwcGVuZFRvKCdib2R5JyksXHJcbiAgICAgICAgICAgICAgICBidG5XaWR0aCA9ICRzZWxlY3RDbG9uZS5jc3MoJ3dpZHRoJywgJ2F1dG8nKS5jaGlsZHJlbignYnV0dG9uJykub3V0ZXJXaWR0aCgpO1xyXG5cclxuICAgICAgICAgICAgJHNlbGVjdENsb25lLnJlbW92ZSgpO1xyXG5cclxuICAgICAgICAgICAgLy8gU2V0IHdpZHRoIHRvIHdoYXRldmVyJ3MgbGFyZ2VyLCBidXR0b24gdGl0bGUgb3IgbG9uZ2VzdCBvcHRpb25cclxuICAgICAgICAgICAgdGhhdC5zaXplSW5mby5zZWxlY3RXaWR0aCA9IE1hdGgubWF4KHRoYXQuc2l6ZUluZm8udG90YWxNZW51V2lkdGgsIGJ0bldpZHRoKTtcclxuICAgICAgICAgICAgdGhhdC4kbmV3RWxlbWVudC5jc3MoJ3dpZHRoJywgdGhhdC5zaXplSW5mby5zZWxlY3RXaWR0aCArICdweCcpO1xyXG4gICAgICAgICAgfSk7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH0gZWxzZSBpZiAodGhpcy5vcHRpb25zLndpZHRoID09PSAnZml0Jykge1xyXG4gICAgICAgIC8vIFJlbW92ZSBpbmxpbmUgbWluLXdpZHRoIHNvIHdpZHRoIGNhbiBiZSBjaGFuZ2VkIGZyb20gJ2F1dG8nXHJcbiAgICAgICAgdGhpcy4kbWVudS5jc3MoJ21pbi13aWR0aCcsICcnKTtcclxuICAgICAgICB0aGlzLiRuZXdFbGVtZW50LmNzcygnd2lkdGgnLCAnJykuYWRkQ2xhc3MoJ2ZpdC13aWR0aCcpO1xyXG4gICAgICB9IGVsc2UgaWYgKHRoaXMub3B0aW9ucy53aWR0aCkge1xyXG4gICAgICAgIC8vIFJlbW92ZSBpbmxpbmUgbWluLXdpZHRoIHNvIHdpZHRoIGNhbiBiZSBjaGFuZ2VkIGZyb20gJ2F1dG8nXHJcbiAgICAgICAgdGhpcy4kbWVudS5jc3MoJ21pbi13aWR0aCcsICcnKTtcclxuICAgICAgICB0aGlzLiRuZXdFbGVtZW50LmNzcygnd2lkdGgnLCB0aGlzLm9wdGlvbnMud2lkdGgpO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIC8vIFJlbW92ZSBpbmxpbmUgbWluLXdpZHRoL3dpZHRoIHNvIHdpZHRoIGNhbiBiZSBjaGFuZ2VkXHJcbiAgICAgICAgdGhpcy4kbWVudS5jc3MoJ21pbi13aWR0aCcsICcnKTtcclxuICAgICAgICB0aGlzLiRuZXdFbGVtZW50LmNzcygnd2lkdGgnLCAnJyk7XHJcbiAgICAgIH1cclxuICAgICAgLy8gUmVtb3ZlIGZpdC13aWR0aCBjbGFzcyBpZiB3aWR0aCBpcyBjaGFuZ2VkIHByb2dyYW1tYXRpY2FsbHlcclxuICAgICAgaWYgKHRoaXMuJG5ld0VsZW1lbnQuaGFzQ2xhc3MoJ2ZpdC13aWR0aCcpICYmIHRoaXMub3B0aW9ucy53aWR0aCAhPT0gJ2ZpdCcpIHtcclxuICAgICAgICB0aGlzLiRuZXdFbGVtZW50WzBdLmNsYXNzTGlzdC5yZW1vdmUoJ2ZpdC13aWR0aCcpO1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG5cclxuICAgIHNlbGVjdFBvc2l0aW9uOiBmdW5jdGlvbiAoKSB7XHJcbiAgICAgIHRoaXMuJGJzQ29udGFpbmVyID0gJCgnPGRpdiBjbGFzcz1cImJzLWNvbnRhaW5lclwiIC8+Jyk7XHJcblxyXG4gICAgICB2YXIgdGhhdCA9IHRoaXMsXHJcbiAgICAgICAgICAkY29udGFpbmVyID0gJCh0aGlzLm9wdGlvbnMuY29udGFpbmVyKSxcclxuICAgICAgICAgIHBvcyxcclxuICAgICAgICAgIGNvbnRhaW5lclBvcyxcclxuICAgICAgICAgIGFjdHVhbEhlaWdodCxcclxuICAgICAgICAgIGdldFBsYWNlbWVudCA9IGZ1bmN0aW9uICgkZWxlbWVudCkge1xyXG4gICAgICAgICAgICB2YXIgY29udGFpbmVyUG9zaXRpb24gPSB7fSxcclxuICAgICAgICAgICAgICAgIC8vIGZhbGwgYmFjayB0byBkcm9wZG93bidzIGRlZmF1bHQgZGlzcGxheSBzZXR0aW5nIGlmIGRpc3BsYXkgaXMgbm90IG1hbnVhbGx5IHNldFxyXG4gICAgICAgICAgICAgICAgZGlzcGxheSA9IHRoYXQub3B0aW9ucy5kaXNwbGF5IHx8IChcclxuICAgICAgICAgICAgICAgICAgLy8gQm9vdHN0cmFwIDMgZG9lc24ndCBoYXZlICQuZm4uZHJvcGRvd24uQ29uc3RydWN0b3IuRGVmYXVsdFxyXG4gICAgICAgICAgICAgICAgICAkLmZuLmRyb3Bkb3duLkNvbnN0cnVjdG9yLkRlZmF1bHQgPyAkLmZuLmRyb3Bkb3duLkNvbnN0cnVjdG9yLkRlZmF1bHQuZGlzcGxheVxyXG4gICAgICAgICAgICAgICAgICA6IGZhbHNlXHJcbiAgICAgICAgICAgICAgICApO1xyXG5cclxuICAgICAgICAgICAgdGhhdC4kYnNDb250YWluZXIuYWRkQ2xhc3MoJGVsZW1lbnQuYXR0cignY2xhc3MnKS5yZXBsYWNlKC9mb3JtLWNvbnRyb2x8Zml0LXdpZHRoL2dpLCAnJykpLnRvZ2dsZUNsYXNzKGNsYXNzTmFtZXMuRFJPUFVQLCAkZWxlbWVudC5oYXNDbGFzcyhjbGFzc05hbWVzLkRST1BVUCkpO1xyXG4gICAgICAgICAgICBwb3MgPSAkZWxlbWVudC5vZmZzZXQoKTtcclxuXHJcbiAgICAgICAgICAgIGlmICghJGNvbnRhaW5lci5pcygnYm9keScpKSB7XHJcbiAgICAgICAgICAgICAgY29udGFpbmVyUG9zID0gJGNvbnRhaW5lci5vZmZzZXQoKTtcclxuICAgICAgICAgICAgICBjb250YWluZXJQb3MudG9wICs9IHBhcnNlSW50KCRjb250YWluZXIuY3NzKCdib3JkZXJUb3BXaWR0aCcpKSAtICRjb250YWluZXIuc2Nyb2xsVG9wKCk7XHJcbiAgICAgICAgICAgICAgY29udGFpbmVyUG9zLmxlZnQgKz0gcGFyc2VJbnQoJGNvbnRhaW5lci5jc3MoJ2JvcmRlckxlZnRXaWR0aCcpKSAtICRjb250YWluZXIuc2Nyb2xsTGVmdCgpO1xyXG4gICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgIGNvbnRhaW5lclBvcyA9IHsgdG9wOiAwLCBsZWZ0OiAwIH07XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIGFjdHVhbEhlaWdodCA9ICRlbGVtZW50Lmhhc0NsYXNzKGNsYXNzTmFtZXMuRFJPUFVQKSA/IDAgOiAkZWxlbWVudFswXS5vZmZzZXRIZWlnaHQ7XHJcblxyXG4gICAgICAgICAgICAvLyBCb290c3RyYXAgNCsgdXNlcyBQb3BwZXIgZm9yIG1lbnUgcG9zaXRpb25pbmdcclxuICAgICAgICAgICAgaWYgKHZlcnNpb24ubWFqb3IgPCA0IHx8IGRpc3BsYXkgPT09ICdzdGF0aWMnKSB7XHJcbiAgICAgICAgICAgICAgY29udGFpbmVyUG9zaXRpb24udG9wID0gcG9zLnRvcCAtIGNvbnRhaW5lclBvcy50b3AgKyBhY3R1YWxIZWlnaHQ7XHJcbiAgICAgICAgICAgICAgY29udGFpbmVyUG9zaXRpb24ubGVmdCA9IHBvcy5sZWZ0IC0gY29udGFpbmVyUG9zLmxlZnQ7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIGNvbnRhaW5lclBvc2l0aW9uLndpZHRoID0gJGVsZW1lbnRbMF0ub2Zmc2V0V2lkdGg7XHJcblxyXG4gICAgICAgICAgICB0aGF0LiRic0NvbnRhaW5lci5jc3MoY29udGFpbmVyUG9zaXRpb24pO1xyXG4gICAgICAgICAgfTtcclxuXHJcbiAgICAgIHRoaXMuJGJ1dHRvbi5vbignY2xpY2suYnMuZHJvcGRvd24uZGF0YS1hcGknLCBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgaWYgKHRoYXQuaXNEaXNhYmxlZCgpKSB7XHJcbiAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBnZXRQbGFjZW1lbnQodGhhdC4kbmV3RWxlbWVudCk7XHJcblxyXG4gICAgICAgIHRoYXQuJGJzQ29udGFpbmVyXHJcbiAgICAgICAgICAuYXBwZW5kVG8odGhhdC5vcHRpb25zLmNvbnRhaW5lcilcclxuICAgICAgICAgIC50b2dnbGVDbGFzcyhjbGFzc05hbWVzLlNIT1csICF0aGF0LiRidXR0b24uaGFzQ2xhc3MoY2xhc3NOYW1lcy5TSE9XKSlcclxuICAgICAgICAgIC5hcHBlbmQodGhhdC4kbWVudSk7XHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgJCh3aW5kb3cpXHJcbiAgICAgICAgLm9mZigncmVzaXplJyArIEVWRU5UX0tFWSArICcuJyArIHRoaXMuc2VsZWN0SWQgKyAnIHNjcm9sbCcgKyBFVkVOVF9LRVkgKyAnLicgKyB0aGlzLnNlbGVjdElkKVxyXG4gICAgICAgIC5vbigncmVzaXplJyArIEVWRU5UX0tFWSArICcuJyArIHRoaXMuc2VsZWN0SWQgKyAnIHNjcm9sbCcgKyBFVkVOVF9LRVkgKyAnLicgKyB0aGlzLnNlbGVjdElkLCBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICB2YXIgaXNBY3RpdmUgPSB0aGF0LiRuZXdFbGVtZW50Lmhhc0NsYXNzKGNsYXNzTmFtZXMuU0hPVyk7XHJcblxyXG4gICAgICAgICAgaWYgKGlzQWN0aXZlKSBnZXRQbGFjZW1lbnQodGhhdC4kbmV3RWxlbWVudCk7XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICB0aGlzLiRlbGVtZW50Lm9uKCdoaWRlJyArIEVWRU5UX0tFWSwgZnVuY3Rpb24gKCkge1xyXG4gICAgICAgIHRoYXQuJG1lbnUuZGF0YSgnaGVpZ2h0JywgdGhhdC4kbWVudS5oZWlnaHQoKSk7XHJcbiAgICAgICAgdGhhdC4kYnNDb250YWluZXIuZGV0YWNoKCk7XHJcbiAgICAgIH0pO1xyXG4gICAgfSxcclxuXHJcbiAgICBjcmVhdGVPcHRpb246IGZ1bmN0aW9uIChkYXRhLCBpbml0KSB7XHJcbiAgICAgIHZhciBvcHRpb25EYXRhID0gIWRhdGEub3B0aW9uID8gZGF0YSA6IGRhdGEub3B0aW9uO1xyXG5cclxuICAgICAgaWYgKG9wdGlvbkRhdGEgJiYgb3B0aW9uRGF0YS5ub2RlVHlwZSAhPT0gMSkge1xyXG4gICAgICAgIHZhciBvcHRpb24gPSAoaW5pdCA/IGVsZW1lbnRUZW1wbGF0ZXMuc2VsZWN0ZWRPcHRpb24gOiBlbGVtZW50VGVtcGxhdGVzLm9wdGlvbikuY2xvbmVOb2RlKHRydWUpO1xyXG4gICAgICAgIGlmIChvcHRpb25EYXRhLnZhbHVlICE9PSB1bmRlZmluZWQpIG9wdGlvbi52YWx1ZSA9IG9wdGlvbkRhdGEudmFsdWU7XHJcbiAgICAgICAgb3B0aW9uLnRleHRDb250ZW50ID0gb3B0aW9uRGF0YS50ZXh0O1xyXG5cclxuICAgICAgICBvcHRpb24uc2VsZWN0ZWQgPSB0cnVlO1xyXG5cclxuICAgICAgICBpZiAob3B0aW9uRGF0YS5saUluZGV4ICE9PSB1bmRlZmluZWQpIHtcclxuICAgICAgICAgIG9wdGlvbi5saUluZGV4ID0gb3B0aW9uRGF0YS5saUluZGV4O1xyXG4gICAgICAgIH0gZWxzZSBpZiAoIWluaXQpIHtcclxuICAgICAgICAgIG9wdGlvbi5saUluZGV4ID0gZGF0YS5pbmRleDtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGRhdGEub3B0aW9uID0gb3B0aW9uO1xyXG5cclxuICAgICAgICB0aGlzLnNlbGVjdHBpY2tlci5tYWluLm9wdGlvblF1ZXVlLmFwcGVuZENoaWxkKG9wdGlvbik7XHJcbiAgICAgIH1cclxuICAgIH0sXHJcblxyXG4gICAgc2V0T3B0aW9uU3RhdHVzOiBmdW5jdGlvbiAoc2VsZWN0ZWRPbmx5KSB7XHJcbiAgICAgIHZhciB0aGF0ID0gdGhpcztcclxuXHJcbiAgICAgIHRoYXQubm9TY3JvbGwgPSBmYWxzZTtcclxuXHJcbiAgICAgIGlmICh0aGF0LnNlbGVjdHBpY2tlci52aWV3LnZpc2libGVFbGVtZW50cyAmJiB0aGF0LnNlbGVjdHBpY2tlci52aWV3LnZpc2libGVFbGVtZW50cy5sZW5ndGgpIHtcclxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoYXQuc2VsZWN0cGlja2VyLnZpZXcudmlzaWJsZUVsZW1lbnRzLmxlbmd0aDsgaSsrKSB7XHJcbiAgICAgICAgICB2YXIgbGlEYXRhID0gdGhhdC5zZWxlY3RwaWNrZXIuY3VycmVudC5kYXRhW2kgKyB0aGF0LnNlbGVjdHBpY2tlci52aWV3LnBvc2l0aW9uMF0sXHJcbiAgICAgICAgICAgICAgb3B0aW9uID0gbGlEYXRhLm9wdGlvbjtcclxuXHJcbiAgICAgICAgICBpZiAob3B0aW9uKSB7XHJcbiAgICAgICAgICAgIGlmIChzZWxlY3RlZE9ubHkgIT09IHRydWUpIHtcclxuICAgICAgICAgICAgICB0aGF0LnNldERpc2FibGVkKGxpRGF0YSk7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIHRoYXQuc2V0U2VsZWN0ZWQobGlEYXRhKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIGFwcGVuZCBvcHRpb25RdWV1ZSAoZG9jdW1lbnRGcmFnbWVudCB3aXRoIG9wdGlvbiBlbGVtZW50cyBmb3Igc2VsZWN0IG9wdGlvbnMpXHJcbiAgICAgICAgaWYgKHRoaXMub3B0aW9ucy5zb3VyY2UuZGF0YSkgdGhpcy4kZWxlbWVudFswXS5hcHBlbmRDaGlsZCh0aGlzLnNlbGVjdHBpY2tlci5tYWluLm9wdGlvblF1ZXVlKTtcclxuICAgICAgfVxyXG4gICAgfSxcclxuXHJcbiAgICAvKipcclxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBpbmRleCAtIHRoZSBpbmRleCBvZiB0aGUgb3B0aW9uIHRoYXQgaXMgYmVpbmcgY2hhbmdlZFxyXG4gICAgICogQHBhcmFtIHtib29sZWFufSBzZWxlY3RlZCAtIHRydWUgaWYgdGhlIG9wdGlvbiBpcyBiZWluZyBzZWxlY3RlZCwgZmFsc2UgaWYgYmVpbmcgZGVzZWxlY3RlZFxyXG4gICAgICovXHJcbiAgICBzZXRTZWxlY3RlZDogZnVuY3Rpb24gKGxpRGF0YSwgc2VsZWN0ZWQpIHtcclxuICAgICAgc2VsZWN0ZWQgPSBzZWxlY3RlZCA9PT0gdW5kZWZpbmVkID8gbGlEYXRhLnNlbGVjdGVkIDogc2VsZWN0ZWQ7XHJcblxyXG4gICAgICB2YXIgaW5kZXggPSBsaURhdGEuaW5kZXgsXHJcbiAgICAgICAgICBsaSA9IGxpRGF0YS5lbGVtZW50LFxyXG4gICAgICAgICAgYWN0aXZlSW5kZXhJc1NldCA9IHRoaXMuYWN0aXZlSW5kZXggIT09IHVuZGVmaW5lZCxcclxuICAgICAgICAgIHRoaXNJc0FjdGl2ZSA9IHRoaXMuYWN0aXZlSW5kZXggPT09IGluZGV4LFxyXG4gICAgICAgICAgcHJldkFjdGl2ZSxcclxuICAgICAgICAgIGEsXHJcbiAgICAgICAgICAvLyBpZiBjdXJyZW50IG9wdGlvbiBpcyBhbHJlYWR5IGFjdGl2ZVxyXG4gICAgICAgICAgLy8gT1JcclxuICAgICAgICAgIC8vIGlmIHRoZSBjdXJyZW50IG9wdGlvbiBpcyBiZWluZyBzZWxlY3RlZCwgaXQncyBOT1QgbXVsdGlwbGUsIGFuZFxyXG4gICAgICAgICAgLy8gYWN0aXZlSW5kZXggaXMgdW5kZWZpbmVkOlxyXG4gICAgICAgICAgLy8gIC0gd2hlbiB0aGUgbWVudSBpcyBmaXJzdCBiZWluZyBvcGVuZWQsIE9SXHJcbiAgICAgICAgICAvLyAgLSBhZnRlciBhIHNlYXJjaCBoYXMgYmVlbiBwZXJmb3JtZWQsIE9SXHJcbiAgICAgICAgICAvLyAgLSB3aGVuIHJldGFpbkFjdGl2ZSBpcyBmYWxzZSB3aGVuIHNlbGVjdGluZyBhIG5ldyBvcHRpb24gKGkuZS4gaW5kZXggb2YgdGhlIG5ld2x5IHNlbGVjdGVkIG9wdGlvbiBpcyBub3QgdGhlIHNhbWUgYXMgdGhlIGN1cnJlbnQgYWN0aXZlSW5kZXgpXHJcbiAgICAgICAgICBrZWVwQWN0aXZlID0gdGhpc0lzQWN0aXZlIHx8IChzZWxlY3RlZCAmJiAhdGhpcy5tdWx0aXBsZSAmJiAhYWN0aXZlSW5kZXhJc1NldCk7XHJcblxyXG4gICAgICBpZiAoIWxpKSByZXR1cm47XHJcblxyXG4gICAgICBpZiAoc2VsZWN0ZWQgIT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgIGxpRGF0YS5zZWxlY3RlZCA9IHNlbGVjdGVkO1xyXG4gICAgICAgIGlmIChsaURhdGEub3B0aW9uKSBsaURhdGEub3B0aW9uLnNlbGVjdGVkID0gc2VsZWN0ZWQ7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmIChzZWxlY3RlZCAmJiB0aGlzLm9wdGlvbnMuc291cmNlLmRhdGEpIHtcclxuICAgICAgICB0aGlzLmNyZWF0ZU9wdGlvbihsaURhdGEsIGZhbHNlKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgYSA9IGxpLmZpcnN0Q2hpbGQ7XHJcblxyXG4gICAgICBpZiAoc2VsZWN0ZWQpIHtcclxuICAgICAgICB0aGlzLnNlbGVjdGVkSW5kZXggPSBpbmRleDtcclxuICAgICAgfVxyXG5cclxuICAgICAgbGkuY2xhc3NMaXN0LnRvZ2dsZSgnc2VsZWN0ZWQnLCBzZWxlY3RlZCk7XHJcblxyXG4gICAgICBpZiAoa2VlcEFjdGl2ZSkge1xyXG4gICAgICAgIHRoaXMuZm9jdXNJdGVtKGxpLCBsaURhdGEpO1xyXG4gICAgICAgIHRoaXMuc2VsZWN0cGlja2VyLnZpZXcuY3VycmVudEFjdGl2ZSA9IGxpO1xyXG4gICAgICAgIHRoaXMuYWN0aXZlSW5kZXggPSBpbmRleDtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICB0aGlzLmRlZm9jdXNJdGVtKGxpKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKGEpIHtcclxuICAgICAgICBhLmNsYXNzTGlzdC50b2dnbGUoJ3NlbGVjdGVkJywgc2VsZWN0ZWQpO1xyXG5cclxuICAgICAgICBpZiAoc2VsZWN0ZWQpIHtcclxuICAgICAgICAgIGEuc2V0QXR0cmlidXRlKCdhcmlhLXNlbGVjdGVkJywgdHJ1ZSk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIGlmICh0aGlzLm11bHRpcGxlKSB7XHJcbiAgICAgICAgICAgIGEuc2V0QXR0cmlidXRlKCdhcmlhLXNlbGVjdGVkJywgZmFsc2UpO1xyXG4gICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgYS5yZW1vdmVBdHRyaWJ1dGUoJ2FyaWEtc2VsZWN0ZWQnKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmICgha2VlcEFjdGl2ZSAmJiAhYWN0aXZlSW5kZXhJc1NldCAmJiBzZWxlY3RlZCAmJiB0aGlzLnByZXZBY3RpdmVJbmRleCAhPT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgICAgcHJldkFjdGl2ZSA9IHRoaXMuc2VsZWN0cGlja2VyLm1haW4uZWxlbWVudHNbdGhpcy5wcmV2QWN0aXZlSW5kZXhdO1xyXG5cclxuICAgICAgICB0aGlzLmRlZm9jdXNJdGVtKHByZXZBY3RpdmUpO1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG5cclxuICAgIC8qKlxyXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IGluZGV4IC0gdGhlIGluZGV4IG9mIHRoZSBvcHRpb24gdGhhdCBpcyBiZWluZyBkaXNhYmxlZFxyXG4gICAgICogQHBhcmFtIHtib29sZWFufSBkaXNhYmxlZCAtIHRydWUgaWYgdGhlIG9wdGlvbiBpcyBiZWluZyBkaXNhYmxlZCwgZmFsc2UgaWYgYmVpbmcgZW5hYmxlZFxyXG4gICAgICovXHJcbiAgICBzZXREaXNhYmxlZDogZnVuY3Rpb24gKGxpRGF0YSkge1xyXG4gICAgICB2YXIgZGlzYWJsZWQgPSBsaURhdGEuZGlzYWJsZWQsXHJcbiAgICAgICAgICBsaSA9IGxpRGF0YS5lbGVtZW50LFxyXG4gICAgICAgICAgYTtcclxuXHJcbiAgICAgIGlmICghbGkpIHJldHVybjtcclxuXHJcbiAgICAgIGEgPSBsaS5maXJzdENoaWxkO1xyXG5cclxuICAgICAgbGkuY2xhc3NMaXN0LnRvZ2dsZShjbGFzc05hbWVzLkRJU0FCTEVELCBkaXNhYmxlZCk7XHJcblxyXG4gICAgICBpZiAoYSkge1xyXG4gICAgICAgIGlmICh2ZXJzaW9uLm1ham9yID49ICc0JykgYS5jbGFzc0xpc3QudG9nZ2xlKGNsYXNzTmFtZXMuRElTQUJMRUQsIGRpc2FibGVkKTtcclxuXHJcbiAgICAgICAgaWYgKGRpc2FibGVkKSB7XHJcbiAgICAgICAgICBhLnNldEF0dHJpYnV0ZSgnYXJpYS1kaXNhYmxlZCcsIGRpc2FibGVkKTtcclxuICAgICAgICAgIGEuc2V0QXR0cmlidXRlKCd0YWJpbmRleCcsIC0xKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgYS5yZW1vdmVBdHRyaWJ1dGUoJ2FyaWEtZGlzYWJsZWQnKTtcclxuICAgICAgICAgIGEuc2V0QXR0cmlidXRlKCd0YWJpbmRleCcsIDApO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfSxcclxuXHJcbiAgICBpc0Rpc2FibGVkOiBmdW5jdGlvbiAoKSB7XHJcbiAgICAgIHJldHVybiB0aGlzLiRlbGVtZW50WzBdLmRpc2FibGVkO1xyXG4gICAgfSxcclxuXHJcbiAgICBjaGVja0Rpc2FibGVkOiBmdW5jdGlvbiAoKSB7XHJcbiAgICAgIGlmICh0aGlzLmlzRGlzYWJsZWQoKSkge1xyXG4gICAgICAgIHRoaXMuJG5ld0VsZW1lbnRbMF0uY2xhc3NMaXN0LmFkZChjbGFzc05hbWVzLkRJU0FCTEVEKTtcclxuICAgICAgICB0aGlzLiRidXR0b24uYWRkQ2xhc3MoY2xhc3NOYW1lcy5ESVNBQkxFRCkuYXR0cignYXJpYS1kaXNhYmxlZCcsIHRydWUpO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIGlmICh0aGlzLiRidXR0b25bMF0uY2xhc3NMaXN0LmNvbnRhaW5zKGNsYXNzTmFtZXMuRElTQUJMRUQpKSB7XHJcbiAgICAgICAgICB0aGlzLiRuZXdFbGVtZW50WzBdLmNsYXNzTGlzdC5yZW1vdmUoY2xhc3NOYW1lcy5ESVNBQkxFRCk7XHJcbiAgICAgICAgICB0aGlzLiRidXR0b24ucmVtb3ZlQ2xhc3MoY2xhc3NOYW1lcy5ESVNBQkxFRCkuYXR0cignYXJpYS1kaXNhYmxlZCcsIGZhbHNlKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH0sXHJcblxyXG4gICAgY2xpY2tMaXN0ZW5lcjogZnVuY3Rpb24gKCkge1xyXG4gICAgICB2YXIgdGhhdCA9IHRoaXMsXHJcbiAgICAgICAgICAkZG9jdW1lbnQgPSAkKGRvY3VtZW50KTtcclxuXHJcbiAgICAgICRkb2N1bWVudC5kYXRhKCdzcGFjZVNlbGVjdCcsIGZhbHNlKTtcclxuXHJcbiAgICAgIHRoaXMuJGJ1dHRvbi5vbigna2V5dXAnLCBmdW5jdGlvbiAoZSkge1xyXG4gICAgICAgIGlmICgvKDMyKS8udGVzdChlLmtleUNvZGUudG9TdHJpbmcoMTApKSAmJiAkZG9jdW1lbnQuZGF0YSgnc3BhY2VTZWxlY3QnKSkge1xyXG4gICAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xyXG4gICAgICAgICAgJGRvY3VtZW50LmRhdGEoJ3NwYWNlU2VsZWN0JywgZmFsc2UpO1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcblxyXG4gICAgICB0aGlzLiRuZXdFbGVtZW50Lm9uKCdzaG93LmJzLmRyb3Bkb3duJywgZnVuY3Rpb24gKCkge1xyXG4gICAgICAgIGlmICghdGhhdC5kcm9wZG93biAmJiB2ZXJzaW9uLm1ham9yID09PSAnNCcpIHtcclxuICAgICAgICAgIHRoYXQuZHJvcGRvd24gPSB0aGF0LiRidXR0b24uZGF0YSgnYnMuZHJvcGRvd24nKTtcclxuICAgICAgICAgIHRoYXQuZHJvcGRvd24uX21lbnUgPSB0aGF0LiRtZW51WzBdO1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcblxyXG4gICAgICBmdW5jdGlvbiBjbGVhclNlbGVjdGlvbiAoZSkge1xyXG4gICAgICAgIGlmICh0aGF0Lm11bHRpcGxlKSB7XHJcbiAgICAgICAgICB0aGF0LmRlc2VsZWN0QWxsKCk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIHZhciBlbGVtZW50ID0gdGhhdC4kZWxlbWVudFswXSxcclxuICAgICAgICAgICAgICBwcmV2VmFsdWUgPSBlbGVtZW50LnZhbHVlLFxyXG4gICAgICAgICAgICAgIHByZXZJbmRleCA9IGVsZW1lbnQuc2VsZWN0ZWRJbmRleCxcclxuICAgICAgICAgICAgICBwcmV2T3B0aW9uID0gZWxlbWVudC5vcHRpb25zW3ByZXZJbmRleF0sXHJcbiAgICAgICAgICAgICAgcHJldkRhdGEgPSBwcmV2T3B0aW9uID8gdGhhdC5zZWxlY3RwaWNrZXIubWFpbi5kYXRhW3ByZXZPcHRpb24ubGlJbmRleF0gOiBmYWxzZTtcclxuXHJcbiAgICAgICAgICBpZiAocHJldkRhdGEpIHtcclxuICAgICAgICAgICAgdGhhdC5zZXRTZWxlY3RlZChwcmV2RGF0YSwgZmFsc2UpO1xyXG4gICAgICAgICAgfVxyXG5cclxuICAgICAgICAgIGVsZW1lbnQuc2VsZWN0ZWRJbmRleCA9IDA7XHJcblxyXG4gICAgICAgICAgY2hhbmdlZEFyZ3VtZW50cyA9IFtwcmV2SW5kZXgsIGZhbHNlLCBwcmV2VmFsdWVdO1xyXG4gICAgICAgICAgdGhhdC4kZWxlbWVudC50cmlnZ2VyTmF0aXZlKCdjaGFuZ2UnKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIHJlbW92ZSBzZWxlY3RlZCBzdHlsaW5nIGlmIG1lbnUgaXMgb3BlblxyXG4gICAgICAgIGlmICh0aGF0LiRuZXdFbGVtZW50Lmhhc0NsYXNzKGNsYXNzTmFtZXMuU0hPVykpIHtcclxuICAgICAgICAgIGlmICh0aGF0Lm9wdGlvbnMubGl2ZVNlYXJjaCkge1xyXG4gICAgICAgICAgICB0aGF0LiRzZWFyY2hib3gudHJpZ2dlcignZm9jdXMnKTtcclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICB0aGF0LmNyZWF0ZVZpZXcoZmFsc2UpO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgdGhpcy4kYnV0dG9uLm9uKCdjbGljay5icy5kcm9wZG93bi5kYXRhLWFwaScsIGZ1bmN0aW9uIChlKSB7XHJcbiAgICAgICAgaWYgKHRoYXQub3B0aW9ucy5hbGxvd0NsZWFyKSB7XHJcbiAgICAgICAgICB2YXIgdGFyZ2V0ID0gZS50YXJnZXQsXHJcbiAgICAgICAgICAgICAgY2xlYXJCdXR0b24gPSB0aGF0LiRjbGVhckJ1dHRvblswXTtcclxuXHJcbiAgICAgICAgICAvLyBJRSBkb2Vzbid0IHN1cHBvcnQgZXZlbnQgbGlzdGVuZXJzIG9uIGNoaWxkIGVsZW1lbnRzIG9mIGJ1dHRvbnNcclxuICAgICAgICAgIGlmICgvTVNJRXxUcmlkZW50Ly50ZXN0KHdpbmRvdy5uYXZpZ2F0b3IudXNlckFnZW50KSkge1xyXG4gICAgICAgICAgICB0YXJnZXQgPSBkb2N1bWVudC5lbGVtZW50RnJvbVBvaW50KGUuY2xpZW50WCwgZS5jbGllbnRZKTtcclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICBpZiAodGFyZ2V0ID09PSBjbGVhckJ1dHRvbiB8fCB0YXJnZXQucGFyZW50RWxlbWVudCA9PT0gY2xlYXJCdXR0b24pIHtcclxuICAgICAgICAgICAgZS5zdG9wSW1tZWRpYXRlUHJvcGFnYXRpb24oKTtcclxuICAgICAgICAgICAgY2xlYXJTZWxlY3Rpb24oZSk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBpZiAoIXRoYXQuJG5ld0VsZW1lbnQuaGFzQ2xhc3MoY2xhc3NOYW1lcy5TSE9XKSkge1xyXG4gICAgICAgICAgdGhhdC5zZXRTaXplKCk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9KTtcclxuXHJcbiAgICAgIGZ1bmN0aW9uIHNldEZvY3VzICgpIHtcclxuICAgICAgICBpZiAodGhhdC5vcHRpb25zLmxpdmVTZWFyY2gpIHtcclxuICAgICAgICAgIHRoYXQuJHNlYXJjaGJveC50cmlnZ2VyKCdmb2N1cycpO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICB0aGF0LiRtZW51SW5uZXIudHJpZ2dlcignZm9jdXMnKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGZ1bmN0aW9uIGNoZWNrUG9wcGVyRXhpc3RzICgpIHtcclxuICAgICAgICBpZiAodGhhdC5kcm9wZG93biAmJiB0aGF0LmRyb3Bkb3duLl9wb3BwZXIgJiYgdGhhdC5kcm9wZG93bi5fcG9wcGVyLnN0YXRlKSB7XHJcbiAgICAgICAgICBzZXRGb2N1cygpO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICByZXF1ZXN0QW5pbWF0aW9uRnJhbWUoY2hlY2tQb3BwZXJFeGlzdHMpO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgdGhpcy4kZWxlbWVudC5vbignc2hvd24nICsgRVZFTlRfS0VZLCBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgaWYgKHRoYXQuJG1lbnVJbm5lclswXS5zY3JvbGxUb3AgIT09IHRoYXQuc2VsZWN0cGlja2VyLnZpZXcuc2Nyb2xsVG9wKSB7XHJcbiAgICAgICAgICB0aGF0LiRtZW51SW5uZXJbMF0uc2Nyb2xsVG9wID0gdGhhdC5zZWxlY3RwaWNrZXIudmlldy5zY3JvbGxUb3A7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBpZiAodmVyc2lvbi5tYWpvciA+IDMpIHtcclxuICAgICAgICAgIHJlcXVlc3RBbmltYXRpb25GcmFtZShjaGVja1BvcHBlckV4aXN0cyk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIHNldEZvY3VzKCk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9KTtcclxuXHJcbiAgICAgIC8vIGVuc3VyZSBwb3NpbnNldCBhbmQgc2V0c2l6ZSBhcmUgY29ycmVjdCBiZWZvcmUgc2VsZWN0aW5nIGFuIG9wdGlvbiB2aWEgYSBjbGlja1xyXG4gICAgICB0aGlzLiRtZW51SW5uZXIub24oJ21vdXNlZW50ZXInLCAnbGkgYScsIGZ1bmN0aW9uIChlKSB7XHJcbiAgICAgICAgdmFyIGhvdmVyTGkgPSB0aGlzLnBhcmVudEVsZW1lbnQsXHJcbiAgICAgICAgICAgIHBvc2l0aW9uMCA9IHRoYXQuaXNWaXJ0dWFsKCkgPyB0aGF0LnNlbGVjdHBpY2tlci52aWV3LnBvc2l0aW9uMCA6IDAsXHJcbiAgICAgICAgICAgIGluZGV4ID0gQXJyYXkucHJvdG90eXBlLmluZGV4T2YuY2FsbChob3ZlckxpLnBhcmVudEVsZW1lbnQuY2hpbGRyZW4sIGhvdmVyTGkpLFxyXG4gICAgICAgICAgICBob3ZlckRhdGEgPSB0aGF0LnNlbGVjdHBpY2tlci5jdXJyZW50LmRhdGFbaW5kZXggKyBwb3NpdGlvbjBdO1xyXG5cclxuICAgICAgICB0aGF0LmZvY3VzSXRlbShob3ZlckxpLCBob3ZlckRhdGEsIHRydWUpO1xyXG4gICAgICB9KTtcclxuXHJcbiAgICAgIHRoaXMuJG1lbnVJbm5lci5vbignY2xpY2snLCAnbGkgYScsIGZ1bmN0aW9uIChlLCByZXRhaW5BY3RpdmUpIHtcclxuICAgICAgICB2YXIgJHRoaXMgPSAkKHRoaXMpLFxyXG4gICAgICAgICAgICBlbGVtZW50ID0gdGhhdC4kZWxlbWVudFswXSxcclxuICAgICAgICAgICAgcG9zaXRpb24wID0gdGhhdC5pc1ZpcnR1YWwoKSA/IHRoYXQuc2VsZWN0cGlja2VyLnZpZXcucG9zaXRpb24wIDogMCxcclxuICAgICAgICAgICAgY2xpY2tlZERhdGEgPSB0aGF0LnNlbGVjdHBpY2tlci5jdXJyZW50LmRhdGFbJHRoaXMucGFyZW50KCkuaW5kZXgoKSArIHBvc2l0aW9uMF0sXHJcbiAgICAgICAgICAgIGNsaWNrZWRJbmRleCA9IGNsaWNrZWREYXRhLmluZGV4LFxyXG4gICAgICAgICAgICBwcmV2VmFsdWUgPSBnZXRTZWxlY3RWYWx1ZXMuY2FsbCh0aGF0KSxcclxuICAgICAgICAgICAgcHJldkluZGV4ID0gZWxlbWVudC5zZWxlY3RlZEluZGV4LFxyXG4gICAgICAgICAgICBwcmV2T3B0aW9uID0gZWxlbWVudC5vcHRpb25zW3ByZXZJbmRleF0sXHJcbiAgICAgICAgICAgIHByZXZEYXRhID0gcHJldk9wdGlvbiA/IHRoYXQuc2VsZWN0cGlja2VyLm1haW4uZGF0YVtwcmV2T3B0aW9uLmxpSW5kZXhdIDogZmFsc2UsXHJcbiAgICAgICAgICAgIHRyaWdnZXJDaGFuZ2UgPSB0cnVlO1xyXG5cclxuICAgICAgICAvLyBEb24ndCBjbG9zZSBvbiBtdWx0aSBjaG9pY2UgbWVudVxyXG4gICAgICAgIGlmICh0aGF0Lm11bHRpcGxlICYmIHRoYXQub3B0aW9ucy5tYXhPcHRpb25zICE9PSAxKSB7XHJcbiAgICAgICAgICBlLnN0b3BQcm9wYWdhdGlvbigpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xyXG5cclxuICAgICAgICAvLyBEb24ndCBydW4gaWYgdGhlIHNlbGVjdCBpcyBkaXNhYmxlZFxyXG4gICAgICAgIGlmICghdGhhdC5pc0Rpc2FibGVkKCkgJiYgISR0aGlzLnBhcmVudCgpLmhhc0NsYXNzKGNsYXNzTmFtZXMuRElTQUJMRUQpKSB7XHJcbiAgICAgICAgICB2YXIgb3B0aW9uID0gY2xpY2tlZERhdGEub3B0aW9uLFxyXG4gICAgICAgICAgICAgICRvcHRpb24gPSAkKG9wdGlvbiksXHJcbiAgICAgICAgICAgICAgc3RhdGUgPSBvcHRpb24uc2VsZWN0ZWQsXHJcbiAgICAgICAgICAgICAgJG9wdGdyb3VwID0gJG9wdGlvbi5wYXJlbnQoJ29wdGdyb3VwJyksXHJcbiAgICAgICAgICAgICAgJG9wdGdyb3VwT3B0aW9ucyA9ICRvcHRncm91cC5maW5kKCdvcHRpb24nKSxcclxuICAgICAgICAgICAgICBtYXhPcHRpb25zID0gdGhhdC5vcHRpb25zLm1heE9wdGlvbnMsXHJcbiAgICAgICAgICAgICAgbWF4T3B0aW9uc0dycCA9ICRvcHRncm91cC5kYXRhKCdtYXhPcHRpb25zJykgfHwgZmFsc2U7XHJcblxyXG4gICAgICAgICAgaWYgKGNsaWNrZWRJbmRleCA9PT0gdGhhdC5hY3RpdmVJbmRleCkgcmV0YWluQWN0aXZlID0gdHJ1ZTtcclxuXHJcbiAgICAgICAgICBpZiAoIXJldGFpbkFjdGl2ZSkge1xyXG4gICAgICAgICAgICB0aGF0LnByZXZBY3RpdmVJbmRleCA9IHRoYXQuYWN0aXZlSW5kZXg7XHJcbiAgICAgICAgICAgIHRoYXQuYWN0aXZlSW5kZXggPSB1bmRlZmluZWQ7XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgaWYgKCF0aGF0Lm11bHRpcGxlKSB7IC8vIERlc2VsZWN0IHByZXZpb3VzIG9wdGlvbiBpZiBub3QgbXVsdGkgc2VsZWN0XHJcbiAgICAgICAgICAgIGlmIChwcmV2RGF0YSkgdGhhdC5zZXRTZWxlY3RlZChwcmV2RGF0YSwgZmFsc2UpO1xyXG4gICAgICAgICAgICB0aGF0LnNldFNlbGVjdGVkKGNsaWNrZWREYXRhLCB0cnVlKTtcclxuICAgICAgICAgIH0gZWxzZSB7IC8vIFRvZ2dsZSB0aGUgY2xpY2tlZCBvcHRpb24gaWYgbXVsdGkgc2VsZWN0LlxyXG4gICAgICAgICAgICB0aGF0LnNldFNlbGVjdGVkKGNsaWNrZWREYXRhLCAhc3RhdGUpO1xyXG4gICAgICAgICAgICB0aGF0LmZvY3VzZWRQYXJlbnQuZm9jdXMoKTtcclxuXHJcbiAgICAgICAgICAgIGlmIChtYXhPcHRpb25zICE9PSBmYWxzZSB8fCBtYXhPcHRpb25zR3JwICE9PSBmYWxzZSkge1xyXG4gICAgICAgICAgICAgIHZhciBtYXhSZWFjaGVkID0gbWF4T3B0aW9ucyA8IGdldFNlbGVjdGVkT3B0aW9ucy5jYWxsKHRoYXQpLmxlbmd0aCxcclxuICAgICAgICAgICAgICAgICAgbWF4UmVhY2hlZEdycCA9IG1heE9wdGlvbnNHcnAgPCAkb3B0Z3JvdXAuZmluZCgnb3B0aW9uOnNlbGVjdGVkJykubGVuZ3RoO1xyXG5cclxuICAgICAgICAgICAgICBpZiAoKG1heE9wdGlvbnMgJiYgbWF4UmVhY2hlZCkgfHwgKG1heE9wdGlvbnNHcnAgJiYgbWF4UmVhY2hlZEdycCkpIHtcclxuICAgICAgICAgICAgICAgIGlmIChtYXhPcHRpb25zICYmIG1heE9wdGlvbnMgPT0gMSkge1xyXG4gICAgICAgICAgICAgICAgICBlbGVtZW50LnNlbGVjdGVkSW5kZXggPSAtMTtcclxuICAgICAgICAgICAgICAgICAgb3B0aW9uLnNlbGVjdGVkID0gdHJ1ZTtcclxuICAgICAgICAgICAgICAgICAgdGhhdC5zZXRPcHRpb25TdGF0dXModHJ1ZSk7XHJcbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKG1heE9wdGlvbnNHcnAgJiYgbWF4T3B0aW9uc0dycCA9PSAxKSB7XHJcbiAgICAgICAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgJG9wdGdyb3VwT3B0aW9ucy5sZW5ndGg7IGkrKykge1xyXG4gICAgICAgICAgICAgICAgICAgIHZhciBfb3B0aW9uID0gJG9wdGdyb3VwT3B0aW9uc1tpXTtcclxuICAgICAgICAgICAgICAgICAgICBfb3B0aW9uLnNlbGVjdGVkID0gZmFsc2U7XHJcbiAgICAgICAgICAgICAgICAgICAgdGhhdC5zZXRTZWxlY3RlZChfb3B0aW9uLmxpSW5kZXgsIGZhbHNlKTtcclxuICAgICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgICAgb3B0aW9uLnNlbGVjdGVkID0gdHJ1ZTtcclxuICAgICAgICAgICAgICAgICAgdGhhdC5zZXRTZWxlY3RlZChjbGlja2VkSW5kZXgsIHRydWUpO1xyXG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgICAgdmFyIG1heE9wdGlvbnNUZXh0ID0gdHlwZW9mIHRoYXQub3B0aW9ucy5tYXhPcHRpb25zVGV4dCA9PT0gJ3N0cmluZycgPyBbdGhhdC5vcHRpb25zLm1heE9wdGlvbnNUZXh0LCB0aGF0Lm9wdGlvbnMubWF4T3B0aW9uc1RleHRdIDogdGhhdC5vcHRpb25zLm1heE9wdGlvbnNUZXh0LFxyXG4gICAgICAgICAgICAgICAgICAgICAgbWF4T3B0aW9uc0FyciA9IHR5cGVvZiBtYXhPcHRpb25zVGV4dCA9PT0gJ2Z1bmN0aW9uJyA/IG1heE9wdGlvbnNUZXh0KG1heE9wdGlvbnMsIG1heE9wdGlvbnNHcnApIDogbWF4T3B0aW9uc1RleHQsXHJcbiAgICAgICAgICAgICAgICAgICAgICBtYXhUeHQgPSBtYXhPcHRpb25zQXJyWzBdLnJlcGxhY2UoJ3tufScsIG1heE9wdGlvbnMpLFxyXG4gICAgICAgICAgICAgICAgICAgICAgbWF4VHh0R3JwID0gbWF4T3B0aW9uc0FyclsxXS5yZXBsYWNlKCd7bn0nLCBtYXhPcHRpb25zR3JwKSxcclxuICAgICAgICAgICAgICAgICAgICAgICRub3RpZnkgPSAkKCc8ZGl2IGNsYXNzPVwibm90aWZ5XCI+PC9kaXY+Jyk7XHJcbiAgICAgICAgICAgICAgICAgIC8vIElmIHt2YXJ9IGlzIHNldCBpbiBhcnJheSwgcmVwbGFjZSBpdFxyXG4gICAgICAgICAgICAgICAgICAvKiogQGRlcHJlY2F0ZWQgKi9cclxuICAgICAgICAgICAgICAgICAgaWYgKG1heE9wdGlvbnNBcnJbMl0pIHtcclxuICAgICAgICAgICAgICAgICAgICBtYXhUeHQgPSBtYXhUeHQucmVwbGFjZSgne3Zhcn0nLCBtYXhPcHRpb25zQXJyWzJdW21heE9wdGlvbnMgPiAxID8gMCA6IDFdKTtcclxuICAgICAgICAgICAgICAgICAgICBtYXhUeHRHcnAgPSBtYXhUeHRHcnAucmVwbGFjZSgne3Zhcn0nLCBtYXhPcHRpb25zQXJyWzJdW21heE9wdGlvbnNHcnAgPiAxID8gMCA6IDFdKTtcclxuICAgICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgICAgb3B0aW9uLnNlbGVjdGVkID0gZmFsc2U7XHJcblxyXG4gICAgICAgICAgICAgICAgICB0aGF0LiRtZW51LmFwcGVuZCgkbm90aWZ5KTtcclxuXHJcbiAgICAgICAgICAgICAgICAgIGlmIChtYXhPcHRpb25zICYmIG1heFJlYWNoZWQpIHtcclxuICAgICAgICAgICAgICAgICAgICAkbm90aWZ5LmFwcGVuZCgkKCc8ZGl2PicgKyBtYXhUeHQgKyAnPC9kaXY+JykpO1xyXG4gICAgICAgICAgICAgICAgICAgIHRyaWdnZXJDaGFuZ2UgPSBmYWxzZTtcclxuICAgICAgICAgICAgICAgICAgICB0aGF0LiRlbGVtZW50LnRyaWdnZXIoJ21heFJlYWNoZWQnICsgRVZFTlRfS0VZKTtcclxuICAgICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgICAgaWYgKG1heE9wdGlvbnNHcnAgJiYgbWF4UmVhY2hlZEdycCkge1xyXG4gICAgICAgICAgICAgICAgICAgICRub3RpZnkuYXBwZW5kKCQoJzxkaXY+JyArIG1heFR4dEdycCArICc8L2Rpdj4nKSk7XHJcbiAgICAgICAgICAgICAgICAgICAgdHJpZ2dlckNoYW5nZSA9IGZhbHNlO1xyXG4gICAgICAgICAgICAgICAgICAgIHRoYXQuJGVsZW1lbnQudHJpZ2dlcignbWF4UmVhY2hlZEdycCcgKyBFVkVOVF9LRVkpO1xyXG4gICAgICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgICAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgICAgICAgICB0aGF0LnNldFNlbGVjdGVkKGNsaWNrZWRJbmRleCwgZmFsc2UpO1xyXG4gICAgICAgICAgICAgICAgICB9LCAxMCk7XHJcblxyXG4gICAgICAgICAgICAgICAgICAkbm90aWZ5WzBdLmNsYXNzTGlzdC5hZGQoJ2ZhZGVPdXQnKTtcclxuXHJcbiAgICAgICAgICAgICAgICAgIHNldFRpbWVvdXQoZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICAgICAgICAgICRub3RpZnkucmVtb3ZlKCk7XHJcbiAgICAgICAgICAgICAgICAgIH0sIDEwNTApO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG5cclxuICAgICAgICAgIGlmICh0aGF0Lm9wdGlvbnMuc291cmNlLmRhdGEpIHRoYXQuJGVsZW1lbnRbMF0uYXBwZW5kQ2hpbGQodGhhdC5zZWxlY3RwaWNrZXIubWFpbi5vcHRpb25RdWV1ZSk7XHJcblxyXG4gICAgICAgICAgaWYgKCF0aGF0Lm11bHRpcGxlIHx8ICh0aGF0Lm11bHRpcGxlICYmIHRoYXQub3B0aW9ucy5tYXhPcHRpb25zID09PSAxKSkge1xyXG4gICAgICAgICAgICB0aGF0LiRidXR0b24udHJpZ2dlcignZm9jdXMnKTtcclxuICAgICAgICAgIH0gZWxzZSBpZiAodGhhdC5vcHRpb25zLmxpdmVTZWFyY2gpIHtcclxuICAgICAgICAgICAgdGhhdC4kc2VhcmNoYm94LnRyaWdnZXIoJ2ZvY3VzJyk7XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgLy8gVHJpZ2dlciBzZWxlY3QgJ2NoYW5nZSdcclxuICAgICAgICAgIGlmICh0cmlnZ2VyQ2hhbmdlKSB7XHJcbiAgICAgICAgICAgIGlmICh0aGF0Lm11bHRpcGxlIHx8IHByZXZJbmRleCAhPT0gZWxlbWVudC5zZWxlY3RlZEluZGV4KSB7XHJcbiAgICAgICAgICAgICAgLy8gJG9wdGlvbi5wcm9wKCdzZWxlY3RlZCcpIGlzIGN1cnJlbnQgb3B0aW9uIHN0YXRlIChzZWxlY3RlZC91bnNlbGVjdGVkKS4gcHJldlZhbHVlIGlzIHRoZSB2YWx1ZSBvZiB0aGUgc2VsZWN0IHByaW9yIHRvIGJlaW5nIGNoYW5nZWQuXHJcbiAgICAgICAgICAgICAgY2hhbmdlZEFyZ3VtZW50cyA9IFtvcHRpb24uaW5kZXgsICRvcHRpb24ucHJvcCgnc2VsZWN0ZWQnKSwgcHJldlZhbHVlXTtcclxuICAgICAgICAgICAgICB0aGF0LiRlbGVtZW50XHJcbiAgICAgICAgICAgICAgICAudHJpZ2dlck5hdGl2ZSgnY2hhbmdlJyk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgdGhpcy4kbWVudS5vbignY2xpY2snLCAnbGkuJyArIGNsYXNzTmFtZXMuRElTQUJMRUQgKyAnIGEsIC4nICsgY2xhc3NOYW1lcy5QT1BPVkVSSEVBREVSICsgJywgLicgKyBjbGFzc05hbWVzLlBPUE9WRVJIRUFERVIgKyAnIDpub3QoLmNsb3NlKScsIGZ1bmN0aW9uIChlKSB7XHJcbiAgICAgICAgaWYgKGUuY3VycmVudFRhcmdldCA9PSB0aGlzKSB7XHJcbiAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XHJcbiAgICAgICAgICBlLnN0b3BQcm9wYWdhdGlvbigpO1xyXG4gICAgICAgICAgaWYgKHRoYXQub3B0aW9ucy5saXZlU2VhcmNoICYmICEkKGUudGFyZ2V0KS5oYXNDbGFzcygnY2xvc2UnKSkge1xyXG4gICAgICAgICAgICB0aGF0LiRzZWFyY2hib3gudHJpZ2dlcignZm9jdXMnKTtcclxuICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIHRoYXQuJGJ1dHRvbi50cmlnZ2VyKCdmb2N1cycpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcblxyXG4gICAgICB0aGlzLiRtZW51SW5uZXIub24oJ2NsaWNrJywgJy5kaXZpZGVyLCAuZHJvcGRvd24taGVhZGVyJywgZnVuY3Rpb24gKGUpIHtcclxuICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XHJcbiAgICAgICAgZS5zdG9wUHJvcGFnYXRpb24oKTtcclxuICAgICAgICBpZiAodGhhdC5vcHRpb25zLmxpdmVTZWFyY2gpIHtcclxuICAgICAgICAgIHRoYXQuJHNlYXJjaGJveC50cmlnZ2VyKCdmb2N1cycpO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICB0aGF0LiRidXR0b24udHJpZ2dlcignZm9jdXMnKTtcclxuICAgICAgICB9XHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgdGhpcy4kbWVudS5vbignY2xpY2snLCAnLicgKyBjbGFzc05hbWVzLlBPUE9WRVJIRUFERVIgKyAnIC5jbG9zZScsIGZ1bmN0aW9uICgpIHtcclxuICAgICAgICB0aGF0LiRidXR0b24udHJpZ2dlcignY2xpY2snKTtcclxuICAgICAgfSk7XHJcblxyXG4gICAgICB0aGlzLiRzZWFyY2hib3gub24oJ2NsaWNrJywgZnVuY3Rpb24gKGUpIHtcclxuICAgICAgICBlLnN0b3BQcm9wYWdhdGlvbigpO1xyXG4gICAgICB9KTtcclxuXHJcbiAgICAgIHRoaXMuJG1lbnUub24oJ2NsaWNrJywgJy5hY3Rpb25zLWJ0bicsIGZ1bmN0aW9uIChlKSB7XHJcbiAgICAgICAgaWYgKHRoYXQub3B0aW9ucy5saXZlU2VhcmNoKSB7XHJcbiAgICAgICAgICB0aGF0LiRzZWFyY2hib3gudHJpZ2dlcignZm9jdXMnKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgdGhhdC4kYnV0dG9uLnRyaWdnZXIoJ2ZvY3VzJyk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XHJcbiAgICAgICAgZS5zdG9wUHJvcGFnYXRpb24oKTtcclxuXHJcbiAgICAgICAgaWYgKCQodGhpcykuaGFzQ2xhc3MoJ2JzLXNlbGVjdC1hbGwnKSkge1xyXG4gICAgICAgICAgdGhhdC5zZWxlY3RBbGwoKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgdGhhdC5kZXNlbGVjdEFsbCgpO1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcblxyXG4gICAgICB0aGlzLiRidXR0b25cclxuICAgICAgICAub24oJ2ZvY3VzJyArIEVWRU5UX0tFWSwgZnVuY3Rpb24gKGUpIHtcclxuICAgICAgICAgIHZhciB0YWJpbmRleCA9IHRoYXQuJGVsZW1lbnRbMF0uZ2V0QXR0cmlidXRlKCd0YWJpbmRleCcpO1xyXG5cclxuICAgICAgICAgIC8vIG9ubHkgY2hhbmdlIHdoZW4gYnV0dG9uIGlzIGFjdHVhbGx5IGZvY3VzZWRcclxuICAgICAgICAgIGlmICh0YWJpbmRleCAhPT0gdW5kZWZpbmVkICYmIGUub3JpZ2luYWxFdmVudCAmJiBlLm9yaWdpbmFsRXZlbnQuaXNUcnVzdGVkKSB7XHJcbiAgICAgICAgICAgIC8vIGFwcGx5IHNlbGVjdCBlbGVtZW50J3MgdGFiaW5kZXggdG8gZW5zdXJlIGNvcnJlY3Qgb3JkZXIgaXMgZm9sbG93ZWQgd2hlbiB0YWJiaW5nIHRvIHRoZSBuZXh0IGVsZW1lbnRcclxuICAgICAgICAgICAgdGhpcy5zZXRBdHRyaWJ1dGUoJ3RhYmluZGV4JywgdGFiaW5kZXgpO1xyXG4gICAgICAgICAgICAvLyBzZXQgZWxlbWVudCdzIHRhYmluZGV4IHRvIC0xIHRvIGFsbG93IGZvciByZXZlcnNlIHRhYmJpbmdcclxuICAgICAgICAgICAgdGhhdC4kZWxlbWVudFswXS5zZXRBdHRyaWJ1dGUoJ3RhYmluZGV4JywgLTEpO1xyXG4gICAgICAgICAgICB0aGF0LnNlbGVjdHBpY2tlci52aWV3LnRhYmluZGV4ID0gdGFiaW5kZXg7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSlcclxuICAgICAgICAub24oJ2JsdXInICsgRVZFTlRfS0VZLCBmdW5jdGlvbiAoZSkge1xyXG4gICAgICAgICAgLy8gcmV2ZXJ0IGV2ZXJ5dGhpbmcgdG8gb3JpZ2luYWwgdGFiaW5kZXhcclxuICAgICAgICAgIGlmICh0aGF0LnNlbGVjdHBpY2tlci52aWV3LnRhYmluZGV4ICE9PSB1bmRlZmluZWQgJiYgZS5vcmlnaW5hbEV2ZW50ICYmIGUub3JpZ2luYWxFdmVudC5pc1RydXN0ZWQpIHtcclxuICAgICAgICAgICAgdGhhdC4kZWxlbWVudFswXS5zZXRBdHRyaWJ1dGUoJ3RhYmluZGV4JywgdGhhdC5zZWxlY3RwaWNrZXIudmlldy50YWJpbmRleCk7XHJcbiAgICAgICAgICAgIHRoaXMuc2V0QXR0cmlidXRlKCd0YWJpbmRleCcsIC0xKTtcclxuICAgICAgICAgICAgdGhhdC5zZWxlY3RwaWNrZXIudmlldy50YWJpbmRleCA9IHVuZGVmaW5lZDtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgIHRoaXMuJGVsZW1lbnRcclxuICAgICAgICAub24oJ2NoYW5nZScgKyBFVkVOVF9LRVksIGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgIHRoYXQucmVuZGVyKCk7XHJcbiAgICAgICAgICB0aGF0LiRlbGVtZW50LnRyaWdnZXIoJ2NoYW5nZWQnICsgRVZFTlRfS0VZLCBjaGFuZ2VkQXJndW1lbnRzKTtcclxuICAgICAgICAgIGNoYW5nZWRBcmd1bWVudHMgPSBudWxsO1xyXG4gICAgICAgIH0pXHJcbiAgICAgICAgLm9uKCdmb2N1cycgKyBFVkVOVF9LRVksIGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgIGlmICghdGhhdC5vcHRpb25zLm1vYmlsZSkgdGhhdC4kYnV0dG9uWzBdLmZvY3VzKCk7XHJcbiAgICAgICAgfSk7XHJcbiAgICB9LFxyXG5cclxuICAgIGxpdmVTZWFyY2hMaXN0ZW5lcjogZnVuY3Rpb24gKCkge1xyXG4gICAgICB2YXIgdGhhdCA9IHRoaXM7XHJcblxyXG4gICAgICB0aGlzLiRidXR0b24ub24oJ2NsaWNrLmJzLmRyb3Bkb3duLmRhdGEtYXBpJywgZnVuY3Rpb24gKCkge1xyXG4gICAgICAgIGlmICghIXRoYXQuJHNlYXJjaGJveC52YWwoKSkge1xyXG4gICAgICAgICAgdGhhdC4kc2VhcmNoYm94LnZhbCgnJyk7XHJcbiAgICAgICAgICB0aGF0LnNlbGVjdHBpY2tlci5zZWFyY2gucHJldmlvdXNWYWx1ZSA9IHVuZGVmaW5lZDtcclxuICAgICAgICB9XHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgdGhpcy4kc2VhcmNoYm94Lm9uKCdjbGljay5icy5kcm9wZG93bi5kYXRhLWFwaSBmb2N1cy5icy5kcm9wZG93bi5kYXRhLWFwaSB0b3VjaGVuZC5icy5kcm9wZG93bi5kYXRhLWFwaScsIGZ1bmN0aW9uIChlKSB7XHJcbiAgICAgICAgZS5zdG9wUHJvcGFnYXRpb24oKTtcclxuICAgICAgfSk7XHJcblxyXG4gICAgICB0aGlzLiRzZWFyY2hib3gub24oJ2lucHV0IHByb3BlcnR5Y2hhbmdlJywgZnVuY3Rpb24gKCkge1xyXG4gICAgICAgIHZhciBzZWFyY2hWYWx1ZSA9IHRoYXQuJHNlYXJjaGJveFswXS52YWx1ZTtcclxuXHJcbiAgICAgICAgdGhhdC5zZWxlY3RwaWNrZXIuc2VhcmNoLmVsZW1lbnRzID0gW107XHJcbiAgICAgICAgdGhhdC5zZWxlY3RwaWNrZXIuc2VhcmNoLmRhdGEgPSBbXTtcclxuXHJcbiAgICAgICAgaWYgKHNlYXJjaFZhbHVlKSB7XHJcbiAgICAgICAgICBpZiAodGhhdC5vcHRpb25zLnNvdXJjZS5zZWFyY2gpIHtcclxuICAgICAgICAgICAgdGhhdC5mZXRjaERhdGEoZnVuY3Rpb24gKGJ1aWx0RGF0YSkge1xyXG4gICAgICAgICAgICAgIHRoYXQucmVuZGVyKCk7XHJcbiAgICAgICAgICAgICAgdGhhdC5idWlsZExpc3QodW5kZWZpbmVkLCB0cnVlKTtcclxuICAgICAgICAgICAgICB0aGF0LmNyZWF0ZVZpZXcodHJ1ZSk7XHJcbiAgICAgICAgICAgICAgc2hvd05vUmVzdWx0cy5jYWxsKHRoYXQsIGJ1aWx0RGF0YSwgc2VhcmNoVmFsdWUpO1xyXG4gICAgICAgICAgICB9LCAnc2VhcmNoJywgMCwgc2VhcmNoVmFsdWUpO1xyXG4gICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgdmFyIGksXHJcbiAgICAgICAgICAgICAgICBzZWFyY2hNYXRjaCA9IFtdLFxyXG4gICAgICAgICAgICAgICAgcSA9IHNlYXJjaFZhbHVlLnRvVXBwZXJDYXNlKCksXHJcbiAgICAgICAgICAgICAgICBjYWNoZSA9IHt9LFxyXG4gICAgICAgICAgICAgICAgY2FjaGVBcnIgPSBbXSxcclxuICAgICAgICAgICAgICAgIHNlYXJjaFN0eWxlID0gdGhhdC5fc2VhcmNoU3R5bGUoKSxcclxuICAgICAgICAgICAgICAgIG5vcm1hbGl6ZVNlYXJjaCA9IHRoYXQub3B0aW9ucy5saXZlU2VhcmNoTm9ybWFsaXplO1xyXG5cclxuICAgICAgICAgICAgaWYgKG5vcm1hbGl6ZVNlYXJjaCkgcSA9IG5vcm1hbGl6ZVRvQmFzZShxKTtcclxuXHJcbiAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhhdC5zZWxlY3RwaWNrZXIubWFpbi5kYXRhLmxlbmd0aDsgaSsrKSB7XHJcbiAgICAgICAgICAgICAgdmFyIGxpID0gdGhhdC5zZWxlY3RwaWNrZXIubWFpbi5kYXRhW2ldO1xyXG5cclxuICAgICAgICAgICAgICBpZiAoIWNhY2hlW2ldKSB7XHJcbiAgICAgICAgICAgICAgICBjYWNoZVtpXSA9IHN0cmluZ1NlYXJjaChsaSwgcSwgc2VhcmNoU3R5bGUsIG5vcm1hbGl6ZVNlYXJjaCk7XHJcbiAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICBpZiAoY2FjaGVbaV0gJiYgbGkuaGVhZGVySW5kZXggIT09IHVuZGVmaW5lZCAmJiBjYWNoZUFyci5pbmRleE9mKGxpLmhlYWRlckluZGV4KSA9PT0gLTEpIHtcclxuICAgICAgICAgICAgICAgIGlmIChsaS5oZWFkZXJJbmRleCA+IDApIHtcclxuICAgICAgICAgICAgICAgICAgY2FjaGVbbGkuaGVhZGVySW5kZXggLSAxXSA9IHRydWU7XHJcbiAgICAgICAgICAgICAgICAgIGNhY2hlQXJyLnB1c2gobGkuaGVhZGVySW5kZXggLSAxKTtcclxuICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICBjYWNoZVtsaS5oZWFkZXJJbmRleF0gPSB0cnVlO1xyXG4gICAgICAgICAgICAgICAgY2FjaGVBcnIucHVzaChsaS5oZWFkZXJJbmRleCk7XHJcblxyXG4gICAgICAgICAgICAgICAgY2FjaGVbbGkubGFzdEluZGV4ICsgMV0gPSB0cnVlO1xyXG4gICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgaWYgKGNhY2hlW2ldICYmIGxpLnR5cGUgIT09ICdvcHRncm91cC1sYWJlbCcpIGNhY2hlQXJyLnB1c2goaSk7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIGZvciAodmFyIGkgPSAwLCBjYWNoZUxlbiA9IGNhY2hlQXJyLmxlbmd0aDsgaSA8IGNhY2hlTGVuOyBpKyspIHtcclxuICAgICAgICAgICAgICB2YXIgaW5kZXggPSBjYWNoZUFycltpXSxcclxuICAgICAgICAgICAgICAgICAgcHJldkluZGV4ID0gY2FjaGVBcnJbaSAtIDFdLFxyXG4gICAgICAgICAgICAgICAgICBsaSA9IHRoYXQuc2VsZWN0cGlja2VyLm1haW4uZGF0YVtpbmRleF0sXHJcbiAgICAgICAgICAgICAgICAgIGxpUHJldiA9IHRoYXQuc2VsZWN0cGlja2VyLm1haW4uZGF0YVtwcmV2SW5kZXhdO1xyXG5cclxuICAgICAgICAgICAgICBpZiAobGkudHlwZSAhPT0gJ2RpdmlkZXInIHx8IChsaS50eXBlID09PSAnZGl2aWRlcicgJiYgbGlQcmV2ICYmIGxpUHJldi50eXBlICE9PSAnZGl2aWRlcicgJiYgY2FjaGVMZW4gLSAxICE9PSBpKSkge1xyXG4gICAgICAgICAgICAgICAgdGhhdC5zZWxlY3RwaWNrZXIuc2VhcmNoLmRhdGEucHVzaChsaSk7XHJcbiAgICAgICAgICAgICAgICBzZWFyY2hNYXRjaC5wdXNoKHRoYXQuc2VsZWN0cGlja2VyLm1haW4uZWxlbWVudHNbaW5kZXhdKTtcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIHRoYXQuYWN0aXZlSW5kZXggPSB1bmRlZmluZWQ7XHJcbiAgICAgICAgICAgIHRoYXQubm9TY3JvbGwgPSB0cnVlO1xyXG4gICAgICAgICAgICB0aGF0LiRtZW51SW5uZXIuc2Nyb2xsVG9wKDApO1xyXG4gICAgICAgICAgICB0aGF0LnNlbGVjdHBpY2tlci5zZWFyY2guZWxlbWVudHMgPSBzZWFyY2hNYXRjaDtcclxuICAgICAgICAgICAgdGhhdC5jcmVhdGVWaWV3KHRydWUpO1xyXG4gICAgICAgICAgICBzaG93Tm9SZXN1bHRzLmNhbGwodGhhdCwgc2VhcmNoTWF0Y2gsIHNlYXJjaFZhbHVlKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9IGVsc2UgaWYgKHRoYXQuc2VsZWN0cGlja2VyLnNlYXJjaC5wcmV2aW91c1ZhbHVlKSB7IC8vIGZvciBJRTExICgjMjQwMilcclxuICAgICAgICAgIHRoYXQuJG1lbnVJbm5lci5zY3JvbGxUb3AoMCk7XHJcbiAgICAgICAgICB0aGF0LmNyZWF0ZVZpZXcoZmFsc2UpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgdGhhdC5zZWxlY3RwaWNrZXIuc2VhcmNoLnByZXZpb3VzVmFsdWUgPSAgc2VhcmNoVmFsdWU7XHJcbiAgICAgIH0pO1xyXG4gICAgfSxcclxuXHJcbiAgICBfc2VhcmNoU3R5bGU6IGZ1bmN0aW9uICgpIHtcclxuICAgICAgcmV0dXJuIHRoaXMub3B0aW9ucy5saXZlU2VhcmNoU3R5bGUgfHwgJ2NvbnRhaW5zJztcclxuICAgIH0sXHJcblxyXG4gICAgdmFsOiBmdW5jdGlvbiAodmFsdWUpIHtcclxuICAgICAgdmFyIGVsZW1lbnQgPSB0aGlzLiRlbGVtZW50WzBdO1xyXG5cclxuICAgICAgaWYgKHR5cGVvZiB2YWx1ZSAhPT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgICB2YXIgc2VsZWN0ZWRPcHRpb25zID0gZ2V0U2VsZWN0ZWRPcHRpb25zLmNhbGwodGhpcyksXHJcbiAgICAgICAgICAgIHByZXZWYWx1ZSA9IGdldFNlbGVjdFZhbHVlcy5jYWxsKHRoaXMsIHNlbGVjdGVkT3B0aW9ucyk7XHJcblxyXG4gICAgICAgIGNoYW5nZWRBcmd1bWVudHMgPSBbbnVsbCwgbnVsbCwgcHJldlZhbHVlXTtcclxuXHJcbiAgICAgICAgaWYgKCFBcnJheS5pc0FycmF5KHZhbHVlKSkgdmFsdWUgPSBbIHZhbHVlIF07XHJcblxyXG4gICAgICAgIHZhbHVlLm1hcChTdHJpbmcpO1xyXG5cclxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHNlbGVjdGVkT3B0aW9ucy5sZW5ndGg7IGkrKykge1xyXG4gICAgICAgICAgdmFyIGl0ZW0gPSBzZWxlY3RlZE9wdGlvbnNbaV07XHJcblxyXG4gICAgICAgICAgaWYgKGl0ZW0gJiYgdmFsdWUuaW5kZXhPZihTdHJpbmcoaXRlbS52YWx1ZSkpID09PSAtMSkge1xyXG4gICAgICAgICAgICB0aGlzLnNldFNlbGVjdGVkKGl0ZW0sIGZhbHNlKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIG9ubHkgdXBkYXRlIHNlbGVjdGVkIHZhbHVlIGlmIGl0IG1hdGNoZXMgYW4gZXhpc3Rpbmcgb3B0aW9uXHJcbiAgICAgICAgdGhpcy5zZWxlY3RwaWNrZXIubWFpbi5kYXRhLmZpbHRlcihmdW5jdGlvbiAoaXRlbSkge1xyXG4gICAgICAgICAgaWYgKHZhbHVlLmluZGV4T2YoU3RyaW5nKGl0ZW0udmFsdWUpKSAhPT0gLTEpIHtcclxuICAgICAgICAgICAgdGhpcy5zZXRTZWxlY3RlZChpdGVtLCB0cnVlKTtcclxuICAgICAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICAgIH0sIHRoaXMpO1xyXG5cclxuICAgICAgICBpZiAodGhpcy5vcHRpb25zLnNvdXJjZS5kYXRhKSBlbGVtZW50LmFwcGVuZENoaWxkKHRoaXMuc2VsZWN0cGlja2VyLm1haW4ub3B0aW9uUXVldWUpO1xyXG5cclxuICAgICAgICB0aGlzLiRlbGVtZW50LnRyaWdnZXIoJ2NoYW5nZWQnICsgRVZFTlRfS0VZLCBjaGFuZ2VkQXJndW1lbnRzKTtcclxuXHJcbiAgICAgICAgaWYgKHRoaXMuJG5ld0VsZW1lbnQuaGFzQ2xhc3MoY2xhc3NOYW1lcy5TSE9XKSkge1xyXG4gICAgICAgICAgaWYgKHRoaXMubXVsdGlwbGUpIHtcclxuICAgICAgICAgICAgdGhpcy5zZXRPcHRpb25TdGF0dXModHJ1ZSk7XHJcbiAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICB2YXIgbGlTZWxlY3RlZEluZGV4ID0gKGVsZW1lbnQub3B0aW9uc1tlbGVtZW50LnNlbGVjdGVkSW5kZXhdIHx8IHt9KS5saUluZGV4O1xyXG5cclxuICAgICAgICAgICAgaWYgKHR5cGVvZiBsaVNlbGVjdGVkSW5kZXggPT09ICdudW1iZXInKSB7XHJcbiAgICAgICAgICAgICAgdGhpcy5zZXRTZWxlY3RlZCh0aGlzLnNlbGVjdGVkSW5kZXgsIGZhbHNlKTtcclxuICAgICAgICAgICAgICB0aGlzLnNldFNlbGVjdGVkKGxpU2VsZWN0ZWRJbmRleCwgdHJ1ZSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHRoaXMucmVuZGVyKCk7XHJcblxyXG4gICAgICAgIGNoYW5nZWRBcmd1bWVudHMgPSBudWxsO1xyXG5cclxuICAgICAgICByZXR1cm4gdGhpcy4kZWxlbWVudDtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICByZXR1cm4gdGhpcy4kZWxlbWVudC52YWwoKTtcclxuICAgICAgfVxyXG4gICAgfSxcclxuXHJcbiAgICBjaGFuZ2VBbGw6IGZ1bmN0aW9uIChzdGF0dXMpIHtcclxuICAgICAgaWYgKCF0aGlzLm11bHRpcGxlKSByZXR1cm47XHJcbiAgICAgIGlmICh0eXBlb2Ygc3RhdHVzID09PSAndW5kZWZpbmVkJykgc3RhdHVzID0gdHJ1ZTtcclxuXHJcbiAgICAgIHZhciBlbGVtZW50ID0gdGhpcy4kZWxlbWVudFswXSxcclxuICAgICAgICAgIHByZXZpb3VzU2VsZWN0ZWQgPSAwLFxyXG4gICAgICAgICAgY3VycmVudFNlbGVjdGVkID0gMCxcclxuICAgICAgICAgIHByZXZWYWx1ZSA9IGdldFNlbGVjdFZhbHVlcy5jYWxsKHRoaXMpO1xyXG5cclxuICAgICAgZWxlbWVudC5jbGFzc0xpc3QuYWRkKCdicy1zZWxlY3QtaGlkZGVuJyk7XHJcblxyXG4gICAgICBmb3IgKHZhciBpID0gMCwgZGF0YSA9IHRoaXMuc2VsZWN0cGlja2VyLmN1cnJlbnQuZGF0YSwgbGVuID0gZGF0YS5sZW5ndGg7IGkgPCBsZW47IGkrKykge1xyXG4gICAgICAgIHZhciBsaURhdGEgPSBkYXRhW2ldLFxyXG4gICAgICAgICAgICBvcHRpb24gPSBsaURhdGEub3B0aW9uO1xyXG5cclxuICAgICAgICBpZiAob3B0aW9uICYmICFsaURhdGEuZGlzYWJsZWQgJiYgbGlEYXRhLnR5cGUgIT09ICdkaXZpZGVyJykge1xyXG4gICAgICAgICAgaWYgKGxpRGF0YS5zZWxlY3RlZCkgcHJldmlvdXNTZWxlY3RlZCsrO1xyXG4gICAgICAgICAgb3B0aW9uLnNlbGVjdGVkID0gc3RhdHVzO1xyXG4gICAgICAgICAgbGlEYXRhLnNlbGVjdGVkID0gc3RhdHVzO1xyXG4gICAgICAgICAgaWYgKHN0YXR1cyA9PT0gdHJ1ZSkgY3VycmVudFNlbGVjdGVkKys7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICBlbGVtZW50LmNsYXNzTGlzdC5yZW1vdmUoJ2JzLXNlbGVjdC1oaWRkZW4nKTtcclxuXHJcbiAgICAgIGlmIChwcmV2aW91c1NlbGVjdGVkID09PSBjdXJyZW50U2VsZWN0ZWQpIHJldHVybjtcclxuXHJcbiAgICAgIHRoaXMuc2V0T3B0aW9uU3RhdHVzKCk7XHJcblxyXG4gICAgICBjaGFuZ2VkQXJndW1lbnRzID0gW251bGwsIG51bGwsIHByZXZWYWx1ZV07XHJcblxyXG4gICAgICB0aGlzLiRlbGVtZW50XHJcbiAgICAgICAgLnRyaWdnZXJOYXRpdmUoJ2NoYW5nZScpO1xyXG4gICAgfSxcclxuXHJcbiAgICBzZWxlY3RBbGw6IGZ1bmN0aW9uICgpIHtcclxuICAgICAgcmV0dXJuIHRoaXMuY2hhbmdlQWxsKHRydWUpO1xyXG4gICAgfSxcclxuXHJcbiAgICBkZXNlbGVjdEFsbDogZnVuY3Rpb24gKCkge1xyXG4gICAgICByZXR1cm4gdGhpcy5jaGFuZ2VBbGwoZmFsc2UpO1xyXG4gICAgfSxcclxuXHJcbiAgICB0b2dnbGU6IGZ1bmN0aW9uIChlLCBzdGF0ZSkge1xyXG4gICAgICB2YXIgaXNBY3RpdmUsXHJcbiAgICAgICAgICB0cmlnZ2VyQ2xpY2sgPSBzdGF0ZSA9PT0gdW5kZWZpbmVkO1xyXG5cclxuICAgICAgZSA9IGUgfHwgd2luZG93LmV2ZW50O1xyXG5cclxuICAgICAgaWYgKGUpIGUuc3RvcFByb3BhZ2F0aW9uKCk7XHJcblxyXG4gICAgICBpZiAodHJpZ2dlckNsaWNrID09PSBmYWxzZSkge1xyXG4gICAgICAgIGlzQWN0aXZlID0gdGhpcy4kbmV3RWxlbWVudFswXS5jbGFzc0xpc3QuY29udGFpbnMoY2xhc3NOYW1lcy5TSE9XKTtcclxuICAgICAgICB0cmlnZ2VyQ2xpY2sgPSBzdGF0ZSA9PT0gdHJ1ZSAmJiBpc0FjdGl2ZSA9PT0gZmFsc2UgfHwgc3RhdGUgPT09IGZhbHNlICYmIGlzQWN0aXZlID09PSB0cnVlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAodHJpZ2dlckNsaWNrKSB0aGlzLiRidXR0b24udHJpZ2dlcignY2xpY2suYnMuZHJvcGRvd24uZGF0YS1hcGknKTtcclxuICAgIH0sXHJcblxyXG4gICAgb3BlbjogZnVuY3Rpb24gKGUpIHtcclxuICAgICAgdGhpcy50b2dnbGUoZSwgdHJ1ZSk7XHJcbiAgICB9LFxyXG5cclxuICAgIGNsb3NlOiBmdW5jdGlvbiAoZSkge1xyXG4gICAgICB0aGlzLnRvZ2dsZShlLCBmYWxzZSk7XHJcbiAgICB9LFxyXG5cclxuICAgIGtleWRvd246IGZ1bmN0aW9uIChlKSB7XHJcbiAgICAgIHZhciAkdGhpcyA9ICQodGhpcyksXHJcbiAgICAgICAgICBpc1RvZ2dsZSA9ICR0aGlzLmhhc0NsYXNzKCdkcm9wZG93bi10b2dnbGUnKSxcclxuICAgICAgICAgICRwYXJlbnQgPSBpc1RvZ2dsZSA/ICR0aGlzLmNsb3Nlc3QoJy5kcm9wZG93bicpIDogJHRoaXMuY2xvc2VzdChTZWxlY3Rvci5NRU5VKSxcclxuICAgICAgICAgIHRoYXQgPSAkcGFyZW50LmRhdGEoJ3RoaXMnKSxcclxuICAgICAgICAgICRpdGVtcyA9IHRoYXQuZmluZExpcygpLFxyXG4gICAgICAgICAgaW5kZXgsXHJcbiAgICAgICAgICBpc0FjdGl2ZSxcclxuICAgICAgICAgIGxpQWN0aXZlLFxyXG4gICAgICAgICAgYWN0aXZlTGksXHJcbiAgICAgICAgICBvZmZzZXQsXHJcbiAgICAgICAgICB1cGRhdGVTY3JvbGwgPSBmYWxzZSxcclxuICAgICAgICAgIGRvd25PblRhYiA9IGUud2hpY2ggPT09IGtleUNvZGVzLlRBQiAmJiAhaXNUb2dnbGUgJiYgIXRoYXQub3B0aW9ucy5zZWxlY3RPblRhYixcclxuICAgICAgICAgIGlzQXJyb3dLZXkgPSBSRUdFWFBfQVJST1cudGVzdChlLndoaWNoKSB8fCBkb3duT25UYWIsXHJcbiAgICAgICAgICBzY3JvbGxUb3AgPSB0aGF0LiRtZW51SW5uZXJbMF0uc2Nyb2xsVG9wLFxyXG4gICAgICAgICAgaXNWaXJ0dWFsID0gdGhhdC5pc1ZpcnR1YWwoKSxcclxuICAgICAgICAgIHBvc2l0aW9uMCA9IGlzVmlydHVhbCA9PT0gdHJ1ZSA/IHRoYXQuc2VsZWN0cGlja2VyLnZpZXcucG9zaXRpb24wIDogMDtcclxuXHJcbiAgICAgIC8vIGRvIG5vdGhpbmcgaWYgYSBmdW5jdGlvbiBrZXkgaXMgcHJlc3NlZFxyXG4gICAgICBpZiAoZS53aGljaCA+PSAxMTIgJiYgZS53aGljaCA8PSAxMjMpIHJldHVybjtcclxuXHJcbiAgICAgIGlzQWN0aXZlID0gdGhhdC4kbWVudS5oYXNDbGFzcyhjbGFzc05hbWVzLlNIT1cpO1xyXG5cclxuICAgICAgaWYgKFxyXG4gICAgICAgICFpc0FjdGl2ZSAmJlxyXG4gICAgICAgIChcclxuICAgICAgICAgIGlzQXJyb3dLZXkgfHxcclxuICAgICAgICAgIChlLndoaWNoID49IDQ4ICYmIGUud2hpY2ggPD0gNTcpIHx8XHJcbiAgICAgICAgICAoZS53aGljaCA+PSA5NiAmJiBlLndoaWNoIDw9IDEwNSkgfHxcclxuICAgICAgICAgIChlLndoaWNoID49IDY1ICYmIGUud2hpY2ggPD0gOTApXHJcbiAgICAgICAgKVxyXG4gICAgICApIHtcclxuICAgICAgICB0aGF0LiRidXR0b24udHJpZ2dlcignY2xpY2suYnMuZHJvcGRvd24uZGF0YS1hcGknKTtcclxuXHJcbiAgICAgICAgaWYgKHRoYXQub3B0aW9ucy5saXZlU2VhcmNoKSB7XHJcbiAgICAgICAgICB0aGF0LiRzZWFyY2hib3gudHJpZ2dlcignZm9jdXMnKTtcclxuICAgICAgICAgIHJldHVybjtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmIChlLndoaWNoID09PSBrZXlDb2Rlcy5FU0NBUEUgJiYgaXNBY3RpdmUpIHtcclxuICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XHJcbiAgICAgICAgdGhhdC4kYnV0dG9uLnRyaWdnZXIoJ2NsaWNrLmJzLmRyb3Bkb3duLmRhdGEtYXBpJykudHJpZ2dlcignZm9jdXMnKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKGlzQXJyb3dLZXkpIHsgLy8gaWYgdXAgb3IgZG93blxyXG4gICAgICAgIGlmICghJGl0ZW1zLmxlbmd0aCkgcmV0dXJuO1xyXG5cclxuICAgICAgICBsaUFjdGl2ZSA9IHRoYXQuc2VsZWN0cGlja2VyLm1haW4uZWxlbWVudHNbdGhhdC5hY3RpdmVJbmRleF07XHJcbiAgICAgICAgaW5kZXggPSBsaUFjdGl2ZSA/IEFycmF5LnByb3RvdHlwZS5pbmRleE9mLmNhbGwobGlBY3RpdmUucGFyZW50RWxlbWVudC5jaGlsZHJlbiwgbGlBY3RpdmUpIDogLTE7XHJcblxyXG4gICAgICAgIGlmIChpbmRleCAhPT0gLTEpIHtcclxuICAgICAgICAgIHRoYXQuZGVmb2N1c0l0ZW0obGlBY3RpdmUpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgaWYgKGUud2hpY2ggPT09IGtleUNvZGVzLkFSUk9XX1VQKSB7IC8vIHVwXHJcbiAgICAgICAgICBpZiAoaW5kZXggIT09IC0xKSBpbmRleC0tO1xyXG4gICAgICAgICAgaWYgKGluZGV4ICsgcG9zaXRpb24wIDwgMCkgaW5kZXggKz0gJGl0ZW1zLmxlbmd0aDtcclxuXHJcbiAgICAgICAgICBpZiAoIXRoYXQuc2VsZWN0cGlja2VyLnZpZXcuY2FuSGlnaGxpZ2h0W2luZGV4ICsgcG9zaXRpb24wXSkge1xyXG4gICAgICAgICAgICBpbmRleCA9IHRoYXQuc2VsZWN0cGlja2VyLnZpZXcuY2FuSGlnaGxpZ2h0LnNsaWNlKDAsIGluZGV4ICsgcG9zaXRpb24wKS5sYXN0SW5kZXhPZih0cnVlKSAtIHBvc2l0aW9uMDtcclxuICAgICAgICAgICAgaWYgKGluZGV4ID09PSAtMSkgaW5kZXggPSAkaXRlbXMubGVuZ3RoIC0gMTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9IGVsc2UgaWYgKGUud2hpY2ggPT09IGtleUNvZGVzLkFSUk9XX0RPV04gfHwgZG93bk9uVGFiKSB7IC8vIGRvd25cclxuICAgICAgICAgIGluZGV4Kys7XHJcbiAgICAgICAgICBpZiAoaW5kZXggKyBwb3NpdGlvbjAgPj0gdGhhdC5zZWxlY3RwaWNrZXIudmlldy5jYW5IaWdobGlnaHQubGVuZ3RoKSBpbmRleCA9IHRoYXQuc2VsZWN0cGlja2VyLnZpZXcuZmlyc3RIaWdobGlnaHRJbmRleDtcclxuXHJcbiAgICAgICAgICBpZiAoIXRoYXQuc2VsZWN0cGlja2VyLnZpZXcuY2FuSGlnaGxpZ2h0W2luZGV4ICsgcG9zaXRpb24wXSkge1xyXG4gICAgICAgICAgICBpbmRleCA9IGluZGV4ICsgMSArIHRoYXQuc2VsZWN0cGlja2VyLnZpZXcuY2FuSGlnaGxpZ2h0LnNsaWNlKGluZGV4ICsgcG9zaXRpb24wICsgMSkuaW5kZXhPZih0cnVlKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcclxuXHJcbiAgICAgICAgdmFyIGxpQWN0aXZlSW5kZXggPSBwb3NpdGlvbjAgKyBpbmRleDtcclxuXHJcbiAgICAgICAgaWYgKGUud2hpY2ggPT09IGtleUNvZGVzLkFSUk9XX1VQKSB7IC8vIHVwXHJcbiAgICAgICAgICAvLyBzY3JvbGwgdG8gYm90dG9tIGFuZCBoaWdobGlnaHQgbGFzdCBvcHRpb25cclxuICAgICAgICAgIGlmIChwb3NpdGlvbjAgPT09IDAgJiYgaW5kZXggPT09ICRpdGVtcy5sZW5ndGggLSAxKSB7XHJcbiAgICAgICAgICAgIHRoYXQuJG1lbnVJbm5lclswXS5zY3JvbGxUb3AgPSB0aGF0LiRtZW51SW5uZXJbMF0uc2Nyb2xsSGVpZ2h0O1xyXG5cclxuICAgICAgICAgICAgbGlBY3RpdmVJbmRleCA9IHRoYXQuc2VsZWN0cGlja2VyLmN1cnJlbnQuZWxlbWVudHMubGVuZ3RoIC0gMTtcclxuICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIGFjdGl2ZUxpID0gdGhhdC5zZWxlY3RwaWNrZXIuY3VycmVudC5kYXRhW2xpQWN0aXZlSW5kZXhdO1xyXG4gICAgICAgICAgICBvZmZzZXQgPSBhY3RpdmVMaS5wb3NpdGlvbiAtIGFjdGl2ZUxpLmhlaWdodDtcclxuXHJcbiAgICAgICAgICAgIHVwZGF0ZVNjcm9sbCA9IG9mZnNldCA8IHNjcm9sbFRvcDtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9IGVsc2UgaWYgKGUud2hpY2ggPT09IGtleUNvZGVzLkFSUk9XX0RPV04gfHwgZG93bk9uVGFiKSB7IC8vIGRvd25cclxuICAgICAgICAgIC8vIHNjcm9sbCB0byB0b3AgYW5kIGhpZ2hsaWdodCBmaXJzdCBvcHRpb25cclxuICAgICAgICAgIGlmIChpbmRleCA9PT0gdGhhdC5zZWxlY3RwaWNrZXIudmlldy5maXJzdEhpZ2hsaWdodEluZGV4KSB7XHJcbiAgICAgICAgICAgIHRoYXQuJG1lbnVJbm5lclswXS5zY3JvbGxUb3AgPSAwO1xyXG5cclxuICAgICAgICAgICAgbGlBY3RpdmVJbmRleCA9IHRoYXQuc2VsZWN0cGlja2VyLnZpZXcuZmlyc3RIaWdobGlnaHRJbmRleDtcclxuICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIGFjdGl2ZUxpID0gdGhhdC5zZWxlY3RwaWNrZXIuY3VycmVudC5kYXRhW2xpQWN0aXZlSW5kZXhdO1xyXG4gICAgICAgICAgICBvZmZzZXQgPSBhY3RpdmVMaS5wb3NpdGlvbiAtIHRoYXQuc2l6ZUluZm8ubWVudUlubmVySGVpZ2h0O1xyXG5cclxuICAgICAgICAgICAgdXBkYXRlU2Nyb2xsID0gb2Zmc2V0ID4gc2Nyb2xsVG9wO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgbGlBY3RpdmUgPSB0aGF0LnNlbGVjdHBpY2tlci5jdXJyZW50LmVsZW1lbnRzW2xpQWN0aXZlSW5kZXhdO1xyXG5cclxuICAgICAgICB0aGF0LmFjdGl2ZUluZGV4ID0gdGhhdC5zZWxlY3RwaWNrZXIuY3VycmVudC5kYXRhW2xpQWN0aXZlSW5kZXhdLmluZGV4O1xyXG5cclxuICAgICAgICB0aGF0LmZvY3VzSXRlbShsaUFjdGl2ZSk7XHJcblxyXG4gICAgICAgIHRoYXQuc2VsZWN0cGlja2VyLnZpZXcuY3VycmVudEFjdGl2ZSA9IGxpQWN0aXZlO1xyXG5cclxuICAgICAgICBpZiAodXBkYXRlU2Nyb2xsKSB0aGF0LiRtZW51SW5uZXJbMF0uc2Nyb2xsVG9wID0gb2Zmc2V0O1xyXG5cclxuICAgICAgICBpZiAodGhhdC5vcHRpb25zLmxpdmVTZWFyY2gpIHtcclxuICAgICAgICAgIHRoYXQuJHNlYXJjaGJveC50cmlnZ2VyKCdmb2N1cycpO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAkdGhpcy50cmlnZ2VyKCdmb2N1cycpO1xyXG4gICAgICAgIH1cclxuICAgICAgfSBlbHNlIGlmIChcclxuICAgICAgICAoISR0aGlzLmlzKCdpbnB1dCcpICYmICFSRUdFWFBfVEFCX09SX0VTQ0FQRS50ZXN0KGUud2hpY2gpKSB8fFxyXG4gICAgICAgIChlLndoaWNoID09PSBrZXlDb2Rlcy5TUEFDRSAmJiB0aGF0LnNlbGVjdHBpY2tlci5rZXlkb3duLmtleUhpc3RvcnkpXHJcbiAgICAgICkge1xyXG4gICAgICAgIHZhciBzZWFyY2hNYXRjaCxcclxuICAgICAgICAgICAgbWF0Y2hlcyA9IFtdLFxyXG4gICAgICAgICAgICBrZXlIaXN0b3J5O1xyXG5cclxuICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XHJcblxyXG4gICAgICAgIHRoYXQuc2VsZWN0cGlja2VyLmtleWRvd24ua2V5SGlzdG9yeSArPSBrZXlDb2RlTWFwW2Uud2hpY2hdO1xyXG5cclxuICAgICAgICBpZiAodGhhdC5zZWxlY3RwaWNrZXIua2V5ZG93bi5yZXNldEtleUhpc3RvcnkuY2FuY2VsKSBjbGVhclRpbWVvdXQodGhhdC5zZWxlY3RwaWNrZXIua2V5ZG93bi5yZXNldEtleUhpc3RvcnkuY2FuY2VsKTtcclxuICAgICAgICB0aGF0LnNlbGVjdHBpY2tlci5rZXlkb3duLnJlc2V0S2V5SGlzdG9yeS5jYW5jZWwgPSB0aGF0LnNlbGVjdHBpY2tlci5rZXlkb3duLnJlc2V0S2V5SGlzdG9yeS5zdGFydCgpO1xyXG5cclxuICAgICAgICBrZXlIaXN0b3J5ID0gdGhhdC5zZWxlY3RwaWNrZXIua2V5ZG93bi5rZXlIaXN0b3J5O1xyXG5cclxuICAgICAgICAvLyBpZiBhbGwgbGV0dGVycyBhcmUgdGhlIHNhbWUsIHNldCBrZXlIaXN0b3J5IHRvIGp1c3QgdGhlIGZpcnN0IGNoYXJhY3RlciB3aGVuIHNlYXJjaGluZ1xyXG4gICAgICAgIGlmICgvXiguKVxcMSskLy50ZXN0KGtleUhpc3RvcnkpKSB7XHJcbiAgICAgICAgICBrZXlIaXN0b3J5ID0ga2V5SGlzdG9yeS5jaGFyQXQoMCk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBmaW5kIG1hdGNoZXNcclxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoYXQuc2VsZWN0cGlja2VyLmN1cnJlbnQuZGF0YS5sZW5ndGg7IGkrKykge1xyXG4gICAgICAgICAgdmFyIGxpID0gdGhhdC5zZWxlY3RwaWNrZXIuY3VycmVudC5kYXRhW2ldLFxyXG4gICAgICAgICAgICAgIGhhc01hdGNoO1xyXG5cclxuICAgICAgICAgIGhhc01hdGNoID0gc3RyaW5nU2VhcmNoKGxpLCBrZXlIaXN0b3J5LCAnc3RhcnRzV2l0aCcsIHRydWUpO1xyXG5cclxuICAgICAgICAgIGlmIChoYXNNYXRjaCAmJiB0aGF0LnNlbGVjdHBpY2tlci52aWV3LmNhbkhpZ2hsaWdodFtpXSkge1xyXG4gICAgICAgICAgICBtYXRjaGVzLnB1c2gobGkuaW5kZXgpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgaWYgKG1hdGNoZXMubGVuZ3RoKSB7XHJcbiAgICAgICAgICB2YXIgbWF0Y2hJbmRleCA9IDA7XHJcblxyXG4gICAgICAgICAgJGl0ZW1zLnJlbW92ZUNsYXNzKCdhY3RpdmUnKS5maW5kKCdhJykucmVtb3ZlQ2xhc3MoJ2FjdGl2ZScpO1xyXG5cclxuICAgICAgICAgIC8vIGVpdGhlciBvbmx5IG9uZSBrZXkgaGFzIGJlZW4gcHJlc3NlZCBvciB0aGV5IGFyZSBhbGwgdGhlIHNhbWUga2V5XHJcbiAgICAgICAgICBpZiAoa2V5SGlzdG9yeS5sZW5ndGggPT09IDEpIHtcclxuICAgICAgICAgICAgbWF0Y2hJbmRleCA9IG1hdGNoZXMuaW5kZXhPZih0aGF0LmFjdGl2ZUluZGV4KTtcclxuXHJcbiAgICAgICAgICAgIGlmIChtYXRjaEluZGV4ID09PSAtMSB8fCBtYXRjaEluZGV4ID09PSBtYXRjaGVzLmxlbmd0aCAtIDEpIHtcclxuICAgICAgICAgICAgICBtYXRjaEluZGV4ID0gMDtcclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICBtYXRjaEluZGV4Kys7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICBzZWFyY2hNYXRjaCA9IG1hdGNoZXNbbWF0Y2hJbmRleF07XHJcblxyXG4gICAgICAgICAgYWN0aXZlTGkgPSB0aGF0LnNlbGVjdHBpY2tlci5tYWluLmRhdGFbc2VhcmNoTWF0Y2hdO1xyXG5cclxuICAgICAgICAgIGlmIChzY3JvbGxUb3AgLSBhY3RpdmVMaS5wb3NpdGlvbiA+IDApIHtcclxuICAgICAgICAgICAgb2Zmc2V0ID0gYWN0aXZlTGkucG9zaXRpb24gLSBhY3RpdmVMaS5oZWlnaHQ7XHJcbiAgICAgICAgICAgIHVwZGF0ZVNjcm9sbCA9IHRydWU7XHJcbiAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICBvZmZzZXQgPSBhY3RpdmVMaS5wb3NpdGlvbiAtIHRoYXQuc2l6ZUluZm8ubWVudUlubmVySGVpZ2h0O1xyXG4gICAgICAgICAgICAvLyBpZiB0aGUgb3B0aW9uIGlzIGFscmVhZHkgdmlzaWJsZSBhdCB0aGUgY3VycmVudCBzY3JvbGwgcG9zaXRpb24sIGp1c3Qga2VlcCBpdCB0aGUgc2FtZVxyXG4gICAgICAgICAgICB1cGRhdGVTY3JvbGwgPSBhY3RpdmVMaS5wb3NpdGlvbiA+IHNjcm9sbFRvcCArIHRoYXQuc2l6ZUluZm8ubWVudUlubmVySGVpZ2h0O1xyXG4gICAgICAgICAgfVxyXG5cclxuICAgICAgICAgIGxpQWN0aXZlID0gdGhhdC5zZWxlY3RwaWNrZXIubWFpbi5lbGVtZW50c1tzZWFyY2hNYXRjaF07XHJcblxyXG4gICAgICAgICAgdGhhdC5hY3RpdmVJbmRleCA9IG1hdGNoZXNbbWF0Y2hJbmRleF07XHJcblxyXG4gICAgICAgICAgdGhhdC5mb2N1c0l0ZW0obGlBY3RpdmUpO1xyXG5cclxuICAgICAgICAgIGlmIChsaUFjdGl2ZSkgbGlBY3RpdmUuZmlyc3RDaGlsZC5mb2N1cygpO1xyXG5cclxuICAgICAgICAgIGlmICh1cGRhdGVTY3JvbGwpIHRoYXQuJG1lbnVJbm5lclswXS5zY3JvbGxUb3AgPSBvZmZzZXQ7XHJcblxyXG4gICAgICAgICAgJHRoaXMudHJpZ2dlcignZm9jdXMnKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIFNlbGVjdCBmb2N1c2VkIG9wdGlvbiBpZiBcIkVudGVyXCIsIFwiU3BhY2ViYXJcIiBvciBcIlRhYlwiICh3aGVuIHNlbGVjdE9uVGFiIGlzIHRydWUpIGFyZSBwcmVzc2VkIGluc2lkZSB0aGUgbWVudS5cclxuICAgICAgaWYgKFxyXG4gICAgICAgIGlzQWN0aXZlICYmXHJcbiAgICAgICAgKFxyXG4gICAgICAgICAgKGUud2hpY2ggPT09IGtleUNvZGVzLlNQQUNFICYmICF0aGF0LnNlbGVjdHBpY2tlci5rZXlkb3duLmtleUhpc3RvcnkpIHx8XHJcbiAgICAgICAgICBlLndoaWNoID09PSBrZXlDb2Rlcy5FTlRFUiB8fFxyXG4gICAgICAgICAgKGUud2hpY2ggPT09IGtleUNvZGVzLlRBQiAmJiB0aGF0Lm9wdGlvbnMuc2VsZWN0T25UYWIpXHJcbiAgICAgICAgKVxyXG4gICAgICApIHtcclxuICAgICAgICBpZiAoZS53aGljaCAhPT0ga2V5Q29kZXMuU1BBQ0UpIGUucHJldmVudERlZmF1bHQoKTtcclxuXHJcbiAgICAgICAgaWYgKCF0aGF0Lm9wdGlvbnMubGl2ZVNlYXJjaCB8fCBlLndoaWNoICE9PSBrZXlDb2Rlcy5TUEFDRSkge1xyXG4gICAgICAgICAgdGhhdC4kbWVudUlubmVyLmZpbmQoJy5hY3RpdmUgYScpLnRyaWdnZXIoJ2NsaWNrJywgdHJ1ZSk7IC8vIHJldGFpbiBhY3RpdmUgY2xhc3NcclxuICAgICAgICAgICR0aGlzLnRyaWdnZXIoJ2ZvY3VzJyk7XHJcblxyXG4gICAgICAgICAgaWYgKCF0aGF0Lm9wdGlvbnMubGl2ZVNlYXJjaCkge1xyXG4gICAgICAgICAgICAvLyBQcmV2ZW50IHNjcmVlbiBmcm9tIHNjcm9sbGluZyBpZiB0aGUgdXNlciBoaXRzIHRoZSBzcGFjZWJhclxyXG4gICAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XHJcbiAgICAgICAgICAgIC8vIEZpeGVzIHNwYWNlYmFyIHNlbGVjdGlvbiBvZiBkcm9wZG93biBpdGVtcyBpbiBGRiAmIElFXHJcbiAgICAgICAgICAgICQoZG9jdW1lbnQpLmRhdGEoJ3NwYWNlU2VsZWN0JywgdHJ1ZSk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9LFxyXG5cclxuICAgIG1vYmlsZTogZnVuY3Rpb24gKCkge1xyXG4gICAgICAvLyBlbnN1cmUgbW9iaWxlIGlzIHNldCB0byB0cnVlIGlmIG1vYmlsZSBmdW5jdGlvbiBpcyBjYWxsZWQgYWZ0ZXIgaW5pdFxyXG4gICAgICB0aGlzLm9wdGlvbnMubW9iaWxlID0gdHJ1ZTtcclxuICAgICAgdGhpcy4kZWxlbWVudFswXS5jbGFzc0xpc3QuYWRkKCdtb2JpbGUtZGV2aWNlJyk7XHJcbiAgICB9LFxyXG5cclxuICAgIHJlZnJlc2g6IGZ1bmN0aW9uICgpIHtcclxuICAgICAgdmFyIHRoYXQgPSB0aGlzO1xyXG4gICAgICAvLyB1cGRhdGUgb3B0aW9ucyBpZiBkYXRhIGF0dHJpYnV0ZXMgaGF2ZSBiZWVuIGNoYW5nZWRcclxuICAgICAgdmFyIGNvbmZpZyA9ICQuZXh0ZW5kKHt9LCB0aGlzLm9wdGlvbnMsIGdldEF0dHJpYnV0ZXNPYmplY3QodGhpcy4kZWxlbWVudCksIHRoaXMuJGVsZW1lbnQuZGF0YSgpKTsgLy8gaW4gdGhpcyBvcmRlciBvbiByZWZyZXNoLCBhcyB1c2VyIG1heSBjaGFuZ2UgYXR0cmlidXRlcyBvbiBzZWxlY3QsIGFuZCBvcHRpb25zIG9iamVjdCBpcyBub3QgcGFzc2VkIG9uIHJlZnJlc2hcclxuICAgICAgdGhpcy5vcHRpb25zID0gY29uZmlnO1xyXG5cclxuICAgICAgaWYgKHRoaXMub3B0aW9ucy5zb3VyY2UuZGF0YSkge1xyXG4gICAgICAgIHRoaXMucmVuZGVyKCk7XHJcbiAgICAgICAgdGhpcy5idWlsZExpc3QoKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICB0aGlzLmZldGNoRGF0YShmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICB0aGF0LnJlbmRlcigpO1xyXG4gICAgICAgICAgdGhhdC5idWlsZExpc3QoKTtcclxuICAgICAgICB9KTtcclxuICAgICAgfVxyXG5cclxuICAgICAgdGhpcy5jaGVja0Rpc2FibGVkKCk7XHJcbiAgICAgIHRoaXMuc2V0U3R5bGUoKTtcclxuICAgICAgdGhpcy5zZXRXaWR0aCgpO1xyXG5cclxuICAgICAgdGhpcy5zZXRTaXplKHRydWUpO1xyXG5cclxuICAgICAgdGhpcy4kZWxlbWVudC50cmlnZ2VyKCdyZWZyZXNoZWQnICsgRVZFTlRfS0VZKTtcclxuICAgIH0sXHJcblxyXG4gICAgaGlkZTogZnVuY3Rpb24gKCkge1xyXG4gICAgICB0aGlzLiRuZXdFbGVtZW50LmhpZGUoKTtcclxuICAgIH0sXHJcblxyXG4gICAgc2hvdzogZnVuY3Rpb24gKCkge1xyXG4gICAgICB0aGlzLiRuZXdFbGVtZW50LnNob3coKTtcclxuICAgIH0sXHJcblxyXG4gICAgcmVtb3ZlOiBmdW5jdGlvbiAoKSB7XHJcbiAgICAgIHRoaXMuJG5ld0VsZW1lbnQucmVtb3ZlKCk7XHJcbiAgICAgIHRoaXMuJGVsZW1lbnQucmVtb3ZlKCk7XHJcbiAgICB9LFxyXG5cclxuICAgIGRlc3Ryb3k6IGZ1bmN0aW9uICgpIHtcclxuICAgICAgdGhpcy4kbmV3RWxlbWVudC5iZWZvcmUodGhpcy4kZWxlbWVudCkucmVtb3ZlKCk7XHJcblxyXG4gICAgICBpZiAodGhpcy4kYnNDb250YWluZXIpIHtcclxuICAgICAgICB0aGlzLiRic0NvbnRhaW5lci5yZW1vdmUoKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICB0aGlzLiRtZW51LnJlbW92ZSgpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAodGhpcy5zZWxlY3RwaWNrZXIudmlldy50aXRsZU9wdGlvbiAmJiB0aGlzLnNlbGVjdHBpY2tlci52aWV3LnRpdGxlT3B0aW9uLnBhcmVudE5vZGUpIHtcclxuICAgICAgICB0aGlzLnNlbGVjdHBpY2tlci52aWV3LnRpdGxlT3B0aW9uLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQodGhpcy5zZWxlY3RwaWNrZXIudmlldy50aXRsZU9wdGlvbik7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHRoaXMuJGVsZW1lbnRcclxuICAgICAgICAub2ZmKEVWRU5UX0tFWSlcclxuICAgICAgICAucmVtb3ZlRGF0YSgnc2VsZWN0cGlja2VyJylcclxuICAgICAgICAucmVtb3ZlQ2xhc3MoJ2JzLXNlbGVjdC1oaWRkZW4gc2VsZWN0cGlja2VyJyk7XHJcblxyXG4gICAgICAkKHdpbmRvdykub2ZmKEVWRU5UX0tFWSArICcuJyArIHRoaXMuc2VsZWN0SWQpO1xyXG4gICAgfVxyXG4gIH07XHJcblxyXG4gIC8vIFNFTEVDVFBJQ0tFUiBQTFVHSU4gREVGSU5JVElPTlxyXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxyXG4gIGZ1bmN0aW9uIFBsdWdpbiAob3B0aW9uKSB7XHJcbiAgICAvLyBnZXQgdGhlIGFyZ3Mgb2YgdGhlIG91dGVyIGZ1bmN0aW9uLi5cclxuICAgIHZhciBhcmdzID0gYXJndW1lbnRzO1xyXG4gICAgLy8gVGhlIGFyZ3VtZW50cyBvZiB0aGUgZnVuY3Rpb24gYXJlIGV4cGxpY2l0bHkgcmUtZGVmaW5lZCBmcm9tIHRoZSBhcmd1bWVudCBsaXN0LCBiZWNhdXNlIHRoZSBzaGlmdCBjYXVzZXMgdGhlbVxyXG4gICAgLy8gdG8gZ2V0IGxvc3QvY29ycnVwdGVkIGluIGFuZHJvaWQgMi4zIGFuZCBJRTkgIzcxNSAjNzc1XHJcbiAgICB2YXIgX29wdGlvbiA9IG9wdGlvbjtcclxuXHJcbiAgICBbXS5zaGlmdC5hcHBseShhcmdzKTtcclxuXHJcbiAgICAvLyBpZiB0aGUgdmVyc2lvbiB3YXMgbm90IHNldCBzdWNjZXNzZnVsbHlcclxuICAgIGlmICghdmVyc2lvbi5zdWNjZXNzKSB7XHJcbiAgICAgIC8vIHRyeSB0byByZXRyZWl2ZSBpdCBhZ2FpblxyXG4gICAgICB0cnkge1xyXG4gICAgICAgIHZlcnNpb24uZnVsbCA9IChnZXRWZXJzaW9uKCkgfHwgJycpLnNwbGl0KCcgJylbMF0uc3BsaXQoJy4nKTtcclxuICAgICAgfSBjYXRjaCAoZXJyKSB7XHJcbiAgICAgICAgLy8gZmFsbCBiYWNrIHRvIHVzZSBCb290c3RyYXBWZXJzaW9uIGlmIHNldFxyXG4gICAgICAgIGlmIChTZWxlY3RwaWNrZXIuQm9vdHN0cmFwVmVyc2lvbikge1xyXG4gICAgICAgICAgdmVyc2lvbi5mdWxsID0gU2VsZWN0cGlja2VyLkJvb3RzdHJhcFZlcnNpb24uc3BsaXQoJyAnKVswXS5zcGxpdCgnLicpO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICB2ZXJzaW9uLmZ1bGwgPSBbdmVyc2lvbi5tYWpvciwgJzAnLCAnMCddO1xyXG5cclxuICAgICAgICAgIGNvbnNvbGUud2FybihcclxuICAgICAgICAgICAgJ1RoZXJlIHdhcyBhbiBpc3N1ZSByZXRyaWV2aW5nIEJvb3RzdHJhcFxcJ3MgdmVyc2lvbi4gJyArXHJcbiAgICAgICAgICAgICdFbnN1cmUgQm9vdHN0cmFwIGlzIGJlaW5nIGxvYWRlZCBiZWZvcmUgYm9vdHN0cmFwLXNlbGVjdCBhbmQgdGhlcmUgaXMgbm8gbmFtZXNwYWNlIGNvbGxpc2lvbi4gJyArXHJcbiAgICAgICAgICAgICdJZiBsb2FkaW5nIEJvb3RzdHJhcCBhc3luY2hyb25vdXNseSwgdGhlIHZlcnNpb24gbWF5IG5lZWQgdG8gYmUgbWFudWFsbHkgc3BlY2lmaWVkIHZpYSAkLmZuLnNlbGVjdHBpY2tlci5Db25zdHJ1Y3Rvci5Cb290c3RyYXBWZXJzaW9uLicsXHJcbiAgICAgICAgICAgIGVyclxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHZlcnNpb24ubWFqb3IgPSB2ZXJzaW9uLmZ1bGxbMF07XHJcbiAgICAgIHZlcnNpb24uc3VjY2VzcyA9IHRydWU7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHZlcnNpb24ubWFqb3IgPj0gJzQnKSB7XHJcbiAgICAgIC8vIHNvbWUgZGVmYXVsdHMgbmVlZCB0byBiZSBjaGFuZ2VkIGlmIHVzaW5nIEJvb3RzdHJhcCA0XHJcbiAgICAgIC8vIGNoZWNrIHRvIHNlZSBpZiB0aGV5IGhhdmUgYWxyZWFkeSBiZWVuIG1hbnVhbGx5IGNoYW5nZWQgYmVmb3JlIGZvcmNpbmcgdGhlbSB0byB1cGRhdGVcclxuICAgICAgdmFyIHRvVXBkYXRlID0gW107XHJcblxyXG4gICAgICBpZiAoU2VsZWN0cGlja2VyLkRFRkFVTFRTLnN0eWxlID09PSBjbGFzc05hbWVzLkJVVFRPTkNMQVNTKSB0b1VwZGF0ZS5wdXNoKHsgbmFtZTogJ3N0eWxlJywgY2xhc3NOYW1lOiAnQlVUVE9OQ0xBU1MnIH0pO1xyXG4gICAgICBpZiAoU2VsZWN0cGlja2VyLkRFRkFVTFRTLmljb25CYXNlID09PSBjbGFzc05hbWVzLklDT05CQVNFKSB0b1VwZGF0ZS5wdXNoKHsgbmFtZTogJ2ljb25CYXNlJywgY2xhc3NOYW1lOiAnSUNPTkJBU0UnIH0pO1xyXG4gICAgICBpZiAoU2VsZWN0cGlja2VyLkRFRkFVTFRTLnRpY2tJY29uID09PSBjbGFzc05hbWVzLlRJQ0tJQ09OKSB0b1VwZGF0ZS5wdXNoKHsgbmFtZTogJ3RpY2tJY29uJywgY2xhc3NOYW1lOiAnVElDS0lDT04nIH0pO1xyXG5cclxuICAgICAgY2xhc3NOYW1lcy5ESVZJREVSID0gJ2Ryb3Bkb3duLWRpdmlkZXInO1xyXG4gICAgICBjbGFzc05hbWVzLlNIT1cgPSAnc2hvdyc7XHJcbiAgICAgIGNsYXNzTmFtZXMuQlVUVE9OQ0xBU1MgPSAnYnRuLWxpZ2h0JztcclxuICAgICAgY2xhc3NOYW1lcy5QT1BPVkVSSEVBREVSID0gJ3BvcG92ZXItaGVhZGVyJztcclxuICAgICAgY2xhc3NOYW1lcy5JQ09OQkFTRSA9ICcnO1xyXG4gICAgICBjbGFzc05hbWVzLlRJQ0tJQ09OID0gJ2JzLW9rLWRlZmF1bHQnO1xyXG5cclxuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0b1VwZGF0ZS5sZW5ndGg7IGkrKykge1xyXG4gICAgICAgIHZhciBvcHRpb24gPSB0b1VwZGF0ZVtpXTtcclxuICAgICAgICBTZWxlY3RwaWNrZXIuREVGQVVMVFNbb3B0aW9uLm5hbWVdID0gY2xhc3NOYW1lc1tvcHRpb24uY2xhc3NOYW1lXTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIGlmICh2ZXJzaW9uLm1ham9yID4gJzQnKSB7XHJcbiAgICAgIFNlbGVjdG9yLkRBVEFfVE9HR0xFID0gJ2RhdGEtYnMtdG9nZ2xlPVwiZHJvcGRvd25cIidcclxuICAgIH1cclxuXHJcbiAgICB2YXIgdmFsdWU7XHJcbiAgICB2YXIgY2hhaW4gPSB0aGlzLmVhY2goZnVuY3Rpb24gKCkge1xyXG4gICAgICB2YXIgJHRoaXMgPSAkKHRoaXMpO1xyXG4gICAgICBpZiAoJHRoaXMuaXMoJ3NlbGVjdCcpKSB7XHJcbiAgICAgICAgdmFyIGRhdGEgPSAkdGhpcy5kYXRhKCdzZWxlY3RwaWNrZXInKSxcclxuICAgICAgICAgICAgb3B0aW9ucyA9IHR5cGVvZiBfb3B0aW9uID09ICdvYmplY3QnICYmIF9vcHRpb247XHJcblxyXG4gICAgICAgIC8vIGZvciBiYWNrd2FyZHMgY29tcGF0aWJpbGl0eVxyXG4gICAgICAgIC8vICh1c2luZyB0aXRsZSBhcyBwbGFjZWhvbGRlciBpcyBkZXByZWNhdGVkIC0gcmVtb3ZlIGluIHYyLjAuMClcclxuICAgICAgICBpZiAob3B0aW9ucy50aXRsZSkgb3B0aW9ucy5wbGFjZWhvbGRlciA9IG9wdGlvbnMudGl0bGU7XHJcblxyXG4gICAgICAgIGlmICghZGF0YSkge1xyXG4gICAgICAgICAgdmFyIGRhdGFBdHRyaWJ1dGVzID0gJHRoaXMuZGF0YSgpO1xyXG5cclxuICAgICAgICAgIGZvciAodmFyIGRhdGFBdHRyIGluIGRhdGFBdHRyaWJ1dGVzKSB7XHJcbiAgICAgICAgICAgIGlmIChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoZGF0YUF0dHJpYnV0ZXMsIGRhdGFBdHRyKSAmJiAkLmluQXJyYXkoZGF0YUF0dHIsIERJU0FMTE9XRURfQVRUUklCVVRFUykgIT09IC0xKSB7XHJcbiAgICAgICAgICAgICAgZGVsZXRlIGRhdGFBdHRyaWJ1dGVzW2RhdGFBdHRyXTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG5cclxuICAgICAgICAgIHZhciBjb25maWcgPSAkLmV4dGVuZCh7fSwgU2VsZWN0cGlja2VyLkRFRkFVTFRTLCAkLmZuLnNlbGVjdHBpY2tlci5kZWZhdWx0cyB8fCB7fSwgZ2V0QXR0cmlidXRlc09iamVjdCgkdGhpcyksIGRhdGFBdHRyaWJ1dGVzLCBvcHRpb25zKTsgLy8gdGhpcyBpcyBjb3JyZWN0IG9yZGVyIG9uIGluaXRpYWwgcmVuZGVyXHJcbiAgICAgICAgICBjb25maWcudGVtcGxhdGUgPSAkLmV4dGVuZCh7fSwgU2VsZWN0cGlja2VyLkRFRkFVTFRTLnRlbXBsYXRlLCAoJC5mbi5zZWxlY3RwaWNrZXIuZGVmYXVsdHMgPyAkLmZuLnNlbGVjdHBpY2tlci5kZWZhdWx0cy50ZW1wbGF0ZSA6IHt9KSwgZGF0YUF0dHJpYnV0ZXMudGVtcGxhdGUsIG9wdGlvbnMudGVtcGxhdGUpO1xyXG4gICAgICAgICAgJHRoaXMuZGF0YSgnc2VsZWN0cGlja2VyJywgKGRhdGEgPSBuZXcgU2VsZWN0cGlja2VyKHRoaXMsIGNvbmZpZykpKTtcclxuICAgICAgICB9IGVsc2UgaWYgKG9wdGlvbnMpIHtcclxuICAgICAgICAgIGZvciAodmFyIGkgaW4gb3B0aW9ucykge1xyXG4gICAgICAgICAgICBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9wdGlvbnMsIGkpKSB7XHJcbiAgICAgICAgICAgICAgZGF0YS5vcHRpb25zW2ldID0gb3B0aW9uc1tpXTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgaWYgKHR5cGVvZiBfb3B0aW9uID09ICdzdHJpbmcnKSB7XHJcbiAgICAgICAgICBpZiAoZGF0YVtfb3B0aW9uXSBpbnN0YW5jZW9mIEZ1bmN0aW9uKSB7XHJcbiAgICAgICAgICAgIHZhbHVlID0gZGF0YVtfb3B0aW9uXS5hcHBseShkYXRhLCBhcmdzKTtcclxuICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIHZhbHVlID0gZGF0YS5vcHRpb25zW19vcHRpb25dO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfSk7XHJcblxyXG4gICAgaWYgKHR5cGVvZiB2YWx1ZSAhPT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgLy8gbm9pbnNwZWN0aW9uIEpTVW51c2VkQXNzaWdubWVudFxyXG4gICAgICByZXR1cm4gdmFsdWU7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICByZXR1cm4gY2hhaW47XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICB2YXIgb2xkID0gJC5mbi5zZWxlY3RwaWNrZXI7XHJcbiAgJC5mbi5zZWxlY3RwaWNrZXIgPSBQbHVnaW47XHJcbiAgJC5mbi5zZWxlY3RwaWNrZXIuQ29uc3RydWN0b3IgPSBTZWxlY3RwaWNrZXI7XHJcblxyXG4gIC8vIFNFTEVDVFBJQ0tFUiBOTyBDT05GTElDVFxyXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PVxyXG4gICQuZm4uc2VsZWN0cGlja2VyLm5vQ29uZmxpY3QgPSBmdW5jdGlvbiAoKSB7XHJcbiAgICAkLmZuLnNlbGVjdHBpY2tlciA9IG9sZDtcclxuICAgIHJldHVybiB0aGlzO1xyXG4gIH07XHJcblxyXG4gIC8vIGdldCBCb290c3RyYXAncyBrZXlkb3duIGV2ZW50IGhhbmRsZXIgZm9yIGVpdGhlciBCb290c3RyYXAgNCBvciBCb290c3RyYXAgM1xyXG4gIGZ1bmN0aW9uIGtleWRvd25IYW5kbGVyICgpIHtcclxuICAgIGlmICh2ZXJzaW9uLm1ham9yIDwgNSkge1xyXG4gICAgICBpZiAoJC5mbi5kcm9wZG93bikge1xyXG4gICAgICAgIC8vIHdhaXQgdG8gZGVmaW5lIHVudGlsIGZ1bmN0aW9uIGlzIGNhbGxlZCBpbiBjYXNlIEJvb3RzdHJhcCBpc24ndCBsb2FkZWQgeWV0XHJcbiAgICAgICAgdmFyIGJvb3RzdHJhcEtleWRvd24gPSAkLmZuLmRyb3Bkb3duLkNvbnN0cnVjdG9yLl9kYXRhQXBpS2V5ZG93bkhhbmRsZXIgfHwgJC5mbi5kcm9wZG93bi5Db25zdHJ1Y3Rvci5wcm90b3R5cGUua2V5ZG93bjtcclxuICAgICAgICByZXR1cm4gYm9vdHN0cmFwS2V5ZG93bi5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xyXG4gICAgICB9XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICByZXR1cm4gRHJvcGRvd24uZGF0YUFwaUtleWRvd25IYW5kbGVyO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgJChkb2N1bWVudClcclxuICAgIC5vZmYoJ2tleWRvd24uYnMuZHJvcGRvd24uZGF0YS1hcGknKVxyXG4gICAgLm9uKCdrZXlkb3duLmJzLmRyb3Bkb3duLmRhdGEtYXBpJywgJzpub3QoLmJvb3RzdHJhcC1zZWxlY3QpID4gWycgKyBTZWxlY3Rvci5EQVRBX1RPR0dMRSArICddJywga2V5ZG93bkhhbmRsZXIpXHJcbiAgICAub24oJ2tleWRvd24uYnMuZHJvcGRvd24uZGF0YS1hcGknLCAnOm5vdCguYm9vdHN0cmFwLXNlbGVjdCkgPiAuZHJvcGRvd24tbWVudScsIGtleWRvd25IYW5kbGVyKVxyXG4gICAgLm9uKCdrZXlkb3duJyArIEVWRU5UX0tFWSwgJy5ib290c3RyYXAtc2VsZWN0IFsnICsgU2VsZWN0b3IuREFUQV9UT0dHTEUgKyAnXSwgLmJvb3RzdHJhcC1zZWxlY3QgW3JvbGU9XCJsaXN0Ym94XCJdLCAuYm9vdHN0cmFwLXNlbGVjdCAuYnMtc2VhcmNoYm94IGlucHV0JywgU2VsZWN0cGlja2VyLnByb3RvdHlwZS5rZXlkb3duKVxyXG4gICAgLm9uKCdmb2N1c2luLm1vZGFsJywgJy5ib290c3RyYXAtc2VsZWN0IFsnICsgU2VsZWN0b3IuREFUQV9UT0dHTEUgKyAnXSwgLmJvb3RzdHJhcC1zZWxlY3QgW3JvbGU9XCJsaXN0Ym94XCJdLCAuYm9vdHN0cmFwLXNlbGVjdCAuYnMtc2VhcmNoYm94IGlucHV0JywgZnVuY3Rpb24gKGUpIHtcclxuICAgICAgZS5zdG9wUHJvcGFnYXRpb24oKTtcclxuICAgIH0pO1xyXG5cclxuICAvLyBTRUxFQ1RQSUNLRVIgREFUQS1BUElcclxuICAvLyA9PT09PT09PT09PT09PT09PT09PT1cclxuICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCdET01Db250ZW50TG9hZGVkJywgZnVuY3Rpb24gKCkge1xyXG4gICAgJCgnLnNlbGVjdHBpY2tlcicpLmVhY2goZnVuY3Rpb24gKCkge1xyXG4gICAgICB2YXIgJHNlbGVjdHBpY2tlciA9ICQodGhpcyk7XHJcbiAgICAgIFBsdWdpbi5jYWxsKCRzZWxlY3RwaWNrZXIsICRzZWxlY3RwaWNrZXIuZGF0YSgpKTtcclxuICAgIH0pXHJcbiAgfSk7XHJcbn0pKGpRdWVyeSk7XHJcblxyXG5cclxufSkpO1xuLy8jIHNvdXJjZU1hcHBpbmdVUkw9Ym9vdHN0cmFwLXNlbGVjdC5qcy5tYXAiXSwic291cmNlUm9vdCI6IiJ9", "@public_path/build/vendors-node_modules_bootstrap-select_dist_js_bootstrap-select_js.js", "/builds/dev/refonte_sav/public/build/vendors-node_modules_bootstrap-select_dist_js_bootstrap-select_js.js");
    }
}
