zordius/webtasks

View on GitHub
static/js/main.js

Summary

Maintainability
A
0 mins
Test Coverage
require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({"$R":[function(require,module,exports){
var React = require('react'),
 REACTS = {
 './react/Bug.jsx': require('./react/Bug.jsx'),
 './react/LimitSelect.jsx': require('./react/LimitSelect.jsx'),
 './react/Path.jsx': require('./react/Path.jsx'),
 './react/Product.jsx': require('./react/Product.jsx'),
},
render = function (N, D, M) {React.render(React.createFactory(REACTS[N])(D), M);
return render};
module.exports = render;
},{"./react/Bug.jsx":"/Users/zordius/webtasks/react/Bug.jsx","./react/LimitSelect.jsx":"/Users/zordius/webtasks/react/LimitSelect.jsx","./react/Path.jsx":"/Users/zordius/webtasks/react/Path.jsx","./react/Product.jsx":"/Users/zordius/webtasks/react/Product.jsx","react":"/Users/zordius/webtasks/node_modules/react/react.js"}],"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js":[function(require,module,exports){
// shim for using process in browser

var process = module.exports = {};

process.nextTick = (function () {
    var canSetImmediate = typeof window !== 'undefined'
    && window.setImmediate;
    var canMutationObserver = typeof window !== 'undefined'
    && window.MutationObserver;
    var canPost = typeof window !== 'undefined'
    && window.postMessage && window.addEventListener
    ;

    if (canSetImmediate) {
        return function (f) { return window.setImmediate(f) };
    }

    var queue = [];

    if (canMutationObserver) {
        var hiddenDiv = document.createElement("div");
        var observer = new MutationObserver(function () {
            var queueList = queue.slice();
            queue.length = 0;
            queueList.forEach(function (fn) {
                fn();
            });
        });

        observer.observe(hiddenDiv, { attributes: true });

        return function nextTick(fn) {
            if (!queue.length) {
                hiddenDiv.setAttribute('yes', 'no');
            }
            queue.push(fn);
        };
    }

    if (canPost) {
        window.addEventListener('message', function (ev) {
            var source = ev.source;
            if ((source === window || source === null) && ev.data === 'process-tick') {
                ev.stopPropagation();
                if (queue.length > 0) {
                    var fn = queue.shift();
                    fn();
                }
            }
        }, true);

        return function nextTick(fn) {
            queue.push(fn);
            window.postMessage('process-tick', '*');
        };
    }

    return function nextTick(fn) {
        setTimeout(fn, 0);
    };
})();

process.title = 'browser';
process.browser = true;
process.env = {};
process.argv = [];

function noop() {}

process.on = noop;
process.addListener = noop;
process.once = noop;
process.off = noop;
process.removeListener = noop;
process.removeAllListeners = noop;
process.emit = noop;

process.binding = function (name) {
    throw new Error('process.binding is not supported');
};

// TODO(shtylman)
process.cwd = function () { return '/' };
process.chdir = function (dir) {
    throw new Error('process.chdir is not supported');
};

},{}],"/Users/zordius/webtasks/node_modules/react/lib/AutoFocusMixin.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule AutoFocusMixin
 * @typechecks static-only
 */

"use strict";

var focusNode = require("./focusNode");

var AutoFocusMixin = {
  componentDidMount: function() {
    if (this.props.autoFocus) {
      focusNode(this.getDOMNode());
    }
  }
};

module.exports = AutoFocusMixin;

},{"./focusNode":"/Users/zordius/webtasks/node_modules/react/lib/focusNode.js"}],"/Users/zordius/webtasks/node_modules/react/lib/BeforeInputEventPlugin.js":[function(require,module,exports){
/**
 * Copyright 2013 Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule BeforeInputEventPlugin
 * @typechecks static-only
 */

"use strict";

var EventConstants = require("./EventConstants");
var EventPropagators = require("./EventPropagators");
var ExecutionEnvironment = require("./ExecutionEnvironment");
var SyntheticInputEvent = require("./SyntheticInputEvent");

var keyOf = require("./keyOf");

var canUseTextInputEvent = (
  ExecutionEnvironment.canUseDOM &&
  'TextEvent' in window &&
  !('documentMode' in document || isPresto())
);

/**
 * Opera <= 12 includes TextEvent in window, but does not fire
 * text input events. Rely on keypress instead.
 */
function isPresto() {
  var opera = window.opera;
  return (
    typeof opera === 'object' &&
    typeof opera.version === 'function' &&
    parseInt(opera.version(), 10) <= 12
  );
}

var SPACEBAR_CODE = 32;
var SPACEBAR_CHAR = String.fromCharCode(SPACEBAR_CODE);

var topLevelTypes = EventConstants.topLevelTypes;

// Events and their corresponding property names.
var eventTypes = {
  beforeInput: {
    phasedRegistrationNames: {
      bubbled: keyOf({onBeforeInput: null}),
      captured: keyOf({onBeforeInputCapture: null})
    },
    dependencies: [
      topLevelTypes.topCompositionEnd,
      topLevelTypes.topKeyPress,
      topLevelTypes.topTextInput,
      topLevelTypes.topPaste
    ]
  }
};

// Track characters inserted via keypress and composition events.
var fallbackChars = null;

// Track whether we've ever handled a keypress on the space key.
var hasSpaceKeypress = false;

/**
 * Return whether a native keypress event is assumed to be a command.
 * This is required because Firefox fires `keypress` events for key commands
 * (cut, copy, select-all, etc.) even though no character is inserted.
 */
function isKeypressCommand(nativeEvent) {
  return (
    (nativeEvent.ctrlKey || nativeEvent.altKey || nativeEvent.metaKey) &&
    // ctrlKey && altKey is equivalent to AltGr, and is not a command.
    !(nativeEvent.ctrlKey && nativeEvent.altKey)
  );
}

/**
 * Create an `onBeforeInput` event to match
 * http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105/#events-inputevents.
 *
 * This event plugin is based on the native `textInput` event
 * available in Chrome, Safari, Opera, and IE. This event fires after
 * `onKeyPress` and `onCompositionEnd`, but before `onInput`.
 *
 * `beforeInput` is spec'd but not implemented in any browsers, and
 * the `input` event does not provide any useful information about what has
 * actually been added, contrary to the spec. Thus, `textInput` is the best
 * available event to identify the characters that have actually been inserted
 * into the target node.
 */
var BeforeInputEventPlugin = {

  eventTypes: eventTypes,

  /**
   * @param {string} topLevelType Record from `EventConstants`.
   * @param {DOMEventTarget} topLevelTarget The listening component root node.
   * @param {string} topLevelTargetID ID of `topLevelTarget`.
   * @param {object} nativeEvent Native browser event.
   * @return {*} An accumulation of synthetic events.
   * @see {EventPluginHub.extractEvents}
   */
  extractEvents: function(
      topLevelType,
      topLevelTarget,
      topLevelTargetID,
      nativeEvent) {

    var chars;

    if (canUseTextInputEvent) {
      switch (topLevelType) {
        case topLevelTypes.topKeyPress:
          /**
           * If native `textInput` events are available, our goal is to make
           * use of them. However, there is a special case: the spacebar key.
           * In Webkit, preventing default on a spacebar `textInput` event
           * cancels character insertion, but it *also* causes the browser
           * to fall back to its default spacebar behavior of scrolling the
           * page.
           *
           * Tracking at:
           * https://code.google.com/p/chromium/issues/detail?id=355103
           *
           * To avoid this issue, use the keypress event as if no `textInput`
           * event is available.
           */
          var which = nativeEvent.which;
          if (which !== SPACEBAR_CODE) {
            return;
          }

          hasSpaceKeypress = true;
          chars = SPACEBAR_CHAR;
          break;

        case topLevelTypes.topTextInput:
          // Record the characters to be added to the DOM.
          chars = nativeEvent.data;

          // If it's a spacebar character, assume that we have already handled
          // it at the keypress level and bail immediately. Android Chrome
          // doesn't give us keycodes, so we need to blacklist it.
          if (chars === SPACEBAR_CHAR && hasSpaceKeypress) {
            return;
          }

          // Otherwise, carry on.
          break;

        default:
          // For other native event types, do nothing.
          return;
      }
    } else {
      switch (topLevelType) {
        case topLevelTypes.topPaste:
          // If a paste event occurs after a keypress, throw out the input
          // chars. Paste events should not lead to BeforeInput events.
          fallbackChars = null;
          break;
        case topLevelTypes.topKeyPress:
          /**
           * As of v27, Firefox may fire keypress events even when no character
           * will be inserted. A few possibilities:
           *
           * - `which` is `0`. Arrow keys, Esc key, etc.
           *
           * - `which` is the pressed key code, but no char is available.
           *   Ex: 'AltGr + d` in Polish. There is no modified character for
           *   this key combination and no character is inserted into the
           *   document, but FF fires the keypress for char code `100` anyway.
           *   No `input` event will occur.
           *
           * - `which` is the pressed key code, but a command combination is
           *   being used. Ex: `Cmd+C`. No character is inserted, and no
           *   `input` event will occur.
           */
          if (nativeEvent.which && !isKeypressCommand(nativeEvent)) {
            fallbackChars = String.fromCharCode(nativeEvent.which);
          }
          break;
        case topLevelTypes.topCompositionEnd:
          fallbackChars = nativeEvent.data;
          break;
      }

      // If no changes have occurred to the fallback string, no relevant
      // event has fired and we're done.
      if (fallbackChars === null) {
        return;
      }

      chars = fallbackChars;
    }

    // If no characters are being inserted, no BeforeInput event should
    // be fired.
    if (!chars) {
      return;
    }

    var event = SyntheticInputEvent.getPooled(
      eventTypes.beforeInput,
      topLevelTargetID,
      nativeEvent
    );

    event.data = chars;
    fallbackChars = null;
    EventPropagators.accumulateTwoPhaseDispatches(event);
    return event;
  }
};

module.exports = BeforeInputEventPlugin;

},{"./EventConstants":"/Users/zordius/webtasks/node_modules/react/lib/EventConstants.js","./EventPropagators":"/Users/zordius/webtasks/node_modules/react/lib/EventPropagators.js","./ExecutionEnvironment":"/Users/zordius/webtasks/node_modules/react/lib/ExecutionEnvironment.js","./SyntheticInputEvent":"/Users/zordius/webtasks/node_modules/react/lib/SyntheticInputEvent.js","./keyOf":"/Users/zordius/webtasks/node_modules/react/lib/keyOf.js"}],"/Users/zordius/webtasks/node_modules/react/lib/CSSProperty.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule CSSProperty
 */

"use strict";

/**
 * CSS properties which accept numbers but are not in units of "px".
 */
var isUnitlessNumber = {
  columnCount: true,
  fillOpacity: true,
  flex: true,
  flexGrow: true,
  flexShrink: true,
  fontWeight: true,
  lineClamp: true,
  lineHeight: true,
  opacity: true,
  order: true,
  orphans: true,
  widows: true,
  zIndex: true,
  zoom: true
};

/**
 * @param {string} prefix vendor-specific prefix, eg: Webkit
 * @param {string} key style name, eg: transitionDuration
 * @return {string} style name prefixed with `prefix`, properly camelCased, eg:
 * WebkitTransitionDuration
 */
function prefixKey(prefix, key) {
  return prefix + key.charAt(0).toUpperCase() + key.substring(1);
}

/**
 * Support style names that may come passed in prefixed by adding permutations
 * of vendor prefixes.
 */
var prefixes = ['Webkit', 'ms', 'Moz', 'O'];

// Using Object.keys here, or else the vanilla for-in loop makes IE8 go into an
// infinite loop, because it iterates over the newly added props too.
Object.keys(isUnitlessNumber).forEach(function(prop) {
  prefixes.forEach(function(prefix) {
    isUnitlessNumber[prefixKey(prefix, prop)] = isUnitlessNumber[prop];
  });
});

/**
 * Most style properties can be unset by doing .style[prop] = '' but IE8
 * doesn't like doing that with shorthand properties so for the properties that
 * IE8 breaks on, which are listed here, we instead unset each of the
 * individual properties. See http://bugs.jquery.com/ticket/12385.
 * The 4-value 'clock' properties like margin, padding, border-width seem to
 * behave without any problems. Curiously, list-style works too without any
 * special prodding.
 */
var shorthandPropertyExpansions = {
  background: {
    backgroundImage: true,
    backgroundPosition: true,
    backgroundRepeat: true,
    backgroundColor: true
  },
  border: {
    borderWidth: true,
    borderStyle: true,
    borderColor: true
  },
  borderBottom: {
    borderBottomWidth: true,
    borderBottomStyle: true,
    borderBottomColor: true
  },
  borderLeft: {
    borderLeftWidth: true,
    borderLeftStyle: true,
    borderLeftColor: true
  },
  borderRight: {
    borderRightWidth: true,
    borderRightStyle: true,
    borderRightColor: true
  },
  borderTop: {
    borderTopWidth: true,
    borderTopStyle: true,
    borderTopColor: true
  },
  font: {
    fontStyle: true,
    fontVariant: true,
    fontWeight: true,
    fontSize: true,
    lineHeight: true,
    fontFamily: true
  }
};

var CSSProperty = {
  isUnitlessNumber: isUnitlessNumber,
  shorthandPropertyExpansions: shorthandPropertyExpansions
};

module.exports = CSSProperty;

},{}],"/Users/zordius/webtasks/node_modules/react/lib/CSSPropertyOperations.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule CSSPropertyOperations
 * @typechecks static-only
 */

"use strict";

var CSSProperty = require("./CSSProperty");
var ExecutionEnvironment = require("./ExecutionEnvironment");

var camelizeStyleName = require("./camelizeStyleName");
var dangerousStyleValue = require("./dangerousStyleValue");
var hyphenateStyleName = require("./hyphenateStyleName");
var memoizeStringOnly = require("./memoizeStringOnly");
var warning = require("./warning");

var processStyleName = memoizeStringOnly(function(styleName) {
  return hyphenateStyleName(styleName);
});

var styleFloatAccessor = 'cssFloat';
if (ExecutionEnvironment.canUseDOM) {
  // IE8 only supports accessing cssFloat (standard) as styleFloat
  if (document.documentElement.style.cssFloat === undefined) {
    styleFloatAccessor = 'styleFloat';
  }
}

if ("production" !== process.env.NODE_ENV) {
  var warnedStyleNames = {};

  var warnHyphenatedStyleName = function(name) {
    if (warnedStyleNames.hasOwnProperty(name) && warnedStyleNames[name]) {
      return;
    }

    warnedStyleNames[name] = true;
    ("production" !== process.env.NODE_ENV ? warning(
      false,
      'Unsupported style property ' + name + '. Did you mean ' +
      camelizeStyleName(name) + '?'
    ) : null);
  };
}

/**
 * Operations for dealing with CSS properties.
 */
var CSSPropertyOperations = {

  /**
   * Serializes a mapping of style properties for use as inline styles:
   *
   *   > createMarkupForStyles({width: '200px', height: 0})
   *   "width:200px;height:0;"
   *
   * Undefined values are ignored so that declarative programming is easier.
   * The result should be HTML-escaped before insertion into the DOM.
   *
   * @param {object} styles
   * @return {?string}
   */
  createMarkupForStyles: function(styles) {
    var serialized = '';
    for (var styleName in styles) {
      if (!styles.hasOwnProperty(styleName)) {
        continue;
      }
      if ("production" !== process.env.NODE_ENV) {
        if (styleName.indexOf('-') > -1) {
          warnHyphenatedStyleName(styleName);
        }
      }
      var styleValue = styles[styleName];
      if (styleValue != null) {
        serialized += processStyleName(styleName) + ':';
        serialized += dangerousStyleValue(styleName, styleValue) + ';';
      }
    }
    return serialized || null;
  },

  /**
   * Sets the value for multiple styles on a node.  If a value is specified as
   * '' (empty string), the corresponding style property will be unset.
   *
   * @param {DOMElement} node
   * @param {object} styles
   */
  setValueForStyles: function(node, styles) {
    var style = node.style;
    for (var styleName in styles) {
      if (!styles.hasOwnProperty(styleName)) {
        continue;
      }
      if ("production" !== process.env.NODE_ENV) {
        if (styleName.indexOf('-') > -1) {
          warnHyphenatedStyleName(styleName);
        }
      }
      var styleValue = dangerousStyleValue(styleName, styles[styleName]);
      if (styleName === 'float') {
        styleName = styleFloatAccessor;
      }
      if (styleValue) {
        style[styleName] = styleValue;
      } else {
        var expansion = CSSProperty.shorthandPropertyExpansions[styleName];
        if (expansion) {
          // Shorthand property that IE8 won't like unsetting, so unset each
          // component to placate it
          for (var individualStyleName in expansion) {
            style[individualStyleName] = '';
          }
        } else {
          style[styleName] = '';
        }
      }
    }
  }

};

module.exports = CSSPropertyOperations;

}).call(this,require('_process'))
},{"./CSSProperty":"/Users/zordius/webtasks/node_modules/react/lib/CSSProperty.js","./ExecutionEnvironment":"/Users/zordius/webtasks/node_modules/react/lib/ExecutionEnvironment.js","./camelizeStyleName":"/Users/zordius/webtasks/node_modules/react/lib/camelizeStyleName.js","./dangerousStyleValue":"/Users/zordius/webtasks/node_modules/react/lib/dangerousStyleValue.js","./hyphenateStyleName":"/Users/zordius/webtasks/node_modules/react/lib/hyphenateStyleName.js","./memoizeStringOnly":"/Users/zordius/webtasks/node_modules/react/lib/memoizeStringOnly.js","./warning":"/Users/zordius/webtasks/node_modules/react/lib/warning.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/CallbackQueue.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule CallbackQueue
 */

"use strict";

var PooledClass = require("./PooledClass");

var assign = require("./Object.assign");
var invariant = require("./invariant");

/**
 * A specialized pseudo-event module to help keep track of components waiting to
 * be notified when their DOM representations are available for use.
 *
 * This implements `PooledClass`, so you should never need to instantiate this.
 * Instead, use `CallbackQueue.getPooled()`.
 *
 * @class ReactMountReady
 * @implements PooledClass
 * @internal
 */
function CallbackQueue() {
  this._callbacks = null;
  this._contexts = null;
}

assign(CallbackQueue.prototype, {

  /**
   * Enqueues a callback to be invoked when `notifyAll` is invoked.
   *
   * @param {function} callback Invoked when `notifyAll` is invoked.
   * @param {?object} context Context to call `callback` with.
   * @internal
   */
  enqueue: function(callback, context) {
    this._callbacks = this._callbacks || [];
    this._contexts = this._contexts || [];
    this._callbacks.push(callback);
    this._contexts.push(context);
  },

  /**
   * Invokes all enqueued callbacks and clears the queue. This is invoked after
   * the DOM representation of a component has been created or updated.
   *
   * @internal
   */
  notifyAll: function() {
    var callbacks = this._callbacks;
    var contexts = this._contexts;
    if (callbacks) {
      ("production" !== process.env.NODE_ENV ? invariant(
        callbacks.length === contexts.length,
        "Mismatched list of contexts in callback queue"
      ) : invariant(callbacks.length === contexts.length));
      this._callbacks = null;
      this._contexts = null;
      for (var i = 0, l = callbacks.length; i < l; i++) {
        callbacks[i].call(contexts[i]);
      }
      callbacks.length = 0;
      contexts.length = 0;
    }
  },

  /**
   * Resets the internal queue.
   *
   * @internal
   */
  reset: function() {
    this._callbacks = null;
    this._contexts = null;
  },

  /**
   * `PooledClass` looks for this.
   */
  destructor: function() {
    this.reset();
  }

});

PooledClass.addPoolingTo(CallbackQueue);

module.exports = CallbackQueue;

}).call(this,require('_process'))
},{"./Object.assign":"/Users/zordius/webtasks/node_modules/react/lib/Object.assign.js","./PooledClass":"/Users/zordius/webtasks/node_modules/react/lib/PooledClass.js","./invariant":"/Users/zordius/webtasks/node_modules/react/lib/invariant.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ChangeEventPlugin.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ChangeEventPlugin
 */

"use strict";

var EventConstants = require("./EventConstants");
var EventPluginHub = require("./EventPluginHub");
var EventPropagators = require("./EventPropagators");
var ExecutionEnvironment = require("./ExecutionEnvironment");
var ReactUpdates = require("./ReactUpdates");
var SyntheticEvent = require("./SyntheticEvent");

var isEventSupported = require("./isEventSupported");
var isTextInputElement = require("./isTextInputElement");
var keyOf = require("./keyOf");

var topLevelTypes = EventConstants.topLevelTypes;

var eventTypes = {
  change: {
    phasedRegistrationNames: {
      bubbled: keyOf({onChange: null}),
      captured: keyOf({onChangeCapture: null})
    },
    dependencies: [
      topLevelTypes.topBlur,
      topLevelTypes.topChange,
      topLevelTypes.topClick,
      topLevelTypes.topFocus,
      topLevelTypes.topInput,
      topLevelTypes.topKeyDown,
      topLevelTypes.topKeyUp,
      topLevelTypes.topSelectionChange
    ]
  }
};

/**
 * For IE shims
 */
var activeElement = null;
var activeElementID = null;
var activeElementValue = null;
var activeElementValueProp = null;

/**
 * SECTION: handle `change` event
 */
function shouldUseChangeEvent(elem) {
  return (
    elem.nodeName === 'SELECT' ||
    (elem.nodeName === 'INPUT' && elem.type === 'file')
  );
}

var doesChangeEventBubble = false;
if (ExecutionEnvironment.canUseDOM) {
  // See `handleChange` comment below
  doesChangeEventBubble = isEventSupported('change') && (
    !('documentMode' in document) || document.documentMode > 8
  );
}

function manualDispatchChangeEvent(nativeEvent) {
  var event = SyntheticEvent.getPooled(
    eventTypes.change,
    activeElementID,
    nativeEvent
  );
  EventPropagators.accumulateTwoPhaseDispatches(event);

  // If change and propertychange bubbled, we'd just bind to it like all the
  // other events and have it go through ReactBrowserEventEmitter. Since it
  // doesn't, we manually listen for the events and so we have to enqueue and
  // process the abstract event manually.
  //
  // Batching is necessary here in order to ensure that all event handlers run
  // before the next rerender (including event handlers attached to ancestor
  // elements instead of directly on the input). Without this, controlled
  // components don't work properly in conjunction with event bubbling because
  // the component is rerendered and the value reverted before all the event
  // handlers can run. See https://github.com/facebook/react/issues/708.
  ReactUpdates.batchedUpdates(runEventInBatch, event);
}

function runEventInBatch(event) {
  EventPluginHub.enqueueEvents(event);
  EventPluginHub.processEventQueue();
}

function startWatchingForChangeEventIE8(target, targetID) {
  activeElement = target;
  activeElementID = targetID;
  activeElement.attachEvent('onchange', manualDispatchChangeEvent);
}

function stopWatchingForChangeEventIE8() {
  if (!activeElement) {
    return;
  }
  activeElement.detachEvent('onchange', manualDispatchChangeEvent);
  activeElement = null;
  activeElementID = null;
}

function getTargetIDForChangeEvent(
    topLevelType,
    topLevelTarget,
    topLevelTargetID) {
  if (topLevelType === topLevelTypes.topChange) {
    return topLevelTargetID;
  }
}
function handleEventsForChangeEventIE8(
    topLevelType,
    topLevelTarget,
    topLevelTargetID) {
  if (topLevelType === topLevelTypes.topFocus) {
    // stopWatching() should be a noop here but we call it just in case we
    // missed a blur event somehow.
    stopWatchingForChangeEventIE8();
    startWatchingForChangeEventIE8(topLevelTarget, topLevelTargetID);
  } else if (topLevelType === topLevelTypes.topBlur) {
    stopWatchingForChangeEventIE8();
  }
}


/**
 * SECTION: handle `input` event
 */
var isInputEventSupported = false;
if (ExecutionEnvironment.canUseDOM) {
  // IE9 claims to support the input event but fails to trigger it when
  // deleting text, so we ignore its input events
  isInputEventSupported = isEventSupported('input') && (
    !('documentMode' in document) || document.documentMode > 9
  );
}

/**
 * (For old IE.) Replacement getter/setter for the `value` property that gets
 * set on the active element.
 */
var newValueProp =  {
  get: function() {
    return activeElementValueProp.get.call(this);
  },
  set: function(val) {
    // Cast to a string so we can do equality checks.
    activeElementValue = '' + val;
    activeElementValueProp.set.call(this, val);
  }
};

/**
 * (For old IE.) Starts tracking propertychange events on the passed-in element
 * and override the value property so that we can distinguish user events from
 * value changes in JS.
 */
function startWatchingForValueChange(target, targetID) {
  activeElement = target;
  activeElementID = targetID;
  activeElementValue = target.value;
  activeElementValueProp = Object.getOwnPropertyDescriptor(
    target.constructor.prototype,
    'value'
  );

  Object.defineProperty(activeElement, 'value', newValueProp);
  activeElement.attachEvent('onpropertychange', handlePropertyChange);
}

/**
 * (For old IE.) Removes the event listeners from the currently-tracked element,
 * if any exists.
 */
function stopWatchingForValueChange() {
  if (!activeElement) {
    return;
  }

  // delete restores the original property definition
  delete activeElement.value;
  activeElement.detachEvent('onpropertychange', handlePropertyChange);

  activeElement = null;
  activeElementID = null;
  activeElementValue = null;
  activeElementValueProp = null;
}

/**
 * (For old IE.) Handles a propertychange event, sending a `change` event if
 * the value of the active element has changed.
 */
function handlePropertyChange(nativeEvent) {
  if (nativeEvent.propertyName !== 'value') {
    return;
  }
  var value = nativeEvent.srcElement.value;
  if (value === activeElementValue) {
    return;
  }
  activeElementValue = value;

  manualDispatchChangeEvent(nativeEvent);
}

/**
 * If a `change` event should be fired, returns the target's ID.
 */
function getTargetIDForInputEvent(
    topLevelType,
    topLevelTarget,
    topLevelTargetID) {
  if (topLevelType === topLevelTypes.topInput) {
    // In modern browsers (i.e., not IE8 or IE9), the input event is exactly
    // what we want so fall through here and trigger an abstract event
    return topLevelTargetID;
  }
}

// For IE8 and IE9.
function handleEventsForInputEventIE(
    topLevelType,
    topLevelTarget,
    topLevelTargetID) {
  if (topLevelType === topLevelTypes.topFocus) {
    // In IE8, we can capture almost all .value changes by adding a
    // propertychange handler and looking for events with propertyName
    // equal to 'value'
    // In IE9, propertychange fires for most input events but is buggy and
    // doesn't fire when text is deleted, but conveniently, selectionchange
    // appears to fire in all of the remaining cases so we catch those and
    // forward the event if the value has changed
    // In either case, we don't want to call the event handler if the value
    // is changed from JS so we redefine a setter for `.value` that updates
    // our activeElementValue variable, allowing us to ignore those changes
    //
    // stopWatching() should be a noop here but we call it just in case we
    // missed a blur event somehow.
    stopWatchingForValueChange();
    startWatchingForValueChange(topLevelTarget, topLevelTargetID);
  } else if (topLevelType === topLevelTypes.topBlur) {
    stopWatchingForValueChange();
  }
}

// For IE8 and IE9.
function getTargetIDForInputEventIE(
    topLevelType,
    topLevelTarget,
    topLevelTargetID) {
  if (topLevelType === topLevelTypes.topSelectionChange ||
      topLevelType === topLevelTypes.topKeyUp ||
      topLevelType === topLevelTypes.topKeyDown) {
    // On the selectionchange event, the target is just document which isn't
    // helpful for us so just check activeElement instead.
    //
    // 99% of the time, keydown and keyup aren't necessary. IE8 fails to fire
    // propertychange on the first input event after setting `value` from a
    // script and fires only keydown, keypress, keyup. Catching keyup usually
    // gets it and catching keydown lets us fire an event for the first
    // keystroke if user does a key repeat (it'll be a little delayed: right
    // before the second keystroke). Other input methods (e.g., paste) seem to
    // fire selectionchange normally.
    if (activeElement && activeElement.value !== activeElementValue) {
      activeElementValue = activeElement.value;
      return activeElementID;
    }
  }
}


/**
 * SECTION: handle `click` event
 */
function shouldUseClickEvent(elem) {
  // Use the `click` event to detect changes to checkbox and radio inputs.
  // This approach works across all browsers, whereas `change` does not fire
  // until `blur` in IE8.
  return (
    elem.nodeName === 'INPUT' &&
    (elem.type === 'checkbox' || elem.type === 'radio')
  );
}

function getTargetIDForClickEvent(
    topLevelType,
    topLevelTarget,
    topLevelTargetID) {
  if (topLevelType === topLevelTypes.topClick) {
    return topLevelTargetID;
  }
}

/**
 * This plugin creates an `onChange` event that normalizes change events
 * across form elements. This event fires at a time when it's possible to
 * change the element's value without seeing a flicker.
 *
 * Supported elements are:
 * - input (see `isTextInputElement`)
 * - textarea
 * - select
 */
var ChangeEventPlugin = {

  eventTypes: eventTypes,

  /**
   * @param {string} topLevelType Record from `EventConstants`.
   * @param {DOMEventTarget} topLevelTarget The listening component root node.
   * @param {string} topLevelTargetID ID of `topLevelTarget`.
   * @param {object} nativeEvent Native browser event.
   * @return {*} An accumulation of synthetic events.
   * @see {EventPluginHub.extractEvents}
   */
  extractEvents: function(
      topLevelType,
      topLevelTarget,
      topLevelTargetID,
      nativeEvent) {

    var getTargetIDFunc, handleEventFunc;
    if (shouldUseChangeEvent(topLevelTarget)) {
      if (doesChangeEventBubble) {
        getTargetIDFunc = getTargetIDForChangeEvent;
      } else {
        handleEventFunc = handleEventsForChangeEventIE8;
      }
    } else if (isTextInputElement(topLevelTarget)) {
      if (isInputEventSupported) {
        getTargetIDFunc = getTargetIDForInputEvent;
      } else {
        getTargetIDFunc = getTargetIDForInputEventIE;
        handleEventFunc = handleEventsForInputEventIE;
      }
    } else if (shouldUseClickEvent(topLevelTarget)) {
      getTargetIDFunc = getTargetIDForClickEvent;
    }

    if (getTargetIDFunc) {
      var targetID = getTargetIDFunc(
        topLevelType,
        topLevelTarget,
        topLevelTargetID
      );
      if (targetID) {
        var event = SyntheticEvent.getPooled(
          eventTypes.change,
          targetID,
          nativeEvent
        );
        EventPropagators.accumulateTwoPhaseDispatches(event);
        return event;
      }
    }

    if (handleEventFunc) {
      handleEventFunc(
        topLevelType,
        topLevelTarget,
        topLevelTargetID
      );
    }
  }

};

module.exports = ChangeEventPlugin;

},{"./EventConstants":"/Users/zordius/webtasks/node_modules/react/lib/EventConstants.js","./EventPluginHub":"/Users/zordius/webtasks/node_modules/react/lib/EventPluginHub.js","./EventPropagators":"/Users/zordius/webtasks/node_modules/react/lib/EventPropagators.js","./ExecutionEnvironment":"/Users/zordius/webtasks/node_modules/react/lib/ExecutionEnvironment.js","./ReactUpdates":"/Users/zordius/webtasks/node_modules/react/lib/ReactUpdates.js","./SyntheticEvent":"/Users/zordius/webtasks/node_modules/react/lib/SyntheticEvent.js","./isEventSupported":"/Users/zordius/webtasks/node_modules/react/lib/isEventSupported.js","./isTextInputElement":"/Users/zordius/webtasks/node_modules/react/lib/isTextInputElement.js","./keyOf":"/Users/zordius/webtasks/node_modules/react/lib/keyOf.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ClientReactRootIndex.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ClientReactRootIndex
 * @typechecks
 */

"use strict";

var nextReactRootIndex = 0;

var ClientReactRootIndex = {
  createReactRootIndex: function() {
    return nextReactRootIndex++;
  }
};

module.exports = ClientReactRootIndex;

},{}],"/Users/zordius/webtasks/node_modules/react/lib/CompositionEventPlugin.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule CompositionEventPlugin
 * @typechecks static-only
 */

"use strict";

var EventConstants = require("./EventConstants");
var EventPropagators = require("./EventPropagators");
var ExecutionEnvironment = require("./ExecutionEnvironment");
var ReactInputSelection = require("./ReactInputSelection");
var SyntheticCompositionEvent = require("./SyntheticCompositionEvent");

var getTextContentAccessor = require("./getTextContentAccessor");
var keyOf = require("./keyOf");

var END_KEYCODES = [9, 13, 27, 32]; // Tab, Return, Esc, Space
var START_KEYCODE = 229;

var useCompositionEvent = (
  ExecutionEnvironment.canUseDOM &&
  'CompositionEvent' in window
);

// In IE9+, we have access to composition events, but the data supplied
// by the native compositionend event may be incorrect. In Korean, for example,
// the compositionend event contains only one character regardless of
// how many characters have been composed since compositionstart.
// We therefore use the fallback data while still using the native
// events as triggers.
var useFallbackData = (
  !useCompositionEvent ||
  (
    'documentMode' in document &&
    document.documentMode > 8 &&
    document.documentMode <= 11
  )
);

var topLevelTypes = EventConstants.topLevelTypes;
var currentComposition = null;

// Events and their corresponding property names.
var eventTypes = {
  compositionEnd: {
    phasedRegistrationNames: {
      bubbled: keyOf({onCompositionEnd: null}),
      captured: keyOf({onCompositionEndCapture: null})
    },
    dependencies: [
      topLevelTypes.topBlur,
      topLevelTypes.topCompositionEnd,
      topLevelTypes.topKeyDown,
      topLevelTypes.topKeyPress,
      topLevelTypes.topKeyUp,
      topLevelTypes.topMouseDown
    ]
  },
  compositionStart: {
    phasedRegistrationNames: {
      bubbled: keyOf({onCompositionStart: null}),
      captured: keyOf({onCompositionStartCapture: null})
    },
    dependencies: [
      topLevelTypes.topBlur,
      topLevelTypes.topCompositionStart,
      topLevelTypes.topKeyDown,
      topLevelTypes.topKeyPress,
      topLevelTypes.topKeyUp,
      topLevelTypes.topMouseDown
    ]
  },
  compositionUpdate: {
    phasedRegistrationNames: {
      bubbled: keyOf({onCompositionUpdate: null}),
      captured: keyOf({onCompositionUpdateCapture: null})
    },
    dependencies: [
      topLevelTypes.topBlur,
      topLevelTypes.topCompositionUpdate,
      topLevelTypes.topKeyDown,
      topLevelTypes.topKeyPress,
      topLevelTypes.topKeyUp,
      topLevelTypes.topMouseDown
    ]
  }
};

/**
 * Translate native top level events into event types.
 *
 * @param {string} topLevelType
 * @return {object}
 */
function getCompositionEventType(topLevelType) {
  switch (topLevelType) {
    case topLevelTypes.topCompositionStart:
      return eventTypes.compositionStart;
    case topLevelTypes.topCompositionEnd:
      return eventTypes.compositionEnd;
    case topLevelTypes.topCompositionUpdate:
      return eventTypes.compositionUpdate;
  }
}

/**
 * Does our fallback best-guess model think this event signifies that
 * composition has begun?
 *
 * @param {string} topLevelType
 * @param {object} nativeEvent
 * @return {boolean}
 */
function isFallbackStart(topLevelType, nativeEvent) {
  return (
    topLevelType === topLevelTypes.topKeyDown &&
    nativeEvent.keyCode === START_KEYCODE
  );
}

/**
 * Does our fallback mode think that this event is the end of composition?
 *
 * @param {string} topLevelType
 * @param {object} nativeEvent
 * @return {boolean}
 */
function isFallbackEnd(topLevelType, nativeEvent) {
  switch (topLevelType) {
    case topLevelTypes.topKeyUp:
      // Command keys insert or clear IME input.
      return (END_KEYCODES.indexOf(nativeEvent.keyCode) !== -1);
    case topLevelTypes.topKeyDown:
      // Expect IME keyCode on each keydown. If we get any other
      // code we must have exited earlier.
      return (nativeEvent.keyCode !== START_KEYCODE);
    case topLevelTypes.topKeyPress:
    case topLevelTypes.topMouseDown:
    case topLevelTypes.topBlur:
      // Events are not possible without cancelling IME.
      return true;
    default:
      return false;
  }
}

/**
 * Helper class stores information about selection and document state
 * so we can figure out what changed at a later date.
 *
 * @param {DOMEventTarget} root
 */
function FallbackCompositionState(root) {
  this.root = root;
  this.startSelection = ReactInputSelection.getSelection(root);
  this.startValue = this.getText();
}

/**
 * Get current text of input.
 *
 * @return {string}
 */
FallbackCompositionState.prototype.getText = function() {
  return this.root.value || this.root[getTextContentAccessor()];
};

/**
 * Text that has changed since the start of composition.
 *
 * @return {string}
 */
FallbackCompositionState.prototype.getData = function() {
  var endValue = this.getText();
  var prefixLength = this.startSelection.start;
  var suffixLength = this.startValue.length - this.startSelection.end;

  return endValue.substr(
    prefixLength,
    endValue.length - suffixLength - prefixLength
  );
};

/**
 * This plugin creates `onCompositionStart`, `onCompositionUpdate` and
 * `onCompositionEnd` events on inputs, textareas and contentEditable
 * nodes.
 */
var CompositionEventPlugin = {

  eventTypes: eventTypes,

  /**
   * @param {string} topLevelType Record from `EventConstants`.
   * @param {DOMEventTarget} topLevelTarget The listening component root node.
   * @param {string} topLevelTargetID ID of `topLevelTarget`.
   * @param {object} nativeEvent Native browser event.
   * @return {*} An accumulation of synthetic events.
   * @see {EventPluginHub.extractEvents}
   */
  extractEvents: function(
      topLevelType,
      topLevelTarget,
      topLevelTargetID,
      nativeEvent) {

    var eventType;
    var data;

    if (useCompositionEvent) {
      eventType = getCompositionEventType(topLevelType);
    } else if (!currentComposition) {
      if (isFallbackStart(topLevelType, nativeEvent)) {
        eventType = eventTypes.compositionStart;
      }
    } else if (isFallbackEnd(topLevelType, nativeEvent)) {
      eventType = eventTypes.compositionEnd;
    }

    if (useFallbackData) {
      // The current composition is stored statically and must not be
      // overwritten while composition continues.
      if (!currentComposition && eventType === eventTypes.compositionStart) {
        currentComposition = new FallbackCompositionState(topLevelTarget);
      } else if (eventType === eventTypes.compositionEnd) {
        if (currentComposition) {
          data = currentComposition.getData();
          currentComposition = null;
        }
      }
    }

    if (eventType) {
      var event = SyntheticCompositionEvent.getPooled(
        eventType,
        topLevelTargetID,
        nativeEvent
      );
      if (data) {
        // Inject data generated from fallback path into the synthetic event.
        // This matches the property of native CompositionEventInterface.
        event.data = data;
      }
      EventPropagators.accumulateTwoPhaseDispatches(event);
      return event;
    }
  }
};

module.exports = CompositionEventPlugin;

},{"./EventConstants":"/Users/zordius/webtasks/node_modules/react/lib/EventConstants.js","./EventPropagators":"/Users/zordius/webtasks/node_modules/react/lib/EventPropagators.js","./ExecutionEnvironment":"/Users/zordius/webtasks/node_modules/react/lib/ExecutionEnvironment.js","./ReactInputSelection":"/Users/zordius/webtasks/node_modules/react/lib/ReactInputSelection.js","./SyntheticCompositionEvent":"/Users/zordius/webtasks/node_modules/react/lib/SyntheticCompositionEvent.js","./getTextContentAccessor":"/Users/zordius/webtasks/node_modules/react/lib/getTextContentAccessor.js","./keyOf":"/Users/zordius/webtasks/node_modules/react/lib/keyOf.js"}],"/Users/zordius/webtasks/node_modules/react/lib/DOMChildrenOperations.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule DOMChildrenOperations
 * @typechecks static-only
 */

"use strict";

var Danger = require("./Danger");
var ReactMultiChildUpdateTypes = require("./ReactMultiChildUpdateTypes");

var getTextContentAccessor = require("./getTextContentAccessor");
var invariant = require("./invariant");

/**
 * The DOM property to use when setting text content.
 *
 * @type {string}
 * @private
 */
var textContentAccessor = getTextContentAccessor();

/**
 * Inserts `childNode` as a child of `parentNode` at the `index`.
 *
 * @param {DOMElement} parentNode Parent node in which to insert.
 * @param {DOMElement} childNode Child node to insert.
 * @param {number} index Index at which to insert the child.
 * @internal
 */
function insertChildAt(parentNode, childNode, index) {
  // By exploiting arrays returning `undefined` for an undefined index, we can
  // rely exclusively on `insertBefore(node, null)` instead of also using
  // `appendChild(node)`. However, using `undefined` is not allowed by all
  // browsers so we must replace it with `null`.
  parentNode.insertBefore(
    childNode,
    parentNode.childNodes[index] || null
  );
}

var updateTextContent;
if (textContentAccessor === 'textContent') {
  /**
   * Sets the text content of `node` to `text`.
   *
   * @param {DOMElement} node Node to change
   * @param {string} text New text content
   */
  updateTextContent = function(node, text) {
    node.textContent = text;
  };
} else {
  /**
   * Sets the text content of `node` to `text`.
   *
   * @param {DOMElement} node Node to change
   * @param {string} text New text content
   */
  updateTextContent = function(node, text) {
    // In order to preserve newlines correctly, we can't use .innerText to set
    // the contents (see #1080), so we empty the element then append a text node
    while (node.firstChild) {
      node.removeChild(node.firstChild);
    }
    if (text) {
      var doc = node.ownerDocument || document;
      node.appendChild(doc.createTextNode(text));
    }
  };
}

/**
 * Operations for updating with DOM children.
 */
var DOMChildrenOperations = {

  dangerouslyReplaceNodeWithMarkup: Danger.dangerouslyReplaceNodeWithMarkup,

  updateTextContent: updateTextContent,

  /**
   * Updates a component's children by processing a series of updates. The
   * update configurations are each expected to have a `parentNode` property.
   *
   * @param {array<object>} updates List of update configurations.
   * @param {array<string>} markupList List of markup strings.
   * @internal
   */
  processUpdates: function(updates, markupList) {
    var update;
    // Mapping from parent IDs to initial child orderings.
    var initialChildren = null;
    // List of children that will be moved or removed.
    var updatedChildren = null;

    for (var i = 0; update = updates[i]; i++) {
      if (update.type === ReactMultiChildUpdateTypes.MOVE_EXISTING ||
          update.type === ReactMultiChildUpdateTypes.REMOVE_NODE) {
        var updatedIndex = update.fromIndex;
        var updatedChild = update.parentNode.childNodes[updatedIndex];
        var parentID = update.parentID;

        ("production" !== process.env.NODE_ENV ? invariant(
          updatedChild,
          'processUpdates(): Unable to find child %s of element. This ' +
          'probably means the DOM was unexpectedly mutated (e.g., by the ' +
          'browser), usually due to forgetting a <tbody> when using tables, ' +
          'nesting tags like <form>, <p>, or <a>, or using non-SVG elements '+
          'in an <svg> parent. Try inspecting the child nodes of the element ' +
          'with React ID `%s`.',
          updatedIndex,
          parentID
        ) : invariant(updatedChild));

        initialChildren = initialChildren || {};
        initialChildren[parentID] = initialChildren[parentID] || [];
        initialChildren[parentID][updatedIndex] = updatedChild;

        updatedChildren = updatedChildren || [];
        updatedChildren.push(updatedChild);
      }
    }

    var renderedMarkup = Danger.dangerouslyRenderMarkup(markupList);

    // Remove updated children first so that `toIndex` is consistent.
    if (updatedChildren) {
      for (var j = 0; j < updatedChildren.length; j++) {
        updatedChildren[j].parentNode.removeChild(updatedChildren[j]);
      }
    }

    for (var k = 0; update = updates[k]; k++) {
      switch (update.type) {
        case ReactMultiChildUpdateTypes.INSERT_MARKUP:
          insertChildAt(
            update.parentNode,
            renderedMarkup[update.markupIndex],
            update.toIndex
          );
          break;
        case ReactMultiChildUpdateTypes.MOVE_EXISTING:
          insertChildAt(
            update.parentNode,
            initialChildren[update.parentID][update.fromIndex],
            update.toIndex
          );
          break;
        case ReactMultiChildUpdateTypes.TEXT_CONTENT:
          updateTextContent(
            update.parentNode,
            update.textContent
          );
          break;
        case ReactMultiChildUpdateTypes.REMOVE_NODE:
          // Already removed by the for-loop above.
          break;
      }
    }
  }

};

module.exports = DOMChildrenOperations;

}).call(this,require('_process'))
},{"./Danger":"/Users/zordius/webtasks/node_modules/react/lib/Danger.js","./ReactMultiChildUpdateTypes":"/Users/zordius/webtasks/node_modules/react/lib/ReactMultiChildUpdateTypes.js","./getTextContentAccessor":"/Users/zordius/webtasks/node_modules/react/lib/getTextContentAccessor.js","./invariant":"/Users/zordius/webtasks/node_modules/react/lib/invariant.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/DOMProperty.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule DOMProperty
 * @typechecks static-only
 */

/*jslint bitwise: true */

"use strict";

var invariant = require("./invariant");

function checkMask(value, bitmask) {
  return (value & bitmask) === bitmask;
}

var DOMPropertyInjection = {
  /**
   * Mapping from normalized, camelcased property names to a configuration that
   * specifies how the associated DOM property should be accessed or rendered.
   */
  MUST_USE_ATTRIBUTE: 0x1,
  MUST_USE_PROPERTY: 0x2,
  HAS_SIDE_EFFECTS: 0x4,
  HAS_BOOLEAN_VALUE: 0x8,
  HAS_NUMERIC_VALUE: 0x10,
  HAS_POSITIVE_NUMERIC_VALUE: 0x20 | 0x10,
  HAS_OVERLOADED_BOOLEAN_VALUE: 0x40,

  /**
   * Inject some specialized knowledge about the DOM. This takes a config object
   * with the following properties:
   *
   * isCustomAttribute: function that given an attribute name will return true
   * if it can be inserted into the DOM verbatim. Useful for data-* or aria-*
   * attributes where it's impossible to enumerate all of the possible
   * attribute names,
   *
   * Properties: object mapping DOM property name to one of the
   * DOMPropertyInjection constants or null. If your attribute isn't in here,
   * it won't get written to the DOM.
   *
   * DOMAttributeNames: object mapping React attribute name to the DOM
   * attribute name. Attribute names not specified use the **lowercase**
   * normalized name.
   *
   * DOMPropertyNames: similar to DOMAttributeNames but for DOM properties.
   * Property names not specified use the normalized name.
   *
   * DOMMutationMethods: Properties that require special mutation methods. If
   * `value` is undefined, the mutation method should unset the property.
   *
   * @param {object} domPropertyConfig the config as described above.
   */
  injectDOMPropertyConfig: function(domPropertyConfig) {
    var Properties = domPropertyConfig.Properties || {};
    var DOMAttributeNames = domPropertyConfig.DOMAttributeNames || {};
    var DOMPropertyNames = domPropertyConfig.DOMPropertyNames || {};
    var DOMMutationMethods = domPropertyConfig.DOMMutationMethods || {};

    if (domPropertyConfig.isCustomAttribute) {
      DOMProperty._isCustomAttributeFunctions.push(
        domPropertyConfig.isCustomAttribute
      );
    }

    for (var propName in Properties) {
      ("production" !== process.env.NODE_ENV ? invariant(
        !DOMProperty.isStandardName.hasOwnProperty(propName),
        'injectDOMPropertyConfig(...): You\'re trying to inject DOM property ' +
        '\'%s\' which has already been injected. You may be accidentally ' +
        'injecting the same DOM property config twice, or you may be ' +
        'injecting two configs that have conflicting property names.',
        propName
      ) : invariant(!DOMProperty.isStandardName.hasOwnProperty(propName)));

      DOMProperty.isStandardName[propName] = true;

      var lowerCased = propName.toLowerCase();
      DOMProperty.getPossibleStandardName[lowerCased] = propName;

      if (DOMAttributeNames.hasOwnProperty(propName)) {
        var attributeName = DOMAttributeNames[propName];
        DOMProperty.getPossibleStandardName[attributeName] = propName;
        DOMProperty.getAttributeName[propName] = attributeName;
      } else {
        DOMProperty.getAttributeName[propName] = lowerCased;
      }

      DOMProperty.getPropertyName[propName] =
        DOMPropertyNames.hasOwnProperty(propName) ?
          DOMPropertyNames[propName] :
          propName;

      if (DOMMutationMethods.hasOwnProperty(propName)) {
        DOMProperty.getMutationMethod[propName] = DOMMutationMethods[propName];
      } else {
        DOMProperty.getMutationMethod[propName] = null;
      }

      var propConfig = Properties[propName];
      DOMProperty.mustUseAttribute[propName] =
        checkMask(propConfig, DOMPropertyInjection.MUST_USE_ATTRIBUTE);
      DOMProperty.mustUseProperty[propName] =
        checkMask(propConfig, DOMPropertyInjection.MUST_USE_PROPERTY);
      DOMProperty.hasSideEffects[propName] =
        checkMask(propConfig, DOMPropertyInjection.HAS_SIDE_EFFECTS);
      DOMProperty.hasBooleanValue[propName] =
        checkMask(propConfig, DOMPropertyInjection.HAS_BOOLEAN_VALUE);
      DOMProperty.hasNumericValue[propName] =
        checkMask(propConfig, DOMPropertyInjection.HAS_NUMERIC_VALUE);
      DOMProperty.hasPositiveNumericValue[propName] =
        checkMask(propConfig, DOMPropertyInjection.HAS_POSITIVE_NUMERIC_VALUE);
      DOMProperty.hasOverloadedBooleanValue[propName] =
        checkMask(propConfig, DOMPropertyInjection.HAS_OVERLOADED_BOOLEAN_VALUE);

      ("production" !== process.env.NODE_ENV ? invariant(
        !DOMProperty.mustUseAttribute[propName] ||
          !DOMProperty.mustUseProperty[propName],
        'DOMProperty: Cannot require using both attribute and property: %s',
        propName
      ) : invariant(!DOMProperty.mustUseAttribute[propName] ||
        !DOMProperty.mustUseProperty[propName]));
      ("production" !== process.env.NODE_ENV ? invariant(
        DOMProperty.mustUseProperty[propName] ||
          !DOMProperty.hasSideEffects[propName],
        'DOMProperty: Properties that have side effects must use property: %s',
        propName
      ) : invariant(DOMProperty.mustUseProperty[propName] ||
        !DOMProperty.hasSideEffects[propName]));
      ("production" !== process.env.NODE_ENV ? invariant(
        !!DOMProperty.hasBooleanValue[propName] +
          !!DOMProperty.hasNumericValue[propName] +
          !!DOMProperty.hasOverloadedBooleanValue[propName] <= 1,
        'DOMProperty: Value can be one of boolean, overloaded boolean, or ' +
        'numeric value, but not a combination: %s',
        propName
      ) : invariant(!!DOMProperty.hasBooleanValue[propName] +
        !!DOMProperty.hasNumericValue[propName] +
        !!DOMProperty.hasOverloadedBooleanValue[propName] <= 1));
    }
  }
};
var defaultValueCache = {};

/**
 * DOMProperty exports lookup objects that can be used like functions:
 *
 *   > DOMProperty.isValid['id']
 *   true
 *   > DOMProperty.isValid['foobar']
 *   undefined
 *
 * Although this may be confusing, it performs better in general.
 *
 * @see http://jsperf.com/key-exists
 * @see http://jsperf.com/key-missing
 */
var DOMProperty = {

  ID_ATTRIBUTE_NAME: 'data-reactid',

  /**
   * Checks whether a property name is a standard property.
   * @type {Object}
   */
  isStandardName: {},

  /**
   * Mapping from lowercase property names to the properly cased version, used
   * to warn in the case of missing properties.
   * @type {Object}
   */
  getPossibleStandardName: {},

  /**
   * Mapping from normalized names to attribute names that differ. Attribute
   * names are used when rendering markup or with `*Attribute()`.
   * @type {Object}
   */
  getAttributeName: {},

  /**
   * Mapping from normalized names to properties on DOM node instances.
   * (This includes properties that mutate due to external factors.)
   * @type {Object}
   */
  getPropertyName: {},

  /**
   * Mapping from normalized names to mutation methods. This will only exist if
   * mutation cannot be set simply by the property or `setAttribute()`.
   * @type {Object}
   */
  getMutationMethod: {},

  /**
   * Whether the property must be accessed and mutated as an object property.
   * @type {Object}
   */
  mustUseAttribute: {},

  /**
   * Whether the property must be accessed and mutated using `*Attribute()`.
   * (This includes anything that fails `<propName> in <element>`.)
   * @type {Object}
   */
  mustUseProperty: {},

  /**
   * Whether or not setting a value causes side effects such as triggering
   * resources to be loaded or text selection changes. We must ensure that
   * the value is only set if it has changed.
   * @type {Object}
   */
  hasSideEffects: {},

  /**
   * Whether the property should be removed when set to a falsey value.
   * @type {Object}
   */
  hasBooleanValue: {},

  /**
   * Whether the property must be numeric or parse as a
   * numeric and should be removed when set to a falsey value.
   * @type {Object}
   */
  hasNumericValue: {},

  /**
   * Whether the property must be positive numeric or parse as a positive
   * numeric and should be removed when set to a falsey value.
   * @type {Object}
   */
  hasPositiveNumericValue: {},

  /**
   * Whether the property can be used as a flag as well as with a value. Removed
   * when strictly equal to false; present without a value when strictly equal
   * to true; present with a value otherwise.
   * @type {Object}
   */
  hasOverloadedBooleanValue: {},

  /**
   * All of the isCustomAttribute() functions that have been injected.
   */
  _isCustomAttributeFunctions: [],

  /**
   * Checks whether a property name is a custom attribute.
   * @method
   */
  isCustomAttribute: function(attributeName) {
    for (var i = 0; i < DOMProperty._isCustomAttributeFunctions.length; i++) {
      var isCustomAttributeFn = DOMProperty._isCustomAttributeFunctions[i];
      if (isCustomAttributeFn(attributeName)) {
        return true;
      }
    }
    return false;
  },

  /**
   * Returns the default property value for a DOM property (i.e., not an
   * attribute). Most default values are '' or false, but not all. Worse yet,
   * some (in particular, `type`) vary depending on the type of element.
   *
   * TODO: Is it better to grab all the possible properties when creating an
   * element to avoid having to create the same element twice?
   */
  getDefaultValueForProperty: function(nodeName, prop) {
    var nodeDefaults = defaultValueCache[nodeName];
    var testElement;
    if (!nodeDefaults) {
      defaultValueCache[nodeName] = nodeDefaults = {};
    }
    if (!(prop in nodeDefaults)) {
      testElement = document.createElement(nodeName);
      nodeDefaults[prop] = testElement[prop];
    }
    return nodeDefaults[prop];
  },

  injection: DOMPropertyInjection
};

module.exports = DOMProperty;

}).call(this,require('_process'))
},{"./invariant":"/Users/zordius/webtasks/node_modules/react/lib/invariant.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/DOMPropertyOperations.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule DOMPropertyOperations
 * @typechecks static-only
 */

"use strict";

var DOMProperty = require("./DOMProperty");

var escapeTextForBrowser = require("./escapeTextForBrowser");
var memoizeStringOnly = require("./memoizeStringOnly");
var warning = require("./warning");

function shouldIgnoreValue(name, value) {
  return value == null ||
    (DOMProperty.hasBooleanValue[name] && !value) ||
    (DOMProperty.hasNumericValue[name] && isNaN(value)) ||
    (DOMProperty.hasPositiveNumericValue[name] && (value < 1)) ||
    (DOMProperty.hasOverloadedBooleanValue[name] && value === false);
}

var processAttributeNameAndPrefix = memoizeStringOnly(function(name) {
  return escapeTextForBrowser(name) + '="';
});

if ("production" !== process.env.NODE_ENV) {
  var reactProps = {
    children: true,
    dangerouslySetInnerHTML: true,
    key: true,
    ref: true
  };
  var warnedProperties = {};

  var warnUnknownProperty = function(name) {
    if (reactProps.hasOwnProperty(name) && reactProps[name] ||
        warnedProperties.hasOwnProperty(name) && warnedProperties[name]) {
      return;
    }

    warnedProperties[name] = true;
    var lowerCasedName = name.toLowerCase();

    // data-* attributes should be lowercase; suggest the lowercase version
    var standardName = (
      DOMProperty.isCustomAttribute(lowerCasedName) ?
        lowerCasedName :
      DOMProperty.getPossibleStandardName.hasOwnProperty(lowerCasedName) ?
        DOMProperty.getPossibleStandardName[lowerCasedName] :
        null
    );

    // For now, only warn when we have a suggested correction. This prevents
    // logging too much when using transferPropsTo.
    ("production" !== process.env.NODE_ENV ? warning(
      standardName == null,
      'Unknown DOM property ' + name + '. Did you mean ' + standardName + '?'
    ) : null);

  };
}

/**
 * Operations for dealing with DOM properties.
 */
var DOMPropertyOperations = {

  /**
   * Creates markup for the ID property.
   *
   * @param {string} id Unescaped ID.
   * @return {string} Markup string.
   */
  createMarkupForID: function(id) {
    return processAttributeNameAndPrefix(DOMProperty.ID_ATTRIBUTE_NAME) +
      escapeTextForBrowser(id) + '"';
  },

  /**
   * Creates markup for a property.
   *
   * @param {string} name
   * @param {*} value
   * @return {?string} Markup string, or null if the property was invalid.
   */
  createMarkupForProperty: function(name, value) {
    if (DOMProperty.isStandardName.hasOwnProperty(name) &&
        DOMProperty.isStandardName[name]) {
      if (shouldIgnoreValue(name, value)) {
        return '';
      }
      var attributeName = DOMProperty.getAttributeName[name];
      if (DOMProperty.hasBooleanValue[name] ||
          (DOMProperty.hasOverloadedBooleanValue[name] && value === true)) {
        return escapeTextForBrowser(attributeName);
      }
      return processAttributeNameAndPrefix(attributeName) +
        escapeTextForBrowser(value) + '"';
    } else if (DOMProperty.isCustomAttribute(name)) {
      if (value == null) {
        return '';
      }
      return processAttributeNameAndPrefix(name) +
        escapeTextForBrowser(value) + '"';
    } else if ("production" !== process.env.NODE_ENV) {
      warnUnknownProperty(name);
    }
    return null;
  },

  /**
   * Sets the value for a property on a node.
   *
   * @param {DOMElement} node
   * @param {string} name
   * @param {*} value
   */
  setValueForProperty: function(node, name, value) {
    if (DOMProperty.isStandardName.hasOwnProperty(name) &&
        DOMProperty.isStandardName[name]) {
      var mutationMethod = DOMProperty.getMutationMethod[name];
      if (mutationMethod) {
        mutationMethod(node, value);
      } else if (shouldIgnoreValue(name, value)) {
        this.deleteValueForProperty(node, name);
      } else if (DOMProperty.mustUseAttribute[name]) {
        // `setAttribute` with objects becomes only `[object]` in IE8/9,
        // ('' + value) makes it output the correct toString()-value.
        node.setAttribute(DOMProperty.getAttributeName[name], '' + value);
      } else {
        var propName = DOMProperty.getPropertyName[name];
        // Must explicitly cast values for HAS_SIDE_EFFECTS-properties to the
        // property type before comparing; only `value` does and is string.
        if (!DOMProperty.hasSideEffects[name] ||
            ('' + node[propName]) !== ('' + value)) {
          // Contrary to `setAttribute`, object properties are properly
          // `toString`ed by IE8/9.
          node[propName] = value;
        }
      }
    } else if (DOMProperty.isCustomAttribute(name)) {
      if (value == null) {
        node.removeAttribute(name);
      } else {
        node.setAttribute(name, '' + value);
      }
    } else if ("production" !== process.env.NODE_ENV) {
      warnUnknownProperty(name);
    }
  },

  /**
   * Deletes the value for a property on a node.
   *
   * @param {DOMElement} node
   * @param {string} name
   */
  deleteValueForProperty: function(node, name) {
    if (DOMProperty.isStandardName.hasOwnProperty(name) &&
        DOMProperty.isStandardName[name]) {
      var mutationMethod = DOMProperty.getMutationMethod[name];
      if (mutationMethod) {
        mutationMethod(node, undefined);
      } else if (DOMProperty.mustUseAttribute[name]) {
        node.removeAttribute(DOMProperty.getAttributeName[name]);
      } else {
        var propName = DOMProperty.getPropertyName[name];
        var defaultValue = DOMProperty.getDefaultValueForProperty(
          node.nodeName,
          propName
        );
        if (!DOMProperty.hasSideEffects[name] ||
            ('' + node[propName]) !== defaultValue) {
          node[propName] = defaultValue;
        }
      }
    } else if (DOMProperty.isCustomAttribute(name)) {
      node.removeAttribute(name);
    } else if ("production" !== process.env.NODE_ENV) {
      warnUnknownProperty(name);
    }
  }

};

module.exports = DOMPropertyOperations;

}).call(this,require('_process'))
},{"./DOMProperty":"/Users/zordius/webtasks/node_modules/react/lib/DOMProperty.js","./escapeTextForBrowser":"/Users/zordius/webtasks/node_modules/react/lib/escapeTextForBrowser.js","./memoizeStringOnly":"/Users/zordius/webtasks/node_modules/react/lib/memoizeStringOnly.js","./warning":"/Users/zordius/webtasks/node_modules/react/lib/warning.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/Danger.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule Danger
 * @typechecks static-only
 */

/*jslint evil: true, sub: true */

"use strict";

var ExecutionEnvironment = require("./ExecutionEnvironment");

var createNodesFromMarkup = require("./createNodesFromMarkup");
var emptyFunction = require("./emptyFunction");
var getMarkupWrap = require("./getMarkupWrap");
var invariant = require("./invariant");

var OPEN_TAG_NAME_EXP = /^(<[^ \/>]+)/;
var RESULT_INDEX_ATTR = 'data-danger-index';

/**
 * Extracts the `nodeName` from a string of markup.
 *
 * NOTE: Extracting the `nodeName` does not require a regular expression match
 * because we make assumptions about React-generated markup (i.e. there are no
 * spaces surrounding the opening tag and there is at least one attribute).
 *
 * @param {string} markup String of markup.
 * @return {string} Node name of the supplied markup.
 * @see http://jsperf.com/extract-nodename
 */
function getNodeName(markup) {
  return markup.substring(1, markup.indexOf(' '));
}

var Danger = {

  /**
   * Renders markup into an array of nodes. The markup is expected to render
   * into a list of root nodes. Also, the length of `resultList` and
   * `markupList` should be the same.
   *
   * @param {array<string>} markupList List of markup strings to render.
   * @return {array<DOMElement>} List of rendered nodes.
   * @internal
   */
  dangerouslyRenderMarkup: function(markupList) {
    ("production" !== process.env.NODE_ENV ? invariant(
      ExecutionEnvironment.canUseDOM,
      'dangerouslyRenderMarkup(...): Cannot render markup in a worker ' +
      'thread. Make sure `window` and `document` are available globally ' +
      'before requiring React when unit testing or use ' +
      'React.renderToString for server rendering.'
    ) : invariant(ExecutionEnvironment.canUseDOM));
    var nodeName;
    var markupByNodeName = {};
    // Group markup by `nodeName` if a wrap is necessary, else by '*'.
    for (var i = 0; i < markupList.length; i++) {
      ("production" !== process.env.NODE_ENV ? invariant(
        markupList[i],
        'dangerouslyRenderMarkup(...): Missing markup.'
      ) : invariant(markupList[i]));
      nodeName = getNodeName(markupList[i]);
      nodeName = getMarkupWrap(nodeName) ? nodeName : '*';
      markupByNodeName[nodeName] = markupByNodeName[nodeName] || [];
      markupByNodeName[nodeName][i] = markupList[i];
    }
    var resultList = [];
    var resultListAssignmentCount = 0;
    for (nodeName in markupByNodeName) {
      if (!markupByNodeName.hasOwnProperty(nodeName)) {
        continue;
      }
      var markupListByNodeName = markupByNodeName[nodeName];

      // This for-in loop skips the holes of the sparse array. The order of
      // iteration should follow the order of assignment, which happens to match
      // numerical index order, but we don't rely on that.
      for (var resultIndex in markupListByNodeName) {
        if (markupListByNodeName.hasOwnProperty(resultIndex)) {
          var markup = markupListByNodeName[resultIndex];

          // Push the requested markup with an additional RESULT_INDEX_ATTR
          // attribute.  If the markup does not start with a < character, it
          // will be discarded below (with an appropriate console.error).
          markupListByNodeName[resultIndex] = markup.replace(
            OPEN_TAG_NAME_EXP,
            // This index will be parsed back out below.
            '$1 ' + RESULT_INDEX_ATTR + '="' + resultIndex + '" '
          );
        }
      }

      // Render each group of markup with similar wrapping `nodeName`.
      var renderNodes = createNodesFromMarkup(
        markupListByNodeName.join(''),
        emptyFunction // Do nothing special with <script> tags.
      );

      for (i = 0; i < renderNodes.length; ++i) {
        var renderNode = renderNodes[i];
        if (renderNode.hasAttribute &&
            renderNode.hasAttribute(RESULT_INDEX_ATTR)) {

          resultIndex = +renderNode.getAttribute(RESULT_INDEX_ATTR);
          renderNode.removeAttribute(RESULT_INDEX_ATTR);

          ("production" !== process.env.NODE_ENV ? invariant(
            !resultList.hasOwnProperty(resultIndex),
            'Danger: Assigning to an already-occupied result index.'
          ) : invariant(!resultList.hasOwnProperty(resultIndex)));

          resultList[resultIndex] = renderNode;

          // This should match resultList.length and markupList.length when
          // we're done.
          resultListAssignmentCount += 1;

        } else if ("production" !== process.env.NODE_ENV) {
          console.error(
            "Danger: Discarding unexpected node:",
            renderNode
          );
        }
      }
    }

    // Although resultList was populated out of order, it should now be a dense
    // array.
    ("production" !== process.env.NODE_ENV ? invariant(
      resultListAssignmentCount === resultList.length,
      'Danger: Did not assign to every index of resultList.'
    ) : invariant(resultListAssignmentCount === resultList.length));

    ("production" !== process.env.NODE_ENV ? invariant(
      resultList.length === markupList.length,
      'Danger: Expected markup to render %s nodes, but rendered %s.',
      markupList.length,
      resultList.length
    ) : invariant(resultList.length === markupList.length));

    return resultList;
  },

  /**
   * Replaces a node with a string of markup at its current position within its
   * parent. The markup must render into a single root node.
   *
   * @param {DOMElement} oldChild Child node to replace.
   * @param {string} markup Markup to render in place of the child node.
   * @internal
   */
  dangerouslyReplaceNodeWithMarkup: function(oldChild, markup) {
    ("production" !== process.env.NODE_ENV ? invariant(
      ExecutionEnvironment.canUseDOM,
      'dangerouslyReplaceNodeWithMarkup(...): Cannot render markup in a ' +
      'worker thread. Make sure `window` and `document` are available ' +
      'globally before requiring React when unit testing or use ' +
      'React.renderToString for server rendering.'
    ) : invariant(ExecutionEnvironment.canUseDOM));
    ("production" !== process.env.NODE_ENV ? invariant(markup, 'dangerouslyReplaceNodeWithMarkup(...): Missing markup.') : invariant(markup));
    ("production" !== process.env.NODE_ENV ? invariant(
      oldChild.tagName.toLowerCase() !== 'html',
      'dangerouslyReplaceNodeWithMarkup(...): Cannot replace markup of the ' +
      '<html> node. This is because browser quirks make this unreliable ' +
      'and/or slow. If you want to render to the root you must use ' +
      'server rendering. See renderComponentToString().'
    ) : invariant(oldChild.tagName.toLowerCase() !== 'html'));

    var newChild = createNodesFromMarkup(markup, emptyFunction)[0];
    oldChild.parentNode.replaceChild(newChild, oldChild);
  }

};

module.exports = Danger;

}).call(this,require('_process'))
},{"./ExecutionEnvironment":"/Users/zordius/webtasks/node_modules/react/lib/ExecutionEnvironment.js","./createNodesFromMarkup":"/Users/zordius/webtasks/node_modules/react/lib/createNodesFromMarkup.js","./emptyFunction":"/Users/zordius/webtasks/node_modules/react/lib/emptyFunction.js","./getMarkupWrap":"/Users/zordius/webtasks/node_modules/react/lib/getMarkupWrap.js","./invariant":"/Users/zordius/webtasks/node_modules/react/lib/invariant.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/DefaultEventPluginOrder.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule DefaultEventPluginOrder
 */

"use strict";

 var keyOf = require("./keyOf");

/**
 * Module that is injectable into `EventPluginHub`, that specifies a
 * deterministic ordering of `EventPlugin`s. A convenient way to reason about
 * plugins, without having to package every one of them. This is better than
 * having plugins be ordered in the same order that they are injected because
 * that ordering would be influenced by the packaging order.
 * `ResponderEventPlugin` must occur before `SimpleEventPlugin` so that
 * preventing default on events is convenient in `SimpleEventPlugin` handlers.
 */
var DefaultEventPluginOrder = [
  keyOf({ResponderEventPlugin: null}),
  keyOf({SimpleEventPlugin: null}),
  keyOf({TapEventPlugin: null}),
  keyOf({EnterLeaveEventPlugin: null}),
  keyOf({ChangeEventPlugin: null}),
  keyOf({SelectEventPlugin: null}),
  keyOf({CompositionEventPlugin: null}),
  keyOf({BeforeInputEventPlugin: null}),
  keyOf({AnalyticsEventPlugin: null}),
  keyOf({MobileSafariClickEventPlugin: null})
];

module.exports = DefaultEventPluginOrder;

},{"./keyOf":"/Users/zordius/webtasks/node_modules/react/lib/keyOf.js"}],"/Users/zordius/webtasks/node_modules/react/lib/EnterLeaveEventPlugin.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule EnterLeaveEventPlugin
 * @typechecks static-only
 */

"use strict";

var EventConstants = require("./EventConstants");
var EventPropagators = require("./EventPropagators");
var SyntheticMouseEvent = require("./SyntheticMouseEvent");

var ReactMount = require("./ReactMount");
var keyOf = require("./keyOf");

var topLevelTypes = EventConstants.topLevelTypes;
var getFirstReactDOM = ReactMount.getFirstReactDOM;

var eventTypes = {
  mouseEnter: {
    registrationName: keyOf({onMouseEnter: null}),
    dependencies: [
      topLevelTypes.topMouseOut,
      topLevelTypes.topMouseOver
    ]
  },
  mouseLeave: {
    registrationName: keyOf({onMouseLeave: null}),
    dependencies: [
      topLevelTypes.topMouseOut,
      topLevelTypes.topMouseOver
    ]
  }
};

var extractedEvents = [null, null];

var EnterLeaveEventPlugin = {

  eventTypes: eventTypes,

  /**
   * For almost every interaction we care about, there will be both a top-level
   * `mouseover` and `mouseout` event that occurs. Only use `mouseout` so that
   * we do not extract duplicate events. However, moving the mouse into the
   * browser from outside will not fire a `mouseout` event. In this case, we use
   * the `mouseover` top-level event.
   *
   * @param {string} topLevelType Record from `EventConstants`.
   * @param {DOMEventTarget} topLevelTarget The listening component root node.
   * @param {string} topLevelTargetID ID of `topLevelTarget`.
   * @param {object} nativeEvent Native browser event.
   * @return {*} An accumulation of synthetic events.
   * @see {EventPluginHub.extractEvents}
   */
  extractEvents: function(
      topLevelType,
      topLevelTarget,
      topLevelTargetID,
      nativeEvent) {
    if (topLevelType === topLevelTypes.topMouseOver &&
        (nativeEvent.relatedTarget || nativeEvent.fromElement)) {
      return null;
    }
    if (topLevelType !== topLevelTypes.topMouseOut &&
        topLevelType !== topLevelTypes.topMouseOver) {
      // Must not be a mouse in or mouse out - ignoring.
      return null;
    }

    var win;
    if (topLevelTarget.window === topLevelTarget) {
      // `topLevelTarget` is probably a window object.
      win = topLevelTarget;
    } else {
      // TODO: Figure out why `ownerDocument` is sometimes undefined in IE8.
      var doc = topLevelTarget.ownerDocument;
      if (doc) {
        win = doc.defaultView || doc.parentWindow;
      } else {
        win = window;
      }
    }

    var from, to;
    if (topLevelType === topLevelTypes.topMouseOut) {
      from = topLevelTarget;
      to =
        getFirstReactDOM(nativeEvent.relatedTarget || nativeEvent.toElement) ||
        win;
    } else {
      from = win;
      to = topLevelTarget;
    }

    if (from === to) {
      // Nothing pertains to our managed components.
      return null;
    }

    var fromID = from ? ReactMount.getID(from) : '';
    var toID = to ? ReactMount.getID(to) : '';

    var leave = SyntheticMouseEvent.getPooled(
      eventTypes.mouseLeave,
      fromID,
      nativeEvent
    );
    leave.type = 'mouseleave';
    leave.target = from;
    leave.relatedTarget = to;

    var enter = SyntheticMouseEvent.getPooled(
      eventTypes.mouseEnter,
      toID,
      nativeEvent
    );
    enter.type = 'mouseenter';
    enter.target = to;
    enter.relatedTarget = from;

    EventPropagators.accumulateEnterLeaveDispatches(leave, enter, fromID, toID);

    extractedEvents[0] = leave;
    extractedEvents[1] = enter;

    return extractedEvents;
  }

};

module.exports = EnterLeaveEventPlugin;

},{"./EventConstants":"/Users/zordius/webtasks/node_modules/react/lib/EventConstants.js","./EventPropagators":"/Users/zordius/webtasks/node_modules/react/lib/EventPropagators.js","./ReactMount":"/Users/zordius/webtasks/node_modules/react/lib/ReactMount.js","./SyntheticMouseEvent":"/Users/zordius/webtasks/node_modules/react/lib/SyntheticMouseEvent.js","./keyOf":"/Users/zordius/webtasks/node_modules/react/lib/keyOf.js"}],"/Users/zordius/webtasks/node_modules/react/lib/EventConstants.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule EventConstants
 */

"use strict";

var keyMirror = require("./keyMirror");

var PropagationPhases = keyMirror({bubbled: null, captured: null});

/**
 * Types of raw signals from the browser caught at the top level.
 */
var topLevelTypes = keyMirror({
  topBlur: null,
  topChange: null,
  topClick: null,
  topCompositionEnd: null,
  topCompositionStart: null,
  topCompositionUpdate: null,
  topContextMenu: null,
  topCopy: null,
  topCut: null,
  topDoubleClick: null,
  topDrag: null,
  topDragEnd: null,
  topDragEnter: null,
  topDragExit: null,
  topDragLeave: null,
  topDragOver: null,
  topDragStart: null,
  topDrop: null,
  topError: null,
  topFocus: null,
  topInput: null,
  topKeyDown: null,
  topKeyPress: null,
  topKeyUp: null,
  topLoad: null,
  topMouseDown: null,
  topMouseMove: null,
  topMouseOut: null,
  topMouseOver: null,
  topMouseUp: null,
  topPaste: null,
  topReset: null,
  topScroll: null,
  topSelectionChange: null,
  topSubmit: null,
  topTextInput: null,
  topTouchCancel: null,
  topTouchEnd: null,
  topTouchMove: null,
  topTouchStart: null,
  topWheel: null
});

var EventConstants = {
  topLevelTypes: topLevelTypes,
  PropagationPhases: PropagationPhases
};

module.exports = EventConstants;

},{"./keyMirror":"/Users/zordius/webtasks/node_modules/react/lib/keyMirror.js"}],"/Users/zordius/webtasks/node_modules/react/lib/EventListener.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014 Facebook, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * @providesModule EventListener
 * @typechecks
 */

var emptyFunction = require("./emptyFunction");

/**
 * Upstream version of event listener. Does not take into account specific
 * nature of platform.
 */
var EventListener = {
  /**
   * Listen to DOM events during the bubble phase.
   *
   * @param {DOMEventTarget} target DOM element to register listener on.
   * @param {string} eventType Event type, e.g. 'click' or 'mouseover'.
   * @param {function} callback Callback function.
   * @return {object} Object with a `remove` method.
   */
  listen: function(target, eventType, callback) {
    if (target.addEventListener) {
      target.addEventListener(eventType, callback, false);
      return {
        remove: function() {
          target.removeEventListener(eventType, callback, false);
        }
      };
    } else if (target.attachEvent) {
      target.attachEvent('on' + eventType, callback);
      return {
        remove: function() {
          target.detachEvent('on' + eventType, callback);
        }
      };
    }
  },

  /**
   * Listen to DOM events during the capture phase.
   *
   * @param {DOMEventTarget} target DOM element to register listener on.
   * @param {string} eventType Event type, e.g. 'click' or 'mouseover'.
   * @param {function} callback Callback function.
   * @return {object} Object with a `remove` method.
   */
  capture: function(target, eventType, callback) {
    if (!target.addEventListener) {
      if ("production" !== process.env.NODE_ENV) {
        console.error(
          'Attempted to listen to events during the capture phase on a ' +
          'browser that does not support the capture phase. Your application ' +
          'will not receive some events.'
        );
      }
      return {
        remove: emptyFunction
      };
    } else {
      target.addEventListener(eventType, callback, true);
      return {
        remove: function() {
          target.removeEventListener(eventType, callback, true);
        }
      };
    }
  },

  registerDefault: function() {}
};

module.exports = EventListener;

}).call(this,require('_process'))
},{"./emptyFunction":"/Users/zordius/webtasks/node_modules/react/lib/emptyFunction.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/EventPluginHub.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule EventPluginHub
 */

"use strict";

var EventPluginRegistry = require("./EventPluginRegistry");
var EventPluginUtils = require("./EventPluginUtils");

var accumulateInto = require("./accumulateInto");
var forEachAccumulated = require("./forEachAccumulated");
var invariant = require("./invariant");

/**
 * Internal store for event listeners
 */
var listenerBank = {};

/**
 * Internal queue of events that have accumulated their dispatches and are
 * waiting to have their dispatches executed.
 */
var eventQueue = null;

/**
 * Dispatches an event and releases it back into the pool, unless persistent.
 *
 * @param {?object} event Synthetic event to be dispatched.
 * @private
 */
var executeDispatchesAndRelease = function(event) {
  if (event) {
    var executeDispatch = EventPluginUtils.executeDispatch;
    // Plugins can provide custom behavior when dispatching events.
    var PluginModule = EventPluginRegistry.getPluginModuleForEvent(event);
    if (PluginModule && PluginModule.executeDispatch) {
      executeDispatch = PluginModule.executeDispatch;
    }
    EventPluginUtils.executeDispatchesInOrder(event, executeDispatch);

    if (!event.isPersistent()) {
      event.constructor.release(event);
    }
  }
};

/**
 * - `InstanceHandle`: [required] Module that performs logical traversals of DOM
 *   hierarchy given ids of the logical DOM elements involved.
 */
var InstanceHandle = null;

function validateInstanceHandle() {
  var invalid = !InstanceHandle||
    !InstanceHandle.traverseTwoPhase ||
    !InstanceHandle.traverseEnterLeave;
  if (invalid) {
    throw new Error('InstanceHandle not injected before use!');
  }
}

/**
 * This is a unified interface for event plugins to be installed and configured.
 *
 * Event plugins can implement the following properties:
 *
 *   `extractEvents` {function(string, DOMEventTarget, string, object): *}
 *     Required. When a top-level event is fired, this method is expected to
 *     extract synthetic events that will in turn be queued and dispatched.
 *
 *   `eventTypes` {object}
 *     Optional, plugins that fire events must publish a mapping of registration
 *     names that are used to register listeners. Values of this mapping must
 *     be objects that contain `registrationName` or `phasedRegistrationNames`.
 *
 *   `executeDispatch` {function(object, function, string)}
 *     Optional, allows plugins to override how an event gets dispatched. By
 *     default, the listener is simply invoked.
 *
 * Each plugin that is injected into `EventsPluginHub` is immediately operable.
 *
 * @public
 */
var EventPluginHub = {

  /**
   * Methods for injecting dependencies.
   */
  injection: {

    /**
     * @param {object} InjectedMount
     * @public
     */
    injectMount: EventPluginUtils.injection.injectMount,

    /**
     * @param {object} InjectedInstanceHandle
     * @public
     */
    injectInstanceHandle: function(InjectedInstanceHandle) {
      InstanceHandle = InjectedInstanceHandle;
      if ("production" !== process.env.NODE_ENV) {
        validateInstanceHandle();
      }
    },

    getInstanceHandle: function() {
      if ("production" !== process.env.NODE_ENV) {
        validateInstanceHandle();
      }
      return InstanceHandle;
    },

    /**
     * @param {array} InjectedEventPluginOrder
     * @public
     */
    injectEventPluginOrder: EventPluginRegistry.injectEventPluginOrder,

    /**
     * @param {object} injectedNamesToPlugins Map from names to plugin modules.
     */
    injectEventPluginsByName: EventPluginRegistry.injectEventPluginsByName

  },

  eventNameDispatchConfigs: EventPluginRegistry.eventNameDispatchConfigs,

  registrationNameModules: EventPluginRegistry.registrationNameModules,

  /**
   * Stores `listener` at `listenerBank[registrationName][id]`. Is idempotent.
   *
   * @param {string} id ID of the DOM element.
   * @param {string} registrationName Name of listener (e.g. `onClick`).
   * @param {?function} listener The callback to store.
   */
  putListener: function(id, registrationName, listener) {
    ("production" !== process.env.NODE_ENV ? invariant(
      !listener || typeof listener === 'function',
      'Expected %s listener to be a function, instead got type %s',
      registrationName, typeof listener
    ) : invariant(!listener || typeof listener === 'function'));

    var bankForRegistrationName =
      listenerBank[registrationName] || (listenerBank[registrationName] = {});
    bankForRegistrationName[id] = listener;
  },

  /**
   * @param {string} id ID of the DOM element.
   * @param {string} registrationName Name of listener (e.g. `onClick`).
   * @return {?function} The stored callback.
   */
  getListener: function(id, registrationName) {
    var bankForRegistrationName = listenerBank[registrationName];
    return bankForRegistrationName && bankForRegistrationName[id];
  },

  /**
   * Deletes a listener from the registration bank.
   *
   * @param {string} id ID of the DOM element.
   * @param {string} registrationName Name of listener (e.g. `onClick`).
   */
  deleteListener: function(id, registrationName) {
    var bankForRegistrationName = listenerBank[registrationName];
    if (bankForRegistrationName) {
      delete bankForRegistrationName[id];
    }
  },

  /**
   * Deletes all listeners for the DOM element with the supplied ID.
   *
   * @param {string} id ID of the DOM element.
   */
  deleteAllListeners: function(id) {
    for (var registrationName in listenerBank) {
      delete listenerBank[registrationName][id];
    }
  },

  /**
   * Allows registered plugins an opportunity to extract events from top-level
   * native browser events.
   *
   * @param {string} topLevelType Record from `EventConstants`.
   * @param {DOMEventTarget} topLevelTarget The listening component root node.
   * @param {string} topLevelTargetID ID of `topLevelTarget`.
   * @param {object} nativeEvent Native browser event.
   * @return {*} An accumulation of synthetic events.
   * @internal
   */
  extractEvents: function(
      topLevelType,
      topLevelTarget,
      topLevelTargetID,
      nativeEvent) {
    var events;
    var plugins = EventPluginRegistry.plugins;
    for (var i = 0, l = plugins.length; i < l; i++) {
      // Not every plugin in the ordering may be loaded at runtime.
      var possiblePlugin = plugins[i];
      if (possiblePlugin) {
        var extractedEvents = possiblePlugin.extractEvents(
          topLevelType,
          topLevelTarget,
          topLevelTargetID,
          nativeEvent
        );
        if (extractedEvents) {
          events = accumulateInto(events, extractedEvents);
        }
      }
    }
    return events;
  },

  /**
   * Enqueues a synthetic event that should be dispatched when
   * `processEventQueue` is invoked.
   *
   * @param {*} events An accumulation of synthetic events.
   * @internal
   */
  enqueueEvents: function(events) {
    if (events) {
      eventQueue = accumulateInto(eventQueue, events);
    }
  },

  /**
   * Dispatches all synthetic events on the event queue.
   *
   * @internal
   */
  processEventQueue: function() {
    // Set `eventQueue` to null before processing it so that we can tell if more
    // events get enqueued while processing.
    var processingEventQueue = eventQueue;
    eventQueue = null;
    forEachAccumulated(processingEventQueue, executeDispatchesAndRelease);
    ("production" !== process.env.NODE_ENV ? invariant(
      !eventQueue,
      'processEventQueue(): Additional events were enqueued while processing ' +
      'an event queue. Support for this has not yet been implemented.'
    ) : invariant(!eventQueue));
  },

  /**
   * These are needed for tests only. Do not use!
   */
  __purge: function() {
    listenerBank = {};
  },

  __getListenerBank: function() {
    return listenerBank;
  }

};

module.exports = EventPluginHub;

}).call(this,require('_process'))
},{"./EventPluginRegistry":"/Users/zordius/webtasks/node_modules/react/lib/EventPluginRegistry.js","./EventPluginUtils":"/Users/zordius/webtasks/node_modules/react/lib/EventPluginUtils.js","./accumulateInto":"/Users/zordius/webtasks/node_modules/react/lib/accumulateInto.js","./forEachAccumulated":"/Users/zordius/webtasks/node_modules/react/lib/forEachAccumulated.js","./invariant":"/Users/zordius/webtasks/node_modules/react/lib/invariant.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/EventPluginRegistry.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule EventPluginRegistry
 * @typechecks static-only
 */

"use strict";

var invariant = require("./invariant");

/**
 * Injectable ordering of event plugins.
 */
var EventPluginOrder = null;

/**
 * Injectable mapping from names to event plugin modules.
 */
var namesToPlugins = {};

/**
 * Recomputes the plugin list using the injected plugins and plugin ordering.
 *
 * @private
 */
function recomputePluginOrdering() {
  if (!EventPluginOrder) {
    // Wait until an `EventPluginOrder` is injected.
    return;
  }
  for (var pluginName in namesToPlugins) {
    var PluginModule = namesToPlugins[pluginName];
    var pluginIndex = EventPluginOrder.indexOf(pluginName);
    ("production" !== process.env.NODE_ENV ? invariant(
      pluginIndex > -1,
      'EventPluginRegistry: Cannot inject event plugins that do not exist in ' +
      'the plugin ordering, `%s`.',
      pluginName
    ) : invariant(pluginIndex > -1));
    if (EventPluginRegistry.plugins[pluginIndex]) {
      continue;
    }
    ("production" !== process.env.NODE_ENV ? invariant(
      PluginModule.extractEvents,
      'EventPluginRegistry: Event plugins must implement an `extractEvents` ' +
      'method, but `%s` does not.',
      pluginName
    ) : invariant(PluginModule.extractEvents));
    EventPluginRegistry.plugins[pluginIndex] = PluginModule;
    var publishedEvents = PluginModule.eventTypes;
    for (var eventName in publishedEvents) {
      ("production" !== process.env.NODE_ENV ? invariant(
        publishEventForPlugin(
          publishedEvents[eventName],
          PluginModule,
          eventName
        ),
        'EventPluginRegistry: Failed to publish event `%s` for plugin `%s`.',
        eventName,
        pluginName
      ) : invariant(publishEventForPlugin(
        publishedEvents[eventName],
        PluginModule,
        eventName
      )));
    }
  }
}

/**
 * Publishes an event so that it can be dispatched by the supplied plugin.
 *
 * @param {object} dispatchConfig Dispatch configuration for the event.
 * @param {object} PluginModule Plugin publishing the event.
 * @return {boolean} True if the event was successfully published.
 * @private
 */
function publishEventForPlugin(dispatchConfig, PluginModule, eventName) {
  ("production" !== process.env.NODE_ENV ? invariant(
    !EventPluginRegistry.eventNameDispatchConfigs.hasOwnProperty(eventName),
    'EventPluginHub: More than one plugin attempted to publish the same ' +
    'event name, `%s`.',
    eventName
  ) : invariant(!EventPluginRegistry.eventNameDispatchConfigs.hasOwnProperty(eventName)));
  EventPluginRegistry.eventNameDispatchConfigs[eventName] = dispatchConfig;

  var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames;
  if (phasedRegistrationNames) {
    for (var phaseName in phasedRegistrationNames) {
      if (phasedRegistrationNames.hasOwnProperty(phaseName)) {
        var phasedRegistrationName = phasedRegistrationNames[phaseName];
        publishRegistrationName(
          phasedRegistrationName,
          PluginModule,
          eventName
        );
      }
    }
    return true;
  } else if (dispatchConfig.registrationName) {
    publishRegistrationName(
      dispatchConfig.registrationName,
      PluginModule,
      eventName
    );
    return true;
  }
  return false;
}

/**
 * Publishes a registration name that is used to identify dispatched events and
 * can be used with `EventPluginHub.putListener` to register listeners.
 *
 * @param {string} registrationName Registration name to add.
 * @param {object} PluginModule Plugin publishing the event.
 * @private
 */
function publishRegistrationName(registrationName, PluginModule, eventName) {
  ("production" !== process.env.NODE_ENV ? invariant(
    !EventPluginRegistry.registrationNameModules[registrationName],
    'EventPluginHub: More than one plugin attempted to publish the same ' +
    'registration name, `%s`.',
    registrationName
  ) : invariant(!EventPluginRegistry.registrationNameModules[registrationName]));
  EventPluginRegistry.registrationNameModules[registrationName] = PluginModule;
  EventPluginRegistry.registrationNameDependencies[registrationName] =
    PluginModule.eventTypes[eventName].dependencies;
}

/**
 * Registers plugins so that they can extract and dispatch events.
 *
 * @see {EventPluginHub}
 */
var EventPluginRegistry = {

  /**
   * Ordered list of injected plugins.
   */
  plugins: [],

  /**
   * Mapping from event name to dispatch config
   */
  eventNameDispatchConfigs: {},

  /**
   * Mapping from registration name to plugin module
   */
  registrationNameModules: {},

  /**
   * Mapping from registration name to event name
   */
  registrationNameDependencies: {},

  /**
   * Injects an ordering of plugins (by plugin name). This allows the ordering
   * to be decoupled from injection of the actual plugins so that ordering is
   * always deterministic regardless of packaging, on-the-fly injection, etc.
   *
   * @param {array} InjectedEventPluginOrder
   * @internal
   * @see {EventPluginHub.injection.injectEventPluginOrder}
   */
  injectEventPluginOrder: function(InjectedEventPluginOrder) {
    ("production" !== process.env.NODE_ENV ? invariant(
      !EventPluginOrder,
      'EventPluginRegistry: Cannot inject event plugin ordering more than ' +
      'once. You are likely trying to load more than one copy of React.'
    ) : invariant(!EventPluginOrder));
    // Clone the ordering so it cannot be dynamically mutated.
    EventPluginOrder = Array.prototype.slice.call(InjectedEventPluginOrder);
    recomputePluginOrdering();
  },

  /**
   * Injects plugins to be used by `EventPluginHub`. The plugin names must be
   * in the ordering injected by `injectEventPluginOrder`.
   *
   * Plugins can be injected as part of page initialization or on-the-fly.
   *
   * @param {object} injectedNamesToPlugins Map from names to plugin modules.
   * @internal
   * @see {EventPluginHub.injection.injectEventPluginsByName}
   */
  injectEventPluginsByName: function(injectedNamesToPlugins) {
    var isOrderingDirty = false;
    for (var pluginName in injectedNamesToPlugins) {
      if (!injectedNamesToPlugins.hasOwnProperty(pluginName)) {
        continue;
      }
      var PluginModule = injectedNamesToPlugins[pluginName];
      if (!namesToPlugins.hasOwnProperty(pluginName) ||
          namesToPlugins[pluginName] !== PluginModule) {
        ("production" !== process.env.NODE_ENV ? invariant(
          !namesToPlugins[pluginName],
          'EventPluginRegistry: Cannot inject two different event plugins ' +
          'using the same name, `%s`.',
          pluginName
        ) : invariant(!namesToPlugins[pluginName]));
        namesToPlugins[pluginName] = PluginModule;
        isOrderingDirty = true;
      }
    }
    if (isOrderingDirty) {
      recomputePluginOrdering();
    }
  },

  /**
   * Looks up the plugin for the supplied event.
   *
   * @param {object} event A synthetic event.
   * @return {?object} The plugin that created the supplied event.
   * @internal
   */
  getPluginModuleForEvent: function(event) {
    var dispatchConfig = event.dispatchConfig;
    if (dispatchConfig.registrationName) {
      return EventPluginRegistry.registrationNameModules[
        dispatchConfig.registrationName
      ] || null;
    }
    for (var phase in dispatchConfig.phasedRegistrationNames) {
      if (!dispatchConfig.phasedRegistrationNames.hasOwnProperty(phase)) {
        continue;
      }
      var PluginModule = EventPluginRegistry.registrationNameModules[
        dispatchConfig.phasedRegistrationNames[phase]
      ];
      if (PluginModule) {
        return PluginModule;
      }
    }
    return null;
  },

  /**
   * Exposed for unit testing.
   * @private
   */
  _resetEventPlugins: function() {
    EventPluginOrder = null;
    for (var pluginName in namesToPlugins) {
      if (namesToPlugins.hasOwnProperty(pluginName)) {
        delete namesToPlugins[pluginName];
      }
    }
    EventPluginRegistry.plugins.length = 0;

    var eventNameDispatchConfigs = EventPluginRegistry.eventNameDispatchConfigs;
    for (var eventName in eventNameDispatchConfigs) {
      if (eventNameDispatchConfigs.hasOwnProperty(eventName)) {
        delete eventNameDispatchConfigs[eventName];
      }
    }

    var registrationNameModules = EventPluginRegistry.registrationNameModules;
    for (var registrationName in registrationNameModules) {
      if (registrationNameModules.hasOwnProperty(registrationName)) {
        delete registrationNameModules[registrationName];
      }
    }
  }

};

module.exports = EventPluginRegistry;

}).call(this,require('_process'))
},{"./invariant":"/Users/zordius/webtasks/node_modules/react/lib/invariant.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/EventPluginUtils.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule EventPluginUtils
 */

"use strict";

var EventConstants = require("./EventConstants");

var invariant = require("./invariant");

/**
 * Injected dependencies:
 */

/**
 * - `Mount`: [required] Module that can convert between React dom IDs and
 *   actual node references.
 */
var injection = {
  Mount: null,
  injectMount: function(InjectedMount) {
    injection.Mount = InjectedMount;
    if ("production" !== process.env.NODE_ENV) {
      ("production" !== process.env.NODE_ENV ? invariant(
        InjectedMount && InjectedMount.getNode,
        'EventPluginUtils.injection.injectMount(...): Injected Mount module ' +
        'is missing getNode.'
      ) : invariant(InjectedMount && InjectedMount.getNode));
    }
  }
};

var topLevelTypes = EventConstants.topLevelTypes;

function isEndish(topLevelType) {
  return topLevelType === topLevelTypes.topMouseUp ||
         topLevelType === topLevelTypes.topTouchEnd ||
         topLevelType === topLevelTypes.topTouchCancel;
}

function isMoveish(topLevelType) {
  return topLevelType === topLevelTypes.topMouseMove ||
         topLevelType === topLevelTypes.topTouchMove;
}
function isStartish(topLevelType) {
  return topLevelType === topLevelTypes.topMouseDown ||
         topLevelType === topLevelTypes.topTouchStart;
}


var validateEventDispatches;
if ("production" !== process.env.NODE_ENV) {
  validateEventDispatches = function(event) {
    var dispatchListeners = event._dispatchListeners;
    var dispatchIDs = event._dispatchIDs;

    var listenersIsArr = Array.isArray(dispatchListeners);
    var idsIsArr = Array.isArray(dispatchIDs);
    var IDsLen = idsIsArr ? dispatchIDs.length : dispatchIDs ? 1 : 0;
    var listenersLen = listenersIsArr ?
      dispatchListeners.length :
      dispatchListeners ? 1 : 0;

    ("production" !== process.env.NODE_ENV ? invariant(
      idsIsArr === listenersIsArr && IDsLen === listenersLen,
      'EventPluginUtils: Invalid `event`.'
    ) : invariant(idsIsArr === listenersIsArr && IDsLen === listenersLen));
  };
}

/**
 * Invokes `cb(event, listener, id)`. Avoids using call if no scope is
 * provided. The `(listener,id)` pair effectively forms the "dispatch" but are
 * kept separate to conserve memory.
 */
function forEachEventDispatch(event, cb) {
  var dispatchListeners = event._dispatchListeners;
  var dispatchIDs = event._dispatchIDs;
  if ("production" !== process.env.NODE_ENV) {
    validateEventDispatches(event);
  }
  if (Array.isArray(dispatchListeners)) {
    for (var i = 0; i < dispatchListeners.length; i++) {
      if (event.isPropagationStopped()) {
        break;
      }
      // Listeners and IDs are two parallel arrays that are always in sync.
      cb(event, dispatchListeners[i], dispatchIDs[i]);
    }
  } else if (dispatchListeners) {
    cb(event, dispatchListeners, dispatchIDs);
  }
}

/**
 * Default implementation of PluginModule.executeDispatch().
 * @param {SyntheticEvent} SyntheticEvent to handle
 * @param {function} Application-level callback
 * @param {string} domID DOM id to pass to the callback.
 */
function executeDispatch(event, listener, domID) {
  event.currentTarget = injection.Mount.getNode(domID);
  var returnValue = listener(event, domID);
  event.currentTarget = null;
  return returnValue;
}

/**
 * Standard/simple iteration through an event's collected dispatches.
 */
function executeDispatchesInOrder(event, executeDispatch) {
  forEachEventDispatch(event, executeDispatch);
  event._dispatchListeners = null;
  event._dispatchIDs = null;
}

/**
 * Standard/simple iteration through an event's collected dispatches, but stops
 * at the first dispatch execution returning true, and returns that id.
 *
 * @return id of the first dispatch execution who's listener returns true, or
 * null if no listener returned true.
 */
function executeDispatchesInOrderStopAtTrueImpl(event) {
  var dispatchListeners = event._dispatchListeners;
  var dispatchIDs = event._dispatchIDs;
  if ("production" !== process.env.NODE_ENV) {
    validateEventDispatches(event);
  }
  if (Array.isArray(dispatchListeners)) {
    for (var i = 0; i < dispatchListeners.length; i++) {
      if (event.isPropagationStopped()) {
        break;
      }
      // Listeners and IDs are two parallel arrays that are always in sync.
      if (dispatchListeners[i](event, dispatchIDs[i])) {
        return dispatchIDs[i];
      }
    }
  } else if (dispatchListeners) {
    if (dispatchListeners(event, dispatchIDs)) {
      return dispatchIDs;
    }
  }
  return null;
}

/**
 * @see executeDispatchesInOrderStopAtTrueImpl
 */
function executeDispatchesInOrderStopAtTrue(event) {
  var ret = executeDispatchesInOrderStopAtTrueImpl(event);
  event._dispatchIDs = null;
  event._dispatchListeners = null;
  return ret;
}

/**
 * Execution of a "direct" dispatch - there must be at most one dispatch
 * accumulated on the event or it is considered an error. It doesn't really make
 * sense for an event with multiple dispatches (bubbled) to keep track of the
 * return values at each dispatch execution, but it does tend to make sense when
 * dealing with "direct" dispatches.
 *
 * @return The return value of executing the single dispatch.
 */
function executeDirectDispatch(event) {
  if ("production" !== process.env.NODE_ENV) {
    validateEventDispatches(event);
  }
  var dispatchListener = event._dispatchListeners;
  var dispatchID = event._dispatchIDs;
  ("production" !== process.env.NODE_ENV ? invariant(
    !Array.isArray(dispatchListener),
    'executeDirectDispatch(...): Invalid `event`.'
  ) : invariant(!Array.isArray(dispatchListener)));
  var res = dispatchListener ?
    dispatchListener(event, dispatchID) :
    null;
  event._dispatchListeners = null;
  event._dispatchIDs = null;
  return res;
}

/**
 * @param {SyntheticEvent} event
 * @return {bool} True iff number of dispatches accumulated is greater than 0.
 */
function hasDispatches(event) {
  return !!event._dispatchListeners;
}

/**
 * General utilities that are useful in creating custom Event Plugins.
 */
var EventPluginUtils = {
  isEndish: isEndish,
  isMoveish: isMoveish,
  isStartish: isStartish,

  executeDirectDispatch: executeDirectDispatch,
  executeDispatch: executeDispatch,
  executeDispatchesInOrder: executeDispatchesInOrder,
  executeDispatchesInOrderStopAtTrue: executeDispatchesInOrderStopAtTrue,
  hasDispatches: hasDispatches,
  injection: injection,
  useTouchEvents: false
};

module.exports = EventPluginUtils;

}).call(this,require('_process'))
},{"./EventConstants":"/Users/zordius/webtasks/node_modules/react/lib/EventConstants.js","./invariant":"/Users/zordius/webtasks/node_modules/react/lib/invariant.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/EventPropagators.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule EventPropagators
 */

"use strict";

var EventConstants = require("./EventConstants");
var EventPluginHub = require("./EventPluginHub");

var accumulateInto = require("./accumulateInto");
var forEachAccumulated = require("./forEachAccumulated");

var PropagationPhases = EventConstants.PropagationPhases;
var getListener = EventPluginHub.getListener;

/**
 * Some event types have a notion of different registration names for different
 * "phases" of propagation. This finds listeners by a given phase.
 */
function listenerAtPhase(id, event, propagationPhase) {
  var registrationName =
    event.dispatchConfig.phasedRegistrationNames[propagationPhase];
  return getListener(id, registrationName);
}

/**
 * Tags a `SyntheticEvent` with dispatched listeners. Creating this function
 * here, allows us to not have to bind or create functions for each event.
 * Mutating the event's members allows us to not have to create a wrapping
 * "dispatch" object that pairs the event with the listener.
 */
function accumulateDirectionalDispatches(domID, upwards, event) {
  if ("production" !== process.env.NODE_ENV) {
    if (!domID) {
      throw new Error('Dispatching id must not be null');
    }
  }
  var phase = upwards ? PropagationPhases.bubbled : PropagationPhases.captured;
  var listener = listenerAtPhase(domID, event, phase);
  if (listener) {
    event._dispatchListeners =
      accumulateInto(event._dispatchListeners, listener);
    event._dispatchIDs = accumulateInto(event._dispatchIDs, domID);
  }
}

/**
 * Collect dispatches (must be entirely collected before dispatching - see unit
 * tests). Lazily allocate the array to conserve memory.  We must loop through
 * each event and perform the traversal for each one. We can not perform a
 * single traversal for the entire collection of events because each event may
 * have a different target.
 */
function accumulateTwoPhaseDispatchesSingle(event) {
  if (event && event.dispatchConfig.phasedRegistrationNames) {
    EventPluginHub.injection.getInstanceHandle().traverseTwoPhase(
      event.dispatchMarker,
      accumulateDirectionalDispatches,
      event
    );
  }
}


/**
 * Accumulates without regard to direction, does not look for phased
 * registration names. Same as `accumulateDirectDispatchesSingle` but without
 * requiring that the `dispatchMarker` be the same as the dispatched ID.
 */
function accumulateDispatches(id, ignoredDirection, event) {
  if (event && event.dispatchConfig.registrationName) {
    var registrationName = event.dispatchConfig.registrationName;
    var listener = getListener(id, registrationName);
    if (listener) {
      event._dispatchListeners =
        accumulateInto(event._dispatchListeners, listener);
      event._dispatchIDs = accumulateInto(event._dispatchIDs, id);
    }
  }
}

/**
 * Accumulates dispatches on an `SyntheticEvent`, but only for the
 * `dispatchMarker`.
 * @param {SyntheticEvent} event
 */
function accumulateDirectDispatchesSingle(event) {
  if (event && event.dispatchConfig.registrationName) {
    accumulateDispatches(event.dispatchMarker, null, event);
  }
}

function accumulateTwoPhaseDispatches(events) {
  forEachAccumulated(events, accumulateTwoPhaseDispatchesSingle);
}

function accumulateEnterLeaveDispatches(leave, enter, fromID, toID) {
  EventPluginHub.injection.getInstanceHandle().traverseEnterLeave(
    fromID,
    toID,
    accumulateDispatches,
    leave,
    enter
  );
}


function accumulateDirectDispatches(events) {
  forEachAccumulated(events, accumulateDirectDispatchesSingle);
}



/**
 * A small set of propagation patterns, each of which will accept a small amount
 * of information, and generate a set of "dispatch ready event objects" - which
 * are sets of events that have already been annotated with a set of dispatched
 * listener functions/ids. The API is designed this way to discourage these
 * propagation strategies from actually executing the dispatches, since we
 * always want to collect the entire set of dispatches before executing event a
 * single one.
 *
 * @constructor EventPropagators
 */
var EventPropagators = {
  accumulateTwoPhaseDispatches: accumulateTwoPhaseDispatches,
  accumulateDirectDispatches: accumulateDirectDispatches,
  accumulateEnterLeaveDispatches: accumulateEnterLeaveDispatches
};

module.exports = EventPropagators;

}).call(this,require('_process'))
},{"./EventConstants":"/Users/zordius/webtasks/node_modules/react/lib/EventConstants.js","./EventPluginHub":"/Users/zordius/webtasks/node_modules/react/lib/EventPluginHub.js","./accumulateInto":"/Users/zordius/webtasks/node_modules/react/lib/accumulateInto.js","./forEachAccumulated":"/Users/zordius/webtasks/node_modules/react/lib/forEachAccumulated.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ExecutionEnvironment.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ExecutionEnvironment
 */

/*jslint evil: true */

"use strict";

var canUseDOM = !!(
  typeof window !== 'undefined' &&
  window.document &&
  window.document.createElement
);

/**
 * Simple, lightweight module assisting with the detection and context of
 * Worker. Helps avoid circular dependencies and allows code to reason about
 * whether or not they are in a Worker, even if they never include the main
 * `ReactWorker` dependency.
 */
var ExecutionEnvironment = {

  canUseDOM: canUseDOM,

  canUseWorkers: typeof Worker !== 'undefined',

  canUseEventListeners:
    canUseDOM && !!(window.addEventListener || window.attachEvent),

  canUseViewport: canUseDOM && !!window.screen,

  isInWorker: !canUseDOM // For now, this is true - might change in the future.

};

module.exports = ExecutionEnvironment;

},{}],"/Users/zordius/webtasks/node_modules/react/lib/HTMLDOMPropertyConfig.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule HTMLDOMPropertyConfig
 */

/*jslint bitwise: true*/

"use strict";

var DOMProperty = require("./DOMProperty");
var ExecutionEnvironment = require("./ExecutionEnvironment");

var MUST_USE_ATTRIBUTE = DOMProperty.injection.MUST_USE_ATTRIBUTE;
var MUST_USE_PROPERTY = DOMProperty.injection.MUST_USE_PROPERTY;
var HAS_BOOLEAN_VALUE = DOMProperty.injection.HAS_BOOLEAN_VALUE;
var HAS_SIDE_EFFECTS = DOMProperty.injection.HAS_SIDE_EFFECTS;
var HAS_NUMERIC_VALUE = DOMProperty.injection.HAS_NUMERIC_VALUE;
var HAS_POSITIVE_NUMERIC_VALUE =
  DOMProperty.injection.HAS_POSITIVE_NUMERIC_VALUE;
var HAS_OVERLOADED_BOOLEAN_VALUE =
  DOMProperty.injection.HAS_OVERLOADED_BOOLEAN_VALUE;

var hasSVG;
if (ExecutionEnvironment.canUseDOM) {
  var implementation = document.implementation;
  hasSVG = (
    implementation &&
    implementation.hasFeature &&
    implementation.hasFeature(
      'http://www.w3.org/TR/SVG11/feature#BasicStructure',
      '1.1'
    )
  );
}


var HTMLDOMPropertyConfig = {
  isCustomAttribute: RegExp.prototype.test.bind(
    /^(data|aria)-[a-z_][a-z\d_.\-]*$/
  ),
  Properties: {
    /**
     * Standard Properties
     */
    accept: null,
    acceptCharset: null,
    accessKey: null,
    action: null,
    allowFullScreen: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE,
    allowTransparency: MUST_USE_ATTRIBUTE,
    alt: null,
    async: HAS_BOOLEAN_VALUE,
    autoComplete: null,
    // autoFocus is polyfilled/normalized by AutoFocusMixin
    // autoFocus: HAS_BOOLEAN_VALUE,
    autoPlay: HAS_BOOLEAN_VALUE,
    cellPadding: null,
    cellSpacing: null,
    charSet: MUST_USE_ATTRIBUTE,
    checked: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
    classID: MUST_USE_ATTRIBUTE,
    // To set className on SVG elements, it's necessary to use .setAttribute;
    // this works on HTML elements too in all browsers except IE8. Conveniently,
    // IE8 doesn't support SVG and so we can simply use the attribute in
    // browsers that support SVG and the property in browsers that don't,
    // regardless of whether the element is HTML or SVG.
    className: hasSVG ? MUST_USE_ATTRIBUTE : MUST_USE_PROPERTY,
    cols: MUST_USE_ATTRIBUTE | HAS_POSITIVE_NUMERIC_VALUE,
    colSpan: null,
    content: null,
    contentEditable: null,
    contextMenu: MUST_USE_ATTRIBUTE,
    controls: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
    coords: null,
    crossOrigin: null,
    data: null, // For `<object />` acts as `src`.
    dateTime: MUST_USE_ATTRIBUTE,
    defer: HAS_BOOLEAN_VALUE,
    dir: null,
    disabled: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE,
    download: HAS_OVERLOADED_BOOLEAN_VALUE,
    draggable: null,
    encType: null,
    form: MUST_USE_ATTRIBUTE,
    formNoValidate: HAS_BOOLEAN_VALUE,
    frameBorder: MUST_USE_ATTRIBUTE,
    height: MUST_USE_ATTRIBUTE,
    hidden: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE,
    href: null,
    hrefLang: null,
    htmlFor: null,
    httpEquiv: null,
    icon: null,
    id: MUST_USE_PROPERTY,
    label: null,
    lang: null,
    list: MUST_USE_ATTRIBUTE,
    loop: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
    manifest: MUST_USE_ATTRIBUTE,
    max: null,
    maxLength: MUST_USE_ATTRIBUTE,
    media: MUST_USE_ATTRIBUTE,
    mediaGroup: null,
    method: null,
    min: null,
    multiple: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
    muted: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
    name: null,
    noValidate: HAS_BOOLEAN_VALUE,
    open: null,
    pattern: null,
    placeholder: null,
    poster: null,
    preload: null,
    radioGroup: null,
    readOnly: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
    rel: null,
    required: HAS_BOOLEAN_VALUE,
    role: MUST_USE_ATTRIBUTE,
    rows: MUST_USE_ATTRIBUTE | HAS_POSITIVE_NUMERIC_VALUE,
    rowSpan: null,
    sandbox: null,
    scope: null,
    scrolling: null,
    seamless: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE,
    selected: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
    shape: null,
    size: MUST_USE_ATTRIBUTE | HAS_POSITIVE_NUMERIC_VALUE,
    sizes: MUST_USE_ATTRIBUTE,
    span: HAS_POSITIVE_NUMERIC_VALUE,
    spellCheck: null,
    src: null,
    srcDoc: MUST_USE_PROPERTY,
    srcSet: MUST_USE_ATTRIBUTE,
    start: HAS_NUMERIC_VALUE,
    step: null,
    style: null,
    tabIndex: null,
    target: null,
    title: null,
    type: null,
    useMap: null,
    value: MUST_USE_PROPERTY | HAS_SIDE_EFFECTS,
    width: MUST_USE_ATTRIBUTE,
    wmode: MUST_USE_ATTRIBUTE,

    /**
     * Non-standard Properties
     */
    autoCapitalize: null, // Supported in Mobile Safari for keyboard hints
    autoCorrect: null, // Supported in Mobile Safari for keyboard hints
    itemProp: MUST_USE_ATTRIBUTE, // Microdata: http://schema.org/docs/gs.html
    itemScope: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE, // Microdata: http://schema.org/docs/gs.html
    itemType: MUST_USE_ATTRIBUTE, // Microdata: http://schema.org/docs/gs.html
    property: null // Supports OG in meta tags
  },
  DOMAttributeNames: {
    acceptCharset: 'accept-charset',
    className: 'class',
    htmlFor: 'for',
    httpEquiv: 'http-equiv'
  },
  DOMPropertyNames: {
    autoCapitalize: 'autocapitalize',
    autoComplete: 'autocomplete',
    autoCorrect: 'autocorrect',
    autoFocus: 'autofocus',
    autoPlay: 'autoplay',
    encType: 'enctype',
    hrefLang: 'hreflang',
    radioGroup: 'radiogroup',
    spellCheck: 'spellcheck',
    srcDoc: 'srcdoc',
    srcSet: 'srcset'
  }
};

module.exports = HTMLDOMPropertyConfig;

},{"./DOMProperty":"/Users/zordius/webtasks/node_modules/react/lib/DOMProperty.js","./ExecutionEnvironment":"/Users/zordius/webtasks/node_modules/react/lib/ExecutionEnvironment.js"}],"/Users/zordius/webtasks/node_modules/react/lib/LinkedValueUtils.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule LinkedValueUtils
 * @typechecks static-only
 */

"use strict";

var ReactPropTypes = require("./ReactPropTypes");

var invariant = require("./invariant");

var hasReadOnlyValue = {
  'button': true,
  'checkbox': true,
  'image': true,
  'hidden': true,
  'radio': true,
  'reset': true,
  'submit': true
};

function _assertSingleLink(input) {
  ("production" !== process.env.NODE_ENV ? invariant(
    input.props.checkedLink == null || input.props.valueLink == null,
    'Cannot provide a checkedLink and a valueLink. If you want to use ' +
    'checkedLink, you probably don\'t want to use valueLink and vice versa.'
  ) : invariant(input.props.checkedLink == null || input.props.valueLink == null));
}
function _assertValueLink(input) {
  _assertSingleLink(input);
  ("production" !== process.env.NODE_ENV ? invariant(
    input.props.value == null && input.props.onChange == null,
    'Cannot provide a valueLink and a value or onChange event. If you want ' +
    'to use value or onChange, you probably don\'t want to use valueLink.'
  ) : invariant(input.props.value == null && input.props.onChange == null));
}

function _assertCheckedLink(input) {
  _assertSingleLink(input);
  ("production" !== process.env.NODE_ENV ? invariant(
    input.props.checked == null && input.props.onChange == null,
    'Cannot provide a checkedLink and a checked property or onChange event. ' +
    'If you want to use checked or onChange, you probably don\'t want to ' +
    'use checkedLink'
  ) : invariant(input.props.checked == null && input.props.onChange == null));
}

/**
 * @param {SyntheticEvent} e change event to handle
 */
function _handleLinkedValueChange(e) {
  /*jshint validthis:true */
  this.props.valueLink.requestChange(e.target.value);
}

/**
  * @param {SyntheticEvent} e change event to handle
  */
function _handleLinkedCheckChange(e) {
  /*jshint validthis:true */
  this.props.checkedLink.requestChange(e.target.checked);
}

/**
 * Provide a linked `value` attribute for controlled forms. You should not use
 * this outside of the ReactDOM controlled form components.
 */
var LinkedValueUtils = {
  Mixin: {
    propTypes: {
      value: function(props, propName, componentName) {
        if (!props[propName] ||
            hasReadOnlyValue[props.type] ||
            props.onChange ||
            props.readOnly ||
            props.disabled) {
          return;
        }
        return new Error(
          'You provided a `value` prop to a form field without an ' +
          '`onChange` handler. This will render a read-only field. If ' +
          'the field should be mutable use `defaultValue`. Otherwise, ' +
          'set either `onChange` or `readOnly`.'
        );
      },
      checked: function(props, propName, componentName) {
        if (!props[propName] ||
            props.onChange ||
            props.readOnly ||
            props.disabled) {
          return;
        }
        return new Error(
          'You provided a `checked` prop to a form field without an ' +
          '`onChange` handler. This will render a read-only field. If ' +
          'the field should be mutable use `defaultChecked`. Otherwise, ' +
          'set either `onChange` or `readOnly`.'
        );
      },
      onChange: ReactPropTypes.func
    }
  },

  /**
   * @param {ReactComponent} input Form component
   * @return {*} current value of the input either from value prop or link.
   */
  getValue: function(input) {
    if (input.props.valueLink) {
      _assertValueLink(input);
      return input.props.valueLink.value;
    }
    return input.props.value;
  },

  /**
   * @param {ReactComponent} input Form component
   * @return {*} current checked status of the input either from checked prop
   *             or link.
   */
  getChecked: function(input) {
    if (input.props.checkedLink) {
      _assertCheckedLink(input);
      return input.props.checkedLink.value;
    }
    return input.props.checked;
  },

  /**
   * @param {ReactComponent} input Form component
   * @return {function} change callback either from onChange prop or link.
   */
  getOnChange: function(input) {
    if (input.props.valueLink) {
      _assertValueLink(input);
      return _handleLinkedValueChange;
    } else if (input.props.checkedLink) {
      _assertCheckedLink(input);
      return _handleLinkedCheckChange;
    }
    return input.props.onChange;
  }
};

module.exports = LinkedValueUtils;

}).call(this,require('_process'))
},{"./ReactPropTypes":"/Users/zordius/webtasks/node_modules/react/lib/ReactPropTypes.js","./invariant":"/Users/zordius/webtasks/node_modules/react/lib/invariant.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/LocalEventTrapMixin.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule LocalEventTrapMixin
 */

"use strict";

var ReactBrowserEventEmitter = require("./ReactBrowserEventEmitter");

var accumulateInto = require("./accumulateInto");
var forEachAccumulated = require("./forEachAccumulated");
var invariant = require("./invariant");

function remove(event) {
  event.remove();
}

var LocalEventTrapMixin = {
  trapBubbledEvent:function(topLevelType, handlerBaseName) {
    ("production" !== process.env.NODE_ENV ? invariant(this.isMounted(), 'Must be mounted to trap events') : invariant(this.isMounted()));
    var listener = ReactBrowserEventEmitter.trapBubbledEvent(
      topLevelType,
      handlerBaseName,
      this.getDOMNode()
    );
    this._localEventListeners =
      accumulateInto(this._localEventListeners, listener);
  },

  // trapCapturedEvent would look nearly identical. We don't implement that
  // method because it isn't currently needed.

  componentWillUnmount:function() {
    if (this._localEventListeners) {
      forEachAccumulated(this._localEventListeners, remove);
    }
  }
};

module.exports = LocalEventTrapMixin;

}).call(this,require('_process'))
},{"./ReactBrowserEventEmitter":"/Users/zordius/webtasks/node_modules/react/lib/ReactBrowserEventEmitter.js","./accumulateInto":"/Users/zordius/webtasks/node_modules/react/lib/accumulateInto.js","./forEachAccumulated":"/Users/zordius/webtasks/node_modules/react/lib/forEachAccumulated.js","./invariant":"/Users/zordius/webtasks/node_modules/react/lib/invariant.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/MobileSafariClickEventPlugin.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule MobileSafariClickEventPlugin
 * @typechecks static-only
 */

"use strict";

var EventConstants = require("./EventConstants");

var emptyFunction = require("./emptyFunction");

var topLevelTypes = EventConstants.topLevelTypes;

/**
 * Mobile Safari does not fire properly bubble click events on non-interactive
 * elements, which means delegated click listeners do not fire. The workaround
 * for this bug involves attaching an empty click listener on the target node.
 *
 * This particular plugin works around the bug by attaching an empty click
 * listener on `touchstart` (which does fire on every element).
 */
var MobileSafariClickEventPlugin = {

  eventTypes: null,

  /**
   * @param {string} topLevelType Record from `EventConstants`.
   * @param {DOMEventTarget} topLevelTarget The listening component root node.
   * @param {string} topLevelTargetID ID of `topLevelTarget`.
   * @param {object} nativeEvent Native browser event.
   * @return {*} An accumulation of synthetic events.
   * @see {EventPluginHub.extractEvents}
   */
  extractEvents: function(
      topLevelType,
      topLevelTarget,
      topLevelTargetID,
      nativeEvent) {
    if (topLevelType === topLevelTypes.topTouchStart) {
      var target = nativeEvent.target;
      if (target && !target.onclick) {
        target.onclick = emptyFunction;
      }
    }
  }

};

module.exports = MobileSafariClickEventPlugin;

},{"./EventConstants":"/Users/zordius/webtasks/node_modules/react/lib/EventConstants.js","./emptyFunction":"/Users/zordius/webtasks/node_modules/react/lib/emptyFunction.js"}],"/Users/zordius/webtasks/node_modules/react/lib/Object.assign.js":[function(require,module,exports){
/**
 * Copyright 2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule Object.assign
 */

// https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.assign

function assign(target, sources) {
  if (target == null) {
    throw new TypeError('Object.assign target cannot be null or undefined');
  }

  var to = Object(target);
  var hasOwnProperty = Object.prototype.hasOwnProperty;

  for (var nextIndex = 1; nextIndex < arguments.length; nextIndex++) {
    var nextSource = arguments[nextIndex];
    if (nextSource == null) {
      continue;
    }

    var from = Object(nextSource);

    // We don't currently support accessors nor proxies. Therefore this
    // copy cannot throw. If we ever supported this then we must handle
    // exceptions and side-effects. We don't support symbols so they won't
    // be transferred.

    for (var key in from) {
      if (hasOwnProperty.call(from, key)) {
        to[key] = from[key];
      }
    }
  }

  return to;
};

module.exports = assign;

},{}],"/Users/zordius/webtasks/node_modules/react/lib/PooledClass.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule PooledClass
 */

"use strict";

var invariant = require("./invariant");

/**
 * Static poolers. Several custom versions for each potential number of
 * arguments. A completely generic pooler is easy to implement, but would
 * require accessing the `arguments` object. In each of these, `this` refers to
 * the Class itself, not an instance. If any others are needed, simply add them
 * here, or in their own files.
 */
var oneArgumentPooler = function(copyFieldsFrom) {
  var Klass = this;
  if (Klass.instancePool.length) {
    var instance = Klass.instancePool.pop();
    Klass.call(instance, copyFieldsFrom);
    return instance;
  } else {
    return new Klass(copyFieldsFrom);
  }
};

var twoArgumentPooler = function(a1, a2) {
  var Klass = this;
  if (Klass.instancePool.length) {
    var instance = Klass.instancePool.pop();
    Klass.call(instance, a1, a2);
    return instance;
  } else {
    return new Klass(a1, a2);
  }
};

var threeArgumentPooler = function(a1, a2, a3) {
  var Klass = this;
  if (Klass.instancePool.length) {
    var instance = Klass.instancePool.pop();
    Klass.call(instance, a1, a2, a3);
    return instance;
  } else {
    return new Klass(a1, a2, a3);
  }
};

var fiveArgumentPooler = function(a1, a2, a3, a4, a5) {
  var Klass = this;
  if (Klass.instancePool.length) {
    var instance = Klass.instancePool.pop();
    Klass.call(instance, a1, a2, a3, a4, a5);
    return instance;
  } else {
    return new Klass(a1, a2, a3, a4, a5);
  }
};

var standardReleaser = function(instance) {
  var Klass = this;
  ("production" !== process.env.NODE_ENV ? invariant(
    instance instanceof Klass,
    'Trying to release an instance into a pool of a different type.'
  ) : invariant(instance instanceof Klass));
  if (instance.destructor) {
    instance.destructor();
  }
  if (Klass.instancePool.length < Klass.poolSize) {
    Klass.instancePool.push(instance);
  }
};

var DEFAULT_POOL_SIZE = 10;
var DEFAULT_POOLER = oneArgumentPooler;

/**
 * Augments `CopyConstructor` to be a poolable class, augmenting only the class
 * itself (statically) not adding any prototypical fields. Any CopyConstructor
 * you give this may have a `poolSize` property, and will look for a
 * prototypical `destructor` on instances (optional).
 *
 * @param {Function} CopyConstructor Constructor that can be used to reset.
 * @param {Function} pooler Customizable pooler.
 */
var addPoolingTo = function(CopyConstructor, pooler) {
  var NewKlass = CopyConstructor;
  NewKlass.instancePool = [];
  NewKlass.getPooled = pooler || DEFAULT_POOLER;
  if (!NewKlass.poolSize) {
    NewKlass.poolSize = DEFAULT_POOL_SIZE;
  }
  NewKlass.release = standardReleaser;
  return NewKlass;
};

var PooledClass = {
  addPoolingTo: addPoolingTo,
  oneArgumentPooler: oneArgumentPooler,
  twoArgumentPooler: twoArgumentPooler,
  threeArgumentPooler: threeArgumentPooler,
  fiveArgumentPooler: fiveArgumentPooler
};

module.exports = PooledClass;

}).call(this,require('_process'))
},{"./invariant":"/Users/zordius/webtasks/node_modules/react/lib/invariant.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/React.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule React
 */

"use strict";

var DOMPropertyOperations = require("./DOMPropertyOperations");
var EventPluginUtils = require("./EventPluginUtils");
var ReactChildren = require("./ReactChildren");
var ReactComponent = require("./ReactComponent");
var ReactCompositeComponent = require("./ReactCompositeComponent");
var ReactContext = require("./ReactContext");
var ReactCurrentOwner = require("./ReactCurrentOwner");
var ReactElement = require("./ReactElement");
var ReactElementValidator = require("./ReactElementValidator");
var ReactDOM = require("./ReactDOM");
var ReactDOMComponent = require("./ReactDOMComponent");
var ReactDefaultInjection = require("./ReactDefaultInjection");
var ReactInstanceHandles = require("./ReactInstanceHandles");
var ReactLegacyElement = require("./ReactLegacyElement");
var ReactMount = require("./ReactMount");
var ReactMultiChild = require("./ReactMultiChild");
var ReactPerf = require("./ReactPerf");
var ReactPropTypes = require("./ReactPropTypes");
var ReactServerRendering = require("./ReactServerRendering");
var ReactTextComponent = require("./ReactTextComponent");

var assign = require("./Object.assign");
var deprecated = require("./deprecated");
var onlyChild = require("./onlyChild");

ReactDefaultInjection.inject();

var createElement = ReactElement.createElement;
var createFactory = ReactElement.createFactory;

if ("production" !== process.env.NODE_ENV) {
  createElement = ReactElementValidator.createElement;
  createFactory = ReactElementValidator.createFactory;
}

// TODO: Drop legacy elements once classes no longer export these factories
createElement = ReactLegacyElement.wrapCreateElement(
  createElement
);
createFactory = ReactLegacyElement.wrapCreateFactory(
  createFactory
);

var render = ReactPerf.measure('React', 'render', ReactMount.render);

var React = {
  Children: {
    map: ReactChildren.map,
    forEach: ReactChildren.forEach,
    count: ReactChildren.count,
    only: onlyChild
  },
  DOM: ReactDOM,
  PropTypes: ReactPropTypes,
  initializeTouchEvents: function(shouldUseTouch) {
    EventPluginUtils.useTouchEvents = shouldUseTouch;
  },
  createClass: ReactCompositeComponent.createClass,
  createElement: createElement,
  createFactory: createFactory,
  constructAndRenderComponent: ReactMount.constructAndRenderComponent,
  constructAndRenderComponentByID: ReactMount.constructAndRenderComponentByID,
  render: render,
  renderToString: ReactServerRendering.renderToString,
  renderToStaticMarkup: ReactServerRendering.renderToStaticMarkup,
  unmountComponentAtNode: ReactMount.unmountComponentAtNode,
  isValidClass: ReactLegacyElement.isValidClass,
  isValidElement: ReactElement.isValidElement,
  withContext: ReactContext.withContext,

  // Hook for JSX spread, don't use this for anything else.
  __spread: assign,

  // Deprecations (remove for 0.13)
  renderComponent: deprecated(
    'React',
    'renderComponent',
    'render',
    this,
    render
  ),
  renderComponentToString: deprecated(
    'React',
    'renderComponentToString',
    'renderToString',
    this,
    ReactServerRendering.renderToString
  ),
  renderComponentToStaticMarkup: deprecated(
    'React',
    'renderComponentToStaticMarkup',
    'renderToStaticMarkup',
    this,
    ReactServerRendering.renderToStaticMarkup
  ),
  isValidComponent: deprecated(
    'React',
    'isValidComponent',
    'isValidElement',
    this,
    ReactElement.isValidElement
  )
};

// Inject the runtime into a devtools global hook regardless of browser.
// Allows for debugging when the hook is injected on the page.
if (
  typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== 'undefined' &&
  typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.inject === 'function') {
  __REACT_DEVTOOLS_GLOBAL_HOOK__.inject({
    Component: ReactComponent,
    CurrentOwner: ReactCurrentOwner,
    DOMComponent: ReactDOMComponent,
    DOMPropertyOperations: DOMPropertyOperations,
    InstanceHandles: ReactInstanceHandles,
    Mount: ReactMount,
    MultiChild: ReactMultiChild,
    TextComponent: ReactTextComponent
  });
}

if ("production" !== process.env.NODE_ENV) {
  var ExecutionEnvironment = require("./ExecutionEnvironment");
  if (ExecutionEnvironment.canUseDOM && window.top === window.self) {

    // If we're in Chrome, look for the devtools marker and provide a download
    // link if not installed.
    if (navigator.userAgent.indexOf('Chrome') > -1) {
      if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined') {
        console.debug(
          'Download the React DevTools for a better development experience: ' +
          'http://fb.me/react-devtools'
        );
      }
    }

    var expectedFeatures = [
      // shims
      Array.isArray,
      Array.prototype.every,
      Array.prototype.forEach,
      Array.prototype.indexOf,
      Array.prototype.map,
      Date.now,
      Function.prototype.bind,
      Object.keys,
      String.prototype.split,
      String.prototype.trim,

      // shams
      Object.create,
      Object.freeze
    ];

    for (var i = 0; i < expectedFeatures.length; i++) {
      if (!expectedFeatures[i]) {
        console.error(
          'One or more ES5 shim/shams expected by React are not available: ' +
          'http://fb.me/react-warning-polyfills'
        );
        break;
      }
    }
  }
}

// Version exists only in the open-source version of React, not in Facebook's
// internal version.
React.version = '0.12.1';

module.exports = React;

}).call(this,require('_process'))
},{"./DOMPropertyOperations":"/Users/zordius/webtasks/node_modules/react/lib/DOMPropertyOperations.js","./EventPluginUtils":"/Users/zordius/webtasks/node_modules/react/lib/EventPluginUtils.js","./ExecutionEnvironment":"/Users/zordius/webtasks/node_modules/react/lib/ExecutionEnvironment.js","./Object.assign":"/Users/zordius/webtasks/node_modules/react/lib/Object.assign.js","./ReactChildren":"/Users/zordius/webtasks/node_modules/react/lib/ReactChildren.js","./ReactComponent":"/Users/zordius/webtasks/node_modules/react/lib/ReactComponent.js","./ReactCompositeComponent":"/Users/zordius/webtasks/node_modules/react/lib/ReactCompositeComponent.js","./ReactContext":"/Users/zordius/webtasks/node_modules/react/lib/ReactContext.js","./ReactCurrentOwner":"/Users/zordius/webtasks/node_modules/react/lib/ReactCurrentOwner.js","./ReactDOM":"/Users/zordius/webtasks/node_modules/react/lib/ReactDOM.js","./ReactDOMComponent":"/Users/zordius/webtasks/node_modules/react/lib/ReactDOMComponent.js","./ReactDefaultInjection":"/Users/zordius/webtasks/node_modules/react/lib/ReactDefaultInjection.js","./ReactElement":"/Users/zordius/webtasks/node_modules/react/lib/ReactElement.js","./ReactElementValidator":"/Users/zordius/webtasks/node_modules/react/lib/ReactElementValidator.js","./ReactInstanceHandles":"/Users/zordius/webtasks/node_modules/react/lib/ReactInstanceHandles.js","./ReactLegacyElement":"/Users/zordius/webtasks/node_modules/react/lib/ReactLegacyElement.js","./ReactMount":"/Users/zordius/webtasks/node_modules/react/lib/ReactMount.js","./ReactMultiChild":"/Users/zordius/webtasks/node_modules/react/lib/ReactMultiChild.js","./ReactPerf":"/Users/zordius/webtasks/node_modules/react/lib/ReactPerf.js","./ReactPropTypes":"/Users/zordius/webtasks/node_modules/react/lib/ReactPropTypes.js","./ReactServerRendering":"/Users/zordius/webtasks/node_modules/react/lib/ReactServerRendering.js","./ReactTextComponent":"/Users/zordius/webtasks/node_modules/react/lib/ReactTextComponent.js","./deprecated":"/Users/zordius/webtasks/node_modules/react/lib/deprecated.js","./onlyChild":"/Users/zordius/webtasks/node_modules/react/lib/onlyChild.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactBrowserComponentMixin.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactBrowserComponentMixin
 */

"use strict";

var ReactEmptyComponent = require("./ReactEmptyComponent");
var ReactMount = require("./ReactMount");

var invariant = require("./invariant");

var ReactBrowserComponentMixin = {
  /**
   * Returns the DOM node rendered by this component.
   *
   * @return {DOMElement} The root node of this component.
   * @final
   * @protected
   */
  getDOMNode: function() {
    ("production" !== process.env.NODE_ENV ? invariant(
      this.isMounted(),
      'getDOMNode(): A component must be mounted to have a DOM node.'
    ) : invariant(this.isMounted()));
    if (ReactEmptyComponent.isNullComponentID(this._rootNodeID)) {
      return null;
    }
    return ReactMount.getNode(this._rootNodeID);
  }
};

module.exports = ReactBrowserComponentMixin;

}).call(this,require('_process'))
},{"./ReactEmptyComponent":"/Users/zordius/webtasks/node_modules/react/lib/ReactEmptyComponent.js","./ReactMount":"/Users/zordius/webtasks/node_modules/react/lib/ReactMount.js","./invariant":"/Users/zordius/webtasks/node_modules/react/lib/invariant.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactBrowserEventEmitter.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactBrowserEventEmitter
 * @typechecks static-only
 */

"use strict";

var EventConstants = require("./EventConstants");
var EventPluginHub = require("./EventPluginHub");
var EventPluginRegistry = require("./EventPluginRegistry");
var ReactEventEmitterMixin = require("./ReactEventEmitterMixin");
var ViewportMetrics = require("./ViewportMetrics");

var assign = require("./Object.assign");
var isEventSupported = require("./isEventSupported");

/**
 * Summary of `ReactBrowserEventEmitter` event handling:
 *
 *  - Top-level delegation is used to trap most native browser events. This
 *    may only occur in the main thread and is the responsibility of
 *    ReactEventListener, which is injected and can therefore support pluggable
 *    event sources. This is the only work that occurs in the main thread.
 *
 *  - We normalize and de-duplicate events to account for browser quirks. This
 *    may be done in the worker thread.
 *
 *  - Forward these native events (with the associated top-level type used to
 *    trap it) to `EventPluginHub`, which in turn will ask plugins if they want
 *    to extract any synthetic events.
 *
 *  - The `EventPluginHub` will then process each event by annotating them with
 *    "dispatches", a sequence of listeners and IDs that care about that event.
 *
 *  - The `EventPluginHub` then dispatches the events.
 *
 * Overview of React and the event system:
 *
 * +------------+    .
 * |    DOM     |    .
 * +------------+    .
 *       |           .
 *       v           .
 * +------------+    .
 * | ReactEvent |    .
 * |  Listener  |    .
 * +------------+    .                         +-----------+
 *       |           .               +--------+|SimpleEvent|
 *       |           .               |         |Plugin     |
 * +-----|------+    .               v         +-----------+
 * |     |      |    .    +--------------+                    +------------+
 * |     +-----------.--->|EventPluginHub|                    |    Event   |
 * |            |    .    |              |     +-----------+  | Propagators|
 * | ReactEvent |    .    |              |     |TapEvent   |  |------------|
 * |  Emitter   |    .    |              |<---+|Plugin     |  |other plugin|
 * |            |    .    |              |     +-----------+  |  utilities |
 * |     +-----------.--->|              |                    +------------+
 * |     |      |    .    +--------------+
 * +-----|------+    .                ^        +-----------+
 *       |           .                |        |Enter/Leave|
 *       +           .                +-------+|Plugin     |
 * +-------------+   .                         +-----------+
 * | application |   .
 * |-------------|   .
 * |             |   .
 * |             |   .
 * +-------------+   .
 *                   .
 *    React Core     .  General Purpose Event Plugin System
 */

var alreadyListeningTo = {};
var isMonitoringScrollValue = false;
var reactTopListenersCounter = 0;

// For events like 'submit' which don't consistently bubble (which we trap at a
// lower node than `document`), binding at `document` would cause duplicate
// events so we don't include them here
var topEventMapping = {
  topBlur: 'blur',
  topChange: 'change',
  topClick: 'click',
  topCompositionEnd: 'compositionend',
  topCompositionStart: 'compositionstart',
  topCompositionUpdate: 'compositionupdate',
  topContextMenu: 'contextmenu',
  topCopy: 'copy',
  topCut: 'cut',
  topDoubleClick: 'dblclick',
  topDrag: 'drag',
  topDragEnd: 'dragend',
  topDragEnter: 'dragenter',
  topDragExit: 'dragexit',
  topDragLeave: 'dragleave',
  topDragOver: 'dragover',
  topDragStart: 'dragstart',
  topDrop: 'drop',
  topFocus: 'focus',
  topInput: 'input',
  topKeyDown: 'keydown',
  topKeyPress: 'keypress',
  topKeyUp: 'keyup',
  topMouseDown: 'mousedown',
  topMouseMove: 'mousemove',
  topMouseOut: 'mouseout',
  topMouseOver: 'mouseover',
  topMouseUp: 'mouseup',
  topPaste: 'paste',
  topScroll: 'scroll',
  topSelectionChange: 'selectionchange',
  topTextInput: 'textInput',
  topTouchCancel: 'touchcancel',
  topTouchEnd: 'touchend',
  topTouchMove: 'touchmove',
  topTouchStart: 'touchstart',
  topWheel: 'wheel'
};

/**
 * To ensure no conflicts with other potential React instances on the page
 */
var topListenersIDKey = "_reactListenersID" + String(Math.random()).slice(2);

function getListeningForDocument(mountAt) {
  // In IE8, `mountAt` is a host object and doesn't have `hasOwnProperty`
  // directly.
  if (!Object.prototype.hasOwnProperty.call(mountAt, topListenersIDKey)) {
    mountAt[topListenersIDKey] = reactTopListenersCounter++;
    alreadyListeningTo[mountAt[topListenersIDKey]] = {};
  }
  return alreadyListeningTo[mountAt[topListenersIDKey]];
}

/**
 * `ReactBrowserEventEmitter` is used to attach top-level event listeners. For
 * example:
 *
 *   ReactBrowserEventEmitter.putListener('myID', 'onClick', myFunction);
 *
 * This would allocate a "registration" of `('onClick', myFunction)` on 'myID'.
 *
 * @internal
 */
var ReactBrowserEventEmitter = assign({}, ReactEventEmitterMixin, {

  /**
   * Injectable event backend
   */
  ReactEventListener: null,

  injection: {
    /**
     * @param {object} ReactEventListener
     */
    injectReactEventListener: function(ReactEventListener) {
      ReactEventListener.setHandleTopLevel(
        ReactBrowserEventEmitter.handleTopLevel
      );
      ReactBrowserEventEmitter.ReactEventListener = ReactEventListener;
    }
  },

  /**
   * Sets whether or not any created callbacks should be enabled.
   *
   * @param {boolean} enabled True if callbacks should be enabled.
   */
  setEnabled: function(enabled) {
    if (ReactBrowserEventEmitter.ReactEventListener) {
      ReactBrowserEventEmitter.ReactEventListener.setEnabled(enabled);
    }
  },

  /**
   * @return {boolean} True if callbacks are enabled.
   */
  isEnabled: function() {
    return !!(
      ReactBrowserEventEmitter.ReactEventListener &&
      ReactBrowserEventEmitter.ReactEventListener.isEnabled()
    );
  },

  /**
   * We listen for bubbled touch events on the document object.
   *
   * Firefox v8.01 (and possibly others) exhibited strange behavior when
   * mounting `onmousemove` events at some node that was not the document
   * element. The symptoms were that if your mouse is not moving over something
   * contained within that mount point (for example on the background) the
   * top-level listeners for `onmousemove` won't be called. However, if you
   * register the `mousemove` on the document object, then it will of course
   * catch all `mousemove`s. This along with iOS quirks, justifies restricting
   * top-level listeners to the document object only, at least for these
   * movement types of events and possibly all events.
   *
   * @see http://www.quirksmode.org/blog/archives/2010/09/click_event_del.html
   *
   * Also, `keyup`/`keypress`/`keydown` do not bubble to the window on IE, but
   * they bubble to document.
   *
   * @param {string} registrationName Name of listener (e.g. `onClick`).
   * @param {object} contentDocumentHandle Document which owns the container
   */
  listenTo: function(registrationName, contentDocumentHandle) {
    var mountAt = contentDocumentHandle;
    var isListening = getListeningForDocument(mountAt);
    var dependencies = EventPluginRegistry.
      registrationNameDependencies[registrationName];

    var topLevelTypes = EventConstants.topLevelTypes;
    for (var i = 0, l = dependencies.length; i < l; i++) {
      var dependency = dependencies[i];
      if (!(
            isListening.hasOwnProperty(dependency) &&
            isListening[dependency]
          )) {
        if (dependency === topLevelTypes.topWheel) {
          if (isEventSupported('wheel')) {
            ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
              topLevelTypes.topWheel,
              'wheel',
              mountAt
            );
          } else if (isEventSupported('mousewheel')) {
            ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
              topLevelTypes.topWheel,
              'mousewheel',
              mountAt
            );
          } else {
            // Firefox needs to capture a different mouse scroll event.
            // @see http://www.quirksmode.org/dom/events/tests/scroll.html
            ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
              topLevelTypes.topWheel,
              'DOMMouseScroll',
              mountAt
            );
          }
        } else if (dependency === topLevelTypes.topScroll) {

          if (isEventSupported('scroll', true)) {
            ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(
              topLevelTypes.topScroll,
              'scroll',
              mountAt
            );
          } else {
            ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
              topLevelTypes.topScroll,
              'scroll',
              ReactBrowserEventEmitter.ReactEventListener.WINDOW_HANDLE
            );
          }
        } else if (dependency === topLevelTypes.topFocus ||
            dependency === topLevelTypes.topBlur) {

          if (isEventSupported('focus', true)) {
            ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(
              topLevelTypes.topFocus,
              'focus',
              mountAt
            );
            ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(
              topLevelTypes.topBlur,
              'blur',
              mountAt
            );
          } else if (isEventSupported('focusin')) {
            // IE has `focusin` and `focusout` events which bubble.
            // @see http://www.quirksmode.org/blog/archives/2008/04/delegating_the.html
            ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
              topLevelTypes.topFocus,
              'focusin',
              mountAt
            );
            ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
              topLevelTypes.topBlur,
              'focusout',
              mountAt
            );
          }

          // to make sure blur and focus event listeners are only attached once
          isListening[topLevelTypes.topBlur] = true;
          isListening[topLevelTypes.topFocus] = true;
        } else if (topEventMapping.hasOwnProperty(dependency)) {
          ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
            dependency,
            topEventMapping[dependency],
            mountAt
          );
        }

        isListening[dependency] = true;
      }
    }
  },

  trapBubbledEvent: function(topLevelType, handlerBaseName, handle) {
    return ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent(
      topLevelType,
      handlerBaseName,
      handle
    );
  },

  trapCapturedEvent: function(topLevelType, handlerBaseName, handle) {
    return ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent(
      topLevelType,
      handlerBaseName,
      handle
    );
  },

  /**
   * Listens to window scroll and resize events. We cache scroll values so that
   * application code can access them without triggering reflows.
   *
   * NOTE: Scroll events do not bubble.
   *
   * @see http://www.quirksmode.org/dom/events/scroll.html
   */
  ensureScrollValueMonitoring: function(){
    if (!isMonitoringScrollValue) {
      var refresh = ViewportMetrics.refreshScrollValues;
      ReactBrowserEventEmitter.ReactEventListener.monitorScrollValue(refresh);
      isMonitoringScrollValue = true;
    }
  },

  eventNameDispatchConfigs: EventPluginHub.eventNameDispatchConfigs,

  registrationNameModules: EventPluginHub.registrationNameModules,

  putListener: EventPluginHub.putListener,

  getListener: EventPluginHub.getListener,

  deleteListener: EventPluginHub.deleteListener,

  deleteAllListeners: EventPluginHub.deleteAllListeners

});

module.exports = ReactBrowserEventEmitter;

},{"./EventConstants":"/Users/zordius/webtasks/node_modules/react/lib/EventConstants.js","./EventPluginHub":"/Users/zordius/webtasks/node_modules/react/lib/EventPluginHub.js","./EventPluginRegistry":"/Users/zordius/webtasks/node_modules/react/lib/EventPluginRegistry.js","./Object.assign":"/Users/zordius/webtasks/node_modules/react/lib/Object.assign.js","./ReactEventEmitterMixin":"/Users/zordius/webtasks/node_modules/react/lib/ReactEventEmitterMixin.js","./ViewportMetrics":"/Users/zordius/webtasks/node_modules/react/lib/ViewportMetrics.js","./isEventSupported":"/Users/zordius/webtasks/node_modules/react/lib/isEventSupported.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactChildren.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactChildren
 */

"use strict";

var PooledClass = require("./PooledClass");

var traverseAllChildren = require("./traverseAllChildren");
var warning = require("./warning");

var twoArgumentPooler = PooledClass.twoArgumentPooler;
var threeArgumentPooler = PooledClass.threeArgumentPooler;

/**
 * PooledClass representing the bookkeeping associated with performing a child
 * traversal. Allows avoiding binding callbacks.
 *
 * @constructor ForEachBookKeeping
 * @param {!function} forEachFunction Function to perform traversal with.
 * @param {?*} forEachContext Context to perform context with.
 */
function ForEachBookKeeping(forEachFunction, forEachContext) {
  this.forEachFunction = forEachFunction;
  this.forEachContext = forEachContext;
}
PooledClass.addPoolingTo(ForEachBookKeeping, twoArgumentPooler);

function forEachSingleChild(traverseContext, child, name, i) {
  var forEachBookKeeping = traverseContext;
  forEachBookKeeping.forEachFunction.call(
    forEachBookKeeping.forEachContext, child, i);
}

/**
 * Iterates through children that are typically specified as `props.children`.
 *
 * The provided forEachFunc(child, index) will be called for each
 * leaf child.
 *
 * @param {?*} children Children tree container.
 * @param {function(*, int)} forEachFunc.
 * @param {*} forEachContext Context for forEachContext.
 */
function forEachChildren(children, forEachFunc, forEachContext) {
  if (children == null) {
    return children;
  }

  var traverseContext =
    ForEachBookKeeping.getPooled(forEachFunc, forEachContext);
  traverseAllChildren(children, forEachSingleChild, traverseContext);
  ForEachBookKeeping.release(traverseContext);
}

/**
 * PooledClass representing the bookkeeping associated with performing a child
 * mapping. Allows avoiding binding callbacks.
 *
 * @constructor MapBookKeeping
 * @param {!*} mapResult Object containing the ordered map of results.
 * @param {!function} mapFunction Function to perform mapping with.
 * @param {?*} mapContext Context to perform mapping with.
 */
function MapBookKeeping(mapResult, mapFunction, mapContext) {
  this.mapResult = mapResult;
  this.mapFunction = mapFunction;
  this.mapContext = mapContext;
}
PooledClass.addPoolingTo(MapBookKeeping, threeArgumentPooler);

function mapSingleChildIntoContext(traverseContext, child, name, i) {
  var mapBookKeeping = traverseContext;
  var mapResult = mapBookKeeping.mapResult;

  var keyUnique = !mapResult.hasOwnProperty(name);
  ("production" !== process.env.NODE_ENV ? warning(
    keyUnique,
    'ReactChildren.map(...): Encountered two children with the same key, ' +
    '`%s`. Child keys must be unique; when two children share a key, only ' +
    'the first child will be used.',
    name
  ) : null);

  if (keyUnique) {
    var mappedChild =
      mapBookKeeping.mapFunction.call(mapBookKeeping.mapContext, child, i);
    mapResult[name] = mappedChild;
  }
}

/**
 * Maps children that are typically specified as `props.children`.
 *
 * The provided mapFunction(child, key, index) will be called for each
 * leaf child.
 *
 * TODO: This may likely break any calls to `ReactChildren.map` that were
 * previously relying on the fact that we guarded against null children.
 *
 * @param {?*} children Children tree container.
 * @param {function(*, int)} mapFunction.
 * @param {*} mapContext Context for mapFunction.
 * @return {object} Object containing the ordered map of results.
 */
function mapChildren(children, func, context) {
  if (children == null) {
    return children;
  }

  var mapResult = {};
  var traverseContext = MapBookKeeping.getPooled(mapResult, func, context);
  traverseAllChildren(children, mapSingleChildIntoContext, traverseContext);
  MapBookKeeping.release(traverseContext);
  return mapResult;
}

function forEachSingleChildDummy(traverseContext, child, name, i) {
  return null;
}

/**
 * Count the number of children that are typically specified as
 * `props.children`.
 *
 * @param {?*} children Children tree container.
 * @return {number} The number of children.
 */
function countChildren(children, context) {
  return traverseAllChildren(children, forEachSingleChildDummy, null);
}

var ReactChildren = {
  forEach: forEachChildren,
  map: mapChildren,
  count: countChildren
};

module.exports = ReactChildren;

}).call(this,require('_process'))
},{"./PooledClass":"/Users/zordius/webtasks/node_modules/react/lib/PooledClass.js","./traverseAllChildren":"/Users/zordius/webtasks/node_modules/react/lib/traverseAllChildren.js","./warning":"/Users/zordius/webtasks/node_modules/react/lib/warning.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactComponent.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactComponent
 */

"use strict";

var ReactElement = require("./ReactElement");
var ReactOwner = require("./ReactOwner");
var ReactUpdates = require("./ReactUpdates");

var assign = require("./Object.assign");
var invariant = require("./invariant");
var keyMirror = require("./keyMirror");

/**
 * Every React component is in one of these life cycles.
 */
var ComponentLifeCycle = keyMirror({
  /**
   * Mounted components have a DOM node representation and are capable of
   * receiving new props.
   */
  MOUNTED: null,
  /**
   * Unmounted components are inactive and cannot receive new props.
   */
  UNMOUNTED: null
});

var injected = false;

/**
 * Optionally injectable environment dependent cleanup hook. (server vs.
 * browser etc). Example: A browser system caches DOM nodes based on component
 * ID and must remove that cache entry when this instance is unmounted.
 *
 * @private
 */
var unmountIDFromEnvironment = null;

/**
 * The "image" of a component tree, is the platform specific (typically
 * serialized) data that represents a tree of lower level UI building blocks.
 * On the web, this "image" is HTML markup which describes a construction of
 * low level `div` and `span` nodes. Other platforms may have different
 * encoding of this "image". This must be injected.
 *
 * @private
 */
var mountImageIntoNode = null;

/**
 * Components are the basic units of composition in React.
 *
 * Every component accepts a set of keyed input parameters known as "props" that
 * are initialized by the constructor. Once a component is mounted, the props
 * can be mutated using `setProps` or `replaceProps`.
 *
 * Every component is capable of the following operations:
 *
 *   `mountComponent`
 *     Initializes the component, renders markup, and registers event listeners.
 *
 *   `receiveComponent`
 *     Updates the rendered DOM nodes to match the given component.
 *
 *   `unmountComponent`
 *     Releases any resources allocated by this component.
 *
 * Components can also be "owned" by other components. Being owned by another
 * component means being constructed by that component. This is different from
 * being the child of a component, which means having a DOM representation that
 * is a child of the DOM representation of that component.
 *
 * @class ReactComponent
 */
var ReactComponent = {

  injection: {
    injectEnvironment: function(ReactComponentEnvironment) {
      ("production" !== process.env.NODE_ENV ? invariant(
        !injected,
        'ReactComponent: injectEnvironment() can only be called once.'
      ) : invariant(!injected));
      mountImageIntoNode = ReactComponentEnvironment.mountImageIntoNode;
      unmountIDFromEnvironment =
        ReactComponentEnvironment.unmountIDFromEnvironment;
      ReactComponent.BackendIDOperations =
        ReactComponentEnvironment.BackendIDOperations;
      injected = true;
    }
  },

  /**
   * @internal
   */
  LifeCycle: ComponentLifeCycle,

  /**
   * Injected module that provides ability to mutate individual properties.
   * Injected into the base class because many different subclasses need access
   * to this.
   *
   * @internal
   */
  BackendIDOperations: null,

  /**
   * Base functionality for every ReactComponent constructor. Mixed into the
   * `ReactComponent` prototype, but exposed statically for easy access.
   *
   * @lends {ReactComponent.prototype}
   */
  Mixin: {

    /**
     * Checks whether or not this component is mounted.
     *
     * @return {boolean} True if mounted, false otherwise.
     * @final
     * @protected
     */
    isMounted: function() {
      return this._lifeCycleState === ComponentLifeCycle.MOUNTED;
    },

    /**
     * Sets a subset of the props.
     *
     * @param {object} partialProps Subset of the next props.
     * @param {?function} callback Called after props are updated.
     * @final
     * @public
     */
    setProps: function(partialProps, callback) {
      // Merge with the pending element if it exists, otherwise with existing
      // element props.
      var element = this._pendingElement || this._currentElement;
      this.replaceProps(
        assign({}, element.props, partialProps),
        callback
      );
    },

    /**
     * Replaces all of the props.
     *
     * @param {object} props New props.
     * @param {?function} callback Called after props are updated.
     * @final
     * @public
     */
    replaceProps: function(props, callback) {
      ("production" !== process.env.NODE_ENV ? invariant(
        this.isMounted(),
        'replaceProps(...): Can only update a mounted component.'
      ) : invariant(this.isMounted()));
      ("production" !== process.env.NODE_ENV ? invariant(
        this._mountDepth === 0,
        'replaceProps(...): You called `setProps` or `replaceProps` on a ' +
        'component with a parent. This is an anti-pattern since props will ' +
        'get reactively updated when rendered. Instead, change the owner\'s ' +
        '`render` method to pass the correct value as props to the component ' +
        'where it is created.'
      ) : invariant(this._mountDepth === 0));
      // This is a deoptimized path. We optimize for always having a element.
      // This creates an extra internal element.
      this._pendingElement = ReactElement.cloneAndReplaceProps(
        this._pendingElement || this._currentElement,
        props
      );
      ReactUpdates.enqueueUpdate(this, callback);
    },

    /**
     * Schedule a partial update to the props. Only used for internal testing.
     *
     * @param {object} partialProps Subset of the next props.
     * @param {?function} callback Called after props are updated.
     * @final
     * @internal
     */
    _setPropsInternal: function(partialProps, callback) {
      // This is a deoptimized path. We optimize for always having a element.
      // This creates an extra internal element.
      var element = this._pendingElement || this._currentElement;
      this._pendingElement = ReactElement.cloneAndReplaceProps(
        element,
        assign({}, element.props, partialProps)
      );
      ReactUpdates.enqueueUpdate(this, callback);
    },

    /**
     * Base constructor for all React components.
     *
     * Subclasses that override this method should make sure to invoke
     * `ReactComponent.Mixin.construct.call(this, ...)`.
     *
     * @param {ReactElement} element
     * @internal
     */
    construct: function(element) {
      // This is the public exposed props object after it has been processed
      // with default props. The element's props represents the true internal
      // state of the props.
      this.props = element.props;
      // Record the component responsible for creating this component.
      // This is accessible through the element but we maintain an extra
      // field for compatibility with devtools and as a way to make an
      // incremental update. TODO: Consider deprecating this field.
      this._owner = element._owner;

      // All components start unmounted.
      this._lifeCycleState = ComponentLifeCycle.UNMOUNTED;

      // See ReactUpdates.
      this._pendingCallbacks = null;

      // We keep the old element and a reference to the pending element
      // to track updates.
      this._currentElement = element;
      this._pendingElement = null;
    },

    /**
     * Initializes the component, renders markup, and registers event listeners.
     *
     * NOTE: This does not insert any nodes into the DOM.
     *
     * Subclasses that override this method should make sure to invoke
     * `ReactComponent.Mixin.mountComponent.call(this, ...)`.
     *
     * @param {string} rootID DOM ID of the root node.
     * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
     * @param {number} mountDepth number of components in the owner hierarchy.
     * @return {?string} Rendered markup to be inserted into the DOM.
     * @internal
     */
    mountComponent: function(rootID, transaction, mountDepth) {
      ("production" !== process.env.NODE_ENV ? invariant(
        !this.isMounted(),
        'mountComponent(%s, ...): Can only mount an unmounted component. ' +
        'Make sure to avoid storing components between renders or reusing a ' +
        'single component instance in multiple places.',
        rootID
      ) : invariant(!this.isMounted()));
      var ref = this._currentElement.ref;
      if (ref != null) {
        var owner = this._currentElement._owner;
        ReactOwner.addComponentAsRefTo(this, ref, owner);
      }
      this._rootNodeID = rootID;
      this._lifeCycleState = ComponentLifeCycle.MOUNTED;
      this._mountDepth = mountDepth;
      // Effectively: return '';
    },

    /**
     * Releases any resources allocated by `mountComponent`.
     *
     * NOTE: This does not remove any nodes from the DOM.
     *
     * Subclasses that override this method should make sure to invoke
     * `ReactComponent.Mixin.unmountComponent.call(this)`.
     *
     * @internal
     */
    unmountComponent: function() {
      ("production" !== process.env.NODE_ENV ? invariant(
        this.isMounted(),
        'unmountComponent(): Can only unmount a mounted component.'
      ) : invariant(this.isMounted()));
      var ref = this._currentElement.ref;
      if (ref != null) {
        ReactOwner.removeComponentAsRefFrom(this, ref, this._owner);
      }
      unmountIDFromEnvironment(this._rootNodeID);
      this._rootNodeID = null;
      this._lifeCycleState = ComponentLifeCycle.UNMOUNTED;
    },

    /**
     * Given a new instance of this component, updates the rendered DOM nodes
     * as if that instance was rendered instead.
     *
     * Subclasses that override this method should make sure to invoke
     * `ReactComponent.Mixin.receiveComponent.call(this, ...)`.
     *
     * @param {object} nextComponent Next set of properties.
     * @param {ReactReconcileTransaction} transaction
     * @internal
     */
    receiveComponent: function(nextElement, transaction) {
      ("production" !== process.env.NODE_ENV ? invariant(
        this.isMounted(),
        'receiveComponent(...): Can only update a mounted component.'
      ) : invariant(this.isMounted()));
      this._pendingElement = nextElement;
      this.performUpdateIfNecessary(transaction);
    },

    /**
     * If `_pendingElement` is set, update the component.
     *
     * @param {ReactReconcileTransaction} transaction
     * @internal
     */
    performUpdateIfNecessary: function(transaction) {
      if (this._pendingElement == null) {
        return;
      }
      var prevElement = this._currentElement;
      var nextElement = this._pendingElement;
      this._currentElement = nextElement;
      this.props = nextElement.props;
      this._owner = nextElement._owner;
      this._pendingElement = null;
      this.updateComponent(transaction, prevElement);
    },

    /**
     * Updates the component's currently mounted representation.
     *
     * @param {ReactReconcileTransaction} transaction
     * @param {object} prevElement
     * @internal
     */
    updateComponent: function(transaction, prevElement) {
      var nextElement = this._currentElement;

      // If either the owner or a `ref` has changed, make sure the newest owner
      // has stored a reference to `this`, and the previous owner (if different)
      // has forgotten the reference to `this`. We use the element instead
      // of the public this.props because the post processing cannot determine
      // a ref. The ref conceptually lives on the element.

      // TODO: Should this even be possible? The owner cannot change because
      // it's forbidden by shouldUpdateReactComponent. The ref can change
      // if you swap the keys of but not the refs. Reconsider where this check
      // is made. It probably belongs where the key checking and
      // instantiateReactComponent is done.

      if (nextElement._owner !== prevElement._owner ||
          nextElement.ref !== prevElement.ref) {
        if (prevElement.ref != null) {
          ReactOwner.removeComponentAsRefFrom(
            this, prevElement.ref, prevElement._owner
          );
        }
        // Correct, even if the owner is the same, and only the ref has changed.
        if (nextElement.ref != null) {
          ReactOwner.addComponentAsRefTo(
            this,
            nextElement.ref,
            nextElement._owner
          );
        }
      }
    },

    /**
     * Mounts this component and inserts it into the DOM.
     *
     * @param {string} rootID DOM ID of the root node.
     * @param {DOMElement} container DOM element to mount into.
     * @param {boolean} shouldReuseMarkup If true, do not insert markup
     * @final
     * @internal
     * @see {ReactMount.render}
     */
    mountComponentIntoNode: function(rootID, container, shouldReuseMarkup) {
      var transaction = ReactUpdates.ReactReconcileTransaction.getPooled();
      transaction.perform(
        this._mountComponentIntoNode,
        this,
        rootID,
        container,
        transaction,
        shouldReuseMarkup
      );
      ReactUpdates.ReactReconcileTransaction.release(transaction);
    },

    /**
     * @param {string} rootID DOM ID of the root node.
     * @param {DOMElement} container DOM element to mount into.
     * @param {ReactReconcileTransaction} transaction
     * @param {boolean} shouldReuseMarkup If true, do not insert markup
     * @final
     * @private
     */
    _mountComponentIntoNode: function(
        rootID,
        container,
        transaction,
        shouldReuseMarkup) {
      var markup = this.mountComponent(rootID, transaction, 0);
      mountImageIntoNode(markup, container, shouldReuseMarkup);
    },

    /**
     * Checks if this component is owned by the supplied `owner` component.
     *
     * @param {ReactComponent} owner Component to check.
     * @return {boolean} True if `owners` owns this component.
     * @final
     * @internal
     */
    isOwnedBy: function(owner) {
      return this._owner === owner;
    },

    /**
     * Gets another component, that shares the same owner as this one, by ref.
     *
     * @param {string} ref of a sibling Component.
     * @return {?ReactComponent} the actual sibling Component.
     * @final
     * @internal
     */
    getSiblingByRef: function(ref) {
      var owner = this._owner;
      if (!owner || !owner.refs) {
        return null;
      }
      return owner.refs[ref];
    }
  }
};

module.exports = ReactComponent;

}).call(this,require('_process'))
},{"./Object.assign":"/Users/zordius/webtasks/node_modules/react/lib/Object.assign.js","./ReactElement":"/Users/zordius/webtasks/node_modules/react/lib/ReactElement.js","./ReactOwner":"/Users/zordius/webtasks/node_modules/react/lib/ReactOwner.js","./ReactUpdates":"/Users/zordius/webtasks/node_modules/react/lib/ReactUpdates.js","./invariant":"/Users/zordius/webtasks/node_modules/react/lib/invariant.js","./keyMirror":"/Users/zordius/webtasks/node_modules/react/lib/keyMirror.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactComponentBrowserEnvironment.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactComponentBrowserEnvironment
 */

/*jslint evil: true */

"use strict";

var ReactDOMIDOperations = require("./ReactDOMIDOperations");
var ReactMarkupChecksum = require("./ReactMarkupChecksum");
var ReactMount = require("./ReactMount");
var ReactPerf = require("./ReactPerf");
var ReactReconcileTransaction = require("./ReactReconcileTransaction");

var getReactRootElementInContainer = require("./getReactRootElementInContainer");
var invariant = require("./invariant");
var setInnerHTML = require("./setInnerHTML");


var ELEMENT_NODE_TYPE = 1;
var DOC_NODE_TYPE = 9;


/**
 * Abstracts away all functionality of `ReactComponent` requires knowledge of
 * the browser context.
 */
var ReactComponentBrowserEnvironment = {
  ReactReconcileTransaction: ReactReconcileTransaction,

  BackendIDOperations: ReactDOMIDOperations,

  /**
   * If a particular environment requires that some resources be cleaned up,
   * specify this in the injected Mixin. In the DOM, we would likely want to
   * purge any cached node ID lookups.
   *
   * @private
   */
  unmountIDFromEnvironment: function(rootNodeID) {
    ReactMount.purgeID(rootNodeID);
  },

  /**
   * @param {string} markup Markup string to place into the DOM Element.
   * @param {DOMElement} container DOM Element to insert markup into.
   * @param {boolean} shouldReuseMarkup Should reuse the existing markup in the
   * container if possible.
   */
  mountImageIntoNode: ReactPerf.measure(
    'ReactComponentBrowserEnvironment',
    'mountImageIntoNode',
    function(markup, container, shouldReuseMarkup) {
      ("production" !== process.env.NODE_ENV ? invariant(
        container && (
          container.nodeType === ELEMENT_NODE_TYPE ||
            container.nodeType === DOC_NODE_TYPE
        ),
        'mountComponentIntoNode(...): Target container is not valid.'
      ) : invariant(container && (
        container.nodeType === ELEMENT_NODE_TYPE ||
          container.nodeType === DOC_NODE_TYPE
      )));

      if (shouldReuseMarkup) {
        if (ReactMarkupChecksum.canReuseMarkup(
          markup,
          getReactRootElementInContainer(container))) {
          return;
        } else {
          ("production" !== process.env.NODE_ENV ? invariant(
            container.nodeType !== DOC_NODE_TYPE,
            'You\'re trying to render a component to the document using ' +
            'server rendering but the checksum was invalid. This usually ' +
            'means you rendered a different component type or props on ' +
            'the client from the one on the server, or your render() ' +
            'methods are impure. React cannot handle this case due to ' +
            'cross-browser quirks by rendering at the document root. You ' +
            'should look for environment dependent code in your components ' +
            'and ensure the props are the same client and server side.'
          ) : invariant(container.nodeType !== DOC_NODE_TYPE));

          if ("production" !== process.env.NODE_ENV) {
            console.warn(
              'React attempted to use reuse markup in a container but the ' +
              'checksum was invalid. This generally means that you are ' +
              'using server rendering and the markup generated on the ' +
              'server was not what the client was expecting. React injected ' +
              'new markup to compensate which works but you have lost many ' +
              'of the benefits of server rendering. Instead, figure out ' +
              'why the markup being generated is different on the client ' +
              'or server.'
            );
          }
        }
      }

      ("production" !== process.env.NODE_ENV ? invariant(
        container.nodeType !== DOC_NODE_TYPE,
        'You\'re trying to render a component to the document but ' +
          'you didn\'t use server rendering. We can\'t do this ' +
          'without using server rendering due to cross-browser quirks. ' +
          'See renderComponentToString() for server rendering.'
      ) : invariant(container.nodeType !== DOC_NODE_TYPE));

      setInnerHTML(container, markup);
    }
  )
};

module.exports = ReactComponentBrowserEnvironment;

}).call(this,require('_process'))
},{"./ReactDOMIDOperations":"/Users/zordius/webtasks/node_modules/react/lib/ReactDOMIDOperations.js","./ReactMarkupChecksum":"/Users/zordius/webtasks/node_modules/react/lib/ReactMarkupChecksum.js","./ReactMount":"/Users/zordius/webtasks/node_modules/react/lib/ReactMount.js","./ReactPerf":"/Users/zordius/webtasks/node_modules/react/lib/ReactPerf.js","./ReactReconcileTransaction":"/Users/zordius/webtasks/node_modules/react/lib/ReactReconcileTransaction.js","./getReactRootElementInContainer":"/Users/zordius/webtasks/node_modules/react/lib/getReactRootElementInContainer.js","./invariant":"/Users/zordius/webtasks/node_modules/react/lib/invariant.js","./setInnerHTML":"/Users/zordius/webtasks/node_modules/react/lib/setInnerHTML.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactCompositeComponent.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactCompositeComponent
 */

"use strict";

var ReactComponent = require("./ReactComponent");
var ReactContext = require("./ReactContext");
var ReactCurrentOwner = require("./ReactCurrentOwner");
var ReactElement = require("./ReactElement");
var ReactElementValidator = require("./ReactElementValidator");
var ReactEmptyComponent = require("./ReactEmptyComponent");
var ReactErrorUtils = require("./ReactErrorUtils");
var ReactLegacyElement = require("./ReactLegacyElement");
var ReactOwner = require("./ReactOwner");
var ReactPerf = require("./ReactPerf");
var ReactPropTransferer = require("./ReactPropTransferer");
var ReactPropTypeLocations = require("./ReactPropTypeLocations");
var ReactPropTypeLocationNames = require("./ReactPropTypeLocationNames");
var ReactUpdates = require("./ReactUpdates");

var assign = require("./Object.assign");
var instantiateReactComponent = require("./instantiateReactComponent");
var invariant = require("./invariant");
var keyMirror = require("./keyMirror");
var keyOf = require("./keyOf");
var monitorCodeUse = require("./monitorCodeUse");
var mapObject = require("./mapObject");
var shouldUpdateReactComponent = require("./shouldUpdateReactComponent");
var warning = require("./warning");

var MIXINS_KEY = keyOf({mixins: null});

/**
 * Policies that describe methods in `ReactCompositeComponentInterface`.
 */
var SpecPolicy = keyMirror({
  /**
   * These methods may be defined only once by the class specification or mixin.
   */
  DEFINE_ONCE: null,
  /**
   * These methods may be defined by both the class specification and mixins.
   * Subsequent definitions will be chained. These methods must return void.
   */
  DEFINE_MANY: null,
  /**
   * These methods are overriding the base ReactCompositeComponent class.
   */
  OVERRIDE_BASE: null,
  /**
   * These methods are similar to DEFINE_MANY, except we assume they return
   * objects. We try to merge the keys of the return values of all the mixed in
   * functions. If there is a key conflict we throw.
   */
  DEFINE_MANY_MERGED: null
});


var injectedMixins = [];

/**
 * Composite components are higher-level components that compose other composite
 * or native components.
 *
 * To create a new type of `ReactCompositeComponent`, pass a specification of
 * your new class to `React.createClass`. The only requirement of your class
 * specification is that you implement a `render` method.
 *
 *   var MyComponent = React.createClass({
 *     render: function() {
 *       return <div>Hello World</div>;
 *     }
 *   });
 *
 * The class specification supports a specific protocol of methods that have
 * special meaning (e.g. `render`). See `ReactCompositeComponentInterface` for
 * more the comprehensive protocol. Any other properties and methods in the
 * class specification will available on the prototype.
 *
 * @interface ReactCompositeComponentInterface
 * @internal
 */
var ReactCompositeComponentInterface = {

  /**
   * An array of Mixin objects to include when defining your component.
   *
   * @type {array}
   * @optional
   */
  mixins: SpecPolicy.DEFINE_MANY,

  /**
   * An object containing properties and methods that should be defined on
   * the component's constructor instead of its prototype (static methods).
   *
   * @type {object}
   * @optional
   */
  statics: SpecPolicy.DEFINE_MANY,

  /**
   * Definition of prop types for this component.
   *
   * @type {object}
   * @optional
   */
  propTypes: SpecPolicy.DEFINE_MANY,

  /**
   * Definition of context types for this component.
   *
   * @type {object}
   * @optional
   */
  contextTypes: SpecPolicy.DEFINE_MANY,

  /**
   * Definition of context types this component sets for its children.
   *
   * @type {object}
   * @optional
   */
  childContextTypes: SpecPolicy.DEFINE_MANY,

  // ==== Definition methods ====

  /**
   * Invoked when the component is mounted. Values in the mapping will be set on
   * `this.props` if that prop is not specified (i.e. using an `in` check).
   *
   * This method is invoked before `getInitialState` and therefore cannot rely
   * on `this.state` or use `this.setState`.
   *
   * @return {object}
   * @optional
   */
  getDefaultProps: SpecPolicy.DEFINE_MANY_MERGED,

  /**
   * Invoked once before the component is mounted. The return value will be used
   * as the initial value of `this.state`.
   *
   *   getInitialState: function() {
   *     return {
   *       isOn: false,
   *       fooBaz: new BazFoo()
   *     }
   *   }
   *
   * @return {object}
   * @optional
   */
  getInitialState: SpecPolicy.DEFINE_MANY_MERGED,

  /**
   * @return {object}
   * @optional
   */
  getChildContext: SpecPolicy.DEFINE_MANY_MERGED,

  /**
   * Uses props from `this.props` and state from `this.state` to render the
   * structure of the component.
   *
   * No guarantees are made about when or how often this method is invoked, so
   * it must not have side effects.
   *
   *   render: function() {
   *     var name = this.props.name;
   *     return <div>Hello, {name}!</div>;
   *   }
   *
   * @return {ReactComponent}
   * @nosideeffects
   * @required
   */
  render: SpecPolicy.DEFINE_ONCE,



  // ==== Delegate methods ====

  /**
   * Invoked when the component is initially created and about to be mounted.
   * This may have side effects, but any external subscriptions or data created
   * by this method must be cleaned up in `componentWillUnmount`.
   *
   * @optional
   */
  componentWillMount: SpecPolicy.DEFINE_MANY,

  /**
   * Invoked when the component has been mounted and has a DOM representation.
   * However, there is no guarantee that the DOM node is in the document.
   *
   * Use this as an opportunity to operate on the DOM when the component has
   * been mounted (initialized and rendered) for the first time.
   *
   * @param {DOMElement} rootNode DOM element representing the component.
   * @optional
   */
  componentDidMount: SpecPolicy.DEFINE_MANY,

  /**
   * Invoked before the component receives new props.
   *
   * Use this as an opportunity to react to a prop transition by updating the
   * state using `this.setState`. Current props are accessed via `this.props`.
   *
   *   componentWillReceiveProps: function(nextProps, nextContext) {
   *     this.setState({
   *       likesIncreasing: nextProps.likeCount > this.props.likeCount
   *     });
   *   }
   *
   * NOTE: There is no equivalent `componentWillReceiveState`. An incoming prop
   * transition may cause a state change, but the opposite is not true. If you
   * need it, you are probably looking for `componentWillUpdate`.
   *
   * @param {object} nextProps
   * @optional
   */
  componentWillReceiveProps: SpecPolicy.DEFINE_MANY,

  /**
   * Invoked while deciding if the component should be updated as a result of
   * receiving new props, state and/or context.
   *
   * Use this as an opportunity to `return false` when you're certain that the
   * transition to the new props/state/context will not require a component
   * update.
   *
   *   shouldComponentUpdate: function(nextProps, nextState, nextContext) {
   *     return !equal(nextProps, this.props) ||
   *       !equal(nextState, this.state) ||
   *       !equal(nextContext, this.context);
   *   }
   *
   * @param {object} nextProps
   * @param {?object} nextState
   * @param {?object} nextContext
   * @return {boolean} True if the component should update.
   * @optional
   */
  shouldComponentUpdate: SpecPolicy.DEFINE_ONCE,

  /**
   * Invoked when the component is about to update due to a transition from
   * `this.props`, `this.state` and `this.context` to `nextProps`, `nextState`
   * and `nextContext`.
   *
   * Use this as an opportunity to perform preparation before an update occurs.
   *
   * NOTE: You **cannot** use `this.setState()` in this method.
   *
   * @param {object} nextProps
   * @param {?object} nextState
   * @param {?object} nextContext
   * @param {ReactReconcileTransaction} transaction
   * @optional
   */
  componentWillUpdate: SpecPolicy.DEFINE_MANY,

  /**
   * Invoked when the component's DOM representation has been updated.
   *
   * Use this as an opportunity to operate on the DOM when the component has
   * been updated.
   *
   * @param {object} prevProps
   * @param {?object} prevState
   * @param {?object} prevContext
   * @param {DOMElement} rootNode DOM element representing the component.
   * @optional
   */
  componentDidUpdate: SpecPolicy.DEFINE_MANY,

  /**
   * Invoked when the component is about to be removed from its parent and have
   * its DOM representation destroyed.
   *
   * Use this as an opportunity to deallocate any external resources.
   *
   * NOTE: There is no `componentDidUnmount` since your component will have been
   * destroyed by that point.
   *
   * @optional
   */
  componentWillUnmount: SpecPolicy.DEFINE_MANY,



  // ==== Advanced methods ====

  /**
   * Updates the component's currently mounted DOM representation.
   *
   * By default, this implements React's rendering and reconciliation algorithm.
   * Sophisticated clients may wish to override this.
   *
   * @param {ReactReconcileTransaction} transaction
   * @internal
   * @overridable
   */
  updateComponent: SpecPolicy.OVERRIDE_BASE

};

/**
 * Mapping from class specification keys to special processing functions.
 *
 * Although these are declared like instance properties in the specification
 * when defining classes using `React.createClass`, they are actually static
 * and are accessible on the constructor instead of the prototype. Despite
 * being static, they must be defined outside of the "statics" key under
 * which all other static methods are defined.
 */
var RESERVED_SPEC_KEYS = {
  displayName: function(Constructor, displayName) {
    Constructor.displayName = displayName;
  },
  mixins: function(Constructor, mixins) {
    if (mixins) {
      for (var i = 0; i < mixins.length; i++) {
        mixSpecIntoComponent(Constructor, mixins[i]);
      }
    }
  },
  childContextTypes: function(Constructor, childContextTypes) {
    validateTypeDef(
      Constructor,
      childContextTypes,
      ReactPropTypeLocations.childContext
    );
    Constructor.childContextTypes = assign(
      {},
      Constructor.childContextTypes,
      childContextTypes
    );
  },
  contextTypes: function(Constructor, contextTypes) {
    validateTypeDef(
      Constructor,
      contextTypes,
      ReactPropTypeLocations.context
    );
    Constructor.contextTypes = assign(
      {},
      Constructor.contextTypes,
      contextTypes
    );
  },
  /**
   * Special case getDefaultProps which should move into statics but requires
   * automatic merging.
   */
  getDefaultProps: function(Constructor, getDefaultProps) {
    if (Constructor.getDefaultProps) {
      Constructor.getDefaultProps = createMergedResultFunction(
        Constructor.getDefaultProps,
        getDefaultProps
      );
    } else {
      Constructor.getDefaultProps = getDefaultProps;
    }
  },
  propTypes: function(Constructor, propTypes) {
    validateTypeDef(
      Constructor,
      propTypes,
      ReactPropTypeLocations.prop
    );
    Constructor.propTypes = assign(
      {},
      Constructor.propTypes,
      propTypes
    );
  },
  statics: function(Constructor, statics) {
    mixStaticSpecIntoComponent(Constructor, statics);
  }
};

function getDeclarationErrorAddendum(component) {
  var owner = component._owner || null;
  if (owner && owner.constructor && owner.constructor.displayName) {
    return ' Check the render method of `' + owner.constructor.displayName +
      '`.';
  }
  return '';
}

function validateTypeDef(Constructor, typeDef, location) {
  for (var propName in typeDef) {
    if (typeDef.hasOwnProperty(propName)) {
      ("production" !== process.env.NODE_ENV ? invariant(
        typeof typeDef[propName] == 'function',
        '%s: %s type `%s` is invalid; it must be a function, usually from ' +
        'React.PropTypes.',
        Constructor.displayName || 'ReactCompositeComponent',
        ReactPropTypeLocationNames[location],
        propName
      ) : invariant(typeof typeDef[propName] == 'function'));
    }
  }
}

function validateMethodOverride(proto, name) {
  var specPolicy = ReactCompositeComponentInterface.hasOwnProperty(name) ?
    ReactCompositeComponentInterface[name] :
    null;

  // Disallow overriding of base class methods unless explicitly allowed.
  if (ReactCompositeComponentMixin.hasOwnProperty(name)) {
    ("production" !== process.env.NODE_ENV ? invariant(
      specPolicy === SpecPolicy.OVERRIDE_BASE,
      'ReactCompositeComponentInterface: You are attempting to override ' +
      '`%s` from your class specification. Ensure that your method names ' +
      'do not overlap with React methods.',
      name
    ) : invariant(specPolicy === SpecPolicy.OVERRIDE_BASE));
  }

  // Disallow defining methods more than once unless explicitly allowed.
  if (proto.hasOwnProperty(name)) {
    ("production" !== process.env.NODE_ENV ? invariant(
      specPolicy === SpecPolicy.DEFINE_MANY ||
      specPolicy === SpecPolicy.DEFINE_MANY_MERGED,
      'ReactCompositeComponentInterface: You are attempting to define ' +
      '`%s` on your component more than once. This conflict may be due ' +
      'to a mixin.',
      name
    ) : invariant(specPolicy === SpecPolicy.DEFINE_MANY ||
    specPolicy === SpecPolicy.DEFINE_MANY_MERGED));
  }
}

function validateLifeCycleOnReplaceState(instance) {
  var compositeLifeCycleState = instance._compositeLifeCycleState;
  ("production" !== process.env.NODE_ENV ? invariant(
    instance.isMounted() ||
      compositeLifeCycleState === CompositeLifeCycle.MOUNTING,
    'replaceState(...): Can only update a mounted or mounting component.'
  ) : invariant(instance.isMounted() ||
    compositeLifeCycleState === CompositeLifeCycle.MOUNTING));
  ("production" !== process.env.NODE_ENV ? invariant(
    ReactCurrentOwner.current == null,
    'replaceState(...): Cannot update during an existing state transition ' +
    '(such as within `render`). Render methods should be a pure function ' +
    'of props and state.'
  ) : invariant(ReactCurrentOwner.current == null));
  ("production" !== process.env.NODE_ENV ? invariant(compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING,
    'replaceState(...): Cannot update while unmounting component. This ' +
    'usually means you called setState() on an unmounted component.'
  ) : invariant(compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING));
}

/**
 * Mixin helper which handles policy validation and reserved
 * specification keys when building `ReactCompositeComponent` classses.
 */
function mixSpecIntoComponent(Constructor, spec) {
  if (!spec) {
    return;
  }

  ("production" !== process.env.NODE_ENV ? invariant(
    !ReactLegacyElement.isValidFactory(spec),
    'ReactCompositeComponent: You\'re attempting to ' +
    'use a component class as a mixin. Instead, just use a regular object.'
  ) : invariant(!ReactLegacyElement.isValidFactory(spec)));
  ("production" !== process.env.NODE_ENV ? invariant(
    !ReactElement.isValidElement(spec),
    'ReactCompositeComponent: You\'re attempting to ' +
    'use a component as a mixin. Instead, just use a regular object.'
  ) : invariant(!ReactElement.isValidElement(spec)));

  var proto = Constructor.prototype;

  // By handling mixins before any other properties, we ensure the same
  // chaining order is applied to methods with DEFINE_MANY policy, whether
  // mixins are listed before or after these methods in the spec.
  if (spec.hasOwnProperty(MIXINS_KEY)) {
    RESERVED_SPEC_KEYS.mixins(Constructor, spec.mixins);
  }

  for (var name in spec) {
    if (!spec.hasOwnProperty(name)) {
      continue;
    }

    if (name === MIXINS_KEY) {
      // We have already handled mixins in a special case above
      continue;
    }

    var property = spec[name];
    validateMethodOverride(proto, name);

    if (RESERVED_SPEC_KEYS.hasOwnProperty(name)) {
      RESERVED_SPEC_KEYS[name](Constructor, property);
    } else {
      // Setup methods on prototype:
      // The following member methods should not be automatically bound:
      // 1. Expected ReactCompositeComponent methods (in the "interface").
      // 2. Overridden methods (that were mixed in).
      var isCompositeComponentMethod =
        ReactCompositeComponentInterface.hasOwnProperty(name);
      var isAlreadyDefined = proto.hasOwnProperty(name);
      var markedDontBind = property && property.__reactDontBind;
      var isFunction = typeof property === 'function';
      var shouldAutoBind =
        isFunction &&
        !isCompositeComponentMethod &&
        !isAlreadyDefined &&
        !markedDontBind;

      if (shouldAutoBind) {
        if (!proto.__reactAutoBindMap) {
          proto.__reactAutoBindMap = {};
        }
        proto.__reactAutoBindMap[name] = property;
        proto[name] = property;
      } else {
        if (isAlreadyDefined) {
          var specPolicy = ReactCompositeComponentInterface[name];

          // These cases should already be caught by validateMethodOverride
          ("production" !== process.env.NODE_ENV ? invariant(
            isCompositeComponentMethod && (
              specPolicy === SpecPolicy.DEFINE_MANY_MERGED ||
              specPolicy === SpecPolicy.DEFINE_MANY
            ),
            'ReactCompositeComponent: Unexpected spec policy %s for key %s ' +
            'when mixing in component specs.',
            specPolicy,
            name
          ) : invariant(isCompositeComponentMethod && (
            specPolicy === SpecPolicy.DEFINE_MANY_MERGED ||
            specPolicy === SpecPolicy.DEFINE_MANY
          )));

          // For methods which are defined more than once, call the existing
          // methods before calling the new property, merging if appropriate.
          if (specPolicy === SpecPolicy.DEFINE_MANY_MERGED) {
            proto[name] = createMergedResultFunction(proto[name], property);
          } else if (specPolicy === SpecPolicy.DEFINE_MANY) {
            proto[name] = createChainedFunction(proto[name], property);
          }
        } else {
          proto[name] = property;
          if ("production" !== process.env.NODE_ENV) {
            // Add verbose displayName to the function, which helps when looking
            // at profiling tools.
            if (typeof property === 'function' && spec.displayName) {
              proto[name].displayName = spec.displayName + '_' + name;
            }
          }
        }
      }
    }
  }
}

function mixStaticSpecIntoComponent(Constructor, statics) {
  if (!statics) {
    return;
  }
  for (var name in statics) {
    var property = statics[name];
    if (!statics.hasOwnProperty(name)) {
      continue;
    }

    var isReserved = name in RESERVED_SPEC_KEYS;
    ("production" !== process.env.NODE_ENV ? invariant(
      !isReserved,
      'ReactCompositeComponent: You are attempting to define a reserved ' +
      'property, `%s`, that shouldn\'t be on the "statics" key. Define it ' +
      'as an instance property instead; it will still be accessible on the ' +
      'constructor.',
      name
    ) : invariant(!isReserved));

    var isInherited = name in Constructor;
    ("production" !== process.env.NODE_ENV ? invariant(
      !isInherited,
      'ReactCompositeComponent: You are attempting to define ' +
      '`%s` on your component more than once. This conflict may be ' +
      'due to a mixin.',
      name
    ) : invariant(!isInherited));
    Constructor[name] = property;
  }
}

/**
 * Merge two objects, but throw if both contain the same key.
 *
 * @param {object} one The first object, which is mutated.
 * @param {object} two The second object
 * @return {object} one after it has been mutated to contain everything in two.
 */
function mergeObjectsWithNoDuplicateKeys(one, two) {
  ("production" !== process.env.NODE_ENV ? invariant(
    one && two && typeof one === 'object' && typeof two === 'object',
    'mergeObjectsWithNoDuplicateKeys(): Cannot merge non-objects'
  ) : invariant(one && two && typeof one === 'object' && typeof two === 'object'));

  mapObject(two, function(value, key) {
    ("production" !== process.env.NODE_ENV ? invariant(
      one[key] === undefined,
      'mergeObjectsWithNoDuplicateKeys(): ' +
      'Tried to merge two objects with the same key: `%s`. This conflict ' +
      'may be due to a mixin; in particular, this may be caused by two ' +
      'getInitialState() or getDefaultProps() methods returning objects ' +
      'with clashing keys.',
      key
    ) : invariant(one[key] === undefined));
    one[key] = value;
  });
  return one;
}

/**
 * Creates a function that invokes two functions and merges their return values.
 *
 * @param {function} one Function to invoke first.
 * @param {function} two Function to invoke second.
 * @return {function} Function that invokes the two argument functions.
 * @private
 */
function createMergedResultFunction(one, two) {
  return function mergedResult() {
    var a = one.apply(this, arguments);
    var b = two.apply(this, arguments);
    if (a == null) {
      return b;
    } else if (b == null) {
      return a;
    }
    return mergeObjectsWithNoDuplicateKeys(a, b);
  };
}

/**
 * Creates a function that invokes two functions and ignores their return vales.
 *
 * @param {function} one Function to invoke first.
 * @param {function} two Function to invoke second.
 * @return {function} Function that invokes the two argument functions.
 * @private
 */
function createChainedFunction(one, two) {
  return function chainedFunction() {
    one.apply(this, arguments);
    two.apply(this, arguments);
  };
}

/**
 * `ReactCompositeComponent` maintains an auxiliary life cycle state in
 * `this._compositeLifeCycleState` (which can be null).
 *
 * This is different from the life cycle state maintained by `ReactComponent` in
 * `this._lifeCycleState`. The following diagram shows how the states overlap in
 * time. There are times when the CompositeLifeCycle is null - at those times it
 * is only meaningful to look at ComponentLifeCycle alone.
 *
 * Top Row: ReactComponent.ComponentLifeCycle
 * Low Row: ReactComponent.CompositeLifeCycle
 *
 * +-------+---------------------------------+--------+
 * |  UN   |             MOUNTED             |   UN   |
 * |MOUNTED|                                 | MOUNTED|
 * +-------+---------------------------------+--------+
 * |       ^--------+   +-------+   +--------^        |
 * |       |        |   |       |   |        |        |
 * |    0--|MOUNTING|-0-|RECEIVE|-0-|   UN   |--->0   |
 * |       |        |   |PROPS  |   |MOUNTING|        |
 * |       |        |   |       |   |        |        |
 * |       |        |   |       |   |        |        |
 * |       +--------+   +-------+   +--------+        |
 * |       |                                 |        |
 * +-------+---------------------------------+--------+
 */
var CompositeLifeCycle = keyMirror({
  /**
   * Components in the process of being mounted respond to state changes
   * differently.
   */
  MOUNTING: null,
  /**
   * Components in the process of being unmounted are guarded against state
   * changes.
   */
  UNMOUNTING: null,
  /**
   * Components that are mounted and receiving new props respond to state
   * changes differently.
   */
  RECEIVING_PROPS: null
});

/**
 * @lends {ReactCompositeComponent.prototype}
 */
var ReactCompositeComponentMixin = {

  /**
   * Base constructor for all composite component.
   *
   * @param {ReactElement} element
   * @final
   * @internal
   */
  construct: function(element) {
    // Children can be either an array or more than one argument
    ReactComponent.Mixin.construct.apply(this, arguments);
    ReactOwner.Mixin.construct.apply(this, arguments);

    this.state = null;
    this._pendingState = null;

    // This is the public post-processed context. The real context and pending
    // context lives on the element.
    this.context = null;

    this._compositeLifeCycleState = null;
  },

  /**
   * Checks whether or not this composite component is mounted.
   * @return {boolean} True if mounted, false otherwise.
   * @protected
   * @final
   */
  isMounted: function() {
    return ReactComponent.Mixin.isMounted.call(this) &&
      this._compositeLifeCycleState !== CompositeLifeCycle.MOUNTING;
  },

  /**
   * Initializes the component, renders markup, and registers event listeners.
   *
   * @param {string} rootID DOM ID of the root node.
   * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
   * @param {number} mountDepth number of components in the owner hierarchy
   * @return {?string} Rendered markup to be inserted into the DOM.
   * @final
   * @internal
   */
  mountComponent: ReactPerf.measure(
    'ReactCompositeComponent',
    'mountComponent',
    function(rootID, transaction, mountDepth) {
      ReactComponent.Mixin.mountComponent.call(
        this,
        rootID,
        transaction,
        mountDepth
      );
      this._compositeLifeCycleState = CompositeLifeCycle.MOUNTING;

      if (this.__reactAutoBindMap) {
        this._bindAutoBindMethods();
      }

      this.context = this._processContext(this._currentElement._context);
      this.props = this._processProps(this.props);

      this.state = this.getInitialState ? this.getInitialState() : null;
      ("production" !== process.env.NODE_ENV ? invariant(
        typeof this.state === 'object' && !Array.isArray(this.state),
        '%s.getInitialState(): must return an object or null',
        this.constructor.displayName || 'ReactCompositeComponent'
      ) : invariant(typeof this.state === 'object' && !Array.isArray(this.state)));

      this._pendingState = null;
      this._pendingForceUpdate = false;

      if (this.componentWillMount) {
        this.componentWillMount();
        // When mounting, calls to `setState` by `componentWillMount` will set
        // `this._pendingState` without triggering a re-render.
        if (this._pendingState) {
          this.state = this._pendingState;
          this._pendingState = null;
        }
      }

      this._renderedComponent = instantiateReactComponent(
        this._renderValidatedComponent(),
        this._currentElement.type // The wrapping type
      );

      // Done with mounting, `setState` will now trigger UI changes.
      this._compositeLifeCycleState = null;
      var markup = this._renderedComponent.mountComponent(
        rootID,
        transaction,
        mountDepth + 1
      );
      if (this.componentDidMount) {
        transaction.getReactMountReady().enqueue(this.componentDidMount, this);
      }
      return markup;
    }
  ),

  /**
   * Releases any resources allocated by `mountComponent`.
   *
   * @final
   * @internal
   */
  unmountComponent: function() {
    this._compositeLifeCycleState = CompositeLifeCycle.UNMOUNTING;
    if (this.componentWillUnmount) {
      this.componentWillUnmount();
    }
    this._compositeLifeCycleState = null;

    this._renderedComponent.unmountComponent();
    this._renderedComponent = null;

    ReactComponent.Mixin.unmountComponent.call(this);

    // Some existing components rely on this.props even after they've been
    // destroyed (in event handlers).
    // TODO: this.props = null;
    // TODO: this.state = null;
  },

  /**
   * Sets a subset of the state. Always use this or `replaceState` to mutate
   * state. You should treat `this.state` as immutable.
   *
   * There is no guarantee that `this.state` will be immediately updated, so
   * accessing `this.state` after calling this method may return the old value.
   *
   * There is no guarantee that calls to `setState` will run synchronously,
   * as they may eventually be batched together.  You can provide an optional
   * callback that will be executed when the call to setState is actually
   * completed.
   *
   * @param {object} partialState Next partial state to be merged with state.
   * @param {?function} callback Called after state is updated.
   * @final
   * @protected
   */
  setState: function(partialState, callback) {
    ("production" !== process.env.NODE_ENV ? invariant(
      typeof partialState === 'object' || partialState == null,
      'setState(...): takes an object of state variables to update.'
    ) : invariant(typeof partialState === 'object' || partialState == null));
    if ("production" !== process.env.NODE_ENV){
      ("production" !== process.env.NODE_ENV ? warning(
        partialState != null,
        'setState(...): You passed an undefined or null state object; ' +
        'instead, use forceUpdate().'
      ) : null);
    }
    // Merge with `_pendingState` if it exists, otherwise with existing state.
    this.replaceState(
      assign({}, this._pendingState || this.state, partialState),
      callback
    );
  },

  /**
   * Replaces all of the state. Always use this or `setState` to mutate state.
   * You should treat `this.state` as immutable.
   *
   * There is no guarantee that `this.state` will be immediately updated, so
   * accessing `this.state` after calling this method may return the old value.
   *
   * @param {object} completeState Next state.
   * @param {?function} callback Called after state is updated.
   * @final
   * @protected
   */
  replaceState: function(completeState, callback) {
    validateLifeCycleOnReplaceState(this);
    this._pendingState = completeState;
    if (this._compositeLifeCycleState !== CompositeLifeCycle.MOUNTING) {
      // If we're in a componentWillMount handler, don't enqueue a rerender
      // because ReactUpdates assumes we're in a browser context (which is wrong
      // for server rendering) and we're about to do a render anyway.
      // TODO: The callback here is ignored when setState is called from
      // componentWillMount. Either fix it or disallow doing so completely in
      // favor of getInitialState.
      ReactUpdates.enqueueUpdate(this, callback);
    }
  },

  /**
   * Filters the context object to only contain keys specified in
   * `contextTypes`, and asserts that they are valid.
   *
   * @param {object} context
   * @return {?object}
   * @private
   */
  _processContext: function(context) {
    var maskedContext = null;
    var contextTypes = this.constructor.contextTypes;
    if (contextTypes) {
      maskedContext = {};
      for (var contextName in contextTypes) {
        maskedContext[contextName] = context[contextName];
      }
      if ("production" !== process.env.NODE_ENV) {
        this._checkPropTypes(
          contextTypes,
          maskedContext,
          ReactPropTypeLocations.context
        );
      }
    }
    return maskedContext;
  },

  /**
   * @param {object} currentContext
   * @return {object}
   * @private
   */
  _processChildContext: function(currentContext) {
    var childContext = this.getChildContext && this.getChildContext();
    var displayName = this.constructor.displayName || 'ReactCompositeComponent';
    if (childContext) {
      ("production" !== process.env.NODE_ENV ? invariant(
        typeof this.constructor.childContextTypes === 'object',
        '%s.getChildContext(): childContextTypes must be defined in order to ' +
        'use getChildContext().',
        displayName
      ) : invariant(typeof this.constructor.childContextTypes === 'object'));
      if ("production" !== process.env.NODE_ENV) {
        this._checkPropTypes(
          this.constructor.childContextTypes,
          childContext,
          ReactPropTypeLocations.childContext
        );
      }
      for (var name in childContext) {
        ("production" !== process.env.NODE_ENV ? invariant(
          name in this.constructor.childContextTypes,
          '%s.getChildContext(): key "%s" is not defined in childContextTypes.',
          displayName,
          name
        ) : invariant(name in this.constructor.childContextTypes));
      }
      return assign({}, currentContext, childContext);
    }
    return currentContext;
  },

  /**
   * Processes props by setting default values for unspecified props and
   * asserting that the props are valid. Does not mutate its argument; returns
   * a new props object with defaults merged in.
   *
   * @param {object} newProps
   * @return {object}
   * @private
   */
  _processProps: function(newProps) {
    if ("production" !== process.env.NODE_ENV) {
      var propTypes = this.constructor.propTypes;
      if (propTypes) {
        this._checkPropTypes(propTypes, newProps, ReactPropTypeLocations.prop);
      }
    }
    return newProps;
  },

  /**
   * Assert that the props are valid
   *
   * @param {object} propTypes Map of prop name to a ReactPropType
   * @param {object} props
   * @param {string} location e.g. "prop", "context", "child context"
   * @private
   */
  _checkPropTypes: function(propTypes, props, location) {
    // TODO: Stop validating prop types here and only use the element
    // validation.
    var componentName = this.constructor.displayName;
    for (var propName in propTypes) {
      if (propTypes.hasOwnProperty(propName)) {
        var error =
          propTypes[propName](props, propName, componentName, location);
        if (error instanceof Error) {
          // We may want to extend this logic for similar errors in
          // renderComponent calls, so I'm abstracting it away into
          // a function to minimize refactoring in the future
          var addendum = getDeclarationErrorAddendum(this);
          ("production" !== process.env.NODE_ENV ? warning(false, error.message + addendum) : null);
        }
      }
    }
  },

  /**
   * If any of `_pendingElement`, `_pendingState`, or `_pendingForceUpdate`
   * is set, update the component.
   *
   * @param {ReactReconcileTransaction} transaction
   * @internal
   */
  performUpdateIfNecessary: function(transaction) {
    var compositeLifeCycleState = this._compositeLifeCycleState;
    // Do not trigger a state transition if we are in the middle of mounting or
    // receiving props because both of those will already be doing this.
    if (compositeLifeCycleState === CompositeLifeCycle.MOUNTING ||
        compositeLifeCycleState === CompositeLifeCycle.RECEIVING_PROPS) {
      return;
    }

    if (this._pendingElement == null &&
        this._pendingState == null &&
        !this._pendingForceUpdate) {
      return;
    }

    var nextContext = this.context;
    var nextProps = this.props;
    var nextElement = this._currentElement;
    if (this._pendingElement != null) {
      nextElement = this._pendingElement;
      nextContext = this._processContext(nextElement._context);
      nextProps = this._processProps(nextElement.props);
      this._pendingElement = null;

      this._compositeLifeCycleState = CompositeLifeCycle.RECEIVING_PROPS;
      if (this.componentWillReceiveProps) {
        this.componentWillReceiveProps(nextProps, nextContext);
      }
    }

    this._compositeLifeCycleState = null;

    var nextState = this._pendingState || this.state;
    this._pendingState = null;

    var shouldUpdate =
      this._pendingForceUpdate ||
      !this.shouldComponentUpdate ||
      this.shouldComponentUpdate(nextProps, nextState, nextContext);

    if ("production" !== process.env.NODE_ENV) {
      if (typeof shouldUpdate === "undefined") {
        console.warn(
          (this.constructor.displayName || 'ReactCompositeComponent') +
          '.shouldComponentUpdate(): Returned undefined instead of a ' +
          'boolean value. Make sure to return true or false.'
        );
      }
    }

    if (shouldUpdate) {
      this._pendingForceUpdate = false;
      // Will set `this.props`, `this.state` and `this.context`.
      this._performComponentUpdate(
        nextElement,
        nextProps,
        nextState,
        nextContext,
        transaction
      );
    } else {
      // If it's determined that a component should not update, we still want
      // to set props and state.
      this._currentElement = nextElement;
      this.props = nextProps;
      this.state = nextState;
      this.context = nextContext;

      // Owner cannot change because shouldUpdateReactComponent doesn't allow
      // it. TODO: Remove this._owner completely.
      this._owner = nextElement._owner;
    }
  },

  /**
   * Merges new props and state, notifies delegate methods of update and
   * performs update.
   *
   * @param {ReactElement} nextElement Next element
   * @param {object} nextProps Next public object to set as properties.
   * @param {?object} nextState Next object to set as state.
   * @param {?object} nextContext Next public object to set as context.
   * @param {ReactReconcileTransaction} transaction
   * @private
   */
  _performComponentUpdate: function(
    nextElement,
    nextProps,
    nextState,
    nextContext,
    transaction
  ) {
    var prevElement = this._currentElement;
    var prevProps = this.props;
    var prevState = this.state;
    var prevContext = this.context;

    if (this.componentWillUpdate) {
      this.componentWillUpdate(nextProps, nextState, nextContext);
    }

    this._currentElement = nextElement;
    this.props = nextProps;
    this.state = nextState;
    this.context = nextContext;

    // Owner cannot change because shouldUpdateReactComponent doesn't allow
    // it. TODO: Remove this._owner completely.
    this._owner = nextElement._owner;

    this.updateComponent(
      transaction,
      prevElement
    );

    if (this.componentDidUpdate) {
      transaction.getReactMountReady().enqueue(
        this.componentDidUpdate.bind(this, prevProps, prevState, prevContext),
        this
      );
    }
  },

  receiveComponent: function(nextElement, transaction) {
    if (nextElement === this._currentElement &&
        nextElement._owner != null) {
      // Since elements are immutable after the owner is rendered,
      // we can do a cheap identity compare here to determine if this is a
      // superfluous reconcile. It's possible for state to be mutable but such
      // change should trigger an update of the owner which would recreate
      // the element. We explicitly check for the existence of an owner since
      // it's possible for a element created outside a composite to be
      // deeply mutated and reused.
      return;
    }

    ReactComponent.Mixin.receiveComponent.call(
      this,
      nextElement,
      transaction
    );
  },

  /**
   * Updates the component's currently mounted DOM representation.
   *
   * By default, this implements React's rendering and reconciliation algorithm.
   * Sophisticated clients may wish to override this.
   *
   * @param {ReactReconcileTransaction} transaction
   * @param {ReactElement} prevElement
   * @internal
   * @overridable
   */
  updateComponent: ReactPerf.measure(
    'ReactCompositeComponent',
    'updateComponent',
    function(transaction, prevParentElement) {
      ReactComponent.Mixin.updateComponent.call(
        this,
        transaction,
        prevParentElement
      );

      var prevComponentInstance = this._renderedComponent;
      var prevElement = prevComponentInstance._currentElement;
      var nextElement = this._renderValidatedComponent();
      if (shouldUpdateReactComponent(prevElement, nextElement)) {
        prevComponentInstance.receiveComponent(nextElement, transaction);
      } else {
        // These two IDs are actually the same! But nothing should rely on that.
        var thisID = this._rootNodeID;
        var prevComponentID = prevComponentInstance._rootNodeID;
        prevComponentInstance.unmountComponent();
        this._renderedComponent = instantiateReactComponent(
          nextElement,
          this._currentElement.type
        );
        var nextMarkup = this._renderedComponent.mountComponent(
          thisID,
          transaction,
          this._mountDepth + 1
        );
        ReactComponent.BackendIDOperations.dangerouslyReplaceNodeWithMarkupByID(
          prevComponentID,
          nextMarkup
        );
      }
    }
  ),

  /**
   * Forces an update. This should only be invoked when it is known with
   * certainty that we are **not** in a DOM transaction.
   *
   * You may want to call this when you know that some deeper aspect of the
   * component's state has changed but `setState` was not called.
   *
   * This will not invoke `shouldUpdateComponent`, but it will invoke
   * `componentWillUpdate` and `componentDidUpdate`.
   *
   * @param {?function} callback Called after update is complete.
   * @final
   * @protected
   */
  forceUpdate: function(callback) {
    var compositeLifeCycleState = this._compositeLifeCycleState;
    ("production" !== process.env.NODE_ENV ? invariant(
      this.isMounted() ||
        compositeLifeCycleState === CompositeLifeCycle.MOUNTING,
      'forceUpdate(...): Can only force an update on mounted or mounting ' +
        'components.'
    ) : invariant(this.isMounted() ||
      compositeLifeCycleState === CompositeLifeCycle.MOUNTING));
    ("production" !== process.env.NODE_ENV ? invariant(
      compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING &&
      ReactCurrentOwner.current == null,
      'forceUpdate(...): Cannot force an update while unmounting component ' +
      'or within a `render` function.'
    ) : invariant(compositeLifeCycleState !== CompositeLifeCycle.UNMOUNTING &&
    ReactCurrentOwner.current == null));
    this._pendingForceUpdate = true;
    ReactUpdates.enqueueUpdate(this, callback);
  },

  /**
   * @private
   */
  _renderValidatedComponent: ReactPerf.measure(
    'ReactCompositeComponent',
    '_renderValidatedComponent',
    function() {
      var renderedComponent;
      var previousContext = ReactContext.current;
      ReactContext.current = this._processChildContext(
        this._currentElement._context
      );
      ReactCurrentOwner.current = this;
      try {
        renderedComponent = this.render();
        if (renderedComponent === null || renderedComponent === false) {
          renderedComponent = ReactEmptyComponent.getEmptyComponent();
          ReactEmptyComponent.registerNullComponentID(this._rootNodeID);
        } else {
          ReactEmptyComponent.deregisterNullComponentID(this._rootNodeID);
        }
      } finally {
        ReactContext.current = previousContext;
        ReactCurrentOwner.current = null;
      }
      ("production" !== process.env.NODE_ENV ? invariant(
        ReactElement.isValidElement(renderedComponent),
        '%s.render(): A valid ReactComponent must be returned. You may have ' +
          'returned undefined, an array or some other invalid object.',
        this.constructor.displayName || 'ReactCompositeComponent'
      ) : invariant(ReactElement.isValidElement(renderedComponent)));
      return renderedComponent;
    }
  ),

  /**
   * @private
   */
  _bindAutoBindMethods: function() {
    for (var autoBindKey in this.__reactAutoBindMap) {
      if (!this.__reactAutoBindMap.hasOwnProperty(autoBindKey)) {
        continue;
      }
      var method = this.__reactAutoBindMap[autoBindKey];
      this[autoBindKey] = this._bindAutoBindMethod(ReactErrorUtils.guard(
        method,
        this.constructor.displayName + '.' + autoBindKey
      ));
    }
  },

  /**
   * Binds a method to the component.
   *
   * @param {function} method Method to be bound.
   * @private
   */
  _bindAutoBindMethod: function(method) {
    var component = this;
    var boundMethod = method.bind(component);
    if ("production" !== process.env.NODE_ENV) {
      boundMethod.__reactBoundContext = component;
      boundMethod.__reactBoundMethod = method;
      boundMethod.__reactBoundArguments = null;
      var componentName = component.constructor.displayName;
      var _bind = boundMethod.bind;
      boundMethod.bind = function(newThis ) {for (var args=[],$__0=1,$__1=arguments.length;$__0<$__1;$__0++) args.push(arguments[$__0]);
        // User is trying to bind() an autobound method; we effectively will
        // ignore the value of "this" that the user is trying to use, so
        // let's warn.
        if (newThis !== component && newThis !== null) {
          monitorCodeUse('react_bind_warning', { component: componentName });
          console.warn(
            'bind(): React component methods may only be bound to the ' +
            'component instance. See ' + componentName
          );
        } else if (!args.length) {
          monitorCodeUse('react_bind_warning', { component: componentName });
          console.warn(
            'bind(): You are binding a component method to the component. ' +
            'React does this for you automatically in a high-performance ' +
            'way, so you can safely remove this call. See ' + componentName
          );
          return boundMethod;
        }
        var reboundMethod = _bind.apply(boundMethod, arguments);
        reboundMethod.__reactBoundContext = component;
        reboundMethod.__reactBoundMethod = method;
        reboundMethod.__reactBoundArguments = args;
        return reboundMethod;
      };
    }
    return boundMethod;
  }
};

var ReactCompositeComponentBase = function() {};
assign(
  ReactCompositeComponentBase.prototype,
  ReactComponent.Mixin,
  ReactOwner.Mixin,
  ReactPropTransferer.Mixin,
  ReactCompositeComponentMixin
);

/**
 * Module for creating composite components.
 *
 * @class ReactCompositeComponent
 * @extends ReactComponent
 * @extends ReactOwner
 * @extends ReactPropTransferer
 */
var ReactCompositeComponent = {

  LifeCycle: CompositeLifeCycle,

  Base: ReactCompositeComponentBase,

  /**
   * Creates a composite component class given a class specification.
   *
   * @param {object} spec Class specification (which must define `render`).
   * @return {function} Component constructor function.
   * @public
   */
  createClass: function(spec) {
    var Constructor = function(props) {
      // This constructor is overridden by mocks. The argument is used
      // by mocks to assert on what gets mounted. This will later be used
      // by the stand-alone class implementation.
    };
    Constructor.prototype = new ReactCompositeComponentBase();
    Constructor.prototype.constructor = Constructor;

    injectedMixins.forEach(
      mixSpecIntoComponent.bind(null, Constructor)
    );

    mixSpecIntoComponent(Constructor, spec);

    // Initialize the defaultProps property after all mixins have been merged
    if (Constructor.getDefaultProps) {
      Constructor.defaultProps = Constructor.getDefaultProps();
    }

    ("production" !== process.env.NODE_ENV ? invariant(
      Constructor.prototype.render,
      'createClass(...): Class specification must implement a `render` method.'
    ) : invariant(Constructor.prototype.render));

    if ("production" !== process.env.NODE_ENV) {
      if (Constructor.prototype.componentShouldUpdate) {
        monitorCodeUse(
          'react_component_should_update_warning',
          { component: spec.displayName }
        );
        console.warn(
          (spec.displayName || 'A component') + ' has a method called ' +
          'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' +
          'The name is phrased as a question because the function is ' +
          'expected to return a value.'
         );
      }
    }

    // Reduce time spent doing lookups by setting these on the prototype.
    for (var methodName in ReactCompositeComponentInterface) {
      if (!Constructor.prototype[methodName]) {
        Constructor.prototype[methodName] = null;
      }
    }

    if ("production" !== process.env.NODE_ENV) {
      return ReactLegacyElement.wrapFactory(
        ReactElementValidator.createFactory(Constructor)
      );
    }
    return ReactLegacyElement.wrapFactory(
      ReactElement.createFactory(Constructor)
    );
  },

  injection: {
    injectMixin: function(mixin) {
      injectedMixins.push(mixin);
    }
  }
};

module.exports = ReactCompositeComponent;

}).call(this,require('_process'))
},{"./Object.assign":"/Users/zordius/webtasks/node_modules/react/lib/Object.assign.js","./ReactComponent":"/Users/zordius/webtasks/node_modules/react/lib/ReactComponent.js","./ReactContext":"/Users/zordius/webtasks/node_modules/react/lib/ReactContext.js","./ReactCurrentOwner":"/Users/zordius/webtasks/node_modules/react/lib/ReactCurrentOwner.js","./ReactElement":"/Users/zordius/webtasks/node_modules/react/lib/ReactElement.js","./ReactElementValidator":"/Users/zordius/webtasks/node_modules/react/lib/ReactElementValidator.js","./ReactEmptyComponent":"/Users/zordius/webtasks/node_modules/react/lib/ReactEmptyComponent.js","./ReactErrorUtils":"/Users/zordius/webtasks/node_modules/react/lib/ReactErrorUtils.js","./ReactLegacyElement":"/Users/zordius/webtasks/node_modules/react/lib/ReactLegacyElement.js","./ReactOwner":"/Users/zordius/webtasks/node_modules/react/lib/ReactOwner.js","./ReactPerf":"/Users/zordius/webtasks/node_modules/react/lib/ReactPerf.js","./ReactPropTransferer":"/Users/zordius/webtasks/node_modules/react/lib/ReactPropTransferer.js","./ReactPropTypeLocationNames":"/Users/zordius/webtasks/node_modules/react/lib/ReactPropTypeLocationNames.js","./ReactPropTypeLocations":"/Users/zordius/webtasks/node_modules/react/lib/ReactPropTypeLocations.js","./ReactUpdates":"/Users/zordius/webtasks/node_modules/react/lib/ReactUpdates.js","./instantiateReactComponent":"/Users/zordius/webtasks/node_modules/react/lib/instantiateReactComponent.js","./invariant":"/Users/zordius/webtasks/node_modules/react/lib/invariant.js","./keyMirror":"/Users/zordius/webtasks/node_modules/react/lib/keyMirror.js","./keyOf":"/Users/zordius/webtasks/node_modules/react/lib/keyOf.js","./mapObject":"/Users/zordius/webtasks/node_modules/react/lib/mapObject.js","./monitorCodeUse":"/Users/zordius/webtasks/node_modules/react/lib/monitorCodeUse.js","./shouldUpdateReactComponent":"/Users/zordius/webtasks/node_modules/react/lib/shouldUpdateReactComponent.js","./warning":"/Users/zordius/webtasks/node_modules/react/lib/warning.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactContext.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactContext
 */

"use strict";

var assign = require("./Object.assign");

/**
 * Keeps track of the current context.
 *
 * The context is automatically passed down the component ownership hierarchy
 * and is accessible via `this.context` on ReactCompositeComponents.
 */
var ReactContext = {

  /**
   * @internal
   * @type {object}
   */
  current: {},

  /**
   * Temporarily extends the current context while executing scopedCallback.
   *
   * A typical use case might look like
   *
   *  render: function() {
   *    var children = ReactContext.withContext({foo: 'foo'}, () => (
   *
   *    ));
   *    return <div>{children}</div>;
   *  }
   *
   * @param {object} newContext New context to merge into the existing context
   * @param {function} scopedCallback Callback to run with the new context
   * @return {ReactComponent|array<ReactComponent>}
   */
  withContext: function(newContext, scopedCallback) {
    var result;
    var previousContext = ReactContext.current;
    ReactContext.current = assign({}, previousContext, newContext);
    try {
      result = scopedCallback();
    } finally {
      ReactContext.current = previousContext;
    }
    return result;
  }

};

module.exports = ReactContext;

},{"./Object.assign":"/Users/zordius/webtasks/node_modules/react/lib/Object.assign.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactCurrentOwner.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactCurrentOwner
 */

"use strict";

/**
 * Keeps track of the current owner.
 *
 * The current owner is the component who should own any components that are
 * currently being constructed.
 *
 * The depth indicate how many composite components are above this render level.
 */
var ReactCurrentOwner = {

  /**
   * @internal
   * @type {ReactComponent}
   */
  current: null

};

module.exports = ReactCurrentOwner;

},{}],"/Users/zordius/webtasks/node_modules/react/lib/ReactDOM.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactDOM
 * @typechecks static-only
 */

"use strict";

var ReactElement = require("./ReactElement");
var ReactElementValidator = require("./ReactElementValidator");
var ReactLegacyElement = require("./ReactLegacyElement");

var mapObject = require("./mapObject");

/**
 * Create a factory that creates HTML tag elements.
 *
 * @param {string} tag Tag name (e.g. `div`).
 * @private
 */
function createDOMFactory(tag) {
  if ("production" !== process.env.NODE_ENV) {
    return ReactLegacyElement.markNonLegacyFactory(
      ReactElementValidator.createFactory(tag)
    );
  }
  return ReactLegacyElement.markNonLegacyFactory(
    ReactElement.createFactory(tag)
  );
}

/**
 * Creates a mapping from supported HTML tags to `ReactDOMComponent` classes.
 * This is also accessible via `React.DOM`.
 *
 * @public
 */
var ReactDOM = mapObject({
  a: 'a',
  abbr: 'abbr',
  address: 'address',
  area: 'area',
  article: 'article',
  aside: 'aside',
  audio: 'audio',
  b: 'b',
  base: 'base',
  bdi: 'bdi',
  bdo: 'bdo',
  big: 'big',
  blockquote: 'blockquote',
  body: 'body',
  br: 'br',
  button: 'button',
  canvas: 'canvas',
  caption: 'caption',
  cite: 'cite',
  code: 'code',
  col: 'col',
  colgroup: 'colgroup',
  data: 'data',
  datalist: 'datalist',
  dd: 'dd',
  del: 'del',
  details: 'details',
  dfn: 'dfn',
  dialog: 'dialog',
  div: 'div',
  dl: 'dl',
  dt: 'dt',
  em: 'em',
  embed: 'embed',
  fieldset: 'fieldset',
  figcaption: 'figcaption',
  figure: 'figure',
  footer: 'footer',
  form: 'form',
  h1: 'h1',
  h2: 'h2',
  h3: 'h3',
  h4: 'h4',
  h5: 'h5',
  h6: 'h6',
  head: 'head',
  header: 'header',
  hr: 'hr',
  html: 'html',
  i: 'i',
  iframe: 'iframe',
  img: 'img',
  input: 'input',
  ins: 'ins',
  kbd: 'kbd',
  keygen: 'keygen',
  label: 'label',
  legend: 'legend',
  li: 'li',
  link: 'link',
  main: 'main',
  map: 'map',
  mark: 'mark',
  menu: 'menu',
  menuitem: 'menuitem',
  meta: 'meta',
  meter: 'meter',
  nav: 'nav',
  noscript: 'noscript',
  object: 'object',
  ol: 'ol',
  optgroup: 'optgroup',
  option: 'option',
  output: 'output',
  p: 'p',
  param: 'param',
  picture: 'picture',
  pre: 'pre',
  progress: 'progress',
  q: 'q',
  rp: 'rp',
  rt: 'rt',
  ruby: 'ruby',
  s: 's',
  samp: 'samp',
  script: 'script',
  section: 'section',
  select: 'select',
  small: 'small',
  source: 'source',
  span: 'span',
  strong: 'strong',
  style: 'style',
  sub: 'sub',
  summary: 'summary',
  sup: 'sup',
  table: 'table',
  tbody: 'tbody',
  td: 'td',
  textarea: 'textarea',
  tfoot: 'tfoot',
  th: 'th',
  thead: 'thead',
  time: 'time',
  title: 'title',
  tr: 'tr',
  track: 'track',
  u: 'u',
  ul: 'ul',
  'var': 'var',
  video: 'video',
  wbr: 'wbr',

  // SVG
  circle: 'circle',
  defs: 'defs',
  ellipse: 'ellipse',
  g: 'g',
  line: 'line',
  linearGradient: 'linearGradient',
  mask: 'mask',
  path: 'path',
  pattern: 'pattern',
  polygon: 'polygon',
  polyline: 'polyline',
  radialGradient: 'radialGradient',
  rect: 'rect',
  stop: 'stop',
  svg: 'svg',
  text: 'text',
  tspan: 'tspan'

}, createDOMFactory);

module.exports = ReactDOM;

}).call(this,require('_process'))
},{"./ReactElement":"/Users/zordius/webtasks/node_modules/react/lib/ReactElement.js","./ReactElementValidator":"/Users/zordius/webtasks/node_modules/react/lib/ReactElementValidator.js","./ReactLegacyElement":"/Users/zordius/webtasks/node_modules/react/lib/ReactLegacyElement.js","./mapObject":"/Users/zordius/webtasks/node_modules/react/lib/mapObject.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactDOMButton.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactDOMButton
 */

"use strict";

var AutoFocusMixin = require("./AutoFocusMixin");
var ReactBrowserComponentMixin = require("./ReactBrowserComponentMixin");
var ReactCompositeComponent = require("./ReactCompositeComponent");
var ReactElement = require("./ReactElement");
var ReactDOM = require("./ReactDOM");

var keyMirror = require("./keyMirror");

// Store a reference to the <button> `ReactDOMComponent`. TODO: use string
var button = ReactElement.createFactory(ReactDOM.button.type);

var mouseListenerNames = keyMirror({
  onClick: true,
  onDoubleClick: true,
  onMouseDown: true,
  onMouseMove: true,
  onMouseUp: true,
  onClickCapture: true,
  onDoubleClickCapture: true,
  onMouseDownCapture: true,
  onMouseMoveCapture: true,
  onMouseUpCapture: true
});

/**
 * Implements a <button> native component that does not receive mouse events
 * when `disabled` is set.
 */
var ReactDOMButton = ReactCompositeComponent.createClass({
  displayName: 'ReactDOMButton',

  mixins: [AutoFocusMixin, ReactBrowserComponentMixin],

  render: function() {
    var props = {};

    // Copy the props; except the mouse listeners if we're disabled
    for (var key in this.props) {
      if (this.props.hasOwnProperty(key) &&
          (!this.props.disabled || !mouseListenerNames[key])) {
        props[key] = this.props[key];
      }
    }

    return button(props, this.props.children);
  }

});

module.exports = ReactDOMButton;

},{"./AutoFocusMixin":"/Users/zordius/webtasks/node_modules/react/lib/AutoFocusMixin.js","./ReactBrowserComponentMixin":"/Users/zordius/webtasks/node_modules/react/lib/ReactBrowserComponentMixin.js","./ReactCompositeComponent":"/Users/zordius/webtasks/node_modules/react/lib/ReactCompositeComponent.js","./ReactDOM":"/Users/zordius/webtasks/node_modules/react/lib/ReactDOM.js","./ReactElement":"/Users/zordius/webtasks/node_modules/react/lib/ReactElement.js","./keyMirror":"/Users/zordius/webtasks/node_modules/react/lib/keyMirror.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactDOMComponent.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactDOMComponent
 * @typechecks static-only
 */

"use strict";

var CSSPropertyOperations = require("./CSSPropertyOperations");
var DOMProperty = require("./DOMProperty");
var DOMPropertyOperations = require("./DOMPropertyOperations");
var ReactBrowserComponentMixin = require("./ReactBrowserComponentMixin");
var ReactComponent = require("./ReactComponent");
var ReactBrowserEventEmitter = require("./ReactBrowserEventEmitter");
var ReactMount = require("./ReactMount");
var ReactMultiChild = require("./ReactMultiChild");
var ReactPerf = require("./ReactPerf");

var assign = require("./Object.assign");
var escapeTextForBrowser = require("./escapeTextForBrowser");
var invariant = require("./invariant");
var isEventSupported = require("./isEventSupported");
var keyOf = require("./keyOf");
var monitorCodeUse = require("./monitorCodeUse");

var deleteListener = ReactBrowserEventEmitter.deleteListener;
var listenTo = ReactBrowserEventEmitter.listenTo;
var registrationNameModules = ReactBrowserEventEmitter.registrationNameModules;

// For quickly matching children type, to test if can be treated as content.
var CONTENT_TYPES = {'string': true, 'number': true};

var STYLE = keyOf({style: null});

var ELEMENT_NODE_TYPE = 1;

/**
 * @param {?object} props
 */
function assertValidProps(props) {
  if (!props) {
    return;
  }
  // Note the use of `==` which checks for null or undefined.
  ("production" !== process.env.NODE_ENV ? invariant(
    props.children == null || props.dangerouslySetInnerHTML == null,
    'Can only set one of `children` or `props.dangerouslySetInnerHTML`.'
  ) : invariant(props.children == null || props.dangerouslySetInnerHTML == null));
  if ("production" !== process.env.NODE_ENV) {
    if (props.contentEditable && props.children != null) {
      console.warn(
        'A component is `contentEditable` and contains `children` managed by ' +
        'React. It is now your responsibility to guarantee that none of those '+
        'nodes are unexpectedly modified or duplicated. This is probably not ' +
        'intentional.'
      );
    }
  }
  ("production" !== process.env.NODE_ENV ? invariant(
    props.style == null || typeof props.style === 'object',
    'The `style` prop expects a mapping from style properties to values, ' +
    'not a string.'
  ) : invariant(props.style == null || typeof props.style === 'object'));
}

function putListener(id, registrationName, listener, transaction) {
  if ("production" !== process.env.NODE_ENV) {
    // IE8 has no API for event capturing and the `onScroll` event doesn't
    // bubble.
    if (registrationName === 'onScroll' &&
        !isEventSupported('scroll', true)) {
      monitorCodeUse('react_no_scroll_event');
      console.warn('This browser doesn\'t support the `onScroll` event');
    }
  }
  var container = ReactMount.findReactContainerForID(id);
  if (container) {
    var doc = container.nodeType === ELEMENT_NODE_TYPE ?
      container.ownerDocument :
      container;
    listenTo(registrationName, doc);
  }
  transaction.getPutListenerQueue().enqueuePutListener(
    id,
    registrationName,
    listener
  );
}

// For HTML, certain tags should omit their close tag. We keep a whitelist for
// those special cased tags.

var omittedCloseTags = {
  'area': true,
  'base': true,
  'br': true,
  'col': true,
  'embed': true,
  'hr': true,
  'img': true,
  'input': true,
  'keygen': true,
  'link': true,
  'meta': true,
  'param': true,
  'source': true,
  'track': true,
  'wbr': true
  // NOTE: menuitem's close tag should be omitted, but that causes problems.
};

// We accept any tag to be rendered but since this gets injected into abitrary
// HTML, we want to make sure that it's a safe tag.
// http://www.w3.org/TR/REC-xml/#NT-Name

var VALID_TAG_REGEX = /^[a-zA-Z][a-zA-Z:_\.\-\d]*$/; // Simplified subset
var validatedTagCache = {};
var hasOwnProperty = {}.hasOwnProperty;

function validateDangerousTag(tag) {
  if (!hasOwnProperty.call(validatedTagCache, tag)) {
    ("production" !== process.env.NODE_ENV ? invariant(VALID_TAG_REGEX.test(tag), 'Invalid tag: %s', tag) : invariant(VALID_TAG_REGEX.test(tag)));
    validatedTagCache[tag] = true;
  }
}

/**
 * Creates a new React class that is idempotent and capable of containing other
 * React components. It accepts event listeners and DOM properties that are
 * valid according to `DOMProperty`.
 *
 *  - Event listeners: `onClick`, `onMouseDown`, etc.
 *  - DOM properties: `className`, `name`, `title`, etc.
 *
 * The `style` property functions differently from the DOM API. It accepts an
 * object mapping of style properties to values.
 *
 * @constructor ReactDOMComponent
 * @extends ReactComponent
 * @extends ReactMultiChild
 */
function ReactDOMComponent(tag) {
  validateDangerousTag(tag);
  this._tag = tag;
  this.tagName = tag.toUpperCase();
}

ReactDOMComponent.displayName = 'ReactDOMComponent';

ReactDOMComponent.Mixin = {

  /**
   * Generates root tag markup then recurses. This method has side effects and
   * is not idempotent.
   *
   * @internal
   * @param {string} rootID The root DOM ID for this node.
   * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
   * @param {number} mountDepth number of components in the owner hierarchy
   * @return {string} The computed markup.
   */
  mountComponent: ReactPerf.measure(
    'ReactDOMComponent',
    'mountComponent',
    function(rootID, transaction, mountDepth) {
      ReactComponent.Mixin.mountComponent.call(
        this,
        rootID,
        transaction,
        mountDepth
      );
      assertValidProps(this.props);
      var closeTag = omittedCloseTags[this._tag] ? '' : '</' + this._tag + '>';
      return (
        this._createOpenTagMarkupAndPutListeners(transaction) +
        this._createContentMarkup(transaction) +
        closeTag
      );
    }
  ),

  /**
   * Creates markup for the open tag and all attributes.
   *
   * This method has side effects because events get registered.
   *
   * Iterating over object properties is faster than iterating over arrays.
   * @see http://jsperf.com/obj-vs-arr-iteration
   *
   * @private
   * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
   * @return {string} Markup of opening tag.
   */
  _createOpenTagMarkupAndPutListeners: function(transaction) {
    var props = this.props;
    var ret = '<' + this._tag;

    for (var propKey in props) {
      if (!props.hasOwnProperty(propKey)) {
        continue;
      }
      var propValue = props[propKey];
      if (propValue == null) {
        continue;
      }
      if (registrationNameModules.hasOwnProperty(propKey)) {
        putListener(this._rootNodeID, propKey, propValue, transaction);
      } else {
        if (propKey === STYLE) {
          if (propValue) {
            propValue = props.style = assign({}, props.style);
          }
          propValue = CSSPropertyOperations.createMarkupForStyles(propValue);
        }
        var markup =
          DOMPropertyOperations.createMarkupForProperty(propKey, propValue);
        if (markup) {
          ret += ' ' + markup;
        }
      }
    }

    // For static pages, no need to put React ID and checksum. Saves lots of
    // bytes.
    if (transaction.renderToStaticMarkup) {
      return ret + '>';
    }

    var markupForID = DOMPropertyOperations.createMarkupForID(this._rootNodeID);
    return ret + ' ' + markupForID + '>';
  },

  /**
   * Creates markup for the content between the tags.
   *
   * @private
   * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
   * @return {string} Content markup.
   */
  _createContentMarkup: function(transaction) {
    // Intentional use of != to avoid catching zero/false.
    var innerHTML = this.props.dangerouslySetInnerHTML;
    if (innerHTML != null) {
      if (innerHTML.__html != null) {
        return innerHTML.__html;
      }
    } else {
      var contentToUse =
        CONTENT_TYPES[typeof this.props.children] ? this.props.children : null;
      var childrenToUse = contentToUse != null ? null : this.props.children;
      if (contentToUse != null) {
        return escapeTextForBrowser(contentToUse);
      } else if (childrenToUse != null) {
        var mountImages = this.mountChildren(
          childrenToUse,
          transaction
        );
        return mountImages.join('');
      }
    }
    return '';
  },

  receiveComponent: function(nextElement, transaction) {
    if (nextElement === this._currentElement &&
        nextElement._owner != null) {
      // Since elements are immutable after the owner is rendered,
      // we can do a cheap identity compare here to determine if this is a
      // superfluous reconcile. It's possible for state to be mutable but such
      // change should trigger an update of the owner which would recreate
      // the element. We explicitly check for the existence of an owner since
      // it's possible for a element created outside a composite to be
      // deeply mutated and reused.
      return;
    }

    ReactComponent.Mixin.receiveComponent.call(
      this,
      nextElement,
      transaction
    );
  },

  /**
   * Updates a native DOM component after it has already been allocated and
   * attached to the DOM. Reconciles the root DOM node, then recurses.
   *
   * @param {ReactReconcileTransaction} transaction
   * @param {ReactElement} prevElement
   * @internal
   * @overridable
   */
  updateComponent: ReactPerf.measure(
    'ReactDOMComponent',
    'updateComponent',
    function(transaction, prevElement) {
      assertValidProps(this._currentElement.props);
      ReactComponent.Mixin.updateComponent.call(
        this,
        transaction,
        prevElement
      );
      this._updateDOMProperties(prevElement.props, transaction);
      this._updateDOMChildren(prevElement.props, transaction);
    }
  ),

  /**
   * Reconciles the properties by detecting differences in property values and
   * updating the DOM as necessary. This function is probably the single most
   * critical path for performance optimization.
   *
   * TODO: Benchmark whether checking for changed values in memory actually
   *       improves performance (especially statically positioned elements).
   * TODO: Benchmark the effects of putting this at the top since 99% of props
   *       do not change for a given reconciliation.
   * TODO: Benchmark areas that can be improved with caching.
   *
   * @private
   * @param {object} lastProps
   * @param {ReactReconcileTransaction} transaction
   */
  _updateDOMProperties: function(lastProps, transaction) {
    var nextProps = this.props;
    var propKey;
    var styleName;
    var styleUpdates;
    for (propKey in lastProps) {
      if (nextProps.hasOwnProperty(propKey) ||
         !lastProps.hasOwnProperty(propKey)) {
        continue;
      }
      if (propKey === STYLE) {
        var lastStyle = lastProps[propKey];
        for (styleName in lastStyle) {
          if (lastStyle.hasOwnProperty(styleName)) {
            styleUpdates = styleUpdates || {};
            styleUpdates[styleName] = '';
          }
        }
      } else if (registrationNameModules.hasOwnProperty(propKey)) {
        deleteListener(this._rootNodeID, propKey);
      } else if (
          DOMProperty.isStandardName[propKey] ||
          DOMProperty.isCustomAttribute(propKey)) {
        ReactComponent.BackendIDOperations.deletePropertyByID(
          this._rootNodeID,
          propKey
        );
      }
    }
    for (propKey in nextProps) {
      var nextProp = nextProps[propKey];
      var lastProp = lastProps[propKey];
      if (!nextProps.hasOwnProperty(propKey) || nextProp === lastProp) {
        continue;
      }
      if (propKey === STYLE) {
        if (nextProp) {
          nextProp = nextProps.style = assign({}, nextProp);
        }
        if (lastProp) {
          // Unset styles on `lastProp` but not on `nextProp`.
          for (styleName in lastProp) {
            if (lastProp.hasOwnProperty(styleName) &&
                (!nextProp || !nextProp.hasOwnProperty(styleName))) {
              styleUpdates = styleUpdates || {};
              styleUpdates[styleName] = '';
            }
          }
          // Update styles that changed since `lastProp`.
          for (styleName in nextProp) {
            if (nextProp.hasOwnProperty(styleName) &&
                lastProp[styleName] !== nextProp[styleName]) {
              styleUpdates = styleUpdates || {};
              styleUpdates[styleName] = nextProp[styleName];
            }
          }
        } else {
          // Relies on `updateStylesByID` not mutating `styleUpdates`.
          styleUpdates = nextProp;
        }
      } else if (registrationNameModules.hasOwnProperty(propKey)) {
        putListener(this._rootNodeID, propKey, nextProp, transaction);
      } else if (
          DOMProperty.isStandardName[propKey] ||
          DOMProperty.isCustomAttribute(propKey)) {
        ReactComponent.BackendIDOperations.updatePropertyByID(
          this._rootNodeID,
          propKey,
          nextProp
        );
      }
    }
    if (styleUpdates) {
      ReactComponent.BackendIDOperations.updateStylesByID(
        this._rootNodeID,
        styleUpdates
      );
    }
  },

  /**
   * Reconciles the children with the various properties that affect the
   * children content.
   *
   * @param {object} lastProps
   * @param {ReactReconcileTransaction} transaction
   */
  _updateDOMChildren: function(lastProps, transaction) {
    var nextProps = this.props;

    var lastContent =
      CONTENT_TYPES[typeof lastProps.children] ? lastProps.children : null;
    var nextContent =
      CONTENT_TYPES[typeof nextProps.children] ? nextProps.children : null;

    var lastHtml =
      lastProps.dangerouslySetInnerHTML &&
      lastProps.dangerouslySetInnerHTML.__html;
    var nextHtml =
      nextProps.dangerouslySetInnerHTML &&
      nextProps.dangerouslySetInnerHTML.__html;

    // Note the use of `!=` which checks for null or undefined.
    var lastChildren = lastContent != null ? null : lastProps.children;
    var nextChildren = nextContent != null ? null : nextProps.children;

    // If we're switching from children to content/html or vice versa, remove
    // the old content
    var lastHasContentOrHtml = lastContent != null || lastHtml != null;
    var nextHasContentOrHtml = nextContent != null || nextHtml != null;
    if (lastChildren != null && nextChildren == null) {
      this.updateChildren(null, transaction);
    } else if (lastHasContentOrHtml && !nextHasContentOrHtml) {
      this.updateTextContent('');
    }

    if (nextContent != null) {
      if (lastContent !== nextContent) {
        this.updateTextContent('' + nextContent);
      }
    } else if (nextHtml != null) {
      if (lastHtml !== nextHtml) {
        ReactComponent.BackendIDOperations.updateInnerHTMLByID(
          this._rootNodeID,
          nextHtml
        );
      }
    } else if (nextChildren != null) {
      this.updateChildren(nextChildren, transaction);
    }
  },

  /**
   * Destroys all event registrations for this instance. Does not remove from
   * the DOM. That must be done by the parent.
   *
   * @internal
   */
  unmountComponent: function() {
    this.unmountChildren();
    ReactBrowserEventEmitter.deleteAllListeners(this._rootNodeID);
    ReactComponent.Mixin.unmountComponent.call(this);
  }

};

assign(
  ReactDOMComponent.prototype,
  ReactComponent.Mixin,
  ReactDOMComponent.Mixin,
  ReactMultiChild.Mixin,
  ReactBrowserComponentMixin
);

module.exports = ReactDOMComponent;

}).call(this,require('_process'))
},{"./CSSPropertyOperations":"/Users/zordius/webtasks/node_modules/react/lib/CSSPropertyOperations.js","./DOMProperty":"/Users/zordius/webtasks/node_modules/react/lib/DOMProperty.js","./DOMPropertyOperations":"/Users/zordius/webtasks/node_modules/react/lib/DOMPropertyOperations.js","./Object.assign":"/Users/zordius/webtasks/node_modules/react/lib/Object.assign.js","./ReactBrowserComponentMixin":"/Users/zordius/webtasks/node_modules/react/lib/ReactBrowserComponentMixin.js","./ReactBrowserEventEmitter":"/Users/zordius/webtasks/node_modules/react/lib/ReactBrowserEventEmitter.js","./ReactComponent":"/Users/zordius/webtasks/node_modules/react/lib/ReactComponent.js","./ReactMount":"/Users/zordius/webtasks/node_modules/react/lib/ReactMount.js","./ReactMultiChild":"/Users/zordius/webtasks/node_modules/react/lib/ReactMultiChild.js","./ReactPerf":"/Users/zordius/webtasks/node_modules/react/lib/ReactPerf.js","./escapeTextForBrowser":"/Users/zordius/webtasks/node_modules/react/lib/escapeTextForBrowser.js","./invariant":"/Users/zordius/webtasks/node_modules/react/lib/invariant.js","./isEventSupported":"/Users/zordius/webtasks/node_modules/react/lib/isEventSupported.js","./keyOf":"/Users/zordius/webtasks/node_modules/react/lib/keyOf.js","./monitorCodeUse":"/Users/zordius/webtasks/node_modules/react/lib/monitorCodeUse.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactDOMForm.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactDOMForm
 */

"use strict";

var EventConstants = require("./EventConstants");
var LocalEventTrapMixin = require("./LocalEventTrapMixin");
var ReactBrowserComponentMixin = require("./ReactBrowserComponentMixin");
var ReactCompositeComponent = require("./ReactCompositeComponent");
var ReactElement = require("./ReactElement");
var ReactDOM = require("./ReactDOM");

// Store a reference to the <form> `ReactDOMComponent`. TODO: use string
var form = ReactElement.createFactory(ReactDOM.form.type);

/**
 * Since onSubmit doesn't bubble OR capture on the top level in IE8, we need
 * to capture it on the <form> element itself. There are lots of hacks we could
 * do to accomplish this, but the most reliable is to make <form> a
 * composite component and use `componentDidMount` to attach the event handlers.
 */
var ReactDOMForm = ReactCompositeComponent.createClass({
  displayName: 'ReactDOMForm',

  mixins: [ReactBrowserComponentMixin, LocalEventTrapMixin],

  render: function() {
    // TODO: Instead of using `ReactDOM` directly, we should use JSX. However,
    // `jshint` fails to parse JSX so in order for linting to work in the open
    // source repo, we need to just use `ReactDOM.form`.
    return form(this.props);
  },

  componentDidMount: function() {
    this.trapBubbledEvent(EventConstants.topLevelTypes.topReset, 'reset');
    this.trapBubbledEvent(EventConstants.topLevelTypes.topSubmit, 'submit');
  }
});

module.exports = ReactDOMForm;

},{"./EventConstants":"/Users/zordius/webtasks/node_modules/react/lib/EventConstants.js","./LocalEventTrapMixin":"/Users/zordius/webtasks/node_modules/react/lib/LocalEventTrapMixin.js","./ReactBrowserComponentMixin":"/Users/zordius/webtasks/node_modules/react/lib/ReactBrowserComponentMixin.js","./ReactCompositeComponent":"/Users/zordius/webtasks/node_modules/react/lib/ReactCompositeComponent.js","./ReactDOM":"/Users/zordius/webtasks/node_modules/react/lib/ReactDOM.js","./ReactElement":"/Users/zordius/webtasks/node_modules/react/lib/ReactElement.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactDOMIDOperations.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactDOMIDOperations
 * @typechecks static-only
 */

/*jslint evil: true */

"use strict";

var CSSPropertyOperations = require("./CSSPropertyOperations");
var DOMChildrenOperations = require("./DOMChildrenOperations");
var DOMPropertyOperations = require("./DOMPropertyOperations");
var ReactMount = require("./ReactMount");
var ReactPerf = require("./ReactPerf");

var invariant = require("./invariant");
var setInnerHTML = require("./setInnerHTML");

/**
 * Errors for properties that should not be updated with `updatePropertyById()`.
 *
 * @type {object}
 * @private
 */
var INVALID_PROPERTY_ERRORS = {
  dangerouslySetInnerHTML:
    '`dangerouslySetInnerHTML` must be set using `updateInnerHTMLByID()`.',
  style: '`style` must be set using `updateStylesByID()`.'
};

/**
 * Operations used to process updates to DOM nodes. This is made injectable via
 * `ReactComponent.BackendIDOperations`.
 */
var ReactDOMIDOperations = {

  /**
   * Updates a DOM node with new property values. This should only be used to
   * update DOM properties in `DOMProperty`.
   *
   * @param {string} id ID of the node to update.
   * @param {string} name A valid property name, see `DOMProperty`.
   * @param {*} value New value of the property.
   * @internal
   */
  updatePropertyByID: ReactPerf.measure(
    'ReactDOMIDOperations',
    'updatePropertyByID',
    function(id, name, value) {
      var node = ReactMount.getNode(id);
      ("production" !== process.env.NODE_ENV ? invariant(
        !INVALID_PROPERTY_ERRORS.hasOwnProperty(name),
        'updatePropertyByID(...): %s',
        INVALID_PROPERTY_ERRORS[name]
      ) : invariant(!INVALID_PROPERTY_ERRORS.hasOwnProperty(name)));

      // If we're updating to null or undefined, we should remove the property
      // from the DOM node instead of inadvertantly setting to a string. This
      // brings us in line with the same behavior we have on initial render.
      if (value != null) {
        DOMPropertyOperations.setValueForProperty(node, name, value);
      } else {
        DOMPropertyOperations.deleteValueForProperty(node, name);
      }
    }
  ),

  /**
   * Updates a DOM node to remove a property. This should only be used to remove
   * DOM properties in `DOMProperty`.
   *
   * @param {string} id ID of the node to update.
   * @param {string} name A property name to remove, see `DOMProperty`.
   * @internal
   */
  deletePropertyByID: ReactPerf.measure(
    'ReactDOMIDOperations',
    'deletePropertyByID',
    function(id, name, value) {
      var node = ReactMount.getNode(id);
      ("production" !== process.env.NODE_ENV ? invariant(
        !INVALID_PROPERTY_ERRORS.hasOwnProperty(name),
        'updatePropertyByID(...): %s',
        INVALID_PROPERTY_ERRORS[name]
      ) : invariant(!INVALID_PROPERTY_ERRORS.hasOwnProperty(name)));
      DOMPropertyOperations.deleteValueForProperty(node, name, value);
    }
  ),

  /**
   * Updates a DOM node with new style values. If a value is specified as '',
   * the corresponding style property will be unset.
   *
   * @param {string} id ID of the node to update.
   * @param {object} styles Mapping from styles to values.
   * @internal
   */
  updateStylesByID: ReactPerf.measure(
    'ReactDOMIDOperations',
    'updateStylesByID',
    function(id, styles) {
      var node = ReactMount.getNode(id);
      CSSPropertyOperations.setValueForStyles(node, styles);
    }
  ),

  /**
   * Updates a DOM node's innerHTML.
   *
   * @param {string} id ID of the node to update.
   * @param {string} html An HTML string.
   * @internal
   */
  updateInnerHTMLByID: ReactPerf.measure(
    'ReactDOMIDOperations',
    'updateInnerHTMLByID',
    function(id, html) {
      var node = ReactMount.getNode(id);
      setInnerHTML(node, html);
    }
  ),

  /**
   * Updates a DOM node's text content set by `props.content`.
   *
   * @param {string} id ID of the node to update.
   * @param {string} content Text content.
   * @internal
   */
  updateTextContentByID: ReactPerf.measure(
    'ReactDOMIDOperations',
    'updateTextContentByID',
    function(id, content) {
      var node = ReactMount.getNode(id);
      DOMChildrenOperations.updateTextContent(node, content);
    }
  ),

  /**
   * Replaces a DOM node that exists in the document with markup.
   *
   * @param {string} id ID of child to be replaced.
   * @param {string} markup Dangerous markup to inject in place of child.
   * @internal
   * @see {Danger.dangerouslyReplaceNodeWithMarkup}
   */
  dangerouslyReplaceNodeWithMarkupByID: ReactPerf.measure(
    'ReactDOMIDOperations',
    'dangerouslyReplaceNodeWithMarkupByID',
    function(id, markup) {
      var node = ReactMount.getNode(id);
      DOMChildrenOperations.dangerouslyReplaceNodeWithMarkup(node, markup);
    }
  ),

  /**
   * Updates a component's children by processing a series of updates.
   *
   * @param {array<object>} updates List of update configurations.
   * @param {array<string>} markup List of markup strings.
   * @internal
   */
  dangerouslyProcessChildrenUpdates: ReactPerf.measure(
    'ReactDOMIDOperations',
    'dangerouslyProcessChildrenUpdates',
    function(updates, markup) {
      for (var i = 0; i < updates.length; i++) {
        updates[i].parentNode = ReactMount.getNode(updates[i].parentID);
      }
      DOMChildrenOperations.processUpdates(updates, markup);
    }
  )
};

module.exports = ReactDOMIDOperations;

}).call(this,require('_process'))
},{"./CSSPropertyOperations":"/Users/zordius/webtasks/node_modules/react/lib/CSSPropertyOperations.js","./DOMChildrenOperations":"/Users/zordius/webtasks/node_modules/react/lib/DOMChildrenOperations.js","./DOMPropertyOperations":"/Users/zordius/webtasks/node_modules/react/lib/DOMPropertyOperations.js","./ReactMount":"/Users/zordius/webtasks/node_modules/react/lib/ReactMount.js","./ReactPerf":"/Users/zordius/webtasks/node_modules/react/lib/ReactPerf.js","./invariant":"/Users/zordius/webtasks/node_modules/react/lib/invariant.js","./setInnerHTML":"/Users/zordius/webtasks/node_modules/react/lib/setInnerHTML.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactDOMImg.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactDOMImg
 */

"use strict";

var EventConstants = require("./EventConstants");
var LocalEventTrapMixin = require("./LocalEventTrapMixin");
var ReactBrowserComponentMixin = require("./ReactBrowserComponentMixin");
var ReactCompositeComponent = require("./ReactCompositeComponent");
var ReactElement = require("./ReactElement");
var ReactDOM = require("./ReactDOM");

// Store a reference to the <img> `ReactDOMComponent`. TODO: use string
var img = ReactElement.createFactory(ReactDOM.img.type);

/**
 * Since onLoad doesn't bubble OR capture on the top level in IE8, we need to
 * capture it on the <img> element itself. There are lots of hacks we could do
 * to accomplish this, but the most reliable is to make <img> a composite
 * component and use `componentDidMount` to attach the event handlers.
 */
var ReactDOMImg = ReactCompositeComponent.createClass({
  displayName: 'ReactDOMImg',
  tagName: 'IMG',

  mixins: [ReactBrowserComponentMixin, LocalEventTrapMixin],

  render: function() {
    return img(this.props);
  },

  componentDidMount: function() {
    this.trapBubbledEvent(EventConstants.topLevelTypes.topLoad, 'load');
    this.trapBubbledEvent(EventConstants.topLevelTypes.topError, 'error');
  }
});

module.exports = ReactDOMImg;

},{"./EventConstants":"/Users/zordius/webtasks/node_modules/react/lib/EventConstants.js","./LocalEventTrapMixin":"/Users/zordius/webtasks/node_modules/react/lib/LocalEventTrapMixin.js","./ReactBrowserComponentMixin":"/Users/zordius/webtasks/node_modules/react/lib/ReactBrowserComponentMixin.js","./ReactCompositeComponent":"/Users/zordius/webtasks/node_modules/react/lib/ReactCompositeComponent.js","./ReactDOM":"/Users/zordius/webtasks/node_modules/react/lib/ReactDOM.js","./ReactElement":"/Users/zordius/webtasks/node_modules/react/lib/ReactElement.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactDOMInput.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactDOMInput
 */

"use strict";

var AutoFocusMixin = require("./AutoFocusMixin");
var DOMPropertyOperations = require("./DOMPropertyOperations");
var LinkedValueUtils = require("./LinkedValueUtils");
var ReactBrowserComponentMixin = require("./ReactBrowserComponentMixin");
var ReactCompositeComponent = require("./ReactCompositeComponent");
var ReactElement = require("./ReactElement");
var ReactDOM = require("./ReactDOM");
var ReactMount = require("./ReactMount");
var ReactUpdates = require("./ReactUpdates");

var assign = require("./Object.assign");
var invariant = require("./invariant");

// Store a reference to the <input> `ReactDOMComponent`. TODO: use string
var input = ReactElement.createFactory(ReactDOM.input.type);

var instancesByReactID = {};

function forceUpdateIfMounted() {
  /*jshint validthis:true */
  if (this.isMounted()) {
    this.forceUpdate();
  }
}

/**
 * Implements an <input> native component that allows setting these optional
 * props: `checked`, `value`, `defaultChecked`, and `defaultValue`.
 *
 * If `checked` or `value` are not supplied (or null/undefined), user actions
 * that affect the checked state or value will trigger updates to the element.
 *
 * If they are supplied (and not null/undefined), the rendered element will not
 * trigger updates to the element. Instead, the props must change in order for
 * the rendered element to be updated.
 *
 * The rendered element will be initialized as unchecked (or `defaultChecked`)
 * with an empty value (or `defaultValue`).
 *
 * @see http://www.w3.org/TR/2012/WD-html5-20121025/the-input-element.html
 */
var ReactDOMInput = ReactCompositeComponent.createClass({
  displayName: 'ReactDOMInput',

  mixins: [AutoFocusMixin, LinkedValueUtils.Mixin, ReactBrowserComponentMixin],

  getInitialState: function() {
    var defaultValue = this.props.defaultValue;
    return {
      initialChecked: this.props.defaultChecked || false,
      initialValue: defaultValue != null ? defaultValue : null
    };
  },

  render: function() {
    // Clone `this.props` so we don't mutate the input.
    var props = assign({}, this.props);

    props.defaultChecked = null;
    props.defaultValue = null;

    var value = LinkedValueUtils.getValue(this);
    props.value = value != null ? value : this.state.initialValue;

    var checked = LinkedValueUtils.getChecked(this);
    props.checked = checked != null ? checked : this.state.initialChecked;

    props.onChange = this._handleChange;

    return input(props, this.props.children);
  },

  componentDidMount: function() {
    var id = ReactMount.getID(this.getDOMNode());
    instancesByReactID[id] = this;
  },

  componentWillUnmount: function() {
    var rootNode = this.getDOMNode();
    var id = ReactMount.getID(rootNode);
    delete instancesByReactID[id];
  },

  componentDidUpdate: function(prevProps, prevState, prevContext) {
    var rootNode = this.getDOMNode();
    if (this.props.checked != null) {
      DOMPropertyOperations.setValueForProperty(
        rootNode,
        'checked',
        this.props.checked || false
      );
    }

    var value = LinkedValueUtils.getValue(this);
    if (value != null) {
      // Cast `value` to a string to ensure the value is set correctly. While
      // browsers typically do this as necessary, jsdom doesn't.
      DOMPropertyOperations.setValueForProperty(rootNode, 'value', '' + value);
    }
  },

  _handleChange: function(event) {
    var returnValue;
    var onChange = LinkedValueUtils.getOnChange(this);
    if (onChange) {
      returnValue = onChange.call(this, event);
    }
    // Here we use asap to wait until all updates have propagated, which
    // is important when using controlled components within layers:
    // https://github.com/facebook/react/issues/1698
    ReactUpdates.asap(forceUpdateIfMounted, this);

    var name = this.props.name;
    if (this.props.type === 'radio' && name != null) {
      var rootNode = this.getDOMNode();
      var queryRoot = rootNode;

      while (queryRoot.parentNode) {
        queryRoot = queryRoot.parentNode;
      }

      // If `rootNode.form` was non-null, then we could try `form.elements`,
      // but that sometimes behaves strangely in IE8. We could also try using
      // `form.getElementsByName`, but that will only return direct children
      // and won't include inputs that use the HTML5 `form=` attribute. Since
      // the input might not even be in a form, let's just use the global
      // `querySelectorAll` to ensure we don't miss anything.
      var group = queryRoot.querySelectorAll(
        'input[name=' + JSON.stringify('' + name) + '][type="radio"]');

      for (var i = 0, groupLen = group.length; i < groupLen; i++) {
        var otherNode = group[i];
        if (otherNode === rootNode ||
            otherNode.form !== rootNode.form) {
          continue;
        }
        var otherID = ReactMount.getID(otherNode);
        ("production" !== process.env.NODE_ENV ? invariant(
          otherID,
          'ReactDOMInput: Mixing React and non-React radio inputs with the ' +
          'same `name` is not supported.'
        ) : invariant(otherID));
        var otherInstance = instancesByReactID[otherID];
        ("production" !== process.env.NODE_ENV ? invariant(
          otherInstance,
          'ReactDOMInput: Unknown radio button ID %s.',
          otherID
        ) : invariant(otherInstance));
        // If this is a controlled radio button group, forcing the input that
        // was previously checked to update will cause it to be come re-checked
        // as appropriate.
        ReactUpdates.asap(forceUpdateIfMounted, otherInstance);
      }
    }

    return returnValue;
  }

});

module.exports = ReactDOMInput;

}).call(this,require('_process'))
},{"./AutoFocusMixin":"/Users/zordius/webtasks/node_modules/react/lib/AutoFocusMixin.js","./DOMPropertyOperations":"/Users/zordius/webtasks/node_modules/react/lib/DOMPropertyOperations.js","./LinkedValueUtils":"/Users/zordius/webtasks/node_modules/react/lib/LinkedValueUtils.js","./Object.assign":"/Users/zordius/webtasks/node_modules/react/lib/Object.assign.js","./ReactBrowserComponentMixin":"/Users/zordius/webtasks/node_modules/react/lib/ReactBrowserComponentMixin.js","./ReactCompositeComponent":"/Users/zordius/webtasks/node_modules/react/lib/ReactCompositeComponent.js","./ReactDOM":"/Users/zordius/webtasks/node_modules/react/lib/ReactDOM.js","./ReactElement":"/Users/zordius/webtasks/node_modules/react/lib/ReactElement.js","./ReactMount":"/Users/zordius/webtasks/node_modules/react/lib/ReactMount.js","./ReactUpdates":"/Users/zordius/webtasks/node_modules/react/lib/ReactUpdates.js","./invariant":"/Users/zordius/webtasks/node_modules/react/lib/invariant.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactDOMOption.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactDOMOption
 */

"use strict";

var ReactBrowserComponentMixin = require("./ReactBrowserComponentMixin");
var ReactCompositeComponent = require("./ReactCompositeComponent");
var ReactElement = require("./ReactElement");
var ReactDOM = require("./ReactDOM");

var warning = require("./warning");

// Store a reference to the <option> `ReactDOMComponent`. TODO: use string
var option = ReactElement.createFactory(ReactDOM.option.type);

/**
 * Implements an <option> native component that warns when `selected` is set.
 */
var ReactDOMOption = ReactCompositeComponent.createClass({
  displayName: 'ReactDOMOption',

  mixins: [ReactBrowserComponentMixin],

  componentWillMount: function() {
    // TODO (yungsters): Remove support for `selected` in <option>.
    if ("production" !== process.env.NODE_ENV) {
      ("production" !== process.env.NODE_ENV ? warning(
        this.props.selected == null,
        'Use the `defaultValue` or `value` props on <select> instead of ' +
        'setting `selected` on <option>.'
      ) : null);
    }
  },

  render: function() {
    return option(this.props, this.props.children);
  }

});

module.exports = ReactDOMOption;

}).call(this,require('_process'))
},{"./ReactBrowserComponentMixin":"/Users/zordius/webtasks/node_modules/react/lib/ReactBrowserComponentMixin.js","./ReactCompositeComponent":"/Users/zordius/webtasks/node_modules/react/lib/ReactCompositeComponent.js","./ReactDOM":"/Users/zordius/webtasks/node_modules/react/lib/ReactDOM.js","./ReactElement":"/Users/zordius/webtasks/node_modules/react/lib/ReactElement.js","./warning":"/Users/zordius/webtasks/node_modules/react/lib/warning.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactDOMSelect.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactDOMSelect
 */

"use strict";

var AutoFocusMixin = require("./AutoFocusMixin");
var LinkedValueUtils = require("./LinkedValueUtils");
var ReactBrowserComponentMixin = require("./ReactBrowserComponentMixin");
var ReactCompositeComponent = require("./ReactCompositeComponent");
var ReactElement = require("./ReactElement");
var ReactDOM = require("./ReactDOM");
var ReactUpdates = require("./ReactUpdates");

var assign = require("./Object.assign");

// Store a reference to the <select> `ReactDOMComponent`. TODO: use string
var select = ReactElement.createFactory(ReactDOM.select.type);

function updateWithPendingValueIfMounted() {
  /*jshint validthis:true */
  if (this.isMounted()) {
    this.setState({value: this._pendingValue});
    this._pendingValue = 0;
  }
}

/**
 * Validation function for `value` and `defaultValue`.
 * @private
 */
function selectValueType(props, propName, componentName) {
  if (props[propName] == null) {
    return;
  }
  if (props.multiple) {
    if (!Array.isArray(props[propName])) {
      return new Error(
        ("The `" + propName + "` prop supplied to <select> must be an array if ") +
        ("`multiple` is true.")
      );
    }
  } else {
    if (Array.isArray(props[propName])) {
      return new Error(
        ("The `" + propName + "` prop supplied to <select> must be a scalar ") +
        ("value if `multiple` is false.")
      );
    }
  }
}

/**
 * If `value` is supplied, updates <option> elements on mount and update.
 * @param {ReactComponent} component Instance of ReactDOMSelect
 * @param {?*} propValue For uncontrolled components, null/undefined. For
 * controlled components, a string (or with `multiple`, a list of strings).
 * @private
 */
function updateOptions(component, propValue) {
  var multiple = component.props.multiple;
  var value = propValue != null ? propValue : component.state.value;
  var options = component.getDOMNode().options;
  var selectedValue, i, l;
  if (multiple) {
    selectedValue = {};
    for (i = 0, l = value.length; i < l; ++i) {
      selectedValue['' + value[i]] = true;
    }
  } else {
    selectedValue = '' + value;
  }
  for (i = 0, l = options.length; i < l; i++) {
    var selected = multiple ?
      selectedValue.hasOwnProperty(options[i].value) :
      options[i].value === selectedValue;

    if (selected !== options[i].selected) {
      options[i].selected = selected;
    }
  }
}

/**
 * Implements a <select> native component that allows optionally setting the
 * props `value` and `defaultValue`. If `multiple` is false, the prop must be a
 * string. If `multiple` is true, the prop must be an array of strings.
 *
 * If `value` is not supplied (or null/undefined), user actions that change the
 * selected option will trigger updates to the rendered options.
 *
 * If it is supplied (and not null/undefined), the rendered options will not
 * update in response to user actions. Instead, the `value` prop must change in
 * order for the rendered options to update.
 *
 * If `defaultValue` is provided, any options with the supplied values will be
 * selected.
 */
var ReactDOMSelect = ReactCompositeComponent.createClass({
  displayName: 'ReactDOMSelect',

  mixins: [AutoFocusMixin, LinkedValueUtils.Mixin, ReactBrowserComponentMixin],

  propTypes: {
    defaultValue: selectValueType,
    value: selectValueType
  },

  getInitialState: function() {
    return {value: this.props.defaultValue || (this.props.multiple ? [] : '')};
  },

  componentWillMount: function() {
    this._pendingValue = null;
  },

  componentWillReceiveProps: function(nextProps) {
    if (!this.props.multiple && nextProps.multiple) {
      this.setState({value: [this.state.value]});
    } else if (this.props.multiple && !nextProps.multiple) {
      this.setState({value: this.state.value[0]});
    }
  },

  render: function() {
    // Clone `this.props` so we don't mutate the input.
    var props = assign({}, this.props);

    props.onChange = this._handleChange;
    props.value = null;

    return select(props, this.props.children);
  },

  componentDidMount: function() {
    updateOptions(this, LinkedValueUtils.getValue(this));
  },

  componentDidUpdate: function(prevProps) {
    var value = LinkedValueUtils.getValue(this);
    var prevMultiple = !!prevProps.multiple;
    var multiple = !!this.props.multiple;
    if (value != null || prevMultiple !== multiple) {
      updateOptions(this, value);
    }
  },

  _handleChange: function(event) {
    var returnValue;
    var onChange = LinkedValueUtils.getOnChange(this);
    if (onChange) {
      returnValue = onChange.call(this, event);
    }

    var selectedValue;
    if (this.props.multiple) {
      selectedValue = [];
      var options = event.target.options;
      for (var i = 0, l = options.length; i < l; i++) {
        if (options[i].selected) {
          selectedValue.push(options[i].value);
        }
      }
    } else {
      selectedValue = event.target.value;
    }

    this._pendingValue = selectedValue;
    ReactUpdates.asap(updateWithPendingValueIfMounted, this);
    return returnValue;
  }

});

module.exports = ReactDOMSelect;

},{"./AutoFocusMixin":"/Users/zordius/webtasks/node_modules/react/lib/AutoFocusMixin.js","./LinkedValueUtils":"/Users/zordius/webtasks/node_modules/react/lib/LinkedValueUtils.js","./Object.assign":"/Users/zordius/webtasks/node_modules/react/lib/Object.assign.js","./ReactBrowserComponentMixin":"/Users/zordius/webtasks/node_modules/react/lib/ReactBrowserComponentMixin.js","./ReactCompositeComponent":"/Users/zordius/webtasks/node_modules/react/lib/ReactCompositeComponent.js","./ReactDOM":"/Users/zordius/webtasks/node_modules/react/lib/ReactDOM.js","./ReactElement":"/Users/zordius/webtasks/node_modules/react/lib/ReactElement.js","./ReactUpdates":"/Users/zordius/webtasks/node_modules/react/lib/ReactUpdates.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactDOMSelection.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactDOMSelection
 */

"use strict";

var ExecutionEnvironment = require("./ExecutionEnvironment");

var getNodeForCharacterOffset = require("./getNodeForCharacterOffset");
var getTextContentAccessor = require("./getTextContentAccessor");

/**
 * While `isCollapsed` is available on the Selection object and `collapsed`
 * is available on the Range object, IE11 sometimes gets them wrong.
 * If the anchor/focus nodes and offsets are the same, the range is collapsed.
 */
function isCollapsed(anchorNode, anchorOffset, focusNode, focusOffset) {
  return anchorNode === focusNode && anchorOffset === focusOffset;
}

/**
 * Get the appropriate anchor and focus node/offset pairs for IE.
 *
 * The catch here is that IE's selection API doesn't provide information
 * about whether the selection is forward or backward, so we have to
 * behave as though it's always forward.
 *
 * IE text differs from modern selection in that it behaves as though
 * block elements end with a new line. This means character offsets will
 * differ between the two APIs.
 *
 * @param {DOMElement} node
 * @return {object}
 */
function getIEOffsets(node) {
  var selection = document.selection;
  var selectedRange = selection.createRange();
  var selectedLength = selectedRange.text.length;

  // Duplicate selection so we can move range without breaking user selection.
  var fromStart = selectedRange.duplicate();
  fromStart.moveToElementText(node);
  fromStart.setEndPoint('EndToStart', selectedRange);

  var startOffset = fromStart.text.length;
  var endOffset = startOffset + selectedLength;

  return {
    start: startOffset,
    end: endOffset
  };
}

/**
 * @param {DOMElement} node
 * @return {?object}
 */
function getModernOffsets(node) {
  var selection = window.getSelection && window.getSelection();

  if (!selection || selection.rangeCount === 0) {
    return null;
  }

  var anchorNode = selection.anchorNode;
  var anchorOffset = selection.anchorOffset;
  var focusNode = selection.focusNode;
  var focusOffset = selection.focusOffset;

  var currentRange = selection.getRangeAt(0);

  // If the node and offset values are the same, the selection is collapsed.
  // `Selection.isCollapsed` is available natively, but IE sometimes gets
  // this value wrong.
  var isSelectionCollapsed = isCollapsed(
    selection.anchorNode,
    selection.anchorOffset,
    selection.focusNode,
    selection.focusOffset
  );

  var rangeLength = isSelectionCollapsed ? 0 : currentRange.toString().length;

  var tempRange = currentRange.cloneRange();
  tempRange.selectNodeContents(node);
  tempRange.setEnd(currentRange.startContainer, currentRange.startOffset);

  var isTempRangeCollapsed = isCollapsed(
    tempRange.startContainer,
    tempRange.startOffset,
    tempRange.endContainer,
    tempRange.endOffset
  );

  var start = isTempRangeCollapsed ? 0 : tempRange.toString().length;
  var end = start + rangeLength;

  // Detect whether the selection is backward.
  var detectionRange = document.createRange();
  detectionRange.setStart(anchorNode, anchorOffset);
  detectionRange.setEnd(focusNode, focusOffset);
  var isBackward = detectionRange.collapsed;

  return {
    start: isBackward ? end : start,
    end: isBackward ? start : end
  };
}

/**
 * @param {DOMElement|DOMTextNode} node
 * @param {object} offsets
 */
function setIEOffsets(node, offsets) {
  var range = document.selection.createRange().duplicate();
  var start, end;

  if (typeof offsets.end === 'undefined') {
    start = offsets.start;
    end = start;
  } else if (offsets.start > offsets.end) {
    start = offsets.end;
    end = offsets.start;
  } else {
    start = offsets.start;
    end = offsets.end;
  }

  range.moveToElementText(node);
  range.moveStart('character', start);
  range.setEndPoint('EndToStart', range);
  range.moveEnd('character', end - start);
  range.select();
}

/**
 * In modern non-IE browsers, we can support both forward and backward
 * selections.
 *
 * Note: IE10+ supports the Selection object, but it does not support
 * the `extend` method, which means that even in modern IE, it's not possible
 * to programatically create a backward selection. Thus, for all IE
 * versions, we use the old IE API to create our selections.
 *
 * @param {DOMElement|DOMTextNode} node
 * @param {object} offsets
 */
function setModernOffsets(node, offsets) {
  if (!window.getSelection) {
    return;
  }

  var selection = window.getSelection();
  var length = node[getTextContentAccessor()].length;
  var start = Math.min(offsets.start, length);
  var end = typeof offsets.end === 'undefined' ?
            start : Math.min(offsets.end, length);

  // IE 11 uses modern selection, but doesn't support the extend method.
  // Flip backward selections, so we can set with a single range.
  if (!selection.extend && start > end) {
    var temp = end;
    end = start;
    start = temp;
  }

  var startMarker = getNodeForCharacterOffset(node, start);
  var endMarker = getNodeForCharacterOffset(node, end);

  if (startMarker && endMarker) {
    var range = document.createRange();
    range.setStart(startMarker.node, startMarker.offset);
    selection.removeAllRanges();

    if (start > end) {
      selection.addRange(range);
      selection.extend(endMarker.node, endMarker.offset);
    } else {
      range.setEnd(endMarker.node, endMarker.offset);
      selection.addRange(range);
    }
  }
}

var useIEOffsets = ExecutionEnvironment.canUseDOM && document.selection;

var ReactDOMSelection = {
  /**
   * @param {DOMElement} node
   */
  getOffsets: useIEOffsets ? getIEOffsets : getModernOffsets,

  /**
   * @param {DOMElement|DOMTextNode} node
   * @param {object} offsets
   */
  setOffsets: useIEOffsets ? setIEOffsets : setModernOffsets
};

module.exports = ReactDOMSelection;

},{"./ExecutionEnvironment":"/Users/zordius/webtasks/node_modules/react/lib/ExecutionEnvironment.js","./getNodeForCharacterOffset":"/Users/zordius/webtasks/node_modules/react/lib/getNodeForCharacterOffset.js","./getTextContentAccessor":"/Users/zordius/webtasks/node_modules/react/lib/getTextContentAccessor.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactDOMTextarea.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactDOMTextarea
 */

"use strict";

var AutoFocusMixin = require("./AutoFocusMixin");
var DOMPropertyOperations = require("./DOMPropertyOperations");
var LinkedValueUtils = require("./LinkedValueUtils");
var ReactBrowserComponentMixin = require("./ReactBrowserComponentMixin");
var ReactCompositeComponent = require("./ReactCompositeComponent");
var ReactElement = require("./ReactElement");
var ReactDOM = require("./ReactDOM");
var ReactUpdates = require("./ReactUpdates");

var assign = require("./Object.assign");
var invariant = require("./invariant");

var warning = require("./warning");

// Store a reference to the <textarea> `ReactDOMComponent`. TODO: use string
var textarea = ReactElement.createFactory(ReactDOM.textarea.type);

function forceUpdateIfMounted() {
  /*jshint validthis:true */
  if (this.isMounted()) {
    this.forceUpdate();
  }
}

/**
 * Implements a <textarea> native component that allows setting `value`, and
 * `defaultValue`. This differs from the traditional DOM API because value is
 * usually set as PCDATA children.
 *
 * If `value` is not supplied (or null/undefined), user actions that affect the
 * value will trigger updates to the element.
 *
 * If `value` is supplied (and not null/undefined), the rendered element will
 * not trigger updates to the element. Instead, the `value` prop must change in
 * order for the rendered element to be updated.
 *
 * The rendered element will be initialized with an empty value, the prop
 * `defaultValue` if specified, or the children content (deprecated).
 */
var ReactDOMTextarea = ReactCompositeComponent.createClass({
  displayName: 'ReactDOMTextarea',

  mixins: [AutoFocusMixin, LinkedValueUtils.Mixin, ReactBrowserComponentMixin],

  getInitialState: function() {
    var defaultValue = this.props.defaultValue;
    // TODO (yungsters): Remove support for children content in <textarea>.
    var children = this.props.children;
    if (children != null) {
      if ("production" !== process.env.NODE_ENV) {
        ("production" !== process.env.NODE_ENV ? warning(
          false,
          'Use the `defaultValue` or `value` props instead of setting ' +
          'children on <textarea>.'
        ) : null);
      }
      ("production" !== process.env.NODE_ENV ? invariant(
        defaultValue == null,
        'If you supply `defaultValue` on a <textarea>, do not pass children.'
      ) : invariant(defaultValue == null));
      if (Array.isArray(children)) {
        ("production" !== process.env.NODE_ENV ? invariant(
          children.length <= 1,
          '<textarea> can only have at most one child.'
        ) : invariant(children.length <= 1));
        children = children[0];
      }

      defaultValue = '' + children;
    }
    if (defaultValue == null) {
      defaultValue = '';
    }
    var value = LinkedValueUtils.getValue(this);
    return {
      // We save the initial value so that `ReactDOMComponent` doesn't update
      // `textContent` (unnecessary since we update value).
      // The initial value can be a boolean or object so that's why it's
      // forced to be a string.
      initialValue: '' + (value != null ? value : defaultValue)
    };
  },

  render: function() {
    // Clone `this.props` so we don't mutate the input.
    var props = assign({}, this.props);

    ("production" !== process.env.NODE_ENV ? invariant(
      props.dangerouslySetInnerHTML == null,
      '`dangerouslySetInnerHTML` does not make sense on <textarea>.'
    ) : invariant(props.dangerouslySetInnerHTML == null));

    props.defaultValue = null;
    props.value = null;
    props.onChange = this._handleChange;

    // Always set children to the same thing. In IE9, the selection range will
    // get reset if `textContent` is mutated.
    return textarea(props, this.state.initialValue);
  },

  componentDidUpdate: function(prevProps, prevState, prevContext) {
    var value = LinkedValueUtils.getValue(this);
    if (value != null) {
      var rootNode = this.getDOMNode();
      // Cast `value` to a string to ensure the value is set correctly. While
      // browsers typically do this as necessary, jsdom doesn't.
      DOMPropertyOperations.setValueForProperty(rootNode, 'value', '' + value);
    }
  },

  _handleChange: function(event) {
    var returnValue;
    var onChange = LinkedValueUtils.getOnChange(this);
    if (onChange) {
      returnValue = onChange.call(this, event);
    }
    ReactUpdates.asap(forceUpdateIfMounted, this);
    return returnValue;
  }

});

module.exports = ReactDOMTextarea;

}).call(this,require('_process'))
},{"./AutoFocusMixin":"/Users/zordius/webtasks/node_modules/react/lib/AutoFocusMixin.js","./DOMPropertyOperations":"/Users/zordius/webtasks/node_modules/react/lib/DOMPropertyOperations.js","./LinkedValueUtils":"/Users/zordius/webtasks/node_modules/react/lib/LinkedValueUtils.js","./Object.assign":"/Users/zordius/webtasks/node_modules/react/lib/Object.assign.js","./ReactBrowserComponentMixin":"/Users/zordius/webtasks/node_modules/react/lib/ReactBrowserComponentMixin.js","./ReactCompositeComponent":"/Users/zordius/webtasks/node_modules/react/lib/ReactCompositeComponent.js","./ReactDOM":"/Users/zordius/webtasks/node_modules/react/lib/ReactDOM.js","./ReactElement":"/Users/zordius/webtasks/node_modules/react/lib/ReactElement.js","./ReactUpdates":"/Users/zordius/webtasks/node_modules/react/lib/ReactUpdates.js","./invariant":"/Users/zordius/webtasks/node_modules/react/lib/invariant.js","./warning":"/Users/zordius/webtasks/node_modules/react/lib/warning.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactDefaultBatchingStrategy.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactDefaultBatchingStrategy
 */

"use strict";

var ReactUpdates = require("./ReactUpdates");
var Transaction = require("./Transaction");

var assign = require("./Object.assign");
var emptyFunction = require("./emptyFunction");

var RESET_BATCHED_UPDATES = {
  initialize: emptyFunction,
  close: function() {
    ReactDefaultBatchingStrategy.isBatchingUpdates = false;
  }
};

var FLUSH_BATCHED_UPDATES = {
  initialize: emptyFunction,
  close: ReactUpdates.flushBatchedUpdates.bind(ReactUpdates)
};

var TRANSACTION_WRAPPERS = [FLUSH_BATCHED_UPDATES, RESET_BATCHED_UPDATES];

function ReactDefaultBatchingStrategyTransaction() {
  this.reinitializeTransaction();
}

assign(
  ReactDefaultBatchingStrategyTransaction.prototype,
  Transaction.Mixin,
  {
    getTransactionWrappers: function() {
      return TRANSACTION_WRAPPERS;
    }
  }
);

var transaction = new ReactDefaultBatchingStrategyTransaction();

var ReactDefaultBatchingStrategy = {
  isBatchingUpdates: false,

  /**
   * Call the provided function in a context within which calls to `setState`
   * and friends are batched such that components aren't updated unnecessarily.
   */
  batchedUpdates: function(callback, a, b) {
    var alreadyBatchingUpdates = ReactDefaultBatchingStrategy.isBatchingUpdates;

    ReactDefaultBatchingStrategy.isBatchingUpdates = true;

    // The code is written this way to avoid extra allocations
    if (alreadyBatchingUpdates) {
      callback(a, b);
    } else {
      transaction.perform(callback, null, a, b);
    }
  }
};

module.exports = ReactDefaultBatchingStrategy;

},{"./Object.assign":"/Users/zordius/webtasks/node_modules/react/lib/Object.assign.js","./ReactUpdates":"/Users/zordius/webtasks/node_modules/react/lib/ReactUpdates.js","./Transaction":"/Users/zordius/webtasks/node_modules/react/lib/Transaction.js","./emptyFunction":"/Users/zordius/webtasks/node_modules/react/lib/emptyFunction.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactDefaultInjection.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactDefaultInjection
 */

"use strict";

var BeforeInputEventPlugin = require("./BeforeInputEventPlugin");
var ChangeEventPlugin = require("./ChangeEventPlugin");
var ClientReactRootIndex = require("./ClientReactRootIndex");
var CompositionEventPlugin = require("./CompositionEventPlugin");
var DefaultEventPluginOrder = require("./DefaultEventPluginOrder");
var EnterLeaveEventPlugin = require("./EnterLeaveEventPlugin");
var ExecutionEnvironment = require("./ExecutionEnvironment");
var HTMLDOMPropertyConfig = require("./HTMLDOMPropertyConfig");
var MobileSafariClickEventPlugin = require("./MobileSafariClickEventPlugin");
var ReactBrowserComponentMixin = require("./ReactBrowserComponentMixin");
var ReactComponentBrowserEnvironment =
  require("./ReactComponentBrowserEnvironment");
var ReactDefaultBatchingStrategy = require("./ReactDefaultBatchingStrategy");
var ReactDOMComponent = require("./ReactDOMComponent");
var ReactDOMButton = require("./ReactDOMButton");
var ReactDOMForm = require("./ReactDOMForm");
var ReactDOMImg = require("./ReactDOMImg");
var ReactDOMInput = require("./ReactDOMInput");
var ReactDOMOption = require("./ReactDOMOption");
var ReactDOMSelect = require("./ReactDOMSelect");
var ReactDOMTextarea = require("./ReactDOMTextarea");
var ReactEventListener = require("./ReactEventListener");
var ReactInjection = require("./ReactInjection");
var ReactInstanceHandles = require("./ReactInstanceHandles");
var ReactMount = require("./ReactMount");
var SelectEventPlugin = require("./SelectEventPlugin");
var ServerReactRootIndex = require("./ServerReactRootIndex");
var SimpleEventPlugin = require("./SimpleEventPlugin");
var SVGDOMPropertyConfig = require("./SVGDOMPropertyConfig");

var createFullPageComponent = require("./createFullPageComponent");

function inject() {
  ReactInjection.EventEmitter.injectReactEventListener(
    ReactEventListener
  );

  /**
   * Inject modules for resolving DOM hierarchy and plugin ordering.
   */
  ReactInjection.EventPluginHub.injectEventPluginOrder(DefaultEventPluginOrder);
  ReactInjection.EventPluginHub.injectInstanceHandle(ReactInstanceHandles);
  ReactInjection.EventPluginHub.injectMount(ReactMount);

  /**
   * Some important event plugins included by default (without having to require
   * them).
   */
  ReactInjection.EventPluginHub.injectEventPluginsByName({
    SimpleEventPlugin: SimpleEventPlugin,
    EnterLeaveEventPlugin: EnterLeaveEventPlugin,
    ChangeEventPlugin: ChangeEventPlugin,
    CompositionEventPlugin: CompositionEventPlugin,
    MobileSafariClickEventPlugin: MobileSafariClickEventPlugin,
    SelectEventPlugin: SelectEventPlugin,
    BeforeInputEventPlugin: BeforeInputEventPlugin
  });

  ReactInjection.NativeComponent.injectGenericComponentClass(
    ReactDOMComponent
  );

  ReactInjection.NativeComponent.injectComponentClasses({
    'button': ReactDOMButton,
    'form': ReactDOMForm,
    'img': ReactDOMImg,
    'input': ReactDOMInput,
    'option': ReactDOMOption,
    'select': ReactDOMSelect,
    'textarea': ReactDOMTextarea,

    'html': createFullPageComponent('html'),
    'head': createFullPageComponent('head'),
    'body': createFullPageComponent('body')
  });

  // This needs to happen after createFullPageComponent() otherwise the mixin
  // gets double injected.
  ReactInjection.CompositeComponent.injectMixin(ReactBrowserComponentMixin);

  ReactInjection.DOMProperty.injectDOMPropertyConfig(HTMLDOMPropertyConfig);
  ReactInjection.DOMProperty.injectDOMPropertyConfig(SVGDOMPropertyConfig);

  ReactInjection.EmptyComponent.injectEmptyComponent('noscript');

  ReactInjection.Updates.injectReconcileTransaction(
    ReactComponentBrowserEnvironment.ReactReconcileTransaction
  );
  ReactInjection.Updates.injectBatchingStrategy(
    ReactDefaultBatchingStrategy
  );

  ReactInjection.RootIndex.injectCreateReactRootIndex(
    ExecutionEnvironment.canUseDOM ?
      ClientReactRootIndex.createReactRootIndex :
      ServerReactRootIndex.createReactRootIndex
  );

  ReactInjection.Component.injectEnvironment(ReactComponentBrowserEnvironment);

  if ("production" !== process.env.NODE_ENV) {
    var url = (ExecutionEnvironment.canUseDOM && window.location.href) || '';
    if ((/[?&]react_perf\b/).test(url)) {
      var ReactDefaultPerf = require("./ReactDefaultPerf");
      ReactDefaultPerf.start();
    }
  }
}

module.exports = {
  inject: inject
};

}).call(this,require('_process'))
},{"./BeforeInputEventPlugin":"/Users/zordius/webtasks/node_modules/react/lib/BeforeInputEventPlugin.js","./ChangeEventPlugin":"/Users/zordius/webtasks/node_modules/react/lib/ChangeEventPlugin.js","./ClientReactRootIndex":"/Users/zordius/webtasks/node_modules/react/lib/ClientReactRootIndex.js","./CompositionEventPlugin":"/Users/zordius/webtasks/node_modules/react/lib/CompositionEventPlugin.js","./DefaultEventPluginOrder":"/Users/zordius/webtasks/node_modules/react/lib/DefaultEventPluginOrder.js","./EnterLeaveEventPlugin":"/Users/zordius/webtasks/node_modules/react/lib/EnterLeaveEventPlugin.js","./ExecutionEnvironment":"/Users/zordius/webtasks/node_modules/react/lib/ExecutionEnvironment.js","./HTMLDOMPropertyConfig":"/Users/zordius/webtasks/node_modules/react/lib/HTMLDOMPropertyConfig.js","./MobileSafariClickEventPlugin":"/Users/zordius/webtasks/node_modules/react/lib/MobileSafariClickEventPlugin.js","./ReactBrowserComponentMixin":"/Users/zordius/webtasks/node_modules/react/lib/ReactBrowserComponentMixin.js","./ReactComponentBrowserEnvironment":"/Users/zordius/webtasks/node_modules/react/lib/ReactComponentBrowserEnvironment.js","./ReactDOMButton":"/Users/zordius/webtasks/node_modules/react/lib/ReactDOMButton.js","./ReactDOMComponent":"/Users/zordius/webtasks/node_modules/react/lib/ReactDOMComponent.js","./ReactDOMForm":"/Users/zordius/webtasks/node_modules/react/lib/ReactDOMForm.js","./ReactDOMImg":"/Users/zordius/webtasks/node_modules/react/lib/ReactDOMImg.js","./ReactDOMInput":"/Users/zordius/webtasks/node_modules/react/lib/ReactDOMInput.js","./ReactDOMOption":"/Users/zordius/webtasks/node_modules/react/lib/ReactDOMOption.js","./ReactDOMSelect":"/Users/zordius/webtasks/node_modules/react/lib/ReactDOMSelect.js","./ReactDOMTextarea":"/Users/zordius/webtasks/node_modules/react/lib/ReactDOMTextarea.js","./ReactDefaultBatchingStrategy":"/Users/zordius/webtasks/node_modules/react/lib/ReactDefaultBatchingStrategy.js","./ReactDefaultPerf":"/Users/zordius/webtasks/node_modules/react/lib/ReactDefaultPerf.js","./ReactEventListener":"/Users/zordius/webtasks/node_modules/react/lib/ReactEventListener.js","./ReactInjection":"/Users/zordius/webtasks/node_modules/react/lib/ReactInjection.js","./ReactInstanceHandles":"/Users/zordius/webtasks/node_modules/react/lib/ReactInstanceHandles.js","./ReactMount":"/Users/zordius/webtasks/node_modules/react/lib/ReactMount.js","./SVGDOMPropertyConfig":"/Users/zordius/webtasks/node_modules/react/lib/SVGDOMPropertyConfig.js","./SelectEventPlugin":"/Users/zordius/webtasks/node_modules/react/lib/SelectEventPlugin.js","./ServerReactRootIndex":"/Users/zordius/webtasks/node_modules/react/lib/ServerReactRootIndex.js","./SimpleEventPlugin":"/Users/zordius/webtasks/node_modules/react/lib/SimpleEventPlugin.js","./createFullPageComponent":"/Users/zordius/webtasks/node_modules/react/lib/createFullPageComponent.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactDefaultPerf.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactDefaultPerf
 * @typechecks static-only
 */

"use strict";

var DOMProperty = require("./DOMProperty");
var ReactDefaultPerfAnalysis = require("./ReactDefaultPerfAnalysis");
var ReactMount = require("./ReactMount");
var ReactPerf = require("./ReactPerf");

var performanceNow = require("./performanceNow");

function roundFloat(val) {
  return Math.floor(val * 100) / 100;
}

function addValue(obj, key, val) {
  obj[key] = (obj[key] || 0) + val;
}

var ReactDefaultPerf = {
  _allMeasurements: [], // last item in the list is the current one
  _mountStack: [0],
  _injected: false,

  start: function() {
    if (!ReactDefaultPerf._injected) {
      ReactPerf.injection.injectMeasure(ReactDefaultPerf.measure);
    }

    ReactDefaultPerf._allMeasurements.length = 0;
    ReactPerf.enableMeasure = true;
  },

  stop: function() {
    ReactPerf.enableMeasure = false;
  },

  getLastMeasurements: function() {
    return ReactDefaultPerf._allMeasurements;
  },

  printExclusive: function(measurements) {
    measurements = measurements || ReactDefaultPerf._allMeasurements;
    var summary = ReactDefaultPerfAnalysis.getExclusiveSummary(measurements);
    console.table(summary.map(function(item) {
      return {
        'Component class name': item.componentName,
        'Total inclusive time (ms)': roundFloat(item.inclusive),
        'Exclusive mount time (ms)': roundFloat(item.exclusive),
        'Exclusive render time (ms)': roundFloat(item.render),
        'Mount time per instance (ms)': roundFloat(item.exclusive / item.count),
        'Render time per instance (ms)': roundFloat(item.render / item.count),
        'Instances': item.count
      };
    }));
    // TODO: ReactDefaultPerfAnalysis.getTotalTime() does not return the correct
    // number.
  },

  printInclusive: function(measurements) {
    measurements = measurements || ReactDefaultPerf._allMeasurements;
    var summary = ReactDefaultPerfAnalysis.getInclusiveSummary(measurements);
    console.table(summary.map(function(item) {
      return {
        'Owner > component': item.componentName,
        'Inclusive time (ms)': roundFloat(item.time),
        'Instances': item.count
      };
    }));
    console.log(
      'Total time:',
      ReactDefaultPerfAnalysis.getTotalTime(measurements).toFixed(2) + ' ms'
    );
  },

  getMeasurementsSummaryMap: function(measurements) {
    var summary = ReactDefaultPerfAnalysis.getInclusiveSummary(
      measurements,
      true
    );
    return summary.map(function(item) {
      return {
        'Owner > component': item.componentName,
        'Wasted time (ms)': item.time,
        'Instances': item.count
      };
    });
  },

  printWasted: function(measurements) {
    measurements = measurements || ReactDefaultPerf._allMeasurements;
    console.table(ReactDefaultPerf.getMeasurementsSummaryMap(measurements));
    console.log(
      'Total time:',
      ReactDefaultPerfAnalysis.getTotalTime(measurements).toFixed(2) + ' ms'
    );
  },

  printDOM: function(measurements) {
    measurements = measurements || ReactDefaultPerf._allMeasurements;
    var summary = ReactDefaultPerfAnalysis.getDOMSummary(measurements);
    console.table(summary.map(function(item) {
      var result = {};
      result[DOMProperty.ID_ATTRIBUTE_NAME] = item.id;
      result['type'] = item.type;
      result['args'] = JSON.stringify(item.args);
      return result;
    }));
    console.log(
      'Total time:',
      ReactDefaultPerfAnalysis.getTotalTime(measurements).toFixed(2) + ' ms'
    );
  },

  _recordWrite: function(id, fnName, totalTime, args) {
    // TODO: totalTime isn't that useful since it doesn't count paints/reflows
    var writes =
      ReactDefaultPerf
        ._allMeasurements[ReactDefaultPerf._allMeasurements.length - 1]
        .writes;
    writes[id] = writes[id] || [];
    writes[id].push({
      type: fnName,
      time: totalTime,
      args: args
    });
  },

  measure: function(moduleName, fnName, func) {
    return function() {for (var args=[],$__0=0,$__1=arguments.length;$__0<$__1;$__0++) args.push(arguments[$__0]);
      var totalTime;
      var rv;
      var start;

      if (fnName === '_renderNewRootComponent' ||
          fnName === 'flushBatchedUpdates') {
        // A "measurement" is a set of metrics recorded for each flush. We want
        // to group the metrics for a given flush together so we can look at the
        // components that rendered and the DOM operations that actually
        // happened to determine the amount of "wasted work" performed.
        ReactDefaultPerf._allMeasurements.push({
          exclusive: {},
          inclusive: {},
          render: {},
          counts: {},
          writes: {},
          displayNames: {},
          totalTime: 0
        });
        start = performanceNow();
        rv = func.apply(this, args);
        ReactDefaultPerf._allMeasurements[
          ReactDefaultPerf._allMeasurements.length - 1
        ].totalTime = performanceNow() - start;
        return rv;
      } else if (moduleName === 'ReactDOMIDOperations' ||
        moduleName === 'ReactComponentBrowserEnvironment') {
        start = performanceNow();
        rv = func.apply(this, args);
        totalTime = performanceNow() - start;

        if (fnName === 'mountImageIntoNode') {
          var mountID = ReactMount.getID(args[1]);
          ReactDefaultPerf._recordWrite(mountID, fnName, totalTime, args[0]);
        } else if (fnName === 'dangerouslyProcessChildrenUpdates') {
          // special format
          args[0].forEach(function(update) {
            var writeArgs = {};
            if (update.fromIndex !== null) {
              writeArgs.fromIndex = update.fromIndex;
            }
            if (update.toIndex !== null) {
              writeArgs.toIndex = update.toIndex;
            }
            if (update.textContent !== null) {
              writeArgs.textContent = update.textContent;
            }
            if (update.markupIndex !== null) {
              writeArgs.markup = args[1][update.markupIndex];
            }
            ReactDefaultPerf._recordWrite(
              update.parentID,
              update.type,
              totalTime,
              writeArgs
            );
          });
        } else {
          // basic format
          ReactDefaultPerf._recordWrite(
            args[0],
            fnName,
            totalTime,
            Array.prototype.slice.call(args, 1)
          );
        }
        return rv;
      } else if (moduleName === 'ReactCompositeComponent' && (
        fnName === 'mountComponent' ||
        fnName === 'updateComponent' || // TODO: receiveComponent()?
        fnName === '_renderValidatedComponent')) {

        var rootNodeID = fnName === 'mountComponent' ?
          args[0] :
          this._rootNodeID;
        var isRender = fnName === '_renderValidatedComponent';
        var isMount = fnName === 'mountComponent';

        var mountStack = ReactDefaultPerf._mountStack;
        var entry = ReactDefaultPerf._allMeasurements[
          ReactDefaultPerf._allMeasurements.length - 1
        ];

        if (isRender) {
          addValue(entry.counts, rootNodeID, 1);
        } else if (isMount) {
          mountStack.push(0);
        }

        start = performanceNow();
        rv = func.apply(this, args);
        totalTime = performanceNow() - start;

        if (isRender) {
          addValue(entry.render, rootNodeID, totalTime);
        } else if (isMount) {
          var subMountTime = mountStack.pop();
          mountStack[mountStack.length - 1] += totalTime;
          addValue(entry.exclusive, rootNodeID, totalTime - subMountTime);
          addValue(entry.inclusive, rootNodeID, totalTime);
        } else {
          addValue(entry.inclusive, rootNodeID, totalTime);
        }

        entry.displayNames[rootNodeID] = {
          current: this.constructor.displayName,
          owner: this._owner ? this._owner.constructor.displayName : '<root>'
        };

        return rv;
      } else {
        return func.apply(this, args);
      }
    };
  }
};

module.exports = ReactDefaultPerf;

},{"./DOMProperty":"/Users/zordius/webtasks/node_modules/react/lib/DOMProperty.js","./ReactDefaultPerfAnalysis":"/Users/zordius/webtasks/node_modules/react/lib/ReactDefaultPerfAnalysis.js","./ReactMount":"/Users/zordius/webtasks/node_modules/react/lib/ReactMount.js","./ReactPerf":"/Users/zordius/webtasks/node_modules/react/lib/ReactPerf.js","./performanceNow":"/Users/zordius/webtasks/node_modules/react/lib/performanceNow.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactDefaultPerfAnalysis.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactDefaultPerfAnalysis
 */

var assign = require("./Object.assign");

// Don't try to save users less than 1.2ms (a number I made up)
var DONT_CARE_THRESHOLD = 1.2;
var DOM_OPERATION_TYPES = {
  'mountImageIntoNode': 'set innerHTML',
  INSERT_MARKUP: 'set innerHTML',
  MOVE_EXISTING: 'move',
  REMOVE_NODE: 'remove',
  TEXT_CONTENT: 'set textContent',
  'updatePropertyByID': 'update attribute',
  'deletePropertyByID': 'delete attribute',
  'updateStylesByID': 'update styles',
  'updateInnerHTMLByID': 'set innerHTML',
  'dangerouslyReplaceNodeWithMarkupByID': 'replace'
};

function getTotalTime(measurements) {
  // TODO: return number of DOM ops? could be misleading.
  // TODO: measure dropped frames after reconcile?
  // TODO: log total time of each reconcile and the top-level component
  // class that triggered it.
  var totalTime = 0;
  for (var i = 0; i < measurements.length; i++) {
    var measurement = measurements[i];
    totalTime += measurement.totalTime;
  }
  return totalTime;
}

function getDOMSummary(measurements) {
  var items = [];
  for (var i = 0; i < measurements.length; i++) {
    var measurement = measurements[i];
    var id;

    for (id in measurement.writes) {
      measurement.writes[id].forEach(function(write) {
        items.push({
          id: id,
          type: DOM_OPERATION_TYPES[write.type] || write.type,
          args: write.args
        });
      });
    }
  }
  return items;
}

function getExclusiveSummary(measurements) {
  var candidates = {};
  var displayName;

  for (var i = 0; i < measurements.length; i++) {
    var measurement = measurements[i];
    var allIDs = assign(
      {},
      measurement.exclusive,
      measurement.inclusive
    );

    for (var id in allIDs) {
      displayName = measurement.displayNames[id].current;

      candidates[displayName] = candidates[displayName] || {
        componentName: displayName,
        inclusive: 0,
        exclusive: 0,
        render: 0,
        count: 0
      };
      if (measurement.render[id]) {
        candidates[displayName].render += measurement.render[id];
      }
      if (measurement.exclusive[id]) {
        candidates[displayName].exclusive += measurement.exclusive[id];
      }
      if (measurement.inclusive[id]) {
        candidates[displayName].inclusive += measurement.inclusive[id];
      }
      if (measurement.counts[id]) {
        candidates[displayName].count += measurement.counts[id];
      }
    }
  }

  // Now make a sorted array with the results.
  var arr = [];
  for (displayName in candidates) {
    if (candidates[displayName].exclusive >= DONT_CARE_THRESHOLD) {
      arr.push(candidates[displayName]);
    }
  }

  arr.sort(function(a, b) {
    return b.exclusive - a.exclusive;
  });

  return arr;
}

function getInclusiveSummary(measurements, onlyClean) {
  var candidates = {};
  var inclusiveKey;

  for (var i = 0; i < measurements.length; i++) {
    var measurement = measurements[i];
    var allIDs = assign(
      {},
      measurement.exclusive,
      measurement.inclusive
    );
    var cleanComponents;

    if (onlyClean) {
      cleanComponents = getUnchangedComponents(measurement);
    }

    for (var id in allIDs) {
      if (onlyClean && !cleanComponents[id]) {
        continue;
      }

      var displayName = measurement.displayNames[id];

      // Inclusive time is not useful for many components without knowing where
      // they are instantiated. So we aggregate inclusive time with both the
      // owner and current displayName as the key.
      inclusiveKey = displayName.owner + ' > ' + displayName.current;

      candidates[inclusiveKey] = candidates[inclusiveKey] || {
        componentName: inclusiveKey,
        time: 0,
        count: 0
      };

      if (measurement.inclusive[id]) {
        candidates[inclusiveKey].time += measurement.inclusive[id];
      }
      if (measurement.counts[id]) {
        candidates[inclusiveKey].count += measurement.counts[id];
      }
    }
  }

  // Now make a sorted array with the results.
  var arr = [];
  for (inclusiveKey in candidates) {
    if (candidates[inclusiveKey].time >= DONT_CARE_THRESHOLD) {
      arr.push(candidates[inclusiveKey]);
    }
  }

  arr.sort(function(a, b) {
    return b.time - a.time;
  });

  return arr;
}

function getUnchangedComponents(measurement) {
  // For a given reconcile, look at which components did not actually
  // render anything to the DOM and return a mapping of their ID to
  // the amount of time it took to render the entire subtree.
  var cleanComponents = {};
  var dirtyLeafIDs = Object.keys(measurement.writes);
  var allIDs = assign({}, measurement.exclusive, measurement.inclusive);

  for (var id in allIDs) {
    var isDirty = false;
    // For each component that rendered, see if a component that triggered
    // a DOM op is in its subtree.
    for (var i = 0; i < dirtyLeafIDs.length; i++) {
      if (dirtyLeafIDs[i].indexOf(id) === 0) {
        isDirty = true;
        break;
      }
    }
    if (!isDirty && measurement.counts[id] > 0) {
      cleanComponents[id] = true;
    }
  }
  return cleanComponents;
}

var ReactDefaultPerfAnalysis = {
  getExclusiveSummary: getExclusiveSummary,
  getInclusiveSummary: getInclusiveSummary,
  getDOMSummary: getDOMSummary,
  getTotalTime: getTotalTime
};

module.exports = ReactDefaultPerfAnalysis;

},{"./Object.assign":"/Users/zordius/webtasks/node_modules/react/lib/Object.assign.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactElement.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactElement
 */

"use strict";

var ReactContext = require("./ReactContext");
var ReactCurrentOwner = require("./ReactCurrentOwner");

var warning = require("./warning");

var RESERVED_PROPS = {
  key: true,
  ref: true
};

/**
 * Warn for mutations.
 *
 * @internal
 * @param {object} object
 * @param {string} key
 */
function defineWarningProperty(object, key) {
  Object.defineProperty(object, key, {

    configurable: false,
    enumerable: true,

    get: function() {
      if (!this._store) {
        return null;
      }
      return this._store[key];
    },

    set: function(value) {
      ("production" !== process.env.NODE_ENV ? warning(
        false,
        'Don\'t set the ' + key + ' property of the component. ' +
        'Mutate the existing props object instead.'
      ) : null);
      this._store[key] = value;
    }

  });
}

/**
 * This is updated to true if the membrane is successfully created.
 */
var useMutationMembrane = false;

/**
 * Warn for mutations.
 *
 * @internal
 * @param {object} element
 */
function defineMutationMembrane(prototype) {
  try {
    var pseudoFrozenProperties = {
      props: true
    };
    for (var key in pseudoFrozenProperties) {
      defineWarningProperty(prototype, key);
    }
    useMutationMembrane = true;
  } catch (x) {
    // IE will fail on defineProperty
  }
}

/**
 * Base constructor for all React elements. This is only used to make this
 * work with a dynamic instanceof check. Nothing should live on this prototype.
 *
 * @param {*} type
 * @param {string|object} ref
 * @param {*} key
 * @param {*} props
 * @internal
 */
var ReactElement = function(type, key, ref, owner, context, props) {
  // Built-in properties that belong on the element
  this.type = type;
  this.key = key;
  this.ref = ref;

  // Record the component responsible for creating this element.
  this._owner = owner;

  // TODO: Deprecate withContext, and then the context becomes accessible
  // through the owner.
  this._context = context;

  if ("production" !== process.env.NODE_ENV) {
    // The validation flag and props are currently mutative. We put them on
    // an external backing store so that we can freeze the whole object.
    // This can be replaced with a WeakMap once they are implemented in
    // commonly used development environments.
    this._store = { validated: false, props: props };

    // We're not allowed to set props directly on the object so we early
    // return and rely on the prototype membrane to forward to the backing
    // store.
    if (useMutationMembrane) {
      Object.freeze(this);
      return;
    }
  }

  this.props = props;
};

// We intentionally don't expose the function on the constructor property.
// ReactElement should be indistinguishable from a plain object.
ReactElement.prototype = {
  _isReactElement: true
};

if ("production" !== process.env.NODE_ENV) {
  defineMutationMembrane(ReactElement.prototype);
}

ReactElement.createElement = function(type, config, children) {
  var propName;

  // Reserved names are extracted
  var props = {};

  var key = null;
  var ref = null;

  if (config != null) {
    ref = config.ref === undefined ? null : config.ref;
    if ("production" !== process.env.NODE_ENV) {
      ("production" !== process.env.NODE_ENV ? warning(
        config.key !== null,
        'createElement(...): Encountered component with a `key` of null. In ' +
        'a future version, this will be treated as equivalent to the string ' +
        '\'null\'; instead, provide an explicit key or use undefined.'
      ) : null);
    }
    // TODO: Change this back to `config.key === undefined`
    key = config.key == null ? null : '' + config.key;
    // Remaining properties are added to a new props object
    for (propName in config) {
      if (config.hasOwnProperty(propName) &&
          !RESERVED_PROPS.hasOwnProperty(propName)) {
        props[propName] = config[propName];
      }
    }
  }

  // Children can be more than one argument, and those are transferred onto
  // the newly allocated props object.
  var childrenLength = arguments.length - 2;
  if (childrenLength === 1) {
    props.children = children;
  } else if (childrenLength > 1) {
    var childArray = Array(childrenLength);
    for (var i = 0; i < childrenLength; i++) {
      childArray[i] = arguments[i + 2];
    }
    props.children = childArray;
  }

  // Resolve default props
  if (type.defaultProps) {
    var defaultProps = type.defaultProps;
    for (propName in defaultProps) {
      if (typeof props[propName] === 'undefined') {
        props[propName] = defaultProps[propName];
      }
    }
  }

  return new ReactElement(
    type,
    key,
    ref,
    ReactCurrentOwner.current,
    ReactContext.current,
    props
  );
};

ReactElement.createFactory = function(type) {
  var factory = ReactElement.createElement.bind(null, type);
  // Expose the type on the factory and the prototype so that it can be
  // easily accessed on elements. E.g. <Foo />.type === Foo.type.
  // This should not be named `constructor` since this may not be the function
  // that created the element, and it may not even be a constructor.
  factory.type = type;
  return factory;
};

ReactElement.cloneAndReplaceProps = function(oldElement, newProps) {
  var newElement = new ReactElement(
    oldElement.type,
    oldElement.key,
    oldElement.ref,
    oldElement._owner,
    oldElement._context,
    newProps
  );

  if ("production" !== process.env.NODE_ENV) {
    // If the key on the original is valid, then the clone is valid
    newElement._store.validated = oldElement._store.validated;
  }
  return newElement;
};

/**
 * @param {?object} object
 * @return {boolean} True if `object` is a valid component.
 * @final
 */
ReactElement.isValidElement = function(object) {
  // ReactTestUtils is often used outside of beforeEach where as React is
  // within it. This leads to two different instances of React on the same
  // page. To identify a element from a different React instance we use
  // a flag instead of an instanceof check.
  var isElement = !!(object && object._isReactElement);
  // if (isElement && !(object instanceof ReactElement)) {
  // This is an indicator that you're using multiple versions of React at the
  // same time. This will screw with ownership and stuff. Fix it, please.
  // TODO: We could possibly warn here.
  // }
  return isElement;
};

module.exports = ReactElement;

}).call(this,require('_process'))
},{"./ReactContext":"/Users/zordius/webtasks/node_modules/react/lib/ReactContext.js","./ReactCurrentOwner":"/Users/zordius/webtasks/node_modules/react/lib/ReactCurrentOwner.js","./warning":"/Users/zordius/webtasks/node_modules/react/lib/warning.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactElementValidator.js":[function(require,module,exports){
/**
 * Copyright 2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactElementValidator
 */

/**
 * ReactElementValidator provides a wrapper around a element factory
 * which validates the props passed to the element. This is intended to be
 * used only in DEV and could be replaced by a static type checker for languages
 * that support it.
 */

"use strict";

var ReactElement = require("./ReactElement");
var ReactPropTypeLocations = require("./ReactPropTypeLocations");
var ReactCurrentOwner = require("./ReactCurrentOwner");

var monitorCodeUse = require("./monitorCodeUse");

/**
 * Warn if there's no key explicitly set on dynamic arrays of children or
 * object keys are not valid. This allows us to keep track of children between
 * updates.
 */
var ownerHasKeyUseWarning = {
  'react_key_warning': {},
  'react_numeric_key_warning': {}
};
var ownerHasMonitoredObjectMap = {};

var loggedTypeFailures = {};

var NUMERIC_PROPERTY_REGEX = /^\d+$/;

/**
 * Gets the current owner's displayName for use in warnings.
 *
 * @internal
 * @return {?string} Display name or undefined
 */
function getCurrentOwnerDisplayName() {
  var current = ReactCurrentOwner.current;
  return current && current.constructor.displayName || undefined;
}

/**
 * Warn if the component doesn't have an explicit key assigned to it.
 * This component is in an array. The array could grow and shrink or be
 * reordered. All children that haven't already been validated are required to
 * have a "key" property assigned to it.
 *
 * @internal
 * @param {ReactComponent} component Component that requires a key.
 * @param {*} parentType component's parent's type.
 */
function validateExplicitKey(component, parentType) {
  if (component._store.validated || component.key != null) {
    return;
  }
  component._store.validated = true;

  warnAndMonitorForKeyUse(
    'react_key_warning',
    'Each child in an array should have a unique "key" prop.',
    component,
    parentType
  );
}

/**
 * Warn if the key is being defined as an object property but has an incorrect
 * value.
 *
 * @internal
 * @param {string} name Property name of the key.
 * @param {ReactComponent} component Component that requires a key.
 * @param {*} parentType component's parent's type.
 */
function validatePropertyKey(name, component, parentType) {
  if (!NUMERIC_PROPERTY_REGEX.test(name)) {
    return;
  }
  warnAndMonitorForKeyUse(
    'react_numeric_key_warning',
    'Child objects should have non-numeric keys so ordering is preserved.',
    component,
    parentType
  );
}

/**
 * Shared warning and monitoring code for the key warnings.
 *
 * @internal
 * @param {string} warningID The id used when logging.
 * @param {string} message The base warning that gets output.
 * @param {ReactComponent} component Component that requires a key.
 * @param {*} parentType component's parent's type.
 */
function warnAndMonitorForKeyUse(warningID, message, component, parentType) {
  var ownerName = getCurrentOwnerDisplayName();
  var parentName = parentType.displayName;

  var useName = ownerName || parentName;
  var memoizer = ownerHasKeyUseWarning[warningID];
  if (memoizer.hasOwnProperty(useName)) {
    return;
  }
  memoizer[useName] = true;

  message += ownerName ?
    (" Check the render method of " + ownerName + ".") :
    (" Check the renderComponent call using <" + parentName + ">.");

  // Usually the current owner is the offender, but if it accepts children as a
  // property, it may be the creator of the child that's responsible for
  // assigning it a key.
  var childOwnerName = null;
  if (component._owner && component._owner !== ReactCurrentOwner.current) {
    // Name of the component that originally created this child.
    childOwnerName = component._owner.constructor.displayName;

    message += (" It was passed a child from " + childOwnerName + ".");
  }

  message += ' See http://fb.me/react-warning-keys for more information.';
  monitorCodeUse(warningID, {
    component: useName,
    componentOwner: childOwnerName
  });
  console.warn(message);
}

/**
 * Log that we're using an object map. We're considering deprecating this
 * feature and replace it with proper Map and ImmutableMap data structures.
 *
 * @internal
 */
function monitorUseOfObjectMap() {
  var currentName = getCurrentOwnerDisplayName() || '';
  if (ownerHasMonitoredObjectMap.hasOwnProperty(currentName)) {
    return;
  }
  ownerHasMonitoredObjectMap[currentName] = true;
  monitorCodeUse('react_object_map_children');
}

/**
 * Ensure that every component either is passed in a static location, in an
 * array with an explicit keys property defined, or in an object literal
 * with valid key property.
 *
 * @internal
 * @param {*} component Statically passed child of any type.
 * @param {*} parentType component's parent's type.
 * @return {boolean}
 */
function validateChildKeys(component, parentType) {
  if (Array.isArray(component)) {
    for (var i = 0; i < component.length; i++) {
      var child = component[i];
      if (ReactElement.isValidElement(child)) {
        validateExplicitKey(child, parentType);
      }
    }
  } else if (ReactElement.isValidElement(component)) {
    // This component was passed in a valid location.
    component._store.validated = true;
  } else if (component && typeof component === 'object') {
    monitorUseOfObjectMap();
    for (var name in component) {
      validatePropertyKey(name, component[name], parentType);
    }
  }
}

/**
 * Assert that the props are valid
 *
 * @param {string} componentName Name of the component for error messages.
 * @param {object} propTypes Map of prop name to a ReactPropType
 * @param {object} props
 * @param {string} location e.g. "prop", "context", "child context"
 * @private
 */
function checkPropTypes(componentName, propTypes, props, location) {
  for (var propName in propTypes) {
    if (propTypes.hasOwnProperty(propName)) {
      var error;
      // Prop type validation may throw. In case they do, we don't want to
      // fail the render phase where it didn't fail before. So we log it.
      // After these have been cleaned up, we'll let them throw.
      try {
        error = propTypes[propName](props, propName, componentName, location);
      } catch (ex) {
        error = ex;
      }
      if (error instanceof Error && !(error.message in loggedTypeFailures)) {
        // Only monitor this failure once because there tends to be a lot of the
        // same error.
        loggedTypeFailures[error.message] = true;
        // This will soon use the warning module
        monitorCodeUse(
          'react_failed_descriptor_type_check',
          { message: error.message }
        );
      }
    }
  }
}

var ReactElementValidator = {

  createElement: function(type, props, children) {
    var element = ReactElement.createElement.apply(this, arguments);

    // The result can be nullish if a mock or a custom function is used.
    // TODO: Drop this when these are no longer allowed as the type argument.
    if (element == null) {
      return element;
    }

    for (var i = 2; i < arguments.length; i++) {
      validateChildKeys(arguments[i], type);
    }

    var name = type.displayName;
    if (type.propTypes) {
      checkPropTypes(
        name,
        type.propTypes,
        element.props,
        ReactPropTypeLocations.prop
      );
    }
    if (type.contextTypes) {
      checkPropTypes(
        name,
        type.contextTypes,
        element._context,
        ReactPropTypeLocations.context
      );
    }
    return element;
  },

  createFactory: function(type) {
    var validatedFactory = ReactElementValidator.createElement.bind(
      null,
      type
    );
    validatedFactory.type = type;
    return validatedFactory;
  }

};

module.exports = ReactElementValidator;

},{"./ReactCurrentOwner":"/Users/zordius/webtasks/node_modules/react/lib/ReactCurrentOwner.js","./ReactElement":"/Users/zordius/webtasks/node_modules/react/lib/ReactElement.js","./ReactPropTypeLocations":"/Users/zordius/webtasks/node_modules/react/lib/ReactPropTypeLocations.js","./monitorCodeUse":"/Users/zordius/webtasks/node_modules/react/lib/monitorCodeUse.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactEmptyComponent.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactEmptyComponent
 */

"use strict";

var ReactElement = require("./ReactElement");

var invariant = require("./invariant");

var component;
// This registry keeps track of the React IDs of the components that rendered to
// `null` (in reality a placeholder such as `noscript`)
var nullComponentIdsRegistry = {};

var ReactEmptyComponentInjection = {
  injectEmptyComponent: function(emptyComponent) {
    component = ReactElement.createFactory(emptyComponent);
  }
};

/**
 * @return {ReactComponent} component The injected empty component.
 */
function getEmptyComponent() {
  ("production" !== process.env.NODE_ENV ? invariant(
    component,
    'Trying to return null from a render, but no null placeholder component ' +
    'was injected.'
  ) : invariant(component));
  return component();
}

/**
 * Mark the component as having rendered to null.
 * @param {string} id Component's `_rootNodeID`.
 */
function registerNullComponentID(id) {
  nullComponentIdsRegistry[id] = true;
}

/**
 * Unmark the component as having rendered to null: it renders to something now.
 * @param {string} id Component's `_rootNodeID`.
 */
function deregisterNullComponentID(id) {
  delete nullComponentIdsRegistry[id];
}

/**
 * @param {string} id Component's `_rootNodeID`.
 * @return {boolean} True if the component is rendered to null.
 */
function isNullComponentID(id) {
  return nullComponentIdsRegistry[id];
}

var ReactEmptyComponent = {
  deregisterNullComponentID: deregisterNullComponentID,
  getEmptyComponent: getEmptyComponent,
  injection: ReactEmptyComponentInjection,
  isNullComponentID: isNullComponentID,
  registerNullComponentID: registerNullComponentID
};

module.exports = ReactEmptyComponent;

}).call(this,require('_process'))
},{"./ReactElement":"/Users/zordius/webtasks/node_modules/react/lib/ReactElement.js","./invariant":"/Users/zordius/webtasks/node_modules/react/lib/invariant.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactErrorUtils.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactErrorUtils
 * @typechecks
 */

"use strict";

var ReactErrorUtils = {
  /**
   * Creates a guarded version of a function. This is supposed to make debugging
   * of event handlers easier. To aid debugging with the browser's debugger,
   * this currently simply returns the original function.
   *
   * @param {function} func Function to be executed
   * @param {string} name The name of the guard
   * @return {function}
   */
  guard: function(func, name) {
    return func;
  }
};

module.exports = ReactErrorUtils;

},{}],"/Users/zordius/webtasks/node_modules/react/lib/ReactEventEmitterMixin.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactEventEmitterMixin
 */

"use strict";

var EventPluginHub = require("./EventPluginHub");

function runEventQueueInBatch(events) {
  EventPluginHub.enqueueEvents(events);
  EventPluginHub.processEventQueue();
}

var ReactEventEmitterMixin = {

  /**
   * Streams a fired top-level event to `EventPluginHub` where plugins have the
   * opportunity to create `ReactEvent`s to be dispatched.
   *
   * @param {string} topLevelType Record from `EventConstants`.
   * @param {object} topLevelTarget The listening component root node.
   * @param {string} topLevelTargetID ID of `topLevelTarget`.
   * @param {object} nativeEvent Native environment event.
   */
  handleTopLevel: function(
      topLevelType,
      topLevelTarget,
      topLevelTargetID,
      nativeEvent) {
    var events = EventPluginHub.extractEvents(
      topLevelType,
      topLevelTarget,
      topLevelTargetID,
      nativeEvent
    );

    runEventQueueInBatch(events);
  }
};

module.exports = ReactEventEmitterMixin;

},{"./EventPluginHub":"/Users/zordius/webtasks/node_modules/react/lib/EventPluginHub.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactEventListener.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactEventListener
 * @typechecks static-only
 */

"use strict";

var EventListener = require("./EventListener");
var ExecutionEnvironment = require("./ExecutionEnvironment");
var PooledClass = require("./PooledClass");
var ReactInstanceHandles = require("./ReactInstanceHandles");
var ReactMount = require("./ReactMount");
var ReactUpdates = require("./ReactUpdates");

var assign = require("./Object.assign");
var getEventTarget = require("./getEventTarget");
var getUnboundedScrollPosition = require("./getUnboundedScrollPosition");

/**
 * Finds the parent React component of `node`.
 *
 * @param {*} node
 * @return {?DOMEventTarget} Parent container, or `null` if the specified node
 *                           is not nested.
 */
function findParent(node) {
  // TODO: It may be a good idea to cache this to prevent unnecessary DOM
  // traversal, but caching is difficult to do correctly without using a
  // mutation observer to listen for all DOM changes.
  var nodeID = ReactMount.getID(node);
  var rootID = ReactInstanceHandles.getReactRootIDFromNodeID(nodeID);
  var container = ReactMount.findReactContainerForID(rootID);
  var parent = ReactMount.getFirstReactDOM(container);
  return parent;
}

// Used to store ancestor hierarchy in top level callback
function TopLevelCallbackBookKeeping(topLevelType, nativeEvent) {
  this.topLevelType = topLevelType;
  this.nativeEvent = nativeEvent;
  this.ancestors = [];
}
assign(TopLevelCallbackBookKeeping.prototype, {
  destructor: function() {
    this.topLevelType = null;
    this.nativeEvent = null;
    this.ancestors.length = 0;
  }
});
PooledClass.addPoolingTo(
  TopLevelCallbackBookKeeping,
  PooledClass.twoArgumentPooler
);

function handleTopLevelImpl(bookKeeping) {
  var topLevelTarget = ReactMount.getFirstReactDOM(
    getEventTarget(bookKeeping.nativeEvent)
  ) || window;

  // Loop through the hierarchy, in case there's any nested components.
  // It's important that we build the array of ancestors before calling any
  // event handlers, because event handlers can modify the DOM, leading to
  // inconsistencies with ReactMount's node cache. See #1105.
  var ancestor = topLevelTarget;
  while (ancestor) {
    bookKeeping.ancestors.push(ancestor);
    ancestor = findParent(ancestor);
  }

  for (var i = 0, l = bookKeeping.ancestors.length; i < l; i++) {
    topLevelTarget = bookKeeping.ancestors[i];
    var topLevelTargetID = ReactMount.getID(topLevelTarget) || '';
    ReactEventListener._handleTopLevel(
      bookKeeping.topLevelType,
      topLevelTarget,
      topLevelTargetID,
      bookKeeping.nativeEvent
    );
  }
}

function scrollValueMonitor(cb) {
  var scrollPosition = getUnboundedScrollPosition(window);
  cb(scrollPosition);
}

var ReactEventListener = {
  _enabled: true,
  _handleTopLevel: null,

  WINDOW_HANDLE: ExecutionEnvironment.canUseDOM ? window : null,

  setHandleTopLevel: function(handleTopLevel) {
    ReactEventListener._handleTopLevel = handleTopLevel;
  },

  setEnabled: function(enabled) {
    ReactEventListener._enabled = !!enabled;
  },

  isEnabled: function() {
    return ReactEventListener._enabled;
  },


  /**
   * Traps top-level events by using event bubbling.
   *
   * @param {string} topLevelType Record from `EventConstants`.
   * @param {string} handlerBaseName Event name (e.g. "click").
   * @param {object} handle Element on which to attach listener.
   * @return {object} An object with a remove function which will forcefully
   *                  remove the listener.
   * @internal
   */
  trapBubbledEvent: function(topLevelType, handlerBaseName, handle) {
    var element = handle;
    if (!element) {
      return;
    }
    return EventListener.listen(
      element,
      handlerBaseName,
      ReactEventListener.dispatchEvent.bind(null, topLevelType)
    );
  },

  /**
   * Traps a top-level event by using event capturing.
   *
   * @param {string} topLevelType Record from `EventConstants`.
   * @param {string} handlerBaseName Event name (e.g. "click").
   * @param {object} handle Element on which to attach listener.
   * @return {object} An object with a remove function which will forcefully
   *                  remove the listener.
   * @internal
   */
  trapCapturedEvent: function(topLevelType, handlerBaseName, handle) {
    var element = handle;
    if (!element) {
      return;
    }
    return EventListener.capture(
      element,
      handlerBaseName,
      ReactEventListener.dispatchEvent.bind(null, topLevelType)
    );
  },

  monitorScrollValue: function(refresh) {
    var callback = scrollValueMonitor.bind(null, refresh);
    EventListener.listen(window, 'scroll', callback);
    EventListener.listen(window, 'resize', callback);
  },

  dispatchEvent: function(topLevelType, nativeEvent) {
    if (!ReactEventListener._enabled) {
      return;
    }

    var bookKeeping = TopLevelCallbackBookKeeping.getPooled(
      topLevelType,
      nativeEvent
    );
    try {
      // Event queue being processed in the same cycle allows
      // `preventDefault`.
      ReactUpdates.batchedUpdates(handleTopLevelImpl, bookKeeping);
    } finally {
      TopLevelCallbackBookKeeping.release(bookKeeping);
    }
  }
};

module.exports = ReactEventListener;

},{"./EventListener":"/Users/zordius/webtasks/node_modules/react/lib/EventListener.js","./ExecutionEnvironment":"/Users/zordius/webtasks/node_modules/react/lib/ExecutionEnvironment.js","./Object.assign":"/Users/zordius/webtasks/node_modules/react/lib/Object.assign.js","./PooledClass":"/Users/zordius/webtasks/node_modules/react/lib/PooledClass.js","./ReactInstanceHandles":"/Users/zordius/webtasks/node_modules/react/lib/ReactInstanceHandles.js","./ReactMount":"/Users/zordius/webtasks/node_modules/react/lib/ReactMount.js","./ReactUpdates":"/Users/zordius/webtasks/node_modules/react/lib/ReactUpdates.js","./getEventTarget":"/Users/zordius/webtasks/node_modules/react/lib/getEventTarget.js","./getUnboundedScrollPosition":"/Users/zordius/webtasks/node_modules/react/lib/getUnboundedScrollPosition.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactInjection.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactInjection
 */

"use strict";

var DOMProperty = require("./DOMProperty");
var EventPluginHub = require("./EventPluginHub");
var ReactComponent = require("./ReactComponent");
var ReactCompositeComponent = require("./ReactCompositeComponent");
var ReactEmptyComponent = require("./ReactEmptyComponent");
var ReactBrowserEventEmitter = require("./ReactBrowserEventEmitter");
var ReactNativeComponent = require("./ReactNativeComponent");
var ReactPerf = require("./ReactPerf");
var ReactRootIndex = require("./ReactRootIndex");
var ReactUpdates = require("./ReactUpdates");

var ReactInjection = {
  Component: ReactComponent.injection,
  CompositeComponent: ReactCompositeComponent.injection,
  DOMProperty: DOMProperty.injection,
  EmptyComponent: ReactEmptyComponent.injection,
  EventPluginHub: EventPluginHub.injection,
  EventEmitter: ReactBrowserEventEmitter.injection,
  NativeComponent: ReactNativeComponent.injection,
  Perf: ReactPerf.injection,
  RootIndex: ReactRootIndex.injection,
  Updates: ReactUpdates.injection
};

module.exports = ReactInjection;

},{"./DOMProperty":"/Users/zordius/webtasks/node_modules/react/lib/DOMProperty.js","./EventPluginHub":"/Users/zordius/webtasks/node_modules/react/lib/EventPluginHub.js","./ReactBrowserEventEmitter":"/Users/zordius/webtasks/node_modules/react/lib/ReactBrowserEventEmitter.js","./ReactComponent":"/Users/zordius/webtasks/node_modules/react/lib/ReactComponent.js","./ReactCompositeComponent":"/Users/zordius/webtasks/node_modules/react/lib/ReactCompositeComponent.js","./ReactEmptyComponent":"/Users/zordius/webtasks/node_modules/react/lib/ReactEmptyComponent.js","./ReactNativeComponent":"/Users/zordius/webtasks/node_modules/react/lib/ReactNativeComponent.js","./ReactPerf":"/Users/zordius/webtasks/node_modules/react/lib/ReactPerf.js","./ReactRootIndex":"/Users/zordius/webtasks/node_modules/react/lib/ReactRootIndex.js","./ReactUpdates":"/Users/zordius/webtasks/node_modules/react/lib/ReactUpdates.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactInputSelection.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactInputSelection
 */

"use strict";

var ReactDOMSelection = require("./ReactDOMSelection");

var containsNode = require("./containsNode");
var focusNode = require("./focusNode");
var getActiveElement = require("./getActiveElement");

function isInDocument(node) {
  return containsNode(document.documentElement, node);
}

/**
 * @ReactInputSelection: React input selection module. Based on Selection.js,
 * but modified to be suitable for react and has a couple of bug fixes (doesn't
 * assume buttons have range selections allowed).
 * Input selection module for React.
 */
var ReactInputSelection = {

  hasSelectionCapabilities: function(elem) {
    return elem && (
      (elem.nodeName === 'INPUT' && elem.type === 'text') ||
      elem.nodeName === 'TEXTAREA' ||
      elem.contentEditable === 'true'
    );
  },

  getSelectionInformation: function() {
    var focusedElem = getActiveElement();
    return {
      focusedElem: focusedElem,
      selectionRange:
          ReactInputSelection.hasSelectionCapabilities(focusedElem) ?
          ReactInputSelection.getSelection(focusedElem) :
          null
    };
  },

  /**
   * @restoreSelection: If any selection information was potentially lost,
   * restore it. This is useful when performing operations that could remove dom
   * nodes and place them back in, resulting in focus being lost.
   */
  restoreSelection: function(priorSelectionInformation) {
    var curFocusedElem = getActiveElement();
    var priorFocusedElem = priorSelectionInformation.focusedElem;
    var priorSelectionRange = priorSelectionInformation.selectionRange;
    if (curFocusedElem !== priorFocusedElem &&
        isInDocument(priorFocusedElem)) {
      if (ReactInputSelection.hasSelectionCapabilities(priorFocusedElem)) {
        ReactInputSelection.setSelection(
          priorFocusedElem,
          priorSelectionRange
        );
      }
      focusNode(priorFocusedElem);
    }
  },

  /**
   * @getSelection: Gets the selection bounds of a focused textarea, input or
   * contentEditable node.
   * -@input: Look up selection bounds of this input
   * -@return {start: selectionStart, end: selectionEnd}
   */
  getSelection: function(input) {
    var selection;

    if ('selectionStart' in input) {
      // Modern browser with input or textarea.
      selection = {
        start: input.selectionStart,
        end: input.selectionEnd
      };
    } else if (document.selection && input.nodeName === 'INPUT') {
      // IE8 input.
      var range = document.selection.createRange();
      // There can only be one selection per document in IE, so it must
      // be in our element.
      if (range.parentElement() === input) {
        selection = {
          start: -range.moveStart('character', -input.value.length),
          end: -range.moveEnd('character', -input.value.length)
        };
      }
    } else {
      // Content editable or old IE textarea.
      selection = ReactDOMSelection.getOffsets(input);
    }

    return selection || {start: 0, end: 0};
  },

  /**
   * @setSelection: Sets the selection bounds of a textarea or input and focuses
   * the input.
   * -@input     Set selection bounds of this input or textarea
   * -@offsets   Object of same form that is returned from get*
   */
  setSelection: function(input, offsets) {
    var start = offsets.start;
    var end = offsets.end;
    if (typeof end === 'undefined') {
      end = start;
    }

    if ('selectionStart' in input) {
      input.selectionStart = start;
      input.selectionEnd = Math.min(end, input.value.length);
    } else if (document.selection && input.nodeName === 'INPUT') {
      var range = input.createTextRange();
      range.collapse(true);
      range.moveStart('character', start);
      range.moveEnd('character', end - start);
      range.select();
    } else {
      ReactDOMSelection.setOffsets(input, offsets);
    }
  }
};

module.exports = ReactInputSelection;

},{"./ReactDOMSelection":"/Users/zordius/webtasks/node_modules/react/lib/ReactDOMSelection.js","./containsNode":"/Users/zordius/webtasks/node_modules/react/lib/containsNode.js","./focusNode":"/Users/zordius/webtasks/node_modules/react/lib/focusNode.js","./getActiveElement":"/Users/zordius/webtasks/node_modules/react/lib/getActiveElement.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactInstanceHandles.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactInstanceHandles
 * @typechecks static-only
 */

"use strict";

var ReactRootIndex = require("./ReactRootIndex");

var invariant = require("./invariant");

var SEPARATOR = '.';
var SEPARATOR_LENGTH = SEPARATOR.length;

/**
 * Maximum depth of traversals before we consider the possibility of a bad ID.
 */
var MAX_TREE_DEPTH = 100;

/**
 * Creates a DOM ID prefix to use when mounting React components.
 *
 * @param {number} index A unique integer
 * @return {string} React root ID.
 * @internal
 */
function getReactRootIDString(index) {
  return SEPARATOR + index.toString(36);
}

/**
 * Checks if a character in the supplied ID is a separator or the end.
 *
 * @param {string} id A React DOM ID.
 * @param {number} index Index of the character to check.
 * @return {boolean} True if the character is a separator or end of the ID.
 * @private
 */
function isBoundary(id, index) {
  return id.charAt(index) === SEPARATOR || index === id.length;
}

/**
 * Checks if the supplied string is a valid React DOM ID.
 *
 * @param {string} id A React DOM ID, maybe.
 * @return {boolean} True if the string is a valid React DOM ID.
 * @private
 */
function isValidID(id) {
  return id === '' || (
    id.charAt(0) === SEPARATOR && id.charAt(id.length - 1) !== SEPARATOR
  );
}

/**
 * Checks if the first ID is an ancestor of or equal to the second ID.
 *
 * @param {string} ancestorID
 * @param {string} descendantID
 * @return {boolean} True if `ancestorID` is an ancestor of `descendantID`.
 * @internal
 */
function isAncestorIDOf(ancestorID, descendantID) {
  return (
    descendantID.indexOf(ancestorID) === 0 &&
    isBoundary(descendantID, ancestorID.length)
  );
}

/**
 * Gets the parent ID of the supplied React DOM ID, `id`.
 *
 * @param {string} id ID of a component.
 * @return {string} ID of the parent, or an empty string.
 * @private
 */
function getParentID(id) {
  return id ? id.substr(0, id.lastIndexOf(SEPARATOR)) : '';
}

/**
 * Gets the next DOM ID on the tree path from the supplied `ancestorID` to the
 * supplied `destinationID`. If they are equal, the ID is returned.
 *
 * @param {string} ancestorID ID of an ancestor node of `destinationID`.
 * @param {string} destinationID ID of the destination node.
 * @return {string} Next ID on the path from `ancestorID` to `destinationID`.
 * @private
 */
function getNextDescendantID(ancestorID, destinationID) {
  ("production" !== process.env.NODE_ENV ? invariant(
    isValidID(ancestorID) && isValidID(destinationID),
    'getNextDescendantID(%s, %s): Received an invalid React DOM ID.',
    ancestorID,
    destinationID
  ) : invariant(isValidID(ancestorID) && isValidID(destinationID)));
  ("production" !== process.env.NODE_ENV ? invariant(
    isAncestorIDOf(ancestorID, destinationID),
    'getNextDescendantID(...): React has made an invalid assumption about ' +
    'the DOM hierarchy. Expected `%s` to be an ancestor of `%s`.',
    ancestorID,
    destinationID
  ) : invariant(isAncestorIDOf(ancestorID, destinationID)));
  if (ancestorID === destinationID) {
    return ancestorID;
  }
  // Skip over the ancestor and the immediate separator. Traverse until we hit
  // another separator or we reach the end of `destinationID`.
  var start = ancestorID.length + SEPARATOR_LENGTH;
  for (var i = start; i < destinationID.length; i++) {
    if (isBoundary(destinationID, i)) {
      break;
    }
  }
  return destinationID.substr(0, i);
}

/**
 * Gets the nearest common ancestor ID of two IDs.
 *
 * Using this ID scheme, the nearest common ancestor ID is the longest common
 * prefix of the two IDs that immediately preceded a "marker" in both strings.
 *
 * @param {string} oneID
 * @param {string} twoID
 * @return {string} Nearest common ancestor ID, or the empty string if none.
 * @private
 */
function getFirstCommonAncestorID(oneID, twoID) {
  var minLength = Math.min(oneID.length, twoID.length);
  if (minLength === 0) {
    return '';
  }
  var lastCommonMarkerIndex = 0;
  // Use `<=` to traverse until the "EOL" of the shorter string.
  for (var i = 0; i <= minLength; i++) {
    if (isBoundary(oneID, i) && isBoundary(twoID, i)) {
      lastCommonMarkerIndex = i;
    } else if (oneID.charAt(i) !== twoID.charAt(i)) {
      break;
    }
  }
  var longestCommonID = oneID.substr(0, lastCommonMarkerIndex);
  ("production" !== process.env.NODE_ENV ? invariant(
    isValidID(longestCommonID),
    'getFirstCommonAncestorID(%s, %s): Expected a valid React DOM ID: %s',
    oneID,
    twoID,
    longestCommonID
  ) : invariant(isValidID(longestCommonID)));
  return longestCommonID;
}

/**
 * Traverses the parent path between two IDs (either up or down). The IDs must
 * not be the same, and there must exist a parent path between them. If the
 * callback returns `false`, traversal is stopped.
 *
 * @param {?string} start ID at which to start traversal.
 * @param {?string} stop ID at which to end traversal.
 * @param {function} cb Callback to invoke each ID with.
 * @param {?boolean} skipFirst Whether or not to skip the first node.
 * @param {?boolean} skipLast Whether or not to skip the last node.
 * @private
 */
function traverseParentPath(start, stop, cb, arg, skipFirst, skipLast) {
  start = start || '';
  stop = stop || '';
  ("production" !== process.env.NODE_ENV ? invariant(
    start !== stop,
    'traverseParentPath(...): Cannot traverse from and to the same ID, `%s`.',
    start
  ) : invariant(start !== stop));
  var traverseUp = isAncestorIDOf(stop, start);
  ("production" !== process.env.NODE_ENV ? invariant(
    traverseUp || isAncestorIDOf(start, stop),
    'traverseParentPath(%s, %s, ...): Cannot traverse from two IDs that do ' +
    'not have a parent path.',
    start,
    stop
  ) : invariant(traverseUp || isAncestorIDOf(start, stop)));
  // Traverse from `start` to `stop` one depth at a time.
  var depth = 0;
  var traverse = traverseUp ? getParentID : getNextDescendantID;
  for (var id = start; /* until break */; id = traverse(id, stop)) {
    var ret;
    if ((!skipFirst || id !== start) && (!skipLast || id !== stop)) {
      ret = cb(id, traverseUp, arg);
    }
    if (ret === false || id === stop) {
      // Only break //after// visiting `stop`.
      break;
    }
    ("production" !== process.env.NODE_ENV ? invariant(
      depth++ < MAX_TREE_DEPTH,
      'traverseParentPath(%s, %s, ...): Detected an infinite loop while ' +
      'traversing the React DOM ID tree. This may be due to malformed IDs: %s',
      start, stop
    ) : invariant(depth++ < MAX_TREE_DEPTH));
  }
}

/**
 * Manages the IDs assigned to DOM representations of React components. This
 * uses a specific scheme in order to traverse the DOM efficiently (e.g. in
 * order to simulate events).
 *
 * @internal
 */
var ReactInstanceHandles = {

  /**
   * Constructs a React root ID
   * @return {string} A React root ID.
   */
  createReactRootID: function() {
    return getReactRootIDString(ReactRootIndex.createReactRootIndex());
  },

  /**
   * Constructs a React ID by joining a root ID with a name.
   *
   * @param {string} rootID Root ID of a parent component.
   * @param {string} name A component's name (as flattened children).
   * @return {string} A React ID.
   * @internal
   */
  createReactID: function(rootID, name) {
    return rootID + name;
  },

  /**
   * Gets the DOM ID of the React component that is the root of the tree that
   * contains the React component with the supplied DOM ID.
   *
   * @param {string} id DOM ID of a React component.
   * @return {?string} DOM ID of the React component that is the root.
   * @internal
   */
  getReactRootIDFromNodeID: function(id) {
    if (id && id.charAt(0) === SEPARATOR && id.length > 1) {
      var index = id.indexOf(SEPARATOR, 1);
      return index > -1 ? id.substr(0, index) : id;
    }
    return null;
  },

  /**
   * Traverses the ID hierarchy and invokes the supplied `cb` on any IDs that
   * should would receive a `mouseEnter` or `mouseLeave` event.
   *
   * NOTE: Does not invoke the callback on the nearest common ancestor because
   * nothing "entered" or "left" that element.
   *
   * @param {string} leaveID ID being left.
   * @param {string} enterID ID being entered.
   * @param {function} cb Callback to invoke on each entered/left ID.
   * @param {*} upArg Argument to invoke the callback with on left IDs.
   * @param {*} downArg Argument to invoke the callback with on entered IDs.
   * @internal
   */
  traverseEnterLeave: function(leaveID, enterID, cb, upArg, downArg) {
    var ancestorID = getFirstCommonAncestorID(leaveID, enterID);
    if (ancestorID !== leaveID) {
      traverseParentPath(leaveID, ancestorID, cb, upArg, false, true);
    }
    if (ancestorID !== enterID) {
      traverseParentPath(ancestorID, enterID, cb, downArg, true, false);
    }
  },

  /**
   * Simulates the traversal of a two-phase, capture/bubble event dispatch.
   *
   * NOTE: This traversal happens on IDs without touching the DOM.
   *
   * @param {string} targetID ID of the target node.
   * @param {function} cb Callback to invoke.
   * @param {*} arg Argument to invoke the callback with.
   * @internal
   */
  traverseTwoPhase: function(targetID, cb, arg) {
    if (targetID) {
      traverseParentPath('', targetID, cb, arg, true, false);
      traverseParentPath(targetID, '', cb, arg, false, true);
    }
  },

  /**
   * Traverse a node ID, calling the supplied `cb` for each ancestor ID. For
   * example, passing `.0.$row-0.1` would result in `cb` getting called
   * with `.0`, `.0.$row-0`, and `.0.$row-0.1`.
   *
   * NOTE: This traversal happens on IDs without touching the DOM.
   *
   * @param {string} targetID ID of the target node.
   * @param {function} cb Callback to invoke.
   * @param {*} arg Argument to invoke the callback with.
   * @internal
   */
  traverseAncestors: function(targetID, cb, arg) {
    traverseParentPath('', targetID, cb, arg, true, false);
  },

  /**
   * Exposed for unit testing.
   * @private
   */
  _getFirstCommonAncestorID: getFirstCommonAncestorID,

  /**
   * Exposed for unit testing.
   * @private
   */
  _getNextDescendantID: getNextDescendantID,

  isAncestorIDOf: isAncestorIDOf,

  SEPARATOR: SEPARATOR

};

module.exports = ReactInstanceHandles;

}).call(this,require('_process'))
},{"./ReactRootIndex":"/Users/zordius/webtasks/node_modules/react/lib/ReactRootIndex.js","./invariant":"/Users/zordius/webtasks/node_modules/react/lib/invariant.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactLegacyElement.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactLegacyElement
 */

"use strict";

var ReactCurrentOwner = require("./ReactCurrentOwner");

var invariant = require("./invariant");
var monitorCodeUse = require("./monitorCodeUse");
var warning = require("./warning");

var legacyFactoryLogs = {};
function warnForLegacyFactoryCall() {
  if (!ReactLegacyElementFactory._isLegacyCallWarningEnabled) {
    return;
  }
  var owner = ReactCurrentOwner.current;
  var name = owner && owner.constructor ? owner.constructor.displayName : '';
  if (!name) {
    name = 'Something';
  }
  if (legacyFactoryLogs.hasOwnProperty(name)) {
    return;
  }
  legacyFactoryLogs[name] = true;
  ("production" !== process.env.NODE_ENV ? warning(
    false,
    name + ' is calling a React component directly. ' +
    'Use a factory or JSX instead. See: http://fb.me/react-legacyfactory'
  ) : null);
  monitorCodeUse('react_legacy_factory_call', { version: 3, name: name });
}

function warnForPlainFunctionType(type) {
  var isReactClass =
    type.prototype &&
    typeof type.prototype.mountComponent === 'function' &&
    typeof type.prototype.receiveComponent === 'function';
  if (isReactClass) {
    ("production" !== process.env.NODE_ENV ? warning(
      false,
      'Did not expect to get a React class here. Use `Component` instead ' +
      'of `Component.type` or `this.constructor`.'
    ) : null);
  } else {
    if (!type._reactWarnedForThisType) {
      try {
        type._reactWarnedForThisType = true;
      } catch (x) {
        // just incase this is a frozen object or some special object
      }
      monitorCodeUse(
        'react_non_component_in_jsx',
        { version: 3, name: type.name }
      );
    }
    ("production" !== process.env.NODE_ENV ? warning(
      false,
      'This JSX uses a plain function. Only React components are ' +
      'valid in React\'s JSX transform.'
    ) : null);
  }
}

function warnForNonLegacyFactory(type) {
  ("production" !== process.env.NODE_ENV ? warning(
    false,
    'Do not pass React.DOM.' + type.type + ' to JSX or createFactory. ' +
    'Use the string "' + type.type + '" instead.'
  ) : null);
}

/**
 * Transfer static properties from the source to the target. Functions are
 * rebound to have this reflect the original source.
 */
function proxyStaticMethods(target, source) {
  if (typeof source !== 'function') {
    return;
  }
  for (var key in source) {
    if (source.hasOwnProperty(key)) {
      var value = source[key];
      if (typeof value === 'function') {
        var bound = value.bind(source);
        // Copy any properties defined on the function, such as `isRequired` on
        // a PropTypes validator.
        for (var k in value) {
          if (value.hasOwnProperty(k)) {
            bound[k] = value[k];
          }
        }
        target[key] = bound;
      } else {
        target[key] = value;
      }
    }
  }
}

// We use an object instead of a boolean because booleans are ignored by our
// mocking libraries when these factories gets mocked.
var LEGACY_MARKER = {};
var NON_LEGACY_MARKER = {};

var ReactLegacyElementFactory = {};

ReactLegacyElementFactory.wrapCreateFactory = function(createFactory) {
  var legacyCreateFactory = function(type) {
    if (typeof type !== 'function') {
      // Non-function types cannot be legacy factories
      return createFactory(type);
    }

    if (type.isReactNonLegacyFactory) {
      // This is probably a factory created by ReactDOM we unwrap it to get to
      // the underlying string type. It shouldn't have been passed here so we
      // warn.
      if ("production" !== process.env.NODE_ENV) {
        warnForNonLegacyFactory(type);
      }
      return createFactory(type.type);
    }

    if (type.isReactLegacyFactory) {
      // This is probably a legacy factory created by ReactCompositeComponent.
      // We unwrap it to get to the underlying class.
      return createFactory(type.type);
    }

    if ("production" !== process.env.NODE_ENV) {
      warnForPlainFunctionType(type);
    }

    // Unless it's a legacy factory, then this is probably a plain function,
    // that is expecting to be invoked by JSX. We can just return it as is.
    return type;
  };
  return legacyCreateFactory;
};

ReactLegacyElementFactory.wrapCreateElement = function(createElement) {
  var legacyCreateElement = function(type, props, children) {
    if (typeof type !== 'function') {
      // Non-function types cannot be legacy factories
      return createElement.apply(this, arguments);
    }

    var args;

    if (type.isReactNonLegacyFactory) {
      // This is probably a factory created by ReactDOM we unwrap it to get to
      // the underlying string type. It shouldn't have been passed here so we
      // warn.
      if ("production" !== process.env.NODE_ENV) {
        warnForNonLegacyFactory(type);
      }
      args = Array.prototype.slice.call(arguments, 0);
      args[0] = type.type;
      return createElement.apply(this, args);
    }

    if (type.isReactLegacyFactory) {
      // This is probably a legacy factory created by ReactCompositeComponent.
      // We unwrap it to get to the underlying class.
      if (type._isMockFunction) {
        // If this is a mock function, people will expect it to be called. We
        // will actually call the original mock factory function instead. This
        // future proofs unit testing that assume that these are classes.
        type.type._mockedReactClassConstructor = type;
      }
      args = Array.prototype.slice.call(arguments, 0);
      args[0] = type.type;
      return createElement.apply(this, args);
    }

    if ("production" !== process.env.NODE_ENV) {
      warnForPlainFunctionType(type);
    }

    // This is being called with a plain function we should invoke it
    // immediately as if this was used with legacy JSX.
    return type.apply(null, Array.prototype.slice.call(arguments, 1));
  };
  return legacyCreateElement;
};

ReactLegacyElementFactory.wrapFactory = function(factory) {
  ("production" !== process.env.NODE_ENV ? invariant(
    typeof factory === 'function',
    'This is suppose to accept a element factory'
  ) : invariant(typeof factory === 'function'));
  var legacyElementFactory = function(config, children) {
    // This factory should not be called when JSX is used. Use JSX instead.
    if ("production" !== process.env.NODE_ENV) {
      warnForLegacyFactoryCall();
    }
    return factory.apply(this, arguments);
  };
  proxyStaticMethods(legacyElementFactory, factory.type);
  legacyElementFactory.isReactLegacyFactory = LEGACY_MARKER;
  legacyElementFactory.type = factory.type;
  return legacyElementFactory;
};

// This is used to mark a factory that will remain. E.g. we're allowed to call
// it as a function. However, you're not suppose to pass it to createElement
// or createFactory, so it will warn you if you do.
ReactLegacyElementFactory.markNonLegacyFactory = function(factory) {
  factory.isReactNonLegacyFactory = NON_LEGACY_MARKER;
  return factory;
};

// Checks if a factory function is actually a legacy factory pretending to
// be a class.
ReactLegacyElementFactory.isValidFactory = function(factory) {
  // TODO: This will be removed and moved into a class validator or something.
  return typeof factory === 'function' &&
    factory.isReactLegacyFactory === LEGACY_MARKER;
};

ReactLegacyElementFactory.isValidClass = function(factory) {
  if ("production" !== process.env.NODE_ENV) {
    ("production" !== process.env.NODE_ENV ? warning(
      false,
      'isValidClass is deprecated and will be removed in a future release. ' +
      'Use a more specific validator instead.'
    ) : null);
  }
  return ReactLegacyElementFactory.isValidFactory(factory);
};

ReactLegacyElementFactory._isLegacyCallWarningEnabled = true;

module.exports = ReactLegacyElementFactory;

}).call(this,require('_process'))
},{"./ReactCurrentOwner":"/Users/zordius/webtasks/node_modules/react/lib/ReactCurrentOwner.js","./invariant":"/Users/zordius/webtasks/node_modules/react/lib/invariant.js","./monitorCodeUse":"/Users/zordius/webtasks/node_modules/react/lib/monitorCodeUse.js","./warning":"/Users/zordius/webtasks/node_modules/react/lib/warning.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactMarkupChecksum.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactMarkupChecksum
 */

"use strict";

var adler32 = require("./adler32");

var ReactMarkupChecksum = {
  CHECKSUM_ATTR_NAME: 'data-react-checksum',

  /**
   * @param {string} markup Markup string
   * @return {string} Markup string with checksum attribute attached
   */
  addChecksumToMarkup: function(markup) {
    var checksum = adler32(markup);
    return markup.replace(
      '>',
      ' ' + ReactMarkupChecksum.CHECKSUM_ATTR_NAME + '="' + checksum + '">'
    );
  },

  /**
   * @param {string} markup to use
   * @param {DOMElement} element root React element
   * @returns {boolean} whether or not the markup is the same
   */
  canReuseMarkup: function(markup, element) {
    var existingChecksum = element.getAttribute(
      ReactMarkupChecksum.CHECKSUM_ATTR_NAME
    );
    existingChecksum = existingChecksum && parseInt(existingChecksum, 10);
    var markupChecksum = adler32(markup);
    return markupChecksum === existingChecksum;
  }
};

module.exports = ReactMarkupChecksum;

},{"./adler32":"/Users/zordius/webtasks/node_modules/react/lib/adler32.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactMount.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactMount
 */

"use strict";

var DOMProperty = require("./DOMProperty");
var ReactBrowserEventEmitter = require("./ReactBrowserEventEmitter");
var ReactCurrentOwner = require("./ReactCurrentOwner");
var ReactElement = require("./ReactElement");
var ReactLegacyElement = require("./ReactLegacyElement");
var ReactInstanceHandles = require("./ReactInstanceHandles");
var ReactPerf = require("./ReactPerf");

var containsNode = require("./containsNode");
var deprecated = require("./deprecated");
var getReactRootElementInContainer = require("./getReactRootElementInContainer");
var instantiateReactComponent = require("./instantiateReactComponent");
var invariant = require("./invariant");
var shouldUpdateReactComponent = require("./shouldUpdateReactComponent");
var warning = require("./warning");

var createElement = ReactLegacyElement.wrapCreateElement(
  ReactElement.createElement
);

var SEPARATOR = ReactInstanceHandles.SEPARATOR;

var ATTR_NAME = DOMProperty.ID_ATTRIBUTE_NAME;
var nodeCache = {};

var ELEMENT_NODE_TYPE = 1;
var DOC_NODE_TYPE = 9;

/** Mapping from reactRootID to React component instance. */
var instancesByReactRootID = {};

/** Mapping from reactRootID to `container` nodes. */
var containersByReactRootID = {};

if ("production" !== process.env.NODE_ENV) {
  /** __DEV__-only mapping from reactRootID to root elements. */
  var rootElementsByReactRootID = {};
}

// Used to store breadth-first search state in findComponentRoot.
var findComponentRootReusableArray = [];

/**
 * @param {DOMElement} container DOM element that may contain a React component.
 * @return {?string} A "reactRoot" ID, if a React component is rendered.
 */
function getReactRootID(container) {
  var rootElement = getReactRootElementInContainer(container);
  return rootElement && ReactMount.getID(rootElement);
}

/**
 * Accessing node[ATTR_NAME] or calling getAttribute(ATTR_NAME) on a form
 * element can return its control whose name or ID equals ATTR_NAME. All
 * DOM nodes support `getAttributeNode` but this can also get called on
 * other objects so just return '' if we're given something other than a
 * DOM node (such as window).
 *
 * @param {?DOMElement|DOMWindow|DOMDocument|DOMTextNode} node DOM node.
 * @return {string} ID of the supplied `domNode`.
 */
function getID(node) {
  var id = internalGetID(node);
  if (id) {
    if (nodeCache.hasOwnProperty(id)) {
      var cached = nodeCache[id];
      if (cached !== node) {
        ("production" !== process.env.NODE_ENV ? invariant(
          !isValid(cached, id),
          'ReactMount: Two valid but unequal nodes with the same `%s`: %s',
          ATTR_NAME, id
        ) : invariant(!isValid(cached, id)));

        nodeCache[id] = node;
      }
    } else {
      nodeCache[id] = node;
    }
  }

  return id;
}

function internalGetID(node) {
  // If node is something like a window, document, or text node, none of
  // which support attributes or a .getAttribute method, gracefully return
  // the empty string, as if the attribute were missing.
  return node && node.getAttribute && node.getAttribute(ATTR_NAME) || '';
}

/**
 * Sets the React-specific ID of the given node.
 *
 * @param {DOMElement} node The DOM node whose ID will be set.
 * @param {string} id The value of the ID attribute.
 */
function setID(node, id) {
  var oldID = internalGetID(node);
  if (oldID !== id) {
    delete nodeCache[oldID];
  }
  node.setAttribute(ATTR_NAME, id);
  nodeCache[id] = node;
}

/**
 * Finds the node with the supplied React-generated DOM ID.
 *
 * @param {string} id A React-generated DOM ID.
 * @return {DOMElement} DOM node with the suppled `id`.
 * @internal
 */
function getNode(id) {
  if (!nodeCache.hasOwnProperty(id) || !isValid(nodeCache[id], id)) {
    nodeCache[id] = ReactMount.findReactNodeByID(id);
  }
  return nodeCache[id];
}

/**
 * A node is "valid" if it is contained by a currently mounted container.
 *
 * This means that the node does not have to be contained by a document in
 * order to be considered valid.
 *
 * @param {?DOMElement} node The candidate DOM node.
 * @param {string} id The expected ID of the node.
 * @return {boolean} Whether the node is contained by a mounted container.
 */
function isValid(node, id) {
  if (node) {
    ("production" !== process.env.NODE_ENV ? invariant(
      internalGetID(node) === id,
      'ReactMount: Unexpected modification of `%s`',
      ATTR_NAME
    ) : invariant(internalGetID(node) === id));

    var container = ReactMount.findReactContainerForID(id);
    if (container && containsNode(container, node)) {
      return true;
    }
  }

  return false;
}

/**
 * Causes the cache to forget about one React-specific ID.
 *
 * @param {string} id The ID to forget.
 */
function purgeID(id) {
  delete nodeCache[id];
}

var deepestNodeSoFar = null;
function findDeepestCachedAncestorImpl(ancestorID) {
  var ancestor = nodeCache[ancestorID];
  if (ancestor && isValid(ancestor, ancestorID)) {
    deepestNodeSoFar = ancestor;
  } else {
    // This node isn't populated in the cache, so presumably none of its
    // descendants are. Break out of the loop.
    return false;
  }
}

/**
 * Return the deepest cached node whose ID is a prefix of `targetID`.
 */
function findDeepestCachedAncestor(targetID) {
  deepestNodeSoFar = null;
  ReactInstanceHandles.traverseAncestors(
    targetID,
    findDeepestCachedAncestorImpl
  );

  var foundNode = deepestNodeSoFar;
  deepestNodeSoFar = null;
  return foundNode;
}

/**
 * Mounting is the process of initializing a React component by creatings its
 * representative DOM elements and inserting them into a supplied `container`.
 * Any prior content inside `container` is destroyed in the process.
 *
 *   ReactMount.render(
 *     component,
 *     document.getElementById('container')
 *   );
 *
 *   <div id="container">                   <-- Supplied `container`.
 *     <div data-reactid=".3">              <-- Rendered reactRoot of React
 *       // ...                                 component.
 *     </div>
 *   </div>
 *
 * Inside of `container`, the first element rendered is the "reactRoot".
 */
var ReactMount = {
  /** Exposed for debugging purposes **/
  _instancesByReactRootID: instancesByReactRootID,

  /**
   * This is a hook provided to support rendering React components while
   * ensuring that the apparent scroll position of its `container` does not
   * change.
   *
   * @param {DOMElement} container The `container` being rendered into.
   * @param {function} renderCallback This must be called once to do the render.
   */
  scrollMonitor: function(container, renderCallback) {
    renderCallback();
  },

  /**
   * Take a component that's already mounted into the DOM and replace its props
   * @param {ReactComponent} prevComponent component instance already in the DOM
   * @param {ReactComponent} nextComponent component instance to render
   * @param {DOMElement} container container to render into
   * @param {?function} callback function triggered on completion
   */
  _updateRootComponent: function(
      prevComponent,
      nextComponent,
      container,
      callback) {
    var nextProps = nextComponent.props;
    ReactMount.scrollMonitor(container, function() {
      prevComponent.replaceProps(nextProps, callback);
    });

    if ("production" !== process.env.NODE_ENV) {
      // Record the root element in case it later gets transplanted.
      rootElementsByReactRootID[getReactRootID(container)] =
        getReactRootElementInContainer(container);
    }

    return prevComponent;
  },

  /**
   * Register a component into the instance map and starts scroll value
   * monitoring
   * @param {ReactComponent} nextComponent component instance to render
   * @param {DOMElement} container container to render into
   * @return {string} reactRoot ID prefix
   */
  _registerComponent: function(nextComponent, container) {
    ("production" !== process.env.NODE_ENV ? invariant(
      container && (
        container.nodeType === ELEMENT_NODE_TYPE ||
        container.nodeType === DOC_NODE_TYPE
      ),
      '_registerComponent(...): Target container is not a DOM element.'
    ) : invariant(container && (
      container.nodeType === ELEMENT_NODE_TYPE ||
      container.nodeType === DOC_NODE_TYPE
    )));

    ReactBrowserEventEmitter.ensureScrollValueMonitoring();

    var reactRootID = ReactMount.registerContainer(container);
    instancesByReactRootID[reactRootID] = nextComponent;
    return reactRootID;
  },

  /**
   * Render a new component into the DOM.
   * @param {ReactComponent} nextComponent component instance to render
   * @param {DOMElement} container container to render into
   * @param {boolean} shouldReuseMarkup if we should skip the markup insertion
   * @return {ReactComponent} nextComponent
   */
  _renderNewRootComponent: ReactPerf.measure(
    'ReactMount',
    '_renderNewRootComponent',
    function(
        nextComponent,
        container,
        shouldReuseMarkup) {
      // Various parts of our code (such as ReactCompositeComponent's
      // _renderValidatedComponent) assume that calls to render aren't nested;
      // verify that that's the case.
      ("production" !== process.env.NODE_ENV ? warning(
        ReactCurrentOwner.current == null,
        '_renderNewRootComponent(): Render methods should be a pure function ' +
        'of props and state; triggering nested component updates from ' +
        'render is not allowed. If necessary, trigger nested updates in ' +
        'componentDidUpdate.'
      ) : null);

      var componentInstance = instantiateReactComponent(nextComponent, null);
      var reactRootID = ReactMount._registerComponent(
        componentInstance,
        container
      );
      componentInstance.mountComponentIntoNode(
        reactRootID,
        container,
        shouldReuseMarkup
      );

      if ("production" !== process.env.NODE_ENV) {
        // Record the root element in case it later gets transplanted.
        rootElementsByReactRootID[reactRootID] =
          getReactRootElementInContainer(container);
      }

      return componentInstance;
    }
  ),

  /**
   * Renders a React component into the DOM in the supplied `container`.
   *
   * If the React component was previously rendered into `container`, this will
   * perform an update on it and only mutate the DOM as necessary to reflect the
   * latest React component.
   *
   * @param {ReactElement} nextElement Component element to render.
   * @param {DOMElement} container DOM element to render into.
   * @param {?function} callback function triggered on completion
   * @return {ReactComponent} Component instance rendered in `container`.
   */
  render: function(nextElement, container, callback) {
    ("production" !== process.env.NODE_ENV ? invariant(
      ReactElement.isValidElement(nextElement),
      'renderComponent(): Invalid component element.%s',
      (
        typeof nextElement === 'string' ?
          ' Instead of passing an element string, make sure to instantiate ' +
          'it by passing it to React.createElement.' :
        ReactLegacyElement.isValidFactory(nextElement) ?
          ' Instead of passing a component class, make sure to instantiate ' +
          'it by passing it to React.createElement.' :
        // Check if it quacks like a element
        typeof nextElement.props !== "undefined" ?
          ' This may be caused by unintentionally loading two independent ' +
          'copies of React.' :
          ''
      )
    ) : invariant(ReactElement.isValidElement(nextElement)));

    var prevComponent = instancesByReactRootID[getReactRootID(container)];

    if (prevComponent) {
      var prevElement = prevComponent._currentElement;
      if (shouldUpdateReactComponent(prevElement, nextElement)) {
        return ReactMount._updateRootComponent(
          prevComponent,
          nextElement,
          container,
          callback
        );
      } else {
        ReactMount.unmountComponentAtNode(container);
      }
    }

    var reactRootElement = getReactRootElementInContainer(container);
    var containerHasReactMarkup =
      reactRootElement && ReactMount.isRenderedByReact(reactRootElement);

    var shouldReuseMarkup = containerHasReactMarkup && !prevComponent;

    var component = ReactMount._renderNewRootComponent(
      nextElement,
      container,
      shouldReuseMarkup
    );
    callback && callback.call(component);
    return component;
  },

  /**
   * Constructs a component instance of `constructor` with `initialProps` and
   * renders it into the supplied `container`.
   *
   * @param {function} constructor React component constructor.
   * @param {?object} props Initial props of the component instance.
   * @param {DOMElement} container DOM element to render into.
   * @return {ReactComponent} Component instance rendered in `container`.
   */
  constructAndRenderComponent: function(constructor, props, container) {
    var element = createElement(constructor, props);
    return ReactMount.render(element, container);
  },

  /**
   * Constructs a component instance of `constructor` with `initialProps` and
   * renders it into a container node identified by supplied `id`.
   *
   * @param {function} componentConstructor React component constructor
   * @param {?object} props Initial props of the component instance.
   * @param {string} id ID of the DOM element to render into.
   * @return {ReactComponent} Component instance rendered in the container node.
   */
  constructAndRenderComponentByID: function(constructor, props, id) {
    var domNode = document.getElementById(id);
    ("production" !== process.env.NODE_ENV ? invariant(
      domNode,
      'Tried to get element with id of "%s" but it is not present on the page.',
      id
    ) : invariant(domNode));
    return ReactMount.constructAndRenderComponent(constructor, props, domNode);
  },

  /**
   * Registers a container node into which React components will be rendered.
   * This also creates the "reactRoot" ID that will be assigned to the element
   * rendered within.
   *
   * @param {DOMElement} container DOM element to register as a container.
   * @return {string} The "reactRoot" ID of elements rendered within.
   */
  registerContainer: function(container) {
    var reactRootID = getReactRootID(container);
    if (reactRootID) {
      // If one exists, make sure it is a valid "reactRoot" ID.
      reactRootID = ReactInstanceHandles.getReactRootIDFromNodeID(reactRootID);
    }
    if (!reactRootID) {
      // No valid "reactRoot" ID found, create one.
      reactRootID = ReactInstanceHandles.createReactRootID();
    }
    containersByReactRootID[reactRootID] = container;
    return reactRootID;
  },

  /**
   * Unmounts and destroys the React component rendered in the `container`.
   *
   * @param {DOMElement} container DOM element containing a React component.
   * @return {boolean} True if a component was found in and unmounted from
   *                   `container`
   */
  unmountComponentAtNode: function(container) {
    // Various parts of our code (such as ReactCompositeComponent's
    // _renderValidatedComponent) assume that calls to render aren't nested;
    // verify that that's the case. (Strictly speaking, unmounting won't cause a
    // render but we still don't expect to be in a render call here.)
    ("production" !== process.env.NODE_ENV ? warning(
      ReactCurrentOwner.current == null,
      'unmountComponentAtNode(): Render methods should be a pure function of ' +
      'props and state; triggering nested component updates from render is ' +
      'not allowed. If necessary, trigger nested updates in ' +
      'componentDidUpdate.'
    ) : null);

    var reactRootID = getReactRootID(container);
    var component = instancesByReactRootID[reactRootID];
    if (!component) {
      return false;
    }
    ReactMount.unmountComponentFromNode(component, container);
    delete instancesByReactRootID[reactRootID];
    delete containersByReactRootID[reactRootID];
    if ("production" !== process.env.NODE_ENV) {
      delete rootElementsByReactRootID[reactRootID];
    }
    return true;
  },

  /**
   * Unmounts a component and removes it from the DOM.
   *
   * @param {ReactComponent} instance React component instance.
   * @param {DOMElement} container DOM element to unmount from.
   * @final
   * @internal
   * @see {ReactMount.unmountComponentAtNode}
   */
  unmountComponentFromNode: function(instance, container) {
    instance.unmountComponent();

    if (container.nodeType === DOC_NODE_TYPE) {
      container = container.documentElement;
    }

    // http://jsperf.com/emptying-a-node
    while (container.lastChild) {
      container.removeChild(container.lastChild);
    }
  },

  /**
   * Finds the container DOM element that contains React component to which the
   * supplied DOM `id` belongs.
   *
   * @param {string} id The ID of an element rendered by a React component.
   * @return {?DOMElement} DOM element that contains the `id`.
   */
  findReactContainerForID: function(id) {
    var reactRootID = ReactInstanceHandles.getReactRootIDFromNodeID(id);
    var container = containersByReactRootID[reactRootID];

    if ("production" !== process.env.NODE_ENV) {
      var rootElement = rootElementsByReactRootID[reactRootID];
      if (rootElement && rootElement.parentNode !== container) {
        ("production" !== process.env.NODE_ENV ? invariant(
          // Call internalGetID here because getID calls isValid which calls
          // findReactContainerForID (this function).
          internalGetID(rootElement) === reactRootID,
          'ReactMount: Root element ID differed from reactRootID.'
        ) : invariant(// Call internalGetID here because getID calls isValid which calls
        // findReactContainerForID (this function).
        internalGetID(rootElement) === reactRootID));

        var containerChild = container.firstChild;
        if (containerChild &&
            reactRootID === internalGetID(containerChild)) {
          // If the container has a new child with the same ID as the old
          // root element, then rootElementsByReactRootID[reactRootID] is
          // just stale and needs to be updated. The case that deserves a
          // warning is when the container is empty.
          rootElementsByReactRootID[reactRootID] = containerChild;
        } else {
          console.warn(
            'ReactMount: Root element has been removed from its original ' +
            'container. New container:', rootElement.parentNode
          );
        }
      }
    }

    return container;
  },

  /**
   * Finds an element rendered by React with the supplied ID.
   *
   * @param {string} id ID of a DOM node in the React component.
   * @return {DOMElement} Root DOM node of the React component.
   */
  findReactNodeByID: function(id) {
    var reactRoot = ReactMount.findReactContainerForID(id);
    return ReactMount.findComponentRoot(reactRoot, id);
  },

  /**
   * True if the supplied `node` is rendered by React.
   *
   * @param {*} node DOM Element to check.
   * @return {boolean} True if the DOM Element appears to be rendered by React.
   * @internal
   */
  isRenderedByReact: function(node) {
    if (node.nodeType !== 1) {
      // Not a DOMElement, therefore not a React component
      return false;
    }
    var id = ReactMount.getID(node);
    return id ? id.charAt(0) === SEPARATOR : false;
  },

  /**
   * Traverses up the ancestors of the supplied node to find a node that is a
   * DOM representation of a React component.
   *
   * @param {*} node
   * @return {?DOMEventTarget}
   * @internal
   */
  getFirstReactDOM: function(node) {
    var current = node;
    while (current && current.parentNode !== current) {
      if (ReactMount.isRenderedByReact(current)) {
        return current;
      }
      current = current.parentNode;
    }
    return null;
  },

  /**
   * Finds a node with the supplied `targetID` inside of the supplied
   * `ancestorNode`.  Exploits the ID naming scheme to perform the search
   * quickly.
   *
   * @param {DOMEventTarget} ancestorNode Search from this root.
   * @pararm {string} targetID ID of the DOM representation of the component.
   * @return {DOMEventTarget} DOM node with the supplied `targetID`.
   * @internal
   */
  findComponentRoot: function(ancestorNode, targetID) {
    var firstChildren = findComponentRootReusableArray;
    var childIndex = 0;

    var deepestAncestor = findDeepestCachedAncestor(targetID) || ancestorNode;

    firstChildren[0] = deepestAncestor.firstChild;
    firstChildren.length = 1;

    while (childIndex < firstChildren.length) {
      var child = firstChildren[childIndex++];
      var targetChild;

      while (child) {
        var childID = ReactMount.getID(child);
        if (childID) {
          // Even if we find the node we're looking for, we finish looping
          // through its siblings to ensure they're cached so that we don't have
          // to revisit this node again. Otherwise, we make n^2 calls to getID
          // when visiting the many children of a single node in order.

          if (targetID === childID) {
            targetChild = child;
          } else if (ReactInstanceHandles.isAncestorIDOf(childID, targetID)) {
            // If we find a child whose ID is an ancestor of the given ID,
            // then we can be sure that we only want to search the subtree
            // rooted at this child, so we can throw out the rest of the
            // search state.
            firstChildren.length = childIndex = 0;
            firstChildren.push(child.firstChild);
          }

        } else {
          // If this child had no ID, then there's a chance that it was
          // injected automatically by the browser, as when a `<table>`
          // element sprouts an extra `<tbody>` child as a side effect of
          // `.innerHTML` parsing. Optimistically continue down this
          // branch, but not before examining the other siblings.
          firstChildren.push(child.firstChild);
        }

        child = child.nextSibling;
      }

      if (targetChild) {
        // Emptying firstChildren/findComponentRootReusableArray is
        // not necessary for correctness, but it helps the GC reclaim
        // any nodes that were left at the end of the search.
        firstChildren.length = 0;

        return targetChild;
      }
    }

    firstChildren.length = 0;

    ("production" !== process.env.NODE_ENV ? invariant(
      false,
      'findComponentRoot(..., %s): Unable to find element. This probably ' +
      'means the DOM was unexpectedly mutated (e.g., by the browser), ' +
      'usually due to forgetting a <tbody> when using tables, nesting tags ' +
      'like <form>, <p>, or <a>, or using non-SVG elements in an <svg> ' +
      'parent. ' +
      'Try inspecting the child nodes of the element with React ID `%s`.',
      targetID,
      ReactMount.getID(ancestorNode)
    ) : invariant(false));
  },


  /**
   * React ID utilities.
   */

  getReactRootID: getReactRootID,

  getID: getID,

  setID: setID,

  getNode: getNode,

  purgeID: purgeID
};

// Deprecations (remove for 0.13)
ReactMount.renderComponent = deprecated(
  'ReactMount',
  'renderComponent',
  'render',
  this,
  ReactMount.render
);

module.exports = ReactMount;

}).call(this,require('_process'))
},{"./DOMProperty":"/Users/zordius/webtasks/node_modules/react/lib/DOMProperty.js","./ReactBrowserEventEmitter":"/Users/zordius/webtasks/node_modules/react/lib/ReactBrowserEventEmitter.js","./ReactCurrentOwner":"/Users/zordius/webtasks/node_modules/react/lib/ReactCurrentOwner.js","./ReactElement":"/Users/zordius/webtasks/node_modules/react/lib/ReactElement.js","./ReactInstanceHandles":"/Users/zordius/webtasks/node_modules/react/lib/ReactInstanceHandles.js","./ReactLegacyElement":"/Users/zordius/webtasks/node_modules/react/lib/ReactLegacyElement.js","./ReactPerf":"/Users/zordius/webtasks/node_modules/react/lib/ReactPerf.js","./containsNode":"/Users/zordius/webtasks/node_modules/react/lib/containsNode.js","./deprecated":"/Users/zordius/webtasks/node_modules/react/lib/deprecated.js","./getReactRootElementInContainer":"/Users/zordius/webtasks/node_modules/react/lib/getReactRootElementInContainer.js","./instantiateReactComponent":"/Users/zordius/webtasks/node_modules/react/lib/instantiateReactComponent.js","./invariant":"/Users/zordius/webtasks/node_modules/react/lib/invariant.js","./shouldUpdateReactComponent":"/Users/zordius/webtasks/node_modules/react/lib/shouldUpdateReactComponent.js","./warning":"/Users/zordius/webtasks/node_modules/react/lib/warning.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactMultiChild.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactMultiChild
 * @typechecks static-only
 */

"use strict";

var ReactComponent = require("./ReactComponent");
var ReactMultiChildUpdateTypes = require("./ReactMultiChildUpdateTypes");

var flattenChildren = require("./flattenChildren");
var instantiateReactComponent = require("./instantiateReactComponent");
var shouldUpdateReactComponent = require("./shouldUpdateReactComponent");

/**
 * Updating children of a component may trigger recursive updates. The depth is
 * used to batch recursive updates to render markup more efficiently.
 *
 * @type {number}
 * @private
 */
var updateDepth = 0;

/**
 * Queue of update configuration objects.
 *
 * Each object has a `type` property that is in `ReactMultiChildUpdateTypes`.
 *
 * @type {array<object>}
 * @private
 */
var updateQueue = [];

/**
 * Queue of markup to be rendered.
 *
 * @type {array<string>}
 * @private
 */
var markupQueue = [];

/**
 * Enqueues markup to be rendered and inserted at a supplied index.
 *
 * @param {string} parentID ID of the parent component.
 * @param {string} markup Markup that renders into an element.
 * @param {number} toIndex Destination index.
 * @private
 */
function enqueueMarkup(parentID, markup, toIndex) {
  // NOTE: Null values reduce hidden classes.
  updateQueue.push({
    parentID: parentID,
    parentNode: null,
    type: ReactMultiChildUpdateTypes.INSERT_MARKUP,
    markupIndex: markupQueue.push(markup) - 1,
    textContent: null,
    fromIndex: null,
    toIndex: toIndex
  });
}

/**
 * Enqueues moving an existing element to another index.
 *
 * @param {string} parentID ID of the parent component.
 * @param {number} fromIndex Source index of the existing element.
 * @param {number} toIndex Destination index of the element.
 * @private
 */
function enqueueMove(parentID, fromIndex, toIndex) {
  // NOTE: Null values reduce hidden classes.
  updateQueue.push({
    parentID: parentID,
    parentNode: null,
    type: ReactMultiChildUpdateTypes.MOVE_EXISTING,
    markupIndex: null,
    textContent: null,
    fromIndex: fromIndex,
    toIndex: toIndex
  });
}

/**
 * Enqueues removing an element at an index.
 *
 * @param {string} parentID ID of the parent component.
 * @param {number} fromIndex Index of the element to remove.
 * @private
 */
function enqueueRemove(parentID, fromIndex) {
  // NOTE: Null values reduce hidden classes.
  updateQueue.push({
    parentID: parentID,
    parentNode: null,
    type: ReactMultiChildUpdateTypes.REMOVE_NODE,
    markupIndex: null,
    textContent: null,
    fromIndex: fromIndex,
    toIndex: null
  });
}

/**
 * Enqueues setting the text content.
 *
 * @param {string} parentID ID of the parent component.
 * @param {string} textContent Text content to set.
 * @private
 */
function enqueueTextContent(parentID, textContent) {
  // NOTE: Null values reduce hidden classes.
  updateQueue.push({
    parentID: parentID,
    parentNode: null,
    type: ReactMultiChildUpdateTypes.TEXT_CONTENT,
    markupIndex: null,
    textContent: textContent,
    fromIndex: null,
    toIndex: null
  });
}

/**
 * Processes any enqueued updates.
 *
 * @private
 */
function processQueue() {
  if (updateQueue.length) {
    ReactComponent.BackendIDOperations.dangerouslyProcessChildrenUpdates(
      updateQueue,
      markupQueue
    );
    clearQueue();
  }
}

/**
 * Clears any enqueued updates.
 *
 * @private
 */
function clearQueue() {
  updateQueue.length = 0;
  markupQueue.length = 0;
}

/**
 * ReactMultiChild are capable of reconciling multiple children.
 *
 * @class ReactMultiChild
 * @internal
 */
var ReactMultiChild = {

  /**
   * Provides common functionality for components that must reconcile multiple
   * children. This is used by `ReactDOMComponent` to mount, update, and
   * unmount child components.
   *
   * @lends {ReactMultiChild.prototype}
   */
  Mixin: {

    /**
     * Generates a "mount image" for each of the supplied children. In the case
     * of `ReactDOMComponent`, a mount image is a string of markup.
     *
     * @param {?object} nestedChildren Nested child maps.
     * @return {array} An array of mounted representations.
     * @internal
     */
    mountChildren: function(nestedChildren, transaction) {
      var children = flattenChildren(nestedChildren);
      var mountImages = [];
      var index = 0;
      this._renderedChildren = children;
      for (var name in children) {
        var child = children[name];
        if (children.hasOwnProperty(name)) {
          // The rendered children must be turned into instances as they're
          // mounted.
          var childInstance = instantiateReactComponent(child, null);
          children[name] = childInstance;
          // Inlined for performance, see `ReactInstanceHandles.createReactID`.
          var rootID = this._rootNodeID + name;
          var mountImage = childInstance.mountComponent(
            rootID,
            transaction,
            this._mountDepth + 1
          );
          childInstance._mountIndex = index;
          mountImages.push(mountImage);
          index++;
        }
      }
      return mountImages;
    },

    /**
     * Replaces any rendered children with a text content string.
     *
     * @param {string} nextContent String of content.
     * @internal
     */
    updateTextContent: function(nextContent) {
      updateDepth++;
      var errorThrown = true;
      try {
        var prevChildren = this._renderedChildren;
        // Remove any rendered children.
        for (var name in prevChildren) {
          if (prevChildren.hasOwnProperty(name)) {
            this._unmountChildByName(prevChildren[name], name);
          }
        }
        // Set new text content.
        this.setTextContent(nextContent);
        errorThrown = false;
      } finally {
        updateDepth--;
        if (!updateDepth) {
          errorThrown ? clearQueue() : processQueue();
        }
      }
    },

    /**
     * Updates the rendered children with new children.
     *
     * @param {?object} nextNestedChildren Nested child maps.
     * @param {ReactReconcileTransaction} transaction
     * @internal
     */
    updateChildren: function(nextNestedChildren, transaction) {
      updateDepth++;
      var errorThrown = true;
      try {
        this._updateChildren(nextNestedChildren, transaction);
        errorThrown = false;
      } finally {
        updateDepth--;
        if (!updateDepth) {
          errorThrown ? clearQueue() : processQueue();
        }
      }
    },

    /**
     * Improve performance by isolating this hot code path from the try/catch
     * block in `updateChildren`.
     *
     * @param {?object} nextNestedChildren Nested child maps.
     * @param {ReactReconcileTransaction} transaction
     * @final
     * @protected
     */
    _updateChildren: function(nextNestedChildren, transaction) {
      var nextChildren = flattenChildren(nextNestedChildren);
      var prevChildren = this._renderedChildren;
      if (!nextChildren && !prevChildren) {
        return;
      }
      var name;
      // `nextIndex` will increment for each child in `nextChildren`, but
      // `lastIndex` will be the last index visited in `prevChildren`.
      var lastIndex = 0;
      var nextIndex = 0;
      for (name in nextChildren) {
        if (!nextChildren.hasOwnProperty(name)) {
          continue;
        }
        var prevChild = prevChildren && prevChildren[name];
        var prevElement = prevChild && prevChild._currentElement;
        var nextElement = nextChildren[name];
        if (shouldUpdateReactComponent(prevElement, nextElement)) {
          this.moveChild(prevChild, nextIndex, lastIndex);
          lastIndex = Math.max(prevChild._mountIndex, lastIndex);
          prevChild.receiveComponent(nextElement, transaction);
          prevChild._mountIndex = nextIndex;
        } else {
          if (prevChild) {
            // Update `lastIndex` before `_mountIndex` gets unset by unmounting.
            lastIndex = Math.max(prevChild._mountIndex, lastIndex);
            this._unmountChildByName(prevChild, name);
          }
          // The child must be instantiated before it's mounted.
          var nextChildInstance = instantiateReactComponent(
            nextElement,
            null
          );
          this._mountChildByNameAtIndex(
            nextChildInstance, name, nextIndex, transaction
          );
        }
        nextIndex++;
      }
      // Remove children that are no longer present.
      for (name in prevChildren) {
        if (prevChildren.hasOwnProperty(name) &&
            !(nextChildren && nextChildren[name])) {
          this._unmountChildByName(prevChildren[name], name);
        }
      }
    },

    /**
     * Unmounts all rendered children. This should be used to clean up children
     * when this component is unmounted.
     *
     * @internal
     */
    unmountChildren: function() {
      var renderedChildren = this._renderedChildren;
      for (var name in renderedChildren) {
        var renderedChild = renderedChildren[name];
        // TODO: When is this not true?
        if (renderedChild.unmountComponent) {
          renderedChild.unmountComponent();
        }
      }
      this._renderedChildren = null;
    },

    /**
     * Moves a child component to the supplied index.
     *
     * @param {ReactComponent} child Component to move.
     * @param {number} toIndex Destination index of the element.
     * @param {number} lastIndex Last index visited of the siblings of `child`.
     * @protected
     */
    moveChild: function(child, toIndex, lastIndex) {
      // If the index of `child` is less than `lastIndex`, then it needs to
      // be moved. Otherwise, we do not need to move it because a child will be
      // inserted or moved before `child`.
      if (child._mountIndex < lastIndex) {
        enqueueMove(this._rootNodeID, child._mountIndex, toIndex);
      }
    },

    /**
     * Creates a child component.
     *
     * @param {ReactComponent} child Component to create.
     * @param {string} mountImage Markup to insert.
     * @protected
     */
    createChild: function(child, mountImage) {
      enqueueMarkup(this._rootNodeID, mountImage, child._mountIndex);
    },

    /**
     * Removes a child component.
     *
     * @param {ReactComponent} child Child to remove.
     * @protected
     */
    removeChild: function(child) {
      enqueueRemove(this._rootNodeID, child._mountIndex);
    },

    /**
     * Sets this text content string.
     *
     * @param {string} textContent Text content to set.
     * @protected
     */
    setTextContent: function(textContent) {
      enqueueTextContent(this._rootNodeID, textContent);
    },

    /**
     * Mounts a child with the supplied name.
     *
     * NOTE: This is part of `updateChildren` and is here for readability.
     *
     * @param {ReactComponent} child Component to mount.
     * @param {string} name Name of the child.
     * @param {number} index Index at which to insert the child.
     * @param {ReactReconcileTransaction} transaction
     * @private
     */
    _mountChildByNameAtIndex: function(child, name, index, transaction) {
      // Inlined for performance, see `ReactInstanceHandles.createReactID`.
      var rootID = this._rootNodeID + name;
      var mountImage = child.mountComponent(
        rootID,
        transaction,
        this._mountDepth + 1
      );
      child._mountIndex = index;
      this.createChild(child, mountImage);
      this._renderedChildren = this._renderedChildren || {};
      this._renderedChildren[name] = child;
    },

    /**
     * Unmounts a rendered child by name.
     *
     * NOTE: This is part of `updateChildren` and is here for readability.
     *
     * @param {ReactComponent} child Component to unmount.
     * @param {string} name Name of the child in `this._renderedChildren`.
     * @private
     */
    _unmountChildByName: function(child, name) {
      this.removeChild(child);
      child._mountIndex = null;
      child.unmountComponent();
      delete this._renderedChildren[name];
    }

  }

};

module.exports = ReactMultiChild;

},{"./ReactComponent":"/Users/zordius/webtasks/node_modules/react/lib/ReactComponent.js","./ReactMultiChildUpdateTypes":"/Users/zordius/webtasks/node_modules/react/lib/ReactMultiChildUpdateTypes.js","./flattenChildren":"/Users/zordius/webtasks/node_modules/react/lib/flattenChildren.js","./instantiateReactComponent":"/Users/zordius/webtasks/node_modules/react/lib/instantiateReactComponent.js","./shouldUpdateReactComponent":"/Users/zordius/webtasks/node_modules/react/lib/shouldUpdateReactComponent.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactMultiChildUpdateTypes.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactMultiChildUpdateTypes
 */

"use strict";

var keyMirror = require("./keyMirror");

/**
 * When a component's children are updated, a series of update configuration
 * objects are created in order to batch and serialize the required changes.
 *
 * Enumerates all the possible types of update configurations.
 *
 * @internal
 */
var ReactMultiChildUpdateTypes = keyMirror({
  INSERT_MARKUP: null,
  MOVE_EXISTING: null,
  REMOVE_NODE: null,
  TEXT_CONTENT: null
});

module.exports = ReactMultiChildUpdateTypes;

},{"./keyMirror":"/Users/zordius/webtasks/node_modules/react/lib/keyMirror.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactNativeComponent.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactNativeComponent
 */

"use strict";

var assign = require("./Object.assign");
var invariant = require("./invariant");

var genericComponentClass = null;
// This registry keeps track of wrapper classes around native tags
var tagToComponentClass = {};

var ReactNativeComponentInjection = {
  // This accepts a class that receives the tag string. This is a catch all
  // that can render any kind of tag.
  injectGenericComponentClass: function(componentClass) {
    genericComponentClass = componentClass;
  },
  // This accepts a keyed object with classes as values. Each key represents a
  // tag. That particular tag will use this class instead of the generic one.
  injectComponentClasses: function(componentClasses) {
    assign(tagToComponentClass, componentClasses);
  }
};

/**
 * Create an internal class for a specific tag.
 *
 * @param {string} tag The tag for which to create an internal instance.
 * @param {any} props The props passed to the instance constructor.
 * @return {ReactComponent} component The injected empty component.
 */
function createInstanceForTag(tag, props, parentType) {
  var componentClass = tagToComponentClass[tag];
  if (componentClass == null) {
    ("production" !== process.env.NODE_ENV ? invariant(
      genericComponentClass,
      'There is no registered component for the tag %s',
      tag
    ) : invariant(genericComponentClass));
    return new genericComponentClass(tag, props);
  }
  if (parentType === tag) {
    // Avoid recursion
    ("production" !== process.env.NODE_ENV ? invariant(
      genericComponentClass,
      'There is no registered component for the tag %s',
      tag
    ) : invariant(genericComponentClass));
    return new genericComponentClass(tag, props);
  }
  // Unwrap legacy factories
  return new componentClass.type(props);
}

var ReactNativeComponent = {
  createInstanceForTag: createInstanceForTag,
  injection: ReactNativeComponentInjection,
};

module.exports = ReactNativeComponent;

}).call(this,require('_process'))
},{"./Object.assign":"/Users/zordius/webtasks/node_modules/react/lib/Object.assign.js","./invariant":"/Users/zordius/webtasks/node_modules/react/lib/invariant.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactOwner.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactOwner
 */

"use strict";

var emptyObject = require("./emptyObject");
var invariant = require("./invariant");

/**
 * ReactOwners are capable of storing references to owned components.
 *
 * All components are capable of //being// referenced by owner components, but
 * only ReactOwner components are capable of //referencing// owned components.
 * The named reference is known as a "ref".
 *
 * Refs are available when mounted and updated during reconciliation.
 *
 *   var MyComponent = React.createClass({
 *     render: function() {
 *       return (
 *         <div onClick={this.handleClick}>
 *           <CustomComponent ref="custom" />
 *         </div>
 *       );
 *     },
 *     handleClick: function() {
 *       this.refs.custom.handleClick();
 *     },
 *     componentDidMount: function() {
 *       this.refs.custom.initialize();
 *     }
 *   });
 *
 * Refs should rarely be used. When refs are used, they should only be done to
 * control data that is not handled by React's data flow.
 *
 * @class ReactOwner
 */
var ReactOwner = {

  /**
   * @param {?object} object
   * @return {boolean} True if `object` is a valid owner.
   * @final
   */
  isValidOwner: function(object) {
    return !!(
      object &&
      typeof object.attachRef === 'function' &&
      typeof object.detachRef === 'function'
    );
  },

  /**
   * Adds a component by ref to an owner component.
   *
   * @param {ReactComponent} component Component to reference.
   * @param {string} ref Name by which to refer to the component.
   * @param {ReactOwner} owner Component on which to record the ref.
   * @final
   * @internal
   */
  addComponentAsRefTo: function(component, ref, owner) {
    ("production" !== process.env.NODE_ENV ? invariant(
      ReactOwner.isValidOwner(owner),
      'addComponentAsRefTo(...): Only a ReactOwner can have refs. This ' +
      'usually means that you\'re trying to add a ref to a component that ' +
      'doesn\'t have an owner (that is, was not created inside of another ' +
      'component\'s `render` method). Try rendering this component inside of ' +
      'a new top-level component which will hold the ref.'
    ) : invariant(ReactOwner.isValidOwner(owner)));
    owner.attachRef(ref, component);
  },

  /**
   * Removes a component by ref from an owner component.
   *
   * @param {ReactComponent} component Component to dereference.
   * @param {string} ref Name of the ref to remove.
   * @param {ReactOwner} owner Component on which the ref is recorded.
   * @final
   * @internal
   */
  removeComponentAsRefFrom: function(component, ref, owner) {
    ("production" !== process.env.NODE_ENV ? invariant(
      ReactOwner.isValidOwner(owner),
      'removeComponentAsRefFrom(...): Only a ReactOwner can have refs. This ' +
      'usually means that you\'re trying to remove a ref to a component that ' +
      'doesn\'t have an owner (that is, was not created inside of another ' +
      'component\'s `render` method). Try rendering this component inside of ' +
      'a new top-level component which will hold the ref.'
    ) : invariant(ReactOwner.isValidOwner(owner)));
    // Check that `component` is still the current ref because we do not want to
    // detach the ref if another component stole it.
    if (owner.refs[ref] === component) {
      owner.detachRef(ref);
    }
  },

  /**
   * A ReactComponent must mix this in to have refs.
   *
   * @lends {ReactOwner.prototype}
   */
  Mixin: {

    construct: function() {
      this.refs = emptyObject;
    },

    /**
     * Lazily allocates the refs object and stores `component` as `ref`.
     *
     * @param {string} ref Reference name.
     * @param {component} component Component to store as `ref`.
     * @final
     * @private
     */
    attachRef: function(ref, component) {
      ("production" !== process.env.NODE_ENV ? invariant(
        component.isOwnedBy(this),
        'attachRef(%s, ...): Only a component\'s owner can store a ref to it.',
        ref
      ) : invariant(component.isOwnedBy(this)));
      var refs = this.refs === emptyObject ? (this.refs = {}) : this.refs;
      refs[ref] = component;
    },

    /**
     * Detaches a reference name.
     *
     * @param {string} ref Name to dereference.
     * @final
     * @private
     */
    detachRef: function(ref) {
      delete this.refs[ref];
    }

  }

};

module.exports = ReactOwner;

}).call(this,require('_process'))
},{"./emptyObject":"/Users/zordius/webtasks/node_modules/react/lib/emptyObject.js","./invariant":"/Users/zordius/webtasks/node_modules/react/lib/invariant.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactPerf.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactPerf
 * @typechecks static-only
 */

"use strict";

/**
 * ReactPerf is a general AOP system designed to measure performance. This
 * module only has the hooks: see ReactDefaultPerf for the analysis tool.
 */
var ReactPerf = {
  /**
   * Boolean to enable/disable measurement. Set to false by default to prevent
   * accidental logging and perf loss.
   */
  enableMeasure: false,

  /**
   * Holds onto the measure function in use. By default, don't measure
   * anything, but we'll override this if we inject a measure function.
   */
  storedMeasure: _noMeasure,

  /**
   * Use this to wrap methods you want to measure. Zero overhead in production.
   *
   * @param {string} objName
   * @param {string} fnName
   * @param {function} func
   * @return {function}
   */
  measure: function(objName, fnName, func) {
    if ("production" !== process.env.NODE_ENV) {
      var measuredFunc = null;
      var wrapper = function() {
        if (ReactPerf.enableMeasure) {
          if (!measuredFunc) {
            measuredFunc = ReactPerf.storedMeasure(objName, fnName, func);
          }
          return measuredFunc.apply(this, arguments);
        }
        return func.apply(this, arguments);
      };
      wrapper.displayName = objName + '_' + fnName;
      return wrapper;
    }
    return func;
  },

  injection: {
    /**
     * @param {function} measure
     */
    injectMeasure: function(measure) {
      ReactPerf.storedMeasure = measure;
    }
  }
};

/**
 * Simply passes through the measured function, without measuring it.
 *
 * @param {string} objName
 * @param {string} fnName
 * @param {function} func
 * @return {function}
 */
function _noMeasure(objName, fnName, func) {
  return func;
}

module.exports = ReactPerf;

}).call(this,require('_process'))
},{"_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactPropTransferer.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactPropTransferer
 */

"use strict";

var assign = require("./Object.assign");
var emptyFunction = require("./emptyFunction");
var invariant = require("./invariant");
var joinClasses = require("./joinClasses");
var warning = require("./warning");

var didWarn = false;

/**
 * Creates a transfer strategy that will merge prop values using the supplied
 * `mergeStrategy`. If a prop was previously unset, this just sets it.
 *
 * @param {function} mergeStrategy
 * @return {function}
 */
function createTransferStrategy(mergeStrategy) {
  return function(props, key, value) {
    if (!props.hasOwnProperty(key)) {
      props[key] = value;
    } else {
      props[key] = mergeStrategy(props[key], value);
    }
  };
}

var transferStrategyMerge = createTransferStrategy(function(a, b) {
  // `merge` overrides the first object's (`props[key]` above) keys using the
  // second object's (`value`) keys. An object's style's existing `propA` would
  // get overridden. Flip the order here.
  return assign({}, b, a);
});

/**
 * Transfer strategies dictate how props are transferred by `transferPropsTo`.
 * NOTE: if you add any more exceptions to this list you should be sure to
 * update `cloneWithProps()` accordingly.
 */
var TransferStrategies = {
  /**
   * Never transfer `children`.
   */
  children: emptyFunction,
  /**
   * Transfer the `className` prop by merging them.
   */
  className: createTransferStrategy(joinClasses),
  /**
   * Transfer the `style` prop (which is an object) by merging them.
   */
  style: transferStrategyMerge
};

/**
 * Mutates the first argument by transferring the properties from the second
 * argument.
 *
 * @param {object} props
 * @param {object} newProps
 * @return {object}
 */
function transferInto(props, newProps) {
  for (var thisKey in newProps) {
    if (!newProps.hasOwnProperty(thisKey)) {
      continue;
    }

    var transferStrategy = TransferStrategies[thisKey];

    if (transferStrategy && TransferStrategies.hasOwnProperty(thisKey)) {
      transferStrategy(props, thisKey, newProps[thisKey]);
    } else if (!props.hasOwnProperty(thisKey)) {
      props[thisKey] = newProps[thisKey];
    }
  }
  return props;
}

/**
 * ReactPropTransferer are capable of transferring props to another component
 * using a `transferPropsTo` method.
 *
 * @class ReactPropTransferer
 */
var ReactPropTransferer = {

  TransferStrategies: TransferStrategies,

  /**
   * Merge two props objects using TransferStrategies.
   *
   * @param {object} oldProps original props (they take precedence)
   * @param {object} newProps new props to merge in
   * @return {object} a new object containing both sets of props merged.
   */
  mergeProps: function(oldProps, newProps) {
    return transferInto(assign({}, oldProps), newProps);
  },

  /**
   * @lends {ReactPropTransferer.prototype}
   */
  Mixin: {

    /**
     * Transfer props from this component to a target component.
     *
     * Props that do not have an explicit transfer strategy will be transferred
     * only if the target component does not already have the prop set.
     *
     * This is usually used to pass down props to a returned root component.
     *
     * @param {ReactElement} element Component receiving the properties.
     * @return {ReactElement} The supplied `component`.
     * @final
     * @protected
     */
    transferPropsTo: function(element) {
      ("production" !== process.env.NODE_ENV ? invariant(
        element._owner === this,
        '%s: You can\'t call transferPropsTo() on a component that you ' +
        'don\'t own, %s. This usually means you are calling ' +
        'transferPropsTo() on a component passed in as props or children.',
        this.constructor.displayName,
        typeof element.type === 'string' ?
        element.type :
        element.type.displayName
      ) : invariant(element._owner === this));

      if ("production" !== process.env.NODE_ENV) {
        if (!didWarn) {
          didWarn = true;
          ("production" !== process.env.NODE_ENV ? warning(
            false,
            'transferPropsTo is deprecated. ' +
            'See http://fb.me/react-transferpropsto for more information.'
          ) : null);
        }
      }

      // Because elements are immutable we have to merge into the existing
      // props object rather than clone it.
      transferInto(element.props, this.props);

      return element;
    }

  }
};

module.exports = ReactPropTransferer;

}).call(this,require('_process'))
},{"./Object.assign":"/Users/zordius/webtasks/node_modules/react/lib/Object.assign.js","./emptyFunction":"/Users/zordius/webtasks/node_modules/react/lib/emptyFunction.js","./invariant":"/Users/zordius/webtasks/node_modules/react/lib/invariant.js","./joinClasses":"/Users/zordius/webtasks/node_modules/react/lib/joinClasses.js","./warning":"/Users/zordius/webtasks/node_modules/react/lib/warning.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactPropTypeLocationNames.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactPropTypeLocationNames
 */

"use strict";

var ReactPropTypeLocationNames = {};

if ("production" !== process.env.NODE_ENV) {
  ReactPropTypeLocationNames = {
    prop: 'prop',
    context: 'context',
    childContext: 'child context'
  };
}

module.exports = ReactPropTypeLocationNames;

}).call(this,require('_process'))
},{"_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactPropTypeLocations.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactPropTypeLocations
 */

"use strict";

var keyMirror = require("./keyMirror");

var ReactPropTypeLocations = keyMirror({
  prop: null,
  context: null,
  childContext: null
});

module.exports = ReactPropTypeLocations;

},{"./keyMirror":"/Users/zordius/webtasks/node_modules/react/lib/keyMirror.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactPropTypes.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactPropTypes
 */

"use strict";

var ReactElement = require("./ReactElement");
var ReactPropTypeLocationNames = require("./ReactPropTypeLocationNames");

var deprecated = require("./deprecated");
var emptyFunction = require("./emptyFunction");

/**
 * Collection of methods that allow declaration and validation of props that are
 * supplied to React components. Example usage:
 *
 *   var Props = require('ReactPropTypes');
 *   var MyArticle = React.createClass({
 *     propTypes: {
 *       // An optional string prop named "description".
 *       description: Props.string,
 *
 *       // A required enum prop named "category".
 *       category: Props.oneOf(['News','Photos']).isRequired,
 *
 *       // A prop named "dialog" that requires an instance of Dialog.
 *       dialog: Props.instanceOf(Dialog).isRequired
 *     },
 *     render: function() { ... }
 *   });
 *
 * A more formal specification of how these methods are used:
 *
 *   type := array|bool|func|object|number|string|oneOf([...])|instanceOf(...)
 *   decl := ReactPropTypes.{type}(.isRequired)?
 *
 * Each and every declaration produces a function with the same signature. This
 * allows the creation of custom validation functions. For example:
 *
 *  var MyLink = React.createClass({
 *    propTypes: {
 *      // An optional string or URI prop named "href".
 *      href: function(props, propName, componentName) {
 *        var propValue = props[propName];
 *        if (propValue != null && typeof propValue !== 'string' &&
 *            !(propValue instanceof URI)) {
 *          return new Error(
 *            'Expected a string or an URI for ' + propName + ' in ' +
 *            componentName
 *          );
 *        }
 *      }
 *    },
 *    render: function() {...}
 *  });
 *
 * @internal
 */

var ANONYMOUS = '<<anonymous>>';

var elementTypeChecker = createElementTypeChecker();
var nodeTypeChecker = createNodeChecker();

var ReactPropTypes = {
  array: createPrimitiveTypeChecker('array'),
  bool: createPrimitiveTypeChecker('boolean'),
  func: createPrimitiveTypeChecker('function'),
  number: createPrimitiveTypeChecker('number'),
  object: createPrimitiveTypeChecker('object'),
  string: createPrimitiveTypeChecker('string'),

  any: createAnyTypeChecker(),
  arrayOf: createArrayOfTypeChecker,
  element: elementTypeChecker,
  instanceOf: createInstanceTypeChecker,
  node: nodeTypeChecker,
  objectOf: createObjectOfTypeChecker,
  oneOf: createEnumTypeChecker,
  oneOfType: createUnionTypeChecker,
  shape: createShapeTypeChecker,

  component: deprecated(
    'React.PropTypes',
    'component',
    'element',
    this,
    elementTypeChecker
  ),
  renderable: deprecated(
    'React.PropTypes',
    'renderable',
    'node',
    this,
    nodeTypeChecker
  )
};

function createChainableTypeChecker(validate) {
  function checkType(isRequired, props, propName, componentName, location) {
    componentName = componentName || ANONYMOUS;
    if (props[propName] == null) {
      var locationName = ReactPropTypeLocationNames[location];
      if (isRequired) {
        return new Error(
          ("Required " + locationName + " `" + propName + "` was not specified in ")+
          ("`" + componentName + "`.")
        );
      }
    } else {
      return validate(props, propName, componentName, location);
    }
  }

  var chainedCheckType = checkType.bind(null, false);
  chainedCheckType.isRequired = checkType.bind(null, true);

  return chainedCheckType;
}

function createPrimitiveTypeChecker(expectedType) {
  function validate(props, propName, componentName, location) {
    var propValue = props[propName];
    var propType = getPropType(propValue);
    if (propType !== expectedType) {
      var locationName = ReactPropTypeLocationNames[location];
      // `propValue` being instance of, say, date/regexp, pass the 'object'
      // check, but we can offer a more precise error message here rather than
      // 'of type `object`'.
      var preciseType = getPreciseType(propValue);

      return new Error(
        ("Invalid " + locationName + " `" + propName + "` of type `" + preciseType + "` ") +
        ("supplied to `" + componentName + "`, expected `" + expectedType + "`.")
      );
    }
  }
  return createChainableTypeChecker(validate);
}

function createAnyTypeChecker() {
  return createChainableTypeChecker(emptyFunction.thatReturns());
}

function createArrayOfTypeChecker(typeChecker) {
  function validate(props, propName, componentName, location) {
    var propValue = props[propName];
    if (!Array.isArray(propValue)) {
      var locationName = ReactPropTypeLocationNames[location];
      var propType = getPropType(propValue);
      return new Error(
        ("Invalid " + locationName + " `" + propName + "` of type ") +
        ("`" + propType + "` supplied to `" + componentName + "`, expected an array.")
      );
    }
    for (var i = 0; i < propValue.length; i++) {
      var error = typeChecker(propValue, i, componentName, location);
      if (error instanceof Error) {
        return error;
      }
    }
  }
  return createChainableTypeChecker(validate);
}

function createElementTypeChecker() {
  function validate(props, propName, componentName, location) {
    if (!ReactElement.isValidElement(props[propName])) {
      var locationName = ReactPropTypeLocationNames[location];
      return new Error(
        ("Invalid " + locationName + " `" + propName + "` supplied to ") +
        ("`" + componentName + "`, expected a ReactElement.")
      );
    }
  }
  return createChainableTypeChecker(validate);
}

function createInstanceTypeChecker(expectedClass) {
  function validate(props, propName, componentName, location) {
    if (!(props[propName] instanceof expectedClass)) {
      var locationName = ReactPropTypeLocationNames[location];
      var expectedClassName = expectedClass.name || ANONYMOUS;
      return new Error(
        ("Invalid " + locationName + " `" + propName + "` supplied to ") +
        ("`" + componentName + "`, expected instance of `" + expectedClassName + "`.")
      );
    }
  }
  return createChainableTypeChecker(validate);
}

function createEnumTypeChecker(expectedValues) {
  function validate(props, propName, componentName, location) {
    var propValue = props[propName];
    for (var i = 0; i < expectedValues.length; i++) {
      if (propValue === expectedValues[i]) {
        return;
      }
    }

    var locationName = ReactPropTypeLocationNames[location];
    var valuesString = JSON.stringify(expectedValues);
    return new Error(
      ("Invalid " + locationName + " `" + propName + "` of value `" + propValue + "` ") +
      ("supplied to `" + componentName + "`, expected one of " + valuesString + ".")
    );
  }
  return createChainableTypeChecker(validate);
}

function createObjectOfTypeChecker(typeChecker) {
  function validate(props, propName, componentName, location) {
    var propValue = props[propName];
    var propType = getPropType(propValue);
    if (propType !== 'object') {
      var locationName = ReactPropTypeLocationNames[location];
      return new Error(
        ("Invalid " + locationName + " `" + propName + "` of type ") +
        ("`" + propType + "` supplied to `" + componentName + "`, expected an object.")
      );
    }
    for (var key in propValue) {
      if (propValue.hasOwnProperty(key)) {
        var error = typeChecker(propValue, key, componentName, location);
        if (error instanceof Error) {
          return error;
        }
      }
    }
  }
  return createChainableTypeChecker(validate);
}

function createUnionTypeChecker(arrayOfTypeCheckers) {
  function validate(props, propName, componentName, location) {
    for (var i = 0; i < arrayOfTypeCheckers.length; i++) {
      var checker = arrayOfTypeCheckers[i];
      if (checker(props, propName, componentName, location) == null) {
        return;
      }
    }

    var locationName = ReactPropTypeLocationNames[location];
    return new Error(
      ("Invalid " + locationName + " `" + propName + "` supplied to ") +
      ("`" + componentName + "`.")
    );
  }
  return createChainableTypeChecker(validate);
}

function createNodeChecker() {
  function validate(props, propName, componentName, location) {
    if (!isNode(props[propName])) {
      var locationName = ReactPropTypeLocationNames[location];
      return new Error(
        ("Invalid " + locationName + " `" + propName + "` supplied to ") +
        ("`" + componentName + "`, expected a ReactNode.")
      );
    }
  }
  return createChainableTypeChecker(validate);
}

function createShapeTypeChecker(shapeTypes) {
  function validate(props, propName, componentName, location) {
    var propValue = props[propName];
    var propType = getPropType(propValue);
    if (propType !== 'object') {
      var locationName = ReactPropTypeLocationNames[location];
      return new Error(
        ("Invalid " + locationName + " `" + propName + "` of type `" + propType + "` ") +
        ("supplied to `" + componentName + "`, expected `object`.")
      );
    }
    for (var key in shapeTypes) {
      var checker = shapeTypes[key];
      if (!checker) {
        continue;
      }
      var error = checker(propValue, key, componentName, location);
      if (error) {
        return error;
      }
    }
  }
  return createChainableTypeChecker(validate, 'expected `object`');
}

function isNode(propValue) {
  switch(typeof propValue) {
    case 'number':
    case 'string':
      return true;
    case 'boolean':
      return !propValue;
    case 'object':
      if (Array.isArray(propValue)) {
        return propValue.every(isNode);
      }
      if (ReactElement.isValidElement(propValue)) {
        return true;
      }
      for (var k in propValue) {
        if (!isNode(propValue[k])) {
          return false;
        }
      }
      return true;
    default:
      return false;
  }
}

// Equivalent of `typeof` but with special handling for array and regexp.
function getPropType(propValue) {
  var propType = typeof propValue;
  if (Array.isArray(propValue)) {
    return 'array';
  }
  if (propValue instanceof RegExp) {
    // Old webkits (at least until Android 4.0) return 'function' rather than
    // 'object' for typeof a RegExp. We'll normalize this here so that /bla/
    // passes PropTypes.object.
    return 'object';
  }
  return propType;
}

// This handles more types than `getPropType`. Only used for error messages.
// See `createPrimitiveTypeChecker`.
function getPreciseType(propValue) {
  var propType = getPropType(propValue);
  if (propType === 'object') {
    if (propValue instanceof Date) {
      return 'date';
    } else if (propValue instanceof RegExp) {
      return 'regexp';
    }
  }
  return propType;
}

module.exports = ReactPropTypes;

},{"./ReactElement":"/Users/zordius/webtasks/node_modules/react/lib/ReactElement.js","./ReactPropTypeLocationNames":"/Users/zordius/webtasks/node_modules/react/lib/ReactPropTypeLocationNames.js","./deprecated":"/Users/zordius/webtasks/node_modules/react/lib/deprecated.js","./emptyFunction":"/Users/zordius/webtasks/node_modules/react/lib/emptyFunction.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactPutListenerQueue.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactPutListenerQueue
 */

"use strict";

var PooledClass = require("./PooledClass");
var ReactBrowserEventEmitter = require("./ReactBrowserEventEmitter");

var assign = require("./Object.assign");

function ReactPutListenerQueue() {
  this.listenersToPut = [];
}

assign(ReactPutListenerQueue.prototype, {
  enqueuePutListener: function(rootNodeID, propKey, propValue) {
    this.listenersToPut.push({
      rootNodeID: rootNodeID,
      propKey: propKey,
      propValue: propValue
    });
  },

  putListeners: function() {
    for (var i = 0; i < this.listenersToPut.length; i++) {
      var listenerToPut = this.listenersToPut[i];
      ReactBrowserEventEmitter.putListener(
        listenerToPut.rootNodeID,
        listenerToPut.propKey,
        listenerToPut.propValue
      );
    }
  },

  reset: function() {
    this.listenersToPut.length = 0;
  },

  destructor: function() {
    this.reset();
  }
});

PooledClass.addPoolingTo(ReactPutListenerQueue);

module.exports = ReactPutListenerQueue;

},{"./Object.assign":"/Users/zordius/webtasks/node_modules/react/lib/Object.assign.js","./PooledClass":"/Users/zordius/webtasks/node_modules/react/lib/PooledClass.js","./ReactBrowserEventEmitter":"/Users/zordius/webtasks/node_modules/react/lib/ReactBrowserEventEmitter.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactReconcileTransaction.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactReconcileTransaction
 * @typechecks static-only
 */

"use strict";

var CallbackQueue = require("./CallbackQueue");
var PooledClass = require("./PooledClass");
var ReactBrowserEventEmitter = require("./ReactBrowserEventEmitter");
var ReactInputSelection = require("./ReactInputSelection");
var ReactPutListenerQueue = require("./ReactPutListenerQueue");
var Transaction = require("./Transaction");

var assign = require("./Object.assign");

/**
 * Ensures that, when possible, the selection range (currently selected text
 * input) is not disturbed by performing the transaction.
 */
var SELECTION_RESTORATION = {
  /**
   * @return {Selection} Selection information.
   */
  initialize: ReactInputSelection.getSelectionInformation,
  /**
   * @param {Selection} sel Selection information returned from `initialize`.
   */
  close: ReactInputSelection.restoreSelection
};

/**
 * Suppresses events (blur/focus) that could be inadvertently dispatched due to
 * high level DOM manipulations (like temporarily removing a text input from the
 * DOM).
 */
var EVENT_SUPPRESSION = {
  /**
   * @return {boolean} The enabled status of `ReactBrowserEventEmitter` before
   * the reconciliation.
   */
  initialize: function() {
    var currentlyEnabled = ReactBrowserEventEmitter.isEnabled();
    ReactBrowserEventEmitter.setEnabled(false);
    return currentlyEnabled;
  },

  /**
   * @param {boolean} previouslyEnabled Enabled status of
   *   `ReactBrowserEventEmitter` before the reconciliation occured. `close`
   *   restores the previous value.
   */
  close: function(previouslyEnabled) {
    ReactBrowserEventEmitter.setEnabled(previouslyEnabled);
  }
};

/**
 * Provides a queue for collecting `componentDidMount` and
 * `componentDidUpdate` callbacks during the the transaction.
 */
var ON_DOM_READY_QUEUEING = {
  /**
   * Initializes the internal `onDOMReady` queue.
   */
  initialize: function() {
    this.reactMountReady.reset();
  },

  /**
   * After DOM is flushed, invoke all registered `onDOMReady` callbacks.
   */
  close: function() {
    this.reactMountReady.notifyAll();
  }
};

var PUT_LISTENER_QUEUEING = {
  initialize: function() {
    this.putListenerQueue.reset();
  },

  close: function() {
    this.putListenerQueue.putListeners();
  }
};

/**
 * Executed within the scope of the `Transaction` instance. Consider these as
 * being member methods, but with an implied ordering while being isolated from
 * each other.
 */
var TRANSACTION_WRAPPERS = [
  PUT_LISTENER_QUEUEING,
  SELECTION_RESTORATION,
  EVENT_SUPPRESSION,
  ON_DOM_READY_QUEUEING
];

/**
 * Currently:
 * - The order that these are listed in the transaction is critical:
 * - Suppresses events.
 * - Restores selection range.
 *
 * Future:
 * - Restore document/overflow scroll positions that were unintentionally
 *   modified via DOM insertions above the top viewport boundary.
 * - Implement/integrate with customized constraint based layout system and keep
 *   track of which dimensions must be remeasured.
 *
 * @class ReactReconcileTransaction
 */
function ReactReconcileTransaction() {
  this.reinitializeTransaction();
  // Only server-side rendering really needs this option (see
  // `ReactServerRendering`), but server-side uses
  // `ReactServerRenderingTransaction` instead. This option is here so that it's
  // accessible and defaults to false when `ReactDOMComponent` and
  // `ReactTextComponent` checks it in `mountComponent`.`
  this.renderToStaticMarkup = false;
  this.reactMountReady = CallbackQueue.getPooled(null);
  this.putListenerQueue = ReactPutListenerQueue.getPooled();
}

var Mixin = {
  /**
   * @see Transaction
   * @abstract
   * @final
   * @return {array<object>} List of operation wrap proceedures.
   *   TODO: convert to array<TransactionWrapper>
   */
  getTransactionWrappers: function() {
    return TRANSACTION_WRAPPERS;
  },

  /**
   * @return {object} The queue to collect `onDOMReady` callbacks with.
   */
  getReactMountReady: function() {
    return this.reactMountReady;
  },

  getPutListenerQueue: function() {
    return this.putListenerQueue;
  },

  /**
   * `PooledClass` looks for this, and will invoke this before allowing this
   * instance to be resused.
   */
  destructor: function() {
    CallbackQueue.release(this.reactMountReady);
    this.reactMountReady = null;

    ReactPutListenerQueue.release(this.putListenerQueue);
    this.putListenerQueue = null;
  }
};


assign(ReactReconcileTransaction.prototype, Transaction.Mixin, Mixin);

PooledClass.addPoolingTo(ReactReconcileTransaction);

module.exports = ReactReconcileTransaction;

},{"./CallbackQueue":"/Users/zordius/webtasks/node_modules/react/lib/CallbackQueue.js","./Object.assign":"/Users/zordius/webtasks/node_modules/react/lib/Object.assign.js","./PooledClass":"/Users/zordius/webtasks/node_modules/react/lib/PooledClass.js","./ReactBrowserEventEmitter":"/Users/zordius/webtasks/node_modules/react/lib/ReactBrowserEventEmitter.js","./ReactInputSelection":"/Users/zordius/webtasks/node_modules/react/lib/ReactInputSelection.js","./ReactPutListenerQueue":"/Users/zordius/webtasks/node_modules/react/lib/ReactPutListenerQueue.js","./Transaction":"/Users/zordius/webtasks/node_modules/react/lib/Transaction.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactRootIndex.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactRootIndex
 * @typechecks
 */

"use strict";

var ReactRootIndexInjection = {
  /**
   * @param {function} _createReactRootIndex
   */
  injectCreateReactRootIndex: function(_createReactRootIndex) {
    ReactRootIndex.createReactRootIndex = _createReactRootIndex;
  }
};

var ReactRootIndex = {
  createReactRootIndex: null,
  injection: ReactRootIndexInjection
};

module.exports = ReactRootIndex;

},{}],"/Users/zordius/webtasks/node_modules/react/lib/ReactServerRendering.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @typechecks static-only
 * @providesModule ReactServerRendering
 */
"use strict";

var ReactElement = require("./ReactElement");
var ReactInstanceHandles = require("./ReactInstanceHandles");
var ReactMarkupChecksum = require("./ReactMarkupChecksum");
var ReactServerRenderingTransaction =
  require("./ReactServerRenderingTransaction");

var instantiateReactComponent = require("./instantiateReactComponent");
var invariant = require("./invariant");

/**
 * @param {ReactElement} element
 * @return {string} the HTML markup
 */
function renderToString(element) {
  ("production" !== process.env.NODE_ENV ? invariant(
    ReactElement.isValidElement(element),
    'renderToString(): You must pass a valid ReactElement.'
  ) : invariant(ReactElement.isValidElement(element)));

  var transaction;
  try {
    var id = ReactInstanceHandles.createReactRootID();
    transaction = ReactServerRenderingTransaction.getPooled(false);

    return transaction.perform(function() {
      var componentInstance = instantiateReactComponent(element, null);
      var markup = componentInstance.mountComponent(id, transaction, 0);
      return ReactMarkupChecksum.addChecksumToMarkup(markup);
    }, null);
  } finally {
    ReactServerRenderingTransaction.release(transaction);
  }
}

/**
 * @param {ReactElement} element
 * @return {string} the HTML markup, without the extra React ID and checksum
 * (for generating static pages)
 */
function renderToStaticMarkup(element) {
  ("production" !== process.env.NODE_ENV ? invariant(
    ReactElement.isValidElement(element),
    'renderToStaticMarkup(): You must pass a valid ReactElement.'
  ) : invariant(ReactElement.isValidElement(element)));

  var transaction;
  try {
    var id = ReactInstanceHandles.createReactRootID();
    transaction = ReactServerRenderingTransaction.getPooled(true);

    return transaction.perform(function() {
      var componentInstance = instantiateReactComponent(element, null);
      return componentInstance.mountComponent(id, transaction, 0);
    }, null);
  } finally {
    ReactServerRenderingTransaction.release(transaction);
  }
}

module.exports = {
  renderToString: renderToString,
  renderToStaticMarkup: renderToStaticMarkup
};

}).call(this,require('_process'))
},{"./ReactElement":"/Users/zordius/webtasks/node_modules/react/lib/ReactElement.js","./ReactInstanceHandles":"/Users/zordius/webtasks/node_modules/react/lib/ReactInstanceHandles.js","./ReactMarkupChecksum":"/Users/zordius/webtasks/node_modules/react/lib/ReactMarkupChecksum.js","./ReactServerRenderingTransaction":"/Users/zordius/webtasks/node_modules/react/lib/ReactServerRenderingTransaction.js","./instantiateReactComponent":"/Users/zordius/webtasks/node_modules/react/lib/instantiateReactComponent.js","./invariant":"/Users/zordius/webtasks/node_modules/react/lib/invariant.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactServerRenderingTransaction.js":[function(require,module,exports){
/**
 * Copyright 2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactServerRenderingTransaction
 * @typechecks
 */

"use strict";

var PooledClass = require("./PooledClass");
var CallbackQueue = require("./CallbackQueue");
var ReactPutListenerQueue = require("./ReactPutListenerQueue");
var Transaction = require("./Transaction");

var assign = require("./Object.assign");
var emptyFunction = require("./emptyFunction");

/**
 * Provides a `CallbackQueue` queue for collecting `onDOMReady` callbacks
 * during the performing of the transaction.
 */
var ON_DOM_READY_QUEUEING = {
  /**
   * Initializes the internal `onDOMReady` queue.
   */
  initialize: function() {
    this.reactMountReady.reset();
  },

  close: emptyFunction
};

var PUT_LISTENER_QUEUEING = {
  initialize: function() {
    this.putListenerQueue.reset();
  },

  close: emptyFunction
};

/**
 * Executed within the scope of the `Transaction` instance. Consider these as
 * being member methods, but with an implied ordering while being isolated from
 * each other.
 */
var TRANSACTION_WRAPPERS = [
  PUT_LISTENER_QUEUEING,
  ON_DOM_READY_QUEUEING
];

/**
 * @class ReactServerRenderingTransaction
 * @param {boolean} renderToStaticMarkup
 */
function ReactServerRenderingTransaction(renderToStaticMarkup) {
  this.reinitializeTransaction();
  this.renderToStaticMarkup = renderToStaticMarkup;
  this.reactMountReady = CallbackQueue.getPooled(null);
  this.putListenerQueue = ReactPutListenerQueue.getPooled();
}

var Mixin = {
  /**
   * @see Transaction
   * @abstract
   * @final
   * @return {array} Empty list of operation wrap proceedures.
   */
  getTransactionWrappers: function() {
    return TRANSACTION_WRAPPERS;
  },

  /**
   * @return {object} The queue to collect `onDOMReady` callbacks with.
   */
  getReactMountReady: function() {
    return this.reactMountReady;
  },

  getPutListenerQueue: function() {
    return this.putListenerQueue;
  },

  /**
   * `PooledClass` looks for this, and will invoke this before allowing this
   * instance to be resused.
   */
  destructor: function() {
    CallbackQueue.release(this.reactMountReady);
    this.reactMountReady = null;

    ReactPutListenerQueue.release(this.putListenerQueue);
    this.putListenerQueue = null;
  }
};


assign(
  ReactServerRenderingTransaction.prototype,
  Transaction.Mixin,
  Mixin
);

PooledClass.addPoolingTo(ReactServerRenderingTransaction);

module.exports = ReactServerRenderingTransaction;

},{"./CallbackQueue":"/Users/zordius/webtasks/node_modules/react/lib/CallbackQueue.js","./Object.assign":"/Users/zordius/webtasks/node_modules/react/lib/Object.assign.js","./PooledClass":"/Users/zordius/webtasks/node_modules/react/lib/PooledClass.js","./ReactPutListenerQueue":"/Users/zordius/webtasks/node_modules/react/lib/ReactPutListenerQueue.js","./Transaction":"/Users/zordius/webtasks/node_modules/react/lib/Transaction.js","./emptyFunction":"/Users/zordius/webtasks/node_modules/react/lib/emptyFunction.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactTextComponent.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactTextComponent
 * @typechecks static-only
 */

"use strict";

var DOMPropertyOperations = require("./DOMPropertyOperations");
var ReactComponent = require("./ReactComponent");
var ReactElement = require("./ReactElement");

var assign = require("./Object.assign");
var escapeTextForBrowser = require("./escapeTextForBrowser");

/**
 * Text nodes violate a couple assumptions that React makes about components:
 *
 *  - When mounting text into the DOM, adjacent text nodes are merged.
 *  - Text nodes cannot be assigned a React root ID.
 *
 * This component is used to wrap strings in elements so that they can undergo
 * the same reconciliation that is applied to elements.
 *
 * TODO: Investigate representing React components in the DOM with text nodes.
 *
 * @class ReactTextComponent
 * @extends ReactComponent
 * @internal
 */
var ReactTextComponent = function(props) {
  // This constructor and it's argument is currently used by mocks.
};

assign(ReactTextComponent.prototype, ReactComponent.Mixin, {

  /**
   * Creates the markup for this text node. This node is not intended to have
   * any features besides containing text content.
   *
   * @param {string} rootID DOM ID of the root node.
   * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
   * @param {number} mountDepth number of components in the owner hierarchy
   * @return {string} Markup for this text node.
   * @internal
   */
  mountComponent: function(rootID, transaction, mountDepth) {
    ReactComponent.Mixin.mountComponent.call(
      this,
      rootID,
      transaction,
      mountDepth
    );

    var escapedText = escapeTextForBrowser(this.props);

    if (transaction.renderToStaticMarkup) {
      // Normally we'd wrap this in a `span` for the reasons stated above, but
      // since this is a situation where React won't take over (static pages),
      // we can simply return the text as it is.
      return escapedText;
    }

    return (
      '<span ' + DOMPropertyOperations.createMarkupForID(rootID) + '>' +
        escapedText +
      '</span>'
    );
  },

  /**
   * Updates this component by updating the text content.
   *
   * @param {object} nextComponent Contains the next text content.
   * @param {ReactReconcileTransaction} transaction
   * @internal
   */
  receiveComponent: function(nextComponent, transaction) {
    var nextProps = nextComponent.props;
    if (nextProps !== this.props) {
      this.props = nextProps;
      ReactComponent.BackendIDOperations.updateTextContentByID(
        this._rootNodeID,
        nextProps
      );
    }
  }

});

var ReactTextComponentFactory = function(text) {
  // Bypass validation and configuration
  return new ReactElement(ReactTextComponent, null, null, null, null, text);
};

ReactTextComponentFactory.type = ReactTextComponent;

module.exports = ReactTextComponentFactory;

},{"./DOMPropertyOperations":"/Users/zordius/webtasks/node_modules/react/lib/DOMPropertyOperations.js","./Object.assign":"/Users/zordius/webtasks/node_modules/react/lib/Object.assign.js","./ReactComponent":"/Users/zordius/webtasks/node_modules/react/lib/ReactComponent.js","./ReactElement":"/Users/zordius/webtasks/node_modules/react/lib/ReactElement.js","./escapeTextForBrowser":"/Users/zordius/webtasks/node_modules/react/lib/escapeTextForBrowser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ReactUpdates.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ReactUpdates
 */

"use strict";

var CallbackQueue = require("./CallbackQueue");
var PooledClass = require("./PooledClass");
var ReactCurrentOwner = require("./ReactCurrentOwner");
var ReactPerf = require("./ReactPerf");
var Transaction = require("./Transaction");

var assign = require("./Object.assign");
var invariant = require("./invariant");
var warning = require("./warning");

var dirtyComponents = [];
var asapCallbackQueue = CallbackQueue.getPooled();
var asapEnqueued = false;

var batchingStrategy = null;

function ensureInjected() {
  ("production" !== process.env.NODE_ENV ? invariant(
    ReactUpdates.ReactReconcileTransaction && batchingStrategy,
    'ReactUpdates: must inject a reconcile transaction class and batching ' +
    'strategy'
  ) : invariant(ReactUpdates.ReactReconcileTransaction && batchingStrategy));
}

var NESTED_UPDATES = {
  initialize: function() {
    this.dirtyComponentsLength = dirtyComponents.length;
  },
  close: function() {
    if (this.dirtyComponentsLength !== dirtyComponents.length) {
      // Additional updates were enqueued by componentDidUpdate handlers or
      // similar; before our own UPDATE_QUEUEING wrapper closes, we want to run
      // these new updates so that if A's componentDidUpdate calls setState on
      // B, B will update before the callback A's updater provided when calling
      // setState.
      dirtyComponents.splice(0, this.dirtyComponentsLength);
      flushBatchedUpdates();
    } else {
      dirtyComponents.length = 0;
    }
  }
};

var UPDATE_QUEUEING = {
  initialize: function() {
    this.callbackQueue.reset();
  },
  close: function() {
    this.callbackQueue.notifyAll();
  }
};

var TRANSACTION_WRAPPERS = [NESTED_UPDATES, UPDATE_QUEUEING];

function ReactUpdatesFlushTransaction() {
  this.reinitializeTransaction();
  this.dirtyComponentsLength = null;
  this.callbackQueue = CallbackQueue.getPooled();
  this.reconcileTransaction =
    ReactUpdates.ReactReconcileTransaction.getPooled();
}

assign(
  ReactUpdatesFlushTransaction.prototype,
  Transaction.Mixin, {
  getTransactionWrappers: function() {
    return TRANSACTION_WRAPPERS;
  },

  destructor: function() {
    this.dirtyComponentsLength = null;
    CallbackQueue.release(this.callbackQueue);
    this.callbackQueue = null;
    ReactUpdates.ReactReconcileTransaction.release(this.reconcileTransaction);
    this.reconcileTransaction = null;
  },

  perform: function(method, scope, a) {
    // Essentially calls `this.reconcileTransaction.perform(method, scope, a)`
    // with this transaction's wrappers around it.
    return Transaction.Mixin.perform.call(
      this,
      this.reconcileTransaction.perform,
      this.reconcileTransaction,
      method,
      scope,
      a
    );
  }
});

PooledClass.addPoolingTo(ReactUpdatesFlushTransaction);

function batchedUpdates(callback, a, b) {
  ensureInjected();
  batchingStrategy.batchedUpdates(callback, a, b);
}

/**
 * Array comparator for ReactComponents by owner depth
 *
 * @param {ReactComponent} c1 first component you're comparing
 * @param {ReactComponent} c2 second component you're comparing
 * @return {number} Return value usable by Array.prototype.sort().
 */
function mountDepthComparator(c1, c2) {
  return c1._mountDepth - c2._mountDepth;
}

function runBatchedUpdates(transaction) {
  var len = transaction.dirtyComponentsLength;
  ("production" !== process.env.NODE_ENV ? invariant(
    len === dirtyComponents.length,
    'Expected flush transaction\'s stored dirty-components length (%s) to ' +
    'match dirty-components array length (%s).',
    len,
    dirtyComponents.length
  ) : invariant(len === dirtyComponents.length));

  // Since reconciling a component higher in the owner hierarchy usually (not
  // always -- see shouldComponentUpdate()) will reconcile children, reconcile
  // them before their children by sorting the array.
  dirtyComponents.sort(mountDepthComparator);

  for (var i = 0; i < len; i++) {
    // If a component is unmounted before pending changes apply, ignore them
    // TODO: Queue unmounts in the same list to avoid this happening at all
    var component = dirtyComponents[i];
    if (component.isMounted()) {
      // If performUpdateIfNecessary happens to enqueue any new updates, we
      // shouldn't execute the callbacks until the next render happens, so
      // stash the callbacks first
      var callbacks = component._pendingCallbacks;
      component._pendingCallbacks = null;
      component.performUpdateIfNecessary(transaction.reconcileTransaction);

      if (callbacks) {
        for (var j = 0; j < callbacks.length; j++) {
          transaction.callbackQueue.enqueue(
            callbacks[j],
            component
          );
        }
      }
    }
  }
}

var flushBatchedUpdates = ReactPerf.measure(
  'ReactUpdates',
  'flushBatchedUpdates',
  function() {
    // ReactUpdatesFlushTransaction's wrappers will clear the dirtyComponents
    // array and perform any updates enqueued by mount-ready handlers (i.e.,
    // componentDidUpdate) but we need to check here too in order to catch
    // updates enqueued by setState callbacks and asap calls.
    while (dirtyComponents.length || asapEnqueued) {
      if (dirtyComponents.length) {
        var transaction = ReactUpdatesFlushTransaction.getPooled();
        transaction.perform(runBatchedUpdates, null, transaction);
        ReactUpdatesFlushTransaction.release(transaction);
      }

      if (asapEnqueued) {
        asapEnqueued = false;
        var queue = asapCallbackQueue;
        asapCallbackQueue = CallbackQueue.getPooled();
        queue.notifyAll();
        CallbackQueue.release(queue);
      }
    }
  }
);

/**
 * Mark a component as needing a rerender, adding an optional callback to a
 * list of functions which will be executed once the rerender occurs.
 */
function enqueueUpdate(component, callback) {
  ("production" !== process.env.NODE_ENV ? invariant(
    !callback || typeof callback === "function",
    'enqueueUpdate(...): You called `setProps`, `replaceProps`, ' +
    '`setState`, `replaceState`, or `forceUpdate` with a callback that ' +
    'isn\'t callable.'
  ) : invariant(!callback || typeof callback === "function"));
  ensureInjected();

  // Various parts of our code (such as ReactCompositeComponent's
  // _renderValidatedComponent) assume that calls to render aren't nested;
  // verify that that's the case. (This is called by each top-level update
  // function, like setProps, setState, forceUpdate, etc.; creation and
  // destruction of top-level components is guarded in ReactMount.)
  ("production" !== process.env.NODE_ENV ? warning(
    ReactCurrentOwner.current == null,
    'enqueueUpdate(): Render methods should be a pure function of props ' +
    'and state; triggering nested component updates from render is not ' +
    'allowed. If necessary, trigger nested updates in ' +
    'componentDidUpdate.'
  ) : null);

  if (!batchingStrategy.isBatchingUpdates) {
    batchingStrategy.batchedUpdates(enqueueUpdate, component, callback);
    return;
  }

  dirtyComponents.push(component);

  if (callback) {
    if (component._pendingCallbacks) {
      component._pendingCallbacks.push(callback);
    } else {
      component._pendingCallbacks = [callback];
    }
  }
}

/**
 * Enqueue a callback to be run at the end of the current batching cycle. Throws
 * if no updates are currently being performed.
 */
function asap(callback, context) {
  ("production" !== process.env.NODE_ENV ? invariant(
    batchingStrategy.isBatchingUpdates,
    'ReactUpdates.asap: Can\'t enqueue an asap callback in a context where' +
    'updates are not being batched.'
  ) : invariant(batchingStrategy.isBatchingUpdates));
  asapCallbackQueue.enqueue(callback, context);
  asapEnqueued = true;
}

var ReactUpdatesInjection = {
  injectReconcileTransaction: function(ReconcileTransaction) {
    ("production" !== process.env.NODE_ENV ? invariant(
      ReconcileTransaction,
      'ReactUpdates: must provide a reconcile transaction class'
    ) : invariant(ReconcileTransaction));
    ReactUpdates.ReactReconcileTransaction = ReconcileTransaction;
  },

  injectBatchingStrategy: function(_batchingStrategy) {
    ("production" !== process.env.NODE_ENV ? invariant(
      _batchingStrategy,
      'ReactUpdates: must provide a batching strategy'
    ) : invariant(_batchingStrategy));
    ("production" !== process.env.NODE_ENV ? invariant(
      typeof _batchingStrategy.batchedUpdates === 'function',
      'ReactUpdates: must provide a batchedUpdates() function'
    ) : invariant(typeof _batchingStrategy.batchedUpdates === 'function'));
    ("production" !== process.env.NODE_ENV ? invariant(
      typeof _batchingStrategy.isBatchingUpdates === 'boolean',
      'ReactUpdates: must provide an isBatchingUpdates boolean attribute'
    ) : invariant(typeof _batchingStrategy.isBatchingUpdates === 'boolean'));
    batchingStrategy = _batchingStrategy;
  }
};

var ReactUpdates = {
  /**
   * React references `ReactReconcileTransaction` using this property in order
   * to allow dependency injection.
   *
   * @internal
   */
  ReactReconcileTransaction: null,

  batchedUpdates: batchedUpdates,
  enqueueUpdate: enqueueUpdate,
  flushBatchedUpdates: flushBatchedUpdates,
  injection: ReactUpdatesInjection,
  asap: asap
};

module.exports = ReactUpdates;

}).call(this,require('_process'))
},{"./CallbackQueue":"/Users/zordius/webtasks/node_modules/react/lib/CallbackQueue.js","./Object.assign":"/Users/zordius/webtasks/node_modules/react/lib/Object.assign.js","./PooledClass":"/Users/zordius/webtasks/node_modules/react/lib/PooledClass.js","./ReactCurrentOwner":"/Users/zordius/webtasks/node_modules/react/lib/ReactCurrentOwner.js","./ReactPerf":"/Users/zordius/webtasks/node_modules/react/lib/ReactPerf.js","./Transaction":"/Users/zordius/webtasks/node_modules/react/lib/Transaction.js","./invariant":"/Users/zordius/webtasks/node_modules/react/lib/invariant.js","./warning":"/Users/zordius/webtasks/node_modules/react/lib/warning.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/SVGDOMPropertyConfig.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule SVGDOMPropertyConfig
 */

/*jslint bitwise: true*/

"use strict";

var DOMProperty = require("./DOMProperty");

var MUST_USE_ATTRIBUTE = DOMProperty.injection.MUST_USE_ATTRIBUTE;

var SVGDOMPropertyConfig = {
  Properties: {
    cx: MUST_USE_ATTRIBUTE,
    cy: MUST_USE_ATTRIBUTE,
    d: MUST_USE_ATTRIBUTE,
    dx: MUST_USE_ATTRIBUTE,
    dy: MUST_USE_ATTRIBUTE,
    fill: MUST_USE_ATTRIBUTE,
    fillOpacity: MUST_USE_ATTRIBUTE,
    fontFamily: MUST_USE_ATTRIBUTE,
    fontSize: MUST_USE_ATTRIBUTE,
    fx: MUST_USE_ATTRIBUTE,
    fy: MUST_USE_ATTRIBUTE,
    gradientTransform: MUST_USE_ATTRIBUTE,
    gradientUnits: MUST_USE_ATTRIBUTE,
    markerEnd: MUST_USE_ATTRIBUTE,
    markerMid: MUST_USE_ATTRIBUTE,
    markerStart: MUST_USE_ATTRIBUTE,
    offset: MUST_USE_ATTRIBUTE,
    opacity: MUST_USE_ATTRIBUTE,
    patternContentUnits: MUST_USE_ATTRIBUTE,
    patternUnits: MUST_USE_ATTRIBUTE,
    points: MUST_USE_ATTRIBUTE,
    preserveAspectRatio: MUST_USE_ATTRIBUTE,
    r: MUST_USE_ATTRIBUTE,
    rx: MUST_USE_ATTRIBUTE,
    ry: MUST_USE_ATTRIBUTE,
    spreadMethod: MUST_USE_ATTRIBUTE,
    stopColor: MUST_USE_ATTRIBUTE,
    stopOpacity: MUST_USE_ATTRIBUTE,
    stroke: MUST_USE_ATTRIBUTE,
    strokeDasharray: MUST_USE_ATTRIBUTE,
    strokeLinecap: MUST_USE_ATTRIBUTE,
    strokeOpacity: MUST_USE_ATTRIBUTE,
    strokeWidth: MUST_USE_ATTRIBUTE,
    textAnchor: MUST_USE_ATTRIBUTE,
    transform: MUST_USE_ATTRIBUTE,
    version: MUST_USE_ATTRIBUTE,
    viewBox: MUST_USE_ATTRIBUTE,
    x1: MUST_USE_ATTRIBUTE,
    x2: MUST_USE_ATTRIBUTE,
    x: MUST_USE_ATTRIBUTE,
    y1: MUST_USE_ATTRIBUTE,
    y2: MUST_USE_ATTRIBUTE,
    y: MUST_USE_ATTRIBUTE
  },
  DOMAttributeNames: {
    fillOpacity: 'fill-opacity',
    fontFamily: 'font-family',
    fontSize: 'font-size',
    gradientTransform: 'gradientTransform',
    gradientUnits: 'gradientUnits',
    markerEnd: 'marker-end',
    markerMid: 'marker-mid',
    markerStart: 'marker-start',
    patternContentUnits: 'patternContentUnits',
    patternUnits: 'patternUnits',
    preserveAspectRatio: 'preserveAspectRatio',
    spreadMethod: 'spreadMethod',
    stopColor: 'stop-color',
    stopOpacity: 'stop-opacity',
    strokeDasharray: 'stroke-dasharray',
    strokeLinecap: 'stroke-linecap',
    strokeOpacity: 'stroke-opacity',
    strokeWidth: 'stroke-width',
    textAnchor: 'text-anchor',
    viewBox: 'viewBox'
  }
};

module.exports = SVGDOMPropertyConfig;

},{"./DOMProperty":"/Users/zordius/webtasks/node_modules/react/lib/DOMProperty.js"}],"/Users/zordius/webtasks/node_modules/react/lib/SelectEventPlugin.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule SelectEventPlugin
 */

"use strict";

var EventConstants = require("./EventConstants");
var EventPropagators = require("./EventPropagators");
var ReactInputSelection = require("./ReactInputSelection");
var SyntheticEvent = require("./SyntheticEvent");

var getActiveElement = require("./getActiveElement");
var isTextInputElement = require("./isTextInputElement");
var keyOf = require("./keyOf");
var shallowEqual = require("./shallowEqual");

var topLevelTypes = EventConstants.topLevelTypes;

var eventTypes = {
  select: {
    phasedRegistrationNames: {
      bubbled: keyOf({onSelect: null}),
      captured: keyOf({onSelectCapture: null})
    },
    dependencies: [
      topLevelTypes.topBlur,
      topLevelTypes.topContextMenu,
      topLevelTypes.topFocus,
      topLevelTypes.topKeyDown,
      topLevelTypes.topMouseDown,
      topLevelTypes.topMouseUp,
      topLevelTypes.topSelectionChange
    ]
  }
};

var activeElement = null;
var activeElementID = null;
var lastSelection = null;
var mouseDown = false;

/**
 * Get an object which is a unique representation of the current selection.
 *
 * The return value will not be consistent across nodes or browsers, but
 * two identical selections on the same node will return identical objects.
 *
 * @param {DOMElement} node
 * @param {object}
 */
function getSelection(node) {
  if ('selectionStart' in node &&
      ReactInputSelection.hasSelectionCapabilities(node)) {
    return {
      start: node.selectionStart,
      end: node.selectionEnd
    };
  } else if (window.getSelection) {
    var selection = window.getSelection();
    return {
      anchorNode: selection.anchorNode,
      anchorOffset: selection.anchorOffset,
      focusNode: selection.focusNode,
      focusOffset: selection.focusOffset
    };
  } else if (document.selection) {
    var range = document.selection.createRange();
    return {
      parentElement: range.parentElement(),
      text: range.text,
      top: range.boundingTop,
      left: range.boundingLeft
    };
  }
}

/**
 * Poll selection to see whether it's changed.
 *
 * @param {object} nativeEvent
 * @return {?SyntheticEvent}
 */
function constructSelectEvent(nativeEvent) {
  // Ensure we have the right element, and that the user is not dragging a
  // selection (this matches native `select` event behavior). In HTML5, select
  // fires only on input and textarea thus if there's no focused element we
  // won't dispatch.
  if (mouseDown ||
      activeElement == null ||
      activeElement != getActiveElement()) {
    return;
  }

  // Only fire when selection has actually changed.
  var currentSelection = getSelection(activeElement);
  if (!lastSelection || !shallowEqual(lastSelection, currentSelection)) {
    lastSelection = currentSelection;

    var syntheticEvent = SyntheticEvent.getPooled(
      eventTypes.select,
      activeElementID,
      nativeEvent
    );

    syntheticEvent.type = 'select';
    syntheticEvent.target = activeElement;

    EventPropagators.accumulateTwoPhaseDispatches(syntheticEvent);

    return syntheticEvent;
  }
}

/**
 * This plugin creates an `onSelect` event that normalizes select events
 * across form elements.
 *
 * Supported elements are:
 * - input (see `isTextInputElement`)
 * - textarea
 * - contentEditable
 *
 * This differs from native browser implementations in the following ways:
 * - Fires on contentEditable fields as well as inputs.
 * - Fires for collapsed selection.
 * - Fires after user input.
 */
var SelectEventPlugin = {

  eventTypes: eventTypes,

  /**
   * @param {string} topLevelType Record from `EventConstants`.
   * @param {DOMEventTarget} topLevelTarget The listening component root node.
   * @param {string} topLevelTargetID ID of `topLevelTarget`.
   * @param {object} nativeEvent Native browser event.
   * @return {*} An accumulation of synthetic events.
   * @see {EventPluginHub.extractEvents}
   */
  extractEvents: function(
      topLevelType,
      topLevelTarget,
      topLevelTargetID,
      nativeEvent) {

    switch (topLevelType) {
      // Track the input node that has focus.
      case topLevelTypes.topFocus:
        if (isTextInputElement(topLevelTarget) ||
            topLevelTarget.contentEditable === 'true') {
          activeElement = topLevelTarget;
          activeElementID = topLevelTargetID;
          lastSelection = null;
        }
        break;
      case topLevelTypes.topBlur:
        activeElement = null;
        activeElementID = null;
        lastSelection = null;
        break;

      // Don't fire the event while the user is dragging. This matches the
      // semantics of the native select event.
      case topLevelTypes.topMouseDown:
        mouseDown = true;
        break;
      case topLevelTypes.topContextMenu:
      case topLevelTypes.topMouseUp:
        mouseDown = false;
        return constructSelectEvent(nativeEvent);

      // Chrome and IE fire non-standard event when selection is changed (and
      // sometimes when it hasn't).
      // Firefox doesn't support selectionchange, so check selection status
      // after each key entry. The selection changes after keydown and before
      // keyup, but we check on keydown as well in the case of holding down a
      // key, when multiple keydown events are fired but only one keyup is.
      case topLevelTypes.topSelectionChange:
      case topLevelTypes.topKeyDown:
      case topLevelTypes.topKeyUp:
        return constructSelectEvent(nativeEvent);
    }
  }
};

module.exports = SelectEventPlugin;

},{"./EventConstants":"/Users/zordius/webtasks/node_modules/react/lib/EventConstants.js","./EventPropagators":"/Users/zordius/webtasks/node_modules/react/lib/EventPropagators.js","./ReactInputSelection":"/Users/zordius/webtasks/node_modules/react/lib/ReactInputSelection.js","./SyntheticEvent":"/Users/zordius/webtasks/node_modules/react/lib/SyntheticEvent.js","./getActiveElement":"/Users/zordius/webtasks/node_modules/react/lib/getActiveElement.js","./isTextInputElement":"/Users/zordius/webtasks/node_modules/react/lib/isTextInputElement.js","./keyOf":"/Users/zordius/webtasks/node_modules/react/lib/keyOf.js","./shallowEqual":"/Users/zordius/webtasks/node_modules/react/lib/shallowEqual.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ServerReactRootIndex.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ServerReactRootIndex
 * @typechecks
 */

"use strict";

/**
 * Size of the reactRoot ID space. We generate random numbers for React root
 * IDs and if there's a collision the events and DOM update system will
 * get confused. In the future we need a way to generate GUIDs but for
 * now this will work on a smaller scale.
 */
var GLOBAL_MOUNT_POINT_MAX = Math.pow(2, 53);

var ServerReactRootIndex = {
  createReactRootIndex: function() {
    return Math.ceil(Math.random() * GLOBAL_MOUNT_POINT_MAX);
  }
};

module.exports = ServerReactRootIndex;

},{}],"/Users/zordius/webtasks/node_modules/react/lib/SimpleEventPlugin.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule SimpleEventPlugin
 */

"use strict";

var EventConstants = require("./EventConstants");
var EventPluginUtils = require("./EventPluginUtils");
var EventPropagators = require("./EventPropagators");
var SyntheticClipboardEvent = require("./SyntheticClipboardEvent");
var SyntheticEvent = require("./SyntheticEvent");
var SyntheticFocusEvent = require("./SyntheticFocusEvent");
var SyntheticKeyboardEvent = require("./SyntheticKeyboardEvent");
var SyntheticMouseEvent = require("./SyntheticMouseEvent");
var SyntheticDragEvent = require("./SyntheticDragEvent");
var SyntheticTouchEvent = require("./SyntheticTouchEvent");
var SyntheticUIEvent = require("./SyntheticUIEvent");
var SyntheticWheelEvent = require("./SyntheticWheelEvent");

var getEventCharCode = require("./getEventCharCode");

var invariant = require("./invariant");
var keyOf = require("./keyOf");
var warning = require("./warning");

var topLevelTypes = EventConstants.topLevelTypes;

var eventTypes = {
  blur: {
    phasedRegistrationNames: {
      bubbled: keyOf({onBlur: true}),
      captured: keyOf({onBlurCapture: true})
    }
  },
  click: {
    phasedRegistrationNames: {
      bubbled: keyOf({onClick: true}),
      captured: keyOf({onClickCapture: true})
    }
  },
  contextMenu: {
    phasedRegistrationNames: {
      bubbled: keyOf({onContextMenu: true}),
      captured: keyOf({onContextMenuCapture: true})
    }
  },
  copy: {
    phasedRegistrationNames: {
      bubbled: keyOf({onCopy: true}),
      captured: keyOf({onCopyCapture: true})
    }
  },
  cut: {
    phasedRegistrationNames: {
      bubbled: keyOf({onCut: true}),
      captured: keyOf({onCutCapture: true})
    }
  },
  doubleClick: {
    phasedRegistrationNames: {
      bubbled: keyOf({onDoubleClick: true}),
      captured: keyOf({onDoubleClickCapture: true})
    }
  },
  drag: {
    phasedRegistrationNames: {
      bubbled: keyOf({onDrag: true}),
      captured: keyOf({onDragCapture: true})
    }
  },
  dragEnd: {
    phasedRegistrationNames: {
      bubbled: keyOf({onDragEnd: true}),
      captured: keyOf({onDragEndCapture: true})
    }
  },
  dragEnter: {
    phasedRegistrationNames: {
      bubbled: keyOf({onDragEnter: true}),
      captured: keyOf({onDragEnterCapture: true})
    }
  },
  dragExit: {
    phasedRegistrationNames: {
      bubbled: keyOf({onDragExit: true}),
      captured: keyOf({onDragExitCapture: true})
    }
  },
  dragLeave: {
    phasedRegistrationNames: {
      bubbled: keyOf({onDragLeave: true}),
      captured: keyOf({onDragLeaveCapture: true})
    }
  },
  dragOver: {
    phasedRegistrationNames: {
      bubbled: keyOf({onDragOver: true}),
      captured: keyOf({onDragOverCapture: true})
    }
  },
  dragStart: {
    phasedRegistrationNames: {
      bubbled: keyOf({onDragStart: true}),
      captured: keyOf({onDragStartCapture: true})
    }
  },
  drop: {
    phasedRegistrationNames: {
      bubbled: keyOf({onDrop: true}),
      captured: keyOf({onDropCapture: true})
    }
  },
  focus: {
    phasedRegistrationNames: {
      bubbled: keyOf({onFocus: true}),
      captured: keyOf({onFocusCapture: true})
    }
  },
  input: {
    phasedRegistrationNames: {
      bubbled: keyOf({onInput: true}),
      captured: keyOf({onInputCapture: true})
    }
  },
  keyDown: {
    phasedRegistrationNames: {
      bubbled: keyOf({onKeyDown: true}),
      captured: keyOf({onKeyDownCapture: true})
    }
  },
  keyPress: {
    phasedRegistrationNames: {
      bubbled: keyOf({onKeyPress: true}),
      captured: keyOf({onKeyPressCapture: true})
    }
  },
  keyUp: {
    phasedRegistrationNames: {
      bubbled: keyOf({onKeyUp: true}),
      captured: keyOf({onKeyUpCapture: true})
    }
  },
  load: {
    phasedRegistrationNames: {
      bubbled: keyOf({onLoad: true}),
      captured: keyOf({onLoadCapture: true})
    }
  },
  error: {
    phasedRegistrationNames: {
      bubbled: keyOf({onError: true}),
      captured: keyOf({onErrorCapture: true})
    }
  },
  // Note: We do not allow listening to mouseOver events. Instead, use the
  // onMouseEnter/onMouseLeave created by `EnterLeaveEventPlugin`.
  mouseDown: {
    phasedRegistrationNames: {
      bubbled: keyOf({onMouseDown: true}),
      captured: keyOf({onMouseDownCapture: true})
    }
  },
  mouseMove: {
    phasedRegistrationNames: {
      bubbled: keyOf({onMouseMove: true}),
      captured: keyOf({onMouseMoveCapture: true})
    }
  },
  mouseOut: {
    phasedRegistrationNames: {
      bubbled: keyOf({onMouseOut: true}),
      captured: keyOf({onMouseOutCapture: true})
    }
  },
  mouseOver: {
    phasedRegistrationNames: {
      bubbled: keyOf({onMouseOver: true}),
      captured: keyOf({onMouseOverCapture: true})
    }
  },
  mouseUp: {
    phasedRegistrationNames: {
      bubbled: keyOf({onMouseUp: true}),
      captured: keyOf({onMouseUpCapture: true})
    }
  },
  paste: {
    phasedRegistrationNames: {
      bubbled: keyOf({onPaste: true}),
      captured: keyOf({onPasteCapture: true})
    }
  },
  reset: {
    phasedRegistrationNames: {
      bubbled: keyOf({onReset: true}),
      captured: keyOf({onResetCapture: true})
    }
  },
  scroll: {
    phasedRegistrationNames: {
      bubbled: keyOf({onScroll: true}),
      captured: keyOf({onScrollCapture: true})
    }
  },
  submit: {
    phasedRegistrationNames: {
      bubbled: keyOf({onSubmit: true}),
      captured: keyOf({onSubmitCapture: true})
    }
  },
  touchCancel: {
    phasedRegistrationNames: {
      bubbled: keyOf({onTouchCancel: true}),
      captured: keyOf({onTouchCancelCapture: true})
    }
  },
  touchEnd: {
    phasedRegistrationNames: {
      bubbled: keyOf({onTouchEnd: true}),
      captured: keyOf({onTouchEndCapture: true})
    }
  },
  touchMove: {
    phasedRegistrationNames: {
      bubbled: keyOf({onTouchMove: true}),
      captured: keyOf({onTouchMoveCapture: true})
    }
  },
  touchStart: {
    phasedRegistrationNames: {
      bubbled: keyOf({onTouchStart: true}),
      captured: keyOf({onTouchStartCapture: true})
    }
  },
  wheel: {
    phasedRegistrationNames: {
      bubbled: keyOf({onWheel: true}),
      captured: keyOf({onWheelCapture: true})
    }
  }
};

var topLevelEventsToDispatchConfig = {
  topBlur:        eventTypes.blur,
  topClick:       eventTypes.click,
  topContextMenu: eventTypes.contextMenu,
  topCopy:        eventTypes.copy,
  topCut:         eventTypes.cut,
  topDoubleClick: eventTypes.doubleClick,
  topDrag:        eventTypes.drag,
  topDragEnd:     eventTypes.dragEnd,
  topDragEnter:   eventTypes.dragEnter,
  topDragExit:    eventTypes.dragExit,
  topDragLeave:   eventTypes.dragLeave,
  topDragOver:    eventTypes.dragOver,
  topDragStart:   eventTypes.dragStart,
  topDrop:        eventTypes.drop,
  topError:       eventTypes.error,
  topFocus:       eventTypes.focus,
  topInput:       eventTypes.input,
  topKeyDown:     eventTypes.keyDown,
  topKeyPress:    eventTypes.keyPress,
  topKeyUp:       eventTypes.keyUp,
  topLoad:        eventTypes.load,
  topMouseDown:   eventTypes.mouseDown,
  topMouseMove:   eventTypes.mouseMove,
  topMouseOut:    eventTypes.mouseOut,
  topMouseOver:   eventTypes.mouseOver,
  topMouseUp:     eventTypes.mouseUp,
  topPaste:       eventTypes.paste,
  topReset:       eventTypes.reset,
  topScroll:      eventTypes.scroll,
  topSubmit:      eventTypes.submit,
  topTouchCancel: eventTypes.touchCancel,
  topTouchEnd:    eventTypes.touchEnd,
  topTouchMove:   eventTypes.touchMove,
  topTouchStart:  eventTypes.touchStart,
  topWheel:       eventTypes.wheel
};

for (var topLevelType in topLevelEventsToDispatchConfig) {
  topLevelEventsToDispatchConfig[topLevelType].dependencies = [topLevelType];
}

var SimpleEventPlugin = {

  eventTypes: eventTypes,

  /**
   * Same as the default implementation, except cancels the event when return
   * value is false. This behavior will be disabled in a future release.
   *
   * @param {object} Event to be dispatched.
   * @param {function} Application-level callback.
   * @param {string} domID DOM ID to pass to the callback.
   */
  executeDispatch: function(event, listener, domID) {
    var returnValue = EventPluginUtils.executeDispatch(event, listener, domID);

    ("production" !== process.env.NODE_ENV ? warning(
      typeof returnValue !== 'boolean',
      'Returning `false` from an event handler is deprecated and will be ' +
      'ignored in a future release. Instead, manually call ' +
      'e.stopPropagation() or e.preventDefault(), as appropriate.'
    ) : null);

    if (returnValue === false) {
      event.stopPropagation();
      event.preventDefault();
    }
  },

  /**
   * @param {string} topLevelType Record from `EventConstants`.
   * @param {DOMEventTarget} topLevelTarget The listening component root node.
   * @param {string} topLevelTargetID ID of `topLevelTarget`.
   * @param {object} nativeEvent Native browser event.
   * @return {*} An accumulation of synthetic events.
   * @see {EventPluginHub.extractEvents}
   */
  extractEvents: function(
      topLevelType,
      topLevelTarget,
      topLevelTargetID,
      nativeEvent) {
    var dispatchConfig = topLevelEventsToDispatchConfig[topLevelType];
    if (!dispatchConfig) {
      return null;
    }
    var EventConstructor;
    switch (topLevelType) {
      case topLevelTypes.topInput:
      case topLevelTypes.topLoad:
      case topLevelTypes.topError:
      case topLevelTypes.topReset:
      case topLevelTypes.topSubmit:
        // HTML Events
        // @see http://www.w3.org/TR/html5/index.html#events-0
        EventConstructor = SyntheticEvent;
        break;
      case topLevelTypes.topKeyPress:
        // FireFox creates a keypress event for function keys too. This removes
        // the unwanted keypress events. Enter is however both printable and
        // non-printable. One would expect Tab to be as well (but it isn't).
        if (getEventCharCode(nativeEvent) === 0) {
          return null;
        }
        /* falls through */
      case topLevelTypes.topKeyDown:
      case topLevelTypes.topKeyUp:
        EventConstructor = SyntheticKeyboardEvent;
        break;
      case topLevelTypes.topBlur:
      case topLevelTypes.topFocus:
        EventConstructor = SyntheticFocusEvent;
        break;
      case topLevelTypes.topClick:
        // Firefox creates a click event on right mouse clicks. This removes the
        // unwanted click events.
        if (nativeEvent.button === 2) {
          return null;
        }
        /* falls through */
      case topLevelTypes.topContextMenu:
      case topLevelTypes.topDoubleClick:
      case topLevelTypes.topMouseDown:
      case topLevelTypes.topMouseMove:
      case topLevelTypes.topMouseOut:
      case topLevelTypes.topMouseOver:
      case topLevelTypes.topMouseUp:
        EventConstructor = SyntheticMouseEvent;
        break;
      case topLevelTypes.topDrag:
      case topLevelTypes.topDragEnd:
      case topLevelTypes.topDragEnter:
      case topLevelTypes.topDragExit:
      case topLevelTypes.topDragLeave:
      case topLevelTypes.topDragOver:
      case topLevelTypes.topDragStart:
      case topLevelTypes.topDrop:
        EventConstructor = SyntheticDragEvent;
        break;
      case topLevelTypes.topTouchCancel:
      case topLevelTypes.topTouchEnd:
      case topLevelTypes.topTouchMove:
      case topLevelTypes.topTouchStart:
        EventConstructor = SyntheticTouchEvent;
        break;
      case topLevelTypes.topScroll:
        EventConstructor = SyntheticUIEvent;
        break;
      case topLevelTypes.topWheel:
        EventConstructor = SyntheticWheelEvent;
        break;
      case topLevelTypes.topCopy:
      case topLevelTypes.topCut:
      case topLevelTypes.topPaste:
        EventConstructor = SyntheticClipboardEvent;
        break;
    }
    ("production" !== process.env.NODE_ENV ? invariant(
      EventConstructor,
      'SimpleEventPlugin: Unhandled event type, `%s`.',
      topLevelType
    ) : invariant(EventConstructor));
    var event = EventConstructor.getPooled(
      dispatchConfig,
      topLevelTargetID,
      nativeEvent
    );
    EventPropagators.accumulateTwoPhaseDispatches(event);
    return event;
  }

};

module.exports = SimpleEventPlugin;

}).call(this,require('_process'))
},{"./EventConstants":"/Users/zordius/webtasks/node_modules/react/lib/EventConstants.js","./EventPluginUtils":"/Users/zordius/webtasks/node_modules/react/lib/EventPluginUtils.js","./EventPropagators":"/Users/zordius/webtasks/node_modules/react/lib/EventPropagators.js","./SyntheticClipboardEvent":"/Users/zordius/webtasks/node_modules/react/lib/SyntheticClipboardEvent.js","./SyntheticDragEvent":"/Users/zordius/webtasks/node_modules/react/lib/SyntheticDragEvent.js","./SyntheticEvent":"/Users/zordius/webtasks/node_modules/react/lib/SyntheticEvent.js","./SyntheticFocusEvent":"/Users/zordius/webtasks/node_modules/react/lib/SyntheticFocusEvent.js","./SyntheticKeyboardEvent":"/Users/zordius/webtasks/node_modules/react/lib/SyntheticKeyboardEvent.js","./SyntheticMouseEvent":"/Users/zordius/webtasks/node_modules/react/lib/SyntheticMouseEvent.js","./SyntheticTouchEvent":"/Users/zordius/webtasks/node_modules/react/lib/SyntheticTouchEvent.js","./SyntheticUIEvent":"/Users/zordius/webtasks/node_modules/react/lib/SyntheticUIEvent.js","./SyntheticWheelEvent":"/Users/zordius/webtasks/node_modules/react/lib/SyntheticWheelEvent.js","./getEventCharCode":"/Users/zordius/webtasks/node_modules/react/lib/getEventCharCode.js","./invariant":"/Users/zordius/webtasks/node_modules/react/lib/invariant.js","./keyOf":"/Users/zordius/webtasks/node_modules/react/lib/keyOf.js","./warning":"/Users/zordius/webtasks/node_modules/react/lib/warning.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/SyntheticClipboardEvent.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule SyntheticClipboardEvent
 * @typechecks static-only
 */

"use strict";

var SyntheticEvent = require("./SyntheticEvent");

/**
 * @interface Event
 * @see http://www.w3.org/TR/clipboard-apis/
 */
var ClipboardEventInterface = {
  clipboardData: function(event) {
    return (
      'clipboardData' in event ?
        event.clipboardData :
        window.clipboardData
    );
  }
};

/**
 * @param {object} dispatchConfig Configuration used to dispatch this event.
 * @param {string} dispatchMarker Marker identifying the event target.
 * @param {object} nativeEvent Native browser event.
 * @extends {SyntheticUIEvent}
 */
function SyntheticClipboardEvent(dispatchConfig, dispatchMarker, nativeEvent) {
  SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
}

SyntheticEvent.augmentClass(SyntheticClipboardEvent, ClipboardEventInterface);

module.exports = SyntheticClipboardEvent;


},{"./SyntheticEvent":"/Users/zordius/webtasks/node_modules/react/lib/SyntheticEvent.js"}],"/Users/zordius/webtasks/node_modules/react/lib/SyntheticCompositionEvent.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule SyntheticCompositionEvent
 * @typechecks static-only
 */

"use strict";

var SyntheticEvent = require("./SyntheticEvent");

/**
 * @interface Event
 * @see http://www.w3.org/TR/DOM-Level-3-Events/#events-compositionevents
 */
var CompositionEventInterface = {
  data: null
};

/**
 * @param {object} dispatchConfig Configuration used to dispatch this event.
 * @param {string} dispatchMarker Marker identifying the event target.
 * @param {object} nativeEvent Native browser event.
 * @extends {SyntheticUIEvent}
 */
function SyntheticCompositionEvent(
  dispatchConfig,
  dispatchMarker,
  nativeEvent) {
  SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
}

SyntheticEvent.augmentClass(
  SyntheticCompositionEvent,
  CompositionEventInterface
);

module.exports = SyntheticCompositionEvent;


},{"./SyntheticEvent":"/Users/zordius/webtasks/node_modules/react/lib/SyntheticEvent.js"}],"/Users/zordius/webtasks/node_modules/react/lib/SyntheticDragEvent.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule SyntheticDragEvent
 * @typechecks static-only
 */

"use strict";

var SyntheticMouseEvent = require("./SyntheticMouseEvent");

/**
 * @interface DragEvent
 * @see http://www.w3.org/TR/DOM-Level-3-Events/
 */
var DragEventInterface = {
  dataTransfer: null
};

/**
 * @param {object} dispatchConfig Configuration used to dispatch this event.
 * @param {string} dispatchMarker Marker identifying the event target.
 * @param {object} nativeEvent Native browser event.
 * @extends {SyntheticUIEvent}
 */
function SyntheticDragEvent(dispatchConfig, dispatchMarker, nativeEvent) {
  SyntheticMouseEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
}

SyntheticMouseEvent.augmentClass(SyntheticDragEvent, DragEventInterface);

module.exports = SyntheticDragEvent;

},{"./SyntheticMouseEvent":"/Users/zordius/webtasks/node_modules/react/lib/SyntheticMouseEvent.js"}],"/Users/zordius/webtasks/node_modules/react/lib/SyntheticEvent.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule SyntheticEvent
 * @typechecks static-only
 */

"use strict";

var PooledClass = require("./PooledClass");

var assign = require("./Object.assign");
var emptyFunction = require("./emptyFunction");
var getEventTarget = require("./getEventTarget");

/**
 * @interface Event
 * @see http://www.w3.org/TR/DOM-Level-3-Events/
 */
var EventInterface = {
  type: null,
  target: getEventTarget,
  // currentTarget is set when dispatching; no use in copying it here
  currentTarget: emptyFunction.thatReturnsNull,
  eventPhase: null,
  bubbles: null,
  cancelable: null,
  timeStamp: function(event) {
    return event.timeStamp || Date.now();
  },
  defaultPrevented: null,
  isTrusted: null
};

/**
 * Synthetic events are dispatched by event plugins, typically in response to a
 * top-level event delegation handler.
 *
 * These systems should generally use pooling to reduce the frequency of garbage
 * collection. The system should check `isPersistent` to determine whether the
 * event should be released into the pool after being dispatched. Users that
 * need a persisted event should invoke `persist`.
 *
 * Synthetic events (and subclasses) implement the DOM Level 3 Events API by
 * normalizing browser quirks. Subclasses do not necessarily have to implement a
 * DOM interface; custom application-specific events can also subclass this.
 *
 * @param {object} dispatchConfig Configuration used to dispatch this event.
 * @param {string} dispatchMarker Marker identifying the event target.
 * @param {object} nativeEvent Native browser event.
 */
function SyntheticEvent(dispatchConfig, dispatchMarker, nativeEvent) {
  this.dispatchConfig = dispatchConfig;
  this.dispatchMarker = dispatchMarker;
  this.nativeEvent = nativeEvent;

  var Interface = this.constructor.Interface;
  for (var propName in Interface) {
    if (!Interface.hasOwnProperty(propName)) {
      continue;
    }
    var normalize = Interface[propName];
    if (normalize) {
      this[propName] = normalize(nativeEvent);
    } else {
      this[propName] = nativeEvent[propName];
    }
  }

  var defaultPrevented = nativeEvent.defaultPrevented != null ?
    nativeEvent.defaultPrevented :
    nativeEvent.returnValue === false;
  if (defaultPrevented) {
    this.isDefaultPrevented = emptyFunction.thatReturnsTrue;
  } else {
    this.isDefaultPrevented = emptyFunction.thatReturnsFalse;
  }
  this.isPropagationStopped = emptyFunction.thatReturnsFalse;
}

assign(SyntheticEvent.prototype, {

  preventDefault: function() {
    this.defaultPrevented = true;
    var event = this.nativeEvent;
    event.preventDefault ? event.preventDefault() : event.returnValue = false;
    this.isDefaultPrevented = emptyFunction.thatReturnsTrue;
  },

  stopPropagation: function() {
    var event = this.nativeEvent;
    event.stopPropagation ? event.stopPropagation() : event.cancelBubble = true;
    this.isPropagationStopped = emptyFunction.thatReturnsTrue;
  },

  /**
   * We release all dispatched `SyntheticEvent`s after each event loop, adding
   * them back into the pool. This allows a way to hold onto a reference that
   * won't be added back into the pool.
   */
  persist: function() {
    this.isPersistent = emptyFunction.thatReturnsTrue;
  },

  /**
   * Checks if this event should be released back into the pool.
   *
   * @return {boolean} True if this should not be released, false otherwise.
   */
  isPersistent: emptyFunction.thatReturnsFalse,

  /**
   * `PooledClass` looks for `destructor` on each instance it releases.
   */
  destructor: function() {
    var Interface = this.constructor.Interface;
    for (var propName in Interface) {
      this[propName] = null;
    }
    this.dispatchConfig = null;
    this.dispatchMarker = null;
    this.nativeEvent = null;
  }

});

SyntheticEvent.Interface = EventInterface;

/**
 * Helper to reduce boilerplate when creating subclasses.
 *
 * @param {function} Class
 * @param {?object} Interface
 */
SyntheticEvent.augmentClass = function(Class, Interface) {
  var Super = this;

  var prototype = Object.create(Super.prototype);
  assign(prototype, Class.prototype);
  Class.prototype = prototype;
  Class.prototype.constructor = Class;

  Class.Interface = assign({}, Super.Interface, Interface);
  Class.augmentClass = Super.augmentClass;

  PooledClass.addPoolingTo(Class, PooledClass.threeArgumentPooler);
};

PooledClass.addPoolingTo(SyntheticEvent, PooledClass.threeArgumentPooler);

module.exports = SyntheticEvent;

},{"./Object.assign":"/Users/zordius/webtasks/node_modules/react/lib/Object.assign.js","./PooledClass":"/Users/zordius/webtasks/node_modules/react/lib/PooledClass.js","./emptyFunction":"/Users/zordius/webtasks/node_modules/react/lib/emptyFunction.js","./getEventTarget":"/Users/zordius/webtasks/node_modules/react/lib/getEventTarget.js"}],"/Users/zordius/webtasks/node_modules/react/lib/SyntheticFocusEvent.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule SyntheticFocusEvent
 * @typechecks static-only
 */

"use strict";

var SyntheticUIEvent = require("./SyntheticUIEvent");

/**
 * @interface FocusEvent
 * @see http://www.w3.org/TR/DOM-Level-3-Events/
 */
var FocusEventInterface = {
  relatedTarget: null
};

/**
 * @param {object} dispatchConfig Configuration used to dispatch this event.
 * @param {string} dispatchMarker Marker identifying the event target.
 * @param {object} nativeEvent Native browser event.
 * @extends {SyntheticUIEvent}
 */
function SyntheticFocusEvent(dispatchConfig, dispatchMarker, nativeEvent) {
  SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
}

SyntheticUIEvent.augmentClass(SyntheticFocusEvent, FocusEventInterface);

module.exports = SyntheticFocusEvent;

},{"./SyntheticUIEvent":"/Users/zordius/webtasks/node_modules/react/lib/SyntheticUIEvent.js"}],"/Users/zordius/webtasks/node_modules/react/lib/SyntheticInputEvent.js":[function(require,module,exports){
/**
 * Copyright 2013 Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule SyntheticInputEvent
 * @typechecks static-only
 */

"use strict";

var SyntheticEvent = require("./SyntheticEvent");

/**
 * @interface Event
 * @see http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105
 *      /#events-inputevents
 */
var InputEventInterface = {
  data: null
};

/**
 * @param {object} dispatchConfig Configuration used to dispatch this event.
 * @param {string} dispatchMarker Marker identifying the event target.
 * @param {object} nativeEvent Native browser event.
 * @extends {SyntheticUIEvent}
 */
function SyntheticInputEvent(
  dispatchConfig,
  dispatchMarker,
  nativeEvent) {
  SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
}

SyntheticEvent.augmentClass(
  SyntheticInputEvent,
  InputEventInterface
);

module.exports = SyntheticInputEvent;


},{"./SyntheticEvent":"/Users/zordius/webtasks/node_modules/react/lib/SyntheticEvent.js"}],"/Users/zordius/webtasks/node_modules/react/lib/SyntheticKeyboardEvent.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule SyntheticKeyboardEvent
 * @typechecks static-only
 */

"use strict";

var SyntheticUIEvent = require("./SyntheticUIEvent");

var getEventCharCode = require("./getEventCharCode");
var getEventKey = require("./getEventKey");
var getEventModifierState = require("./getEventModifierState");

/**
 * @interface KeyboardEvent
 * @see http://www.w3.org/TR/DOM-Level-3-Events/
 */
var KeyboardEventInterface = {
  key: getEventKey,
  location: null,
  ctrlKey: null,
  shiftKey: null,
  altKey: null,
  metaKey: null,
  repeat: null,
  locale: null,
  getModifierState: getEventModifierState,
  // Legacy Interface
  charCode: function(event) {
    // `charCode` is the result of a KeyPress event and represents the value of
    // the actual printable character.

    // KeyPress is deprecated, but its replacement is not yet final and not
    // implemented in any major browser. Only KeyPress has charCode.
    if (event.type === 'keypress') {
      return getEventCharCode(event);
    }
    return 0;
  },
  keyCode: function(event) {
    // `keyCode` is the result of a KeyDown/Up event and represents the value of
    // physical keyboard key.

    // The actual meaning of the value depends on the users' keyboard layout
    // which cannot be detected. Assuming that it is a US keyboard layout
    // provides a surprisingly accurate mapping for US and European users.
    // Due to this, it is left to the user to implement at this time.
    if (event.type === 'keydown' || event.type === 'keyup') {
      return event.keyCode;
    }
    return 0;
  },
  which: function(event) {
    // `which` is an alias for either `keyCode` or `charCode` depending on the
    // type of the event.
    if (event.type === 'keypress') {
      return getEventCharCode(event);
    }
    if (event.type === 'keydown' || event.type === 'keyup') {
      return event.keyCode;
    }
    return 0;
  }
};

/**
 * @param {object} dispatchConfig Configuration used to dispatch this event.
 * @param {string} dispatchMarker Marker identifying the event target.
 * @param {object} nativeEvent Native browser event.
 * @extends {SyntheticUIEvent}
 */
function SyntheticKeyboardEvent(dispatchConfig, dispatchMarker, nativeEvent) {
  SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
}

SyntheticUIEvent.augmentClass(SyntheticKeyboardEvent, KeyboardEventInterface);

module.exports = SyntheticKeyboardEvent;

},{"./SyntheticUIEvent":"/Users/zordius/webtasks/node_modules/react/lib/SyntheticUIEvent.js","./getEventCharCode":"/Users/zordius/webtasks/node_modules/react/lib/getEventCharCode.js","./getEventKey":"/Users/zordius/webtasks/node_modules/react/lib/getEventKey.js","./getEventModifierState":"/Users/zordius/webtasks/node_modules/react/lib/getEventModifierState.js"}],"/Users/zordius/webtasks/node_modules/react/lib/SyntheticMouseEvent.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule SyntheticMouseEvent
 * @typechecks static-only
 */

"use strict";

var SyntheticUIEvent = require("./SyntheticUIEvent");
var ViewportMetrics = require("./ViewportMetrics");

var getEventModifierState = require("./getEventModifierState");

/**
 * @interface MouseEvent
 * @see http://www.w3.org/TR/DOM-Level-3-Events/
 */
var MouseEventInterface = {
  screenX: null,
  screenY: null,
  clientX: null,
  clientY: null,
  ctrlKey: null,
  shiftKey: null,
  altKey: null,
  metaKey: null,
  getModifierState: getEventModifierState,
  button: function(event) {
    // Webkit, Firefox, IE9+
    // which:  1 2 3
    // button: 0 1 2 (standard)
    var button = event.button;
    if ('which' in event) {
      return button;
    }
    // IE<9
    // which:  undefined
    // button: 0 0 0
    // button: 1 4 2 (onmouseup)
    return button === 2 ? 2 : button === 4 ? 1 : 0;
  },
  buttons: null,
  relatedTarget: function(event) {
    return event.relatedTarget || (
      event.fromElement === event.srcElement ?
        event.toElement :
        event.fromElement
    );
  },
  // "Proprietary" Interface.
  pageX: function(event) {
    return 'pageX' in event ?
      event.pageX :
      event.clientX + ViewportMetrics.currentScrollLeft;
  },
  pageY: function(event) {
    return 'pageY' in event ?
      event.pageY :
      event.clientY + ViewportMetrics.currentScrollTop;
  }
};

/**
 * @param {object} dispatchConfig Configuration used to dispatch this event.
 * @param {string} dispatchMarker Marker identifying the event target.
 * @param {object} nativeEvent Native browser event.
 * @extends {SyntheticUIEvent}
 */
function SyntheticMouseEvent(dispatchConfig, dispatchMarker, nativeEvent) {
  SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
}

SyntheticUIEvent.augmentClass(SyntheticMouseEvent, MouseEventInterface);

module.exports = SyntheticMouseEvent;

},{"./SyntheticUIEvent":"/Users/zordius/webtasks/node_modules/react/lib/SyntheticUIEvent.js","./ViewportMetrics":"/Users/zordius/webtasks/node_modules/react/lib/ViewportMetrics.js","./getEventModifierState":"/Users/zordius/webtasks/node_modules/react/lib/getEventModifierState.js"}],"/Users/zordius/webtasks/node_modules/react/lib/SyntheticTouchEvent.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule SyntheticTouchEvent
 * @typechecks static-only
 */

"use strict";

var SyntheticUIEvent = require("./SyntheticUIEvent");

var getEventModifierState = require("./getEventModifierState");

/**
 * @interface TouchEvent
 * @see http://www.w3.org/TR/touch-events/
 */
var TouchEventInterface = {
  touches: null,
  targetTouches: null,
  changedTouches: null,
  altKey: null,
  metaKey: null,
  ctrlKey: null,
  shiftKey: null,
  getModifierState: getEventModifierState
};

/**
 * @param {object} dispatchConfig Configuration used to dispatch this event.
 * @param {string} dispatchMarker Marker identifying the event target.
 * @param {object} nativeEvent Native browser event.
 * @extends {SyntheticUIEvent}
 */
function SyntheticTouchEvent(dispatchConfig, dispatchMarker, nativeEvent) {
  SyntheticUIEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
}

SyntheticUIEvent.augmentClass(SyntheticTouchEvent, TouchEventInterface);

module.exports = SyntheticTouchEvent;

},{"./SyntheticUIEvent":"/Users/zordius/webtasks/node_modules/react/lib/SyntheticUIEvent.js","./getEventModifierState":"/Users/zordius/webtasks/node_modules/react/lib/getEventModifierState.js"}],"/Users/zordius/webtasks/node_modules/react/lib/SyntheticUIEvent.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule SyntheticUIEvent
 * @typechecks static-only
 */

"use strict";

var SyntheticEvent = require("./SyntheticEvent");

var getEventTarget = require("./getEventTarget");

/**
 * @interface UIEvent
 * @see http://www.w3.org/TR/DOM-Level-3-Events/
 */
var UIEventInterface = {
  view: function(event) {
    if (event.view) {
      return event.view;
    }

    var target = getEventTarget(event);
    if (target != null && target.window === target) {
      // target is a window object
      return target;
    }

    var doc = target.ownerDocument;
    // TODO: Figure out why `ownerDocument` is sometimes undefined in IE8.
    if (doc) {
      return doc.defaultView || doc.parentWindow;
    } else {
      return window;
    }
  },
  detail: function(event) {
    return event.detail || 0;
  }
};

/**
 * @param {object} dispatchConfig Configuration used to dispatch this event.
 * @param {string} dispatchMarker Marker identifying the event target.
 * @param {object} nativeEvent Native browser event.
 * @extends {SyntheticEvent}
 */
function SyntheticUIEvent(dispatchConfig, dispatchMarker, nativeEvent) {
  SyntheticEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
}

SyntheticEvent.augmentClass(SyntheticUIEvent, UIEventInterface);

module.exports = SyntheticUIEvent;

},{"./SyntheticEvent":"/Users/zordius/webtasks/node_modules/react/lib/SyntheticEvent.js","./getEventTarget":"/Users/zordius/webtasks/node_modules/react/lib/getEventTarget.js"}],"/Users/zordius/webtasks/node_modules/react/lib/SyntheticWheelEvent.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule SyntheticWheelEvent
 * @typechecks static-only
 */

"use strict";

var SyntheticMouseEvent = require("./SyntheticMouseEvent");

/**
 * @interface WheelEvent
 * @see http://www.w3.org/TR/DOM-Level-3-Events/
 */
var WheelEventInterface = {
  deltaX: function(event) {
    return (
      'deltaX' in event ? event.deltaX :
      // Fallback to `wheelDeltaX` for Webkit and normalize (right is positive).
      'wheelDeltaX' in event ? -event.wheelDeltaX : 0
    );
  },
  deltaY: function(event) {
    return (
      'deltaY' in event ? event.deltaY :
      // Fallback to `wheelDeltaY` for Webkit and normalize (down is positive).
      'wheelDeltaY' in event ? -event.wheelDeltaY :
      // Fallback to `wheelDelta` for IE<9 and normalize (down is positive).
      'wheelDelta' in event ? -event.wheelDelta : 0
    );
  },
  deltaZ: null,

  // Browsers without "deltaMode" is reporting in raw wheel delta where one
  // notch on the scroll is always +/- 120, roughly equivalent to pixels.
  // A good approximation of DOM_DELTA_LINE (1) is 5% of viewport size or
  // ~40 pixels, for DOM_DELTA_SCREEN (2) it is 87.5% of viewport size.
  deltaMode: null
};

/**
 * @param {object} dispatchConfig Configuration used to dispatch this event.
 * @param {string} dispatchMarker Marker identifying the event target.
 * @param {object} nativeEvent Native browser event.
 * @extends {SyntheticMouseEvent}
 */
function SyntheticWheelEvent(dispatchConfig, dispatchMarker, nativeEvent) {
  SyntheticMouseEvent.call(this, dispatchConfig, dispatchMarker, nativeEvent);
}

SyntheticMouseEvent.augmentClass(SyntheticWheelEvent, WheelEventInterface);

module.exports = SyntheticWheelEvent;

},{"./SyntheticMouseEvent":"/Users/zordius/webtasks/node_modules/react/lib/SyntheticMouseEvent.js"}],"/Users/zordius/webtasks/node_modules/react/lib/Transaction.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule Transaction
 */

"use strict";

var invariant = require("./invariant");

/**
 * `Transaction` creates a black box that is able to wrap any method such that
 * certain invariants are maintained before and after the method is invoked
 * (Even if an exception is thrown while invoking the wrapped method). Whoever
 * instantiates a transaction can provide enforcers of the invariants at
 * creation time. The `Transaction` class itself will supply one additional
 * automatic invariant for you - the invariant that any transaction instance
 * should not be run while it is already being run. You would typically create a
 * single instance of a `Transaction` for reuse multiple times, that potentially
 * is used to wrap several different methods. Wrappers are extremely simple -
 * they only require implementing two methods.
 *
 * <pre>
 *                       wrappers (injected at creation time)
 *                                      +        +
 *                                      |        |
 *                    +-----------------|--------|--------------+
 *                    |                 v        |              |
 *                    |      +---------------+   |              |
 *                    |   +--|    wrapper1   |---|----+         |
 *                    |   |  +---------------+   v    |         |
 *                    |   |          +-------------+  |         |
 *                    |   |     +----|   wrapper2  |--------+   |
 *                    |   |     |    +-------------+  |     |   |
 *                    |   |     |                     |     |   |
 *                    |   v     v                     v     v   | wrapper
 *                    | +---+ +---+   +---------+   +---+ +---+ | invariants
 * perform(anyMethod) | |   | |   |   |         |   |   | |   | | maintained
 * +----------------->|-|---|-|---|-->|anyMethod|---|---|-|---|-|-------->
 *                    | |   | |   |   |         |   |   | |   | |
 *                    | |   | |   |   |         |   |   | |   | |
 *                    | |   | |   |   |         |   |   | |   | |
 *                    | +---+ +---+   +---------+   +---+ +---+ |
 *                    |  initialize                    close    |
 *                    +-----------------------------------------+
 * </pre>
 *
 * Use cases:
 * - Preserving the input selection ranges before/after reconciliation.
 *   Restoring selection even in the event of an unexpected error.
 * - Deactivating events while rearranging the DOM, preventing blurs/focuses,
 *   while guaranteeing that afterwards, the event system is reactivated.
 * - Flushing a queue of collected DOM mutations to the main UI thread after a
 *   reconciliation takes place in a worker thread.
 * - Invoking any collected `componentDidUpdate` callbacks after rendering new
 *   content.
 * - (Future use case): Wrapping particular flushes of the `ReactWorker` queue
 *   to preserve the `scrollTop` (an automatic scroll aware DOM).
 * - (Future use case): Layout calculations before and after DOM upates.
 *
 * Transactional plugin API:
 * - A module that has an `initialize` method that returns any precomputation.
 * - and a `close` method that accepts the precomputation. `close` is invoked
 *   when the wrapped process is completed, or has failed.
 *
 * @param {Array<TransactionalWrapper>} transactionWrapper Wrapper modules
 * that implement `initialize` and `close`.
 * @return {Transaction} Single transaction for reuse in thread.
 *
 * @class Transaction
 */
var Mixin = {
  /**
   * Sets up this instance so that it is prepared for collecting metrics. Does
   * so such that this setup method may be used on an instance that is already
   * initialized, in a way that does not consume additional memory upon reuse.
   * That can be useful if you decide to make your subclass of this mixin a
   * "PooledClass".
   */
  reinitializeTransaction: function() {
    this.transactionWrappers = this.getTransactionWrappers();
    if (!this.wrapperInitData) {
      this.wrapperInitData = [];
    } else {
      this.wrapperInitData.length = 0;
    }
    this._isInTransaction = false;
  },

  _isInTransaction: false,

  /**
   * @abstract
   * @return {Array<TransactionWrapper>} Array of transaction wrappers.
   */
  getTransactionWrappers: null,

  isInTransaction: function() {
    return !!this._isInTransaction;
  },

  /**
   * Executes the function within a safety window. Use this for the top level
   * methods that result in large amounts of computation/mutations that would
   * need to be safety checked.
   *
   * @param {function} method Member of scope to call.
   * @param {Object} scope Scope to invoke from.
   * @param {Object?=} args... Arguments to pass to the method (optional).
   *                           Helps prevent need to bind in many cases.
   * @return Return value from `method`.
   */
  perform: function(method, scope, a, b, c, d, e, f) {
    ("production" !== process.env.NODE_ENV ? invariant(
      !this.isInTransaction(),
      'Transaction.perform(...): Cannot initialize a transaction when there ' +
      'is already an outstanding transaction.'
    ) : invariant(!this.isInTransaction()));
    var errorThrown;
    var ret;
    try {
      this._isInTransaction = true;
      // Catching errors makes debugging more difficult, so we start with
      // errorThrown set to true before setting it to false after calling
      // close -- if it's still set to true in the finally block, it means
      // one of these calls threw.
      errorThrown = true;
      this.initializeAll(0);
      ret = method.call(scope, a, b, c, d, e, f);
      errorThrown = false;
    } finally {
      try {
        if (errorThrown) {
          // If `method` throws, prefer to show that stack trace over any thrown
          // by invoking `closeAll`.
          try {
            this.closeAll(0);
          } catch (err) {
          }
        } else {
          // Since `method` didn't throw, we don't want to silence the exception
          // here.
          this.closeAll(0);
        }
      } finally {
        this._isInTransaction = false;
      }
    }
    return ret;
  },

  initializeAll: function(startIndex) {
    var transactionWrappers = this.transactionWrappers;
    for (var i = startIndex; i < transactionWrappers.length; i++) {
      var wrapper = transactionWrappers[i];
      try {
        // Catching errors makes debugging more difficult, so we start with the
        // OBSERVED_ERROR state before overwriting it with the real return value
        // of initialize -- if it's still set to OBSERVED_ERROR in the finally
        // block, it means wrapper.initialize threw.
        this.wrapperInitData[i] = Transaction.OBSERVED_ERROR;
        this.wrapperInitData[i] = wrapper.initialize ?
          wrapper.initialize.call(this) :
          null;
      } finally {
        if (this.wrapperInitData[i] === Transaction.OBSERVED_ERROR) {
          // The initializer for wrapper i threw an error; initialize the
          // remaining wrappers but silence any exceptions from them to ensure
          // that the first error is the one to bubble up.
          try {
            this.initializeAll(i + 1);
          } catch (err) {
          }
        }
      }
    }
  },

  /**
   * Invokes each of `this.transactionWrappers.close[i]` functions, passing into
   * them the respective return values of `this.transactionWrappers.init[i]`
   * (`close`rs that correspond to initializers that failed will not be
   * invoked).
   */
  closeAll: function(startIndex) {
    ("production" !== process.env.NODE_ENV ? invariant(
      this.isInTransaction(),
      'Transaction.closeAll(): Cannot close transaction when none are open.'
    ) : invariant(this.isInTransaction()));
    var transactionWrappers = this.transactionWrappers;
    for (var i = startIndex; i < transactionWrappers.length; i++) {
      var wrapper = transactionWrappers[i];
      var initData = this.wrapperInitData[i];
      var errorThrown;
      try {
        // Catching errors makes debugging more difficult, so we start with
        // errorThrown set to true before setting it to false after calling
        // close -- if it's still set to true in the finally block, it means
        // wrapper.close threw.
        errorThrown = true;
        if (initData !== Transaction.OBSERVED_ERROR) {
          wrapper.close && wrapper.close.call(this, initData);
        }
        errorThrown = false;
      } finally {
        if (errorThrown) {
          // The closer for wrapper i threw an error; close the remaining
          // wrappers but silence any exceptions from them to ensure that the
          // first error is the one to bubble up.
          try {
            this.closeAll(i + 1);
          } catch (e) {
          }
        }
      }
    }
    this.wrapperInitData.length = 0;
  }
};

var Transaction = {

  Mixin: Mixin,

  /**
   * Token to look for to determine if an error occured.
   */
  OBSERVED_ERROR: {}

};

module.exports = Transaction;

}).call(this,require('_process'))
},{"./invariant":"/Users/zordius/webtasks/node_modules/react/lib/invariant.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/ViewportMetrics.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule ViewportMetrics
 */

"use strict";

var getUnboundedScrollPosition = require("./getUnboundedScrollPosition");

var ViewportMetrics = {

  currentScrollLeft: 0,

  currentScrollTop: 0,

  refreshScrollValues: function() {
    var scrollPosition = getUnboundedScrollPosition(window);
    ViewportMetrics.currentScrollLeft = scrollPosition.x;
    ViewportMetrics.currentScrollTop = scrollPosition.y;
  }

};

module.exports = ViewportMetrics;

},{"./getUnboundedScrollPosition":"/Users/zordius/webtasks/node_modules/react/lib/getUnboundedScrollPosition.js"}],"/Users/zordius/webtasks/node_modules/react/lib/accumulateInto.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule accumulateInto
 */

"use strict";

var invariant = require("./invariant");

/**
 *
 * Accumulates items that must not be null or undefined into the first one. This
 * is used to conserve memory by avoiding array allocations, and thus sacrifices
 * API cleanness. Since `current` can be null before being passed in and not
 * null after this function, make sure to assign it back to `current`:
 *
 * `a = accumulateInto(a, b);`
 *
 * This API should be sparingly used. Try `accumulate` for something cleaner.
 *
 * @return {*|array<*>} An accumulation of items.
 */

function accumulateInto(current, next) {
  ("production" !== process.env.NODE_ENV ? invariant(
    next != null,
    'accumulateInto(...): Accumulated items must not be null or undefined.'
  ) : invariant(next != null));
  if (current == null) {
    return next;
  }

  // Both are not empty. Warning: Never call x.concat(y) when you are not
  // certain that x is an Array (x could be a string with concat method).
  var currentIsArray = Array.isArray(current);
  var nextIsArray = Array.isArray(next);

  if (currentIsArray && nextIsArray) {
    current.push.apply(current, next);
    return current;
  }

  if (currentIsArray) {
    current.push(next);
    return current;
  }

  if (nextIsArray) {
    // A bit too dangerous to mutate `next`.
    return [current].concat(next);
  }

  return [current, next];
}

module.exports = accumulateInto;

}).call(this,require('_process'))
},{"./invariant":"/Users/zordius/webtasks/node_modules/react/lib/invariant.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/adler32.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule adler32
 */

/* jslint bitwise:true */

"use strict";

var MOD = 65521;

// This is a clean-room implementation of adler32 designed for detecting
// if markup is not what we expect it to be. It does not need to be
// cryptographically strong, only reasonably good at detecting if markup
// generated on the server is different than that on the client.
function adler32(data) {
  var a = 1;
  var b = 0;
  for (var i = 0; i < data.length; i++) {
    a = (a + data.charCodeAt(i)) % MOD;
    b = (b + a) % MOD;
  }
  return a | (b << 16);
}

module.exports = adler32;

},{}],"/Users/zordius/webtasks/node_modules/react/lib/camelize.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule camelize
 * @typechecks
 */

var _hyphenPattern = /-(.)/g;

/**
 * Camelcases a hyphenated string, for example:
 *
 *   > camelize('background-color')
 *   < "backgroundColor"
 *
 * @param {string} string
 * @return {string}
 */
function camelize(string) {
  return string.replace(_hyphenPattern, function(_, character) {
    return character.toUpperCase();
  });
}

module.exports = camelize;

},{}],"/Users/zordius/webtasks/node_modules/react/lib/camelizeStyleName.js":[function(require,module,exports){
/**
 * Copyright 2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule camelizeStyleName
 * @typechecks
 */

"use strict";

var camelize = require("./camelize");

var msPattern = /^-ms-/;

/**
 * Camelcases a hyphenated CSS property name, for example:
 *
 *   > camelizeStyleName('background-color')
 *   < "backgroundColor"
 *   > camelizeStyleName('-moz-transition')
 *   < "MozTransition"
 *   > camelizeStyleName('-ms-transition')
 *   < "msTransition"
 *
 * As Andi Smith suggests
 * (http://www.andismith.com/blog/2012/02/modernizr-prefixed/), an `-ms` prefix
 * is converted to lowercase `ms`.
 *
 * @param {string} string
 * @return {string}
 */
function camelizeStyleName(string) {
  return camelize(string.replace(msPattern, 'ms-'));
}

module.exports = camelizeStyleName;

},{"./camelize":"/Users/zordius/webtasks/node_modules/react/lib/camelize.js"}],"/Users/zordius/webtasks/node_modules/react/lib/containsNode.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule containsNode
 * @typechecks
 */

var isTextNode = require("./isTextNode");

/*jslint bitwise:true */

/**
 * Checks if a given DOM node contains or is another DOM node.
 *
 * @param {?DOMNode} outerNode Outer DOM node.
 * @param {?DOMNode} innerNode Inner DOM node.
 * @return {boolean} True if `outerNode` contains or is `innerNode`.
 */
function containsNode(outerNode, innerNode) {
  if (!outerNode || !innerNode) {
    return false;
  } else if (outerNode === innerNode) {
    return true;
  } else if (isTextNode(outerNode)) {
    return false;
  } else if (isTextNode(innerNode)) {
    return containsNode(outerNode, innerNode.parentNode);
  } else if (outerNode.contains) {
    return outerNode.contains(innerNode);
  } else if (outerNode.compareDocumentPosition) {
    return !!(outerNode.compareDocumentPosition(innerNode) & 16);
  } else {
    return false;
  }
}

module.exports = containsNode;

},{"./isTextNode":"/Users/zordius/webtasks/node_modules/react/lib/isTextNode.js"}],"/Users/zordius/webtasks/node_modules/react/lib/createArrayFrom.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule createArrayFrom
 * @typechecks
 */

var toArray = require("./toArray");

/**
 * Perform a heuristic test to determine if an object is "array-like".
 *
 *   A monk asked Joshu, a Zen master, "Has a dog Buddha nature?"
 *   Joshu replied: "Mu."
 *
 * This function determines if its argument has "array nature": it returns
 * true if the argument is an actual array, an `arguments' object, or an
 * HTMLCollection (e.g. node.childNodes or node.getElementsByTagName()).
 *
 * It will return false for other array-like objects like Filelist.
 *
 * @param {*} obj
 * @return {boolean}
 */
function hasArrayNature(obj) {
  return (
    // not null/false
    !!obj &&
    // arrays are objects, NodeLists are functions in Safari
    (typeof obj == 'object' || typeof obj == 'function') &&
    // quacks like an array
    ('length' in obj) &&
    // not window
    !('setInterval' in obj) &&
    // no DOM node should be considered an array-like
    // a 'select' element has 'length' and 'item' properties on IE8
    (typeof obj.nodeType != 'number') &&
    (
      // a real array
      (// HTMLCollection/NodeList
      (Array.isArray(obj) ||
      // arguments
      ('callee' in obj) || 'item' in obj))
    )
  );
}

/**
 * Ensure that the argument is an array by wrapping it in an array if it is not.
 * Creates a copy of the argument if it is already an array.
 *
 * This is mostly useful idiomatically:
 *
 *   var createArrayFrom = require('createArrayFrom');
 *
 *   function takesOneOrMoreThings(things) {
 *     things = createArrayFrom(things);
 *     ...
 *   }
 *
 * This allows you to treat `things' as an array, but accept scalars in the API.
 *
 * If you need to convert an array-like object, like `arguments`, into an array
 * use toArray instead.
 *
 * @param {*} obj
 * @return {array}
 */
function createArrayFrom(obj) {
  if (!hasArrayNature(obj)) {
    return [obj];
  } else if (Array.isArray(obj)) {
    return obj.slice();
  } else {
    return toArray(obj);
  }
}

module.exports = createArrayFrom;

},{"./toArray":"/Users/zordius/webtasks/node_modules/react/lib/toArray.js"}],"/Users/zordius/webtasks/node_modules/react/lib/createFullPageComponent.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule createFullPageComponent
 * @typechecks
 */

"use strict";

// Defeat circular references by requiring this directly.
var ReactCompositeComponent = require("./ReactCompositeComponent");
var ReactElement = require("./ReactElement");

var invariant = require("./invariant");

/**
 * Create a component that will throw an exception when unmounted.
 *
 * Components like <html> <head> and <body> can't be removed or added
 * easily in a cross-browser way, however it's valuable to be able to
 * take advantage of React's reconciliation for styling and <title>
 * management. So we just document it and throw in dangerous cases.
 *
 * @param {string} tag The tag to wrap
 * @return {function} convenience constructor of new component
 */
function createFullPageComponent(tag) {
  var elementFactory = ReactElement.createFactory(tag);

  var FullPageComponent = ReactCompositeComponent.createClass({
    displayName: 'ReactFullPageComponent' + tag,

    componentWillUnmount: function() {
      ("production" !== process.env.NODE_ENV ? invariant(
        false,
        '%s tried to unmount. Because of cross-browser quirks it is ' +
        'impossible to unmount some top-level components (eg <html>, <head>, ' +
        'and <body>) reliably and efficiently. To fix this, have a single ' +
        'top-level component that never unmounts render these elements.',
        this.constructor.displayName
      ) : invariant(false));
    },

    render: function() {
      return elementFactory(this.props);
    }
  });

  return FullPageComponent;
}

module.exports = createFullPageComponent;

}).call(this,require('_process'))
},{"./ReactCompositeComponent":"/Users/zordius/webtasks/node_modules/react/lib/ReactCompositeComponent.js","./ReactElement":"/Users/zordius/webtasks/node_modules/react/lib/ReactElement.js","./invariant":"/Users/zordius/webtasks/node_modules/react/lib/invariant.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/createNodesFromMarkup.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule createNodesFromMarkup
 * @typechecks
 */

/*jslint evil: true, sub: true */

var ExecutionEnvironment = require("./ExecutionEnvironment");

var createArrayFrom = require("./createArrayFrom");
var getMarkupWrap = require("./getMarkupWrap");
var invariant = require("./invariant");

/**
 * Dummy container used to render all markup.
 */
var dummyNode =
  ExecutionEnvironment.canUseDOM ? document.createElement('div') : null;

/**
 * Pattern used by `getNodeName`.
 */
var nodeNamePattern = /^\s*<(\w+)/;

/**
 * Extracts the `nodeName` of the first element in a string of markup.
 *
 * @param {string} markup String of markup.
 * @return {?string} Node name of the supplied markup.
 */
function getNodeName(markup) {
  var nodeNameMatch = markup.match(nodeNamePattern);
  return nodeNameMatch && nodeNameMatch[1].toLowerCase();
}

/**
 * Creates an array containing the nodes rendered from the supplied markup. The
 * optionally supplied `handleScript` function will be invoked once for each
 * <script> element that is rendered. If no `handleScript` function is supplied,
 * an exception is thrown if any <script> elements are rendered.
 *
 * @param {string} markup A string of valid HTML markup.
 * @param {?function} handleScript Invoked once for each rendered <script>.
 * @return {array<DOMElement|DOMTextNode>} An array of rendered nodes.
 */
function createNodesFromMarkup(markup, handleScript) {
  var node = dummyNode;
  ("production" !== process.env.NODE_ENV ? invariant(!!dummyNode, 'createNodesFromMarkup dummy not initialized') : invariant(!!dummyNode));
  var nodeName = getNodeName(markup);

  var wrap = nodeName && getMarkupWrap(nodeName);
  if (wrap) {
    node.innerHTML = wrap[1] + markup + wrap[2];

    var wrapDepth = wrap[0];
    while (wrapDepth--) {
      node = node.lastChild;
    }
  } else {
    node.innerHTML = markup;
  }

  var scripts = node.getElementsByTagName('script');
  if (scripts.length) {
    ("production" !== process.env.NODE_ENV ? invariant(
      handleScript,
      'createNodesFromMarkup(...): Unexpected <script> element rendered.'
    ) : invariant(handleScript));
    createArrayFrom(scripts).forEach(handleScript);
  }

  var nodes = createArrayFrom(node.childNodes);
  while (node.lastChild) {
    node.removeChild(node.lastChild);
  }
  return nodes;
}

module.exports = createNodesFromMarkup;

}).call(this,require('_process'))
},{"./ExecutionEnvironment":"/Users/zordius/webtasks/node_modules/react/lib/ExecutionEnvironment.js","./createArrayFrom":"/Users/zordius/webtasks/node_modules/react/lib/createArrayFrom.js","./getMarkupWrap":"/Users/zordius/webtasks/node_modules/react/lib/getMarkupWrap.js","./invariant":"/Users/zordius/webtasks/node_modules/react/lib/invariant.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/dangerousStyleValue.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule dangerousStyleValue
 * @typechecks static-only
 */

"use strict";

var CSSProperty = require("./CSSProperty");

var isUnitlessNumber = CSSProperty.isUnitlessNumber;

/**
 * Convert a value into the proper css writable value. The style name `name`
 * should be logical (no hyphens), as specified
 * in `CSSProperty.isUnitlessNumber`.
 *
 * @param {string} name CSS property name such as `topMargin`.
 * @param {*} value CSS property value such as `10px`.
 * @return {string} Normalized style value with dimensions applied.
 */
function dangerousStyleValue(name, value) {
  // Note that we've removed escapeTextForBrowser() calls here since the
  // whole string will be escaped when the attribute is injected into
  // the markup. If you provide unsafe user data here they can inject
  // arbitrary CSS which may be problematic (I couldn't repro this):
  // https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet
  // http://www.thespanner.co.uk/2007/11/26/ultimate-xss-css-injection/
  // This is not an XSS hole but instead a potential CSS injection issue
  // which has lead to a greater discussion about how we're going to
  // trust URLs moving forward. See #2115901

  var isEmpty = value == null || typeof value === 'boolean' || value === '';
  if (isEmpty) {
    return '';
  }

  var isNonNumeric = isNaN(value);
  if (isNonNumeric || value === 0 ||
      isUnitlessNumber.hasOwnProperty(name) && isUnitlessNumber[name]) {
    return '' + value; // cast to string
  }

  if (typeof value === 'string') {
    value = value.trim();
  }
  return value + 'px';
}

module.exports = dangerousStyleValue;

},{"./CSSProperty":"/Users/zordius/webtasks/node_modules/react/lib/CSSProperty.js"}],"/Users/zordius/webtasks/node_modules/react/lib/deprecated.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule deprecated
 */

var assign = require("./Object.assign");
var warning = require("./warning");

/**
 * This will log a single deprecation notice per function and forward the call
 * on to the new API.
 *
 * @param {string} namespace The namespace of the call, eg 'React'
 * @param {string} oldName The old function name, eg 'renderComponent'
 * @param {string} newName The new function name, eg 'render'
 * @param {*} ctx The context this forwarded call should run in
 * @param {function} fn The function to forward on to
 * @return {*} Will be the value as returned from `fn`
 */
function deprecated(namespace, oldName, newName, ctx, fn) {
  var warned = false;
  if ("production" !== process.env.NODE_ENV) {
    var newFn = function() {
      ("production" !== process.env.NODE_ENV ? warning(
        warned,
        (namespace + "." + oldName + " will be deprecated in a future version. ") +
        ("Use " + namespace + "." + newName + " instead.")
      ) : null);
      warned = true;
      return fn.apply(ctx, arguments);
    };
    newFn.displayName = (namespace + "_" + oldName);
    // We need to make sure all properties of the original fn are copied over.
    // In particular, this is needed to support PropTypes
    return assign(newFn, fn);
  }

  return fn;
}

module.exports = deprecated;

}).call(this,require('_process'))
},{"./Object.assign":"/Users/zordius/webtasks/node_modules/react/lib/Object.assign.js","./warning":"/Users/zordius/webtasks/node_modules/react/lib/warning.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/emptyFunction.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule emptyFunction
 */

function makeEmptyFunction(arg) {
  return function() {
    return arg;
  };
}

/**
 * This function accepts and discards inputs; it has no side effects. This is
 * primarily useful idiomatically for overridable function endpoints which
 * always need to be callable, since JS lacks a null-call idiom ala Cocoa.
 */
function emptyFunction() {}

emptyFunction.thatReturns = makeEmptyFunction;
emptyFunction.thatReturnsFalse = makeEmptyFunction(false);
emptyFunction.thatReturnsTrue = makeEmptyFunction(true);
emptyFunction.thatReturnsNull = makeEmptyFunction(null);
emptyFunction.thatReturnsThis = function() { return this; };
emptyFunction.thatReturnsArgument = function(arg) { return arg; };

module.exports = emptyFunction;

},{}],"/Users/zordius/webtasks/node_modules/react/lib/emptyObject.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule emptyObject
 */

"use strict";

var emptyObject = {};

if ("production" !== process.env.NODE_ENV) {
  Object.freeze(emptyObject);
}

module.exports = emptyObject;

}).call(this,require('_process'))
},{"_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/escapeTextForBrowser.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule escapeTextForBrowser
 * @typechecks static-only
 */

"use strict";

var ESCAPE_LOOKUP = {
  "&": "&amp;",
  ">": "&gt;",
  "<": "&lt;",
  "\"": "&quot;",
  "'": "&#x27;"
};

var ESCAPE_REGEX = /[&><"']/g;

function escaper(match) {
  return ESCAPE_LOOKUP[match];
}

/**
 * Escapes text to prevent scripting attacks.
 *
 * @param {*} text Text value to escape.
 * @return {string} An escaped string.
 */
function escapeTextForBrowser(text) {
  return ('' + text).replace(ESCAPE_REGEX, escaper);
}

module.exports = escapeTextForBrowser;

},{}],"/Users/zordius/webtasks/node_modules/react/lib/flattenChildren.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule flattenChildren
 */

"use strict";

var ReactTextComponent = require("./ReactTextComponent");

var traverseAllChildren = require("./traverseAllChildren");
var warning = require("./warning");

/**
 * @param {function} traverseContext Context passed through traversal.
 * @param {?ReactComponent} child React child component.
 * @param {!string} name String name of key path to child.
 */
function flattenSingleChildIntoContext(traverseContext, child, name) {
  // We found a component instance.
  var result = traverseContext;
  var keyUnique = !result.hasOwnProperty(name);
  ("production" !== process.env.NODE_ENV ? warning(
    keyUnique,
    'flattenChildren(...): Encountered two children with the same key, ' +
    '`%s`. Child keys must be unique; when two children share a key, only ' +
    'the first child will be used.',
    name
  ) : null);
  if (keyUnique && child != null) {
    var type = typeof child;
    var normalizedValue;

    if (type === 'string') {
      normalizedValue = ReactTextComponent(child);
    } else if (type === 'number') {
      normalizedValue = ReactTextComponent('' + child);
    } else {
      normalizedValue = child;
    }

    result[name] = normalizedValue;
  }
}

/**
 * Flattens children that are typically specified as `props.children`. Any null
 * children will not be included in the resulting object.
 * @return {!object} flattened children keyed by name.
 */
function flattenChildren(children) {
  if (children == null) {
    return children;
  }
  var result = {};
  traverseAllChildren(children, flattenSingleChildIntoContext, result);
  return result;
}

module.exports = flattenChildren;

}).call(this,require('_process'))
},{"./ReactTextComponent":"/Users/zordius/webtasks/node_modules/react/lib/ReactTextComponent.js","./traverseAllChildren":"/Users/zordius/webtasks/node_modules/react/lib/traverseAllChildren.js","./warning":"/Users/zordius/webtasks/node_modules/react/lib/warning.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/focusNode.js":[function(require,module,exports){
/**
 * Copyright 2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule focusNode
 */

"use strict";

/**
 * @param {DOMElement} node input/textarea to focus
 */
function focusNode(node) {
  // IE8 can throw "Can't move focus to the control because it is invisible,
  // not enabled, or of a type that does not accept the focus." for all kinds of
  // reasons that are too expensive and fragile to test.
  try {
    node.focus();
  } catch(e) {
  }
}

module.exports = focusNode;

},{}],"/Users/zordius/webtasks/node_modules/react/lib/forEachAccumulated.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule forEachAccumulated
 */

"use strict";

/**
 * @param {array} an "accumulation" of items which is either an Array or
 * a single item. Useful when paired with the `accumulate` module. This is a
 * simple utility that allows us to reason about a collection of items, but
 * handling the case when there is exactly one item (and we do not need to
 * allocate an array).
 */
var forEachAccumulated = function(arr, cb, scope) {
  if (Array.isArray(arr)) {
    arr.forEach(cb, scope);
  } else if (arr) {
    cb.call(scope, arr);
  }
};

module.exports = forEachAccumulated;

},{}],"/Users/zordius/webtasks/node_modules/react/lib/getActiveElement.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule getActiveElement
 * @typechecks
 */

/**
 * Same as document.activeElement but wraps in a try-catch block. In IE it is
 * not safe to call document.activeElement if there is nothing focused.
 *
 * The activeElement will be null only if the document body is not yet defined.
 */
function getActiveElement() /*?DOMElement*/ {
  try {
    return document.activeElement || document.body;
  } catch (e) {
    return document.body;
  }
}

module.exports = getActiveElement;

},{}],"/Users/zordius/webtasks/node_modules/react/lib/getEventCharCode.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule getEventCharCode
 * @typechecks static-only
 */

"use strict";

/**
 * `charCode` represents the actual "character code" and is safe to use with
 * `String.fromCharCode`. As such, only keys that correspond to printable
 * characters produce a valid `charCode`, the only exception to this is Enter.
 * The Tab-key is considered non-printable and does not have a `charCode`,
 * presumably because it does not produce a tab-character in browsers.
 *
 * @param {object} nativeEvent Native browser event.
 * @return {string} Normalized `charCode` property.
 */
function getEventCharCode(nativeEvent) {
  var charCode;
  var keyCode = nativeEvent.keyCode;

  if ('charCode' in nativeEvent) {
    charCode = nativeEvent.charCode;

    // FF does not set `charCode` for the Enter-key, check against `keyCode`.
    if (charCode === 0 && keyCode === 13) {
      charCode = 13;
    }
  } else {
    // IE8 does not implement `charCode`, but `keyCode` has the correct value.
    charCode = keyCode;
  }

  // Some non-printable keys are reported in `charCode`/`keyCode`, discard them.
  // Must not discard the (non-)printable Enter-key.
  if (charCode >= 32 || charCode === 13) {
    return charCode;
  }

  return 0;
}

module.exports = getEventCharCode;

},{}],"/Users/zordius/webtasks/node_modules/react/lib/getEventKey.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule getEventKey
 * @typechecks static-only
 */

"use strict";

var getEventCharCode = require("./getEventCharCode");

/**
 * Normalization of deprecated HTML5 `key` values
 * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Key_names
 */
var normalizeKey = {
  'Esc': 'Escape',
  'Spacebar': ' ',
  'Left': 'ArrowLeft',
  'Up': 'ArrowUp',
  'Right': 'ArrowRight',
  'Down': 'ArrowDown',
  'Del': 'Delete',
  'Win': 'OS',
  'Menu': 'ContextMenu',
  'Apps': 'ContextMenu',
  'Scroll': 'ScrollLock',
  'MozPrintableKey': 'Unidentified'
};

/**
 * Translation from legacy `keyCode` to HTML5 `key`
 * Only special keys supported, all others depend on keyboard layout or browser
 * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Key_names
 */
var translateToKey = {
  8: 'Backspace',
  9: 'Tab',
  12: 'Clear',
  13: 'Enter',
  16: 'Shift',
  17: 'Control',
  18: 'Alt',
  19: 'Pause',
  20: 'CapsLock',
  27: 'Escape',
  32: ' ',
  33: 'PageUp',
  34: 'PageDown',
  35: 'End',
  36: 'Home',
  37: 'ArrowLeft',
  38: 'ArrowUp',
  39: 'ArrowRight',
  40: 'ArrowDown',
  45: 'Insert',
  46: 'Delete',
  112: 'F1', 113: 'F2', 114: 'F3', 115: 'F4', 116: 'F5', 117: 'F6',
  118: 'F7', 119: 'F8', 120: 'F9', 121: 'F10', 122: 'F11', 123: 'F12',
  144: 'NumLock',
  145: 'ScrollLock',
  224: 'Meta'
};

/**
 * @param {object} nativeEvent Native browser event.
 * @return {string} Normalized `key` property.
 */
function getEventKey(nativeEvent) {
  if (nativeEvent.key) {
    // Normalize inconsistent values reported by browsers due to
    // implementations of a working draft specification.

    // FireFox implements `key` but returns `MozPrintableKey` for all
    // printable characters (normalized to `Unidentified`), ignore it.
    var key = normalizeKey[nativeEvent.key] || nativeEvent.key;
    if (key !== 'Unidentified') {
      return key;
    }
  }

  // Browser does not implement `key`, polyfill as much of it as we can.
  if (nativeEvent.type === 'keypress') {
    var charCode = getEventCharCode(nativeEvent);

    // The enter-key is technically both printable and non-printable and can
    // thus be captured by `keypress`, no other non-printable key should.
    return charCode === 13 ? 'Enter' : String.fromCharCode(charCode);
  }
  if (nativeEvent.type === 'keydown' || nativeEvent.type === 'keyup') {
    // While user keyboard layout determines the actual meaning of each
    // `keyCode` value, almost all function keys have a universal value.
    return translateToKey[nativeEvent.keyCode] || 'Unidentified';
  }
  return '';
}

module.exports = getEventKey;

},{"./getEventCharCode":"/Users/zordius/webtasks/node_modules/react/lib/getEventCharCode.js"}],"/Users/zordius/webtasks/node_modules/react/lib/getEventModifierState.js":[function(require,module,exports){
/**
 * Copyright 2013 Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule getEventModifierState
 * @typechecks static-only
 */

"use strict";

/**
 * Translation from modifier key to the associated property in the event.
 * @see http://www.w3.org/TR/DOM-Level-3-Events/#keys-Modifiers
 */

var modifierKeyToProp = {
  'Alt': 'altKey',
  'Control': 'ctrlKey',
  'Meta': 'metaKey',
  'Shift': 'shiftKey'
};

// IE8 does not implement getModifierState so we simply map it to the only
// modifier keys exposed by the event itself, does not support Lock-keys.
// Currently, all major browsers except Chrome seems to support Lock-keys.
function modifierStateGetter(keyArg) {
  /*jshint validthis:true */
  var syntheticEvent = this;
  var nativeEvent = syntheticEvent.nativeEvent;
  if (nativeEvent.getModifierState) {
    return nativeEvent.getModifierState(keyArg);
  }
  var keyProp = modifierKeyToProp[keyArg];
  return keyProp ? !!nativeEvent[keyProp] : false;
}

function getEventModifierState(nativeEvent) {
  return modifierStateGetter;
}

module.exports = getEventModifierState;

},{}],"/Users/zordius/webtasks/node_modules/react/lib/getEventTarget.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule getEventTarget
 * @typechecks static-only
 */

"use strict";

/**
 * Gets the target node from a native browser event by accounting for
 * inconsistencies in browser DOM APIs.
 *
 * @param {object} nativeEvent Native browser event.
 * @return {DOMEventTarget} Target node.
 */
function getEventTarget(nativeEvent) {
  var target = nativeEvent.target || nativeEvent.srcElement || window;
  // Safari may fire events on text nodes (Node.TEXT_NODE is 3).
  // @see http://www.quirksmode.org/js/events_properties.html
  return target.nodeType === 3 ? target.parentNode : target;
}

module.exports = getEventTarget;

},{}],"/Users/zordius/webtasks/node_modules/react/lib/getMarkupWrap.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule getMarkupWrap
 */

var ExecutionEnvironment = require("./ExecutionEnvironment");

var invariant = require("./invariant");

/**
 * Dummy container used to detect which wraps are necessary.
 */
var dummyNode =
  ExecutionEnvironment.canUseDOM ? document.createElement('div') : null;

/**
 * Some browsers cannot use `innerHTML` to render certain elements standalone,
 * so we wrap them, render the wrapped nodes, then extract the desired node.
 *
 * In IE8, certain elements cannot render alone, so wrap all elements ('*').
 */
var shouldWrap = {
  // Force wrapping for SVG elements because if they get created inside a <div>,
  // they will be initialized in the wrong namespace (and will not display).
  'circle': true,
  'defs': true,
  'ellipse': true,
  'g': true,
  'line': true,
  'linearGradient': true,
  'path': true,
  'polygon': true,
  'polyline': true,
  'radialGradient': true,
  'rect': true,
  'stop': true,
  'text': true
};

var selectWrap = [1, '<select multiple="true">', '</select>'];
var tableWrap = [1, '<table>', '</table>'];
var trWrap = [3, '<table><tbody><tr>', '</tr></tbody></table>'];

var svgWrap = [1, '<svg>', '</svg>'];

var markupWrap = {
  '*': [1, '?<div>', '</div>'],

  'area': [1, '<map>', '</map>'],
  'col': [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'],
  'legend': [1, '<fieldset>', '</fieldset>'],
  'param': [1, '<object>', '</object>'],
  'tr': [2, '<table><tbody>', '</tbody></table>'],

  'optgroup': selectWrap,
  'option': selectWrap,

  'caption': tableWrap,
  'colgroup': tableWrap,
  'tbody': tableWrap,
  'tfoot': tableWrap,
  'thead': tableWrap,

  'td': trWrap,
  'th': trWrap,

  'circle': svgWrap,
  'defs': svgWrap,
  'ellipse': svgWrap,
  'g': svgWrap,
  'line': svgWrap,
  'linearGradient': svgWrap,
  'path': svgWrap,
  'polygon': svgWrap,
  'polyline': svgWrap,
  'radialGradient': svgWrap,
  'rect': svgWrap,
  'stop': svgWrap,
  'text': svgWrap
};

/**
 * Gets the markup wrap configuration for the supplied `nodeName`.
 *
 * NOTE: This lazily detects which wraps are necessary for the current browser.
 *
 * @param {string} nodeName Lowercase `nodeName`.
 * @return {?array} Markup wrap configuration, if applicable.
 */
function getMarkupWrap(nodeName) {
  ("production" !== process.env.NODE_ENV ? invariant(!!dummyNode, 'Markup wrapping node not initialized') : invariant(!!dummyNode));
  if (!markupWrap.hasOwnProperty(nodeName)) {
    nodeName = '*';
  }
  if (!shouldWrap.hasOwnProperty(nodeName)) {
    if (nodeName === '*') {
      dummyNode.innerHTML = '<link />';
    } else {
      dummyNode.innerHTML = '<' + nodeName + '></' + nodeName + '>';
    }
    shouldWrap[nodeName] = !dummyNode.firstChild;
  }
  return shouldWrap[nodeName] ? markupWrap[nodeName] : null;
}


module.exports = getMarkupWrap;

}).call(this,require('_process'))
},{"./ExecutionEnvironment":"/Users/zordius/webtasks/node_modules/react/lib/ExecutionEnvironment.js","./invariant":"/Users/zordius/webtasks/node_modules/react/lib/invariant.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/getNodeForCharacterOffset.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule getNodeForCharacterOffset
 */

"use strict";

/**
 * Given any node return the first leaf node without children.
 *
 * @param {DOMElement|DOMTextNode} node
 * @return {DOMElement|DOMTextNode}
 */
function getLeafNode(node) {
  while (node && node.firstChild) {
    node = node.firstChild;
  }
  return node;
}

/**
 * Get the next sibling within a container. This will walk up the
 * DOM if a node's siblings have been exhausted.
 *
 * @param {DOMElement|DOMTextNode} node
 * @return {?DOMElement|DOMTextNode}
 */
function getSiblingNode(node) {
  while (node) {
    if (node.nextSibling) {
      return node.nextSibling;
    }
    node = node.parentNode;
  }
}

/**
 * Get object describing the nodes which contain characters at offset.
 *
 * @param {DOMElement|DOMTextNode} root
 * @param {number} offset
 * @return {?object}
 */
function getNodeForCharacterOffset(root, offset) {
  var node = getLeafNode(root);
  var nodeStart = 0;
  var nodeEnd = 0;

  while (node) {
    if (node.nodeType == 3) {
      nodeEnd = nodeStart + node.textContent.length;

      if (nodeStart <= offset && nodeEnd >= offset) {
        return {
          node: node,
          offset: offset - nodeStart
        };
      }

      nodeStart = nodeEnd;
    }

    node = getLeafNode(getSiblingNode(node));
  }
}

module.exports = getNodeForCharacterOffset;

},{}],"/Users/zordius/webtasks/node_modules/react/lib/getReactRootElementInContainer.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule getReactRootElementInContainer
 */

"use strict";

var DOC_NODE_TYPE = 9;

/**
 * @param {DOMElement|DOMDocument} container DOM element that may contain
 *                                           a React component
 * @return {?*} DOM element that may have the reactRoot ID, or null.
 */
function getReactRootElementInContainer(container) {
  if (!container) {
    return null;
  }

  if (container.nodeType === DOC_NODE_TYPE) {
    return container.documentElement;
  } else {
    return container.firstChild;
  }
}

module.exports = getReactRootElementInContainer;

},{}],"/Users/zordius/webtasks/node_modules/react/lib/getTextContentAccessor.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule getTextContentAccessor
 */

"use strict";

var ExecutionEnvironment = require("./ExecutionEnvironment");

var contentKey = null;

/**
 * Gets the key used to access text content on a DOM node.
 *
 * @return {?string} Key used to access text content.
 * @internal
 */
function getTextContentAccessor() {
  if (!contentKey && ExecutionEnvironment.canUseDOM) {
    // Prefer textContent to innerText because many browsers support both but
    // SVG <text> elements don't support innerText even when <div> does.
    contentKey = 'textContent' in document.documentElement ?
      'textContent' :
      'innerText';
  }
  return contentKey;
}

module.exports = getTextContentAccessor;

},{"./ExecutionEnvironment":"/Users/zordius/webtasks/node_modules/react/lib/ExecutionEnvironment.js"}],"/Users/zordius/webtasks/node_modules/react/lib/getUnboundedScrollPosition.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule getUnboundedScrollPosition
 * @typechecks
 */

"use strict";

/**
 * Gets the scroll position of the supplied element or window.
 *
 * The return values are unbounded, unlike `getScrollPosition`. This means they
 * may be negative or exceed the element boundaries (which is possible using
 * inertial scrolling).
 *
 * @param {DOMWindow|DOMElement} scrollable
 * @return {object} Map with `x` and `y` keys.
 */
function getUnboundedScrollPosition(scrollable) {
  if (scrollable === window) {
    return {
      x: window.pageXOffset || document.documentElement.scrollLeft,
      y: window.pageYOffset || document.documentElement.scrollTop
    };
  }
  return {
    x: scrollable.scrollLeft,
    y: scrollable.scrollTop
  };
}

module.exports = getUnboundedScrollPosition;

},{}],"/Users/zordius/webtasks/node_modules/react/lib/hyphenate.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule hyphenate
 * @typechecks
 */

var _uppercasePattern = /([A-Z])/g;

/**
 * Hyphenates a camelcased string, for example:
 *
 *   > hyphenate('backgroundColor')
 *   < "background-color"
 *
 * For CSS style names, use `hyphenateStyleName` instead which works properly
 * with all vendor prefixes, including `ms`.
 *
 * @param {string} string
 * @return {string}
 */
function hyphenate(string) {
  return string.replace(_uppercasePattern, '-$1').toLowerCase();
}

module.exports = hyphenate;

},{}],"/Users/zordius/webtasks/node_modules/react/lib/hyphenateStyleName.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule hyphenateStyleName
 * @typechecks
 */

"use strict";

var hyphenate = require("./hyphenate");

var msPattern = /^ms-/;

/**
 * Hyphenates a camelcased CSS property name, for example:
 *
 *   > hyphenateStyleName('backgroundColor')
 *   < "background-color"
 *   > hyphenateStyleName('MozTransition')
 *   < "-moz-transition"
 *   > hyphenateStyleName('msTransition')
 *   < "-ms-transition"
 *
 * As Modernizr suggests (http://modernizr.com/docs/#prefixed), an `ms` prefix
 * is converted to `-ms-`.
 *
 * @param {string} string
 * @return {string}
 */
function hyphenateStyleName(string) {
  return hyphenate(string).replace(msPattern, '-ms-');
}

module.exports = hyphenateStyleName;

},{"./hyphenate":"/Users/zordius/webtasks/node_modules/react/lib/hyphenate.js"}],"/Users/zordius/webtasks/node_modules/react/lib/instantiateReactComponent.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule instantiateReactComponent
 * @typechecks static-only
 */

"use strict";

var warning = require("./warning");

var ReactElement = require("./ReactElement");
var ReactLegacyElement = require("./ReactLegacyElement");
var ReactNativeComponent = require("./ReactNativeComponent");
var ReactEmptyComponent = require("./ReactEmptyComponent");

/**
 * Given an `element` create an instance that will actually be mounted.
 *
 * @param {object} element
 * @param {*} parentCompositeType The composite type that resolved this.
 * @return {object} A new instance of the element's constructor.
 * @protected
 */
function instantiateReactComponent(element, parentCompositeType) {
  var instance;

  if ("production" !== process.env.NODE_ENV) {
    ("production" !== process.env.NODE_ENV ? warning(
      element && (typeof element.type === 'function' ||
                     typeof element.type === 'string'),
      'Only functions or strings can be mounted as React components.'
    ) : null);

    // Resolve mock instances
    if (element.type._mockedReactClassConstructor) {
      // If this is a mocked class, we treat the legacy factory as if it was the
      // class constructor for future proofing unit tests. Because this might
      // be mocked as a legacy factory, we ignore any warnings triggerd by
      // this temporary hack.
      ReactLegacyElement._isLegacyCallWarningEnabled = false;
      try {
        instance = new element.type._mockedReactClassConstructor(
          element.props
        );
      } finally {
        ReactLegacyElement._isLegacyCallWarningEnabled = true;
      }

      // If the mock implementation was a legacy factory, then it returns a
      // element. We need to turn this into a real component instance.
      if (ReactElement.isValidElement(instance)) {
        instance = new instance.type(instance.props);
      }

      var render = instance.render;
      if (!render) {
        // For auto-mocked factories, the prototype isn't shimmed and therefore
        // there is no render function on the instance. We replace the whole
        // component with an empty component instance instead.
        element = ReactEmptyComponent.getEmptyComponent();
      } else {
        if (render._isMockFunction && !render._getMockImplementation()) {
          // Auto-mocked components may have a prototype with a mocked render
          // function. For those, we'll need to mock the result of the render
          // since we consider undefined to be invalid results from render.
          render.mockImplementation(
            ReactEmptyComponent.getEmptyComponent
          );
        }
        instance.construct(element);
        return instance;
      }
    }
  }

  // Special case string values
  if (typeof element.type === 'string') {
    instance = ReactNativeComponent.createInstanceForTag(
      element.type,
      element.props,
      parentCompositeType
    );
  } else {
    // Normal case for non-mocks and non-strings
    instance = new element.type(element.props);
  }

  if ("production" !== process.env.NODE_ENV) {
    ("production" !== process.env.NODE_ENV ? warning(
      typeof instance.construct === 'function' &&
      typeof instance.mountComponent === 'function' &&
      typeof instance.receiveComponent === 'function',
      'Only React Components can be mounted.'
    ) : null);
  }

  // This actually sets up the internal instance. This will become decoupled
  // from the public instance in a future diff.
  instance.construct(element);

  return instance;
}

module.exports = instantiateReactComponent;

}).call(this,require('_process'))
},{"./ReactElement":"/Users/zordius/webtasks/node_modules/react/lib/ReactElement.js","./ReactEmptyComponent":"/Users/zordius/webtasks/node_modules/react/lib/ReactEmptyComponent.js","./ReactLegacyElement":"/Users/zordius/webtasks/node_modules/react/lib/ReactLegacyElement.js","./ReactNativeComponent":"/Users/zordius/webtasks/node_modules/react/lib/ReactNativeComponent.js","./warning":"/Users/zordius/webtasks/node_modules/react/lib/warning.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/invariant.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule invariant
 */

"use strict";

/**
 * Use invariant() to assert state which your program assumes to be true.
 *
 * Provide sprintf-style format (only %s is supported) and arguments
 * to provide information about what broke and what you were
 * expecting.
 *
 * The invariant message will be stripped in production, but the invariant
 * will remain to ensure logic does not differ in production.
 */

var invariant = function(condition, format, a, b, c, d, e, f) {
  if ("production" !== process.env.NODE_ENV) {
    if (format === undefined) {
      throw new Error('invariant requires an error message argument');
    }
  }

  if (!condition) {
    var error;
    if (format === undefined) {
      error = new Error(
        'Minified exception occurred; use the non-minified dev environment ' +
        'for the full error message and additional helpful warnings.'
      );
    } else {
      var args = [a, b, c, d, e, f];
      var argIndex = 0;
      error = new Error(
        'Invariant Violation: ' +
        format.replace(/%s/g, function() { return args[argIndex++]; })
      );
    }

    error.framesToPop = 1; // we don't care about invariant's own frame
    throw error;
  }
};

module.exports = invariant;

}).call(this,require('_process'))
},{"_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/isEventSupported.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule isEventSupported
 */

"use strict";

var ExecutionEnvironment = require("./ExecutionEnvironment");

var useHasFeature;
if (ExecutionEnvironment.canUseDOM) {
  useHasFeature =
    document.implementation &&
    document.implementation.hasFeature &&
    // always returns true in newer browsers as per the standard.
    // @see http://dom.spec.whatwg.org/#dom-domimplementation-hasfeature
    document.implementation.hasFeature('', '') !== true;
}

/**
 * Checks if an event is supported in the current execution environment.
 *
 * NOTE: This will not work correctly for non-generic events such as `change`,
 * `reset`, `load`, `error`, and `select`.
 *
 * Borrows from Modernizr.
 *
 * @param {string} eventNameSuffix Event name, e.g. "click".
 * @param {?boolean} capture Check if the capture phase is supported.
 * @return {boolean} True if the event is supported.
 * @internal
 * @license Modernizr 3.0.0pre (Custom Build) | MIT
 */
function isEventSupported(eventNameSuffix, capture) {
  if (!ExecutionEnvironment.canUseDOM ||
      capture && !('addEventListener' in document)) {
    return false;
  }

  var eventName = 'on' + eventNameSuffix;
  var isSupported = eventName in document;

  if (!isSupported) {
    var element = document.createElement('div');
    element.setAttribute(eventName, 'return;');
    isSupported = typeof element[eventName] === 'function';
  }

  if (!isSupported && useHasFeature && eventNameSuffix === 'wheel') {
    // This is the only way to test support for the `wheel` event in IE9+.
    isSupported = document.implementation.hasFeature('Events.wheel', '3.0');
  }

  return isSupported;
}

module.exports = isEventSupported;

},{"./ExecutionEnvironment":"/Users/zordius/webtasks/node_modules/react/lib/ExecutionEnvironment.js"}],"/Users/zordius/webtasks/node_modules/react/lib/isNode.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule isNode
 * @typechecks
 */

/**
 * @param {*} object The object to check.
 * @return {boolean} Whether or not the object is a DOM node.
 */
function isNode(object) {
  return !!(object && (
    typeof Node === 'function' ? object instanceof Node :
      typeof object === 'object' &&
      typeof object.nodeType === 'number' &&
      typeof object.nodeName === 'string'
  ));
}

module.exports = isNode;

},{}],"/Users/zordius/webtasks/node_modules/react/lib/isTextInputElement.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule isTextInputElement
 */

"use strict";

/**
 * @see http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary
 */
var supportedInputTypes = {
  'color': true,
  'date': true,
  'datetime': true,
  'datetime-local': true,
  'email': true,
  'month': true,
  'number': true,
  'password': true,
  'range': true,
  'search': true,
  'tel': true,
  'text': true,
  'time': true,
  'url': true,
  'week': true
};

function isTextInputElement(elem) {
  return elem && (
    (elem.nodeName === 'INPUT' && supportedInputTypes[elem.type]) ||
    elem.nodeName === 'TEXTAREA'
  );
}

module.exports = isTextInputElement;

},{}],"/Users/zordius/webtasks/node_modules/react/lib/isTextNode.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule isTextNode
 * @typechecks
 */

var isNode = require("./isNode");

/**
 * @param {*} object The object to check.
 * @return {boolean} Whether or not the object is a DOM text node.
 */
function isTextNode(object) {
  return isNode(object) && object.nodeType == 3;
}

module.exports = isTextNode;

},{"./isNode":"/Users/zordius/webtasks/node_modules/react/lib/isNode.js"}],"/Users/zordius/webtasks/node_modules/react/lib/joinClasses.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule joinClasses
 * @typechecks static-only
 */

"use strict";

/**
 * Combines multiple className strings into one.
 * http://jsperf.com/joinclasses-args-vs-array
 *
 * @param {...?string} classes
 * @return {string}
 */
function joinClasses(className/*, ... */) {
  if (!className) {
    className = '';
  }
  var nextClass;
  var argLength = arguments.length;
  if (argLength > 1) {
    for (var ii = 1; ii < argLength; ii++) {
      nextClass = arguments[ii];
      if (nextClass) {
        className = (className ? className + ' ' : '') + nextClass;
      }
    }
  }
  return className;
}

module.exports = joinClasses;

},{}],"/Users/zordius/webtasks/node_modules/react/lib/keyMirror.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule keyMirror
 * @typechecks static-only
 */

"use strict";

var invariant = require("./invariant");

/**
 * Constructs an enumeration with keys equal to their value.
 *
 * For example:
 *
 *   var COLORS = keyMirror({blue: null, red: null});
 *   var myColor = COLORS.blue;
 *   var isColorValid = !!COLORS[myColor];
 *
 * The last line could not be performed if the values of the generated enum were
 * not equal to their keys.
 *
 *   Input:  {key1: val1, key2: val2}
 *   Output: {key1: key1, key2: key2}
 *
 * @param {object} obj
 * @return {object}
 */
var keyMirror = function(obj) {
  var ret = {};
  var key;
  ("production" !== process.env.NODE_ENV ? invariant(
    obj instanceof Object && !Array.isArray(obj),
    'keyMirror(...): Argument must be an object.'
  ) : invariant(obj instanceof Object && !Array.isArray(obj)));
  for (key in obj) {
    if (!obj.hasOwnProperty(key)) {
      continue;
    }
    ret[key] = key;
  }
  return ret;
};

module.exports = keyMirror;

}).call(this,require('_process'))
},{"./invariant":"/Users/zordius/webtasks/node_modules/react/lib/invariant.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/keyOf.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule keyOf
 */

/**
 * Allows extraction of a minified key. Let's the build system minify keys
 * without loosing the ability to dynamically use key strings as values
 * themselves. Pass in an object with a single key/val pair and it will return
 * you the string key of that single record. Suppose you want to grab the
 * value for a key 'className' inside of an object. Key/val minification may
 * have aliased that key to be 'xa12'. keyOf({className: null}) will return
 * 'xa12' in that case. Resolve keys you want to use once at startup time, then
 * reuse those resolutions.
 */
var keyOf = function(oneKeyObj) {
  var key;
  for (key in oneKeyObj) {
    if (!oneKeyObj.hasOwnProperty(key)) {
      continue;
    }
    return key;
  }
  return null;
};


module.exports = keyOf;

},{}],"/Users/zordius/webtasks/node_modules/react/lib/mapObject.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule mapObject
 */

'use strict';

var hasOwnProperty = Object.prototype.hasOwnProperty;

/**
 * Executes the provided `callback` once for each enumerable own property in the
 * object and constructs a new object from the results. The `callback` is
 * invoked with three arguments:
 *
 *  - the property value
 *  - the property name
 *  - the object being traversed
 *
 * Properties that are added after the call to `mapObject` will not be visited
 * by `callback`. If the values of existing properties are changed, the value
 * passed to `callback` will be the value at the time `mapObject` visits them.
 * Properties that are deleted before being visited are not visited.
 *
 * @grep function objectMap()
 * @grep function objMap()
 *
 * @param {?object} object
 * @param {function} callback
 * @param {*} context
 * @return {?object}
 */
function mapObject(object, callback, context) {
  if (!object) {
    return null;
  }
  var result = {};
  for (var name in object) {
    if (hasOwnProperty.call(object, name)) {
      result[name] = callback.call(context, object[name], name, object);
    }
  }
  return result;
}

module.exports = mapObject;

},{}],"/Users/zordius/webtasks/node_modules/react/lib/memoizeStringOnly.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule memoizeStringOnly
 * @typechecks static-only
 */

"use strict";

/**
 * Memoizes the return value of a function that accepts one string argument.
 *
 * @param {function} callback
 * @return {function}
 */
function memoizeStringOnly(callback) {
  var cache = {};
  return function(string) {
    if (cache.hasOwnProperty(string)) {
      return cache[string];
    } else {
      return cache[string] = callback.call(this, string);
    }
  };
}

module.exports = memoizeStringOnly;

},{}],"/Users/zordius/webtasks/node_modules/react/lib/monitorCodeUse.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule monitorCodeUse
 */

"use strict";

var invariant = require("./invariant");

/**
 * Provides open-source compatible instrumentation for monitoring certain API
 * uses before we're ready to issue a warning or refactor. It accepts an event
 * name which may only contain the characters [a-z0-9_] and an optional data
 * object with further information.
 */

function monitorCodeUse(eventName, data) {
  ("production" !== process.env.NODE_ENV ? invariant(
    eventName && !/[^a-z0-9_]/.test(eventName),
    'You must provide an eventName using only the characters [a-z0-9_]'
  ) : invariant(eventName && !/[^a-z0-9_]/.test(eventName)));
}

module.exports = monitorCodeUse;

}).call(this,require('_process'))
},{"./invariant":"/Users/zordius/webtasks/node_modules/react/lib/invariant.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/onlyChild.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule onlyChild
 */
"use strict";

var ReactElement = require("./ReactElement");

var invariant = require("./invariant");

/**
 * Returns the first child in a collection of children and verifies that there
 * is only one child in the collection. The current implementation of this
 * function assumes that a single child gets passed without a wrapper, but the
 * purpose of this helper function is to abstract away the particular structure
 * of children.
 *
 * @param {?object} children Child collection structure.
 * @return {ReactComponent} The first and only `ReactComponent` contained in the
 * structure.
 */
function onlyChild(children) {
  ("production" !== process.env.NODE_ENV ? invariant(
    ReactElement.isValidElement(children),
    'onlyChild must be passed a children with exactly one child.'
  ) : invariant(ReactElement.isValidElement(children)));
  return children;
}

module.exports = onlyChild;

}).call(this,require('_process'))
},{"./ReactElement":"/Users/zordius/webtasks/node_modules/react/lib/ReactElement.js","./invariant":"/Users/zordius/webtasks/node_modules/react/lib/invariant.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/performance.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule performance
 * @typechecks
 */

"use strict";

var ExecutionEnvironment = require("./ExecutionEnvironment");

var performance;

if (ExecutionEnvironment.canUseDOM) {
  performance =
    window.performance ||
    window.msPerformance ||
    window.webkitPerformance;
}

module.exports = performance || {};

},{"./ExecutionEnvironment":"/Users/zordius/webtasks/node_modules/react/lib/ExecutionEnvironment.js"}],"/Users/zordius/webtasks/node_modules/react/lib/performanceNow.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule performanceNow
 * @typechecks
 */

var performance = require("./performance");

/**
 * Detect if we can use `window.performance.now()` and gracefully fallback to
 * `Date.now()` if it doesn't exist. We need to support Firefox < 15 for now
 * because of Facebook's testing infrastructure.
 */
if (!performance || !performance.now) {
  performance = Date;
}

var performanceNow = performance.now.bind(performance);

module.exports = performanceNow;

},{"./performance":"/Users/zordius/webtasks/node_modules/react/lib/performance.js"}],"/Users/zordius/webtasks/node_modules/react/lib/setInnerHTML.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule setInnerHTML
 */

"use strict";

var ExecutionEnvironment = require("./ExecutionEnvironment");

var WHITESPACE_TEST = /^[ \r\n\t\f]/;
var NONVISIBLE_TEST = /<(!--|link|noscript|meta|script|style)[ \r\n\t\f\/>]/;

/**
 * Set the innerHTML property of a node, ensuring that whitespace is preserved
 * even in IE8.
 *
 * @param {DOMElement} node
 * @param {string} html
 * @internal
 */
var setInnerHTML = function(node, html) {
  node.innerHTML = html;
};

if (ExecutionEnvironment.canUseDOM) {
  // IE8: When updating a just created node with innerHTML only leading
  // whitespace is removed. When updating an existing node with innerHTML
  // whitespace in root TextNodes is also collapsed.
  // @see quirksmode.org/bugreports/archives/2004/11/innerhtml_and_t.html

  // Feature detection; only IE8 is known to behave improperly like this.
  var testElement = document.createElement('div');
  testElement.innerHTML = ' ';
  if (testElement.innerHTML === '') {
    setInnerHTML = function(node, html) {
      // Magic theory: IE8 supposedly differentiates between added and updated
      // nodes when processing innerHTML, innerHTML on updated nodes suffers
      // from worse whitespace behavior. Re-adding a node like this triggers
      // the initial and more favorable whitespace behavior.
      // TODO: What to do on a detached node?
      if (node.parentNode) {
        node.parentNode.replaceChild(node, node);
      }

      // We also implement a workaround for non-visible tags disappearing into
      // thin air on IE8, this only happens if there is no visible text
      // in-front of the non-visible tags. Piggyback on the whitespace fix
      // and simply check if any non-visible tags appear in the source.
      if (WHITESPACE_TEST.test(html) ||
          html[0] === '<' && NONVISIBLE_TEST.test(html)) {
        // Recover leading whitespace by temporarily prepending any character.
        // \uFEFF has the potential advantage of being zero-width/invisible.
        node.innerHTML = '\uFEFF' + html;

        // deleteData leaves an empty `TextNode` which offsets the index of all
        // children. Definitely want to avoid this.
        var textNode = node.firstChild;
        if (textNode.data.length === 1) {
          node.removeChild(textNode);
        } else {
          textNode.deleteData(0, 1);
        }
      } else {
        node.innerHTML = html;
      }
    };
  }
}

module.exports = setInnerHTML;

},{"./ExecutionEnvironment":"/Users/zordius/webtasks/node_modules/react/lib/ExecutionEnvironment.js"}],"/Users/zordius/webtasks/node_modules/react/lib/shallowEqual.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule shallowEqual
 */

"use strict";

/**
 * Performs equality by iterating through keys on an object and returning
 * false when any key has values which are not strictly equal between
 * objA and objB. Returns true when the values of all keys are strictly equal.
 *
 * @return {boolean}
 */
function shallowEqual(objA, objB) {
  if (objA === objB) {
    return true;
  }
  var key;
  // Test for A's keys different from B.
  for (key in objA) {
    if (objA.hasOwnProperty(key) &&
        (!objB.hasOwnProperty(key) || objA[key] !== objB[key])) {
      return false;
    }
  }
  // Test for B's keys missing from A.
  for (key in objB) {
    if (objB.hasOwnProperty(key) && !objA.hasOwnProperty(key)) {
      return false;
    }
  }
  return true;
}

module.exports = shallowEqual;

},{}],"/Users/zordius/webtasks/node_modules/react/lib/shouldUpdateReactComponent.js":[function(require,module,exports){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule shouldUpdateReactComponent
 * @typechecks static-only
 */

"use strict";

/**
 * Given a `prevElement` and `nextElement`, determines if the existing
 * instance should be updated as opposed to being destroyed or replaced by a new
 * instance. Both arguments are elements. This ensures that this logic can
 * operate on stateless trees without any backing instance.
 *
 * @param {?object} prevElement
 * @param {?object} nextElement
 * @return {boolean} True if the existing instance should be updated.
 * @protected
 */
function shouldUpdateReactComponent(prevElement, nextElement) {
  if (prevElement && nextElement &&
      prevElement.type === nextElement.type &&
      prevElement.key === nextElement.key &&
      prevElement._owner === nextElement._owner) {
    return true;
  }
  return false;
}

module.exports = shouldUpdateReactComponent;

},{}],"/Users/zordius/webtasks/node_modules/react/lib/toArray.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule toArray
 * @typechecks
 */

var invariant = require("./invariant");

/**
 * Convert array-like objects to arrays.
 *
 * This API assumes the caller knows the contents of the data type. For less
 * well defined inputs use createArrayFrom.
 *
 * @param {object|function|filelist} obj
 * @return {array}
 */
function toArray(obj) {
  var length = obj.length;

  // Some browse builtin objects can report typeof 'function' (e.g. NodeList in
  // old versions of Safari).
  ("production" !== process.env.NODE_ENV ? invariant(
    !Array.isArray(obj) &&
    (typeof obj === 'object' || typeof obj === 'function'),
    'toArray: Array-like object expected'
  ) : invariant(!Array.isArray(obj) &&
  (typeof obj === 'object' || typeof obj === 'function')));

  ("production" !== process.env.NODE_ENV ? invariant(
    typeof length === 'number',
    'toArray: Object needs a length property'
  ) : invariant(typeof length === 'number'));

  ("production" !== process.env.NODE_ENV ? invariant(
    length === 0 ||
    (length - 1) in obj,
    'toArray: Object should have keys for indices'
  ) : invariant(length === 0 ||
  (length - 1) in obj));

  // Old IE doesn't give collections access to hasOwnProperty. Assume inputs
  // without method will throw during the slice call and skip straight to the
  // fallback.
  if (obj.hasOwnProperty) {
    try {
      return Array.prototype.slice.call(obj);
    } catch (e) {
      // IE < 9 does not support Array#slice on collections objects
    }
  }

  // Fall back to copying key by key. This assumes all keys have a value,
  // so will not preserve sparsely populated inputs.
  var ret = Array(length);
  for (var ii = 0; ii < length; ii++) {
    ret[ii] = obj[ii];
  }
  return ret;
}

module.exports = toArray;

}).call(this,require('_process'))
},{"./invariant":"/Users/zordius/webtasks/node_modules/react/lib/invariant.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/traverseAllChildren.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2013-2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule traverseAllChildren
 */

"use strict";

var ReactElement = require("./ReactElement");
var ReactInstanceHandles = require("./ReactInstanceHandles");

var invariant = require("./invariant");

var SEPARATOR = ReactInstanceHandles.SEPARATOR;
var SUBSEPARATOR = ':';

/**
 * TODO: Test that:
 * 1. `mapChildren` transforms strings and numbers into `ReactTextComponent`.
 * 2. it('should fail when supplied duplicate key', function() {
 * 3. That a single child and an array with one item have the same key pattern.
 * });
 */

var userProvidedKeyEscaperLookup = {
  '=': '=0',
  '.': '=1',
  ':': '=2'
};

var userProvidedKeyEscapeRegex = /[=.:]/g;

function userProvidedKeyEscaper(match) {
  return userProvidedKeyEscaperLookup[match];
}

/**
 * Generate a key string that identifies a component within a set.
 *
 * @param {*} component A component that could contain a manual key.
 * @param {number} index Index that is used if a manual key is not provided.
 * @return {string}
 */
function getComponentKey(component, index) {
  if (component && component.key != null) {
    // Explicit key
    return wrapUserProvidedKey(component.key);
  }
  // Implicit key determined by the index in the set
  return index.toString(36);
}

/**
 * Escape a component key so that it is safe to use in a reactid.
 *
 * @param {*} key Component key to be escaped.
 * @return {string} An escaped string.
 */
function escapeUserProvidedKey(text) {
  return ('' + text).replace(
    userProvidedKeyEscapeRegex,
    userProvidedKeyEscaper
  );
}

/**
 * Wrap a `key` value explicitly provided by the user to distinguish it from
 * implicitly-generated keys generated by a component's index in its parent.
 *
 * @param {string} key Value of a user-provided `key` attribute
 * @return {string}
 */
function wrapUserProvidedKey(key) {
  return '$' + escapeUserProvidedKey(key);
}

/**
 * @param {?*} children Children tree container.
 * @param {!string} nameSoFar Name of the key path so far.
 * @param {!number} indexSoFar Number of children encountered until this point.
 * @param {!function} callback Callback to invoke with each child found.
 * @param {?*} traverseContext Used to pass information throughout the traversal
 * process.
 * @return {!number} The number of children in this subtree.
 */
var traverseAllChildrenImpl =
  function(children, nameSoFar, indexSoFar, callback, traverseContext) {
    var nextName, nextIndex;
    var subtreeCount = 0;  // Count of children found in the current subtree.
    if (Array.isArray(children)) {
      for (var i = 0; i < children.length; i++) {
        var child = children[i];
        nextName = (
          nameSoFar +
          (nameSoFar ? SUBSEPARATOR : SEPARATOR) +
          getComponentKey(child, i)
        );
        nextIndex = indexSoFar + subtreeCount;
        subtreeCount += traverseAllChildrenImpl(
          child,
          nextName,
          nextIndex,
          callback,
          traverseContext
        );
      }
    } else {
      var type = typeof children;
      var isOnlyChild = nameSoFar === '';
      // If it's the only child, treat the name as if it was wrapped in an array
      // so that it's consistent if the number of children grows
      var storageName =
        isOnlyChild ? SEPARATOR + getComponentKey(children, 0) : nameSoFar;
      if (children == null || type === 'boolean') {
        // All of the above are perceived as null.
        callback(traverseContext, null, storageName, indexSoFar);
        subtreeCount = 1;
      } else if (type === 'string' || type === 'number' ||
                 ReactElement.isValidElement(children)) {
        callback(traverseContext, children, storageName, indexSoFar);
        subtreeCount = 1;
      } else if (type === 'object') {
        ("production" !== process.env.NODE_ENV ? invariant(
          !children || children.nodeType !== 1,
          'traverseAllChildren(...): Encountered an invalid child; DOM ' +
          'elements are not valid children of React components.'
        ) : invariant(!children || children.nodeType !== 1));
        for (var key in children) {
          if (children.hasOwnProperty(key)) {
            nextName = (
              nameSoFar + (nameSoFar ? SUBSEPARATOR : SEPARATOR) +
              wrapUserProvidedKey(key) + SUBSEPARATOR +
              getComponentKey(children[key], 0)
            );
            nextIndex = indexSoFar + subtreeCount;
            subtreeCount += traverseAllChildrenImpl(
              children[key],
              nextName,
              nextIndex,
              callback,
              traverseContext
            );
          }
        }
      }
    }
    return subtreeCount;
  };

/**
 * Traverses children that are typically specified as `props.children`, but
 * might also be specified through attributes:
 *
 * - `traverseAllChildren(this.props.children, ...)`
 * - `traverseAllChildren(this.props.leftPanelChildren, ...)`
 *
 * The `traverseContext` is an optional argument that is passed through the
 * entire traversal. It can be used to store accumulations or anything else that
 * the callback might find relevant.
 *
 * @param {?*} children Children tree object.
 * @param {!function} callback To invoke upon traversing each child.
 * @param {?*} traverseContext Context for traversal.
 * @return {!number} The number of children in this subtree.
 */
function traverseAllChildren(children, callback, traverseContext) {
  if (children == null) {
    return 0;
  }

  return traverseAllChildrenImpl(children, '', 0, callback, traverseContext);
}

module.exports = traverseAllChildren;

}).call(this,require('_process'))
},{"./ReactElement":"/Users/zordius/webtasks/node_modules/react/lib/ReactElement.js","./ReactInstanceHandles":"/Users/zordius/webtasks/node_modules/react/lib/ReactInstanceHandles.js","./invariant":"/Users/zordius/webtasks/node_modules/react/lib/invariant.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/lib/warning.js":[function(require,module,exports){
(function (process){
/**
 * Copyright 2014, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule warning
 */

"use strict";

var emptyFunction = require("./emptyFunction");

/**
 * Similar to invariant but only logs a warning if the condition is not met.
 * This can be used to log issues in development environments in critical
 * paths. Removing the logging code for production environments will keep the
 * same logic and follow the same code paths.
 */

var warning = emptyFunction;

if ("production" !== process.env.NODE_ENV) {
  warning = function(condition, format ) {for (var args=[],$__0=2,$__1=arguments.length;$__0<$__1;$__0++) args.push(arguments[$__0]);
    if (format === undefined) {
      throw new Error(
        '`warning(condition, format, ...args)` requires a warning ' +
        'message argument'
      );
    }

    if (!condition) {
      var argIndex = 0;
      console.warn('Warning: ' + format.replace(/%s/g, function()  {return args[argIndex++];}));
    }
  };
}

module.exports = warning;

}).call(this,require('_process'))
},{"./emptyFunction":"/Users/zordius/webtasks/node_modules/react/lib/emptyFunction.js","_process":"/Users/zordius/webtasks/node_modules/browserify/node_modules/process/browser.js"}],"/Users/zordius/webtasks/node_modules/react/react.js":[function(require,module,exports){
module.exports = require('./lib/React');

},{"./lib/React":"/Users/zordius/webtasks/node_modules/react/lib/React.js"}],"/Users/zordius/webtasks/react/Bug.jsx":[function(require,module,exports){
/** @jsx React.DOM */
var React = require('react'),
///    notfound = require('NotFoundModule'),

Bug = React.createClass({displayName: 'Bug',
    render: function () {
        return (
            React.createElement("div", null, "OK!")
        );
    }
});

module.exports = Bug;

},{"react":"/Users/zordius/webtasks/node_modules/react/react.js"}],"/Users/zordius/webtasks/react/LimitSelect.jsx":[function(require,module,exports){
/** @jsx React.DOM */
var React = require('react'),

LimitSelect = React.createClass({displayName: 'LimitSelect',
    render: function () {
        var options = [],
            I;

        for (I=0;I<this.props.max;I++) {
            options.push(
                React.createElement("option", null, I+1)
            );
        }

        return (
            React.createElement("select", null, 
             options
            )
        );
    }
});

module.exports = LimitSelect;

},{"react":"/Users/zordius/webtasks/node_modules/react/react.js"}],"/Users/zordius/webtasks/react/Path.jsx":[function(require,module,exports){
/** @jsx React.DOM */
var React = require('react'),

Path = React.createClass({displayName: 'Path',
    render: function () {
        var paths = this.props.path.map(function (P) {
            return (
                React.createElement("li", null, React.createElement("a", {href: '/cate/' + P.id}, P.title))
            );
        });
        return (
            React.createElement("ul", {className: "path"}, 
             paths
            )
        );
    }
});

module.exports = Path;

},{"react":"/Users/zordius/webtasks/node_modules/react/react.js"}],"/Users/zordius/webtasks/react/Product.jsx":[function(require,module,exports){
/** @jsx React.DOM */
var React = require('react'),
    LimitSelect = require('./LimitSelect.jsx'),

Product = React.createClass({displayName: 'Product',
    getInitialState: function () {
        return {selectedSpec: this.props.specs[0].id};
    },
    handleSpecChange: function () {
        this.setState({selectedSpec: event.target.value});
    },
    render: function () {
        var specs = [],
            max,
            I;

        for (I=0;I<this.props.specs.length;I++) {
            if (this.props.specs[I].id == this.state.selectedSpec) {
                max = this.props.specs[I].limit;
            }
            specs.push(
                React.createElement("option", {value: this.props.specs[I].id}, this.props.specs[I].title)
            );
        }

        return (
React.createElement("div", null, 
 React.createElement("h1", null, this.props.title), 
 React.createElement("p", null, this.props.description), 
 React.createElement("span", null, "Price: ", React.createElement("i", null, "$"), React.createElement("b", null, this.props.price)), 
 React.createElement("div", null, "Pick a spec:", React.createElement("select", {onChange: this.handleSpecChange, value: this.state.selectedSpec}, specs), 
  React.createElement(LimitSelect, {max: max})
 )
)
        );
    }
});

module.exports = Product;

},{"./LimitSelect.jsx":"/Users/zordius/webtasks/react/LimitSelect.jsx","react":"/Users/zordius/webtasks/node_modules/react/react.js"}]},{},[])
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJfc3RyZWFtXzEuanMiLCJub2RlX21vZHVsZXMvYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvcHJvY2Vzcy9icm93c2VyLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9BdXRvRm9jdXNNaXhpbi5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvQmVmb3JlSW5wdXRFdmVudFBsdWdpbi5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvQ1NTUHJvcGVydHkuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL0NTU1Byb3BlcnR5T3BlcmF0aW9ucy5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvQ2FsbGJhY2tRdWV1ZS5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvQ2hhbmdlRXZlbnRQbHVnaW4uanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL0NsaWVudFJlYWN0Um9vdEluZGV4LmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9Db21wb3NpdGlvbkV2ZW50UGx1Z2luLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9ET01DaGlsZHJlbk9wZXJhdGlvbnMuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL0RPTVByb3BlcnR5LmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9ET01Qcm9wZXJ0eU9wZXJhdGlvbnMuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL0Rhbmdlci5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvRGVmYXVsdEV2ZW50UGx1Z2luT3JkZXIuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL0VudGVyTGVhdmVFdmVudFBsdWdpbi5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvRXZlbnRDb25zdGFudHMuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL0V2ZW50TGlzdGVuZXIuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL0V2ZW50UGx1Z2luSHViLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9FdmVudFBsdWdpblJlZ2lzdHJ5LmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9FdmVudFBsdWdpblV0aWxzLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9FdmVudFByb3BhZ2F0b3JzLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9FeGVjdXRpb25FbnZpcm9ubWVudC5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvSFRNTERPTVByb3BlcnR5Q29uZmlnLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9MaW5rZWRWYWx1ZVV0aWxzLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9Mb2NhbEV2ZW50VHJhcE1peGluLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9Nb2JpbGVTYWZhcmlDbGlja0V2ZW50UGx1Z2luLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9PYmplY3QuYXNzaWduLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9Qb29sZWRDbGFzcy5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvUmVhY3QuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1JlYWN0QnJvd3NlckNvbXBvbmVudE1peGluLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9SZWFjdEJyb3dzZXJFdmVudEVtaXR0ZXIuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1JlYWN0Q2hpbGRyZW4uanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1JlYWN0Q29tcG9uZW50LmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9SZWFjdENvbXBvbmVudEJyb3dzZXJFbnZpcm9ubWVudC5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvUmVhY3RDb21wb3NpdGVDb21wb25lbnQuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1JlYWN0Q29udGV4dC5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvUmVhY3RDdXJyZW50T3duZXIuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1JlYWN0RE9NLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9SZWFjdERPTUJ1dHRvbi5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvUmVhY3RET01Db21wb25lbnQuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1JlYWN0RE9NRm9ybS5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvUmVhY3RET01JRE9wZXJhdGlvbnMuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1JlYWN0RE9NSW1nLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9SZWFjdERPTUlucHV0LmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9SZWFjdERPTU9wdGlvbi5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvUmVhY3RET01TZWxlY3QuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1JlYWN0RE9NU2VsZWN0aW9uLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9SZWFjdERPTVRleHRhcmVhLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9SZWFjdERlZmF1bHRCYXRjaGluZ1N0cmF0ZWd5LmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9SZWFjdERlZmF1bHRJbmplY3Rpb24uanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1JlYWN0RGVmYXVsdFBlcmYuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1JlYWN0RGVmYXVsdFBlcmZBbmFseXNpcy5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvUmVhY3RFbGVtZW50LmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9SZWFjdEVsZW1lbnRWYWxpZGF0b3IuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1JlYWN0RW1wdHlDb21wb25lbnQuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1JlYWN0RXJyb3JVdGlscy5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvUmVhY3RFdmVudEVtaXR0ZXJNaXhpbi5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvUmVhY3RFdmVudExpc3RlbmVyLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9SZWFjdEluamVjdGlvbi5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvUmVhY3RJbnB1dFNlbGVjdGlvbi5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvUmVhY3RJbnN0YW5jZUhhbmRsZXMuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1JlYWN0TGVnYWN5RWxlbWVudC5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvUmVhY3RNYXJrdXBDaGVja3N1bS5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvUmVhY3RNb3VudC5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvUmVhY3RNdWx0aUNoaWxkLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9SZWFjdE11bHRpQ2hpbGRVcGRhdGVUeXBlcy5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvUmVhY3ROYXRpdmVDb21wb25lbnQuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1JlYWN0T3duZXIuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1JlYWN0UGVyZi5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvUmVhY3RQcm9wVHJhbnNmZXJlci5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvUmVhY3RQcm9wVHlwZUxvY2F0aW9uTmFtZXMuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1JlYWN0UHJvcFR5cGVMb2NhdGlvbnMuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1JlYWN0UHJvcFR5cGVzLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9SZWFjdFB1dExpc3RlbmVyUXVldWUuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1JlYWN0UmVjb25jaWxlVHJhbnNhY3Rpb24uanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1JlYWN0Um9vdEluZGV4LmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9SZWFjdFNlcnZlclJlbmRlcmluZy5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvUmVhY3RTZXJ2ZXJSZW5kZXJpbmdUcmFuc2FjdGlvbi5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvUmVhY3RUZXh0Q29tcG9uZW50LmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9SZWFjdFVwZGF0ZXMuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1NWR0RPTVByb3BlcnR5Q29uZmlnLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9TZWxlY3RFdmVudFBsdWdpbi5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvU2VydmVyUmVhY3RSb290SW5kZXguanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1NpbXBsZUV2ZW50UGx1Z2luLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9TeW50aGV0aWNDbGlwYm9hcmRFdmVudC5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvU3ludGhldGljQ29tcG9zaXRpb25FdmVudC5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvU3ludGhldGljRHJhZ0V2ZW50LmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9TeW50aGV0aWNFdmVudC5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvU3ludGhldGljRm9jdXNFdmVudC5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvU3ludGhldGljSW5wdXRFdmVudC5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvU3ludGhldGljS2V5Ym9hcmRFdmVudC5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvU3ludGhldGljTW91c2VFdmVudC5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvU3ludGhldGljVG91Y2hFdmVudC5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvU3ludGhldGljVUlFdmVudC5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvU3ludGhldGljV2hlZWxFdmVudC5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvVHJhbnNhY3Rpb24uanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL1ZpZXdwb3J0TWV0cmljcy5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvYWNjdW11bGF0ZUludG8uanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL2FkbGVyMzIuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL2NhbWVsaXplLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9jYW1lbGl6ZVN0eWxlTmFtZS5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvY29udGFpbnNOb2RlLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9jcmVhdGVBcnJheUZyb20uanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL2NyZWF0ZUZ1bGxQYWdlQ29tcG9uZW50LmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9jcmVhdGVOb2Rlc0Zyb21NYXJrdXAuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL2Rhbmdlcm91c1N0eWxlVmFsdWUuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL2RlcHJlY2F0ZWQuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL2VtcHR5RnVuY3Rpb24uanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL2VtcHR5T2JqZWN0LmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9lc2NhcGVUZXh0Rm9yQnJvd3Nlci5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvZmxhdHRlbkNoaWxkcmVuLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9mb2N1c05vZGUuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL2ZvckVhY2hBY2N1bXVsYXRlZC5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvZ2V0QWN0aXZlRWxlbWVudC5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvZ2V0RXZlbnRDaGFyQ29kZS5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvZ2V0RXZlbnRLZXkuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL2dldEV2ZW50TW9kaWZpZXJTdGF0ZS5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvZ2V0RXZlbnRUYXJnZXQuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL2dldE1hcmt1cFdyYXAuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL2dldE5vZGVGb3JDaGFyYWN0ZXJPZmZzZXQuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL2dldFJlYWN0Um9vdEVsZW1lbnRJbkNvbnRhaW5lci5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvZ2V0VGV4dENvbnRlbnRBY2Nlc3Nvci5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvZ2V0VW5ib3VuZGVkU2Nyb2xsUG9zaXRpb24uanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL2h5cGhlbmF0ZS5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvaHlwaGVuYXRlU3R5bGVOYW1lLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9pbnN0YW50aWF0ZVJlYWN0Q29tcG9uZW50LmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9pbnZhcmlhbnQuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL2lzRXZlbnRTdXBwb3J0ZWQuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL2lzTm9kZS5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvaXNUZXh0SW5wdXRFbGVtZW50LmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9pc1RleHROb2RlLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9qb2luQ2xhc3Nlcy5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIva2V5TWlycm9yLmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9rZXlPZi5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvbWFwT2JqZWN0LmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9tZW1vaXplU3RyaW5nT25seS5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvbW9uaXRvckNvZGVVc2UuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL29ubHlDaGlsZC5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvcGVyZm9ybWFuY2UuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL3BlcmZvcm1hbmNlTm93LmpzIiwibm9kZV9tb2R1bGVzL3JlYWN0L2xpYi9zZXRJbm5lckhUTUwuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL3NoYWxsb3dFcXVhbC5qcyIsIm5vZGVfbW9kdWxlcy9yZWFjdC9saWIvc2hvdWxkVXBkYXRlUmVhY3RDb21wb25lbnQuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL3RvQXJyYXkuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL3RyYXZlcnNlQWxsQ2hpbGRyZW4uanMiLCJub2RlX21vZHVsZXMvcmVhY3QvbGliL3dhcm5pbmcuanMiLCJub2RlX21vZHVsZXMvcmVhY3QvcmVhY3QuanMiLCJyZWFjdC9CdWcuanN4IiwicmVhY3QvTGltaXRTZWxlY3QuanN4IiwicmVhY3QvUGF0aC5qc3giLCJyZWFjdC9Qcm9kdWN0LmpzeCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtBQ0FBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN0RkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1TkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbEhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcklBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVYQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdkJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqUUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdLQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6U0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbk1BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeExBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN0Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMUlBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdEVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeEZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbFJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN0UkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM05BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1SUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4TEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxSkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaERBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDN0NBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxTEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaldBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcEpBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3piQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4SEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM5NUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaENBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDckxBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy9EQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcmVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaExBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25EQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdExBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy9NQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNJQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdkVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL0hBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xRQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1TUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwUEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFRQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOUJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdExBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN0Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RJQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM3VUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JQQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4ckJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFhQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy9CQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdkVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMUpBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbEZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JLQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMUJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaFdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3REQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM5S0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM5RUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL0dBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4R0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaFNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pNQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDN0JBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFhQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNyQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNUpBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDckNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM5Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNURBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy9PQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM5QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM5QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeEZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0JBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM3QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0JBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2R0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDN0NBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM3QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuSEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6RUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy9CQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoSEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL0RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdkNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNyREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbkRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdENBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcENBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdEVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDckxBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0NBO0FBQ0E7O0FDREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNiQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdkJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbkJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIoZnVuY3Rpb24gZSh0LG4scil7ZnVuY3Rpb24gcyhvLHUpe2lmKCFuW29dKXtpZighdFtvXSl7dmFyIGE9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtpZighdSYmYSlyZXR1cm4gYShvLCEwKTtpZihpKXJldHVybiBpKG8sITApO3ZhciBmPW5ldyBFcnJvcihcIkNhbm5vdCBmaW5kIG1vZHVsZSAnXCIrbytcIidcIik7dGhyb3cgZi5jb2RlPVwiTU9EVUxFX05PVF9GT1VORFwiLGZ9dmFyIGw9bltvXT17ZXhwb3J0czp7fX07dFtvXVswXS5jYWxsKGwuZXhwb3J0cyxmdW5jdGlvbihlKXt2YXIgbj10W29dWzFdW2VdO3JldHVybiBzKG4/bjplKX0sbCxsLmV4cG9ydHMsZSx0LG4scil9cmV0dXJuIG5bb10uZXhwb3J0c312YXIgaT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2Zvcih2YXIgbz0wO288ci5sZW5ndGg7bysrKXMocltvXSk7cmV0dXJuIHN9KSIsInZhciBSZWFjdCA9IHJlcXVpcmUoJ3JlYWN0JyksXG4gUkVBQ1RTID0ge1xuICcuL3JlYWN0L0J1Zy5qc3gnOiByZXF1aXJlKCcuL3JlYWN0L0J1Zy5qc3gnKSxcbiAnLi9yZWFjdC9MaW1pdFNlbGVjdC5qc3gnOiByZXF1aXJlKCcuL3JlYWN0L0xpbWl0U2VsZWN0LmpzeCcpLFxuICcuL3JlYWN0L1BhdGguanN4JzogcmVxdWlyZSgnLi9yZWFjdC9QYXRoLmpzeCcpLFxuICcuL3JlYWN0L1Byb2R1Y3QuanN4JzogcmVxdWlyZSgnLi9yZWFjdC9Qcm9kdWN0LmpzeCcpLFxufSxcbnJlbmRlciA9IGZ1bmN0aW9uIChOLCBELCBNKSB7UmVhY3QucmVuZGVyKFJlYWN0LmNyZWF0ZUZhY3RvcnkoUkVBQ1RTW05dKShEKSwgTSk7XG5yZXR1cm4gcmVuZGVyfTtcbm1vZHVsZS5leHBvcnRzID0gcmVuZGVyOyIsIi8vIHNoaW0gZm9yIHVzaW5nIHByb2Nlc3MgaW4gYnJvd3NlclxuXG52YXIgcHJvY2VzcyA9IG1vZHVsZS5leHBvcnRzID0ge307XG5cbnByb2Nlc3MubmV4dFRpY2sgPSAoZnVuY3Rpb24gKCkge1xuICAgIHZhciBjYW5TZXRJbW1lZGlhdGUgPSB0eXBlb2Ygd2luZG93ICE9PSAndW5kZWZpbmVkJ1xuICAgICYmIHdpbmRvdy5zZXRJbW1lZGlhdGU7XG4gICAgdmFyIGNhbk11dGF0aW9uT2JzZXJ2ZXIgPSB0eXBlb2Ygd2luZG93ICE9PSAndW5kZWZpbmVkJ1xuICAgICYmIHdpbmRvdy5NdXRhdGlvbk9ic2VydmVyO1xuICAgIHZhciBjYW5Qb3N0ID0gdHlwZW9mIHdpbmRvdyAhPT0gJ3VuZGVmaW5lZCdcbiAgICAmJiB3aW5kb3cucG9zdE1lc3NhZ2UgJiYgd2luZG93LmFkZEV2ZW50TGlzdGVuZXJcbiAgICA7XG5cbiAgICBpZiAoY2FuU2V0SW1tZWRpYXRlKSB7XG4gICAgICAgIHJldHVybiBmdW5jdGlvbiAoZikgeyByZXR1cm4gd2luZG93LnNldEltbWVkaWF0ZShmKSB9O1xuICAgIH1cblxuICAgIHZhciBxdWV1ZSA9IFtdO1xuXG4gICAgaWYgKGNhbk11dGF0aW9uT2JzZXJ2ZXIpIHtcbiAgICAgICAgdmFyIGhpZGRlbkRpdiA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJkaXZcIik7XG4gICAgICAgIHZhciBvYnNlcnZlciA9IG5ldyBNdXRhdGlvbk9ic2VydmVyKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBxdWV1ZUxpc3QgPSBxdWV1ZS5zbGljZSgpO1xuICAgICAgICAgICAgcXVldWUubGVuZ3RoID0gMDtcbiAgICAgICAgICAgIHF1ZXVlTGlzdC5mb3JFYWNoKGZ1bmN0aW9uIChmbikge1xuICAgICAgICAgICAgICAgIGZuKCk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgb2JzZXJ2ZXIub2JzZXJ2ZShoaWRkZW5EaXYsIHsgYXR0cmlidXRlczogdHJ1ZSB9KTtcblxuICAgICAgICByZXR1cm4gZnVuY3Rpb24gbmV4dFRpY2soZm4pIHtcbiAgICAgICAgICAgIGlmICghcXVldWUubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgaGlkZGVuRGl2LnNldEF0dHJpYnV0ZSgneWVzJywgJ25vJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBxdWV1ZS5wdXNoKGZuKTtcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICBpZiAoY2FuUG9zdCkge1xuICAgICAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignbWVzc2FnZScsIGZ1bmN0aW9uIChldikge1xuICAgICAgICAgICAgdmFyIHNvdXJjZSA9IGV2LnNvdXJjZTtcbiAgICAgICAgICAgIGlmICgoc291cmNlID09PSB3aW5kb3cgfHwgc291cmNlID09PSBudWxsKSAmJiBldi5kYXRhID09PSAncHJvY2Vzcy10aWNrJykge1xuICAgICAgICAgICAgICAgIGV2LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgICAgICAgICAgICAgIGlmIChxdWV1ZS5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBmbiA9IHF1ZXVlLnNoaWZ0KCk7XG4gICAgICAgICAgICAgICAgICAgIGZuKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9LCB0cnVlKTtcblxuICAgICAgICByZXR1cm4gZnVuY3Rpb24gbmV4dFRpY2soZm4pIHtcbiAgICAgICAgICAgIHF1ZXVlLnB1c2goZm4pO1xuICAgICAgICAgICAgd2luZG93LnBvc3RNZXNzYWdlKCdwcm9jZXNzLXRpY2snLCAnKicpO1xuICAgICAgICB9O1xuICAgIH1cblxuICAgIHJldHVybiBmdW5jdGlvbiBuZXh0VGljayhmbikge1xuICAgICAgICBzZXRUaW1lb3V0KGZuLCAwKTtcbiAgICB9O1xufSkoKTtcblxucHJvY2Vzcy50aXRsZSA9ICdicm93c2VyJztcbnByb2Nlc3MuYnJvd3NlciA9IHRydWU7XG5wcm9jZXNzLmVudiA9IHt9O1xucHJvY2Vzcy5hcmd2ID0gW107XG5cbmZ1bmN0aW9uIG5vb3AoKSB7fVxuXG5wcm9jZXNzLm9uID0gbm9vcDtcbnByb2Nlc3MuYWRkTGlzdGVuZXIgPSBub29wO1xucHJvY2Vzcy5vbmNlID0gbm9vcDtcbnByb2Nlc3Mub2ZmID0gbm9vcDtcbnByb2Nlc3MucmVtb3ZlTGlzdGVuZXIgPSBub29wO1xucHJvY2Vzcy5yZW1vdmVBbGxMaXN0ZW5lcnMgPSBub29wO1xucHJvY2Vzcy5lbWl0ID0gbm9vcDtcblxucHJvY2Vzcy5iaW5kaW5nID0gZnVuY3Rpb24gKG5hbWUpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ3Byb2Nlc3MuYmluZGluZyBpcyBub3Qgc3VwcG9ydGVkJyk7XG59O1xuXG4vLyBUT0RPKHNodHlsbWFuKVxucHJvY2Vzcy5jd2QgPSBmdW5jdGlvbiAoKSB7IHJldHVybiAnLycgfTtcbnByb2Nlc3MuY2hkaXIgPSBmdW5jdGlvbiAoZGlyKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdwcm9jZXNzLmNoZGlyIGlzIG5vdCBzdXBwb3J0ZWQnKTtcbn07XG4iLCIvKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgQXV0b0ZvY3VzTWl4aW5cbiAqIEB0eXBlY2hlY2tzIHN0YXRpYy1vbmx5XG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBmb2N1c05vZGUgPSByZXF1aXJlKFwiLi9mb2N1c05vZGVcIik7XG5cbnZhciBBdXRvRm9jdXNNaXhpbiA9IHtcbiAgY29tcG9uZW50RGlkTW91bnQ6IGZ1bmN0aW9uKCkge1xuICAgIGlmICh0aGlzLnByb3BzLmF1dG9Gb2N1cykge1xuICAgICAgZm9jdXNOb2RlKHRoaXMuZ2V0RE9NTm9kZSgpKTtcbiAgICB9XG4gIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gQXV0b0ZvY3VzTWl4aW47XG4iLCIvKipcbiAqIENvcHlyaWdodCAyMDEzIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgQmVmb3JlSW5wdXRFdmVudFBsdWdpblxuICogQHR5cGVjaGVja3Mgc3RhdGljLW9ubHlcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIEV2ZW50Q29uc3RhbnRzID0gcmVxdWlyZShcIi4vRXZlbnRDb25zdGFudHNcIik7XG52YXIgRXZlbnRQcm9wYWdhdG9ycyA9IHJlcXVpcmUoXCIuL0V2ZW50UHJvcGFnYXRvcnNcIik7XG52YXIgRXhlY3V0aW9uRW52aXJvbm1lbnQgPSByZXF1aXJlKFwiLi9FeGVjdXRpb25FbnZpcm9ubWVudFwiKTtcbnZhciBTeW50aGV0aWNJbnB1dEV2ZW50ID0gcmVxdWlyZShcIi4vU3ludGhldGljSW5wdXRFdmVudFwiKTtcblxudmFyIGtleU9mID0gcmVxdWlyZShcIi4va2V5T2ZcIik7XG5cbnZhciBjYW5Vc2VUZXh0SW5wdXRFdmVudCA9IChcbiAgRXhlY3V0aW9uRW52aXJvbm1lbnQuY2FuVXNlRE9NICYmXG4gICdUZXh0RXZlbnQnIGluIHdpbmRvdyAmJlxuICAhKCdkb2N1bWVudE1vZGUnIGluIGRvY3VtZW50IHx8IGlzUHJlc3RvKCkpXG4pO1xuXG4vKipcbiAqIE9wZXJhIDw9IDEyIGluY2x1ZGVzIFRleHRFdmVudCBpbiB3aW5kb3csIGJ1dCBkb2VzIG5vdCBmaXJlXG4gKiB0ZXh0IGlucHV0IGV2ZW50cy4gUmVseSBvbiBrZXlwcmVzcyBpbnN0ZWFkLlxuICovXG5mdW5jdGlvbiBpc1ByZXN0bygpIHtcbiAgdmFyIG9wZXJhID0gd2luZG93Lm9wZXJhO1xuICByZXR1cm4gKFxuICAgIHR5cGVvZiBvcGVyYSA9PT0gJ29iamVjdCcgJiZcbiAgICB0eXBlb2Ygb3BlcmEudmVyc2lvbiA9PT0gJ2Z1bmN0aW9uJyAmJlxuICAgIHBhcnNlSW50KG9wZXJhLnZlcnNpb24oKSwgMTApIDw9IDEyXG4gICk7XG59XG5cbnZhciBTUEFDRUJBUl9DT0RFID0gMzI7XG52YXIgU1BBQ0VCQVJfQ0hBUiA9IFN0cmluZy5mcm9tQ2hhckNvZGUoU1BBQ0VCQVJfQ09ERSk7XG5cbnZhciB0b3BMZXZlbFR5cGVzID0gRXZlbnRDb25zdGFudHMudG9wTGV2ZWxUeXBlcztcblxuLy8gRXZlbnRzIGFuZCB0aGVpciBjb3JyZXNwb25kaW5nIHByb3BlcnR5IG5hbWVzLlxudmFyIGV2ZW50VHlwZXMgPSB7XG4gIGJlZm9yZUlucHV0OiB7XG4gICAgcGhhc2VkUmVnaXN0cmF0aW9uTmFtZXM6IHtcbiAgICAgIGJ1YmJsZWQ6IGtleU9mKHtvbkJlZm9yZUlucHV0OiBudWxsfSksXG4gICAgICBjYXB0dXJlZDoga2V5T2Yoe29uQmVmb3JlSW5wdXRDYXB0dXJlOiBudWxsfSlcbiAgICB9LFxuICAgIGRlcGVuZGVuY2llczogW1xuICAgICAgdG9wTGV2ZWxUeXBlcy50b3BDb21wb3NpdGlvbkVuZCxcbiAgICAgIHRvcExldmVsVHlwZXMudG9wS2V5UHJlc3MsXG4gICAgICB0b3BMZXZlbFR5cGVzLnRvcFRleHRJbnB1dCxcbiAgICAgIHRvcExldmVsVHlwZXMudG9wUGFzdGVcbiAgICBdXG4gIH1cbn07XG5cbi8vIFRyYWNrIGNoYXJhY3RlcnMgaW5zZXJ0ZWQgdmlhIGtleXByZXNzIGFuZCBjb21wb3NpdGlvbiBldmVudHMuXG52YXIgZmFsbGJhY2tDaGFycyA9IG51bGw7XG5cbi8vIFRyYWNrIHdoZXRoZXIgd2UndmUgZXZlciBoYW5kbGVkIGEga2V5cHJlc3Mgb24gdGhlIHNwYWNlIGtleS5cbnZhciBoYXNTcGFjZUtleXByZXNzID0gZmFsc2U7XG5cbi8qKlxuICogUmV0dXJuIHdoZXRoZXIgYSBuYXRpdmUga2V5cHJlc3MgZXZlbnQgaXMgYXNzdW1lZCB0byBiZSBhIGNvbW1hbmQuXG4gKiBUaGlzIGlzIHJlcXVpcmVkIGJlY2F1c2UgRmlyZWZveCBmaXJlcyBga2V5cHJlc3NgIGV2ZW50cyBmb3Iga2V5IGNvbW1hbmRzXG4gKiAoY3V0LCBjb3B5LCBzZWxlY3QtYWxsLCBldGMuKSBldmVuIHRob3VnaCBubyBjaGFyYWN0ZXIgaXMgaW5zZXJ0ZWQuXG4gKi9cbmZ1bmN0aW9uIGlzS2V5cHJlc3NDb21tYW5kKG5hdGl2ZUV2ZW50KSB7XG4gIHJldHVybiAoXG4gICAgKG5hdGl2ZUV2ZW50LmN0cmxLZXkgfHwgbmF0aXZlRXZlbnQuYWx0S2V5IHx8IG5hdGl2ZUV2ZW50Lm1ldGFLZXkpICYmXG4gICAgLy8gY3RybEtleSAmJiBhbHRLZXkgaXMgZXF1aXZhbGVudCB0byBBbHRHciwgYW5kIGlzIG5vdCBhIGNvbW1hbmQuXG4gICAgIShuYXRpdmVFdmVudC5jdHJsS2V5ICYmIG5hdGl2ZUV2ZW50LmFsdEtleSlcbiAgKTtcbn1cblxuLyoqXG4gKiBDcmVhdGUgYW4gYG9uQmVmb3JlSW5wdXRgIGV2ZW50IHRvIG1hdGNoXG4gKiBodHRwOi8vd3d3LnczLm9yZy9UUi8yMDEzL1dELURPTS1MZXZlbC0zLUV2ZW50cy0yMDEzMTEwNS8jZXZlbnRzLWlucHV0ZXZlbnRzLlxuICpcbiAqIFRoaXMgZXZlbnQgcGx1Z2luIGlzIGJhc2VkIG9uIHRoZSBuYXRpdmUgYHRleHRJbnB1dGAgZXZlbnRcbiAqIGF2YWlsYWJsZSBpbiBDaHJvbWUsIFNhZmFyaSwgT3BlcmEsIGFuZCBJRS4gVGhpcyBldmVudCBmaXJlcyBhZnRlclxuICogYG9uS2V5UHJlc3NgIGFuZCBgb25Db21wb3NpdGlvbkVuZGAsIGJ1dCBiZWZvcmUgYG9uSW5wdXRgLlxuICpcbiAqIGBiZWZvcmVJbnB1dGAgaXMgc3BlYydkIGJ1dCBub3QgaW1wbGVtZW50ZWQgaW4gYW55IGJyb3dzZXJzLCBhbmRcbiAqIHRoZSBgaW5wdXRgIGV2ZW50IGRvZXMgbm90IHByb3ZpZGUgYW55IHVzZWZ1bCBpbmZvcm1hdGlvbiBhYm91dCB3aGF0IGhhc1xuICogYWN0dWFsbHkgYmVlbiBhZGRlZCwgY29udHJhcnkgdG8gdGhlIHNwZWMuIFRodXMsIGB0ZXh0SW5wdXRgIGlzIHRoZSBiZXN0XG4gKiBhdmFpbGFibGUgZXZlbnQgdG8gaWRlbnRpZnkgdGhlIGNoYXJhY3RlcnMgdGhhdCBoYXZlIGFjdHVhbGx5IGJlZW4gaW5zZXJ0ZWRcbiAqIGludG8gdGhlIHRhcmdldCBub2RlLlxuICovXG52YXIgQmVmb3JlSW5wdXRFdmVudFBsdWdpbiA9IHtcblxuICBldmVudFR5cGVzOiBldmVudFR5cGVzLFxuXG4gIC8qKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gdG9wTGV2ZWxUeXBlIFJlY29yZCBmcm9tIGBFdmVudENvbnN0YW50c2AuXG4gICAqIEBwYXJhbSB7RE9NRXZlbnRUYXJnZXR9IHRvcExldmVsVGFyZ2V0IFRoZSBsaXN0ZW5pbmcgY29tcG9uZW50IHJvb3Qgbm9kZS5cbiAgICogQHBhcmFtIHtzdHJpbmd9IHRvcExldmVsVGFyZ2V0SUQgSUQgb2YgYHRvcExldmVsVGFyZ2V0YC5cbiAgICogQHBhcmFtIHtvYmplY3R9IG5hdGl2ZUV2ZW50IE5hdGl2ZSBicm93c2VyIGV2ZW50LlxuICAgKiBAcmV0dXJuIHsqfSBBbiBhY2N1bXVsYXRpb24gb2Ygc3ludGhldGljIGV2ZW50cy5cbiAgICogQHNlZSB7RXZlbnRQbHVnaW5IdWIuZXh0cmFjdEV2ZW50c31cbiAgICovXG4gIGV4dHJhY3RFdmVudHM6IGZ1bmN0aW9uKFxuICAgICAgdG9wTGV2ZWxUeXBlLFxuICAgICAgdG9wTGV2ZWxUYXJnZXQsXG4gICAgICB0b3BMZXZlbFRhcmdldElELFxuICAgICAgbmF0aXZlRXZlbnQpIHtcblxuICAgIHZhciBjaGFycztcblxuICAgIGlmIChjYW5Vc2VUZXh0SW5wdXRFdmVudCkge1xuICAgICAgc3dpdGNoICh0b3BMZXZlbFR5cGUpIHtcbiAgICAgICAgY2FzZSB0b3BMZXZlbFR5cGVzLnRvcEtleVByZXNzOlxuICAgICAgICAgIC8qKlxuICAgICAgICAgICAqIElmIG5hdGl2ZSBgdGV4dElucHV0YCBldmVudHMgYXJlIGF2YWlsYWJsZSwgb3VyIGdvYWwgaXMgdG8gbWFrZVxuICAgICAgICAgICAqIHVzZSBvZiB0aGVtLiBIb3dldmVyLCB0aGVyZSBpcyBhIHNwZWNpYWwgY2FzZTogdGhlIHNwYWNlYmFyIGtleS5cbiAgICAgICAgICAgKiBJbiBXZWJraXQsIHByZXZlbnRpbmcgZGVmYXVsdCBvbiBhIHNwYWNlYmFyIGB0ZXh0SW5wdXRgIGV2ZW50XG4gICAgICAgICAgICogY2FuY2VscyBjaGFyYWN0ZXIgaW5zZXJ0aW9uLCBidXQgaXQgKmFsc28qIGNhdXNlcyB0aGUgYnJvd3NlclxuICAgICAgICAgICAqIHRvIGZhbGwgYmFjayB0byBpdHMgZGVmYXVsdCBzcGFjZWJhciBiZWhhdmlvciBvZiBzY3JvbGxpbmcgdGhlXG4gICAgICAgICAgICogcGFnZS5cbiAgICAgICAgICAgKlxuICAgICAgICAgICAqIFRyYWNraW5nIGF0OlxuICAgICAgICAgICAqIGh0dHBzOi8vY29kZS5nb29nbGUuY29tL3AvY2hyb21pdW0vaXNzdWVzL2RldGFpbD9pZD0zNTUxMDNcbiAgICAgICAgICAgKlxuICAgICAgICAgICAqIFRvIGF2b2lkIHRoaXMgaXNzdWUsIHVzZSB0aGUga2V5cHJlc3MgZXZlbnQgYXMgaWYgbm8gYHRleHRJbnB1dGBcbiAgICAgICAgICAgKiBldmVudCBpcyBhdmFpbGFibGUuXG4gICAgICAgICAgICovXG4gICAgICAgICAgdmFyIHdoaWNoID0gbmF0aXZlRXZlbnQud2hpY2g7XG4gICAgICAgICAgaWYgKHdoaWNoICE9PSBTUEFDRUJBUl9DT0RFKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaGFzU3BhY2VLZXlwcmVzcyA9IHRydWU7XG4gICAgICAgICAgY2hhcnMgPSBTUEFDRUJBUl9DSEFSO1xuICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgIGNhc2UgdG9wTGV2ZWxUeXBlcy50b3BUZXh0SW5wdXQ6XG4gICAgICAgICAgLy8gUmVjb3JkIHRoZSBjaGFyYWN0ZXJzIHRvIGJlIGFkZGVkIHRvIHRoZSBET00uXG4gICAgICAgICAgY2hhcnMgPSBuYXRpdmVFdmVudC5kYXRhO1xuXG4gICAgICAgICAgLy8gSWYgaXQncyBhIHNwYWNlYmFyIGNoYXJhY3RlciwgYXNzdW1lIHRoYXQgd2UgaGF2ZSBhbHJlYWR5IGhhbmRsZWRcbiAgICAgICAgICAvLyBpdCBhdCB0aGUga2V5cHJlc3MgbGV2ZWwgYW5kIGJhaWwgaW1tZWRpYXRlbHkuIEFuZHJvaWQgQ2hyb21lXG4gICAgICAgICAgLy8gZG9lc24ndCBnaXZlIHVzIGtleWNvZGVzLCBzbyB3ZSBuZWVkIHRvIGJsYWNrbGlzdCBpdC5cbiAgICAgICAgICBpZiAoY2hhcnMgPT09IFNQQUNFQkFSX0NIQVIgJiYgaGFzU3BhY2VLZXlwcmVzcykge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIE90aGVyd2lzZSwgY2Fycnkgb24uXG4gICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAvLyBGb3Igb3RoZXIgbmF0aXZlIGV2ZW50IHR5cGVzLCBkbyBub3RoaW5nLlxuICAgICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgc3dpdGNoICh0b3BMZXZlbFR5cGUpIHtcbiAgICAgICAgY2FzZSB0b3BMZXZlbFR5cGVzLnRvcFBhc3RlOlxuICAgICAgICAgIC8vIElmIGEgcGFzdGUgZXZlbnQgb2NjdXJzIGFmdGVyIGEga2V5cHJlc3MsIHRocm93IG91dCB0aGUgaW5wdXRcbiAgICAgICAgICAvLyBjaGFycy4gUGFzdGUgZXZlbnRzIHNob3VsZCBub3QgbGVhZCB0byBCZWZvcmVJbnB1dCBldmVudHMuXG4gICAgICAgICAgZmFsbGJhY2tDaGFycyA9IG51bGw7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgdG9wTGV2ZWxUeXBlcy50b3BLZXlQcmVzczpcbiAgICAgICAgICAvKipcbiAgICAgICAgICAgKiBBcyBvZiB2MjcsIEZpcmVmb3ggbWF5IGZpcmUga2V5cHJlc3MgZXZlbnRzIGV2ZW4gd2hlbiBubyBjaGFyYWN0ZXJcbiAgICAgICAgICAgKiB3aWxsIGJlIGluc2VydGVkLiBBIGZldyBwb3NzaWJpbGl0aWVzOlxuICAgICAgICAgICAqXG4gICAgICAgICAgICogLSBgd2hpY2hgIGlzIGAwYC4gQXJyb3cga2V5cywgRXNjIGtleSwgZXRjLlxuICAgICAgICAgICAqXG4gICAgICAgICAgICogLSBgd2hpY2hgIGlzIHRoZSBwcmVzc2VkIGtleSBjb2RlLCBidXQgbm8gY2hhciBpcyBhdmFpbGFibGUuXG4gICAgICAgICAgICogICBFeDogJ0FsdEdyICsgZGAgaW4gUG9saXNoLiBUaGVyZSBpcyBubyBtb2RpZmllZCBjaGFyYWN0ZXIgZm9yXG4gICAgICAgICAgICogICB0aGlzIGtleSBjb21iaW5hdGlvbiBhbmQgbm8gY2hhcmFjdGVyIGlzIGluc2VydGVkIGludG8gdGhlXG4gICAgICAgICAgICogICBkb2N1bWVudCwgYnV0IEZGIGZpcmVzIHRoZSBrZXlwcmVzcyBmb3IgY2hhciBjb2RlIGAxMDBgIGFueXdheS5cbiAgICAgICAgICAgKiAgIE5vIGBpbnB1dGAgZXZlbnQgd2lsbCBvY2N1ci5cbiAgICAgICAgICAgKlxuICAgICAgICAgICAqIC0gYHdoaWNoYCBpcyB0aGUgcHJlc3NlZCBrZXkgY29kZSwgYnV0IGEgY29tbWFuZCBjb21iaW5hdGlvbiBpc1xuICAgICAgICAgICAqICAgYmVpbmcgdXNlZC4gRXg6IGBDbWQrQ2AuIE5vIGNoYXJhY3RlciBpcyBpbnNlcnRlZCwgYW5kIG5vXG4gICAgICAgICAgICogICBgaW5wdXRgIGV2ZW50IHdpbGwgb2NjdXIuXG4gICAgICAgICAgICovXG4gICAgICAgICAgaWYgKG5hdGl2ZUV2ZW50LndoaWNoICYmICFpc0tleXByZXNzQ29tbWFuZChuYXRpdmVFdmVudCkpIHtcbiAgICAgICAgICAgIGZhbGxiYWNrQ2hhcnMgPSBTdHJpbmcuZnJvbUNoYXJDb2RlKG5hdGl2ZUV2ZW50LndoaWNoKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgdG9wTGV2ZWxUeXBlcy50b3BDb21wb3NpdGlvbkVuZDpcbiAgICAgICAgICBmYWxsYmFja0NoYXJzID0gbmF0aXZlRXZlbnQuZGF0YTtcbiAgICAgICAgICBicmVhaztcbiAgICAgIH1cblxuICAgICAgLy8gSWYgbm8gY2hhbmdlcyBoYXZlIG9jY3VycmVkIHRvIHRoZSBmYWxsYmFjayBzdHJpbmcsIG5vIHJlbGV2YW50XG4gICAgICAvLyBldmVudCBoYXMgZmlyZWQgYW5kIHdlJ3JlIGRvbmUuXG4gICAgICBpZiAoZmFsbGJhY2tDaGFycyA9PT0gbnVsbCkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNoYXJzID0gZmFsbGJhY2tDaGFycztcbiAgICB9XG5cbiAgICAvLyBJZiBubyBjaGFyYWN0ZXJzIGFyZSBiZWluZyBpbnNlcnRlZCwgbm8gQmVmb3JlSW5wdXQgZXZlbnQgc2hvdWxkXG4gICAgLy8gYmUgZmlyZWQuXG4gICAgaWYgKCFjaGFycykge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHZhciBldmVudCA9IFN5bnRoZXRpY0lucHV0RXZlbnQuZ2V0UG9vbGVkKFxuICAgICAgZXZlbnRUeXBlcy5iZWZvcmVJbnB1dCxcbiAgICAgIHRvcExldmVsVGFyZ2V0SUQsXG4gICAgICBuYXRpdmVFdmVudFxuICAgICk7XG5cbiAgICBldmVudC5kYXRhID0gY2hhcnM7XG4gICAgZmFsbGJhY2tDaGFycyA9IG51bGw7XG4gICAgRXZlbnRQcm9wYWdhdG9ycy5hY2N1bXVsYXRlVHdvUGhhc2VEaXNwYXRjaGVzKGV2ZW50KTtcbiAgICByZXR1cm4gZXZlbnQ7XG4gIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gQmVmb3JlSW5wdXRFdmVudFBsdWdpbjtcbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBDU1NQcm9wZXJ0eVxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG4vKipcbiAqIENTUyBwcm9wZXJ0aWVzIHdoaWNoIGFjY2VwdCBudW1iZXJzIGJ1dCBhcmUgbm90IGluIHVuaXRzIG9mIFwicHhcIi5cbiAqL1xudmFyIGlzVW5pdGxlc3NOdW1iZXIgPSB7XG4gIGNvbHVtbkNvdW50OiB0cnVlLFxuICBmaWxsT3BhY2l0eTogdHJ1ZSxcbiAgZmxleDogdHJ1ZSxcbiAgZmxleEdyb3c6IHRydWUsXG4gIGZsZXhTaHJpbms6IHRydWUsXG4gIGZvbnRXZWlnaHQ6IHRydWUsXG4gIGxpbmVDbGFtcDogdHJ1ZSxcbiAgbGluZUhlaWdodDogdHJ1ZSxcbiAgb3BhY2l0eTogdHJ1ZSxcbiAgb3JkZXI6IHRydWUsXG4gIG9ycGhhbnM6IHRydWUsXG4gIHdpZG93czogdHJ1ZSxcbiAgekluZGV4OiB0cnVlLFxuICB6b29tOiB0cnVlXG59O1xuXG4vKipcbiAqIEBwYXJhbSB7c3RyaW5nfSBwcmVmaXggdmVuZG9yLXNwZWNpZmljIHByZWZpeCwgZWc6IFdlYmtpdFxuICogQHBhcmFtIHtzdHJpbmd9IGtleSBzdHlsZSBuYW1lLCBlZzogdHJhbnNpdGlvbkR1cmF0aW9uXG4gKiBAcmV0dXJuIHtzdHJpbmd9IHN0eWxlIG5hbWUgcHJlZml4ZWQgd2l0aCBgcHJlZml4YCwgcHJvcGVybHkgY2FtZWxDYXNlZCwgZWc6XG4gKiBXZWJraXRUcmFuc2l0aW9uRHVyYXRpb25cbiAqL1xuZnVuY3Rpb24gcHJlZml4S2V5KHByZWZpeCwga2V5KSB7XG4gIHJldHVybiBwcmVmaXggKyBrZXkuY2hhckF0KDApLnRvVXBwZXJDYXNlKCkgKyBrZXkuc3Vic3RyaW5nKDEpO1xufVxuXG4vKipcbiAqIFN1cHBvcnQgc3R5bGUgbmFtZXMgdGhhdCBtYXkgY29tZSBwYXNzZWQgaW4gcHJlZml4ZWQgYnkgYWRkaW5nIHBlcm11dGF0aW9uc1xuICogb2YgdmVuZG9yIHByZWZpeGVzLlxuICovXG52YXIgcHJlZml4ZXMgPSBbJ1dlYmtpdCcsICdtcycsICdNb3onLCAnTyddO1xuXG4vLyBVc2luZyBPYmplY3Qua2V5cyBoZXJlLCBvciBlbHNlIHRoZSB2YW5pbGxhIGZvci1pbiBsb29wIG1ha2VzIElFOCBnbyBpbnRvIGFuXG4vLyBpbmZpbml0ZSBsb29wLCBiZWNhdXNlIGl0IGl0ZXJhdGVzIG92ZXIgdGhlIG5ld2x5IGFkZGVkIHByb3BzIHRvby5cbk9iamVjdC5rZXlzKGlzVW5pdGxlc3NOdW1iZXIpLmZvckVhY2goZnVuY3Rpb24ocHJvcCkge1xuICBwcmVmaXhlcy5mb3JFYWNoKGZ1bmN0aW9uKHByZWZpeCkge1xuICAgIGlzVW5pdGxlc3NOdW1iZXJbcHJlZml4S2V5KHByZWZpeCwgcHJvcCldID0gaXNVbml0bGVzc051bWJlcltwcm9wXTtcbiAgfSk7XG59KTtcblxuLyoqXG4gKiBNb3N0IHN0eWxlIHByb3BlcnRpZXMgY2FuIGJlIHVuc2V0IGJ5IGRvaW5nIC5zdHlsZVtwcm9wXSA9ICcnIGJ1dCBJRThcbiAqIGRvZXNuJ3QgbGlrZSBkb2luZyB0aGF0IHdpdGggc2hvcnRoYW5kIHByb3BlcnRpZXMgc28gZm9yIHRoZSBwcm9wZXJ0aWVzIHRoYXRcbiAqIElFOCBicmVha3Mgb24sIHdoaWNoIGFyZSBsaXN0ZWQgaGVyZSwgd2UgaW5zdGVhZCB1bnNldCBlYWNoIG9mIHRoZVxuICogaW5kaXZpZHVhbCBwcm9wZXJ0aWVzLiBTZWUgaHR0cDovL2J1Z3MuanF1ZXJ5LmNvbS90aWNrZXQvMTIzODUuXG4gKiBUaGUgNC12YWx1ZSAnY2xvY2snIHByb3BlcnRpZXMgbGlrZSBtYXJnaW4sIHBhZGRpbmcsIGJvcmRlci13aWR0aCBzZWVtIHRvXG4gKiBiZWhhdmUgd2l0aG91dCBhbnkgcHJvYmxlbXMuIEN1cmlvdXNseSwgbGlzdC1zdHlsZSB3b3JrcyB0b28gd2l0aG91dCBhbnlcbiAqIHNwZWNpYWwgcHJvZGRpbmcuXG4gKi9cbnZhciBzaG9ydGhhbmRQcm9wZXJ0eUV4cGFuc2lvbnMgPSB7XG4gIGJhY2tncm91bmQ6IHtcbiAgICBiYWNrZ3JvdW5kSW1hZ2U6IHRydWUsXG4gICAgYmFja2dyb3VuZFBvc2l0aW9uOiB0cnVlLFxuICAgIGJhY2tncm91bmRSZXBlYXQ6IHRydWUsXG4gICAgYmFja2dyb3VuZENvbG9yOiB0cnVlXG4gIH0sXG4gIGJvcmRlcjoge1xuICAgIGJvcmRlcldpZHRoOiB0cnVlLFxuICAgIGJvcmRlclN0eWxlOiB0cnVlLFxuICAgIGJvcmRlckNvbG9yOiB0cnVlXG4gIH0sXG4gIGJvcmRlckJvdHRvbToge1xuICAgIGJvcmRlckJvdHRvbVdpZHRoOiB0cnVlLFxuICAgIGJvcmRlckJvdHRvbVN0eWxlOiB0cnVlLFxuICAgIGJvcmRlckJvdHRvbUNvbG9yOiB0cnVlXG4gIH0sXG4gIGJvcmRlckxlZnQ6IHtcbiAgICBib3JkZXJMZWZ0V2lkdGg6IHRydWUsXG4gICAgYm9yZGVyTGVmdFN0eWxlOiB0cnVlLFxuICAgIGJvcmRlckxlZnRDb2xvcjogdHJ1ZVxuICB9LFxuICBib3JkZXJSaWdodDoge1xuICAgIGJvcmRlclJpZ2h0V2lkdGg6IHRydWUsXG4gICAgYm9yZGVyUmlnaHRTdHlsZTogdHJ1ZSxcbiAgICBib3JkZXJSaWdodENvbG9yOiB0cnVlXG4gIH0sXG4gIGJvcmRlclRvcDoge1xuICAgIGJvcmRlclRvcFdpZHRoOiB0cnVlLFxuICAgIGJvcmRlclRvcFN0eWxlOiB0cnVlLFxuICAgIGJvcmRlclRvcENvbG9yOiB0cnVlXG4gIH0sXG4gIGZvbnQ6IHtcbiAgICBmb250U3R5bGU6IHRydWUsXG4gICAgZm9udFZhcmlhbnQ6IHRydWUsXG4gICAgZm9udFdlaWdodDogdHJ1ZSxcbiAgICBmb250U2l6ZTogdHJ1ZSxcbiAgICBsaW5lSGVpZ2h0OiB0cnVlLFxuICAgIGZvbnRGYW1pbHk6IHRydWVcbiAgfVxufTtcblxudmFyIENTU1Byb3BlcnR5ID0ge1xuICBpc1VuaXRsZXNzTnVtYmVyOiBpc1VuaXRsZXNzTnVtYmVyLFxuICBzaG9ydGhhbmRQcm9wZXJ0eUV4cGFuc2lvbnM6IHNob3J0aGFuZFByb3BlcnR5RXhwYW5zaW9uc1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSBDU1NQcm9wZXJ0eTtcbiIsIihmdW5jdGlvbiAocHJvY2Vzcyl7XG4vKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgQ1NTUHJvcGVydHlPcGVyYXRpb25zXG4gKiBAdHlwZWNoZWNrcyBzdGF0aWMtb25seVxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgQ1NTUHJvcGVydHkgPSByZXF1aXJlKFwiLi9DU1NQcm9wZXJ0eVwiKTtcbnZhciBFeGVjdXRpb25FbnZpcm9ubWVudCA9IHJlcXVpcmUoXCIuL0V4ZWN1dGlvbkVudmlyb25tZW50XCIpO1xuXG52YXIgY2FtZWxpemVTdHlsZU5hbWUgPSByZXF1aXJlKFwiLi9jYW1lbGl6ZVN0eWxlTmFtZVwiKTtcbnZhciBkYW5nZXJvdXNTdHlsZVZhbHVlID0gcmVxdWlyZShcIi4vZGFuZ2Vyb3VzU3R5bGVWYWx1ZVwiKTtcbnZhciBoeXBoZW5hdGVTdHlsZU5hbWUgPSByZXF1aXJlKFwiLi9oeXBoZW5hdGVTdHlsZU5hbWVcIik7XG52YXIgbWVtb2l6ZVN0cmluZ09ubHkgPSByZXF1aXJlKFwiLi9tZW1vaXplU3RyaW5nT25seVwiKTtcbnZhciB3YXJuaW5nID0gcmVxdWlyZShcIi4vd2FybmluZ1wiKTtcblxudmFyIHByb2Nlc3NTdHlsZU5hbWUgPSBtZW1vaXplU3RyaW5nT25seShmdW5jdGlvbihzdHlsZU5hbWUpIHtcbiAgcmV0dXJuIGh5cGhlbmF0ZVN0eWxlTmFtZShzdHlsZU5hbWUpO1xufSk7XG5cbnZhciBzdHlsZUZsb2F0QWNjZXNzb3IgPSAnY3NzRmxvYXQnO1xuaWYgKEV4ZWN1dGlvbkVudmlyb25tZW50LmNhblVzZURPTSkge1xuICAvLyBJRTggb25seSBzdXBwb3J0cyBhY2Nlc3NpbmcgY3NzRmxvYXQgKHN0YW5kYXJkKSBhcyBzdHlsZUZsb2F0XG4gIGlmIChkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuc3R5bGUuY3NzRmxvYXQgPT09IHVuZGVmaW5lZCkge1xuICAgIHN0eWxlRmxvYXRBY2Nlc3NvciA9ICdzdHlsZUZsb2F0JztcbiAgfVxufVxuXG5pZiAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WKSB7XG4gIHZhciB3YXJuZWRTdHlsZU5hbWVzID0ge307XG5cbiAgdmFyIHdhcm5IeXBoZW5hdGVkU3R5bGVOYW1lID0gZnVuY3Rpb24obmFtZSkge1xuICAgIGlmICh3YXJuZWRTdHlsZU5hbWVzLmhhc093blByb3BlcnR5KG5hbWUpICYmIHdhcm5lZFN0eWxlTmFtZXNbbmFtZV0pIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB3YXJuZWRTdHlsZU5hbWVzW25hbWVdID0gdHJ1ZTtcbiAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gd2FybmluZyhcbiAgICAgIGZhbHNlLFxuICAgICAgJ1Vuc3VwcG9ydGVkIHN0eWxlIHByb3BlcnR5ICcgKyBuYW1lICsgJy4gRGlkIHlvdSBtZWFuICcgK1xuICAgICAgY2FtZWxpemVTdHlsZU5hbWUobmFtZSkgKyAnPydcbiAgICApIDogbnVsbCk7XG4gIH07XG59XG5cbi8qKlxuICogT3BlcmF0aW9ucyBmb3IgZGVhbGluZyB3aXRoIENTUyBwcm9wZXJ0aWVzLlxuICovXG52YXIgQ1NTUHJvcGVydHlPcGVyYXRpb25zID0ge1xuXG4gIC8qKlxuICAgKiBTZXJpYWxpemVzIGEgbWFwcGluZyBvZiBzdHlsZSBwcm9wZXJ0aWVzIGZvciB1c2UgYXMgaW5saW5lIHN0eWxlczpcbiAgICpcbiAgICogICA+IGNyZWF0ZU1hcmt1cEZvclN0eWxlcyh7d2lkdGg6ICcyMDBweCcsIGhlaWdodDogMH0pXG4gICAqICAgXCJ3aWR0aDoyMDBweDtoZWlnaHQ6MDtcIlxuICAgKlxuICAgKiBVbmRlZmluZWQgdmFsdWVzIGFyZSBpZ25vcmVkIHNvIHRoYXQgZGVjbGFyYXRpdmUgcHJvZ3JhbW1pbmcgaXMgZWFzaWVyLlxuICAgKiBUaGUgcmVzdWx0IHNob3VsZCBiZSBIVE1MLWVzY2FwZWQgYmVmb3JlIGluc2VydGlvbiBpbnRvIHRoZSBET00uXG4gICAqXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBzdHlsZXNcbiAgICogQHJldHVybiB7P3N0cmluZ31cbiAgICovXG4gIGNyZWF0ZU1hcmt1cEZvclN0eWxlczogZnVuY3Rpb24oc3R5bGVzKSB7XG4gICAgdmFyIHNlcmlhbGl6ZWQgPSAnJztcbiAgICBmb3IgKHZhciBzdHlsZU5hbWUgaW4gc3R5bGVzKSB7XG4gICAgICBpZiAoIXN0eWxlcy5oYXNPd25Qcm9wZXJ0eShzdHlsZU5hbWUpKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgaWYgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOVikge1xuICAgICAgICBpZiAoc3R5bGVOYW1lLmluZGV4T2YoJy0nKSA+IC0xKSB7XG4gICAgICAgICAgd2Fybkh5cGhlbmF0ZWRTdHlsZU5hbWUoc3R5bGVOYW1lKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgdmFyIHN0eWxlVmFsdWUgPSBzdHlsZXNbc3R5bGVOYW1lXTtcbiAgICAgIGlmIChzdHlsZVZhbHVlICE9IG51bGwpIHtcbiAgICAgICAgc2VyaWFsaXplZCArPSBwcm9jZXNzU3R5bGVOYW1lKHN0eWxlTmFtZSkgKyAnOic7XG4gICAgICAgIHNlcmlhbGl6ZWQgKz0gZGFuZ2Vyb3VzU3R5bGVWYWx1ZShzdHlsZU5hbWUsIHN0eWxlVmFsdWUpICsgJzsnO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gc2VyaWFsaXplZCB8fCBudWxsO1xuICB9LFxuXG4gIC8qKlxuICAgKiBTZXRzIHRoZSB2YWx1ZSBmb3IgbXVsdGlwbGUgc3R5bGVzIG9uIGEgbm9kZS4gIElmIGEgdmFsdWUgaXMgc3BlY2lmaWVkIGFzXG4gICAqICcnIChlbXB0eSBzdHJpbmcpLCB0aGUgY29ycmVzcG9uZGluZyBzdHlsZSBwcm9wZXJ0eSB3aWxsIGJlIHVuc2V0LlxuICAgKlxuICAgKiBAcGFyYW0ge0RPTUVsZW1lbnR9IG5vZGVcbiAgICogQHBhcmFtIHtvYmplY3R9IHN0eWxlc1xuICAgKi9cbiAgc2V0VmFsdWVGb3JTdHlsZXM6IGZ1bmN0aW9uKG5vZGUsIHN0eWxlcykge1xuICAgIHZhciBzdHlsZSA9IG5vZGUuc3R5bGU7XG4gICAgZm9yICh2YXIgc3R5bGVOYW1lIGluIHN0eWxlcykge1xuICAgICAgaWYgKCFzdHlsZXMuaGFzT3duUHJvcGVydHkoc3R5bGVOYW1lKSkge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cbiAgICAgIGlmIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYpIHtcbiAgICAgICAgaWYgKHN0eWxlTmFtZS5pbmRleE9mKCctJykgPiAtMSkge1xuICAgICAgICAgIHdhcm5IeXBoZW5hdGVkU3R5bGVOYW1lKHN0eWxlTmFtZSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHZhciBzdHlsZVZhbHVlID0gZGFuZ2Vyb3VzU3R5bGVWYWx1ZShzdHlsZU5hbWUsIHN0eWxlc1tzdHlsZU5hbWVdKTtcbiAgICAgIGlmIChzdHlsZU5hbWUgPT09ICdmbG9hdCcpIHtcbiAgICAgICAgc3R5bGVOYW1lID0gc3R5bGVGbG9hdEFjY2Vzc29yO1xuICAgICAgfVxuICAgICAgaWYgKHN0eWxlVmFsdWUpIHtcbiAgICAgICAgc3R5bGVbc3R5bGVOYW1lXSA9IHN0eWxlVmFsdWU7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB2YXIgZXhwYW5zaW9uID0gQ1NTUHJvcGVydHkuc2hvcnRoYW5kUHJvcGVydHlFeHBhbnNpb25zW3N0eWxlTmFtZV07XG4gICAgICAgIGlmIChleHBhbnNpb24pIHtcbiAgICAgICAgICAvLyBTaG9ydGhhbmQgcHJvcGVydHkgdGhhdCBJRTggd29uJ3QgbGlrZSB1bnNldHRpbmcsIHNvIHVuc2V0IGVhY2hcbiAgICAgICAgICAvLyBjb21wb25lbnQgdG8gcGxhY2F0ZSBpdFxuICAgICAgICAgIGZvciAodmFyIGluZGl2aWR1YWxTdHlsZU5hbWUgaW4gZXhwYW5zaW9uKSB7XG4gICAgICAgICAgICBzdHlsZVtpbmRpdmlkdWFsU3R5bGVOYW1lXSA9ICcnO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBzdHlsZVtzdHlsZU5hbWVdID0gJyc7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cblxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBDU1NQcm9wZXJ0eU9wZXJhdGlvbnM7XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKCdfcHJvY2VzcycpKSIsIihmdW5jdGlvbiAocHJvY2Vzcyl7XG4vKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgQ2FsbGJhY2tRdWV1ZVxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgUG9vbGVkQ2xhc3MgPSByZXF1aXJlKFwiLi9Qb29sZWRDbGFzc1wiKTtcblxudmFyIGFzc2lnbiA9IHJlcXVpcmUoXCIuL09iamVjdC5hc3NpZ25cIik7XG52YXIgaW52YXJpYW50ID0gcmVxdWlyZShcIi4vaW52YXJpYW50XCIpO1xuXG4vKipcbiAqIEEgc3BlY2lhbGl6ZWQgcHNldWRvLWV2ZW50IG1vZHVsZSB0byBoZWxwIGtlZXAgdHJhY2sgb2YgY29tcG9uZW50cyB3YWl0aW5nIHRvXG4gKiBiZSBub3RpZmllZCB3aGVuIHRoZWlyIERPTSByZXByZXNlbnRhdGlvbnMgYXJlIGF2YWlsYWJsZSBmb3IgdXNlLlxuICpcbiAqIFRoaXMgaW1wbGVtZW50cyBgUG9vbGVkQ2xhc3NgLCBzbyB5b3Ugc2hvdWxkIG5ldmVyIG5lZWQgdG8gaW5zdGFudGlhdGUgdGhpcy5cbiAqIEluc3RlYWQsIHVzZSBgQ2FsbGJhY2tRdWV1ZS5nZXRQb29sZWQoKWAuXG4gKlxuICogQGNsYXNzIFJlYWN0TW91bnRSZWFkeVxuICogQGltcGxlbWVudHMgUG9vbGVkQ2xhc3NcbiAqIEBpbnRlcm5hbFxuICovXG5mdW5jdGlvbiBDYWxsYmFja1F1ZXVlKCkge1xuICB0aGlzLl9jYWxsYmFja3MgPSBudWxsO1xuICB0aGlzLl9jb250ZXh0cyA9IG51bGw7XG59XG5cbmFzc2lnbihDYWxsYmFja1F1ZXVlLnByb3RvdHlwZSwge1xuXG4gIC8qKlxuICAgKiBFbnF1ZXVlcyBhIGNhbGxiYWNrIHRvIGJlIGludm9rZWQgd2hlbiBgbm90aWZ5QWxsYCBpcyBpbnZva2VkLlxuICAgKlxuICAgKiBAcGFyYW0ge2Z1bmN0aW9ufSBjYWxsYmFjayBJbnZva2VkIHdoZW4gYG5vdGlmeUFsbGAgaXMgaW52b2tlZC5cbiAgICogQHBhcmFtIHs/b2JqZWN0fSBjb250ZXh0IENvbnRleHQgdG8gY2FsbCBgY2FsbGJhY2tgIHdpdGguXG4gICAqIEBpbnRlcm5hbFxuICAgKi9cbiAgZW5xdWV1ZTogZnVuY3Rpb24oY2FsbGJhY2ssIGNvbnRleHQpIHtcbiAgICB0aGlzLl9jYWxsYmFja3MgPSB0aGlzLl9jYWxsYmFja3MgfHwgW107XG4gICAgdGhpcy5fY29udGV4dHMgPSB0aGlzLl9jb250ZXh0cyB8fCBbXTtcbiAgICB0aGlzLl9jYWxsYmFja3MucHVzaChjYWxsYmFjayk7XG4gICAgdGhpcy5fY29udGV4dHMucHVzaChjb250ZXh0KTtcbiAgfSxcblxuICAvKipcbiAgICogSW52b2tlcyBhbGwgZW5xdWV1ZWQgY2FsbGJhY2tzIGFuZCBjbGVhcnMgdGhlIHF1ZXVlLiBUaGlzIGlzIGludm9rZWQgYWZ0ZXJcbiAgICogdGhlIERPTSByZXByZXNlbnRhdGlvbiBvZiBhIGNvbXBvbmVudCBoYXMgYmVlbiBjcmVhdGVkIG9yIHVwZGF0ZWQuXG4gICAqXG4gICAqIEBpbnRlcm5hbFxuICAgKi9cbiAgbm90aWZ5QWxsOiBmdW5jdGlvbigpIHtcbiAgICB2YXIgY2FsbGJhY2tzID0gdGhpcy5fY2FsbGJhY2tzO1xuICAgIHZhciBjb250ZXh0cyA9IHRoaXMuX2NvbnRleHRzO1xuICAgIGlmIChjYWxsYmFja3MpIHtcbiAgICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICAgIGNhbGxiYWNrcy5sZW5ndGggPT09IGNvbnRleHRzLmxlbmd0aCxcbiAgICAgICAgXCJNaXNtYXRjaGVkIGxpc3Qgb2YgY29udGV4dHMgaW4gY2FsbGJhY2sgcXVldWVcIlxuICAgICAgKSA6IGludmFyaWFudChjYWxsYmFja3MubGVuZ3RoID09PSBjb250ZXh0cy5sZW5ndGgpKTtcbiAgICAgIHRoaXMuX2NhbGxiYWNrcyA9IG51bGw7XG4gICAgICB0aGlzLl9jb250ZXh0cyA9IG51bGw7XG4gICAgICBmb3IgKHZhciBpID0gMCwgbCA9IGNhbGxiYWNrcy5sZW5ndGg7IGkgPCBsOyBpKyspIHtcbiAgICAgICAgY2FsbGJhY2tzW2ldLmNhbGwoY29udGV4dHNbaV0pO1xuICAgICAgfVxuICAgICAgY2FsbGJhY2tzLmxlbmd0aCA9IDA7XG4gICAgICBjb250ZXh0cy5sZW5ndGggPSAwO1xuICAgIH1cbiAgfSxcblxuICAvKipcbiAgICogUmVzZXRzIHRoZSBpbnRlcm5hbCBxdWV1ZS5cbiAgICpcbiAgICogQGludGVybmFsXG4gICAqL1xuICByZXNldDogZnVuY3Rpb24oKSB7XG4gICAgdGhpcy5fY2FsbGJhY2tzID0gbnVsbDtcbiAgICB0aGlzLl9jb250ZXh0cyA9IG51bGw7XG4gIH0sXG5cbiAgLyoqXG4gICAqIGBQb29sZWRDbGFzc2AgbG9va3MgZm9yIHRoaXMuXG4gICAqL1xuICBkZXN0cnVjdG9yOiBmdW5jdGlvbigpIHtcbiAgICB0aGlzLnJlc2V0KCk7XG4gIH1cblxufSk7XG5cblBvb2xlZENsYXNzLmFkZFBvb2xpbmdUbyhDYWxsYmFja1F1ZXVlKTtcblxubW9kdWxlLmV4cG9ydHMgPSBDYWxsYmFja1F1ZXVlO1xuXG59KS5jYWxsKHRoaXMscmVxdWlyZSgnX3Byb2Nlc3MnKSkiLCIvKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgQ2hhbmdlRXZlbnRQbHVnaW5cbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIEV2ZW50Q29uc3RhbnRzID0gcmVxdWlyZShcIi4vRXZlbnRDb25zdGFudHNcIik7XG52YXIgRXZlbnRQbHVnaW5IdWIgPSByZXF1aXJlKFwiLi9FdmVudFBsdWdpbkh1YlwiKTtcbnZhciBFdmVudFByb3BhZ2F0b3JzID0gcmVxdWlyZShcIi4vRXZlbnRQcm9wYWdhdG9yc1wiKTtcbnZhciBFeGVjdXRpb25FbnZpcm9ubWVudCA9IHJlcXVpcmUoXCIuL0V4ZWN1dGlvbkVudmlyb25tZW50XCIpO1xudmFyIFJlYWN0VXBkYXRlcyA9IHJlcXVpcmUoXCIuL1JlYWN0VXBkYXRlc1wiKTtcbnZhciBTeW50aGV0aWNFdmVudCA9IHJlcXVpcmUoXCIuL1N5bnRoZXRpY0V2ZW50XCIpO1xuXG52YXIgaXNFdmVudFN1cHBvcnRlZCA9IHJlcXVpcmUoXCIuL2lzRXZlbnRTdXBwb3J0ZWRcIik7XG52YXIgaXNUZXh0SW5wdXRFbGVtZW50ID0gcmVxdWlyZShcIi4vaXNUZXh0SW5wdXRFbGVtZW50XCIpO1xudmFyIGtleU9mID0gcmVxdWlyZShcIi4va2V5T2ZcIik7XG5cbnZhciB0b3BMZXZlbFR5cGVzID0gRXZlbnRDb25zdGFudHMudG9wTGV2ZWxUeXBlcztcblxudmFyIGV2ZW50VHlwZXMgPSB7XG4gIGNoYW5nZToge1xuICAgIHBoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzOiB7XG4gICAgICBidWJibGVkOiBrZXlPZih7b25DaGFuZ2U6IG51bGx9KSxcbiAgICAgIGNhcHR1cmVkOiBrZXlPZih7b25DaGFuZ2VDYXB0dXJlOiBudWxsfSlcbiAgICB9LFxuICAgIGRlcGVuZGVuY2llczogW1xuICAgICAgdG9wTGV2ZWxUeXBlcy50b3BCbHVyLFxuICAgICAgdG9wTGV2ZWxUeXBlcy50b3BDaGFuZ2UsXG4gICAgICB0b3BMZXZlbFR5cGVzLnRvcENsaWNrLFxuICAgICAgdG9wTGV2ZWxUeXBlcy50b3BGb2N1cyxcbiAgICAgIHRvcExldmVsVHlwZXMudG9wSW5wdXQsXG4gICAgICB0b3BMZXZlbFR5cGVzLnRvcEtleURvd24sXG4gICAgICB0b3BMZXZlbFR5cGVzLnRvcEtleVVwLFxuICAgICAgdG9wTGV2ZWxUeXBlcy50b3BTZWxlY3Rpb25DaGFuZ2VcbiAgICBdXG4gIH1cbn07XG5cbi8qKlxuICogRm9yIElFIHNoaW1zXG4gKi9cbnZhciBhY3RpdmVFbGVtZW50ID0gbnVsbDtcbnZhciBhY3RpdmVFbGVtZW50SUQgPSBudWxsO1xudmFyIGFjdGl2ZUVsZW1lbnRWYWx1ZSA9IG51bGw7XG52YXIgYWN0aXZlRWxlbWVudFZhbHVlUHJvcCA9IG51bGw7XG5cbi8qKlxuICogU0VDVElPTjogaGFuZGxlIGBjaGFuZ2VgIGV2ZW50XG4gKi9cbmZ1bmN0aW9uIHNob3VsZFVzZUNoYW5nZUV2ZW50KGVsZW0pIHtcbiAgcmV0dXJuIChcbiAgICBlbGVtLm5vZGVOYW1lID09PSAnU0VMRUNUJyB8fFxuICAgIChlbGVtLm5vZGVOYW1lID09PSAnSU5QVVQnICYmIGVsZW0udHlwZSA9PT0gJ2ZpbGUnKVxuICApO1xufVxuXG52YXIgZG9lc0NoYW5nZUV2ZW50QnViYmxlID0gZmFsc2U7XG5pZiAoRXhlY3V0aW9uRW52aXJvbm1lbnQuY2FuVXNlRE9NKSB7XG4gIC8vIFNlZSBgaGFuZGxlQ2hhbmdlYCBjb21tZW50IGJlbG93XG4gIGRvZXNDaGFuZ2VFdmVudEJ1YmJsZSA9IGlzRXZlbnRTdXBwb3J0ZWQoJ2NoYW5nZScpICYmIChcbiAgICAhKCdkb2N1bWVudE1vZGUnIGluIGRvY3VtZW50KSB8fCBkb2N1bWVudC5kb2N1bWVudE1vZGUgPiA4XG4gICk7XG59XG5cbmZ1bmN0aW9uIG1hbnVhbERpc3BhdGNoQ2hhbmdlRXZlbnQobmF0aXZlRXZlbnQpIHtcbiAgdmFyIGV2ZW50ID0gU3ludGhldGljRXZlbnQuZ2V0UG9vbGVkKFxuICAgIGV2ZW50VHlwZXMuY2hhbmdlLFxuICAgIGFjdGl2ZUVsZW1lbnRJRCxcbiAgICBuYXRpdmVFdmVudFxuICApO1xuICBFdmVudFByb3BhZ2F0b3JzLmFjY3VtdWxhdGVUd29QaGFzZURpc3BhdGNoZXMoZXZlbnQpO1xuXG4gIC8vIElmIGNoYW5nZSBhbmQgcHJvcGVydHljaGFuZ2UgYnViYmxlZCwgd2UnZCBqdXN0IGJpbmQgdG8gaXQgbGlrZSBhbGwgdGhlXG4gIC8vIG90aGVyIGV2ZW50cyBhbmQgaGF2ZSBpdCBnbyB0aHJvdWdoIFJlYWN0QnJvd3NlckV2ZW50RW1pdHRlci4gU2luY2UgaXRcbiAgLy8gZG9lc24ndCwgd2UgbWFudWFsbHkgbGlzdGVuIGZvciB0aGUgZXZlbnRzIGFuZCBzbyB3ZSBoYXZlIHRvIGVucXVldWUgYW5kXG4gIC8vIHByb2Nlc3MgdGhlIGFic3RyYWN0IGV2ZW50IG1hbnVhbGx5LlxuICAvL1xuICAvLyBCYXRjaGluZyBpcyBuZWNlc3NhcnkgaGVyZSBpbiBvcmRlciB0byBlbnN1cmUgdGhhdCBhbGwgZXZlbnQgaGFuZGxlcnMgcnVuXG4gIC8vIGJlZm9yZSB0aGUgbmV4dCByZXJlbmRlciAoaW5jbHVkaW5nIGV2ZW50IGhhbmRsZXJzIGF0dGFjaGVkIHRvIGFuY2VzdG9yXG4gIC8vIGVsZW1lbnRzIGluc3RlYWQgb2YgZGlyZWN0bHkgb24gdGhlIGlucHV0KS4gV2l0aG91dCB0aGlzLCBjb250cm9sbGVkXG4gIC8vIGNvbXBvbmVudHMgZG9uJ3Qgd29yayBwcm9wZXJseSBpbiBjb25qdW5jdGlvbiB3aXRoIGV2ZW50IGJ1YmJsaW5nIGJlY2F1c2VcbiAgLy8gdGhlIGNvbXBvbmVudCBpcyByZXJlbmRlcmVkIGFuZCB0aGUgdmFsdWUgcmV2ZXJ0ZWQgYmVmb3JlIGFsbCB0aGUgZXZlbnRcbiAgLy8gaGFuZGxlcnMgY2FuIHJ1bi4gU2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9mYWNlYm9vay9yZWFjdC9pc3N1ZXMvNzA4LlxuICBSZWFjdFVwZGF0ZXMuYmF0Y2hlZFVwZGF0ZXMocnVuRXZlbnRJbkJhdGNoLCBldmVudCk7XG59XG5cbmZ1bmN0aW9uIHJ1bkV2ZW50SW5CYXRjaChldmVudCkge1xuICBFdmVudFBsdWdpbkh1Yi5lbnF1ZXVlRXZlbnRzKGV2ZW50KTtcbiAgRXZlbnRQbHVnaW5IdWIucHJvY2Vzc0V2ZW50UXVldWUoKTtcbn1cblxuZnVuY3Rpb24gc3RhcnRXYXRjaGluZ0ZvckNoYW5nZUV2ZW50SUU4KHRhcmdldCwgdGFyZ2V0SUQpIHtcbiAgYWN0aXZlRWxlbWVudCA9IHRhcmdldDtcbiAgYWN0aXZlRWxlbWVudElEID0gdGFyZ2V0SUQ7XG4gIGFjdGl2ZUVsZW1lbnQuYXR0YWNoRXZlbnQoJ29uY2hhbmdlJywgbWFudWFsRGlzcGF0Y2hDaGFuZ2VFdmVudCk7XG59XG5cbmZ1bmN0aW9uIHN0b3BXYXRjaGluZ0ZvckNoYW5nZUV2ZW50SUU4KCkge1xuICBpZiAoIWFjdGl2ZUVsZW1lbnQpIHtcbiAgICByZXR1cm47XG4gIH1cbiAgYWN0aXZlRWxlbWVudC5kZXRhY2hFdmVudCgnb25jaGFuZ2UnLCBtYW51YWxEaXNwYXRjaENoYW5nZUV2ZW50KTtcbiAgYWN0aXZlRWxlbWVudCA9IG51bGw7XG4gIGFjdGl2ZUVsZW1lbnRJRCA9IG51bGw7XG59XG5cbmZ1bmN0aW9uIGdldFRhcmdldElERm9yQ2hhbmdlRXZlbnQoXG4gICAgdG9wTGV2ZWxUeXBlLFxuICAgIHRvcExldmVsVGFyZ2V0LFxuICAgIHRvcExldmVsVGFyZ2V0SUQpIHtcbiAgaWYgKHRvcExldmVsVHlwZSA9PT0gdG9wTGV2ZWxUeXBlcy50b3BDaGFuZ2UpIHtcbiAgICByZXR1cm4gdG9wTGV2ZWxUYXJnZXRJRDtcbiAgfVxufVxuZnVuY3Rpb24gaGFuZGxlRXZlbnRzRm9yQ2hhbmdlRXZlbnRJRTgoXG4gICAgdG9wTGV2ZWxUeXBlLFxuICAgIHRvcExldmVsVGFyZ2V0LFxuICAgIHRvcExldmVsVGFyZ2V0SUQpIHtcbiAgaWYgKHRvcExldmVsVHlwZSA9PT0gdG9wTGV2ZWxUeXBlcy50b3BGb2N1cykge1xuICAgIC8vIHN0b3BXYXRjaGluZygpIHNob3VsZCBiZSBhIG5vb3AgaGVyZSBidXQgd2UgY2FsbCBpdCBqdXN0IGluIGNhc2Ugd2VcbiAgICAvLyBtaXNzZWQgYSBibHVyIGV2ZW50IHNvbWVob3cuXG4gICAgc3RvcFdhdGNoaW5nRm9yQ2hhbmdlRXZlbnRJRTgoKTtcbiAgICBzdGFydFdhdGNoaW5nRm9yQ2hhbmdlRXZlbnRJRTgodG9wTGV2ZWxUYXJnZXQsIHRvcExldmVsVGFyZ2V0SUQpO1xuICB9IGVsc2UgaWYgKHRvcExldmVsVHlwZSA9PT0gdG9wTGV2ZWxUeXBlcy50b3BCbHVyKSB7XG4gICAgc3RvcFdhdGNoaW5nRm9yQ2hhbmdlRXZlbnRJRTgoKTtcbiAgfVxufVxuXG5cbi8qKlxuICogU0VDVElPTjogaGFuZGxlIGBpbnB1dGAgZXZlbnRcbiAqL1xudmFyIGlzSW5wdXRFdmVudFN1cHBvcnRlZCA9IGZhbHNlO1xuaWYgKEV4ZWN1dGlvbkVudmlyb25tZW50LmNhblVzZURPTSkge1xuICAvLyBJRTkgY2xhaW1zIHRvIHN1cHBvcnQgdGhlIGlucHV0IGV2ZW50IGJ1dCBmYWlscyB0byB0cmlnZ2VyIGl0IHdoZW5cbiAgLy8gZGVsZXRpbmcgdGV4dCwgc28gd2UgaWdub3JlIGl0cyBpbnB1dCBldmVudHNcbiAgaXNJbnB1dEV2ZW50U3VwcG9ydGVkID0gaXNFdmVudFN1cHBvcnRlZCgnaW5wdXQnKSAmJiAoXG4gICAgISgnZG9jdW1lbnRNb2RlJyBpbiBkb2N1bWVudCkgfHwgZG9jdW1lbnQuZG9jdW1lbnRNb2RlID4gOVxuICApO1xufVxuXG4vKipcbiAqIChGb3Igb2xkIElFLikgUmVwbGFjZW1lbnQgZ2V0dGVyL3NldHRlciBmb3IgdGhlIGB2YWx1ZWAgcHJvcGVydHkgdGhhdCBnZXRzXG4gKiBzZXQgb24gdGhlIGFjdGl2ZSBlbGVtZW50LlxuICovXG52YXIgbmV3VmFsdWVQcm9wID0gIHtcbiAgZ2V0OiBmdW5jdGlvbigpIHtcbiAgICByZXR1cm4gYWN0aXZlRWxlbWVudFZhbHVlUHJvcC5nZXQuY2FsbCh0aGlzKTtcbiAgfSxcbiAgc2V0OiBmdW5jdGlvbih2YWwpIHtcbiAgICAvLyBDYXN0IHRvIGEgc3RyaW5nIHNvIHdlIGNhbiBkbyBlcXVhbGl0eSBjaGVja3MuXG4gICAgYWN0aXZlRWxlbWVudFZhbHVlID0gJycgKyB2YWw7XG4gICAgYWN0aXZlRWxlbWVudFZhbHVlUHJvcC5zZXQuY2FsbCh0aGlzLCB2YWwpO1xuICB9XG59O1xuXG4vKipcbiAqIChGb3Igb2xkIElFLikgU3RhcnRzIHRyYWNraW5nIHByb3BlcnR5Y2hhbmdlIGV2ZW50cyBvbiB0aGUgcGFzc2VkLWluIGVsZW1lbnRcbiAqIGFuZCBvdmVycmlkZSB0aGUgdmFsdWUgcHJvcGVydHkgc28gdGhhdCB3ZSBjYW4gZGlzdGluZ3Vpc2ggdXNlciBldmVudHMgZnJvbVxuICogdmFsdWUgY2hhbmdlcyBpbiBKUy5cbiAqL1xuZnVuY3Rpb24gc3RhcnRXYXRjaGluZ0ZvclZhbHVlQ2hhbmdlKHRhcmdldCwgdGFyZ2V0SUQpIHtcbiAgYWN0aXZlRWxlbWVudCA9IHRhcmdldDtcbiAgYWN0aXZlRWxlbWVudElEID0gdGFyZ2V0SUQ7XG4gIGFjdGl2ZUVsZW1lbnRWYWx1ZSA9IHRhcmdldC52YWx1ZTtcbiAgYWN0aXZlRWxlbWVudFZhbHVlUHJvcCA9IE9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IoXG4gICAgdGFyZ2V0LmNvbnN0cnVjdG9yLnByb3RvdHlwZSxcbiAgICAndmFsdWUnXG4gICk7XG5cbiAgT2JqZWN0LmRlZmluZVByb3BlcnR5KGFjdGl2ZUVsZW1lbnQsICd2YWx1ZScsIG5ld1ZhbHVlUHJvcCk7XG4gIGFjdGl2ZUVsZW1lbnQuYXR0YWNoRXZlbnQoJ29ucHJvcGVydHljaGFuZ2UnLCBoYW5kbGVQcm9wZXJ0eUNoYW5nZSk7XG59XG5cbi8qKlxuICogKEZvciBvbGQgSUUuKSBSZW1vdmVzIHRoZSBldmVudCBsaXN0ZW5lcnMgZnJvbSB0aGUgY3VycmVudGx5LXRyYWNrZWQgZWxlbWVudCxcbiAqIGlmIGFueSBleGlzdHMuXG4gKi9cbmZ1bmN0aW9uIHN0b3BXYXRjaGluZ0ZvclZhbHVlQ2hhbmdlKCkge1xuICBpZiAoIWFjdGl2ZUVsZW1lbnQpIHtcbiAgICByZXR1cm47XG4gIH1cblxuICAvLyBkZWxldGUgcmVzdG9yZXMgdGhlIG9yaWdpbmFsIHByb3BlcnR5IGRlZmluaXRpb25cbiAgZGVsZXRlIGFjdGl2ZUVsZW1lbnQudmFsdWU7XG4gIGFjdGl2ZUVsZW1lbnQuZGV0YWNoRXZlbnQoJ29ucHJvcGVydHljaGFuZ2UnLCBoYW5kbGVQcm9wZXJ0eUNoYW5nZSk7XG5cbiAgYWN0aXZlRWxlbWVudCA9IG51bGw7XG4gIGFjdGl2ZUVsZW1lbnRJRCA9IG51bGw7XG4gIGFjdGl2ZUVsZW1lbnRWYWx1ZSA9IG51bGw7XG4gIGFjdGl2ZUVsZW1lbnRWYWx1ZVByb3AgPSBudWxsO1xufVxuXG4vKipcbiAqIChGb3Igb2xkIElFLikgSGFuZGxlcyBhIHByb3BlcnR5Y2hhbmdlIGV2ZW50LCBzZW5kaW5nIGEgYGNoYW5nZWAgZXZlbnQgaWZcbiAqIHRoZSB2YWx1ZSBvZiB0aGUgYWN0aXZlIGVsZW1lbnQgaGFzIGNoYW5nZWQuXG4gKi9cbmZ1bmN0aW9uIGhhbmRsZVByb3BlcnR5Q2hhbmdlKG5hdGl2ZUV2ZW50KSB7XG4gIGlmIChuYXRpdmVFdmVudC5wcm9wZXJ0eU5hbWUgIT09ICd2YWx1ZScpIHtcbiAgICByZXR1cm47XG4gIH1cbiAgdmFyIHZhbHVlID0gbmF0aXZlRXZlbnQuc3JjRWxlbWVudC52YWx1ZTtcbiAgaWYgKHZhbHVlID09PSBhY3RpdmVFbGVtZW50VmFsdWUpIHtcbiAgICByZXR1cm47XG4gIH1cbiAgYWN0aXZlRWxlbWVudFZhbHVlID0gdmFsdWU7XG5cbiAgbWFudWFsRGlzcGF0Y2hDaGFuZ2VFdmVudChuYXRpdmVFdmVudCk7XG59XG5cbi8qKlxuICogSWYgYSBgY2hhbmdlYCBldmVudCBzaG91bGQgYmUgZmlyZWQsIHJldHVybnMgdGhlIHRhcmdldCdzIElELlxuICovXG5mdW5jdGlvbiBnZXRUYXJnZXRJREZvcklucHV0RXZlbnQoXG4gICAgdG9wTGV2ZWxUeXBlLFxuICAgIHRvcExldmVsVGFyZ2V0LFxuICAgIHRvcExldmVsVGFyZ2V0SUQpIHtcbiAgaWYgKHRvcExldmVsVHlwZSA9PT0gdG9wTGV2ZWxUeXBlcy50b3BJbnB1dCkge1xuICAgIC8vIEluIG1vZGVybiBicm93c2VycyAoaS5lLiwgbm90IElFOCBvciBJRTkpLCB0aGUgaW5wdXQgZXZlbnQgaXMgZXhhY3RseVxuICAgIC8vIHdoYXQgd2Ugd2FudCBzbyBmYWxsIHRocm91Z2ggaGVyZSBhbmQgdHJpZ2dlciBhbiBhYnN0cmFjdCBldmVudFxuICAgIHJldHVybiB0b3BMZXZlbFRhcmdldElEO1xuICB9XG59XG5cbi8vIEZvciBJRTggYW5kIElFOS5cbmZ1bmN0aW9uIGhhbmRsZUV2ZW50c0ZvcklucHV0RXZlbnRJRShcbiAgICB0b3BMZXZlbFR5cGUsXG4gICAgdG9wTGV2ZWxUYXJnZXQsXG4gICAgdG9wTGV2ZWxUYXJnZXRJRCkge1xuICBpZiAodG9wTGV2ZWxUeXBlID09PSB0b3BMZXZlbFR5cGVzLnRvcEZvY3VzKSB7XG4gICAgLy8gSW4gSUU4LCB3ZSBjYW4gY2FwdHVyZSBhbG1vc3QgYWxsIC52YWx1ZSBjaGFuZ2VzIGJ5IGFkZGluZyBhXG4gICAgLy8gcHJvcGVydHljaGFuZ2UgaGFuZGxlciBhbmQgbG9va2luZyBmb3IgZXZlbnRzIHdpdGggcHJvcGVydHlOYW1lXG4gICAgLy8gZXF1YWwgdG8gJ3ZhbHVlJ1xuICAgIC8vIEluIElFOSwgcHJvcGVydHljaGFuZ2UgZmlyZXMgZm9yIG1vc3QgaW5wdXQgZXZlbnRzIGJ1dCBpcyBidWdneSBhbmRcbiAgICAvLyBkb2Vzbid0IGZpcmUgd2hlbiB0ZXh0IGlzIGRlbGV0ZWQsIGJ1dCBjb252ZW5pZW50bHksIHNlbGVjdGlvbmNoYW5nZVxuICAgIC8vIGFwcGVhcnMgdG8gZmlyZSBpbiBhbGwgb2YgdGhlIHJlbWFpbmluZyBjYXNlcyBzbyB3ZSBjYXRjaCB0aG9zZSBhbmRcbiAgICAvLyBmb3J3YXJkIHRoZSBldmVudCBpZiB0aGUgdmFsdWUgaGFzIGNoYW5nZWRcbiAgICAvLyBJbiBlaXRoZXIgY2FzZSwgd2UgZG9uJ3Qgd2FudCB0byBjYWxsIHRoZSBldmVudCBoYW5kbGVyIGlmIHRoZSB2YWx1ZVxuICAgIC8vIGlzIGNoYW5nZWQgZnJvbSBKUyBzbyB3ZSByZWRlZmluZSBhIHNldHRlciBmb3IgYC52YWx1ZWAgdGhhdCB1cGRhdGVzXG4gICAgLy8gb3VyIGFjdGl2ZUVsZW1lbnRWYWx1ZSB2YXJpYWJsZSwgYWxsb3dpbmcgdXMgdG8gaWdub3JlIHRob3NlIGNoYW5nZXNcbiAgICAvL1xuICAgIC8vIHN0b3BXYXRjaGluZygpIHNob3VsZCBiZSBhIG5vb3AgaGVyZSBidXQgd2UgY2FsbCBpdCBqdXN0IGluIGNhc2Ugd2VcbiAgICAvLyBtaXNzZWQgYSBibHVyIGV2ZW50IHNvbWVob3cuXG4gICAgc3RvcFdhdGNoaW5nRm9yVmFsdWVDaGFuZ2UoKTtcbiAgICBzdGFydFdhdGNoaW5nRm9yVmFsdWVDaGFuZ2UodG9wTGV2ZWxUYXJnZXQsIHRvcExldmVsVGFyZ2V0SUQpO1xuICB9IGVsc2UgaWYgKHRvcExldmVsVHlwZSA9PT0gdG9wTGV2ZWxUeXBlcy50b3BCbHVyKSB7XG4gICAgc3RvcFdhdGNoaW5nRm9yVmFsdWVDaGFuZ2UoKTtcbiAgfVxufVxuXG4vLyBGb3IgSUU4IGFuZCBJRTkuXG5mdW5jdGlvbiBnZXRUYXJnZXRJREZvcklucHV0RXZlbnRJRShcbiAgICB0b3BMZXZlbFR5cGUsXG4gICAgdG9wTGV2ZWxUYXJnZXQsXG4gICAgdG9wTGV2ZWxUYXJnZXRJRCkge1xuICBpZiAodG9wTGV2ZWxUeXBlID09PSB0b3BMZXZlbFR5cGVzLnRvcFNlbGVjdGlvbkNoYW5nZSB8fFxuICAgICAgdG9wTGV2ZWxUeXBlID09PSB0b3BMZXZlbFR5cGVzLnRvcEtleVVwIHx8XG4gICAgICB0b3BMZXZlbFR5cGUgPT09IHRvcExldmVsVHlwZXMudG9wS2V5RG93bikge1xuICAgIC8vIE9uIHRoZSBzZWxlY3Rpb25jaGFuZ2UgZXZlbnQsIHRoZSB0YXJnZXQgaXMganVzdCBkb2N1bWVudCB3aGljaCBpc24ndFxuICAgIC8vIGhlbHBmdWwgZm9yIHVzIHNvIGp1c3QgY2hlY2sgYWN0aXZlRWxlbWVudCBpbnN0ZWFkLlxuICAgIC8vXG4gICAgLy8gOTklIG9mIHRoZSB0aW1lLCBrZXlkb3duIGFuZCBrZXl1cCBhcmVuJ3QgbmVjZXNzYXJ5LiBJRTggZmFpbHMgdG8gZmlyZVxuICAgIC8vIHByb3BlcnR5Y2hhbmdlIG9uIHRoZSBmaXJzdCBpbnB1dCBldmVudCBhZnRlciBzZXR0aW5nIGB2YWx1ZWAgZnJvbSBhXG4gICAgLy8gc2NyaXB0IGFuZCBmaXJlcyBvbmx5IGtleWRvd24sIGtleXByZXNzLCBrZXl1cC4gQ2F0Y2hpbmcga2V5dXAgdXN1YWxseVxuICAgIC8vIGdldHMgaXQgYW5kIGNhdGNoaW5nIGtleWRvd24gbGV0cyB1cyBmaXJlIGFuIGV2ZW50IGZvciB0aGUgZmlyc3RcbiAgICAvLyBrZXlzdHJva2UgaWYgdXNlciBkb2VzIGEga2V5IHJlcGVhdCAoaXQnbGwgYmUgYSBsaXR0bGUgZGVsYXllZDogcmlnaHRcbiAgICAvLyBiZWZvcmUgdGhlIHNlY29uZCBrZXlzdHJva2UpLiBPdGhlciBpbnB1dCBtZXRob2RzIChlLmcuLCBwYXN0ZSkgc2VlbSB0b1xuICAgIC8vIGZpcmUgc2VsZWN0aW9uY2hhbmdlIG5vcm1hbGx5LlxuICAgIGlmIChhY3RpdmVFbGVtZW50ICYmIGFjdGl2ZUVsZW1lbnQudmFsdWUgIT09IGFjdGl2ZUVsZW1lbnRWYWx1ZSkge1xuICAgICAgYWN0aXZlRWxlbWVudFZhbHVlID0gYWN0aXZlRWxlbWVudC52YWx1ZTtcbiAgICAgIHJldHVybiBhY3RpdmVFbGVtZW50SUQ7XG4gICAgfVxuICB9XG59XG5cblxuLyoqXG4gKiBTRUNUSU9OOiBoYW5kbGUgYGNsaWNrYCBldmVudFxuICovXG5mdW5jdGlvbiBzaG91bGRVc2VDbGlja0V2ZW50KGVsZW0pIHtcbiAgLy8gVXNlIHRoZSBgY2xpY2tgIGV2ZW50IHRvIGRldGVjdCBjaGFuZ2VzIHRvIGNoZWNrYm94IGFuZCByYWRpbyBpbnB1dHMuXG4gIC8vIFRoaXMgYXBwcm9hY2ggd29ya3MgYWNyb3NzIGFsbCBicm93c2Vycywgd2hlcmVhcyBgY2hhbmdlYCBkb2VzIG5vdCBmaXJlXG4gIC8vIHVudGlsIGBibHVyYCBpbiBJRTguXG4gIHJldHVybiAoXG4gICAgZWxlbS5ub2RlTmFtZSA9PT0gJ0lOUFVUJyAmJlxuICAgIChlbGVtLnR5cGUgPT09ICdjaGVja2JveCcgfHwgZWxlbS50eXBlID09PSAncmFkaW8nKVxuICApO1xufVxuXG5mdW5jdGlvbiBnZXRUYXJnZXRJREZvckNsaWNrRXZlbnQoXG4gICAgdG9wTGV2ZWxUeXBlLFxuICAgIHRvcExldmVsVGFyZ2V0LFxuICAgIHRvcExldmVsVGFyZ2V0SUQpIHtcbiAgaWYgKHRvcExldmVsVHlwZSA9PT0gdG9wTGV2ZWxUeXBlcy50b3BDbGljaykge1xuICAgIHJldHVybiB0b3BMZXZlbFRhcmdldElEO1xuICB9XG59XG5cbi8qKlxuICogVGhpcyBwbHVnaW4gY3JlYXRlcyBhbiBgb25DaGFuZ2VgIGV2ZW50IHRoYXQgbm9ybWFsaXplcyBjaGFuZ2UgZXZlbnRzXG4gKiBhY3Jvc3MgZm9ybSBlbGVtZW50cy4gVGhpcyBldmVudCBmaXJlcyBhdCBhIHRpbWUgd2hlbiBpdCdzIHBvc3NpYmxlIHRvXG4gKiBjaGFuZ2UgdGhlIGVsZW1lbnQncyB2YWx1ZSB3aXRob3V0IHNlZWluZyBhIGZsaWNrZXIuXG4gKlxuICogU3VwcG9ydGVkIGVsZW1lbnRzIGFyZTpcbiAqIC0gaW5wdXQgKHNlZSBgaXNUZXh0SW5wdXRFbGVtZW50YClcbiAqIC0gdGV4dGFyZWFcbiAqIC0gc2VsZWN0XG4gKi9cbnZhciBDaGFuZ2VFdmVudFBsdWdpbiA9IHtcblxuICBldmVudFR5cGVzOiBldmVudFR5cGVzLFxuXG4gIC8qKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gdG9wTGV2ZWxUeXBlIFJlY29yZCBmcm9tIGBFdmVudENvbnN0YW50c2AuXG4gICAqIEBwYXJhbSB7RE9NRXZlbnRUYXJnZXR9IHRvcExldmVsVGFyZ2V0IFRoZSBsaXN0ZW5pbmcgY29tcG9uZW50IHJvb3Qgbm9kZS5cbiAgICogQHBhcmFtIHtzdHJpbmd9IHRvcExldmVsVGFyZ2V0SUQgSUQgb2YgYHRvcExldmVsVGFyZ2V0YC5cbiAgICogQHBhcmFtIHtvYmplY3R9IG5hdGl2ZUV2ZW50IE5hdGl2ZSBicm93c2VyIGV2ZW50LlxuICAgKiBAcmV0dXJuIHsqfSBBbiBhY2N1bXVsYXRpb24gb2Ygc3ludGhldGljIGV2ZW50cy5cbiAgICogQHNlZSB7RXZlbnRQbHVnaW5IdWIuZXh0cmFjdEV2ZW50c31cbiAgICovXG4gIGV4dHJhY3RFdmVudHM6IGZ1bmN0aW9uKFxuICAgICAgdG9wTGV2ZWxUeXBlLFxuICAgICAgdG9wTGV2ZWxUYXJnZXQsXG4gICAgICB0b3BMZXZlbFRhcmdldElELFxuICAgICAgbmF0aXZlRXZlbnQpIHtcblxuICAgIHZhciBnZXRUYXJnZXRJREZ1bmMsIGhhbmRsZUV2ZW50RnVuYztcbiAgICBpZiAoc2hvdWxkVXNlQ2hhbmdlRXZlbnQodG9wTGV2ZWxUYXJnZXQpKSB7XG4gICAgICBpZiAoZG9lc0NoYW5nZUV2ZW50QnViYmxlKSB7XG4gICAgICAgIGdldFRhcmdldElERnVuYyA9IGdldFRhcmdldElERm9yQ2hhbmdlRXZlbnQ7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBoYW5kbGVFdmVudEZ1bmMgPSBoYW5kbGVFdmVudHNGb3JDaGFuZ2VFdmVudElFODtcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKGlzVGV4dElucHV0RWxlbWVudCh0b3BMZXZlbFRhcmdldCkpIHtcbiAgICAgIGlmIChpc0lucHV0RXZlbnRTdXBwb3J0ZWQpIHtcbiAgICAgICAgZ2V0VGFyZ2V0SURGdW5jID0gZ2V0VGFyZ2V0SURGb3JJbnB1dEV2ZW50O1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZ2V0VGFyZ2V0SURGdW5jID0gZ2V0VGFyZ2V0SURGb3JJbnB1dEV2ZW50SUU7XG4gICAgICAgIGhhbmRsZUV2ZW50RnVuYyA9IGhhbmRsZUV2ZW50c0ZvcklucHV0RXZlbnRJRTtcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKHNob3VsZFVzZUNsaWNrRXZlbnQodG9wTGV2ZWxUYXJnZXQpKSB7XG4gICAgICBnZXRUYXJnZXRJREZ1bmMgPSBnZXRUYXJnZXRJREZvckNsaWNrRXZlbnQ7XG4gICAgfVxuXG4gICAgaWYgKGdldFRhcmdldElERnVuYykge1xuICAgICAgdmFyIHRhcmdldElEID0gZ2V0VGFyZ2V0SURGdW5jKFxuICAgICAgICB0b3BMZXZlbFR5cGUsXG4gICAgICAgIHRvcExldmVsVGFyZ2V0LFxuICAgICAgICB0b3BMZXZlbFRhcmdldElEXG4gICAgICApO1xuICAgICAgaWYgKHRhcmdldElEKSB7XG4gICAgICAgIHZhciBldmVudCA9IFN5bnRoZXRpY0V2ZW50LmdldFBvb2xlZChcbiAgICAgICAgICBldmVudFR5cGVzLmNoYW5nZSxcbiAgICAgICAgICB0YXJnZXRJRCxcbiAgICAgICAgICBuYXRpdmVFdmVudFxuICAgICAgICApO1xuICAgICAgICBFdmVudFByb3BhZ2F0b3JzLmFjY3VtdWxhdGVUd29QaGFzZURpc3BhdGNoZXMoZXZlbnQpO1xuICAgICAgICByZXR1cm4gZXZlbnQ7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKGhhbmRsZUV2ZW50RnVuYykge1xuICAgICAgaGFuZGxlRXZlbnRGdW5jKFxuICAgICAgICB0b3BMZXZlbFR5cGUsXG4gICAgICAgIHRvcExldmVsVGFyZ2V0LFxuICAgICAgICB0b3BMZXZlbFRhcmdldElEXG4gICAgICApO1xuICAgIH1cbiAgfVxuXG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IENoYW5nZUV2ZW50UGx1Z2luO1xuIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIENsaWVudFJlYWN0Um9vdEluZGV4XG4gKiBAdHlwZWNoZWNrc1xuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgbmV4dFJlYWN0Um9vdEluZGV4ID0gMDtcblxudmFyIENsaWVudFJlYWN0Um9vdEluZGV4ID0ge1xuICBjcmVhdGVSZWFjdFJvb3RJbmRleDogZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIG5leHRSZWFjdFJvb3RJbmRleCsrO1xuICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IENsaWVudFJlYWN0Um9vdEluZGV4O1xuIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIENvbXBvc2l0aW9uRXZlbnRQbHVnaW5cbiAqIEB0eXBlY2hlY2tzIHN0YXRpYy1vbmx5XG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBFdmVudENvbnN0YW50cyA9IHJlcXVpcmUoXCIuL0V2ZW50Q29uc3RhbnRzXCIpO1xudmFyIEV2ZW50UHJvcGFnYXRvcnMgPSByZXF1aXJlKFwiLi9FdmVudFByb3BhZ2F0b3JzXCIpO1xudmFyIEV4ZWN1dGlvbkVudmlyb25tZW50ID0gcmVxdWlyZShcIi4vRXhlY3V0aW9uRW52aXJvbm1lbnRcIik7XG52YXIgUmVhY3RJbnB1dFNlbGVjdGlvbiA9IHJlcXVpcmUoXCIuL1JlYWN0SW5wdXRTZWxlY3Rpb25cIik7XG52YXIgU3ludGhldGljQ29tcG9zaXRpb25FdmVudCA9IHJlcXVpcmUoXCIuL1N5bnRoZXRpY0NvbXBvc2l0aW9uRXZlbnRcIik7XG5cbnZhciBnZXRUZXh0Q29udGVudEFjY2Vzc29yID0gcmVxdWlyZShcIi4vZ2V0VGV4dENvbnRlbnRBY2Nlc3NvclwiKTtcbnZhciBrZXlPZiA9IHJlcXVpcmUoXCIuL2tleU9mXCIpO1xuXG52YXIgRU5EX0tFWUNPREVTID0gWzksIDEzLCAyNywgMzJdOyAvLyBUYWIsIFJldHVybiwgRXNjLCBTcGFjZVxudmFyIFNUQVJUX0tFWUNPREUgPSAyMjk7XG5cbnZhciB1c2VDb21wb3NpdGlvbkV2ZW50ID0gKFxuICBFeGVjdXRpb25FbnZpcm9ubWVudC5jYW5Vc2VET00gJiZcbiAgJ0NvbXBvc2l0aW9uRXZlbnQnIGluIHdpbmRvd1xuKTtcblxuLy8gSW4gSUU5Kywgd2UgaGF2ZSBhY2Nlc3MgdG8gY29tcG9zaXRpb24gZXZlbnRzLCBidXQgdGhlIGRhdGEgc3VwcGxpZWRcbi8vIGJ5IHRoZSBuYXRpdmUgY29tcG9zaXRpb25lbmQgZXZlbnQgbWF5IGJlIGluY29ycmVjdC4gSW4gS29yZWFuLCBmb3IgZXhhbXBsZSxcbi8vIHRoZSBjb21wb3NpdGlvbmVuZCBldmVudCBjb250YWlucyBvbmx5IG9uZSBjaGFyYWN0ZXIgcmVnYXJkbGVzcyBvZlxuLy8gaG93IG1hbnkgY2hhcmFjdGVycyBoYXZlIGJlZW4gY29tcG9zZWQgc2luY2UgY29tcG9zaXRpb25zdGFydC5cbi8vIFdlIHRoZXJlZm9yZSB1c2UgdGhlIGZhbGxiYWNrIGRhdGEgd2hpbGUgc3RpbGwgdXNpbmcgdGhlIG5hdGl2ZVxuLy8gZXZlbnRzIGFzIHRyaWdnZXJzLlxudmFyIHVzZUZhbGxiYWNrRGF0YSA9IChcbiAgIXVzZUNvbXBvc2l0aW9uRXZlbnQgfHxcbiAgKFxuICAgICdkb2N1bWVudE1vZGUnIGluIGRvY3VtZW50ICYmXG4gICAgZG9jdW1lbnQuZG9jdW1lbnRNb2RlID4gOCAmJlxuICAgIGRvY3VtZW50LmRvY3VtZW50TW9kZSA8PSAxMVxuICApXG4pO1xuXG52YXIgdG9wTGV2ZWxUeXBlcyA9IEV2ZW50Q29uc3RhbnRzLnRvcExldmVsVHlwZXM7XG52YXIgY3VycmVudENvbXBvc2l0aW9uID0gbnVsbDtcblxuLy8gRXZlbnRzIGFuZCB0aGVpciBjb3JyZXNwb25kaW5nIHByb3BlcnR5IG5hbWVzLlxudmFyIGV2ZW50VHlwZXMgPSB7XG4gIGNvbXBvc2l0aW9uRW5kOiB7XG4gICAgcGhhc2VkUmVnaXN0cmF0aW9uTmFtZXM6IHtcbiAgICAgIGJ1YmJsZWQ6IGtleU9mKHtvbkNvbXBvc2l0aW9uRW5kOiBudWxsfSksXG4gICAgICBjYXB0dXJlZDoga2V5T2Yoe29uQ29tcG9zaXRpb25FbmRDYXB0dXJlOiBudWxsfSlcbiAgICB9LFxuICAgIGRlcGVuZGVuY2llczogW1xuICAgICAgdG9wTGV2ZWxUeXBlcy50b3BCbHVyLFxuICAgICAgdG9wTGV2ZWxUeXBlcy50b3BDb21wb3NpdGlvbkVuZCxcbiAgICAgIHRvcExldmVsVHlwZXMudG9wS2V5RG93bixcbiAgICAgIHRvcExldmVsVHlwZXMudG9wS2V5UHJlc3MsXG4gICAgICB0b3BMZXZlbFR5cGVzLnRvcEtleVVwLFxuICAgICAgdG9wTGV2ZWxUeXBlcy50b3BNb3VzZURvd25cbiAgICBdXG4gIH0sXG4gIGNvbXBvc2l0aW9uU3RhcnQ6IHtcbiAgICBwaGFzZWRSZWdpc3RyYXRpb25OYW1lczoge1xuICAgICAgYnViYmxlZDoga2V5T2Yoe29uQ29tcG9zaXRpb25TdGFydDogbnVsbH0pLFxuICAgICAgY2FwdHVyZWQ6IGtleU9mKHtvbkNvbXBvc2l0aW9uU3RhcnRDYXB0dXJlOiBudWxsfSlcbiAgICB9LFxuICAgIGRlcGVuZGVuY2llczogW1xuICAgICAgdG9wTGV2ZWxUeXBlcy50b3BCbHVyLFxuICAgICAgdG9wTGV2ZWxUeXBlcy50b3BDb21wb3NpdGlvblN0YXJ0LFxuICAgICAgdG9wTGV2ZWxUeXBlcy50b3BLZXlEb3duLFxuICAgICAgdG9wTGV2ZWxUeXBlcy50b3BLZXlQcmVzcyxcbiAgICAgIHRvcExldmVsVHlwZXMudG9wS2V5VXAsXG4gICAgICB0b3BMZXZlbFR5cGVzLnRvcE1vdXNlRG93blxuICAgIF1cbiAgfSxcbiAgY29tcG9zaXRpb25VcGRhdGU6IHtcbiAgICBwaGFzZWRSZWdpc3RyYXRpb25OYW1lczoge1xuICAgICAgYnViYmxlZDoga2V5T2Yoe29uQ29tcG9zaXRpb25VcGRhdGU6IG51bGx9KSxcbiAgICAgIGNhcHR1cmVkOiBrZXlPZih7b25Db21wb3NpdGlvblVwZGF0ZUNhcHR1cmU6IG51bGx9KVxuICAgIH0sXG4gICAgZGVwZW5kZW5jaWVzOiBbXG4gICAgICB0b3BMZXZlbFR5cGVzLnRvcEJsdXIsXG4gICAgICB0b3BMZXZlbFR5cGVzLnRvcENvbXBvc2l0aW9uVXBkYXRlLFxuICAgICAgdG9wTGV2ZWxUeXBlcy50b3BLZXlEb3duLFxuICAgICAgdG9wTGV2ZWxUeXBlcy50b3BLZXlQcmVzcyxcbiAgICAgIHRvcExldmVsVHlwZXMudG9wS2V5VXAsXG4gICAgICB0b3BMZXZlbFR5cGVzLnRvcE1vdXNlRG93blxuICAgIF1cbiAgfVxufTtcblxuLyoqXG4gKiBUcmFuc2xhdGUgbmF0aXZlIHRvcCBsZXZlbCBldmVudHMgaW50byBldmVudCB0eXBlcy5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gdG9wTGV2ZWxUeXBlXG4gKiBAcmV0dXJuIHtvYmplY3R9XG4gKi9cbmZ1bmN0aW9uIGdldENvbXBvc2l0aW9uRXZlbnRUeXBlKHRvcExldmVsVHlwZSkge1xuICBzd2l0Y2ggKHRvcExldmVsVHlwZSkge1xuICAgIGNhc2UgdG9wTGV2ZWxUeXBlcy50b3BDb21wb3NpdGlvblN0YXJ0OlxuICAgICAgcmV0dXJuIGV2ZW50VHlwZXMuY29tcG9zaXRpb25TdGFydDtcbiAgICBjYXNlIHRvcExldmVsVHlwZXMudG9wQ29tcG9zaXRpb25FbmQ6XG4gICAgICByZXR1cm4gZXZlbnRUeXBlcy5jb21wb3NpdGlvbkVuZDtcbiAgICBjYXNlIHRvcExldmVsVHlwZXMudG9wQ29tcG9zaXRpb25VcGRhdGU6XG4gICAgICByZXR1cm4gZXZlbnRUeXBlcy5jb21wb3NpdGlvblVwZGF0ZTtcbiAgfVxufVxuXG4vKipcbiAqIERvZXMgb3VyIGZhbGxiYWNrIGJlc3QtZ3Vlc3MgbW9kZWwgdGhpbmsgdGhpcyBldmVudCBzaWduaWZpZXMgdGhhdFxuICogY29tcG9zaXRpb24gaGFzIGJlZ3VuP1xuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSB0b3BMZXZlbFR5cGVcbiAqIEBwYXJhbSB7b2JqZWN0fSBuYXRpdmVFdmVudFxuICogQHJldHVybiB7Ym9vbGVhbn1cbiAqL1xuZnVuY3Rpb24gaXNGYWxsYmFja1N0YXJ0KHRvcExldmVsVHlwZSwgbmF0aXZlRXZlbnQpIHtcbiAgcmV0dXJuIChcbiAgICB0b3BMZXZlbFR5cGUgPT09IHRvcExldmVsVHlwZXMudG9wS2V5RG93biAmJlxuICAgIG5hdGl2ZUV2ZW50LmtleUNvZGUgPT09IFNUQVJUX0tFWUNPREVcbiAgKTtcbn1cblxuLyoqXG4gKiBEb2VzIG91ciBmYWxsYmFjayBtb2RlIHRoaW5rIHRoYXQgdGhpcyBldmVudCBpcyB0aGUgZW5kIG9mIGNvbXBvc2l0aW9uP1xuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSB0b3BMZXZlbFR5cGVcbiAqIEBwYXJhbSB7b2JqZWN0fSBuYXRpdmVFdmVudFxuICogQHJldHVybiB7Ym9vbGVhbn1cbiAqL1xuZnVuY3Rpb24gaXNGYWxsYmFja0VuZCh0b3BMZXZlbFR5cGUsIG5hdGl2ZUV2ZW50KSB7XG4gIHN3aXRjaCAodG9wTGV2ZWxUeXBlKSB7XG4gICAgY2FzZSB0b3BMZXZlbFR5cGVzLnRvcEtleVVwOlxuICAgICAgLy8gQ29tbWFuZCBrZXlzIGluc2VydCBvciBjbGVhciBJTUUgaW5wdXQuXG4gICAgICByZXR1cm4gKEVORF9LRVlDT0RFUy5pbmRleE9mKG5hdGl2ZUV2ZW50LmtleUNvZGUpICE9PSAtMSk7XG4gICAgY2FzZSB0b3BMZXZlbFR5cGVzLnRvcEtleURvd246XG4gICAgICAvLyBFeHBlY3QgSU1FIGtleUNvZGUgb24gZWFjaCBrZXlkb3duLiBJZiB3ZSBnZXQgYW55IG90aGVyXG4gICAgICAvLyBjb2RlIHdlIG11c3QgaGF2ZSBleGl0ZWQgZWFybGllci5cbiAgICAgIHJldHVybiAobmF0aXZlRXZlbnQua2V5Q29kZSAhPT0gU1RBUlRfS0VZQ09ERSk7XG4gICAgY2FzZSB0b3BMZXZlbFR5cGVzLnRvcEtleVByZXNzOlxuICAgIGNhc2UgdG9wTGV2ZWxUeXBlcy50b3BNb3VzZURvd246XG4gICAgY2FzZSB0b3BMZXZlbFR5cGVzLnRvcEJsdXI6XG4gICAgICAvLyBFdmVudHMgYXJlIG5vdCBwb3NzaWJsZSB3aXRob3V0IGNhbmNlbGxpbmcgSU1FLlxuICAgICAgcmV0dXJuIHRydWU7XG4gICAgZGVmYXVsdDpcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgfVxufVxuXG4vKipcbiAqIEhlbHBlciBjbGFzcyBzdG9yZXMgaW5mb3JtYXRpb24gYWJvdXQgc2VsZWN0aW9uIGFuZCBkb2N1bWVudCBzdGF0ZVxuICogc28gd2UgY2FuIGZpZ3VyZSBvdXQgd2hhdCBjaGFuZ2VkIGF0IGEgbGF0ZXIgZGF0ZS5cbiAqXG4gKiBAcGFyYW0ge0RPTUV2ZW50VGFyZ2V0fSByb290XG4gKi9cbmZ1bmN0aW9uIEZhbGxiYWNrQ29tcG9zaXRpb25TdGF0ZShyb290KSB7XG4gIHRoaXMucm9vdCA9IHJvb3Q7XG4gIHRoaXMuc3RhcnRTZWxlY3Rpb24gPSBSZWFjdElucHV0U2VsZWN0aW9uLmdldFNlbGVjdGlvbihyb290KTtcbiAgdGhpcy5zdGFydFZhbHVlID0gdGhpcy5nZXRUZXh0KCk7XG59XG5cbi8qKlxuICogR2V0IGN1cnJlbnQgdGV4dCBvZiBpbnB1dC5cbiAqXG4gKiBAcmV0dXJuIHtzdHJpbmd9XG4gKi9cbkZhbGxiYWNrQ29tcG9zaXRpb25TdGF0ZS5wcm90b3R5cGUuZ2V0VGV4dCA9IGZ1bmN0aW9uKCkge1xuICByZXR1cm4gdGhpcy5yb290LnZhbHVlIHx8IHRoaXMucm9vdFtnZXRUZXh0Q29udGVudEFjY2Vzc29yKCldO1xufTtcblxuLyoqXG4gKiBUZXh0IHRoYXQgaGFzIGNoYW5nZWQgc2luY2UgdGhlIHN0YXJ0IG9mIGNvbXBvc2l0aW9uLlxuICpcbiAqIEByZXR1cm4ge3N0cmluZ31cbiAqL1xuRmFsbGJhY2tDb21wb3NpdGlvblN0YXRlLnByb3RvdHlwZS5nZXREYXRhID0gZnVuY3Rpb24oKSB7XG4gIHZhciBlbmRWYWx1ZSA9IHRoaXMuZ2V0VGV4dCgpO1xuICB2YXIgcHJlZml4TGVuZ3RoID0gdGhpcy5zdGFydFNlbGVjdGlvbi5zdGFydDtcbiAgdmFyIHN1ZmZpeExlbmd0aCA9IHRoaXMuc3RhcnRWYWx1ZS5sZW5ndGggLSB0aGlzLnN0YXJ0U2VsZWN0aW9uLmVuZDtcblxuICByZXR1cm4gZW5kVmFsdWUuc3Vic3RyKFxuICAgIHByZWZpeExlbmd0aCxcbiAgICBlbmRWYWx1ZS5sZW5ndGggLSBzdWZmaXhMZW5ndGggLSBwcmVmaXhMZW5ndGhcbiAgKTtcbn07XG5cbi8qKlxuICogVGhpcyBwbHVnaW4gY3JlYXRlcyBgb25Db21wb3NpdGlvblN0YXJ0YCwgYG9uQ29tcG9zaXRpb25VcGRhdGVgIGFuZFxuICogYG9uQ29tcG9zaXRpb25FbmRgIGV2ZW50cyBvbiBpbnB1dHMsIHRleHRhcmVhcyBhbmQgY29udGVudEVkaXRhYmxlXG4gKiBub2Rlcy5cbiAqL1xudmFyIENvbXBvc2l0aW9uRXZlbnRQbHVnaW4gPSB7XG5cbiAgZXZlbnRUeXBlczogZXZlbnRUeXBlcyxcblxuICAvKipcbiAgICogQHBhcmFtIHtzdHJpbmd9IHRvcExldmVsVHlwZSBSZWNvcmQgZnJvbSBgRXZlbnRDb25zdGFudHNgLlxuICAgKiBAcGFyYW0ge0RPTUV2ZW50VGFyZ2V0fSB0b3BMZXZlbFRhcmdldCBUaGUgbGlzdGVuaW5nIGNvbXBvbmVudCByb290IG5vZGUuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB0b3BMZXZlbFRhcmdldElEIElEIG9mIGB0b3BMZXZlbFRhcmdldGAuXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBuYXRpdmVFdmVudCBOYXRpdmUgYnJvd3NlciBldmVudC5cbiAgICogQHJldHVybiB7Kn0gQW4gYWNjdW11bGF0aW9uIG9mIHN5bnRoZXRpYyBldmVudHMuXG4gICAqIEBzZWUge0V2ZW50UGx1Z2luSHViLmV4dHJhY3RFdmVudHN9XG4gICAqL1xuICBleHRyYWN0RXZlbnRzOiBmdW5jdGlvbihcbiAgICAgIHRvcExldmVsVHlwZSxcbiAgICAgIHRvcExldmVsVGFyZ2V0LFxuICAgICAgdG9wTGV2ZWxUYXJnZXRJRCxcbiAgICAgIG5hdGl2ZUV2ZW50KSB7XG5cbiAgICB2YXIgZXZlbnRUeXBlO1xuICAgIHZhciBkYXRhO1xuXG4gICAgaWYgKHVzZUNvbXBvc2l0aW9uRXZlbnQpIHtcbiAgICAgIGV2ZW50VHlwZSA9IGdldENvbXBvc2l0aW9uRXZlbnRUeXBlKHRvcExldmVsVHlwZSk7XG4gICAgfSBlbHNlIGlmICghY3VycmVudENvbXBvc2l0aW9uKSB7XG4gICAgICBpZiAoaXNGYWxsYmFja1N0YXJ0KHRvcExldmVsVHlwZSwgbmF0aXZlRXZlbnQpKSB7XG4gICAgICAgIGV2ZW50VHlwZSA9IGV2ZW50VHlwZXMuY29tcG9zaXRpb25TdGFydDtcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKGlzRmFsbGJhY2tFbmQodG9wTGV2ZWxUeXBlLCBuYXRpdmVFdmVudCkpIHtcbiAgICAgIGV2ZW50VHlwZSA9IGV2ZW50VHlwZXMuY29tcG9zaXRpb25FbmQ7XG4gICAgfVxuXG4gICAgaWYgKHVzZUZhbGxiYWNrRGF0YSkge1xuICAgICAgLy8gVGhlIGN1cnJlbnQgY29tcG9zaXRpb24gaXMgc3RvcmVkIHN0YXRpY2FsbHkgYW5kIG11c3Qgbm90IGJlXG4gICAgICAvLyBvdmVyd3JpdHRlbiB3aGlsZSBjb21wb3NpdGlvbiBjb250aW51ZXMuXG4gICAgICBpZiAoIWN1cnJlbnRDb21wb3NpdGlvbiAmJiBldmVudFR5cGUgPT09IGV2ZW50VHlwZXMuY29tcG9zaXRpb25TdGFydCkge1xuICAgICAgICBjdXJyZW50Q29tcG9zaXRpb24gPSBuZXcgRmFsbGJhY2tDb21wb3NpdGlvblN0YXRlKHRvcExldmVsVGFyZ2V0KTtcbiAgICAgIH0gZWxzZSBpZiAoZXZlbnRUeXBlID09PSBldmVudFR5cGVzLmNvbXBvc2l0aW9uRW5kKSB7XG4gICAgICAgIGlmIChjdXJyZW50Q29tcG9zaXRpb24pIHtcbiAgICAgICAgICBkYXRhID0gY3VycmVudENvbXBvc2l0aW9uLmdldERhdGEoKTtcbiAgICAgICAgICBjdXJyZW50Q29tcG9zaXRpb24gPSBudWxsO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKGV2ZW50VHlwZSkge1xuICAgICAgdmFyIGV2ZW50ID0gU3ludGhldGljQ29tcG9zaXRpb25FdmVudC5nZXRQb29sZWQoXG4gICAgICAgIGV2ZW50VHlwZSxcbiAgICAgICAgdG9wTGV2ZWxUYXJnZXRJRCxcbiAgICAgICAgbmF0aXZlRXZlbnRcbiAgICAgICk7XG4gICAgICBpZiAoZGF0YSkge1xuICAgICAgICAvLyBJbmplY3QgZGF0YSBnZW5lcmF0ZWQgZnJvbSBmYWxsYmFjayBwYXRoIGludG8gdGhlIHN5bnRoZXRpYyBldmVudC5cbiAgICAgICAgLy8gVGhpcyBtYXRjaGVzIHRoZSBwcm9wZXJ0eSBvZiBuYXRpdmUgQ29tcG9zaXRpb25FdmVudEludGVyZmFjZS5cbiAgICAgICAgZXZlbnQuZGF0YSA9IGRhdGE7XG4gICAgICB9XG4gICAgICBFdmVudFByb3BhZ2F0b3JzLmFjY3VtdWxhdGVUd29QaGFzZURpc3BhdGNoZXMoZXZlbnQpO1xuICAgICAgcmV0dXJuIGV2ZW50O1xuICAgIH1cbiAgfVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBDb21wb3NpdGlvbkV2ZW50UGx1Z2luO1xuIiwiKGZ1bmN0aW9uIChwcm9jZXNzKXtcbi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBET01DaGlsZHJlbk9wZXJhdGlvbnNcbiAqIEB0eXBlY2hlY2tzIHN0YXRpYy1vbmx5XG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBEYW5nZXIgPSByZXF1aXJlKFwiLi9EYW5nZXJcIik7XG52YXIgUmVhY3RNdWx0aUNoaWxkVXBkYXRlVHlwZXMgPSByZXF1aXJlKFwiLi9SZWFjdE11bHRpQ2hpbGRVcGRhdGVUeXBlc1wiKTtcblxudmFyIGdldFRleHRDb250ZW50QWNjZXNzb3IgPSByZXF1aXJlKFwiLi9nZXRUZXh0Q29udGVudEFjY2Vzc29yXCIpO1xudmFyIGludmFyaWFudCA9IHJlcXVpcmUoXCIuL2ludmFyaWFudFwiKTtcblxuLyoqXG4gKiBUaGUgRE9NIHByb3BlcnR5IHRvIHVzZSB3aGVuIHNldHRpbmcgdGV4dCBjb250ZW50LlxuICpcbiAqIEB0eXBlIHtzdHJpbmd9XG4gKiBAcHJpdmF0ZVxuICovXG52YXIgdGV4dENvbnRlbnRBY2Nlc3NvciA9IGdldFRleHRDb250ZW50QWNjZXNzb3IoKTtcblxuLyoqXG4gKiBJbnNlcnRzIGBjaGlsZE5vZGVgIGFzIGEgY2hpbGQgb2YgYHBhcmVudE5vZGVgIGF0IHRoZSBgaW5kZXhgLlxuICpcbiAqIEBwYXJhbSB7RE9NRWxlbWVudH0gcGFyZW50Tm9kZSBQYXJlbnQgbm9kZSBpbiB3aGljaCB0byBpbnNlcnQuXG4gKiBAcGFyYW0ge0RPTUVsZW1lbnR9IGNoaWxkTm9kZSBDaGlsZCBub2RlIHRvIGluc2VydC5cbiAqIEBwYXJhbSB7bnVtYmVyfSBpbmRleCBJbmRleCBhdCB3aGljaCB0byBpbnNlcnQgdGhlIGNoaWxkLlxuICogQGludGVybmFsXG4gKi9cbmZ1bmN0aW9uIGluc2VydENoaWxkQXQocGFyZW50Tm9kZSwgY2hpbGROb2RlLCBpbmRleCkge1xuICAvLyBCeSBleHBsb2l0aW5nIGFycmF5cyByZXR1cm5pbmcgYHVuZGVmaW5lZGAgZm9yIGFuIHVuZGVmaW5lZCBpbmRleCwgd2UgY2FuXG4gIC8vIHJlbHkgZXhjbHVzaXZlbHkgb24gYGluc2VydEJlZm9yZShub2RlLCBudWxsKWAgaW5zdGVhZCBvZiBhbHNvIHVzaW5nXG4gIC8vIGBhcHBlbmRDaGlsZChub2RlKWAuIEhvd2V2ZXIsIHVzaW5nIGB1bmRlZmluZWRgIGlzIG5vdCBhbGxvd2VkIGJ5IGFsbFxuICAvLyBicm93c2VycyBzbyB3ZSBtdXN0IHJlcGxhY2UgaXQgd2l0aCBgbnVsbGAuXG4gIHBhcmVudE5vZGUuaW5zZXJ0QmVmb3JlKFxuICAgIGNoaWxkTm9kZSxcbiAgICBwYXJlbnROb2RlLmNoaWxkTm9kZXNbaW5kZXhdIHx8IG51bGxcbiAgKTtcbn1cblxudmFyIHVwZGF0ZVRleHRDb250ZW50O1xuaWYgKHRleHRDb250ZW50QWNjZXNzb3IgPT09ICd0ZXh0Q29udGVudCcpIHtcbiAgLyoqXG4gICAqIFNldHMgdGhlIHRleHQgY29udGVudCBvZiBgbm9kZWAgdG8gYHRleHRgLlxuICAgKlxuICAgKiBAcGFyYW0ge0RPTUVsZW1lbnR9IG5vZGUgTm9kZSB0byBjaGFuZ2VcbiAgICogQHBhcmFtIHtzdHJpbmd9IHRleHQgTmV3IHRleHQgY29udGVudFxuICAgKi9cbiAgdXBkYXRlVGV4dENvbnRlbnQgPSBmdW5jdGlvbihub2RlLCB0ZXh0KSB7XG4gICAgbm9kZS50ZXh0Q29udGVudCA9IHRleHQ7XG4gIH07XG59IGVsc2Uge1xuICAvKipcbiAgICogU2V0cyB0aGUgdGV4dCBjb250ZW50IG9mIGBub2RlYCB0byBgdGV4dGAuXG4gICAqXG4gICAqIEBwYXJhbSB7RE9NRWxlbWVudH0gbm9kZSBOb2RlIHRvIGNoYW5nZVxuICAgKiBAcGFyYW0ge3N0cmluZ30gdGV4dCBOZXcgdGV4dCBjb250ZW50XG4gICAqL1xuICB1cGRhdGVUZXh0Q29udGVudCA9IGZ1bmN0aW9uKG5vZGUsIHRleHQpIHtcbiAgICAvLyBJbiBvcmRlciB0byBwcmVzZXJ2ZSBuZXdsaW5lcyBjb3JyZWN0bHksIHdlIGNhbid0IHVzZSAuaW5uZXJUZXh0IHRvIHNldFxuICAgIC8vIHRoZSBjb250ZW50cyAoc2VlICMxMDgwKSwgc28gd2UgZW1wdHkgdGhlIGVsZW1lbnQgdGhlbiBhcHBlbmQgYSB0ZXh0IG5vZGVcbiAgICB3aGlsZSAobm9kZS5maXJzdENoaWxkKSB7XG4gICAgICBub2RlLnJlbW92ZUNoaWxkKG5vZGUuZmlyc3RDaGlsZCk7XG4gICAgfVxuICAgIGlmICh0ZXh0KSB7XG4gICAgICB2YXIgZG9jID0gbm9kZS5vd25lckRvY3VtZW50IHx8IGRvY3VtZW50O1xuICAgICAgbm9kZS5hcHBlbmRDaGlsZChkb2MuY3JlYXRlVGV4dE5vZGUodGV4dCkpO1xuICAgIH1cbiAgfTtcbn1cblxuLyoqXG4gKiBPcGVyYXRpb25zIGZvciB1cGRhdGluZyB3aXRoIERPTSBjaGlsZHJlbi5cbiAqL1xudmFyIERPTUNoaWxkcmVuT3BlcmF0aW9ucyA9IHtcblxuICBkYW5nZXJvdXNseVJlcGxhY2VOb2RlV2l0aE1hcmt1cDogRGFuZ2VyLmRhbmdlcm91c2x5UmVwbGFjZU5vZGVXaXRoTWFya3VwLFxuXG4gIHVwZGF0ZVRleHRDb250ZW50OiB1cGRhdGVUZXh0Q29udGVudCxcblxuICAvKipcbiAgICogVXBkYXRlcyBhIGNvbXBvbmVudCdzIGNoaWxkcmVuIGJ5IHByb2Nlc3NpbmcgYSBzZXJpZXMgb2YgdXBkYXRlcy4gVGhlXG4gICAqIHVwZGF0ZSBjb25maWd1cmF0aW9ucyBhcmUgZWFjaCBleHBlY3RlZCB0byBoYXZlIGEgYHBhcmVudE5vZGVgIHByb3BlcnR5LlxuICAgKlxuICAgKiBAcGFyYW0ge2FycmF5PG9iamVjdD59IHVwZGF0ZXMgTGlzdCBvZiB1cGRhdGUgY29uZmlndXJhdGlvbnMuXG4gICAqIEBwYXJhbSB7YXJyYXk8c3RyaW5nPn0gbWFya3VwTGlzdCBMaXN0IG9mIG1hcmt1cCBzdHJpbmdzLlxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIHByb2Nlc3NVcGRhdGVzOiBmdW5jdGlvbih1cGRhdGVzLCBtYXJrdXBMaXN0KSB7XG4gICAgdmFyIHVwZGF0ZTtcbiAgICAvLyBNYXBwaW5nIGZyb20gcGFyZW50IElEcyB0byBpbml0aWFsIGNoaWxkIG9yZGVyaW5ncy5cbiAgICB2YXIgaW5pdGlhbENoaWxkcmVuID0gbnVsbDtcbiAgICAvLyBMaXN0IG9mIGNoaWxkcmVuIHRoYXQgd2lsbCBiZSBtb3ZlZCBvciByZW1vdmVkLlxuICAgIHZhciB1cGRhdGVkQ2hpbGRyZW4gPSBudWxsO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IHVwZGF0ZSA9IHVwZGF0ZXNbaV07IGkrKykge1xuICAgICAgaWYgKHVwZGF0ZS50eXBlID09PSBSZWFjdE11bHRpQ2hpbGRVcGRhdGVUeXBlcy5NT1ZFX0VYSVNUSU5HIHx8XG4gICAgICAgICAgdXBkYXRlLnR5cGUgPT09IFJlYWN0TXVsdGlDaGlsZFVwZGF0ZVR5cGVzLlJFTU9WRV9OT0RFKSB7XG4gICAgICAgIHZhciB1cGRhdGVkSW5kZXggPSB1cGRhdGUuZnJvbUluZGV4O1xuICAgICAgICB2YXIgdXBkYXRlZENoaWxkID0gdXBkYXRlLnBhcmVudE5vZGUuY2hpbGROb2Rlc1t1cGRhdGVkSW5kZXhdO1xuICAgICAgICB2YXIgcGFyZW50SUQgPSB1cGRhdGUucGFyZW50SUQ7XG5cbiAgICAgICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgICAgICB1cGRhdGVkQ2hpbGQsXG4gICAgICAgICAgJ3Byb2Nlc3NVcGRhdGVzKCk6IFVuYWJsZSB0byBmaW5kIGNoaWxkICVzIG9mIGVsZW1lbnQuIFRoaXMgJyArXG4gICAgICAgICAgJ3Byb2JhYmx5IG1lYW5zIHRoZSBET00gd2FzIHVuZXhwZWN0ZWRseSBtdXRhdGVkIChlLmcuLCBieSB0aGUgJyArXG4gICAgICAgICAgJ2Jyb3dzZXIpLCB1c3VhbGx5IGR1ZSB0byBmb3JnZXR0aW5nIGEgPHRib2R5PiB3aGVuIHVzaW5nIHRhYmxlcywgJyArXG4gICAgICAgICAgJ25lc3RpbmcgdGFncyBsaWtlIDxmb3JtPiwgPHA+LCBvciA8YT4sIG9yIHVzaW5nIG5vbi1TVkcgZWxlbWVudHMgJytcbiAgICAgICAgICAnaW4gYW4gPHN2Zz4gcGFyZW50LiBUcnkgaW5zcGVjdGluZyB0aGUgY2hpbGQgbm9kZXMgb2YgdGhlIGVsZW1lbnQgJyArXG4gICAgICAgICAgJ3dpdGggUmVhY3QgSUQgYCVzYC4nLFxuICAgICAgICAgIHVwZGF0ZWRJbmRleCxcbiAgICAgICAgICBwYXJlbnRJRFxuICAgICAgICApIDogaW52YXJpYW50KHVwZGF0ZWRDaGlsZCkpO1xuXG4gICAgICAgIGluaXRpYWxDaGlsZHJlbiA9IGluaXRpYWxDaGlsZHJlbiB8fCB7fTtcbiAgICAgICAgaW5pdGlhbENoaWxkcmVuW3BhcmVudElEXSA9IGluaXRpYWxDaGlsZHJlbltwYXJlbnRJRF0gfHwgW107XG4gICAgICAgIGluaXRpYWxDaGlsZHJlbltwYXJlbnRJRF1bdXBkYXRlZEluZGV4XSA9IHVwZGF0ZWRDaGlsZDtcblxuICAgICAgICB1cGRhdGVkQ2hpbGRyZW4gPSB1cGRhdGVkQ2hpbGRyZW4gfHwgW107XG4gICAgICAgIHVwZGF0ZWRDaGlsZHJlbi5wdXNoKHVwZGF0ZWRDaGlsZCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgdmFyIHJlbmRlcmVkTWFya3VwID0gRGFuZ2VyLmRhbmdlcm91c2x5UmVuZGVyTWFya3VwKG1hcmt1cExpc3QpO1xuXG4gICAgLy8gUmVtb3ZlIHVwZGF0ZWQgY2hpbGRyZW4gZmlyc3Qgc28gdGhhdCBgdG9JbmRleGAgaXMgY29uc2lzdGVudC5cbiAgICBpZiAodXBkYXRlZENoaWxkcmVuKSB7XG4gICAgICBmb3IgKHZhciBqID0gMDsgaiA8IHVwZGF0ZWRDaGlsZHJlbi5sZW5ndGg7IGorKykge1xuICAgICAgICB1cGRhdGVkQ2hpbGRyZW5bal0ucGFyZW50Tm9kZS5yZW1vdmVDaGlsZCh1cGRhdGVkQ2hpbGRyZW5bal0pO1xuICAgICAgfVxuICAgIH1cblxuICAgIGZvciAodmFyIGsgPSAwOyB1cGRhdGUgPSB1cGRhdGVzW2tdOyBrKyspIHtcbiAgICAgIHN3aXRjaCAodXBkYXRlLnR5cGUpIHtcbiAgICAgICAgY2FzZSBSZWFjdE11bHRpQ2hpbGRVcGRhdGVUeXBlcy5JTlNFUlRfTUFSS1VQOlxuICAgICAgICAgIGluc2VydENoaWxkQXQoXG4gICAgICAgICAgICB1cGRhdGUucGFyZW50Tm9kZSxcbiAgICAgICAgICAgIHJlbmRlcmVkTWFya3VwW3VwZGF0ZS5tYXJrdXBJbmRleF0sXG4gICAgICAgICAgICB1cGRhdGUudG9JbmRleFxuICAgICAgICAgICk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgUmVhY3RNdWx0aUNoaWxkVXBkYXRlVHlwZXMuTU9WRV9FWElTVElORzpcbiAgICAgICAgICBpbnNlcnRDaGlsZEF0KFxuICAgICAgICAgICAgdXBkYXRlLnBhcmVudE5vZGUsXG4gICAgICAgICAgICBpbml0aWFsQ2hpbGRyZW5bdXBkYXRlLnBhcmVudElEXVt1cGRhdGUuZnJvbUluZGV4XSxcbiAgICAgICAgICAgIHVwZGF0ZS50b0luZGV4XG4gICAgICAgICAgKTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSBSZWFjdE11bHRpQ2hpbGRVcGRhdGVUeXBlcy5URVhUX0NPTlRFTlQ6XG4gICAgICAgICAgdXBkYXRlVGV4dENvbnRlbnQoXG4gICAgICAgICAgICB1cGRhdGUucGFyZW50Tm9kZSxcbiAgICAgICAgICAgIHVwZGF0ZS50ZXh0Q29udGVudFxuICAgICAgICAgICk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgUmVhY3RNdWx0aUNoaWxkVXBkYXRlVHlwZXMuUkVNT1ZFX05PREU6XG4gICAgICAgICAgLy8gQWxyZWFkeSByZW1vdmVkIGJ5IHRoZSBmb3ItbG9vcCBhYm92ZS5cbiAgICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9XG4gIH1cblxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBET01DaGlsZHJlbk9wZXJhdGlvbnM7XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKCdfcHJvY2VzcycpKSIsIihmdW5jdGlvbiAocHJvY2Vzcyl7XG4vKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgRE9NUHJvcGVydHlcbiAqIEB0eXBlY2hlY2tzIHN0YXRpYy1vbmx5XG4gKi9cblxuLypqc2xpbnQgYml0d2lzZTogdHJ1ZSAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIGludmFyaWFudCA9IHJlcXVpcmUoXCIuL2ludmFyaWFudFwiKTtcblxuZnVuY3Rpb24gY2hlY2tNYXNrKHZhbHVlLCBiaXRtYXNrKSB7XG4gIHJldHVybiAodmFsdWUgJiBiaXRtYXNrKSA9PT0gYml0bWFzaztcbn1cblxudmFyIERPTVByb3BlcnR5SW5qZWN0aW9uID0ge1xuICAvKipcbiAgICogTWFwcGluZyBmcm9tIG5vcm1hbGl6ZWQsIGNhbWVsY2FzZWQgcHJvcGVydHkgbmFtZXMgdG8gYSBjb25maWd1cmF0aW9uIHRoYXRcbiAgICogc3BlY2lmaWVzIGhvdyB0aGUgYXNzb2NpYXRlZCBET00gcHJvcGVydHkgc2hvdWxkIGJlIGFjY2Vzc2VkIG9yIHJlbmRlcmVkLlxuICAgKi9cbiAgTVVTVF9VU0VfQVRUUklCVVRFOiAweDEsXG4gIE1VU1RfVVNFX1BST1BFUlRZOiAweDIsXG4gIEhBU19TSURFX0VGRkVDVFM6IDB4NCxcbiAgSEFTX0JPT0xFQU5fVkFMVUU6IDB4OCxcbiAgSEFTX05VTUVSSUNfVkFMVUU6IDB4MTAsXG4gIEhBU19QT1NJVElWRV9OVU1FUklDX1ZBTFVFOiAweDIwIHwgMHgxMCxcbiAgSEFTX09WRVJMT0FERURfQk9PTEVBTl9WQUxVRTogMHg0MCxcblxuICAvKipcbiAgICogSW5qZWN0IHNvbWUgc3BlY2lhbGl6ZWQga25vd2xlZGdlIGFib3V0IHRoZSBET00uIFRoaXMgdGFrZXMgYSBjb25maWcgb2JqZWN0XG4gICAqIHdpdGggdGhlIGZvbGxvd2luZyBwcm9wZXJ0aWVzOlxuICAgKlxuICAgKiBpc0N1c3RvbUF0dHJpYnV0ZTogZnVuY3Rpb24gdGhhdCBnaXZlbiBhbiBhdHRyaWJ1dGUgbmFtZSB3aWxsIHJldHVybiB0cnVlXG4gICAqIGlmIGl0IGNhbiBiZSBpbnNlcnRlZCBpbnRvIHRoZSBET00gdmVyYmF0aW0uIFVzZWZ1bCBmb3IgZGF0YS0qIG9yIGFyaWEtKlxuICAgKiBhdHRyaWJ1dGVzIHdoZXJlIGl0J3MgaW1wb3NzaWJsZSB0byBlbnVtZXJhdGUgYWxsIG9mIHRoZSBwb3NzaWJsZVxuICAgKiBhdHRyaWJ1dGUgbmFtZXMsXG4gICAqXG4gICAqIFByb3BlcnRpZXM6IG9iamVjdCBtYXBwaW5nIERPTSBwcm9wZXJ0eSBuYW1lIHRvIG9uZSBvZiB0aGVcbiAgICogRE9NUHJvcGVydHlJbmplY3Rpb24gY29uc3RhbnRzIG9yIG51bGwuIElmIHlvdXIgYXR0cmlidXRlIGlzbid0IGluIGhlcmUsXG4gICAqIGl0IHdvbid0IGdldCB3cml0dGVuIHRvIHRoZSBET00uXG4gICAqXG4gICAqIERPTUF0dHJpYnV0ZU5hbWVzOiBvYmplY3QgbWFwcGluZyBSZWFjdCBhdHRyaWJ1dGUgbmFtZSB0byB0aGUgRE9NXG4gICAqIGF0dHJpYnV0ZSBuYW1lLiBBdHRyaWJ1dGUgbmFtZXMgbm90IHNwZWNpZmllZCB1c2UgdGhlICoqbG93ZXJjYXNlKipcbiAgICogbm9ybWFsaXplZCBuYW1lLlxuICAgKlxuICAgKiBET01Qcm9wZXJ0eU5hbWVzOiBzaW1pbGFyIHRvIERPTUF0dHJpYnV0ZU5hbWVzIGJ1dCBmb3IgRE9NIHByb3BlcnRpZXMuXG4gICAqIFByb3BlcnR5IG5hbWVzIG5vdCBzcGVjaWZpZWQgdXNlIHRoZSBub3JtYWxpemVkIG5hbWUuXG4gICAqXG4gICAqIERPTU11dGF0aW9uTWV0aG9kczogUHJvcGVydGllcyB0aGF0IHJlcXVpcmUgc3BlY2lhbCBtdXRhdGlvbiBtZXRob2RzLiBJZlxuICAgKiBgdmFsdWVgIGlzIHVuZGVmaW5lZCwgdGhlIG11dGF0aW9uIG1ldGhvZCBzaG91bGQgdW5zZXQgdGhlIHByb3BlcnR5LlxuICAgKlxuICAgKiBAcGFyYW0ge29iamVjdH0gZG9tUHJvcGVydHlDb25maWcgdGhlIGNvbmZpZyBhcyBkZXNjcmliZWQgYWJvdmUuXG4gICAqL1xuICBpbmplY3RET01Qcm9wZXJ0eUNvbmZpZzogZnVuY3Rpb24oZG9tUHJvcGVydHlDb25maWcpIHtcbiAgICB2YXIgUHJvcGVydGllcyA9IGRvbVByb3BlcnR5Q29uZmlnLlByb3BlcnRpZXMgfHwge307XG4gICAgdmFyIERPTUF0dHJpYnV0ZU5hbWVzID0gZG9tUHJvcGVydHlDb25maWcuRE9NQXR0cmlidXRlTmFtZXMgfHwge307XG4gICAgdmFyIERPTVByb3BlcnR5TmFtZXMgPSBkb21Qcm9wZXJ0eUNvbmZpZy5ET01Qcm9wZXJ0eU5hbWVzIHx8IHt9O1xuICAgIHZhciBET01NdXRhdGlvbk1ldGhvZHMgPSBkb21Qcm9wZXJ0eUNvbmZpZy5ET01NdXRhdGlvbk1ldGhvZHMgfHwge307XG5cbiAgICBpZiAoZG9tUHJvcGVydHlDb25maWcuaXNDdXN0b21BdHRyaWJ1dGUpIHtcbiAgICAgIERPTVByb3BlcnR5Ll9pc0N1c3RvbUF0dHJpYnV0ZUZ1bmN0aW9ucy5wdXNoKFxuICAgICAgICBkb21Qcm9wZXJ0eUNvbmZpZy5pc0N1c3RvbUF0dHJpYnV0ZVxuICAgICAgKTtcbiAgICB9XG5cbiAgICBmb3IgKHZhciBwcm9wTmFtZSBpbiBQcm9wZXJ0aWVzKSB7XG4gICAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgICAhRE9NUHJvcGVydHkuaXNTdGFuZGFyZE5hbWUuaGFzT3duUHJvcGVydHkocHJvcE5hbWUpLFxuICAgICAgICAnaW5qZWN0RE9NUHJvcGVydHlDb25maWcoLi4uKTogWW91XFwncmUgdHJ5aW5nIHRvIGluamVjdCBET00gcHJvcGVydHkgJyArXG4gICAgICAgICdcXCclc1xcJyB3aGljaCBoYXMgYWxyZWFkeSBiZWVuIGluamVjdGVkLiBZb3UgbWF5IGJlIGFjY2lkZW50YWxseSAnICtcbiAgICAgICAgJ2luamVjdGluZyB0aGUgc2FtZSBET00gcHJvcGVydHkgY29uZmlnIHR3aWNlLCBvciB5b3UgbWF5IGJlICcgK1xuICAgICAgICAnaW5qZWN0aW5nIHR3byBjb25maWdzIHRoYXQgaGF2ZSBjb25mbGljdGluZyBwcm9wZXJ0eSBuYW1lcy4nLFxuICAgICAgICBwcm9wTmFtZVxuICAgICAgKSA6IGludmFyaWFudCghRE9NUHJvcGVydHkuaXNTdGFuZGFyZE5hbWUuaGFzT3duUHJvcGVydHkocHJvcE5hbWUpKSk7XG5cbiAgICAgIERPTVByb3BlcnR5LmlzU3RhbmRhcmROYW1lW3Byb3BOYW1lXSA9IHRydWU7XG5cbiAgICAgIHZhciBsb3dlckNhc2VkID0gcHJvcE5hbWUudG9Mb3dlckNhc2UoKTtcbiAgICAgIERPTVByb3BlcnR5LmdldFBvc3NpYmxlU3RhbmRhcmROYW1lW2xvd2VyQ2FzZWRdID0gcHJvcE5hbWU7XG5cbiAgICAgIGlmIChET01BdHRyaWJ1dGVOYW1lcy5oYXNPd25Qcm9wZXJ0eShwcm9wTmFtZSkpIHtcbiAgICAgICAgdmFyIGF0dHJpYnV0ZU5hbWUgPSBET01BdHRyaWJ1dGVOYW1lc1twcm9wTmFtZV07XG4gICAgICAgIERPTVByb3BlcnR5LmdldFBvc3NpYmxlU3RhbmRhcmROYW1lW2F0dHJpYnV0ZU5hbWVdID0gcHJvcE5hbWU7XG4gICAgICAgIERPTVByb3BlcnR5LmdldEF0dHJpYnV0ZU5hbWVbcHJvcE5hbWVdID0gYXR0cmlidXRlTmFtZTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIERPTVByb3BlcnR5LmdldEF0dHJpYnV0ZU5hbWVbcHJvcE5hbWVdID0gbG93ZXJDYXNlZDtcbiAgICAgIH1cblxuICAgICAgRE9NUHJvcGVydHkuZ2V0UHJvcGVydHlOYW1lW3Byb3BOYW1lXSA9XG4gICAgICAgIERPTVByb3BlcnR5TmFtZXMuaGFzT3duUHJvcGVydHkocHJvcE5hbWUpID9cbiAgICAgICAgICBET01Qcm9wZXJ0eU5hbWVzW3Byb3BOYW1lXSA6XG4gICAgICAgICAgcHJvcE5hbWU7XG5cbiAgICAgIGlmIChET01NdXRhdGlvbk1ldGhvZHMuaGFzT3duUHJvcGVydHkocHJvcE5hbWUpKSB7XG4gICAgICAgIERPTVByb3BlcnR5LmdldE11dGF0aW9uTWV0aG9kW3Byb3BOYW1lXSA9IERPTU11dGF0aW9uTWV0aG9kc1twcm9wTmFtZV07XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBET01Qcm9wZXJ0eS5nZXRNdXRhdGlvbk1ldGhvZFtwcm9wTmFtZV0gPSBudWxsO1xuICAgICAgfVxuXG4gICAgICB2YXIgcHJvcENvbmZpZyA9IFByb3BlcnRpZXNbcHJvcE5hbWVdO1xuICAgICAgRE9NUHJvcGVydHkubXVzdFVzZUF0dHJpYnV0ZVtwcm9wTmFtZV0gPVxuICAgICAgICBjaGVja01hc2socHJvcENvbmZpZywgRE9NUHJvcGVydHlJbmplY3Rpb24uTVVTVF9VU0VfQVRUUklCVVRFKTtcbiAgICAgIERPTVByb3BlcnR5Lm11c3RVc2VQcm9wZXJ0eVtwcm9wTmFtZV0gPVxuICAgICAgICBjaGVja01hc2socHJvcENvbmZpZywgRE9NUHJvcGVydHlJbmplY3Rpb24uTVVTVF9VU0VfUFJPUEVSVFkpO1xuICAgICAgRE9NUHJvcGVydHkuaGFzU2lkZUVmZmVjdHNbcHJvcE5hbWVdID1cbiAgICAgICAgY2hlY2tNYXNrKHByb3BDb25maWcsIERPTVByb3BlcnR5SW5qZWN0aW9uLkhBU19TSURFX0VGRkVDVFMpO1xuICAgICAgRE9NUHJvcGVydHkuaGFzQm9vbGVhblZhbHVlW3Byb3BOYW1lXSA9XG4gICAgICAgIGNoZWNrTWFzayhwcm9wQ29uZmlnLCBET01Qcm9wZXJ0eUluamVjdGlvbi5IQVNfQk9PTEVBTl9WQUxVRSk7XG4gICAgICBET01Qcm9wZXJ0eS5oYXNOdW1lcmljVmFsdWVbcHJvcE5hbWVdID1cbiAgICAgICAgY2hlY2tNYXNrKHByb3BDb25maWcsIERPTVByb3BlcnR5SW5qZWN0aW9uLkhBU19OVU1FUklDX1ZBTFVFKTtcbiAgICAgIERPTVByb3BlcnR5Lmhhc1Bvc2l0aXZlTnVtZXJpY1ZhbHVlW3Byb3BOYW1lXSA9XG4gICAgICAgIGNoZWNrTWFzayhwcm9wQ29uZmlnLCBET01Qcm9wZXJ0eUluamVjdGlvbi5IQVNfUE9TSVRJVkVfTlVNRVJJQ19WQUxVRSk7XG4gICAgICBET01Qcm9wZXJ0eS5oYXNPdmVybG9hZGVkQm9vbGVhblZhbHVlW3Byb3BOYW1lXSA9XG4gICAgICAgIGNoZWNrTWFzayhwcm9wQ29uZmlnLCBET01Qcm9wZXJ0eUluamVjdGlvbi5IQVNfT1ZFUkxPQURFRF9CT09MRUFOX1ZBTFVFKTtcblxuICAgICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgICAgIURPTVByb3BlcnR5Lm11c3RVc2VBdHRyaWJ1dGVbcHJvcE5hbWVdIHx8XG4gICAgICAgICAgIURPTVByb3BlcnR5Lm11c3RVc2VQcm9wZXJ0eVtwcm9wTmFtZV0sXG4gICAgICAgICdET01Qcm9wZXJ0eTogQ2Fubm90IHJlcXVpcmUgdXNpbmcgYm90aCBhdHRyaWJ1dGUgYW5kIHByb3BlcnR5OiAlcycsXG4gICAgICAgIHByb3BOYW1lXG4gICAgICApIDogaW52YXJpYW50KCFET01Qcm9wZXJ0eS5tdXN0VXNlQXR0cmlidXRlW3Byb3BOYW1lXSB8fFxuICAgICAgICAhRE9NUHJvcGVydHkubXVzdFVzZVByb3BlcnR5W3Byb3BOYW1lXSkpO1xuICAgICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgICAgRE9NUHJvcGVydHkubXVzdFVzZVByb3BlcnR5W3Byb3BOYW1lXSB8fFxuICAgICAgICAgICFET01Qcm9wZXJ0eS5oYXNTaWRlRWZmZWN0c1twcm9wTmFtZV0sXG4gICAgICAgICdET01Qcm9wZXJ0eTogUHJvcGVydGllcyB0aGF0IGhhdmUgc2lkZSBlZmZlY3RzIG11c3QgdXNlIHByb3BlcnR5OiAlcycsXG4gICAgICAgIHByb3BOYW1lXG4gICAgICApIDogaW52YXJpYW50KERPTVByb3BlcnR5Lm11c3RVc2VQcm9wZXJ0eVtwcm9wTmFtZV0gfHxcbiAgICAgICAgIURPTVByb3BlcnR5Lmhhc1NpZGVFZmZlY3RzW3Byb3BOYW1lXSkpO1xuICAgICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgICAgISFET01Qcm9wZXJ0eS5oYXNCb29sZWFuVmFsdWVbcHJvcE5hbWVdICtcbiAgICAgICAgICAhIURPTVByb3BlcnR5Lmhhc051bWVyaWNWYWx1ZVtwcm9wTmFtZV0gK1xuICAgICAgICAgICEhRE9NUHJvcGVydHkuaGFzT3ZlcmxvYWRlZEJvb2xlYW5WYWx1ZVtwcm9wTmFtZV0gPD0gMSxcbiAgICAgICAgJ0RPTVByb3BlcnR5OiBWYWx1ZSBjYW4gYmUgb25lIG9mIGJvb2xlYW4sIG92ZXJsb2FkZWQgYm9vbGVhbiwgb3IgJyArXG4gICAgICAgICdudW1lcmljIHZhbHVlLCBidXQgbm90IGEgY29tYmluYXRpb246ICVzJyxcbiAgICAgICAgcHJvcE5hbWVcbiAgICAgICkgOiBpbnZhcmlhbnQoISFET01Qcm9wZXJ0eS5oYXNCb29sZWFuVmFsdWVbcHJvcE5hbWVdICtcbiAgICAgICAgISFET01Qcm9wZXJ0eS5oYXNOdW1lcmljVmFsdWVbcHJvcE5hbWVdICtcbiAgICAgICAgISFET01Qcm9wZXJ0eS5oYXNPdmVybG9hZGVkQm9vbGVhblZhbHVlW3Byb3BOYW1lXSA8PSAxKSk7XG4gICAgfVxuICB9XG59O1xudmFyIGRlZmF1bHRWYWx1ZUNhY2hlID0ge307XG5cbi8qKlxuICogRE9NUHJvcGVydHkgZXhwb3J0cyBsb29rdXAgb2JqZWN0cyB0aGF0IGNhbiBiZSB1c2VkIGxpa2UgZnVuY3Rpb25zOlxuICpcbiAqICAgPiBET01Qcm9wZXJ0eS5pc1ZhbGlkWydpZCddXG4gKiAgIHRydWVcbiAqICAgPiBET01Qcm9wZXJ0eS5pc1ZhbGlkWydmb29iYXInXVxuICogICB1bmRlZmluZWRcbiAqXG4gKiBBbHRob3VnaCB0aGlzIG1heSBiZSBjb25mdXNpbmcsIGl0IHBlcmZvcm1zIGJldHRlciBpbiBnZW5lcmFsLlxuICpcbiAqIEBzZWUgaHR0cDovL2pzcGVyZi5jb20va2V5LWV4aXN0c1xuICogQHNlZSBodHRwOi8vanNwZXJmLmNvbS9rZXktbWlzc2luZ1xuICovXG52YXIgRE9NUHJvcGVydHkgPSB7XG5cbiAgSURfQVRUUklCVVRFX05BTUU6ICdkYXRhLXJlYWN0aWQnLFxuXG4gIC8qKlxuICAgKiBDaGVja3Mgd2hldGhlciBhIHByb3BlcnR5IG5hbWUgaXMgYSBzdGFuZGFyZCBwcm9wZXJ0eS5cbiAgICogQHR5cGUge09iamVjdH1cbiAgICovXG4gIGlzU3RhbmRhcmROYW1lOiB7fSxcblxuICAvKipcbiAgICogTWFwcGluZyBmcm9tIGxvd2VyY2FzZSBwcm9wZXJ0eSBuYW1lcyB0byB0aGUgcHJvcGVybHkgY2FzZWQgdmVyc2lvbiwgdXNlZFxuICAgKiB0byB3YXJuIGluIHRoZSBjYXNlIG9mIG1pc3NpbmcgcHJvcGVydGllcy5cbiAgICogQHR5cGUge09iamVjdH1cbiAgICovXG4gIGdldFBvc3NpYmxlU3RhbmRhcmROYW1lOiB7fSxcblxuICAvKipcbiAgICogTWFwcGluZyBmcm9tIG5vcm1hbGl6ZWQgbmFtZXMgdG8gYXR0cmlidXRlIG5hbWVzIHRoYXQgZGlmZmVyLiBBdHRyaWJ1dGVcbiAgICogbmFtZXMgYXJlIHVzZWQgd2hlbiByZW5kZXJpbmcgbWFya3VwIG9yIHdpdGggYCpBdHRyaWJ1dGUoKWAuXG4gICAqIEB0eXBlIHtPYmplY3R9XG4gICAqL1xuICBnZXRBdHRyaWJ1dGVOYW1lOiB7fSxcblxuICAvKipcbiAgICogTWFwcGluZyBmcm9tIG5vcm1hbGl6ZWQgbmFtZXMgdG8gcHJvcGVydGllcyBvbiBET00gbm9kZSBpbnN0YW5jZXMuXG4gICAqIChUaGlzIGluY2x1ZGVzIHByb3BlcnRpZXMgdGhhdCBtdXRhdGUgZHVlIHRvIGV4dGVybmFsIGZhY3RvcnMuKVxuICAgKiBAdHlwZSB7T2JqZWN0fVxuICAgKi9cbiAgZ2V0UHJvcGVydHlOYW1lOiB7fSxcblxuICAvKipcbiAgICogTWFwcGluZyBmcm9tIG5vcm1hbGl6ZWQgbmFtZXMgdG8gbXV0YXRpb24gbWV0aG9kcy4gVGhpcyB3aWxsIG9ubHkgZXhpc3QgaWZcbiAgICogbXV0YXRpb24gY2Fubm90IGJlIHNldCBzaW1wbHkgYnkgdGhlIHByb3BlcnR5IG9yIGBzZXRBdHRyaWJ1dGUoKWAuXG4gICAqIEB0eXBlIHtPYmplY3R9XG4gICAqL1xuICBnZXRNdXRhdGlvbk1ldGhvZDoge30sXG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdGhlIHByb3BlcnR5IG11c3QgYmUgYWNjZXNzZWQgYW5kIG11dGF0ZWQgYXMgYW4gb2JqZWN0IHByb3BlcnR5LlxuICAgKiBAdHlwZSB7T2JqZWN0fVxuICAgKi9cbiAgbXVzdFVzZUF0dHJpYnV0ZToge30sXG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdGhlIHByb3BlcnR5IG11c3QgYmUgYWNjZXNzZWQgYW5kIG11dGF0ZWQgdXNpbmcgYCpBdHRyaWJ1dGUoKWAuXG4gICAqIChUaGlzIGluY2x1ZGVzIGFueXRoaW5nIHRoYXQgZmFpbHMgYDxwcm9wTmFtZT4gaW4gPGVsZW1lbnQ+YC4pXG4gICAqIEB0eXBlIHtPYmplY3R9XG4gICAqL1xuICBtdXN0VXNlUHJvcGVydHk6IHt9LFxuXG4gIC8qKlxuICAgKiBXaGV0aGVyIG9yIG5vdCBzZXR0aW5nIGEgdmFsdWUgY2F1c2VzIHNpZGUgZWZmZWN0cyBzdWNoIGFzIHRyaWdnZXJpbmdcbiAgICogcmVzb3VyY2VzIHRvIGJlIGxvYWRlZCBvciB0ZXh0IHNlbGVjdGlvbiBjaGFuZ2VzLiBXZSBtdXN0IGVuc3VyZSB0aGF0XG4gICAqIHRoZSB2YWx1ZSBpcyBvbmx5IHNldCBpZiBpdCBoYXMgY2hhbmdlZC5cbiAgICogQHR5cGUge09iamVjdH1cbiAgICovXG4gIGhhc1NpZGVFZmZlY3RzOiB7fSxcblxuICAvKipcbiAgICogV2hldGhlciB0aGUgcHJvcGVydHkgc2hvdWxkIGJlIHJlbW92ZWQgd2hlbiBzZXQgdG8gYSBmYWxzZXkgdmFsdWUuXG4gICAqIEB0eXBlIHtPYmplY3R9XG4gICAqL1xuICBoYXNCb29sZWFuVmFsdWU6IHt9LFxuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRoZSBwcm9wZXJ0eSBtdXN0IGJlIG51bWVyaWMgb3IgcGFyc2UgYXMgYVxuICAgKiBudW1lcmljIGFuZCBzaG91bGQgYmUgcmVtb3ZlZCB3aGVuIHNldCB0byBhIGZhbHNleSB2YWx1ZS5cbiAgICogQHR5cGUge09iamVjdH1cbiAgICovXG4gIGhhc051bWVyaWNWYWx1ZToge30sXG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdGhlIHByb3BlcnR5IG11c3QgYmUgcG9zaXRpdmUgbnVtZXJpYyBvciBwYXJzZSBhcyBhIHBvc2l0aXZlXG4gICAqIG51bWVyaWMgYW5kIHNob3VsZCBiZSByZW1vdmVkIHdoZW4gc2V0IHRvIGEgZmFsc2V5IHZhbHVlLlxuICAgKiBAdHlwZSB7T2JqZWN0fVxuICAgKi9cbiAgaGFzUG9zaXRpdmVOdW1lcmljVmFsdWU6IHt9LFxuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRoZSBwcm9wZXJ0eSBjYW4gYmUgdXNlZCBhcyBhIGZsYWcgYXMgd2VsbCBhcyB3aXRoIGEgdmFsdWUuIFJlbW92ZWRcbiAgICogd2hlbiBzdHJpY3RseSBlcXVhbCB0byBmYWxzZTsgcHJlc2VudCB3aXRob3V0IGEgdmFsdWUgd2hlbiBzdHJpY3RseSBlcXVhbFxuICAgKiB0byB0cnVlOyBwcmVzZW50IHdpdGggYSB2YWx1ZSBvdGhlcndpc2UuXG4gICAqIEB0eXBlIHtPYmplY3R9XG4gICAqL1xuICBoYXNPdmVybG9hZGVkQm9vbGVhblZhbHVlOiB7fSxcblxuICAvKipcbiAgICogQWxsIG9mIHRoZSBpc0N1c3RvbUF0dHJpYnV0ZSgpIGZ1bmN0aW9ucyB0aGF0IGhhdmUgYmVlbiBpbmplY3RlZC5cbiAgICovXG4gIF9pc0N1c3RvbUF0dHJpYnV0ZUZ1bmN0aW9uczogW10sXG5cbiAgLyoqXG4gICAqIENoZWNrcyB3aGV0aGVyIGEgcHJvcGVydHkgbmFtZSBpcyBhIGN1c3RvbSBhdHRyaWJ1dGUuXG4gICAqIEBtZXRob2RcbiAgICovXG4gIGlzQ3VzdG9tQXR0cmlidXRlOiBmdW5jdGlvbihhdHRyaWJ1dGVOYW1lKSB7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBET01Qcm9wZXJ0eS5faXNDdXN0b21BdHRyaWJ1dGVGdW5jdGlvbnMubGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciBpc0N1c3RvbUF0dHJpYnV0ZUZuID0gRE9NUHJvcGVydHkuX2lzQ3VzdG9tQXR0cmlidXRlRnVuY3Rpb25zW2ldO1xuICAgICAgaWYgKGlzQ3VzdG9tQXR0cmlidXRlRm4oYXR0cmlidXRlTmFtZSkpIHtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbiAgfSxcblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgZGVmYXVsdCBwcm9wZXJ0eSB2YWx1ZSBmb3IgYSBET00gcHJvcGVydHkgKGkuZS4sIG5vdCBhblxuICAgKiBhdHRyaWJ1dGUpLiBNb3N0IGRlZmF1bHQgdmFsdWVzIGFyZSAnJyBvciBmYWxzZSwgYnV0IG5vdCBhbGwuIFdvcnNlIHlldCxcbiAgICogc29tZSAoaW4gcGFydGljdWxhciwgYHR5cGVgKSB2YXJ5IGRlcGVuZGluZyBvbiB0aGUgdHlwZSBvZiBlbGVtZW50LlxuICAgKlxuICAgKiBUT0RPOiBJcyBpdCBiZXR0ZXIgdG8gZ3JhYiBhbGwgdGhlIHBvc3NpYmxlIHByb3BlcnRpZXMgd2hlbiBjcmVhdGluZyBhblxuICAgKiBlbGVtZW50IHRvIGF2b2lkIGhhdmluZyB0byBjcmVhdGUgdGhlIHNhbWUgZWxlbWVudCB0d2ljZT9cbiAgICovXG4gIGdldERlZmF1bHRWYWx1ZUZvclByb3BlcnR5OiBmdW5jdGlvbihub2RlTmFtZSwgcHJvcCkge1xuICAgIHZhciBub2RlRGVmYXVsdHMgPSBkZWZhdWx0VmFsdWVDYWNoZVtub2RlTmFtZV07XG4gICAgdmFyIHRlc3RFbGVtZW50O1xuICAgIGlmICghbm9kZURlZmF1bHRzKSB7XG4gICAgICBkZWZhdWx0VmFsdWVDYWNoZVtub2RlTmFtZV0gPSBub2RlRGVmYXVsdHMgPSB7fTtcbiAgICB9XG4gICAgaWYgKCEocHJvcCBpbiBub2RlRGVmYXVsdHMpKSB7XG4gICAgICB0ZXN0RWxlbWVudCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQobm9kZU5hbWUpO1xuICAgICAgbm9kZURlZmF1bHRzW3Byb3BdID0gdGVzdEVsZW1lbnRbcHJvcF07XG4gICAgfVxuICAgIHJldHVybiBub2RlRGVmYXVsdHNbcHJvcF07XG4gIH0sXG5cbiAgaW5qZWN0aW9uOiBET01Qcm9wZXJ0eUluamVjdGlvblxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBET01Qcm9wZXJ0eTtcblxufSkuY2FsbCh0aGlzLHJlcXVpcmUoJ19wcm9jZXNzJykpIiwiKGZ1bmN0aW9uIChwcm9jZXNzKXtcbi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBET01Qcm9wZXJ0eU9wZXJhdGlvbnNcbiAqIEB0eXBlY2hlY2tzIHN0YXRpYy1vbmx5XG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBET01Qcm9wZXJ0eSA9IHJlcXVpcmUoXCIuL0RPTVByb3BlcnR5XCIpO1xuXG52YXIgZXNjYXBlVGV4dEZvckJyb3dzZXIgPSByZXF1aXJlKFwiLi9lc2NhcGVUZXh0Rm9yQnJvd3NlclwiKTtcbnZhciBtZW1vaXplU3RyaW5nT25seSA9IHJlcXVpcmUoXCIuL21lbW9pemVTdHJpbmdPbmx5XCIpO1xudmFyIHdhcm5pbmcgPSByZXF1aXJlKFwiLi93YXJuaW5nXCIpO1xuXG5mdW5jdGlvbiBzaG91bGRJZ25vcmVWYWx1ZShuYW1lLCB2YWx1ZSkge1xuICByZXR1cm4gdmFsdWUgPT0gbnVsbCB8fFxuICAgIChET01Qcm9wZXJ0eS5oYXNCb29sZWFuVmFsdWVbbmFtZV0gJiYgIXZhbHVlKSB8fFxuICAgIChET01Qcm9wZXJ0eS5oYXNOdW1lcmljVmFsdWVbbmFtZV0gJiYgaXNOYU4odmFsdWUpKSB8fFxuICAgIChET01Qcm9wZXJ0eS5oYXNQb3NpdGl2ZU51bWVyaWNWYWx1ZVtuYW1lXSAmJiAodmFsdWUgPCAxKSkgfHxcbiAgICAoRE9NUHJvcGVydHkuaGFzT3ZlcmxvYWRlZEJvb2xlYW5WYWx1ZVtuYW1lXSAmJiB2YWx1ZSA9PT0gZmFsc2UpO1xufVxuXG52YXIgcHJvY2Vzc0F0dHJpYnV0ZU5hbWVBbmRQcmVmaXggPSBtZW1vaXplU3RyaW5nT25seShmdW5jdGlvbihuYW1lKSB7XG4gIHJldHVybiBlc2NhcGVUZXh0Rm9yQnJvd3NlcihuYW1lKSArICc9XCInO1xufSk7XG5cbmlmIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYpIHtcbiAgdmFyIHJlYWN0UHJvcHMgPSB7XG4gICAgY2hpbGRyZW46IHRydWUsXG4gICAgZGFuZ2Vyb3VzbHlTZXRJbm5lckhUTUw6IHRydWUsXG4gICAga2V5OiB0cnVlLFxuICAgIHJlZjogdHJ1ZVxuICB9O1xuICB2YXIgd2FybmVkUHJvcGVydGllcyA9IHt9O1xuXG4gIHZhciB3YXJuVW5rbm93blByb3BlcnR5ID0gZnVuY3Rpb24obmFtZSkge1xuICAgIGlmIChyZWFjdFByb3BzLmhhc093blByb3BlcnR5KG5hbWUpICYmIHJlYWN0UHJvcHNbbmFtZV0gfHxcbiAgICAgICAgd2FybmVkUHJvcGVydGllcy5oYXNPd25Qcm9wZXJ0eShuYW1lKSAmJiB3YXJuZWRQcm9wZXJ0aWVzW25hbWVdKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgd2FybmVkUHJvcGVydGllc1tuYW1lXSA9IHRydWU7XG4gICAgdmFyIGxvd2VyQ2FzZWROYW1lID0gbmFtZS50b0xvd2VyQ2FzZSgpO1xuXG4gICAgLy8gZGF0YS0qIGF0dHJpYnV0ZXMgc2hvdWxkIGJlIGxvd2VyY2FzZTsgc3VnZ2VzdCB0aGUgbG93ZXJjYXNlIHZlcnNpb25cbiAgICB2YXIgc3RhbmRhcmROYW1lID0gKFxuICAgICAgRE9NUHJvcGVydHkuaXNDdXN0b21BdHRyaWJ1dGUobG93ZXJDYXNlZE5hbWUpID9cbiAgICAgICAgbG93ZXJDYXNlZE5hbWUgOlxuICAgICAgRE9NUHJvcGVydHkuZ2V0UG9zc2libGVTdGFuZGFyZE5hbWUuaGFzT3duUHJvcGVydHkobG93ZXJDYXNlZE5hbWUpID9cbiAgICAgICAgRE9NUHJvcGVydHkuZ2V0UG9zc2libGVTdGFuZGFyZE5hbWVbbG93ZXJDYXNlZE5hbWVdIDpcbiAgICAgICAgbnVsbFxuICAgICk7XG5cbiAgICAvLyBGb3Igbm93LCBvbmx5IHdhcm4gd2hlbiB3ZSBoYXZlIGEgc3VnZ2VzdGVkIGNvcnJlY3Rpb24uIFRoaXMgcHJldmVudHNcbiAgICAvLyBsb2dnaW5nIHRvbyBtdWNoIHdoZW4gdXNpbmcgdHJhbnNmZXJQcm9wc1RvLlxuICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyB3YXJuaW5nKFxuICAgICAgc3RhbmRhcmROYW1lID09IG51bGwsXG4gICAgICAnVW5rbm93biBET00gcHJvcGVydHkgJyArIG5hbWUgKyAnLiBEaWQgeW91IG1lYW4gJyArIHN0YW5kYXJkTmFtZSArICc/J1xuICAgICkgOiBudWxsKTtcblxuICB9O1xufVxuXG4vKipcbiAqIE9wZXJhdGlvbnMgZm9yIGRlYWxpbmcgd2l0aCBET00gcHJvcGVydGllcy5cbiAqL1xudmFyIERPTVByb3BlcnR5T3BlcmF0aW9ucyA9IHtcblxuICAvKipcbiAgICogQ3JlYXRlcyBtYXJrdXAgZm9yIHRoZSBJRCBwcm9wZXJ0eS5cbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IGlkIFVuZXNjYXBlZCBJRC5cbiAgICogQHJldHVybiB7c3RyaW5nfSBNYXJrdXAgc3RyaW5nLlxuICAgKi9cbiAgY3JlYXRlTWFya3VwRm9ySUQ6IGZ1bmN0aW9uKGlkKSB7XG4gICAgcmV0dXJuIHByb2Nlc3NBdHRyaWJ1dGVOYW1lQW5kUHJlZml4KERPTVByb3BlcnR5LklEX0FUVFJJQlVURV9OQU1FKSArXG4gICAgICBlc2NhcGVUZXh0Rm9yQnJvd3NlcihpZCkgKyAnXCInO1xuICB9LFxuXG4gIC8qKlxuICAgKiBDcmVhdGVzIG1hcmt1cCBmb3IgYSBwcm9wZXJ0eS5cbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IG5hbWVcbiAgICogQHBhcmFtIHsqfSB2YWx1ZVxuICAgKiBAcmV0dXJuIHs/c3RyaW5nfSBNYXJrdXAgc3RyaW5nLCBvciBudWxsIGlmIHRoZSBwcm9wZXJ0eSB3YXMgaW52YWxpZC5cbiAgICovXG4gIGNyZWF0ZU1hcmt1cEZvclByb3BlcnR5OiBmdW5jdGlvbihuYW1lLCB2YWx1ZSkge1xuICAgIGlmIChET01Qcm9wZXJ0eS5pc1N0YW5kYXJkTmFtZS5oYXNPd25Qcm9wZXJ0eShuYW1lKSAmJlxuICAgICAgICBET01Qcm9wZXJ0eS5pc1N0YW5kYXJkTmFtZVtuYW1lXSkge1xuICAgICAgaWYgKHNob3VsZElnbm9yZVZhbHVlKG5hbWUsIHZhbHVlKSkge1xuICAgICAgICByZXR1cm4gJyc7XG4gICAgICB9XG4gICAgICB2YXIgYXR0cmlidXRlTmFtZSA9IERPTVByb3BlcnR5LmdldEF0dHJpYnV0ZU5hbWVbbmFtZV07XG4gICAgICBpZiAoRE9NUHJvcGVydHkuaGFzQm9vbGVhblZhbHVlW25hbWVdIHx8XG4gICAgICAgICAgKERPTVByb3BlcnR5Lmhhc092ZXJsb2FkZWRCb29sZWFuVmFsdWVbbmFtZV0gJiYgdmFsdWUgPT09IHRydWUpKSB7XG4gICAgICAgIHJldHVybiBlc2NhcGVUZXh0Rm9yQnJvd3NlcihhdHRyaWJ1dGVOYW1lKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBwcm9jZXNzQXR0cmlidXRlTmFtZUFuZFByZWZpeChhdHRyaWJ1dGVOYW1lKSArXG4gICAgICAgIGVzY2FwZVRleHRGb3JCcm93c2VyKHZhbHVlKSArICdcIic7XG4gICAgfSBlbHNlIGlmIChET01Qcm9wZXJ0eS5pc0N1c3RvbUF0dHJpYnV0ZShuYW1lKSkge1xuICAgICAgaWYgKHZhbHVlID09IG51bGwpIHtcbiAgICAgICAgcmV0dXJuICcnO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHByb2Nlc3NBdHRyaWJ1dGVOYW1lQW5kUHJlZml4KG5hbWUpICtcbiAgICAgICAgZXNjYXBlVGV4dEZvckJyb3dzZXIodmFsdWUpICsgJ1wiJztcbiAgICB9IGVsc2UgaWYgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOVikge1xuICAgICAgd2FyblVua25vd25Qcm9wZXJ0eShuYW1lKTtcbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG4gIH0sXG5cbiAgLyoqXG4gICAqIFNldHMgdGhlIHZhbHVlIGZvciBhIHByb3BlcnR5IG9uIGEgbm9kZS5cbiAgICpcbiAgICogQHBhcmFtIHtET01FbGVtZW50fSBub2RlXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lXG4gICAqIEBwYXJhbSB7Kn0gdmFsdWVcbiAgICovXG4gIHNldFZhbHVlRm9yUHJvcGVydHk6IGZ1bmN0aW9uKG5vZGUsIG5hbWUsIHZhbHVlKSB7XG4gICAgaWYgKERPTVByb3BlcnR5LmlzU3RhbmRhcmROYW1lLmhhc093blByb3BlcnR5KG5hbWUpICYmXG4gICAgICAgIERPTVByb3BlcnR5LmlzU3RhbmRhcmROYW1lW25hbWVdKSB7XG4gICAgICB2YXIgbXV0YXRpb25NZXRob2QgPSBET01Qcm9wZXJ0eS5nZXRNdXRhdGlvbk1ldGhvZFtuYW1lXTtcbiAgICAgIGlmIChtdXRhdGlvbk1ldGhvZCkge1xuICAgICAgICBtdXRhdGlvbk1ldGhvZChub2RlLCB2YWx1ZSk7XG4gICAgICB9IGVsc2UgaWYgKHNob3VsZElnbm9yZVZhbHVlKG5hbWUsIHZhbHVlKSkge1xuICAgICAgICB0aGlzLmRlbGV0ZVZhbHVlRm9yUHJvcGVydHkobm9kZSwgbmFtZSk7XG4gICAgICB9IGVsc2UgaWYgKERPTVByb3BlcnR5Lm11c3RVc2VBdHRyaWJ1dGVbbmFtZV0pIHtcbiAgICAgICAgLy8gYHNldEF0dHJpYnV0ZWAgd2l0aCBvYmplY3RzIGJlY29tZXMgb25seSBgW29iamVjdF1gIGluIElFOC85LFxuICAgICAgICAvLyAoJycgKyB2YWx1ZSkgbWFrZXMgaXQgb3V0cHV0IHRoZSBjb3JyZWN0IHRvU3RyaW5nKCktdmFsdWUuXG4gICAgICAgIG5vZGUuc2V0QXR0cmlidXRlKERPTVByb3BlcnR5LmdldEF0dHJpYnV0ZU5hbWVbbmFtZV0sICcnICsgdmFsdWUpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdmFyIHByb3BOYW1lID0gRE9NUHJvcGVydHkuZ2V0UHJvcGVydHlOYW1lW25hbWVdO1xuICAgICAgICAvLyBNdXN0IGV4cGxpY2l0bHkgY2FzdCB2YWx1ZXMgZm9yIEhBU19TSURFX0VGRkVDVFMtcHJvcGVydGllcyB0byB0aGVcbiAgICAgICAgLy8gcHJvcGVydHkgdHlwZSBiZWZvcmUgY29tcGFyaW5nOyBvbmx5IGB2YWx1ZWAgZG9lcyBhbmQgaXMgc3RyaW5nLlxuICAgICAgICBpZiAoIURPTVByb3BlcnR5Lmhhc1NpZGVFZmZlY3RzW25hbWVdIHx8XG4gICAgICAgICAgICAoJycgKyBub2RlW3Byb3BOYW1lXSkgIT09ICgnJyArIHZhbHVlKSkge1xuICAgICAgICAgIC8vIENvbnRyYXJ5IHRvIGBzZXRBdHRyaWJ1dGVgLCBvYmplY3QgcHJvcGVydGllcyBhcmUgcHJvcGVybHlcbiAgICAgICAgICAvLyBgdG9TdHJpbmdgZWQgYnkgSUU4LzkuXG4gICAgICAgICAgbm9kZVtwcm9wTmFtZV0gPSB2YWx1ZTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gZWxzZSBpZiAoRE9NUHJvcGVydHkuaXNDdXN0b21BdHRyaWJ1dGUobmFtZSkpIHtcbiAgICAgIGlmICh2YWx1ZSA9PSBudWxsKSB7XG4gICAgICAgIG5vZGUucmVtb3ZlQXR0cmlidXRlKG5hbWUpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgbm9kZS5zZXRBdHRyaWJ1dGUobmFtZSwgJycgKyB2YWx1ZSk7XG4gICAgICB9XG4gICAgfSBlbHNlIGlmIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYpIHtcbiAgICAgIHdhcm5Vbmtub3duUHJvcGVydHkobmFtZSk7XG4gICAgfVxuICB9LFxuXG4gIC8qKlxuICAgKiBEZWxldGVzIHRoZSB2YWx1ZSBmb3IgYSBwcm9wZXJ0eSBvbiBhIG5vZGUuXG4gICAqXG4gICAqIEBwYXJhbSB7RE9NRWxlbWVudH0gbm9kZVxuICAgKiBAcGFyYW0ge3N0cmluZ30gbmFtZVxuICAgKi9cbiAgZGVsZXRlVmFsdWVGb3JQcm9wZXJ0eTogZnVuY3Rpb24obm9kZSwgbmFtZSkge1xuICAgIGlmIChET01Qcm9wZXJ0eS5pc1N0YW5kYXJkTmFtZS5oYXNPd25Qcm9wZXJ0eShuYW1lKSAmJlxuICAgICAgICBET01Qcm9wZXJ0eS5pc1N0YW5kYXJkTmFtZVtuYW1lXSkge1xuICAgICAgdmFyIG11dGF0aW9uTWV0aG9kID0gRE9NUHJvcGVydHkuZ2V0TXV0YXRpb25NZXRob2RbbmFtZV07XG4gICAgICBpZiAobXV0YXRpb25NZXRob2QpIHtcbiAgICAgICAgbXV0YXRpb25NZXRob2Qobm9kZSwgdW5kZWZpbmVkKTtcbiAgICAgIH0gZWxzZSBpZiAoRE9NUHJvcGVydHkubXVzdFVzZUF0dHJpYnV0ZVtuYW1lXSkge1xuICAgICAgICBub2RlLnJlbW92ZUF0dHJpYnV0ZShET01Qcm9wZXJ0eS5nZXRBdHRyaWJ1dGVOYW1lW25hbWVdKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHZhciBwcm9wTmFtZSA9IERPTVByb3BlcnR5LmdldFByb3BlcnR5TmFtZVtuYW1lXTtcbiAgICAgICAgdmFyIGRlZmF1bHRWYWx1ZSA9IERPTVByb3BlcnR5LmdldERlZmF1bHRWYWx1ZUZvclByb3BlcnR5KFxuICAgICAgICAgIG5vZGUubm9kZU5hbWUsXG4gICAgICAgICAgcHJvcE5hbWVcbiAgICAgICAgKTtcbiAgICAgICAgaWYgKCFET01Qcm9wZXJ0eS5oYXNTaWRlRWZmZWN0c1tuYW1lXSB8fFxuICAgICAgICAgICAgKCcnICsgbm9kZVtwcm9wTmFtZV0pICE9PSBkZWZhdWx0VmFsdWUpIHtcbiAgICAgICAgICBub2RlW3Byb3BOYW1lXSA9IGRlZmF1bHRWYWx1ZTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gZWxzZSBpZiAoRE9NUHJvcGVydHkuaXNDdXN0b21BdHRyaWJ1dGUobmFtZSkpIHtcbiAgICAgIG5vZGUucmVtb3ZlQXR0cmlidXRlKG5hbWUpO1xuICAgIH0gZWxzZSBpZiAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WKSB7XG4gICAgICB3YXJuVW5rbm93blByb3BlcnR5KG5hbWUpO1xuICAgIH1cbiAgfVxuXG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IERPTVByb3BlcnR5T3BlcmF0aW9ucztcblxufSkuY2FsbCh0aGlzLHJlcXVpcmUoJ19wcm9jZXNzJykpIiwiKGZ1bmN0aW9uIChwcm9jZXNzKXtcbi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBEYW5nZXJcbiAqIEB0eXBlY2hlY2tzIHN0YXRpYy1vbmx5XG4gKi9cblxuLypqc2xpbnQgZXZpbDogdHJ1ZSwgc3ViOiB0cnVlICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgRXhlY3V0aW9uRW52aXJvbm1lbnQgPSByZXF1aXJlKFwiLi9FeGVjdXRpb25FbnZpcm9ubWVudFwiKTtcblxudmFyIGNyZWF0ZU5vZGVzRnJvbU1hcmt1cCA9IHJlcXVpcmUoXCIuL2NyZWF0ZU5vZGVzRnJvbU1hcmt1cFwiKTtcbnZhciBlbXB0eUZ1bmN0aW9uID0gcmVxdWlyZShcIi4vZW1wdHlGdW5jdGlvblwiKTtcbnZhciBnZXRNYXJrdXBXcmFwID0gcmVxdWlyZShcIi4vZ2V0TWFya3VwV3JhcFwiKTtcbnZhciBpbnZhcmlhbnQgPSByZXF1aXJlKFwiLi9pbnZhcmlhbnRcIik7XG5cbnZhciBPUEVOX1RBR19OQU1FX0VYUCA9IC9eKDxbXiBcXC8+XSspLztcbnZhciBSRVNVTFRfSU5ERVhfQVRUUiA9ICdkYXRhLWRhbmdlci1pbmRleCc7XG5cbi8qKlxuICogRXh0cmFjdHMgdGhlIGBub2RlTmFtZWAgZnJvbSBhIHN0cmluZyBvZiBtYXJrdXAuXG4gKlxuICogTk9URTogRXh0cmFjdGluZyB0aGUgYG5vZGVOYW1lYCBkb2VzIG5vdCByZXF1aXJlIGEgcmVndWxhciBleHByZXNzaW9uIG1hdGNoXG4gKiBiZWNhdXNlIHdlIG1ha2UgYXNzdW1wdGlvbnMgYWJvdXQgUmVhY3QtZ2VuZXJhdGVkIG1hcmt1cCAoaS5lLiB0aGVyZSBhcmUgbm9cbiAqIHNwYWNlcyBzdXJyb3VuZGluZyB0aGUgb3BlbmluZyB0YWcgYW5kIHRoZXJlIGlzIGF0IGxlYXN0IG9uZSBhdHRyaWJ1dGUpLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBtYXJrdXAgU3RyaW5nIG9mIG1hcmt1cC5cbiAqIEByZXR1cm4ge3N0cmluZ30gTm9kZSBuYW1lIG9mIHRoZSBzdXBwbGllZCBtYXJrdXAuXG4gKiBAc2VlIGh0dHA6Ly9qc3BlcmYuY29tL2V4dHJhY3Qtbm9kZW5hbWVcbiAqL1xuZnVuY3Rpb24gZ2V0Tm9kZU5hbWUobWFya3VwKSB7XG4gIHJldHVybiBtYXJrdXAuc3Vic3RyaW5nKDEsIG1hcmt1cC5pbmRleE9mKCcgJykpO1xufVxuXG52YXIgRGFuZ2VyID0ge1xuXG4gIC8qKlxuICAgKiBSZW5kZXJzIG1hcmt1cCBpbnRvIGFuIGFycmF5IG9mIG5vZGVzLiBUaGUgbWFya3VwIGlzIGV4cGVjdGVkIHRvIHJlbmRlclxuICAgKiBpbnRvIGEgbGlzdCBvZiByb290IG5vZGVzLiBBbHNvLCB0aGUgbGVuZ3RoIG9mIGByZXN1bHRMaXN0YCBhbmRcbiAgICogYG1hcmt1cExpc3RgIHNob3VsZCBiZSB0aGUgc2FtZS5cbiAgICpcbiAgICogQHBhcmFtIHthcnJheTxzdHJpbmc+fSBtYXJrdXBMaXN0IExpc3Qgb2YgbWFya3VwIHN0cmluZ3MgdG8gcmVuZGVyLlxuICAgKiBAcmV0dXJuIHthcnJheTxET01FbGVtZW50Pn0gTGlzdCBvZiByZW5kZXJlZCBub2Rlcy5cbiAgICogQGludGVybmFsXG4gICAqL1xuICBkYW5nZXJvdXNseVJlbmRlck1hcmt1cDogZnVuY3Rpb24obWFya3VwTGlzdCkge1xuICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICBFeGVjdXRpb25FbnZpcm9ubWVudC5jYW5Vc2VET00sXG4gICAgICAnZGFuZ2Vyb3VzbHlSZW5kZXJNYXJrdXAoLi4uKTogQ2Fubm90IHJlbmRlciBtYXJrdXAgaW4gYSB3b3JrZXIgJyArXG4gICAgICAndGhyZWFkLiBNYWtlIHN1cmUgYHdpbmRvd2AgYW5kIGBkb2N1bWVudGAgYXJlIGF2YWlsYWJsZSBnbG9iYWxseSAnICtcbiAgICAgICdiZWZvcmUgcmVxdWlyaW5nIFJlYWN0IHdoZW4gdW5pdCB0ZXN0aW5nIG9yIHVzZSAnICtcbiAgICAgICdSZWFjdC5yZW5kZXJUb1N0cmluZyBmb3Igc2VydmVyIHJlbmRlcmluZy4nXG4gICAgKSA6IGludmFyaWFudChFeGVjdXRpb25FbnZpcm9ubWVudC5jYW5Vc2VET00pKTtcbiAgICB2YXIgbm9kZU5hbWU7XG4gICAgdmFyIG1hcmt1cEJ5Tm9kZU5hbWUgPSB7fTtcbiAgICAvLyBHcm91cCBtYXJrdXAgYnkgYG5vZGVOYW1lYCBpZiBhIHdyYXAgaXMgbmVjZXNzYXJ5LCBlbHNlIGJ5ICcqJy5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IG1hcmt1cExpc3QubGVuZ3RoOyBpKyspIHtcbiAgICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICAgIG1hcmt1cExpc3RbaV0sXG4gICAgICAgICdkYW5nZXJvdXNseVJlbmRlck1hcmt1cCguLi4pOiBNaXNzaW5nIG1hcmt1cC4nXG4gICAgICApIDogaW52YXJpYW50KG1hcmt1cExpc3RbaV0pKTtcbiAgICAgIG5vZGVOYW1lID0gZ2V0Tm9kZU5hbWUobWFya3VwTGlzdFtpXSk7XG4gICAgICBub2RlTmFtZSA9IGdldE1hcmt1cFdyYXAobm9kZU5hbWUpID8gbm9kZU5hbWUgOiAnKic7XG4gICAgICBtYXJrdXBCeU5vZGVOYW1lW25vZGVOYW1lXSA9IG1hcmt1cEJ5Tm9kZU5hbWVbbm9kZU5hbWVdIHx8IFtdO1xuICAgICAgbWFya3VwQnlOb2RlTmFtZVtub2RlTmFtZV1baV0gPSBtYXJrdXBMaXN0W2ldO1xuICAgIH1cbiAgICB2YXIgcmVzdWx0TGlzdCA9IFtdO1xuICAgIHZhciByZXN1bHRMaXN0QXNzaWdubWVudENvdW50ID0gMDtcbiAgICBmb3IgKG5vZGVOYW1lIGluIG1hcmt1cEJ5Tm9kZU5hbWUpIHtcbiAgICAgIGlmICghbWFya3VwQnlOb2RlTmFtZS5oYXNPd25Qcm9wZXJ0eShub2RlTmFtZSkpIHtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG4gICAgICB2YXIgbWFya3VwTGlzdEJ5Tm9kZU5hbWUgPSBtYXJrdXBCeU5vZGVOYW1lW25vZGVOYW1lXTtcblxuICAgICAgLy8gVGhpcyBmb3ItaW4gbG9vcCBza2lwcyB0aGUgaG9sZXMgb2YgdGhlIHNwYXJzZSBhcnJheS4gVGhlIG9yZGVyIG9mXG4gICAgICAvLyBpdGVyYXRpb24gc2hvdWxkIGZvbGxvdyB0aGUgb3JkZXIgb2YgYXNzaWdubWVudCwgd2hpY2ggaGFwcGVucyB0byBtYXRjaFxuICAgICAgLy8gbnVtZXJpY2FsIGluZGV4IG9yZGVyLCBidXQgd2UgZG9uJ3QgcmVseSBvbiB0aGF0LlxuICAgICAgZm9yICh2YXIgcmVzdWx0SW5kZXggaW4gbWFya3VwTGlzdEJ5Tm9kZU5hbWUpIHtcbiAgICAgICAgaWYgKG1hcmt1cExpc3RCeU5vZGVOYW1lLmhhc093blByb3BlcnR5KHJlc3VsdEluZGV4KSkge1xuICAgICAgICAgIHZhciBtYXJrdXAgPSBtYXJrdXBMaXN0QnlOb2RlTmFtZVtyZXN1bHRJbmRleF07XG5cbiAgICAgICAgICAvLyBQdXNoIHRoZSByZXF1ZXN0ZWQgbWFya3VwIHdpdGggYW4gYWRkaXRpb25hbCBSRVNVTFRfSU5ERVhfQVRUUlxuICAgICAgICAgIC8vIGF0dHJpYnV0ZS4gIElmIHRoZSBtYXJrdXAgZG9lcyBub3Qgc3RhcnQgd2l0aCBhIDwgY2hhcmFjdGVyLCBpdFxuICAgICAgICAgIC8vIHdpbGwgYmUgZGlzY2FyZGVkIGJlbG93ICh3aXRoIGFuIGFwcHJvcHJpYXRlIGNvbnNvbGUuZXJyb3IpLlxuICAgICAgICAgIG1hcmt1cExpc3RCeU5vZGVOYW1lW3Jlc3VsdEluZGV4XSA9IG1hcmt1cC5yZXBsYWNlKFxuICAgICAgICAgICAgT1BFTl9UQUdfTkFNRV9FWFAsXG4gICAgICAgICAgICAvLyBUaGlzIGluZGV4IHdpbGwgYmUgcGFyc2VkIGJhY2sgb3V0IGJlbG93LlxuICAgICAgICAgICAgJyQxICcgKyBSRVNVTFRfSU5ERVhfQVRUUiArICc9XCInICsgcmVzdWx0SW5kZXggKyAnXCIgJ1xuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgLy8gUmVuZGVyIGVhY2ggZ3JvdXAgb2YgbWFya3VwIHdpdGggc2ltaWxhciB3cmFwcGluZyBgbm9kZU5hbWVgLlxuICAgICAgdmFyIHJlbmRlck5vZGVzID0gY3JlYXRlTm9kZXNGcm9tTWFya3VwKFxuICAgICAgICBtYXJrdXBMaXN0QnlOb2RlTmFtZS5qb2luKCcnKSxcbiAgICAgICAgZW1wdHlGdW5jdGlvbiAvLyBEbyBub3RoaW5nIHNwZWNpYWwgd2l0aCA8c2NyaXB0PiB0YWdzLlxuICAgICAgKTtcblxuICAgICAgZm9yIChpID0gMDsgaSA8IHJlbmRlck5vZGVzLmxlbmd0aDsgKytpKSB7XG4gICAgICAgIHZhciByZW5kZXJOb2RlID0gcmVuZGVyTm9kZXNbaV07XG4gICAgICAgIGlmIChyZW5kZXJOb2RlLmhhc0F0dHJpYnV0ZSAmJlxuICAgICAgICAgICAgcmVuZGVyTm9kZS5oYXNBdHRyaWJ1dGUoUkVTVUxUX0lOREVYX0FUVFIpKSB7XG5cbiAgICAgICAgICByZXN1bHRJbmRleCA9ICtyZW5kZXJOb2RlLmdldEF0dHJpYnV0ZShSRVNVTFRfSU5ERVhfQVRUUik7XG4gICAgICAgICAgcmVuZGVyTm9kZS5yZW1vdmVBdHRyaWJ1dGUoUkVTVUxUX0lOREVYX0FUVFIpO1xuXG4gICAgICAgICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgICAgICAgICFyZXN1bHRMaXN0Lmhhc093blByb3BlcnR5KHJlc3VsdEluZGV4KSxcbiAgICAgICAgICAgICdEYW5nZXI6IEFzc2lnbmluZyB0byBhbiBhbHJlYWR5LW9jY3VwaWVkIHJlc3VsdCBpbmRleC4nXG4gICAgICAgICAgKSA6IGludmFyaWFudCghcmVzdWx0TGlzdC5oYXNPd25Qcm9wZXJ0eShyZXN1bHRJbmRleCkpKTtcblxuICAgICAgICAgIHJlc3VsdExpc3RbcmVzdWx0SW5kZXhdID0gcmVuZGVyTm9kZTtcblxuICAgICAgICAgIC8vIFRoaXMgc2hvdWxkIG1hdGNoIHJlc3VsdExpc3QubGVuZ3RoIGFuZCBtYXJrdXBMaXN0Lmxlbmd0aCB3aGVuXG4gICAgICAgICAgLy8gd2UncmUgZG9uZS5cbiAgICAgICAgICByZXN1bHRMaXN0QXNzaWdubWVudENvdW50ICs9IDE7XG5cbiAgICAgICAgfSBlbHNlIGlmIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYpIHtcbiAgICAgICAgICBjb25zb2xlLmVycm9yKFxuICAgICAgICAgICAgXCJEYW5nZXI6IERpc2NhcmRpbmcgdW5leHBlY3RlZCBub2RlOlwiLFxuICAgICAgICAgICAgcmVuZGVyTm9kZVxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBBbHRob3VnaCByZXN1bHRMaXN0IHdhcyBwb3B1bGF0ZWQgb3V0IG9mIG9yZGVyLCBpdCBzaG91bGQgbm93IGJlIGEgZGVuc2VcbiAgICAvLyBhcnJheS5cbiAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgcmVzdWx0TGlzdEFzc2lnbm1lbnRDb3VudCA9PT0gcmVzdWx0TGlzdC5sZW5ndGgsXG4gICAgICAnRGFuZ2VyOiBEaWQgbm90IGFzc2lnbiB0byBldmVyeSBpbmRleCBvZiByZXN1bHRMaXN0LidcbiAgICApIDogaW52YXJpYW50KHJlc3VsdExpc3RBc3NpZ25tZW50Q291bnQgPT09IHJlc3VsdExpc3QubGVuZ3RoKSk7XG5cbiAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgcmVzdWx0TGlzdC5sZW5ndGggPT09IG1hcmt1cExpc3QubGVuZ3RoLFxuICAgICAgJ0RhbmdlcjogRXhwZWN0ZWQgbWFya3VwIHRvIHJlbmRlciAlcyBub2RlcywgYnV0IHJlbmRlcmVkICVzLicsXG4gICAgICBtYXJrdXBMaXN0Lmxlbmd0aCxcbiAgICAgIHJlc3VsdExpc3QubGVuZ3RoXG4gICAgKSA6IGludmFyaWFudChyZXN1bHRMaXN0Lmxlbmd0aCA9PT0gbWFya3VwTGlzdC5sZW5ndGgpKTtcblxuICAgIHJldHVybiByZXN1bHRMaXN0O1xuICB9LFxuXG4gIC8qKlxuICAgKiBSZXBsYWNlcyBhIG5vZGUgd2l0aCBhIHN0cmluZyBvZiBtYXJrdXAgYXQgaXRzIGN1cnJlbnQgcG9zaXRpb24gd2l0aGluIGl0c1xuICAgKiBwYXJlbnQuIFRoZSBtYXJrdXAgbXVzdCByZW5kZXIgaW50byBhIHNpbmdsZSByb290IG5vZGUuXG4gICAqXG4gICAqIEBwYXJhbSB7RE9NRWxlbWVudH0gb2xkQ2hpbGQgQ2hpbGQgbm9kZSB0byByZXBsYWNlLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gbWFya3VwIE1hcmt1cCB0byByZW5kZXIgaW4gcGxhY2Ugb2YgdGhlIGNoaWxkIG5vZGUuXG4gICAqIEBpbnRlcm5hbFxuICAgKi9cbiAgZGFuZ2Vyb3VzbHlSZXBsYWNlTm9kZVdpdGhNYXJrdXA6IGZ1bmN0aW9uKG9sZENoaWxkLCBtYXJrdXApIHtcbiAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgRXhlY3V0aW9uRW52aXJvbm1lbnQuY2FuVXNlRE9NLFxuICAgICAgJ2Rhbmdlcm91c2x5UmVwbGFjZU5vZGVXaXRoTWFya3VwKC4uLik6IENhbm5vdCByZW5kZXIgbWFya3VwIGluIGEgJyArXG4gICAgICAnd29ya2VyIHRocmVhZC4gTWFrZSBzdXJlIGB3aW5kb3dgIGFuZCBgZG9jdW1lbnRgIGFyZSBhdmFpbGFibGUgJyArXG4gICAgICAnZ2xvYmFsbHkgYmVmb3JlIHJlcXVpcmluZyBSZWFjdCB3aGVuIHVuaXQgdGVzdGluZyBvciB1c2UgJyArXG4gICAgICAnUmVhY3QucmVuZGVyVG9TdHJpbmcgZm9yIHNlcnZlciByZW5kZXJpbmcuJ1xuICAgICkgOiBpbnZhcmlhbnQoRXhlY3V0aW9uRW52aXJvbm1lbnQuY2FuVXNlRE9NKSk7XG4gICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChtYXJrdXAsICdkYW5nZXJvdXNseVJlcGxhY2VOb2RlV2l0aE1hcmt1cCguLi4pOiBNaXNzaW5nIG1hcmt1cC4nKSA6IGludmFyaWFudChtYXJrdXApKTtcbiAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgb2xkQ2hpbGQudGFnTmFtZS50b0xvd2VyQ2FzZSgpICE9PSAnaHRtbCcsXG4gICAgICAnZGFuZ2Vyb3VzbHlSZXBsYWNlTm9kZVdpdGhNYXJrdXAoLi4uKTogQ2Fubm90IHJlcGxhY2UgbWFya3VwIG9mIHRoZSAnICtcbiAgICAgICc8aHRtbD4gbm9kZS4gVGhpcyBpcyBiZWNhdXNlIGJyb3dzZXIgcXVpcmtzIG1ha2UgdGhpcyB1bnJlbGlhYmxlICcgK1xuICAgICAgJ2FuZC9vciBzbG93LiBJZiB5b3Ugd2FudCB0byByZW5kZXIgdG8gdGhlIHJvb3QgeW91IG11c3QgdXNlICcgK1xuICAgICAgJ3NlcnZlciByZW5kZXJpbmcuIFNlZSByZW5kZXJDb21wb25lbnRUb1N0cmluZygpLidcbiAgICApIDogaW52YXJpYW50KG9sZENoaWxkLnRhZ05hbWUudG9Mb3dlckNhc2UoKSAhPT0gJ2h0bWwnKSk7XG5cbiAgICB2YXIgbmV3Q2hpbGQgPSBjcmVhdGVOb2Rlc0Zyb21NYXJrdXAobWFya3VwLCBlbXB0eUZ1bmN0aW9uKVswXTtcbiAgICBvbGRDaGlsZC5wYXJlbnROb2RlLnJlcGxhY2VDaGlsZChuZXdDaGlsZCwgb2xkQ2hpbGQpO1xuICB9XG5cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gRGFuZ2VyO1xuXG59KS5jYWxsKHRoaXMscmVxdWlyZSgnX3Byb2Nlc3MnKSkiLCIvKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgRGVmYXVsdEV2ZW50UGx1Z2luT3JkZXJcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxuIHZhciBrZXlPZiA9IHJlcXVpcmUoXCIuL2tleU9mXCIpO1xuXG4vKipcbiAqIE1vZHVsZSB0aGF0IGlzIGluamVjdGFibGUgaW50byBgRXZlbnRQbHVnaW5IdWJgLCB0aGF0IHNwZWNpZmllcyBhXG4gKiBkZXRlcm1pbmlzdGljIG9yZGVyaW5nIG9mIGBFdmVudFBsdWdpbmBzLiBBIGNvbnZlbmllbnQgd2F5IHRvIHJlYXNvbiBhYm91dFxuICogcGx1Z2lucywgd2l0aG91dCBoYXZpbmcgdG8gcGFja2FnZSBldmVyeSBvbmUgb2YgdGhlbS4gVGhpcyBpcyBiZXR0ZXIgdGhhblxuICogaGF2aW5nIHBsdWdpbnMgYmUgb3JkZXJlZCBpbiB0aGUgc2FtZSBvcmRlciB0aGF0IHRoZXkgYXJlIGluamVjdGVkIGJlY2F1c2VcbiAqIHRoYXQgb3JkZXJpbmcgd291bGQgYmUgaW5mbHVlbmNlZCBieSB0aGUgcGFja2FnaW5nIG9yZGVyLlxuICogYFJlc3BvbmRlckV2ZW50UGx1Z2luYCBtdXN0IG9jY3VyIGJlZm9yZSBgU2ltcGxlRXZlbnRQbHVnaW5gIHNvIHRoYXRcbiAqIHByZXZlbnRpbmcgZGVmYXVsdCBvbiBldmVudHMgaXMgY29udmVuaWVudCBpbiBgU2ltcGxlRXZlbnRQbHVnaW5gIGhhbmRsZXJzLlxuICovXG52YXIgRGVmYXVsdEV2ZW50UGx1Z2luT3JkZXIgPSBbXG4gIGtleU9mKHtSZXNwb25kZXJFdmVudFBsdWdpbjogbnVsbH0pLFxuICBrZXlPZih7U2ltcGxlRXZlbnRQbHVnaW46IG51bGx9KSxcbiAga2V5T2Yoe1RhcEV2ZW50UGx1Z2luOiBudWxsfSksXG4gIGtleU9mKHtFbnRlckxlYXZlRXZlbnRQbHVnaW46IG51bGx9KSxcbiAga2V5T2Yoe0NoYW5nZUV2ZW50UGx1Z2luOiBudWxsfSksXG4gIGtleU9mKHtTZWxlY3RFdmVudFBsdWdpbjogbnVsbH0pLFxuICBrZXlPZih7Q29tcG9zaXRpb25FdmVudFBsdWdpbjogbnVsbH0pLFxuICBrZXlPZih7QmVmb3JlSW5wdXRFdmVudFBsdWdpbjogbnVsbH0pLFxuICBrZXlPZih7QW5hbHl0aWNzRXZlbnRQbHVnaW46IG51bGx9KSxcbiAga2V5T2Yoe01vYmlsZVNhZmFyaUNsaWNrRXZlbnRQbHVnaW46IG51bGx9KVxuXTtcblxubW9kdWxlLmV4cG9ydHMgPSBEZWZhdWx0RXZlbnRQbHVnaW5PcmRlcjtcbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBFbnRlckxlYXZlRXZlbnRQbHVnaW5cbiAqIEB0eXBlY2hlY2tzIHN0YXRpYy1vbmx5XG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBFdmVudENvbnN0YW50cyA9IHJlcXVpcmUoXCIuL0V2ZW50Q29uc3RhbnRzXCIpO1xudmFyIEV2ZW50UHJvcGFnYXRvcnMgPSByZXF1aXJlKFwiLi9FdmVudFByb3BhZ2F0b3JzXCIpO1xudmFyIFN5bnRoZXRpY01vdXNlRXZlbnQgPSByZXF1aXJlKFwiLi9TeW50aGV0aWNNb3VzZUV2ZW50XCIpO1xuXG52YXIgUmVhY3RNb3VudCA9IHJlcXVpcmUoXCIuL1JlYWN0TW91bnRcIik7XG52YXIga2V5T2YgPSByZXF1aXJlKFwiLi9rZXlPZlwiKTtcblxudmFyIHRvcExldmVsVHlwZXMgPSBFdmVudENvbnN0YW50cy50b3BMZXZlbFR5cGVzO1xudmFyIGdldEZpcnN0UmVhY3RET00gPSBSZWFjdE1vdW50LmdldEZpcnN0UmVhY3RET007XG5cbnZhciBldmVudFR5cGVzID0ge1xuICBtb3VzZUVudGVyOiB7XG4gICAgcmVnaXN0cmF0aW9uTmFtZToga2V5T2Yoe29uTW91c2VFbnRlcjogbnVsbH0pLFxuICAgIGRlcGVuZGVuY2llczogW1xuICAgICAgdG9wTGV2ZWxUeXBlcy50b3BNb3VzZU91dCxcbiAgICAgIHRvcExldmVsVHlwZXMudG9wTW91c2VPdmVyXG4gICAgXVxuICB9LFxuICBtb3VzZUxlYXZlOiB7XG4gICAgcmVnaXN0cmF0aW9uTmFtZToga2V5T2Yoe29uTW91c2VMZWF2ZTogbnVsbH0pLFxuICAgIGRlcGVuZGVuY2llczogW1xuICAgICAgdG9wTGV2ZWxUeXBlcy50b3BNb3VzZU91dCxcbiAgICAgIHRvcExldmVsVHlwZXMudG9wTW91c2VPdmVyXG4gICAgXVxuICB9XG59O1xuXG52YXIgZXh0cmFjdGVkRXZlbnRzID0gW251bGwsIG51bGxdO1xuXG52YXIgRW50ZXJMZWF2ZUV2ZW50UGx1Z2luID0ge1xuXG4gIGV2ZW50VHlwZXM6IGV2ZW50VHlwZXMsXG5cbiAgLyoqXG4gICAqIEZvciBhbG1vc3QgZXZlcnkgaW50ZXJhY3Rpb24gd2UgY2FyZSBhYm91dCwgdGhlcmUgd2lsbCBiZSBib3RoIGEgdG9wLWxldmVsXG4gICAqIGBtb3VzZW92ZXJgIGFuZCBgbW91c2VvdXRgIGV2ZW50IHRoYXQgb2NjdXJzLiBPbmx5IHVzZSBgbW91c2VvdXRgIHNvIHRoYXRcbiAgICogd2UgZG8gbm90IGV4dHJhY3QgZHVwbGljYXRlIGV2ZW50cy4gSG93ZXZlciwgbW92aW5nIHRoZSBtb3VzZSBpbnRvIHRoZVxuICAgKiBicm93c2VyIGZyb20gb3V0c2lkZSB3aWxsIG5vdCBmaXJlIGEgYG1vdXNlb3V0YCBldmVudC4gSW4gdGhpcyBjYXNlLCB3ZSB1c2VcbiAgICogdGhlIGBtb3VzZW92ZXJgIHRvcC1sZXZlbCBldmVudC5cbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IHRvcExldmVsVHlwZSBSZWNvcmQgZnJvbSBgRXZlbnRDb25zdGFudHNgLlxuICAgKiBAcGFyYW0ge0RPTUV2ZW50VGFyZ2V0fSB0b3BMZXZlbFRhcmdldCBUaGUgbGlzdGVuaW5nIGNvbXBvbmVudCByb290IG5vZGUuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB0b3BMZXZlbFRhcmdldElEIElEIG9mIGB0b3BMZXZlbFRhcmdldGAuXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBuYXRpdmVFdmVudCBOYXRpdmUgYnJvd3NlciBldmVudC5cbiAgICogQHJldHVybiB7Kn0gQW4gYWNjdW11bGF0aW9uIG9mIHN5bnRoZXRpYyBldmVudHMuXG4gICAqIEBzZWUge0V2ZW50UGx1Z2luSHViLmV4dHJhY3RFdmVudHN9XG4gICAqL1xuICBleHRyYWN0RXZlbnRzOiBmdW5jdGlvbihcbiAgICAgIHRvcExldmVsVHlwZSxcbiAgICAgIHRvcExldmVsVGFyZ2V0LFxuICAgICAgdG9wTGV2ZWxUYXJnZXRJRCxcbiAgICAgIG5hdGl2ZUV2ZW50KSB7XG4gICAgaWYgKHRvcExldmVsVHlwZSA9PT0gdG9wTGV2ZWxUeXBlcy50b3BNb3VzZU92ZXIgJiZcbiAgICAgICAgKG5hdGl2ZUV2ZW50LnJlbGF0ZWRUYXJnZXQgfHwgbmF0aXZlRXZlbnQuZnJvbUVsZW1lbnQpKSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG4gICAgaWYgKHRvcExldmVsVHlwZSAhPT0gdG9wTGV2ZWxUeXBlcy50b3BNb3VzZU91dCAmJlxuICAgICAgICB0b3BMZXZlbFR5cGUgIT09IHRvcExldmVsVHlwZXMudG9wTW91c2VPdmVyKSB7XG4gICAgICAvLyBNdXN0IG5vdCBiZSBhIG1vdXNlIGluIG9yIG1vdXNlIG91dCAtIGlnbm9yaW5nLlxuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgdmFyIHdpbjtcbiAgICBpZiAodG9wTGV2ZWxUYXJnZXQud2luZG93ID09PSB0b3BMZXZlbFRhcmdldCkge1xuICAgICAgLy8gYHRvcExldmVsVGFyZ2V0YCBpcyBwcm9iYWJseSBhIHdpbmRvdyBvYmplY3QuXG4gICAgICB3aW4gPSB0b3BMZXZlbFRhcmdldDtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gVE9ETzogRmlndXJlIG91dCB3aHkgYG93bmVyRG9jdW1lbnRgIGlzIHNvbWV0aW1lcyB1bmRlZmluZWQgaW4gSUU4LlxuICAgICAgdmFyIGRvYyA9IHRvcExldmVsVGFyZ2V0Lm93bmVyRG9jdW1lbnQ7XG4gICAgICBpZiAoZG9jKSB7XG4gICAgICAgIHdpbiA9IGRvYy5kZWZhdWx0VmlldyB8fCBkb2MucGFyZW50V2luZG93O1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgd2luID0gd2luZG93O1xuICAgICAgfVxuICAgIH1cblxuICAgIHZhciBmcm9tLCB0bztcbiAgICBpZiAodG9wTGV2ZWxUeXBlID09PSB0b3BMZXZlbFR5cGVzLnRvcE1vdXNlT3V0KSB7XG4gICAgICBmcm9tID0gdG9wTGV2ZWxUYXJnZXQ7XG4gICAgICB0byA9XG4gICAgICAgIGdldEZpcnN0UmVhY3RET00obmF0aXZlRXZlbnQucmVsYXRlZFRhcmdldCB8fCBuYXRpdmVFdmVudC50b0VsZW1lbnQpIHx8XG4gICAgICAgIHdpbjtcbiAgICB9IGVsc2Uge1xuICAgICAgZnJvbSA9IHdpbjtcbiAgICAgIHRvID0gdG9wTGV2ZWxUYXJnZXQ7XG4gICAgfVxuXG4gICAgaWYgKGZyb20gPT09IHRvKSB7XG4gICAgICAvLyBOb3RoaW5nIHBlcnRhaW5zIHRvIG91ciBtYW5hZ2VkIGNvbXBvbmVudHMuXG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICB2YXIgZnJvbUlEID0gZnJvbSA/IFJlYWN0TW91bnQuZ2V0SUQoZnJvbSkgOiAnJztcbiAgICB2YXIgdG9JRCA9IHRvID8gUmVhY3RNb3VudC5nZXRJRCh0bykgOiAnJztcblxuICAgIHZhciBsZWF2ZSA9IFN5bnRoZXRpY01vdXNlRXZlbnQuZ2V0UG9vbGVkKFxuICAgICAgZXZlbnRUeXBlcy5tb3VzZUxlYXZlLFxuICAgICAgZnJvbUlELFxuICAgICAgbmF0aXZlRXZlbnRcbiAgICApO1xuICAgIGxlYXZlLnR5cGUgPSAnbW91c2VsZWF2ZSc7XG4gICAgbGVhdmUudGFyZ2V0ID0gZnJvbTtcbiAgICBsZWF2ZS5yZWxhdGVkVGFyZ2V0ID0gdG87XG5cbiAgICB2YXIgZW50ZXIgPSBTeW50aGV0aWNNb3VzZUV2ZW50LmdldFBvb2xlZChcbiAgICAgIGV2ZW50VHlwZXMubW91c2VFbnRlcixcbiAgICAgIHRvSUQsXG4gICAgICBuYXRpdmVFdmVudFxuICAgICk7XG4gICAgZW50ZXIudHlwZSA9ICdtb3VzZWVudGVyJztcbiAgICBlbnRlci50YXJnZXQgPSB0bztcbiAgICBlbnRlci5yZWxhdGVkVGFyZ2V0ID0gZnJvbTtcblxuICAgIEV2ZW50UHJvcGFnYXRvcnMuYWNjdW11bGF0ZUVudGVyTGVhdmVEaXNwYXRjaGVzKGxlYXZlLCBlbnRlciwgZnJvbUlELCB0b0lEKTtcblxuICAgIGV4dHJhY3RlZEV2ZW50c1swXSA9IGxlYXZlO1xuICAgIGV4dHJhY3RlZEV2ZW50c1sxXSA9IGVudGVyO1xuXG4gICAgcmV0dXJuIGV4dHJhY3RlZEV2ZW50cztcbiAgfVxuXG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IEVudGVyTGVhdmVFdmVudFBsdWdpbjtcbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBFdmVudENvbnN0YW50c1xuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIga2V5TWlycm9yID0gcmVxdWlyZShcIi4va2V5TWlycm9yXCIpO1xuXG52YXIgUHJvcGFnYXRpb25QaGFzZXMgPSBrZXlNaXJyb3Ioe2J1YmJsZWQ6IG51bGwsIGNhcHR1cmVkOiBudWxsfSk7XG5cbi8qKlxuICogVHlwZXMgb2YgcmF3IHNpZ25hbHMgZnJvbSB0aGUgYnJvd3NlciBjYXVnaHQgYXQgdGhlIHRvcCBsZXZlbC5cbiAqL1xudmFyIHRvcExldmVsVHlwZXMgPSBrZXlNaXJyb3Ioe1xuICB0b3BCbHVyOiBudWxsLFxuICB0b3BDaGFuZ2U6IG51bGwsXG4gIHRvcENsaWNrOiBudWxsLFxuICB0b3BDb21wb3NpdGlvbkVuZDogbnVsbCxcbiAgdG9wQ29tcG9zaXRpb25TdGFydDogbnVsbCxcbiAgdG9wQ29tcG9zaXRpb25VcGRhdGU6IG51bGwsXG4gIHRvcENvbnRleHRNZW51OiBudWxsLFxuICB0b3BDb3B5OiBudWxsLFxuICB0b3BDdXQ6IG51bGwsXG4gIHRvcERvdWJsZUNsaWNrOiBudWxsLFxuICB0b3BEcmFnOiBudWxsLFxuICB0b3BEcmFnRW5kOiBudWxsLFxuICB0b3BEcmFnRW50ZXI6IG51bGwsXG4gIHRvcERyYWdFeGl0OiBudWxsLFxuICB0b3BEcmFnTGVhdmU6IG51bGwsXG4gIHRvcERyYWdPdmVyOiBudWxsLFxuICB0b3BEcmFnU3RhcnQ6IG51bGwsXG4gIHRvcERyb3A6IG51bGwsXG4gIHRvcEVycm9yOiBudWxsLFxuICB0b3BGb2N1czogbnVsbCxcbiAgdG9wSW5wdXQ6IG51bGwsXG4gIHRvcEtleURvd246IG51bGwsXG4gIHRvcEtleVByZXNzOiBudWxsLFxuICB0b3BLZXlVcDogbnVsbCxcbiAgdG9wTG9hZDogbnVsbCxcbiAgdG9wTW91c2VEb3duOiBudWxsLFxuICB0b3BNb3VzZU1vdmU6IG51bGwsXG4gIHRvcE1vdXNlT3V0OiBudWxsLFxuICB0b3BNb3VzZU92ZXI6IG51bGwsXG4gIHRvcE1vdXNlVXA6IG51bGwsXG4gIHRvcFBhc3RlOiBudWxsLFxuICB0b3BSZXNldDogbnVsbCxcbiAgdG9wU2Nyb2xsOiBudWxsLFxuICB0b3BTZWxlY3Rpb25DaGFuZ2U6IG51bGwsXG4gIHRvcFN1Ym1pdDogbnVsbCxcbiAgdG9wVGV4dElucHV0OiBudWxsLFxuICB0b3BUb3VjaENhbmNlbDogbnVsbCxcbiAgdG9wVG91Y2hFbmQ6IG51bGwsXG4gIHRvcFRvdWNoTW92ZTogbnVsbCxcbiAgdG9wVG91Y2hTdGFydDogbnVsbCxcbiAgdG9wV2hlZWw6IG51bGxcbn0pO1xuXG52YXIgRXZlbnRDb25zdGFudHMgPSB7XG4gIHRvcExldmVsVHlwZXM6IHRvcExldmVsVHlwZXMsXG4gIFByb3BhZ2F0aW9uUGhhc2VzOiBQcm9wYWdhdGlvblBoYXNlc1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSBFdmVudENvbnN0YW50cztcbiIsIihmdW5jdGlvbiAocHJvY2Vzcyl7XG4vKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQgRmFjZWJvb2ssIEluYy5cbiAqXG4gKiBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgXCJMaWNlbnNlXCIpO1xuICogeW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLlxuICogWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0XG4gKlxuICogaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXG4gKlxuICogVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZVxuICogZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gXCJBUyBJU1wiIEJBU0lTLFxuICogV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuXG4gKiBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kXG4gKiBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgRXZlbnRMaXN0ZW5lclxuICogQHR5cGVjaGVja3NcbiAqL1xuXG52YXIgZW1wdHlGdW5jdGlvbiA9IHJlcXVpcmUoXCIuL2VtcHR5RnVuY3Rpb25cIik7XG5cbi8qKlxuICogVXBzdHJlYW0gdmVyc2lvbiBvZiBldmVudCBsaXN0ZW5lci4gRG9lcyBub3QgdGFrZSBpbnRvIGFjY291bnQgc3BlY2lmaWNcbiAqIG5hdHVyZSBvZiBwbGF0Zm9ybS5cbiAqL1xudmFyIEV2ZW50TGlzdGVuZXIgPSB7XG4gIC8qKlxuICAgKiBMaXN0ZW4gdG8gRE9NIGV2ZW50cyBkdXJpbmcgdGhlIGJ1YmJsZSBwaGFzZS5cbiAgICpcbiAgICogQHBhcmFtIHtET01FdmVudFRhcmdldH0gdGFyZ2V0IERPTSBlbGVtZW50IHRvIHJlZ2lzdGVyIGxpc3RlbmVyIG9uLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gZXZlbnRUeXBlIEV2ZW50IHR5cGUsIGUuZy4gJ2NsaWNrJyBvciAnbW91c2VvdmVyJy5cbiAgICogQHBhcmFtIHtmdW5jdGlvbn0gY2FsbGJhY2sgQ2FsbGJhY2sgZnVuY3Rpb24uXG4gICAqIEByZXR1cm4ge29iamVjdH0gT2JqZWN0IHdpdGggYSBgcmVtb3ZlYCBtZXRob2QuXG4gICAqL1xuICBsaXN0ZW46IGZ1bmN0aW9uKHRhcmdldCwgZXZlbnRUeXBlLCBjYWxsYmFjaykge1xuICAgIGlmICh0YXJnZXQuYWRkRXZlbnRMaXN0ZW5lcikge1xuICAgICAgdGFyZ2V0LmFkZEV2ZW50TGlzdGVuZXIoZXZlbnRUeXBlLCBjYWxsYmFjaywgZmFsc2UpO1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgcmVtb3ZlOiBmdW5jdGlvbigpIHtcbiAgICAgICAgICB0YXJnZXQucmVtb3ZlRXZlbnRMaXN0ZW5lcihldmVudFR5cGUsIGNhbGxiYWNrLCBmYWxzZSk7XG4gICAgICAgIH1cbiAgICAgIH07XG4gICAgfSBlbHNlIGlmICh0YXJnZXQuYXR0YWNoRXZlbnQpIHtcbiAgICAgIHRhcmdldC5hdHRhY2hFdmVudCgnb24nICsgZXZlbnRUeXBlLCBjYWxsYmFjayk7XG4gICAgICByZXR1cm4ge1xuICAgICAgICByZW1vdmU6IGZ1bmN0aW9uKCkge1xuICAgICAgICAgIHRhcmdldC5kZXRhY2hFdmVudCgnb24nICsgZXZlbnRUeXBlLCBjYWxsYmFjayk7XG4gICAgICAgIH1cbiAgICAgIH07XG4gICAgfVxuICB9LFxuXG4gIC8qKlxuICAgKiBMaXN0ZW4gdG8gRE9NIGV2ZW50cyBkdXJpbmcgdGhlIGNhcHR1cmUgcGhhc2UuXG4gICAqXG4gICAqIEBwYXJhbSB7RE9NRXZlbnRUYXJnZXR9IHRhcmdldCBET00gZWxlbWVudCB0byByZWdpc3RlciBsaXN0ZW5lciBvbi5cbiAgICogQHBhcmFtIHtzdHJpbmd9IGV2ZW50VHlwZSBFdmVudCB0eXBlLCBlLmcuICdjbGljaycgb3IgJ21vdXNlb3ZlcicuXG4gICAqIEBwYXJhbSB7ZnVuY3Rpb259IGNhbGxiYWNrIENhbGxiYWNrIGZ1bmN0aW9uLlxuICAgKiBAcmV0dXJuIHtvYmplY3R9IE9iamVjdCB3aXRoIGEgYHJlbW92ZWAgbWV0aG9kLlxuICAgKi9cbiAgY2FwdHVyZTogZnVuY3Rpb24odGFyZ2V0LCBldmVudFR5cGUsIGNhbGxiYWNrKSB7XG4gICAgaWYgKCF0YXJnZXQuYWRkRXZlbnRMaXN0ZW5lcikge1xuICAgICAgaWYgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOVikge1xuICAgICAgICBjb25zb2xlLmVycm9yKFxuICAgICAgICAgICdBdHRlbXB0ZWQgdG8gbGlzdGVuIHRvIGV2ZW50cyBkdXJpbmcgdGhlIGNhcHR1cmUgcGhhc2Ugb24gYSAnICtcbiAgICAgICAgICAnYnJvd3NlciB0aGF0IGRvZXMgbm90IHN1cHBvcnQgdGhlIGNhcHR1cmUgcGhhc2UuIFlvdXIgYXBwbGljYXRpb24gJyArXG4gICAgICAgICAgJ3dpbGwgbm90IHJlY2VpdmUgc29tZSBldmVudHMuJ1xuICAgICAgICApO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgcmVtb3ZlOiBlbXB0eUZ1bmN0aW9uXG4gICAgICB9O1xuICAgIH0gZWxzZSB7XG4gICAgICB0YXJnZXQuYWRkRXZlbnRMaXN0ZW5lcihldmVudFR5cGUsIGNhbGxiYWNrLCB0cnVlKTtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHJlbW92ZTogZnVuY3Rpb24oKSB7XG4gICAgICAgICAgdGFyZ2V0LnJlbW92ZUV2ZW50TGlzdGVuZXIoZXZlbnRUeXBlLCBjYWxsYmFjaywgdHJ1ZSk7XG4gICAgICAgIH1cbiAgICAgIH07XG4gICAgfVxuICB9LFxuXG4gIHJlZ2lzdGVyRGVmYXVsdDogZnVuY3Rpb24oKSB7fVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBFdmVudExpc3RlbmVyO1xuXG59KS5jYWxsKHRoaXMscmVxdWlyZSgnX3Byb2Nlc3MnKSkiLCIoZnVuY3Rpb24gKHByb2Nlc3Mpe1xuLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIEV2ZW50UGx1Z2luSHViXG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBFdmVudFBsdWdpblJlZ2lzdHJ5ID0gcmVxdWlyZShcIi4vRXZlbnRQbHVnaW5SZWdpc3RyeVwiKTtcbnZhciBFdmVudFBsdWdpblV0aWxzID0gcmVxdWlyZShcIi4vRXZlbnRQbHVnaW5VdGlsc1wiKTtcblxudmFyIGFjY3VtdWxhdGVJbnRvID0gcmVxdWlyZShcIi4vYWNjdW11bGF0ZUludG9cIik7XG52YXIgZm9yRWFjaEFjY3VtdWxhdGVkID0gcmVxdWlyZShcIi4vZm9yRWFjaEFjY3VtdWxhdGVkXCIpO1xudmFyIGludmFyaWFudCA9IHJlcXVpcmUoXCIuL2ludmFyaWFudFwiKTtcblxuLyoqXG4gKiBJbnRlcm5hbCBzdG9yZSBmb3IgZXZlbnQgbGlzdGVuZXJzXG4gKi9cbnZhciBsaXN0ZW5lckJhbmsgPSB7fTtcblxuLyoqXG4gKiBJbnRlcm5hbCBxdWV1ZSBvZiBldmVudHMgdGhhdCBoYXZlIGFjY3VtdWxhdGVkIHRoZWlyIGRpc3BhdGNoZXMgYW5kIGFyZVxuICogd2FpdGluZyB0byBoYXZlIHRoZWlyIGRpc3BhdGNoZXMgZXhlY3V0ZWQuXG4gKi9cbnZhciBldmVudFF1ZXVlID0gbnVsbDtcblxuLyoqXG4gKiBEaXNwYXRjaGVzIGFuIGV2ZW50IGFuZCByZWxlYXNlcyBpdCBiYWNrIGludG8gdGhlIHBvb2wsIHVubGVzcyBwZXJzaXN0ZW50LlxuICpcbiAqIEBwYXJhbSB7P29iamVjdH0gZXZlbnQgU3ludGhldGljIGV2ZW50IHRvIGJlIGRpc3BhdGNoZWQuXG4gKiBAcHJpdmF0ZVxuICovXG52YXIgZXhlY3V0ZURpc3BhdGNoZXNBbmRSZWxlYXNlID0gZnVuY3Rpb24oZXZlbnQpIHtcbiAgaWYgKGV2ZW50KSB7XG4gICAgdmFyIGV4ZWN1dGVEaXNwYXRjaCA9IEV2ZW50UGx1Z2luVXRpbHMuZXhlY3V0ZURpc3BhdGNoO1xuICAgIC8vIFBsdWdpbnMgY2FuIHByb3ZpZGUgY3VzdG9tIGJlaGF2aW9yIHdoZW4gZGlzcGF0Y2hpbmcgZXZlbnRzLlxuICAgIHZhciBQbHVnaW5Nb2R1bGUgPSBFdmVudFBsdWdpblJlZ2lzdHJ5LmdldFBsdWdpbk1vZHVsZUZvckV2ZW50KGV2ZW50KTtcbiAgICBpZiAoUGx1Z2luTW9kdWxlICYmIFBsdWdpbk1vZHVsZS5leGVjdXRlRGlzcGF0Y2gpIHtcbiAgICAgIGV4ZWN1dGVEaXNwYXRjaCA9IFBsdWdpbk1vZHVsZS5leGVjdXRlRGlzcGF0Y2g7XG4gICAgfVxuICAgIEV2ZW50UGx1Z2luVXRpbHMuZXhlY3V0ZURpc3BhdGNoZXNJbk9yZGVyKGV2ZW50LCBleGVjdXRlRGlzcGF0Y2gpO1xuXG4gICAgaWYgKCFldmVudC5pc1BlcnNpc3RlbnQoKSkge1xuICAgICAgZXZlbnQuY29uc3RydWN0b3IucmVsZWFzZShldmVudCk7XG4gICAgfVxuICB9XG59O1xuXG4vKipcbiAqIC0gYEluc3RhbmNlSGFuZGxlYDogW3JlcXVpcmVkXSBNb2R1bGUgdGhhdCBwZXJmb3JtcyBsb2dpY2FsIHRyYXZlcnNhbHMgb2YgRE9NXG4gKiAgIGhpZXJhcmNoeSBnaXZlbiBpZHMgb2YgdGhlIGxvZ2ljYWwgRE9NIGVsZW1lbnRzIGludm9sdmVkLlxuICovXG52YXIgSW5zdGFuY2VIYW5kbGUgPSBudWxsO1xuXG5mdW5jdGlvbiB2YWxpZGF0ZUluc3RhbmNlSGFuZGxlKCkge1xuICB2YXIgaW52YWxpZCA9ICFJbnN0YW5jZUhhbmRsZXx8XG4gICAgIUluc3RhbmNlSGFuZGxlLnRyYXZlcnNlVHdvUGhhc2UgfHxcbiAgICAhSW5zdGFuY2VIYW5kbGUudHJhdmVyc2VFbnRlckxlYXZlO1xuICBpZiAoaW52YWxpZCkge1xuICAgIHRocm93IG5ldyBFcnJvcignSW5zdGFuY2VIYW5kbGUgbm90IGluamVjdGVkIGJlZm9yZSB1c2UhJyk7XG4gIH1cbn1cblxuLyoqXG4gKiBUaGlzIGlzIGEgdW5pZmllZCBpbnRlcmZhY2UgZm9yIGV2ZW50IHBsdWdpbnMgdG8gYmUgaW5zdGFsbGVkIGFuZCBjb25maWd1cmVkLlxuICpcbiAqIEV2ZW50IHBsdWdpbnMgY2FuIGltcGxlbWVudCB0aGUgZm9sbG93aW5nIHByb3BlcnRpZXM6XG4gKlxuICogICBgZXh0cmFjdEV2ZW50c2Age2Z1bmN0aW9uKHN0cmluZywgRE9NRXZlbnRUYXJnZXQsIHN0cmluZywgb2JqZWN0KTogKn1cbiAqICAgICBSZXF1aXJlZC4gV2hlbiBhIHRvcC1sZXZlbCBldmVudCBpcyBmaXJlZCwgdGhpcyBtZXRob2QgaXMgZXhwZWN0ZWQgdG9cbiAqICAgICBleHRyYWN0IHN5bnRoZXRpYyBldmVudHMgdGhhdCB3aWxsIGluIHR1cm4gYmUgcXVldWVkIGFuZCBkaXNwYXRjaGVkLlxuICpcbiAqICAgYGV2ZW50VHlwZXNgIHtvYmplY3R9XG4gKiAgICAgT3B0aW9uYWwsIHBsdWdpbnMgdGhhdCBmaXJlIGV2ZW50cyBtdXN0IHB1Ymxpc2ggYSBtYXBwaW5nIG9mIHJlZ2lzdHJhdGlvblxuICogICAgIG5hbWVzIHRoYXQgYXJlIHVzZWQgdG8gcmVnaXN0ZXIgbGlzdGVuZXJzLiBWYWx1ZXMgb2YgdGhpcyBtYXBwaW5nIG11c3RcbiAqICAgICBiZSBvYmplY3RzIHRoYXQgY29udGFpbiBgcmVnaXN0cmF0aW9uTmFtZWAgb3IgYHBoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzYC5cbiAqXG4gKiAgIGBleGVjdXRlRGlzcGF0Y2hgIHtmdW5jdGlvbihvYmplY3QsIGZ1bmN0aW9uLCBzdHJpbmcpfVxuICogICAgIE9wdGlvbmFsLCBhbGxvd3MgcGx1Z2lucyB0byBvdmVycmlkZSBob3cgYW4gZXZlbnQgZ2V0cyBkaXNwYXRjaGVkLiBCeVxuICogICAgIGRlZmF1bHQsIHRoZSBsaXN0ZW5lciBpcyBzaW1wbHkgaW52b2tlZC5cbiAqXG4gKiBFYWNoIHBsdWdpbiB0aGF0IGlzIGluamVjdGVkIGludG8gYEV2ZW50c1BsdWdpbkh1YmAgaXMgaW1tZWRpYXRlbHkgb3BlcmFibGUuXG4gKlxuICogQHB1YmxpY1xuICovXG52YXIgRXZlbnRQbHVnaW5IdWIgPSB7XG5cbiAgLyoqXG4gICAqIE1ldGhvZHMgZm9yIGluamVjdGluZyBkZXBlbmRlbmNpZXMuXG4gICAqL1xuICBpbmplY3Rpb246IHtcblxuICAgIC8qKlxuICAgICAqIEBwYXJhbSB7b2JqZWN0fSBJbmplY3RlZE1vdW50XG4gICAgICogQHB1YmxpY1xuICAgICAqL1xuICAgIGluamVjdE1vdW50OiBFdmVudFBsdWdpblV0aWxzLmluamVjdGlvbi5pbmplY3RNb3VudCxcblxuICAgIC8qKlxuICAgICAqIEBwYXJhbSB7b2JqZWN0fSBJbmplY3RlZEluc3RhbmNlSGFuZGxlXG4gICAgICogQHB1YmxpY1xuICAgICAqL1xuICAgIGluamVjdEluc3RhbmNlSGFuZGxlOiBmdW5jdGlvbihJbmplY3RlZEluc3RhbmNlSGFuZGxlKSB7XG4gICAgICBJbnN0YW5jZUhhbmRsZSA9IEluamVjdGVkSW5zdGFuY2VIYW5kbGU7XG4gICAgICBpZiAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WKSB7XG4gICAgICAgIHZhbGlkYXRlSW5zdGFuY2VIYW5kbGUoKTtcbiAgICAgIH1cbiAgICB9LFxuXG4gICAgZ2V0SW5zdGFuY2VIYW5kbGU6IGZ1bmN0aW9uKCkge1xuICAgICAgaWYgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOVikge1xuICAgICAgICB2YWxpZGF0ZUluc3RhbmNlSGFuZGxlKCk7XG4gICAgICB9XG4gICAgICByZXR1cm4gSW5zdGFuY2VIYW5kbGU7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIEBwYXJhbSB7YXJyYXl9IEluamVjdGVkRXZlbnRQbHVnaW5PcmRlclxuICAgICAqIEBwdWJsaWNcbiAgICAgKi9cbiAgICBpbmplY3RFdmVudFBsdWdpbk9yZGVyOiBFdmVudFBsdWdpblJlZ2lzdHJ5LmluamVjdEV2ZW50UGx1Z2luT3JkZXIsXG5cbiAgICAvKipcbiAgICAgKiBAcGFyYW0ge29iamVjdH0gaW5qZWN0ZWROYW1lc1RvUGx1Z2lucyBNYXAgZnJvbSBuYW1lcyB0byBwbHVnaW4gbW9kdWxlcy5cbiAgICAgKi9cbiAgICBpbmplY3RFdmVudFBsdWdpbnNCeU5hbWU6IEV2ZW50UGx1Z2luUmVnaXN0cnkuaW5qZWN0RXZlbnRQbHVnaW5zQnlOYW1lXG5cbiAgfSxcblxuICBldmVudE5hbWVEaXNwYXRjaENvbmZpZ3M6IEV2ZW50UGx1Z2luUmVnaXN0cnkuZXZlbnROYW1lRGlzcGF0Y2hDb25maWdzLFxuXG4gIHJlZ2lzdHJhdGlvbk5hbWVNb2R1bGVzOiBFdmVudFBsdWdpblJlZ2lzdHJ5LnJlZ2lzdHJhdGlvbk5hbWVNb2R1bGVzLFxuXG4gIC8qKlxuICAgKiBTdG9yZXMgYGxpc3RlbmVyYCBhdCBgbGlzdGVuZXJCYW5rW3JlZ2lzdHJhdGlvbk5hbWVdW2lkXWAuIElzIGlkZW1wb3RlbnQuXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBpZCBJRCBvZiB0aGUgRE9NIGVsZW1lbnQuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSByZWdpc3RyYXRpb25OYW1lIE5hbWUgb2YgbGlzdGVuZXIgKGUuZy4gYG9uQ2xpY2tgKS5cbiAgICogQHBhcmFtIHs/ZnVuY3Rpb259IGxpc3RlbmVyIFRoZSBjYWxsYmFjayB0byBzdG9yZS5cbiAgICovXG4gIHB1dExpc3RlbmVyOiBmdW5jdGlvbihpZCwgcmVnaXN0cmF0aW9uTmFtZSwgbGlzdGVuZXIpIHtcbiAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgIWxpc3RlbmVyIHx8IHR5cGVvZiBsaXN0ZW5lciA9PT0gJ2Z1bmN0aW9uJyxcbiAgICAgICdFeHBlY3RlZCAlcyBsaXN0ZW5lciB0byBiZSBhIGZ1bmN0aW9uLCBpbnN0ZWFkIGdvdCB0eXBlICVzJyxcbiAgICAgIHJlZ2lzdHJhdGlvbk5hbWUsIHR5cGVvZiBsaXN0ZW5lclxuICAgICkgOiBpbnZhcmlhbnQoIWxpc3RlbmVyIHx8IHR5cGVvZiBsaXN0ZW5lciA9PT0gJ2Z1bmN0aW9uJykpO1xuXG4gICAgdmFyIGJhbmtGb3JSZWdpc3RyYXRpb25OYW1lID1cbiAgICAgIGxpc3RlbmVyQmFua1tyZWdpc3RyYXRpb25OYW1lXSB8fCAobGlzdGVuZXJCYW5rW3JlZ2lzdHJhdGlvbk5hbWVdID0ge30pO1xuICAgIGJhbmtGb3JSZWdpc3RyYXRpb25OYW1lW2lkXSA9IGxpc3RlbmVyO1xuICB9LFxuXG4gIC8qKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gaWQgSUQgb2YgdGhlIERPTSBlbGVtZW50LlxuICAgKiBAcGFyYW0ge3N0cmluZ30gcmVnaXN0cmF0aW9uTmFtZSBOYW1lIG9mIGxpc3RlbmVyIChlLmcuIGBvbkNsaWNrYCkuXG4gICAqIEByZXR1cm4gez9mdW5jdGlvbn0gVGhlIHN0b3JlZCBjYWxsYmFjay5cbiAgICovXG4gIGdldExpc3RlbmVyOiBmdW5jdGlvbihpZCwgcmVnaXN0cmF0aW9uTmFtZSkge1xuICAgIHZhciBiYW5rRm9yUmVnaXN0cmF0aW9uTmFtZSA9IGxpc3RlbmVyQmFua1tyZWdpc3RyYXRpb25OYW1lXTtcbiAgICByZXR1cm4gYmFua0ZvclJlZ2lzdHJhdGlvbk5hbWUgJiYgYmFua0ZvclJlZ2lzdHJhdGlvbk5hbWVbaWRdO1xuICB9LFxuXG4gIC8qKlxuICAgKiBEZWxldGVzIGEgbGlzdGVuZXIgZnJvbSB0aGUgcmVnaXN0cmF0aW9uIGJhbmsuXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBpZCBJRCBvZiB0aGUgRE9NIGVsZW1lbnQuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSByZWdpc3RyYXRpb25OYW1lIE5hbWUgb2YgbGlzdGVuZXIgKGUuZy4gYG9uQ2xpY2tgKS5cbiAgICovXG4gIGRlbGV0ZUxpc3RlbmVyOiBmdW5jdGlvbihpZCwgcmVnaXN0cmF0aW9uTmFtZSkge1xuICAgIHZhciBiYW5rRm9yUmVnaXN0cmF0aW9uTmFtZSA9IGxpc3RlbmVyQmFua1tyZWdpc3RyYXRpb25OYW1lXTtcbiAgICBpZiAoYmFua0ZvclJlZ2lzdHJhdGlvbk5hbWUpIHtcbiAgICAgIGRlbGV0ZSBiYW5rRm9yUmVnaXN0cmF0aW9uTmFtZVtpZF07XG4gICAgfVxuICB9LFxuXG4gIC8qKlxuICAgKiBEZWxldGVzIGFsbCBsaXN0ZW5lcnMgZm9yIHRoZSBET00gZWxlbWVudCB3aXRoIHRoZSBzdXBwbGllZCBJRC5cbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IGlkIElEIG9mIHRoZSBET00gZWxlbWVudC5cbiAgICovXG4gIGRlbGV0ZUFsbExpc3RlbmVyczogZnVuY3Rpb24oaWQpIHtcbiAgICBmb3IgKHZhciByZWdpc3RyYXRpb25OYW1lIGluIGxpc3RlbmVyQmFuaykge1xuICAgICAgZGVsZXRlIGxpc3RlbmVyQmFua1tyZWdpc3RyYXRpb25OYW1lXVtpZF07XG4gICAgfVxuICB9LFxuXG4gIC8qKlxuICAgKiBBbGxvd3MgcmVnaXN0ZXJlZCBwbHVnaW5zIGFuIG9wcG9ydHVuaXR5IHRvIGV4dHJhY3QgZXZlbnRzIGZyb20gdG9wLWxldmVsXG4gICAqIG5hdGl2ZSBicm93c2VyIGV2ZW50cy5cbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IHRvcExldmVsVHlwZSBSZWNvcmQgZnJvbSBgRXZlbnRDb25zdGFudHNgLlxuICAgKiBAcGFyYW0ge0RPTUV2ZW50VGFyZ2V0fSB0b3BMZXZlbFRhcmdldCBUaGUgbGlzdGVuaW5nIGNvbXBvbmVudCByb290IG5vZGUuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB0b3BMZXZlbFRhcmdldElEIElEIG9mIGB0b3BMZXZlbFRhcmdldGAuXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBuYXRpdmVFdmVudCBOYXRpdmUgYnJvd3NlciBldmVudC5cbiAgICogQHJldHVybiB7Kn0gQW4gYWNjdW11bGF0aW9uIG9mIHN5bnRoZXRpYyBldmVudHMuXG4gICAqIEBpbnRlcm5hbFxuICAgKi9cbiAgZXh0cmFjdEV2ZW50czogZnVuY3Rpb24oXG4gICAgICB0b3BMZXZlbFR5cGUsXG4gICAgICB0b3BMZXZlbFRhcmdldCxcbiAgICAgIHRvcExldmVsVGFyZ2V0SUQsXG4gICAgICBuYXRpdmVFdmVudCkge1xuICAgIHZhciBldmVudHM7XG4gICAgdmFyIHBsdWdpbnMgPSBFdmVudFBsdWdpblJlZ2lzdHJ5LnBsdWdpbnM7XG4gICAgZm9yICh2YXIgaSA9IDAsIGwgPSBwbHVnaW5zLmxlbmd0aDsgaSA8IGw7IGkrKykge1xuICAgICAgLy8gTm90IGV2ZXJ5IHBsdWdpbiBpbiB0aGUgb3JkZXJpbmcgbWF5IGJlIGxvYWRlZCBhdCBydW50aW1lLlxuICAgICAgdmFyIHBvc3NpYmxlUGx1Z2luID0gcGx1Z2luc1tpXTtcbiAgICAgIGlmIChwb3NzaWJsZVBsdWdpbikge1xuICAgICAgICB2YXIgZXh0cmFjdGVkRXZlbnRzID0gcG9zc2libGVQbHVnaW4uZXh0cmFjdEV2ZW50cyhcbiAgICAgICAgICB0b3BMZXZlbFR5cGUsXG4gICAgICAgICAgdG9wTGV2ZWxUYXJnZXQsXG4gICAgICAgICAgdG9wTGV2ZWxUYXJnZXRJRCxcbiAgICAgICAgICBuYXRpdmVFdmVudFxuICAgICAgICApO1xuICAgICAgICBpZiAoZXh0cmFjdGVkRXZlbnRzKSB7XG4gICAgICAgICAgZXZlbnRzID0gYWNjdW11bGF0ZUludG8oZXZlbnRzLCBleHRyYWN0ZWRFdmVudHMpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBldmVudHM7XG4gIH0sXG5cbiAgLyoqXG4gICAqIEVucXVldWVzIGEgc3ludGhldGljIGV2ZW50IHRoYXQgc2hvdWxkIGJlIGRpc3BhdGNoZWQgd2hlblxuICAgKiBgcHJvY2Vzc0V2ZW50UXVldWVgIGlzIGludm9rZWQuXG4gICAqXG4gICAqIEBwYXJhbSB7Kn0gZXZlbnRzIEFuIGFjY3VtdWxhdGlvbiBvZiBzeW50aGV0aWMgZXZlbnRzLlxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIGVucXVldWVFdmVudHM6IGZ1bmN0aW9uKGV2ZW50cykge1xuICAgIGlmIChldmVudHMpIHtcbiAgICAgIGV2ZW50UXVldWUgPSBhY2N1bXVsYXRlSW50byhldmVudFF1ZXVlLCBldmVudHMpO1xuICAgIH1cbiAgfSxcblxuICAvKipcbiAgICogRGlzcGF0Y2hlcyBhbGwgc3ludGhldGljIGV2ZW50cyBvbiB0aGUgZXZlbnQgcXVldWUuXG4gICAqXG4gICAqIEBpbnRlcm5hbFxuICAgKi9cbiAgcHJvY2Vzc0V2ZW50UXVldWU6IGZ1bmN0aW9uKCkge1xuICAgIC8vIFNldCBgZXZlbnRRdWV1ZWAgdG8gbnVsbCBiZWZvcmUgcHJvY2Vzc2luZyBpdCBzbyB0aGF0IHdlIGNhbiB0ZWxsIGlmIG1vcmVcbiAgICAvLyBldmVudHMgZ2V0IGVucXVldWVkIHdoaWxlIHByb2Nlc3NpbmcuXG4gICAgdmFyIHByb2Nlc3NpbmdFdmVudFF1ZXVlID0gZXZlbnRRdWV1ZTtcbiAgICBldmVudFF1ZXVlID0gbnVsbDtcbiAgICBmb3JFYWNoQWNjdW11bGF0ZWQocHJvY2Vzc2luZ0V2ZW50UXVldWUsIGV4ZWN1dGVEaXNwYXRjaGVzQW5kUmVsZWFzZSk7XG4gICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgICFldmVudFF1ZXVlLFxuICAgICAgJ3Byb2Nlc3NFdmVudFF1ZXVlKCk6IEFkZGl0aW9uYWwgZXZlbnRzIHdlcmUgZW5xdWV1ZWQgd2hpbGUgcHJvY2Vzc2luZyAnICtcbiAgICAgICdhbiBldmVudCBxdWV1ZS4gU3VwcG9ydCBmb3IgdGhpcyBoYXMgbm90IHlldCBiZWVuIGltcGxlbWVudGVkLidcbiAgICApIDogaW52YXJpYW50KCFldmVudFF1ZXVlKSk7XG4gIH0sXG5cbiAgLyoqXG4gICAqIFRoZXNlIGFyZSBuZWVkZWQgZm9yIHRlc3RzIG9ubHkuIERvIG5vdCB1c2UhXG4gICAqL1xuICBfX3B1cmdlOiBmdW5jdGlvbigpIHtcbiAgICBsaXN0ZW5lckJhbmsgPSB7fTtcbiAgfSxcblxuICBfX2dldExpc3RlbmVyQmFuazogZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIGxpc3RlbmVyQmFuaztcbiAgfVxuXG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IEV2ZW50UGx1Z2luSHViO1xuXG59KS5jYWxsKHRoaXMscmVxdWlyZSgnX3Byb2Nlc3MnKSkiLCIoZnVuY3Rpb24gKHByb2Nlc3Mpe1xuLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIEV2ZW50UGx1Z2luUmVnaXN0cnlcbiAqIEB0eXBlY2hlY2tzIHN0YXRpYy1vbmx5XG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBpbnZhcmlhbnQgPSByZXF1aXJlKFwiLi9pbnZhcmlhbnRcIik7XG5cbi8qKlxuICogSW5qZWN0YWJsZSBvcmRlcmluZyBvZiBldmVudCBwbHVnaW5zLlxuICovXG52YXIgRXZlbnRQbHVnaW5PcmRlciA9IG51bGw7XG5cbi8qKlxuICogSW5qZWN0YWJsZSBtYXBwaW5nIGZyb20gbmFtZXMgdG8gZXZlbnQgcGx1Z2luIG1vZHVsZXMuXG4gKi9cbnZhciBuYW1lc1RvUGx1Z2lucyA9IHt9O1xuXG4vKipcbiAqIFJlY29tcHV0ZXMgdGhlIHBsdWdpbiBsaXN0IHVzaW5nIHRoZSBpbmplY3RlZCBwbHVnaW5zIGFuZCBwbHVnaW4gb3JkZXJpbmcuXG4gKlxuICogQHByaXZhdGVcbiAqL1xuZnVuY3Rpb24gcmVjb21wdXRlUGx1Z2luT3JkZXJpbmcoKSB7XG4gIGlmICghRXZlbnRQbHVnaW5PcmRlcikge1xuICAgIC8vIFdhaXQgdW50aWwgYW4gYEV2ZW50UGx1Z2luT3JkZXJgIGlzIGluamVjdGVkLlxuICAgIHJldHVybjtcbiAgfVxuICBmb3IgKHZhciBwbHVnaW5OYW1lIGluIG5hbWVzVG9QbHVnaW5zKSB7XG4gICAgdmFyIFBsdWdpbk1vZHVsZSA9IG5hbWVzVG9QbHVnaW5zW3BsdWdpbk5hbWVdO1xuICAgIHZhciBwbHVnaW5JbmRleCA9IEV2ZW50UGx1Z2luT3JkZXIuaW5kZXhPZihwbHVnaW5OYW1lKTtcbiAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgcGx1Z2luSW5kZXggPiAtMSxcbiAgICAgICdFdmVudFBsdWdpblJlZ2lzdHJ5OiBDYW5ub3QgaW5qZWN0IGV2ZW50IHBsdWdpbnMgdGhhdCBkbyBub3QgZXhpc3QgaW4gJyArXG4gICAgICAndGhlIHBsdWdpbiBvcmRlcmluZywgYCVzYC4nLFxuICAgICAgcGx1Z2luTmFtZVxuICAgICkgOiBpbnZhcmlhbnQocGx1Z2luSW5kZXggPiAtMSkpO1xuICAgIGlmIChFdmVudFBsdWdpblJlZ2lzdHJ5LnBsdWdpbnNbcGx1Z2luSW5kZXhdKSB7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG4gICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgIFBsdWdpbk1vZHVsZS5leHRyYWN0RXZlbnRzLFxuICAgICAgJ0V2ZW50UGx1Z2luUmVnaXN0cnk6IEV2ZW50IHBsdWdpbnMgbXVzdCBpbXBsZW1lbnQgYW4gYGV4dHJhY3RFdmVudHNgICcgK1xuICAgICAgJ21ldGhvZCwgYnV0IGAlc2AgZG9lcyBub3QuJyxcbiAgICAgIHBsdWdpbk5hbWVcbiAgICApIDogaW52YXJpYW50KFBsdWdpbk1vZHVsZS5leHRyYWN0RXZlbnRzKSk7XG4gICAgRXZlbnRQbHVnaW5SZWdpc3RyeS5wbHVnaW5zW3BsdWdpbkluZGV4XSA9IFBsdWdpbk1vZHVsZTtcbiAgICB2YXIgcHVibGlzaGVkRXZlbnRzID0gUGx1Z2luTW9kdWxlLmV2ZW50VHlwZXM7XG4gICAgZm9yICh2YXIgZXZlbnROYW1lIGluIHB1Ymxpc2hlZEV2ZW50cykge1xuICAgICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgICAgcHVibGlzaEV2ZW50Rm9yUGx1Z2luKFxuICAgICAgICAgIHB1Ymxpc2hlZEV2ZW50c1tldmVudE5hbWVdLFxuICAgICAgICAgIFBsdWdpbk1vZHVsZSxcbiAgICAgICAgICBldmVudE5hbWVcbiAgICAgICAgKSxcbiAgICAgICAgJ0V2ZW50UGx1Z2luUmVnaXN0cnk6IEZhaWxlZCB0byBwdWJsaXNoIGV2ZW50IGAlc2AgZm9yIHBsdWdpbiBgJXNgLicsXG4gICAgICAgIGV2ZW50TmFtZSxcbiAgICAgICAgcGx1Z2luTmFtZVxuICAgICAgKSA6IGludmFyaWFudChwdWJsaXNoRXZlbnRGb3JQbHVnaW4oXG4gICAgICAgIHB1Ymxpc2hlZEV2ZW50c1tldmVudE5hbWVdLFxuICAgICAgICBQbHVnaW5Nb2R1bGUsXG4gICAgICAgIGV2ZW50TmFtZVxuICAgICAgKSkpO1xuICAgIH1cbiAgfVxufVxuXG4vKipcbiAqIFB1Ymxpc2hlcyBhbiBldmVudCBzbyB0aGF0IGl0IGNhbiBiZSBkaXNwYXRjaGVkIGJ5IHRoZSBzdXBwbGllZCBwbHVnaW4uXG4gKlxuICogQHBhcmFtIHtvYmplY3R9IGRpc3BhdGNoQ29uZmlnIERpc3BhdGNoIGNvbmZpZ3VyYXRpb24gZm9yIHRoZSBldmVudC5cbiAqIEBwYXJhbSB7b2JqZWN0fSBQbHVnaW5Nb2R1bGUgUGx1Z2luIHB1Ymxpc2hpbmcgdGhlIGV2ZW50LlxuICogQHJldHVybiB7Ym9vbGVhbn0gVHJ1ZSBpZiB0aGUgZXZlbnQgd2FzIHN1Y2Nlc3NmdWxseSBwdWJsaXNoZWQuXG4gKiBAcHJpdmF0ZVxuICovXG5mdW5jdGlvbiBwdWJsaXNoRXZlbnRGb3JQbHVnaW4oZGlzcGF0Y2hDb25maWcsIFBsdWdpbk1vZHVsZSwgZXZlbnROYW1lKSB7XG4gIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgIUV2ZW50UGx1Z2luUmVnaXN0cnkuZXZlbnROYW1lRGlzcGF0Y2hDb25maWdzLmhhc093blByb3BlcnR5KGV2ZW50TmFtZSksXG4gICAgJ0V2ZW50UGx1Z2luSHViOiBNb3JlIHRoYW4gb25lIHBsdWdpbiBhdHRlbXB0ZWQgdG8gcHVibGlzaCB0aGUgc2FtZSAnICtcbiAgICAnZXZlbnQgbmFtZSwgYCVzYC4nLFxuICAgIGV2ZW50TmFtZVxuICApIDogaW52YXJpYW50KCFFdmVudFBsdWdpblJlZ2lzdHJ5LmV2ZW50TmFtZURpc3BhdGNoQ29uZmlncy5oYXNPd25Qcm9wZXJ0eShldmVudE5hbWUpKSk7XG4gIEV2ZW50UGx1Z2luUmVnaXN0cnkuZXZlbnROYW1lRGlzcGF0Y2hDb25maWdzW2V2ZW50TmFtZV0gPSBkaXNwYXRjaENvbmZpZztcblxuICB2YXIgcGhhc2VkUmVnaXN0cmF0aW9uTmFtZXMgPSBkaXNwYXRjaENvbmZpZy5waGFzZWRSZWdpc3RyYXRpb25OYW1lcztcbiAgaWYgKHBoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzKSB7XG4gICAgZm9yICh2YXIgcGhhc2VOYW1lIGluIHBoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzKSB7XG4gICAgICBpZiAocGhhc2VkUmVnaXN0cmF0aW9uTmFtZXMuaGFzT3duUHJvcGVydHkocGhhc2VOYW1lKSkge1xuICAgICAgICB2YXIgcGhhc2VkUmVnaXN0cmF0aW9uTmFtZSA9IHBoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzW3BoYXNlTmFtZV07XG4gICAgICAgIHB1Ymxpc2hSZWdpc3RyYXRpb25OYW1lKFxuICAgICAgICAgIHBoYXNlZFJlZ2lzdHJhdGlvbk5hbWUsXG4gICAgICAgICAgUGx1Z2luTW9kdWxlLFxuICAgICAgICAgIGV2ZW50TmFtZVxuICAgICAgICApO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gdHJ1ZTtcbiAgfSBlbHNlIGlmIChkaXNwYXRjaENvbmZpZy5yZWdpc3RyYXRpb25OYW1lKSB7XG4gICAgcHVibGlzaFJlZ2lzdHJhdGlvbk5hbWUoXG4gICAgICBkaXNwYXRjaENvbmZpZy5yZWdpc3RyYXRpb25OYW1lLFxuICAgICAgUGx1Z2luTW9kdWxlLFxuICAgICAgZXZlbnROYW1lXG4gICAgKTtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuICByZXR1cm4gZmFsc2U7XG59XG5cbi8qKlxuICogUHVibGlzaGVzIGEgcmVnaXN0cmF0aW9uIG5hbWUgdGhhdCBpcyB1c2VkIHRvIGlkZW50aWZ5IGRpc3BhdGNoZWQgZXZlbnRzIGFuZFxuICogY2FuIGJlIHVzZWQgd2l0aCBgRXZlbnRQbHVnaW5IdWIucHV0TGlzdGVuZXJgIHRvIHJlZ2lzdGVyIGxpc3RlbmVycy5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gcmVnaXN0cmF0aW9uTmFtZSBSZWdpc3RyYXRpb24gbmFtZSB0byBhZGQuXG4gKiBAcGFyYW0ge29iamVjdH0gUGx1Z2luTW9kdWxlIFBsdWdpbiBwdWJsaXNoaW5nIHRoZSBldmVudC5cbiAqIEBwcml2YXRlXG4gKi9cbmZ1bmN0aW9uIHB1Ymxpc2hSZWdpc3RyYXRpb25OYW1lKHJlZ2lzdHJhdGlvbk5hbWUsIFBsdWdpbk1vZHVsZSwgZXZlbnROYW1lKSB7XG4gIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgIUV2ZW50UGx1Z2luUmVnaXN0cnkucmVnaXN0cmF0aW9uTmFtZU1vZHVsZXNbcmVnaXN0cmF0aW9uTmFtZV0sXG4gICAgJ0V2ZW50UGx1Z2luSHViOiBNb3JlIHRoYW4gb25lIHBsdWdpbiBhdHRlbXB0ZWQgdG8gcHVibGlzaCB0aGUgc2FtZSAnICtcbiAgICAncmVnaXN0cmF0aW9uIG5hbWUsIGAlc2AuJyxcbiAgICByZWdpc3RyYXRpb25OYW1lXG4gICkgOiBpbnZhcmlhbnQoIUV2ZW50UGx1Z2luUmVnaXN0cnkucmVnaXN0cmF0aW9uTmFtZU1vZHVsZXNbcmVnaXN0cmF0aW9uTmFtZV0pKTtcbiAgRXZlbnRQbHVnaW5SZWdpc3RyeS5yZWdpc3RyYXRpb25OYW1lTW9kdWxlc1tyZWdpc3RyYXRpb25OYW1lXSA9IFBsdWdpbk1vZHVsZTtcbiAgRXZlbnRQbHVnaW5SZWdpc3RyeS5yZWdpc3RyYXRpb25OYW1lRGVwZW5kZW5jaWVzW3JlZ2lzdHJhdGlvbk5hbWVdID1cbiAgICBQbHVnaW5Nb2R1bGUuZXZlbnRUeXBlc1tldmVudE5hbWVdLmRlcGVuZGVuY2llcztcbn1cblxuLyoqXG4gKiBSZWdpc3RlcnMgcGx1Z2lucyBzbyB0aGF0IHRoZXkgY2FuIGV4dHJhY3QgYW5kIGRpc3BhdGNoIGV2ZW50cy5cbiAqXG4gKiBAc2VlIHtFdmVudFBsdWdpbkh1Yn1cbiAqL1xudmFyIEV2ZW50UGx1Z2luUmVnaXN0cnkgPSB7XG5cbiAgLyoqXG4gICAqIE9yZGVyZWQgbGlzdCBvZiBpbmplY3RlZCBwbHVnaW5zLlxuICAgKi9cbiAgcGx1Z2luczogW10sXG5cbiAgLyoqXG4gICAqIE1hcHBpbmcgZnJvbSBldmVudCBuYW1lIHRvIGRpc3BhdGNoIGNvbmZpZ1xuICAgKi9cbiAgZXZlbnROYW1lRGlzcGF0Y2hDb25maWdzOiB7fSxcblxuICAvKipcbiAgICogTWFwcGluZyBmcm9tIHJlZ2lzdHJhdGlvbiBuYW1lIHRvIHBsdWdpbiBtb2R1bGVcbiAgICovXG4gIHJlZ2lzdHJhdGlvbk5hbWVNb2R1bGVzOiB7fSxcblxuICAvKipcbiAgICogTWFwcGluZyBmcm9tIHJlZ2lzdHJhdGlvbiBuYW1lIHRvIGV2ZW50IG5hbWVcbiAgICovXG4gIHJlZ2lzdHJhdGlvbk5hbWVEZXBlbmRlbmNpZXM6IHt9LFxuXG4gIC8qKlxuICAgKiBJbmplY3RzIGFuIG9yZGVyaW5nIG9mIHBsdWdpbnMgKGJ5IHBsdWdpbiBuYW1lKS4gVGhpcyBhbGxvd3MgdGhlIG9yZGVyaW5nXG4gICAqIHRvIGJlIGRlY291cGxlZCBmcm9tIGluamVjdGlvbiBvZiB0aGUgYWN0dWFsIHBsdWdpbnMgc28gdGhhdCBvcmRlcmluZyBpc1xuICAgKiBhbHdheXMgZGV0ZXJtaW5pc3RpYyByZWdhcmRsZXNzIG9mIHBhY2thZ2luZywgb24tdGhlLWZseSBpbmplY3Rpb24sIGV0Yy5cbiAgICpcbiAgICogQHBhcmFtIHthcnJheX0gSW5qZWN0ZWRFdmVudFBsdWdpbk9yZGVyXG4gICAqIEBpbnRlcm5hbFxuICAgKiBAc2VlIHtFdmVudFBsdWdpbkh1Yi5pbmplY3Rpb24uaW5qZWN0RXZlbnRQbHVnaW5PcmRlcn1cbiAgICovXG4gIGluamVjdEV2ZW50UGx1Z2luT3JkZXI6IGZ1bmN0aW9uKEluamVjdGVkRXZlbnRQbHVnaW5PcmRlcikge1xuICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICAhRXZlbnRQbHVnaW5PcmRlcixcbiAgICAgICdFdmVudFBsdWdpblJlZ2lzdHJ5OiBDYW5ub3QgaW5qZWN0IGV2ZW50IHBsdWdpbiBvcmRlcmluZyBtb3JlIHRoYW4gJyArXG4gICAgICAnb25jZS4gWW91IGFyZSBsaWtlbHkgdHJ5aW5nIHRvIGxvYWQgbW9yZSB0aGFuIG9uZSBjb3B5IG9mIFJlYWN0LidcbiAgICApIDogaW52YXJpYW50KCFFdmVudFBsdWdpbk9yZGVyKSk7XG4gICAgLy8gQ2xvbmUgdGhlIG9yZGVyaW5nIHNvIGl0IGNhbm5vdCBiZSBkeW5hbWljYWxseSBtdXRhdGVkLlxuICAgIEV2ZW50UGx1Z2luT3JkZXIgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChJbmplY3RlZEV2ZW50UGx1Z2luT3JkZXIpO1xuICAgIHJlY29tcHV0ZVBsdWdpbk9yZGVyaW5nKCk7XG4gIH0sXG5cbiAgLyoqXG4gICAqIEluamVjdHMgcGx1Z2lucyB0byBiZSB1c2VkIGJ5IGBFdmVudFBsdWdpbkh1YmAuIFRoZSBwbHVnaW4gbmFtZXMgbXVzdCBiZVxuICAgKiBpbiB0aGUgb3JkZXJpbmcgaW5qZWN0ZWQgYnkgYGluamVjdEV2ZW50UGx1Z2luT3JkZXJgLlxuICAgKlxuICAgKiBQbHVnaW5zIGNhbiBiZSBpbmplY3RlZCBhcyBwYXJ0IG9mIHBhZ2UgaW5pdGlhbGl6YXRpb24gb3Igb24tdGhlLWZseS5cbiAgICpcbiAgICogQHBhcmFtIHtvYmplY3R9IGluamVjdGVkTmFtZXNUb1BsdWdpbnMgTWFwIGZyb20gbmFtZXMgdG8gcGx1Z2luIG1vZHVsZXMuXG4gICAqIEBpbnRlcm5hbFxuICAgKiBAc2VlIHtFdmVudFBsdWdpbkh1Yi5pbmplY3Rpb24uaW5qZWN0RXZlbnRQbHVnaW5zQnlOYW1lfVxuICAgKi9cbiAgaW5qZWN0RXZlbnRQbHVnaW5zQnlOYW1lOiBmdW5jdGlvbihpbmplY3RlZE5hbWVzVG9QbHVnaW5zKSB7XG4gICAgdmFyIGlzT3JkZXJpbmdEaXJ0eSA9IGZhbHNlO1xuICAgIGZvciAodmFyIHBsdWdpbk5hbWUgaW4gaW5qZWN0ZWROYW1lc1RvUGx1Z2lucykge1xuICAgICAgaWYgKCFpbmplY3RlZE5hbWVzVG9QbHVnaW5zLmhhc093blByb3BlcnR5KHBsdWdpbk5hbWUpKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgdmFyIFBsdWdpbk1vZHVsZSA9IGluamVjdGVkTmFtZXNUb1BsdWdpbnNbcGx1Z2luTmFtZV07XG4gICAgICBpZiAoIW5hbWVzVG9QbHVnaW5zLmhhc093blByb3BlcnR5KHBsdWdpbk5hbWUpIHx8XG4gICAgICAgICAgbmFtZXNUb1BsdWdpbnNbcGx1Z2luTmFtZV0gIT09IFBsdWdpbk1vZHVsZSkge1xuICAgICAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgICAgICFuYW1lc1RvUGx1Z2luc1twbHVnaW5OYW1lXSxcbiAgICAgICAgICAnRXZlbnRQbHVnaW5SZWdpc3RyeTogQ2Fubm90IGluamVjdCB0d28gZGlmZmVyZW50IGV2ZW50IHBsdWdpbnMgJyArXG4gICAgICAgICAgJ3VzaW5nIHRoZSBzYW1lIG5hbWUsIGAlc2AuJyxcbiAgICAgICAgICBwbHVnaW5OYW1lXG4gICAgICAgICkgOiBpbnZhcmlhbnQoIW5hbWVzVG9QbHVnaW5zW3BsdWdpbk5hbWVdKSk7XG4gICAgICAgIG5hbWVzVG9QbHVnaW5zW3BsdWdpbk5hbWVdID0gUGx1Z2luTW9kdWxlO1xuICAgICAgICBpc09yZGVyaW5nRGlydHkgPSB0cnVlO1xuICAgICAgfVxuICAgIH1cbiAgICBpZiAoaXNPcmRlcmluZ0RpcnR5KSB7XG4gICAgICByZWNvbXB1dGVQbHVnaW5PcmRlcmluZygpO1xuICAgIH1cbiAgfSxcblxuICAvKipcbiAgICogTG9va3MgdXAgdGhlIHBsdWdpbiBmb3IgdGhlIHN1cHBsaWVkIGV2ZW50LlxuICAgKlxuICAgKiBAcGFyYW0ge29iamVjdH0gZXZlbnQgQSBzeW50aGV0aWMgZXZlbnQuXG4gICAqIEByZXR1cm4gez9vYmplY3R9IFRoZSBwbHVnaW4gdGhhdCBjcmVhdGVkIHRoZSBzdXBwbGllZCBldmVudC5cbiAgICogQGludGVybmFsXG4gICAqL1xuICBnZXRQbHVnaW5Nb2R1bGVGb3JFdmVudDogZnVuY3Rpb24oZXZlbnQpIHtcbiAgICB2YXIgZGlzcGF0Y2hDb25maWcgPSBldmVudC5kaXNwYXRjaENvbmZpZztcbiAgICBpZiAoZGlzcGF0Y2hDb25maWcucmVnaXN0cmF0aW9uTmFtZSkge1xuICAgICAgcmV0dXJuIEV2ZW50UGx1Z2luUmVnaXN0cnkucmVnaXN0cmF0aW9uTmFtZU1vZHVsZXNbXG4gICAgICAgIGRpc3BhdGNoQ29uZmlnLnJlZ2lzdHJhdGlvbk5hbWVcbiAgICAgIF0gfHwgbnVsbDtcbiAgICB9XG4gICAgZm9yICh2YXIgcGhhc2UgaW4gZGlzcGF0Y2hDb25maWcucGhhc2VkUmVnaXN0cmF0aW9uTmFtZXMpIHtcbiAgICAgIGlmICghZGlzcGF0Y2hDb25maWcucGhhc2VkUmVnaXN0cmF0aW9uTmFtZXMuaGFzT3duUHJvcGVydHkocGhhc2UpKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgdmFyIFBsdWdpbk1vZHVsZSA9IEV2ZW50UGx1Z2luUmVnaXN0cnkucmVnaXN0cmF0aW9uTmFtZU1vZHVsZXNbXG4gICAgICAgIGRpc3BhdGNoQ29uZmlnLnBoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzW3BoYXNlXVxuICAgICAgXTtcbiAgICAgIGlmIChQbHVnaW5Nb2R1bGUpIHtcbiAgICAgICAgcmV0dXJuIFBsdWdpbk1vZHVsZTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG4gIH0sXG5cbiAgLyoqXG4gICAqIEV4cG9zZWQgZm9yIHVuaXQgdGVzdGluZy5cbiAgICogQHByaXZhdGVcbiAgICovXG4gIF9yZXNldEV2ZW50UGx1Z2luczogZnVuY3Rpb24oKSB7XG4gICAgRXZlbnRQbHVnaW5PcmRlciA9IG51bGw7XG4gICAgZm9yICh2YXIgcGx1Z2luTmFtZSBpbiBuYW1lc1RvUGx1Z2lucykge1xuICAgICAgaWYgKG5hbWVzVG9QbHVnaW5zLmhhc093blByb3BlcnR5KHBsdWdpbk5hbWUpKSB7XG4gICAgICAgIGRlbGV0ZSBuYW1lc1RvUGx1Z2luc1twbHVnaW5OYW1lXTtcbiAgICAgIH1cbiAgICB9XG4gICAgRXZlbnRQbHVnaW5SZWdpc3RyeS5wbHVnaW5zLmxlbmd0aCA9IDA7XG5cbiAgICB2YXIgZXZlbnROYW1lRGlzcGF0Y2hDb25maWdzID0gRXZlbnRQbHVnaW5SZWdpc3RyeS5ldmVudE5hbWVEaXNwYXRjaENvbmZpZ3M7XG4gICAgZm9yICh2YXIgZXZlbnROYW1lIGluIGV2ZW50TmFtZURpc3BhdGNoQ29uZmlncykge1xuICAgICAgaWYgKGV2ZW50TmFtZURpc3BhdGNoQ29uZmlncy5oYXNPd25Qcm9wZXJ0eShldmVudE5hbWUpKSB7XG4gICAgICAgIGRlbGV0ZSBldmVudE5hbWVEaXNwYXRjaENvbmZpZ3NbZXZlbnROYW1lXTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICB2YXIgcmVnaXN0cmF0aW9uTmFtZU1vZHVsZXMgPSBFdmVudFBsdWdpblJlZ2lzdHJ5LnJlZ2lzdHJhdGlvbk5hbWVNb2R1bGVzO1xuICAgIGZvciAodmFyIHJlZ2lzdHJhdGlvbk5hbWUgaW4gcmVnaXN0cmF0aW9uTmFtZU1vZHVsZXMpIHtcbiAgICAgIGlmIChyZWdpc3RyYXRpb25OYW1lTW9kdWxlcy5oYXNPd25Qcm9wZXJ0eShyZWdpc3RyYXRpb25OYW1lKSkge1xuICAgICAgICBkZWxldGUgcmVnaXN0cmF0aW9uTmFtZU1vZHVsZXNbcmVnaXN0cmF0aW9uTmFtZV07XG4gICAgICB9XG4gICAgfVxuICB9XG5cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gRXZlbnRQbHVnaW5SZWdpc3RyeTtcblxufSkuY2FsbCh0aGlzLHJlcXVpcmUoJ19wcm9jZXNzJykpIiwiKGZ1bmN0aW9uIChwcm9jZXNzKXtcbi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBFdmVudFBsdWdpblV0aWxzXG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBFdmVudENvbnN0YW50cyA9IHJlcXVpcmUoXCIuL0V2ZW50Q29uc3RhbnRzXCIpO1xuXG52YXIgaW52YXJpYW50ID0gcmVxdWlyZShcIi4vaW52YXJpYW50XCIpO1xuXG4vKipcbiAqIEluamVjdGVkIGRlcGVuZGVuY2llczpcbiAqL1xuXG4vKipcbiAqIC0gYE1vdW50YDogW3JlcXVpcmVkXSBNb2R1bGUgdGhhdCBjYW4gY29udmVydCBiZXR3ZWVuIFJlYWN0IGRvbSBJRHMgYW5kXG4gKiAgIGFjdHVhbCBub2RlIHJlZmVyZW5jZXMuXG4gKi9cbnZhciBpbmplY3Rpb24gPSB7XG4gIE1vdW50OiBudWxsLFxuICBpbmplY3RNb3VudDogZnVuY3Rpb24oSW5qZWN0ZWRNb3VudCkge1xuICAgIGluamVjdGlvbi5Nb3VudCA9IEluamVjdGVkTW91bnQ7XG4gICAgaWYgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOVikge1xuICAgICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgICAgSW5qZWN0ZWRNb3VudCAmJiBJbmplY3RlZE1vdW50LmdldE5vZGUsXG4gICAgICAgICdFdmVudFBsdWdpblV0aWxzLmluamVjdGlvbi5pbmplY3RNb3VudCguLi4pOiBJbmplY3RlZCBNb3VudCBtb2R1bGUgJyArXG4gICAgICAgICdpcyBtaXNzaW5nIGdldE5vZGUuJ1xuICAgICAgKSA6IGludmFyaWFudChJbmplY3RlZE1vdW50ICYmIEluamVjdGVkTW91bnQuZ2V0Tm9kZSkpO1xuICAgIH1cbiAgfVxufTtcblxudmFyIHRvcExldmVsVHlwZXMgPSBFdmVudENvbnN0YW50cy50b3BMZXZlbFR5cGVzO1xuXG5mdW5jdGlvbiBpc0VuZGlzaCh0b3BMZXZlbFR5cGUpIHtcbiAgcmV0dXJuIHRvcExldmVsVHlwZSA9PT0gdG9wTGV2ZWxUeXBlcy50b3BNb3VzZVVwIHx8XG4gICAgICAgICB0b3BMZXZlbFR5cGUgPT09IHRvcExldmVsVHlwZXMudG9wVG91Y2hFbmQgfHxcbiAgICAgICAgIHRvcExldmVsVHlwZSA9PT0gdG9wTGV2ZWxUeXBlcy50b3BUb3VjaENhbmNlbDtcbn1cblxuZnVuY3Rpb24gaXNNb3ZlaXNoKHRvcExldmVsVHlwZSkge1xuICByZXR1cm4gdG9wTGV2ZWxUeXBlID09PSB0b3BMZXZlbFR5cGVzLnRvcE1vdXNlTW92ZSB8fFxuICAgICAgICAgdG9wTGV2ZWxUeXBlID09PSB0b3BMZXZlbFR5cGVzLnRvcFRvdWNoTW92ZTtcbn1cbmZ1bmN0aW9uIGlzU3RhcnRpc2godG9wTGV2ZWxUeXBlKSB7XG4gIHJldHVybiB0b3BMZXZlbFR5cGUgPT09IHRvcExldmVsVHlwZXMudG9wTW91c2VEb3duIHx8XG4gICAgICAgICB0b3BMZXZlbFR5cGUgPT09IHRvcExldmVsVHlwZXMudG9wVG91Y2hTdGFydDtcbn1cblxuXG52YXIgdmFsaWRhdGVFdmVudERpc3BhdGNoZXM7XG5pZiAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WKSB7XG4gIHZhbGlkYXRlRXZlbnREaXNwYXRjaGVzID0gZnVuY3Rpb24oZXZlbnQpIHtcbiAgICB2YXIgZGlzcGF0Y2hMaXN0ZW5lcnMgPSBldmVudC5fZGlzcGF0Y2hMaXN0ZW5lcnM7XG4gICAgdmFyIGRpc3BhdGNoSURzID0gZXZlbnQuX2Rpc3BhdGNoSURzO1xuXG4gICAgdmFyIGxpc3RlbmVyc0lzQXJyID0gQXJyYXkuaXNBcnJheShkaXNwYXRjaExpc3RlbmVycyk7XG4gICAgdmFyIGlkc0lzQXJyID0gQXJyYXkuaXNBcnJheShkaXNwYXRjaElEcyk7XG4gICAgdmFyIElEc0xlbiA9IGlkc0lzQXJyID8gZGlzcGF0Y2hJRHMubGVuZ3RoIDogZGlzcGF0Y2hJRHMgPyAxIDogMDtcbiAgICB2YXIgbGlzdGVuZXJzTGVuID0gbGlzdGVuZXJzSXNBcnIgP1xuICAgICAgZGlzcGF0Y2hMaXN0ZW5lcnMubGVuZ3RoIDpcbiAgICAgIGRpc3BhdGNoTGlzdGVuZXJzID8gMSA6IDA7XG5cbiAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgaWRzSXNBcnIgPT09IGxpc3RlbmVyc0lzQXJyICYmIElEc0xlbiA9PT0gbGlzdGVuZXJzTGVuLFxuICAgICAgJ0V2ZW50UGx1Z2luVXRpbHM6IEludmFsaWQgYGV2ZW50YC4nXG4gICAgKSA6IGludmFyaWFudChpZHNJc0FyciA9PT0gbGlzdGVuZXJzSXNBcnIgJiYgSURzTGVuID09PSBsaXN0ZW5lcnNMZW4pKTtcbiAgfTtcbn1cblxuLyoqXG4gKiBJbnZva2VzIGBjYihldmVudCwgbGlzdGVuZXIsIGlkKWAuIEF2b2lkcyB1c2luZyBjYWxsIGlmIG5vIHNjb3BlIGlzXG4gKiBwcm92aWRlZC4gVGhlIGAobGlzdGVuZXIsaWQpYCBwYWlyIGVmZmVjdGl2ZWx5IGZvcm1zIHRoZSBcImRpc3BhdGNoXCIgYnV0IGFyZVxuICoga2VwdCBzZXBhcmF0ZSB0byBjb25zZXJ2ZSBtZW1vcnkuXG4gKi9cbmZ1bmN0aW9uIGZvckVhY2hFdmVudERpc3BhdGNoKGV2ZW50LCBjYikge1xuICB2YXIgZGlzcGF0Y2hMaXN0ZW5lcnMgPSBldmVudC5fZGlzcGF0Y2hMaXN0ZW5lcnM7XG4gIHZhciBkaXNwYXRjaElEcyA9IGV2ZW50Ll9kaXNwYXRjaElEcztcbiAgaWYgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOVikge1xuICAgIHZhbGlkYXRlRXZlbnREaXNwYXRjaGVzKGV2ZW50KTtcbiAgfVxuICBpZiAoQXJyYXkuaXNBcnJheShkaXNwYXRjaExpc3RlbmVycykpIHtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGRpc3BhdGNoTGlzdGVuZXJzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBpZiAoZXZlbnQuaXNQcm9wYWdhdGlvblN0b3BwZWQoKSkge1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICAgIC8vIExpc3RlbmVycyBhbmQgSURzIGFyZSB0d28gcGFyYWxsZWwgYXJyYXlzIHRoYXQgYXJlIGFsd2F5cyBpbiBzeW5jLlxuICAgICAgY2IoZXZlbnQsIGRpc3BhdGNoTGlzdGVuZXJzW2ldLCBkaXNwYXRjaElEc1tpXSk7XG4gICAgfVxuICB9IGVsc2UgaWYgKGRpc3BhdGNoTGlzdGVuZXJzKSB7XG4gICAgY2IoZXZlbnQsIGRpc3BhdGNoTGlzdGVuZXJzLCBkaXNwYXRjaElEcyk7XG4gIH1cbn1cblxuLyoqXG4gKiBEZWZhdWx0IGltcGxlbWVudGF0aW9uIG9mIFBsdWdpbk1vZHVsZS5leGVjdXRlRGlzcGF0Y2goKS5cbiAqIEBwYXJhbSB7U3ludGhldGljRXZlbnR9IFN5bnRoZXRpY0V2ZW50IHRvIGhhbmRsZVxuICogQHBhcmFtIHtmdW5jdGlvbn0gQXBwbGljYXRpb24tbGV2ZWwgY2FsbGJhY2tcbiAqIEBwYXJhbSB7c3RyaW5nfSBkb21JRCBET00gaWQgdG8gcGFzcyB0byB0aGUgY2FsbGJhY2suXG4gKi9cbmZ1bmN0aW9uIGV4ZWN1dGVEaXNwYXRjaChldmVudCwgbGlzdGVuZXIsIGRvbUlEKSB7XG4gIGV2ZW50LmN1cnJlbnRUYXJnZXQgPSBpbmplY3Rpb24uTW91bnQuZ2V0Tm9kZShkb21JRCk7XG4gIHZhciByZXR1cm5WYWx1ZSA9IGxpc3RlbmVyKGV2ZW50LCBkb21JRCk7XG4gIGV2ZW50LmN1cnJlbnRUYXJnZXQgPSBudWxsO1xuICByZXR1cm4gcmV0dXJuVmFsdWU7XG59XG5cbi8qKlxuICogU3RhbmRhcmQvc2ltcGxlIGl0ZXJhdGlvbiB0aHJvdWdoIGFuIGV2ZW50J3MgY29sbGVjdGVkIGRpc3BhdGNoZXMuXG4gKi9cbmZ1bmN0aW9uIGV4ZWN1dGVEaXNwYXRjaGVzSW5PcmRlcihldmVudCwgZXhlY3V0ZURpc3BhdGNoKSB7XG4gIGZvckVhY2hFdmVudERpc3BhdGNoKGV2ZW50LCBleGVjdXRlRGlzcGF0Y2gpO1xuICBldmVudC5fZGlzcGF0Y2hMaXN0ZW5lcnMgPSBudWxsO1xuICBldmVudC5fZGlzcGF0Y2hJRHMgPSBudWxsO1xufVxuXG4vKipcbiAqIFN0YW5kYXJkL3NpbXBsZSBpdGVyYXRpb24gdGhyb3VnaCBhbiBldmVudCdzIGNvbGxlY3RlZCBkaXNwYXRjaGVzLCBidXQgc3RvcHNcbiAqIGF0IHRoZSBmaXJzdCBkaXNwYXRjaCBleGVjdXRpb24gcmV0dXJuaW5nIHRydWUsIGFuZCByZXR1cm5zIHRoYXQgaWQuXG4gKlxuICogQHJldHVybiBpZCBvZiB0aGUgZmlyc3QgZGlzcGF0Y2ggZXhlY3V0aW9uIHdobydzIGxpc3RlbmVyIHJldHVybnMgdHJ1ZSwgb3JcbiAqIG51bGwgaWYgbm8gbGlzdGVuZXIgcmV0dXJuZWQgdHJ1ZS5cbiAqL1xuZnVuY3Rpb24gZXhlY3V0ZURpc3BhdGNoZXNJbk9yZGVyU3RvcEF0VHJ1ZUltcGwoZXZlbnQpIHtcbiAgdmFyIGRpc3BhdGNoTGlzdGVuZXJzID0gZXZlbnQuX2Rpc3BhdGNoTGlzdGVuZXJzO1xuICB2YXIgZGlzcGF0Y2hJRHMgPSBldmVudC5fZGlzcGF0Y2hJRHM7XG4gIGlmIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYpIHtcbiAgICB2YWxpZGF0ZUV2ZW50RGlzcGF0Y2hlcyhldmVudCk7XG4gIH1cbiAgaWYgKEFycmF5LmlzQXJyYXkoZGlzcGF0Y2hMaXN0ZW5lcnMpKSB7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBkaXNwYXRjaExpc3RlbmVycy5sZW5ndGg7IGkrKykge1xuICAgICAgaWYgKGV2ZW50LmlzUHJvcGFnYXRpb25TdG9wcGVkKCkpIHtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICAvLyBMaXN0ZW5lcnMgYW5kIElEcyBhcmUgdHdvIHBhcmFsbGVsIGFycmF5cyB0aGF0IGFyZSBhbHdheXMgaW4gc3luYy5cbiAgICAgIGlmIChkaXNwYXRjaExpc3RlbmVyc1tpXShldmVudCwgZGlzcGF0Y2hJRHNbaV0pKSB7XG4gICAgICAgIHJldHVybiBkaXNwYXRjaElEc1tpXTtcbiAgICAgIH1cbiAgICB9XG4gIH0gZWxzZSBpZiAoZGlzcGF0Y2hMaXN0ZW5lcnMpIHtcbiAgICBpZiAoZGlzcGF0Y2hMaXN0ZW5lcnMoZXZlbnQsIGRpc3BhdGNoSURzKSkge1xuICAgICAgcmV0dXJuIGRpc3BhdGNoSURzO1xuICAgIH1cbiAgfVxuICByZXR1cm4gbnVsbDtcbn1cblxuLyoqXG4gKiBAc2VlIGV4ZWN1dGVEaXNwYXRjaGVzSW5PcmRlclN0b3BBdFRydWVJbXBsXG4gKi9cbmZ1bmN0aW9uIGV4ZWN1dGVEaXNwYXRjaGVzSW5PcmRlclN0b3BBdFRydWUoZXZlbnQpIHtcbiAgdmFyIHJldCA9IGV4ZWN1dGVEaXNwYXRjaGVzSW5PcmRlclN0b3BBdFRydWVJbXBsKGV2ZW50KTtcbiAgZXZlbnQuX2Rpc3BhdGNoSURzID0gbnVsbDtcbiAgZXZlbnQuX2Rpc3BhdGNoTGlzdGVuZXJzID0gbnVsbDtcbiAgcmV0dXJuIHJldDtcbn1cblxuLyoqXG4gKiBFeGVjdXRpb24gb2YgYSBcImRpcmVjdFwiIGRpc3BhdGNoIC0gdGhlcmUgbXVzdCBiZSBhdCBtb3N0IG9uZSBkaXNwYXRjaFxuICogYWNjdW11bGF0ZWQgb24gdGhlIGV2ZW50IG9yIGl0IGlzIGNvbnNpZGVyZWQgYW4gZXJyb3IuIEl0IGRvZXNuJ3QgcmVhbGx5IG1ha2VcbiAqIHNlbnNlIGZvciBhbiBldmVudCB3aXRoIG11bHRpcGxlIGRpc3BhdGNoZXMgKGJ1YmJsZWQpIHRvIGtlZXAgdHJhY2sgb2YgdGhlXG4gKiByZXR1cm4gdmFsdWVzIGF0IGVhY2ggZGlzcGF0Y2ggZXhlY3V0aW9uLCBidXQgaXQgZG9lcyB0ZW5kIHRvIG1ha2Ugc2Vuc2Ugd2hlblxuICogZGVhbGluZyB3aXRoIFwiZGlyZWN0XCIgZGlzcGF0Y2hlcy5cbiAqXG4gKiBAcmV0dXJuIFRoZSByZXR1cm4gdmFsdWUgb2YgZXhlY3V0aW5nIHRoZSBzaW5nbGUgZGlzcGF0Y2guXG4gKi9cbmZ1bmN0aW9uIGV4ZWN1dGVEaXJlY3REaXNwYXRjaChldmVudCkge1xuICBpZiAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WKSB7XG4gICAgdmFsaWRhdGVFdmVudERpc3BhdGNoZXMoZXZlbnQpO1xuICB9XG4gIHZhciBkaXNwYXRjaExpc3RlbmVyID0gZXZlbnQuX2Rpc3BhdGNoTGlzdGVuZXJzO1xuICB2YXIgZGlzcGF0Y2hJRCA9IGV2ZW50Ll9kaXNwYXRjaElEcztcbiAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAhQXJyYXkuaXNBcnJheShkaXNwYXRjaExpc3RlbmVyKSxcbiAgICAnZXhlY3V0ZURpcmVjdERpc3BhdGNoKC4uLik6IEludmFsaWQgYGV2ZW50YC4nXG4gICkgOiBpbnZhcmlhbnQoIUFycmF5LmlzQXJyYXkoZGlzcGF0Y2hMaXN0ZW5lcikpKTtcbiAgdmFyIHJlcyA9IGRpc3BhdGNoTGlzdGVuZXIgP1xuICAgIGRpc3BhdGNoTGlzdGVuZXIoZXZlbnQsIGRpc3BhdGNoSUQpIDpcbiAgICBudWxsO1xuICBldmVudC5fZGlzcGF0Y2hMaXN0ZW5lcnMgPSBudWxsO1xuICBldmVudC5fZGlzcGF0Y2hJRHMgPSBudWxsO1xuICByZXR1cm4gcmVzO1xufVxuXG4vKipcbiAqIEBwYXJhbSB7U3ludGhldGljRXZlbnR9IGV2ZW50XG4gKiBAcmV0dXJuIHtib29sfSBUcnVlIGlmZiBudW1iZXIgb2YgZGlzcGF0Y2hlcyBhY2N1bXVsYXRlZCBpcyBncmVhdGVyIHRoYW4gMC5cbiAqL1xuZnVuY3Rpb24gaGFzRGlzcGF0Y2hlcyhldmVudCkge1xuICByZXR1cm4gISFldmVudC5fZGlzcGF0Y2hMaXN0ZW5lcnM7XG59XG5cbi8qKlxuICogR2VuZXJhbCB1dGlsaXRpZXMgdGhhdCBhcmUgdXNlZnVsIGluIGNyZWF0aW5nIGN1c3RvbSBFdmVudCBQbHVnaW5zLlxuICovXG52YXIgRXZlbnRQbHVnaW5VdGlscyA9IHtcbiAgaXNFbmRpc2g6IGlzRW5kaXNoLFxuICBpc01vdmVpc2g6IGlzTW92ZWlzaCxcbiAgaXNTdGFydGlzaDogaXNTdGFydGlzaCxcblxuICBleGVjdXRlRGlyZWN0RGlzcGF0Y2g6IGV4ZWN1dGVEaXJlY3REaXNwYXRjaCxcbiAgZXhlY3V0ZURpc3BhdGNoOiBleGVjdXRlRGlzcGF0Y2gsXG4gIGV4ZWN1dGVEaXNwYXRjaGVzSW5PcmRlcjogZXhlY3V0ZURpc3BhdGNoZXNJbk9yZGVyLFxuICBleGVjdXRlRGlzcGF0Y2hlc0luT3JkZXJTdG9wQXRUcnVlOiBleGVjdXRlRGlzcGF0Y2hlc0luT3JkZXJTdG9wQXRUcnVlLFxuICBoYXNEaXNwYXRjaGVzOiBoYXNEaXNwYXRjaGVzLFxuICBpbmplY3Rpb246IGluamVjdGlvbixcbiAgdXNlVG91Y2hFdmVudHM6IGZhbHNlXG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IEV2ZW50UGx1Z2luVXRpbHM7XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKCdfcHJvY2VzcycpKSIsIihmdW5jdGlvbiAocHJvY2Vzcyl7XG4vKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgRXZlbnRQcm9wYWdhdG9yc1xuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgRXZlbnRDb25zdGFudHMgPSByZXF1aXJlKFwiLi9FdmVudENvbnN0YW50c1wiKTtcbnZhciBFdmVudFBsdWdpbkh1YiA9IHJlcXVpcmUoXCIuL0V2ZW50UGx1Z2luSHViXCIpO1xuXG52YXIgYWNjdW11bGF0ZUludG8gPSByZXF1aXJlKFwiLi9hY2N1bXVsYXRlSW50b1wiKTtcbnZhciBmb3JFYWNoQWNjdW11bGF0ZWQgPSByZXF1aXJlKFwiLi9mb3JFYWNoQWNjdW11bGF0ZWRcIik7XG5cbnZhciBQcm9wYWdhdGlvblBoYXNlcyA9IEV2ZW50Q29uc3RhbnRzLlByb3BhZ2F0aW9uUGhhc2VzO1xudmFyIGdldExpc3RlbmVyID0gRXZlbnRQbHVnaW5IdWIuZ2V0TGlzdGVuZXI7XG5cbi8qKlxuICogU29tZSBldmVudCB0eXBlcyBoYXZlIGEgbm90aW9uIG9mIGRpZmZlcmVudCByZWdpc3RyYXRpb24gbmFtZXMgZm9yIGRpZmZlcmVudFxuICogXCJwaGFzZXNcIiBvZiBwcm9wYWdhdGlvbi4gVGhpcyBmaW5kcyBsaXN0ZW5lcnMgYnkgYSBnaXZlbiBwaGFzZS5cbiAqL1xuZnVuY3Rpb24gbGlzdGVuZXJBdFBoYXNlKGlkLCBldmVudCwgcHJvcGFnYXRpb25QaGFzZSkge1xuICB2YXIgcmVnaXN0cmF0aW9uTmFtZSA9XG4gICAgZXZlbnQuZGlzcGF0Y2hDb25maWcucGhhc2VkUmVnaXN0cmF0aW9uTmFtZXNbcHJvcGFnYXRpb25QaGFzZV07XG4gIHJldHVybiBnZXRMaXN0ZW5lcihpZCwgcmVnaXN0cmF0aW9uTmFtZSk7XG59XG5cbi8qKlxuICogVGFncyBhIGBTeW50aGV0aWNFdmVudGAgd2l0aCBkaXNwYXRjaGVkIGxpc3RlbmVycy4gQ3JlYXRpbmcgdGhpcyBmdW5jdGlvblxuICogaGVyZSwgYWxsb3dzIHVzIHRvIG5vdCBoYXZlIHRvIGJpbmQgb3IgY3JlYXRlIGZ1bmN0aW9ucyBmb3IgZWFjaCBldmVudC5cbiAqIE11dGF0aW5nIHRoZSBldmVudCdzIG1lbWJlcnMgYWxsb3dzIHVzIHRvIG5vdCBoYXZlIHRvIGNyZWF0ZSBhIHdyYXBwaW5nXG4gKiBcImRpc3BhdGNoXCIgb2JqZWN0IHRoYXQgcGFpcnMgdGhlIGV2ZW50IHdpdGggdGhlIGxpc3RlbmVyLlxuICovXG5mdW5jdGlvbiBhY2N1bXVsYXRlRGlyZWN0aW9uYWxEaXNwYXRjaGVzKGRvbUlELCB1cHdhcmRzLCBldmVudCkge1xuICBpZiAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WKSB7XG4gICAgaWYgKCFkb21JRCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdEaXNwYXRjaGluZyBpZCBtdXN0IG5vdCBiZSBudWxsJyk7XG4gICAgfVxuICB9XG4gIHZhciBwaGFzZSA9IHVwd2FyZHMgPyBQcm9wYWdhdGlvblBoYXNlcy5idWJibGVkIDogUHJvcGFnYXRpb25QaGFzZXMuY2FwdHVyZWQ7XG4gIHZhciBsaXN0ZW5lciA9IGxpc3RlbmVyQXRQaGFzZShkb21JRCwgZXZlbnQsIHBoYXNlKTtcbiAgaWYgKGxpc3RlbmVyKSB7XG4gICAgZXZlbnQuX2Rpc3BhdGNoTGlzdGVuZXJzID1cbiAgICAgIGFjY3VtdWxhdGVJbnRvKGV2ZW50Ll9kaXNwYXRjaExpc3RlbmVycywgbGlzdGVuZXIpO1xuICAgIGV2ZW50Ll9kaXNwYXRjaElEcyA9IGFjY3VtdWxhdGVJbnRvKGV2ZW50Ll9kaXNwYXRjaElEcywgZG9tSUQpO1xuICB9XG59XG5cbi8qKlxuICogQ29sbGVjdCBkaXNwYXRjaGVzIChtdXN0IGJlIGVudGlyZWx5IGNvbGxlY3RlZCBiZWZvcmUgZGlzcGF0Y2hpbmcgLSBzZWUgdW5pdFxuICogdGVzdHMpLiBMYXppbHkgYWxsb2NhdGUgdGhlIGFycmF5IHRvIGNvbnNlcnZlIG1lbW9yeS4gIFdlIG11c3QgbG9vcCB0aHJvdWdoXG4gKiBlYWNoIGV2ZW50IGFuZCBwZXJmb3JtIHRoZSB0cmF2ZXJzYWwgZm9yIGVhY2ggb25lLiBXZSBjYW4gbm90IHBlcmZvcm0gYVxuICogc2luZ2xlIHRyYXZlcnNhbCBmb3IgdGhlIGVudGlyZSBjb2xsZWN0aW9uIG9mIGV2ZW50cyBiZWNhdXNlIGVhY2ggZXZlbnQgbWF5XG4gKiBoYXZlIGEgZGlmZmVyZW50IHRhcmdldC5cbiAqL1xuZnVuY3Rpb24gYWNjdW11bGF0ZVR3b1BoYXNlRGlzcGF0Y2hlc1NpbmdsZShldmVudCkge1xuICBpZiAoZXZlbnQgJiYgZXZlbnQuZGlzcGF0Y2hDb25maWcucGhhc2VkUmVnaXN0cmF0aW9uTmFtZXMpIHtcbiAgICBFdmVudFBsdWdpbkh1Yi5pbmplY3Rpb24uZ2V0SW5zdGFuY2VIYW5kbGUoKS50cmF2ZXJzZVR3b1BoYXNlKFxuICAgICAgZXZlbnQuZGlzcGF0Y2hNYXJrZXIsXG4gICAgICBhY2N1bXVsYXRlRGlyZWN0aW9uYWxEaXNwYXRjaGVzLFxuICAgICAgZXZlbnRcbiAgICApO1xuICB9XG59XG5cblxuLyoqXG4gKiBBY2N1bXVsYXRlcyB3aXRob3V0IHJlZ2FyZCB0byBkaXJlY3Rpb24sIGRvZXMgbm90IGxvb2sgZm9yIHBoYXNlZFxuICogcmVnaXN0cmF0aW9uIG5hbWVzLiBTYW1lIGFzIGBhY2N1bXVsYXRlRGlyZWN0RGlzcGF0Y2hlc1NpbmdsZWAgYnV0IHdpdGhvdXRcbiAqIHJlcXVpcmluZyB0aGF0IHRoZSBgZGlzcGF0Y2hNYXJrZXJgIGJlIHRoZSBzYW1lIGFzIHRoZSBkaXNwYXRjaGVkIElELlxuICovXG5mdW5jdGlvbiBhY2N1bXVsYXRlRGlzcGF0Y2hlcyhpZCwgaWdub3JlZERpcmVjdGlvbiwgZXZlbnQpIHtcbiAgaWYgKGV2ZW50ICYmIGV2ZW50LmRpc3BhdGNoQ29uZmlnLnJlZ2lzdHJhdGlvbk5hbWUpIHtcbiAgICB2YXIgcmVnaXN0cmF0aW9uTmFtZSA9IGV2ZW50LmRpc3BhdGNoQ29uZmlnLnJlZ2lzdHJhdGlvbk5hbWU7XG4gICAgdmFyIGxpc3RlbmVyID0gZ2V0TGlzdGVuZXIoaWQsIHJlZ2lzdHJhdGlvbk5hbWUpO1xuICAgIGlmIChsaXN0ZW5lcikge1xuICAgICAgZXZlbnQuX2Rpc3BhdGNoTGlzdGVuZXJzID1cbiAgICAgICAgYWNjdW11bGF0ZUludG8oZXZlbnQuX2Rpc3BhdGNoTGlzdGVuZXJzLCBsaXN0ZW5lcik7XG4gICAgICBldmVudC5fZGlzcGF0Y2hJRHMgPSBhY2N1bXVsYXRlSW50byhldmVudC5fZGlzcGF0Y2hJRHMsIGlkKTtcbiAgICB9XG4gIH1cbn1cblxuLyoqXG4gKiBBY2N1bXVsYXRlcyBkaXNwYXRjaGVzIG9uIGFuIGBTeW50aGV0aWNFdmVudGAsIGJ1dCBvbmx5IGZvciB0aGVcbiAqIGBkaXNwYXRjaE1hcmtlcmAuXG4gKiBAcGFyYW0ge1N5bnRoZXRpY0V2ZW50fSBldmVudFxuICovXG5mdW5jdGlvbiBhY2N1bXVsYXRlRGlyZWN0RGlzcGF0Y2hlc1NpbmdsZShldmVudCkge1xuICBpZiAoZXZlbnQgJiYgZXZlbnQuZGlzcGF0Y2hDb25maWcucmVnaXN0cmF0aW9uTmFtZSkge1xuICAgIGFjY3VtdWxhdGVEaXNwYXRjaGVzKGV2ZW50LmRpc3BhdGNoTWFya2VyLCBudWxsLCBldmVudCk7XG4gIH1cbn1cblxuZnVuY3Rpb24gYWNjdW11bGF0ZVR3b1BoYXNlRGlzcGF0Y2hlcyhldmVudHMpIHtcbiAgZm9yRWFjaEFjY3VtdWxhdGVkKGV2ZW50cywgYWNjdW11bGF0ZVR3b1BoYXNlRGlzcGF0Y2hlc1NpbmdsZSk7XG59XG5cbmZ1bmN0aW9uIGFjY3VtdWxhdGVFbnRlckxlYXZlRGlzcGF0Y2hlcyhsZWF2ZSwgZW50ZXIsIGZyb21JRCwgdG9JRCkge1xuICBFdmVudFBsdWdpbkh1Yi5pbmplY3Rpb24uZ2V0SW5zdGFuY2VIYW5kbGUoKS50cmF2ZXJzZUVudGVyTGVhdmUoXG4gICAgZnJvbUlELFxuICAgIHRvSUQsXG4gICAgYWNjdW11bGF0ZURpc3BhdGNoZXMsXG4gICAgbGVhdmUsXG4gICAgZW50ZXJcbiAgKTtcbn1cblxuXG5mdW5jdGlvbiBhY2N1bXVsYXRlRGlyZWN0RGlzcGF0Y2hlcyhldmVudHMpIHtcbiAgZm9yRWFjaEFjY3VtdWxhdGVkKGV2ZW50cywgYWNjdW11bGF0ZURpcmVjdERpc3BhdGNoZXNTaW5nbGUpO1xufVxuXG5cblxuLyoqXG4gKiBBIHNtYWxsIHNldCBvZiBwcm9wYWdhdGlvbiBwYXR0ZXJucywgZWFjaCBvZiB3aGljaCB3aWxsIGFjY2VwdCBhIHNtYWxsIGFtb3VudFxuICogb2YgaW5mb3JtYXRpb24sIGFuZCBnZW5lcmF0ZSBhIHNldCBvZiBcImRpc3BhdGNoIHJlYWR5IGV2ZW50IG9iamVjdHNcIiAtIHdoaWNoXG4gKiBhcmUgc2V0cyBvZiBldmVudHMgdGhhdCBoYXZlIGFscmVhZHkgYmVlbiBhbm5vdGF0ZWQgd2l0aCBhIHNldCBvZiBkaXNwYXRjaGVkXG4gKiBsaXN0ZW5lciBmdW5jdGlvbnMvaWRzLiBUaGUgQVBJIGlzIGRlc2lnbmVkIHRoaXMgd2F5IHRvIGRpc2NvdXJhZ2UgdGhlc2VcbiAqIHByb3BhZ2F0aW9uIHN0cmF0ZWdpZXMgZnJvbSBhY3R1YWxseSBleGVjdXRpbmcgdGhlIGRpc3BhdGNoZXMsIHNpbmNlIHdlXG4gKiBhbHdheXMgd2FudCB0byBjb2xsZWN0IHRoZSBlbnRpcmUgc2V0IG9mIGRpc3BhdGNoZXMgYmVmb3JlIGV4ZWN1dGluZyBldmVudCBhXG4gKiBzaW5nbGUgb25lLlxuICpcbiAqIEBjb25zdHJ1Y3RvciBFdmVudFByb3BhZ2F0b3JzXG4gKi9cbnZhciBFdmVudFByb3BhZ2F0b3JzID0ge1xuICBhY2N1bXVsYXRlVHdvUGhhc2VEaXNwYXRjaGVzOiBhY2N1bXVsYXRlVHdvUGhhc2VEaXNwYXRjaGVzLFxuICBhY2N1bXVsYXRlRGlyZWN0RGlzcGF0Y2hlczogYWNjdW11bGF0ZURpcmVjdERpc3BhdGNoZXMsXG4gIGFjY3VtdWxhdGVFbnRlckxlYXZlRGlzcGF0Y2hlczogYWNjdW11bGF0ZUVudGVyTGVhdmVEaXNwYXRjaGVzXG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IEV2ZW50UHJvcGFnYXRvcnM7XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKCdfcHJvY2VzcycpKSIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBFeGVjdXRpb25FbnZpcm9ubWVudFxuICovXG5cbi8qanNsaW50IGV2aWw6IHRydWUgKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBjYW5Vc2VET00gPSAhIShcbiAgdHlwZW9mIHdpbmRvdyAhPT0gJ3VuZGVmaW5lZCcgJiZcbiAgd2luZG93LmRvY3VtZW50ICYmXG4gIHdpbmRvdy5kb2N1bWVudC5jcmVhdGVFbGVtZW50XG4pO1xuXG4vKipcbiAqIFNpbXBsZSwgbGlnaHR3ZWlnaHQgbW9kdWxlIGFzc2lzdGluZyB3aXRoIHRoZSBkZXRlY3Rpb24gYW5kIGNvbnRleHQgb2ZcbiAqIFdvcmtlci4gSGVscHMgYXZvaWQgY2lyY3VsYXIgZGVwZW5kZW5jaWVzIGFuZCBhbGxvd3MgY29kZSB0byByZWFzb24gYWJvdXRcbiAqIHdoZXRoZXIgb3Igbm90IHRoZXkgYXJlIGluIGEgV29ya2VyLCBldmVuIGlmIHRoZXkgbmV2ZXIgaW5jbHVkZSB0aGUgbWFpblxuICogYFJlYWN0V29ya2VyYCBkZXBlbmRlbmN5LlxuICovXG52YXIgRXhlY3V0aW9uRW52aXJvbm1lbnQgPSB7XG5cbiAgY2FuVXNlRE9NOiBjYW5Vc2VET00sXG5cbiAgY2FuVXNlV29ya2VyczogdHlwZW9mIFdvcmtlciAhPT0gJ3VuZGVmaW5lZCcsXG5cbiAgY2FuVXNlRXZlbnRMaXN0ZW5lcnM6XG4gICAgY2FuVXNlRE9NICYmICEhKHdpbmRvdy5hZGRFdmVudExpc3RlbmVyIHx8IHdpbmRvdy5hdHRhY2hFdmVudCksXG5cbiAgY2FuVXNlVmlld3BvcnQ6IGNhblVzZURPTSAmJiAhIXdpbmRvdy5zY3JlZW4sXG5cbiAgaXNJbldvcmtlcjogIWNhblVzZURPTSAvLyBGb3Igbm93LCB0aGlzIGlzIHRydWUgLSBtaWdodCBjaGFuZ2UgaW4gdGhlIGZ1dHVyZS5cblxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBFeGVjdXRpb25FbnZpcm9ubWVudDtcbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBIVE1MRE9NUHJvcGVydHlDb25maWdcbiAqL1xuXG4vKmpzbGludCBiaXR3aXNlOiB0cnVlKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBET01Qcm9wZXJ0eSA9IHJlcXVpcmUoXCIuL0RPTVByb3BlcnR5XCIpO1xudmFyIEV4ZWN1dGlvbkVudmlyb25tZW50ID0gcmVxdWlyZShcIi4vRXhlY3V0aW9uRW52aXJvbm1lbnRcIik7XG5cbnZhciBNVVNUX1VTRV9BVFRSSUJVVEUgPSBET01Qcm9wZXJ0eS5pbmplY3Rpb24uTVVTVF9VU0VfQVRUUklCVVRFO1xudmFyIE1VU1RfVVNFX1BST1BFUlRZID0gRE9NUHJvcGVydHkuaW5qZWN0aW9uLk1VU1RfVVNFX1BST1BFUlRZO1xudmFyIEhBU19CT09MRUFOX1ZBTFVFID0gRE9NUHJvcGVydHkuaW5qZWN0aW9uLkhBU19CT09MRUFOX1ZBTFVFO1xudmFyIEhBU19TSURFX0VGRkVDVFMgPSBET01Qcm9wZXJ0eS5pbmplY3Rpb24uSEFTX1NJREVfRUZGRUNUUztcbnZhciBIQVNfTlVNRVJJQ19WQUxVRSA9IERPTVByb3BlcnR5LmluamVjdGlvbi5IQVNfTlVNRVJJQ19WQUxVRTtcbnZhciBIQVNfUE9TSVRJVkVfTlVNRVJJQ19WQUxVRSA9XG4gIERPTVByb3BlcnR5LmluamVjdGlvbi5IQVNfUE9TSVRJVkVfTlVNRVJJQ19WQUxVRTtcbnZhciBIQVNfT1ZFUkxPQURFRF9CT09MRUFOX1ZBTFVFID1cbiAgRE9NUHJvcGVydHkuaW5qZWN0aW9uLkhBU19PVkVSTE9BREVEX0JPT0xFQU5fVkFMVUU7XG5cbnZhciBoYXNTVkc7XG5pZiAoRXhlY3V0aW9uRW52aXJvbm1lbnQuY2FuVXNlRE9NKSB7XG4gIHZhciBpbXBsZW1lbnRhdGlvbiA9IGRvY3VtZW50LmltcGxlbWVudGF0aW9uO1xuICBoYXNTVkcgPSAoXG4gICAgaW1wbGVtZW50YXRpb24gJiZcbiAgICBpbXBsZW1lbnRhdGlvbi5oYXNGZWF0dXJlICYmXG4gICAgaW1wbGVtZW50YXRpb24uaGFzRmVhdHVyZShcbiAgICAgICdodHRwOi8vd3d3LnczLm9yZy9UUi9TVkcxMS9mZWF0dXJlI0Jhc2ljU3RydWN0dXJlJyxcbiAgICAgICcxLjEnXG4gICAgKVxuICApO1xufVxuXG5cbnZhciBIVE1MRE9NUHJvcGVydHlDb25maWcgPSB7XG4gIGlzQ3VzdG9tQXR0cmlidXRlOiBSZWdFeHAucHJvdG90eXBlLnRlc3QuYmluZChcbiAgICAvXihkYXRhfGFyaWEpLVthLXpfXVthLXpcXGRfLlxcLV0qJC9cbiAgKSxcbiAgUHJvcGVydGllczoge1xuICAgIC8qKlxuICAgICAqIFN0YW5kYXJkIFByb3BlcnRpZXNcbiAgICAgKi9cbiAgICBhY2NlcHQ6IG51bGwsXG4gICAgYWNjZXB0Q2hhcnNldDogbnVsbCxcbiAgICBhY2Nlc3NLZXk6IG51bGwsXG4gICAgYWN0aW9uOiBudWxsLFxuICAgIGFsbG93RnVsbFNjcmVlbjogTVVTVF9VU0VfQVRUUklCVVRFIHwgSEFTX0JPT0xFQU5fVkFMVUUsXG4gICAgYWxsb3dUcmFuc3BhcmVuY3k6IE1VU1RfVVNFX0FUVFJJQlVURSxcbiAgICBhbHQ6IG51bGwsXG4gICAgYXN5bmM6IEhBU19CT09MRUFOX1ZBTFVFLFxuICAgIGF1dG9Db21wbGV0ZTogbnVsbCxcbiAgICAvLyBhdXRvRm9jdXMgaXMgcG9seWZpbGxlZC9ub3JtYWxpemVkIGJ5IEF1dG9Gb2N1c01peGluXG4gICAgLy8gYXV0b0ZvY3VzOiBIQVNfQk9PTEVBTl9WQUxVRSxcbiAgICBhdXRvUGxheTogSEFTX0JPT0xFQU5fVkFMVUUsXG4gICAgY2VsbFBhZGRpbmc6IG51bGwsXG4gICAgY2VsbFNwYWNpbmc6IG51bGwsXG4gICAgY2hhclNldDogTVVTVF9VU0VfQVRUUklCVVRFLFxuICAgIGNoZWNrZWQ6IE1VU1RfVVNFX1BST1BFUlRZIHwgSEFTX0JPT0xFQU5fVkFMVUUsXG4gICAgY2xhc3NJRDogTVVTVF9VU0VfQVRUUklCVVRFLFxuICAgIC8vIFRvIHNldCBjbGFzc05hbWUgb24gU1ZHIGVsZW1lbnRzLCBpdCdzIG5lY2Vzc2FyeSB0byB1c2UgLnNldEF0dHJpYnV0ZTtcbiAgICAvLyB0aGlzIHdvcmtzIG9uIEhUTUwgZWxlbWVudHMgdG9vIGluIGFsbCBicm93c2VycyBleGNlcHQgSUU4LiBDb252ZW5pZW50bHksXG4gICAgLy8gSUU4IGRvZXNuJ3Qgc3VwcG9ydCBTVkcgYW5kIHNvIHdlIGNhbiBzaW1wbHkgdXNlIHRoZSBhdHRyaWJ1dGUgaW5cbiAgICAvLyBicm93c2VycyB0aGF0IHN1cHBvcnQgU1ZHIGFuZCB0aGUgcHJvcGVydHkgaW4gYnJvd3NlcnMgdGhhdCBkb24ndCxcbiAgICAvLyByZWdhcmRsZXNzIG9mIHdoZXRoZXIgdGhlIGVsZW1lbnQgaXMgSFRNTCBvciBTVkcuXG4gICAgY2xhc3NOYW1lOiBoYXNTVkcgPyBNVVNUX1VTRV9BVFRSSUJVVEUgOiBNVVNUX1VTRV9QUk9QRVJUWSxcbiAgICBjb2xzOiBNVVNUX1VTRV9BVFRSSUJVVEUgfCBIQVNfUE9TSVRJVkVfTlVNRVJJQ19WQUxVRSxcbiAgICBjb2xTcGFuOiBudWxsLFxuICAgIGNvbnRlbnQ6IG51bGwsXG4gICAgY29udGVudEVkaXRhYmxlOiBudWxsLFxuICAgIGNvbnRleHRNZW51OiBNVVNUX1VTRV9BVFRSSUJVVEUsXG4gICAgY29udHJvbHM6IE1VU1RfVVNFX1BST1BFUlRZIHwgSEFTX0JPT0xFQU5fVkFMVUUsXG4gICAgY29vcmRzOiBudWxsLFxuICAgIGNyb3NzT3JpZ2luOiBudWxsLFxuICAgIGRhdGE6IG51bGwsIC8vIEZvciBgPG9iamVjdCAvPmAgYWN0cyBhcyBgc3JjYC5cbiAgICBkYXRlVGltZTogTVVTVF9VU0VfQVRUUklCVVRFLFxuICAgIGRlZmVyOiBIQVNfQk9PTEVBTl9WQUxVRSxcbiAgICBkaXI6IG51bGwsXG4gICAgZGlzYWJsZWQ6IE1VU1RfVVNFX0FUVFJJQlVURSB8IEhBU19CT09MRUFOX1ZBTFVFLFxuICAgIGRvd25sb2FkOiBIQVNfT1ZFUkxPQURFRF9CT09MRUFOX1ZBTFVFLFxuICAgIGRyYWdnYWJsZTogbnVsbCxcbiAgICBlbmNUeXBlOiBudWxsLFxuICAgIGZvcm06IE1VU1RfVVNFX0FUVFJJQlVURSxcbiAgICBmb3JtTm9WYWxpZGF0ZTogSEFTX0JPT0xFQU5fVkFMVUUsXG4gICAgZnJhbWVCb3JkZXI6IE1VU1RfVVNFX0FUVFJJQlVURSxcbiAgICBoZWlnaHQ6IE1VU1RfVVNFX0FUVFJJQlVURSxcbiAgICBoaWRkZW46IE1VU1RfVVNFX0FUVFJJQlVURSB8IEhBU19CT09MRUFOX1ZBTFVFLFxuICAgIGhyZWY6IG51bGwsXG4gICAgaHJlZkxhbmc6IG51bGwsXG4gICAgaHRtbEZvcjogbnVsbCxcbiAgICBodHRwRXF1aXY6IG51bGwsXG4gICAgaWNvbjogbnVsbCxcbiAgICBpZDogTVVTVF9VU0VfUFJPUEVSVFksXG4gICAgbGFiZWw6IG51bGwsXG4gICAgbGFuZzogbnVsbCxcbiAgICBsaXN0OiBNVVNUX1VTRV9BVFRSSUJVVEUsXG4gICAgbG9vcDogTVVTVF9VU0VfUFJPUEVSVFkgfCBIQVNfQk9PTEVBTl9WQUxVRSxcbiAgICBtYW5pZmVzdDogTVVTVF9VU0VfQVRUUklCVVRFLFxuICAgIG1heDogbnVsbCxcbiAgICBtYXhMZW5ndGg6IE1VU1RfVVNFX0FUVFJJQlVURSxcbiAgICBtZWRpYTogTVVTVF9VU0VfQVRUUklCVVRFLFxuICAgIG1lZGlhR3JvdXA6IG51bGwsXG4gICAgbWV0aG9kOiBudWxsLFxuICAgIG1pbjogbnVsbCxcbiAgICBtdWx0aXBsZTogTVVTVF9VU0VfUFJPUEVSVFkgfCBIQVNfQk9PTEVBTl9WQUxVRSxcbiAgICBtdXRlZDogTVVTVF9VU0VfUFJPUEVSVFkgfCBIQVNfQk9PTEVBTl9WQUxVRSxcbiAgICBuYW1lOiBudWxsLFxuICAgIG5vVmFsaWRhdGU6IEhBU19CT09MRUFOX1ZBTFVFLFxuICAgIG9wZW46IG51bGwsXG4gICAgcGF0dGVybjogbnVsbCxcbiAgICBwbGFjZWhvbGRlcjogbnVsbCxcbiAgICBwb3N0ZXI6IG51bGwsXG4gICAgcHJlbG9hZDogbnVsbCxcbiAgICByYWRpb0dyb3VwOiBudWxsLFxuICAgIHJlYWRPbmx5OiBNVVNUX1VTRV9QUk9QRVJUWSB8IEhBU19CT09MRUFOX1ZBTFVFLFxuICAgIHJlbDogbnVsbCxcbiAgICByZXF1aXJlZDogSEFTX0JPT0xFQU5fVkFMVUUsXG4gICAgcm9sZTogTVVTVF9VU0VfQVRUUklCVVRFLFxuICAgIHJvd3M6IE1VU1RfVVNFX0FUVFJJQlVURSB8IEhBU19QT1NJVElWRV9OVU1FUklDX1ZBTFVFLFxuICAgIHJvd1NwYW46IG51bGwsXG4gICAgc2FuZGJveDogbnVsbCxcbiAgICBzY29wZTogbnVsbCxcbiAgICBzY3JvbGxpbmc6IG51bGwsXG4gICAgc2VhbWxlc3M6IE1VU1RfVVNFX0FUVFJJQlVURSB8IEhBU19CT09MRUFOX1ZBTFVFLFxuICAgIHNlbGVjdGVkOiBNVVNUX1VTRV9QUk9QRVJUWSB8IEhBU19CT09MRUFOX1ZBTFVFLFxuICAgIHNoYXBlOiBudWxsLFxuICAgIHNpemU6IE1VU1RfVVNFX0FUVFJJQlVURSB8IEhBU19QT1NJVElWRV9OVU1FUklDX1ZBTFVFLFxuICAgIHNpemVzOiBNVVNUX1VTRV9BVFRSSUJVVEUsXG4gICAgc3BhbjogSEFTX1BPU0lUSVZFX05VTUVSSUNfVkFMVUUsXG4gICAgc3BlbGxDaGVjazogbnVsbCxcbiAgICBzcmM6IG51bGwsXG4gICAgc3JjRG9jOiBNVVNUX1VTRV9QUk9QRVJUWSxcbiAgICBzcmNTZXQ6IE1VU1RfVVNFX0FUVFJJQlVURSxcbiAgICBzdGFydDogSEFTX05VTUVSSUNfVkFMVUUsXG4gICAgc3RlcDogbnVsbCxcbiAgICBzdHlsZTogbnVsbCxcbiAgICB0YWJJbmRleDogbnVsbCxcbiAgICB0YXJnZXQ6IG51bGwsXG4gICAgdGl0bGU6IG51bGwsXG4gICAgdHlwZTogbnVsbCxcbiAgICB1c2VNYXA6IG51bGwsXG4gICAgdmFsdWU6IE1VU1RfVVNFX1BST1BFUlRZIHwgSEFTX1NJREVfRUZGRUNUUyxcbiAgICB3aWR0aDogTVVTVF9VU0VfQVRUUklCVVRFLFxuICAgIHdtb2RlOiBNVVNUX1VTRV9BVFRSSUJVVEUsXG5cbiAgICAvKipcbiAgICAgKiBOb24tc3RhbmRhcmQgUHJvcGVydGllc1xuICAgICAqL1xuICAgIGF1dG9DYXBpdGFsaXplOiBudWxsLCAvLyBTdXBwb3J0ZWQgaW4gTW9iaWxlIFNhZmFyaSBmb3Iga2V5Ym9hcmQgaGludHNcbiAgICBhdXRvQ29ycmVjdDogbnVsbCwgLy8gU3VwcG9ydGVkIGluIE1vYmlsZSBTYWZhcmkgZm9yIGtleWJvYXJkIGhpbnRzXG4gICAgaXRlbVByb3A6IE1VU1RfVVNFX0FUVFJJQlVURSwgLy8gTWljcm9kYXRhOiBodHRwOi8vc2NoZW1hLm9yZy9kb2NzL2dzLmh0bWxcbiAgICBpdGVtU2NvcGU6IE1VU1RfVVNFX0FUVFJJQlVURSB8IEhBU19CT09MRUFOX1ZBTFVFLCAvLyBNaWNyb2RhdGE6IGh0dHA6Ly9zY2hlbWEub3JnL2RvY3MvZ3MuaHRtbFxuICAgIGl0ZW1UeXBlOiBNVVNUX1VTRV9BVFRSSUJVVEUsIC8vIE1pY3JvZGF0YTogaHR0cDovL3NjaGVtYS5vcmcvZG9jcy9ncy5odG1sXG4gICAgcHJvcGVydHk6IG51bGwgLy8gU3VwcG9ydHMgT0cgaW4gbWV0YSB0YWdzXG4gIH0sXG4gIERPTUF0dHJpYnV0ZU5hbWVzOiB7XG4gICAgYWNjZXB0Q2hhcnNldDogJ2FjY2VwdC1jaGFyc2V0JyxcbiAgICBjbGFzc05hbWU6ICdjbGFzcycsXG4gICAgaHRtbEZvcjogJ2ZvcicsXG4gICAgaHR0cEVxdWl2OiAnaHR0cC1lcXVpdidcbiAgfSxcbiAgRE9NUHJvcGVydHlOYW1lczoge1xuICAgIGF1dG9DYXBpdGFsaXplOiAnYXV0b2NhcGl0YWxpemUnLFxuICAgIGF1dG9Db21wbGV0ZTogJ2F1dG9jb21wbGV0ZScsXG4gICAgYXV0b0NvcnJlY3Q6ICdhdXRvY29ycmVjdCcsXG4gICAgYXV0b0ZvY3VzOiAnYXV0b2ZvY3VzJyxcbiAgICBhdXRvUGxheTogJ2F1dG9wbGF5JyxcbiAgICBlbmNUeXBlOiAnZW5jdHlwZScsXG4gICAgaHJlZkxhbmc6ICdocmVmbGFuZycsXG4gICAgcmFkaW9Hcm91cDogJ3JhZGlvZ3JvdXAnLFxuICAgIHNwZWxsQ2hlY2s6ICdzcGVsbGNoZWNrJyxcbiAgICBzcmNEb2M6ICdzcmNkb2MnLFxuICAgIHNyY1NldDogJ3NyY3NldCdcbiAgfVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBIVE1MRE9NUHJvcGVydHlDb25maWc7XG4iLCIoZnVuY3Rpb24gKHByb2Nlc3Mpe1xuLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIExpbmtlZFZhbHVlVXRpbHNcbiAqIEB0eXBlY2hlY2tzIHN0YXRpYy1vbmx5XG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBSZWFjdFByb3BUeXBlcyA9IHJlcXVpcmUoXCIuL1JlYWN0UHJvcFR5cGVzXCIpO1xuXG52YXIgaW52YXJpYW50ID0gcmVxdWlyZShcIi4vaW52YXJpYW50XCIpO1xuXG52YXIgaGFzUmVhZE9ubHlWYWx1ZSA9IHtcbiAgJ2J1dHRvbic6IHRydWUsXG4gICdjaGVja2JveCc6IHRydWUsXG4gICdpbWFnZSc6IHRydWUsXG4gICdoaWRkZW4nOiB0cnVlLFxuICAncmFkaW8nOiB0cnVlLFxuICAncmVzZXQnOiB0cnVlLFxuICAnc3VibWl0JzogdHJ1ZVxufTtcblxuZnVuY3Rpb24gX2Fzc2VydFNpbmdsZUxpbmsoaW5wdXQpIHtcbiAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICBpbnB1dC5wcm9wcy5jaGVja2VkTGluayA9PSBudWxsIHx8IGlucHV0LnByb3BzLnZhbHVlTGluayA9PSBudWxsLFxuICAgICdDYW5ub3QgcHJvdmlkZSBhIGNoZWNrZWRMaW5rIGFuZCBhIHZhbHVlTGluay4gSWYgeW91IHdhbnQgdG8gdXNlICcgK1xuICAgICdjaGVja2VkTGluaywgeW91IHByb2JhYmx5IGRvblxcJ3Qgd2FudCB0byB1c2UgdmFsdWVMaW5rIGFuZCB2aWNlIHZlcnNhLidcbiAgKSA6IGludmFyaWFudChpbnB1dC5wcm9wcy5jaGVja2VkTGluayA9PSBudWxsIHx8IGlucHV0LnByb3BzLnZhbHVlTGluayA9PSBudWxsKSk7XG59XG5mdW5jdGlvbiBfYXNzZXJ0VmFsdWVMaW5rKGlucHV0KSB7XG4gIF9hc3NlcnRTaW5nbGVMaW5rKGlucHV0KTtcbiAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICBpbnB1dC5wcm9wcy52YWx1ZSA9PSBudWxsICYmIGlucHV0LnByb3BzLm9uQ2hhbmdlID09IG51bGwsXG4gICAgJ0Nhbm5vdCBwcm92aWRlIGEgdmFsdWVMaW5rIGFuZCBhIHZhbHVlIG9yIG9uQ2hhbmdlIGV2ZW50LiBJZiB5b3Ugd2FudCAnICtcbiAgICAndG8gdXNlIHZhbHVlIG9yIG9uQ2hhbmdlLCB5b3UgcHJvYmFibHkgZG9uXFwndCB3YW50IHRvIHVzZSB2YWx1ZUxpbmsuJ1xuICApIDogaW52YXJpYW50KGlucHV0LnByb3BzLnZhbHVlID09IG51bGwgJiYgaW5wdXQucHJvcHMub25DaGFuZ2UgPT0gbnVsbCkpO1xufVxuXG5mdW5jdGlvbiBfYXNzZXJ0Q2hlY2tlZExpbmsoaW5wdXQpIHtcbiAgX2Fzc2VydFNpbmdsZUxpbmsoaW5wdXQpO1xuICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgIGlucHV0LnByb3BzLmNoZWNrZWQgPT0gbnVsbCAmJiBpbnB1dC5wcm9wcy5vbkNoYW5nZSA9PSBudWxsLFxuICAgICdDYW5ub3QgcHJvdmlkZSBhIGNoZWNrZWRMaW5rIGFuZCBhIGNoZWNrZWQgcHJvcGVydHkgb3Igb25DaGFuZ2UgZXZlbnQuICcgK1xuICAgICdJZiB5b3Ugd2FudCB0byB1c2UgY2hlY2tlZCBvciBvbkNoYW5nZSwgeW91IHByb2JhYmx5IGRvblxcJ3Qgd2FudCB0byAnICtcbiAgICAndXNlIGNoZWNrZWRMaW5rJ1xuICApIDogaW52YXJpYW50KGlucHV0LnByb3BzLmNoZWNrZWQgPT0gbnVsbCAmJiBpbnB1dC5wcm9wcy5vbkNoYW5nZSA9PSBudWxsKSk7XG59XG5cbi8qKlxuICogQHBhcmFtIHtTeW50aGV0aWNFdmVudH0gZSBjaGFuZ2UgZXZlbnQgdG8gaGFuZGxlXG4gKi9cbmZ1bmN0aW9uIF9oYW5kbGVMaW5rZWRWYWx1ZUNoYW5nZShlKSB7XG4gIC8qanNoaW50IHZhbGlkdGhpczp0cnVlICovXG4gIHRoaXMucHJvcHMudmFsdWVMaW5rLnJlcXVlc3RDaGFuZ2UoZS50YXJnZXQudmFsdWUpO1xufVxuXG4vKipcbiAgKiBAcGFyYW0ge1N5bnRoZXRpY0V2ZW50fSBlIGNoYW5nZSBldmVudCB0byBoYW5kbGVcbiAgKi9cbmZ1bmN0aW9uIF9oYW5kbGVMaW5rZWRDaGVja0NoYW5nZShlKSB7XG4gIC8qanNoaW50IHZhbGlkdGhpczp0cnVlICovXG4gIHRoaXMucHJvcHMuY2hlY2tlZExpbmsucmVxdWVzdENoYW5nZShlLnRhcmdldC5jaGVja2VkKTtcbn1cblxuLyoqXG4gKiBQcm92aWRlIGEgbGlua2VkIGB2YWx1ZWAgYXR0cmlidXRlIGZvciBjb250cm9sbGVkIGZvcm1zLiBZb3Ugc2hvdWxkIG5vdCB1c2VcbiAqIHRoaXMgb3V0c2lkZSBvZiB0aGUgUmVhY3RET00gY29udHJvbGxlZCBmb3JtIGNvbXBvbmVudHMuXG4gKi9cbnZhciBMaW5rZWRWYWx1ZVV0aWxzID0ge1xuICBNaXhpbjoge1xuICAgIHByb3BUeXBlczoge1xuICAgICAgdmFsdWU6IGZ1bmN0aW9uKHByb3BzLCBwcm9wTmFtZSwgY29tcG9uZW50TmFtZSkge1xuICAgICAgICBpZiAoIXByb3BzW3Byb3BOYW1lXSB8fFxuICAgICAgICAgICAgaGFzUmVhZE9ubHlWYWx1ZVtwcm9wcy50eXBlXSB8fFxuICAgICAgICAgICAgcHJvcHMub25DaGFuZ2UgfHxcbiAgICAgICAgICAgIHByb3BzLnJlYWRPbmx5IHx8XG4gICAgICAgICAgICBwcm9wcy5kaXNhYmxlZCkge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gbmV3IEVycm9yKFxuICAgICAgICAgICdZb3UgcHJvdmlkZWQgYSBgdmFsdWVgIHByb3AgdG8gYSBmb3JtIGZpZWxkIHdpdGhvdXQgYW4gJyArXG4gICAgICAgICAgJ2BvbkNoYW5nZWAgaGFuZGxlci4gVGhpcyB3aWxsIHJlbmRlciBhIHJlYWQtb25seSBmaWVsZC4gSWYgJyArXG4gICAgICAgICAgJ3RoZSBmaWVsZCBzaG91bGQgYmUgbXV0YWJsZSB1c2UgYGRlZmF1bHRWYWx1ZWAuIE90aGVyd2lzZSwgJyArXG4gICAgICAgICAgJ3NldCBlaXRoZXIgYG9uQ2hhbmdlYCBvciBgcmVhZE9ubHlgLidcbiAgICAgICAgKTtcbiAgICAgIH0sXG4gICAgICBjaGVja2VkOiBmdW5jdGlvbihwcm9wcywgcHJvcE5hbWUsIGNvbXBvbmVudE5hbWUpIHtcbiAgICAgICAgaWYgKCFwcm9wc1twcm9wTmFtZV0gfHxcbiAgICAgICAgICAgIHByb3BzLm9uQ2hhbmdlIHx8XG4gICAgICAgICAgICBwcm9wcy5yZWFkT25seSB8fFxuICAgICAgICAgICAgcHJvcHMuZGlzYWJsZWQpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG5ldyBFcnJvcihcbiAgICAgICAgICAnWW91IHByb3ZpZGVkIGEgYGNoZWNrZWRgIHByb3AgdG8gYSBmb3JtIGZpZWxkIHdpdGhvdXQgYW4gJyArXG4gICAgICAgICAgJ2BvbkNoYW5nZWAgaGFuZGxlci4gVGhpcyB3aWxsIHJlbmRlciBhIHJlYWQtb25seSBmaWVsZC4gSWYgJyArXG4gICAgICAgICAgJ3RoZSBmaWVsZCBzaG91bGQgYmUgbXV0YWJsZSB1c2UgYGRlZmF1bHRDaGVja2VkYC4gT3RoZXJ3aXNlLCAnICtcbiAgICAgICAgICAnc2V0IGVpdGhlciBgb25DaGFuZ2VgIG9yIGByZWFkT25seWAuJ1xuICAgICAgICApO1xuICAgICAgfSxcbiAgICAgIG9uQ2hhbmdlOiBSZWFjdFByb3BUeXBlcy5mdW5jXG4gICAgfVxuICB9LFxuXG4gIC8qKlxuICAgKiBAcGFyYW0ge1JlYWN0Q29tcG9uZW50fSBpbnB1dCBGb3JtIGNvbXBvbmVudFxuICAgKiBAcmV0dXJuIHsqfSBjdXJyZW50IHZhbHVlIG9mIHRoZSBpbnB1dCBlaXRoZXIgZnJvbSB2YWx1ZSBwcm9wIG9yIGxpbmsuXG4gICAqL1xuICBnZXRWYWx1ZTogZnVuY3Rpb24oaW5wdXQpIHtcbiAgICBpZiAoaW5wdXQucHJvcHMudmFsdWVMaW5rKSB7XG4gICAgICBfYXNzZXJ0VmFsdWVMaW5rKGlucHV0KTtcbiAgICAgIHJldHVybiBpbnB1dC5wcm9wcy52YWx1ZUxpbmsudmFsdWU7XG4gICAgfVxuICAgIHJldHVybiBpbnB1dC5wcm9wcy52YWx1ZTtcbiAgfSxcblxuICAvKipcbiAgICogQHBhcmFtIHtSZWFjdENvbXBvbmVudH0gaW5wdXQgRm9ybSBjb21wb25lbnRcbiAgICogQHJldHVybiB7Kn0gY3VycmVudCBjaGVja2VkIHN0YXR1cyBvZiB0aGUgaW5wdXQgZWl0aGVyIGZyb20gY2hlY2tlZCBwcm9wXG4gICAqICAgICAgICAgICAgIG9yIGxpbmsuXG4gICAqL1xuICBnZXRDaGVja2VkOiBmdW5jdGlvbihpbnB1dCkge1xuICAgIGlmIChpbnB1dC5wcm9wcy5jaGVja2VkTGluaykge1xuICAgICAgX2Fzc2VydENoZWNrZWRMaW5rKGlucHV0KTtcbiAgICAgIHJldHVybiBpbnB1dC5wcm9wcy5jaGVja2VkTGluay52YWx1ZTtcbiAgICB9XG4gICAgcmV0dXJuIGlucHV0LnByb3BzLmNoZWNrZWQ7XG4gIH0sXG5cbiAgLyoqXG4gICAqIEBwYXJhbSB7UmVhY3RDb21wb25lbnR9IGlucHV0IEZvcm0gY29tcG9uZW50XG4gICAqIEByZXR1cm4ge2Z1bmN0aW9ufSBjaGFuZ2UgY2FsbGJhY2sgZWl0aGVyIGZyb20gb25DaGFuZ2UgcHJvcCBvciBsaW5rLlxuICAgKi9cbiAgZ2V0T25DaGFuZ2U6IGZ1bmN0aW9uKGlucHV0KSB7XG4gICAgaWYgKGlucHV0LnByb3BzLnZhbHVlTGluaykge1xuICAgICAgX2Fzc2VydFZhbHVlTGluayhpbnB1dCk7XG4gICAgICByZXR1cm4gX2hhbmRsZUxpbmtlZFZhbHVlQ2hhbmdlO1xuICAgIH0gZWxzZSBpZiAoaW5wdXQucHJvcHMuY2hlY2tlZExpbmspIHtcbiAgICAgIF9hc3NlcnRDaGVja2VkTGluayhpbnB1dCk7XG4gICAgICByZXR1cm4gX2hhbmRsZUxpbmtlZENoZWNrQ2hhbmdlO1xuICAgIH1cbiAgICByZXR1cm4gaW5wdXQucHJvcHMub25DaGFuZ2U7XG4gIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gTGlua2VkVmFsdWVVdGlscztcblxufSkuY2FsbCh0aGlzLHJlcXVpcmUoJ19wcm9jZXNzJykpIiwiKGZ1bmN0aW9uIChwcm9jZXNzKXtcbi8qKlxuICogQ29weXJpZ2h0IDIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgTG9jYWxFdmVudFRyYXBNaXhpblxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgUmVhY3RCcm93c2VyRXZlbnRFbWl0dGVyID0gcmVxdWlyZShcIi4vUmVhY3RCcm93c2VyRXZlbnRFbWl0dGVyXCIpO1xuXG52YXIgYWNjdW11bGF0ZUludG8gPSByZXF1aXJlKFwiLi9hY2N1bXVsYXRlSW50b1wiKTtcbnZhciBmb3JFYWNoQWNjdW11bGF0ZWQgPSByZXF1aXJlKFwiLi9mb3JFYWNoQWNjdW11bGF0ZWRcIik7XG52YXIgaW52YXJpYW50ID0gcmVxdWlyZShcIi4vaW52YXJpYW50XCIpO1xuXG5mdW5jdGlvbiByZW1vdmUoZXZlbnQpIHtcbiAgZXZlbnQucmVtb3ZlKCk7XG59XG5cbnZhciBMb2NhbEV2ZW50VHJhcE1peGluID0ge1xuICB0cmFwQnViYmxlZEV2ZW50OmZ1bmN0aW9uKHRvcExldmVsVHlwZSwgaGFuZGxlckJhc2VOYW1lKSB7XG4gICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudCh0aGlzLmlzTW91bnRlZCgpLCAnTXVzdCBiZSBtb3VudGVkIHRvIHRyYXAgZXZlbnRzJykgOiBpbnZhcmlhbnQodGhpcy5pc01vdW50ZWQoKSkpO1xuICAgIHZhciBsaXN0ZW5lciA9IFJlYWN0QnJvd3NlckV2ZW50RW1pdHRlci50cmFwQnViYmxlZEV2ZW50KFxuICAgICAgdG9wTGV2ZWxUeXBlLFxuICAgICAgaGFuZGxlckJhc2VOYW1lLFxuICAgICAgdGhpcy5nZXRET01Ob2RlKClcbiAgICApO1xuICAgIHRoaXMuX2xvY2FsRXZlbnRMaXN0ZW5lcnMgPVxuICAgICAgYWNjdW11bGF0ZUludG8odGhpcy5fbG9jYWxFdmVudExpc3RlbmVycywgbGlzdGVuZXIpO1xuICB9LFxuXG4gIC8vIHRyYXBDYXB0dXJlZEV2ZW50IHdvdWxkIGxvb2sgbmVhcmx5IGlkZW50aWNhbC4gV2UgZG9uJ3QgaW1wbGVtZW50IHRoYXRcbiAgLy8gbWV0aG9kIGJlY2F1c2UgaXQgaXNuJ3QgY3VycmVudGx5IG5lZWRlZC5cblxuICBjb21wb25lbnRXaWxsVW5tb3VudDpmdW5jdGlvbigpIHtcbiAgICBpZiAodGhpcy5fbG9jYWxFdmVudExpc3RlbmVycykge1xuICAgICAgZm9yRWFjaEFjY3VtdWxhdGVkKHRoaXMuX2xvY2FsRXZlbnRMaXN0ZW5lcnMsIHJlbW92ZSk7XG4gICAgfVxuICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IExvY2FsRXZlbnRUcmFwTWl4aW47XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKCdfcHJvY2VzcycpKSIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBNb2JpbGVTYWZhcmlDbGlja0V2ZW50UGx1Z2luXG4gKiBAdHlwZWNoZWNrcyBzdGF0aWMtb25seVxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgRXZlbnRDb25zdGFudHMgPSByZXF1aXJlKFwiLi9FdmVudENvbnN0YW50c1wiKTtcblxudmFyIGVtcHR5RnVuY3Rpb24gPSByZXF1aXJlKFwiLi9lbXB0eUZ1bmN0aW9uXCIpO1xuXG52YXIgdG9wTGV2ZWxUeXBlcyA9IEV2ZW50Q29uc3RhbnRzLnRvcExldmVsVHlwZXM7XG5cbi8qKlxuICogTW9iaWxlIFNhZmFyaSBkb2VzIG5vdCBmaXJlIHByb3Blcmx5IGJ1YmJsZSBjbGljayBldmVudHMgb24gbm9uLWludGVyYWN0aXZlXG4gKiBlbGVtZW50cywgd2hpY2ggbWVhbnMgZGVsZWdhdGVkIGNsaWNrIGxpc3RlbmVycyBkbyBub3QgZmlyZS4gVGhlIHdvcmthcm91bmRcbiAqIGZvciB0aGlzIGJ1ZyBpbnZvbHZlcyBhdHRhY2hpbmcgYW4gZW1wdHkgY2xpY2sgbGlzdGVuZXIgb24gdGhlIHRhcmdldCBub2RlLlxuICpcbiAqIFRoaXMgcGFydGljdWxhciBwbHVnaW4gd29ya3MgYXJvdW5kIHRoZSBidWcgYnkgYXR0YWNoaW5nIGFuIGVtcHR5IGNsaWNrXG4gKiBsaXN0ZW5lciBvbiBgdG91Y2hzdGFydGAgKHdoaWNoIGRvZXMgZmlyZSBvbiBldmVyeSBlbGVtZW50KS5cbiAqL1xudmFyIE1vYmlsZVNhZmFyaUNsaWNrRXZlbnRQbHVnaW4gPSB7XG5cbiAgZXZlbnRUeXBlczogbnVsbCxcblxuICAvKipcbiAgICogQHBhcmFtIHtzdHJpbmd9IHRvcExldmVsVHlwZSBSZWNvcmQgZnJvbSBgRXZlbnRDb25zdGFudHNgLlxuICAgKiBAcGFyYW0ge0RPTUV2ZW50VGFyZ2V0fSB0b3BMZXZlbFRhcmdldCBUaGUgbGlzdGVuaW5nIGNvbXBvbmVudCByb290IG5vZGUuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB0b3BMZXZlbFRhcmdldElEIElEIG9mIGB0b3BMZXZlbFRhcmdldGAuXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBuYXRpdmVFdmVudCBOYXRpdmUgYnJvd3NlciBldmVudC5cbiAgICogQHJldHVybiB7Kn0gQW4gYWNjdW11bGF0aW9uIG9mIHN5bnRoZXRpYyBldmVudHMuXG4gICAqIEBzZWUge0V2ZW50UGx1Z2luSHViLmV4dHJhY3RFdmVudHN9XG4gICAqL1xuICBleHRyYWN0RXZlbnRzOiBmdW5jdGlvbihcbiAgICAgIHRvcExldmVsVHlwZSxcbiAgICAgIHRvcExldmVsVGFyZ2V0LFxuICAgICAgdG9wTGV2ZWxUYXJnZXRJRCxcbiAgICAgIG5hdGl2ZUV2ZW50KSB7XG4gICAgaWYgKHRvcExldmVsVHlwZSA9PT0gdG9wTGV2ZWxUeXBlcy50b3BUb3VjaFN0YXJ0KSB7XG4gICAgICB2YXIgdGFyZ2V0ID0gbmF0aXZlRXZlbnQudGFyZ2V0O1xuICAgICAgaWYgKHRhcmdldCAmJiAhdGFyZ2V0Lm9uY2xpY2spIHtcbiAgICAgICAgdGFyZ2V0Lm9uY2xpY2sgPSBlbXB0eUZ1bmN0aW9uO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IE1vYmlsZVNhZmFyaUNsaWNrRXZlbnRQbHVnaW47XG4iLCIvKipcbiAqIENvcHlyaWdodCAyMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIE9iamVjdC5hc3NpZ25cbiAqL1xuXG4vLyBodHRwczovL3Blb3BsZS5tb3ppbGxhLm9yZy9+am9yZW5kb3JmZi9lczYtZHJhZnQuaHRtbCNzZWMtb2JqZWN0LmFzc2lnblxuXG5mdW5jdGlvbiBhc3NpZ24odGFyZ2V0LCBzb3VyY2VzKSB7XG4gIGlmICh0YXJnZXQgPT0gbnVsbCkge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ09iamVjdC5hc3NpZ24gdGFyZ2V0IGNhbm5vdCBiZSBudWxsIG9yIHVuZGVmaW5lZCcpO1xuICB9XG5cbiAgdmFyIHRvID0gT2JqZWN0KHRhcmdldCk7XG4gIHZhciBoYXNPd25Qcm9wZXJ0eSA9IE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHk7XG5cbiAgZm9yICh2YXIgbmV4dEluZGV4ID0gMTsgbmV4dEluZGV4IDwgYXJndW1lbnRzLmxlbmd0aDsgbmV4dEluZGV4KyspIHtcbiAgICB2YXIgbmV4dFNvdXJjZSA9IGFyZ3VtZW50c1tuZXh0SW5kZXhdO1xuICAgIGlmIChuZXh0U291cmNlID09IG51bGwpIHtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cblxuICAgIHZhciBmcm9tID0gT2JqZWN0KG5leHRTb3VyY2UpO1xuXG4gICAgLy8gV2UgZG9uJ3QgY3VycmVudGx5IHN1cHBvcnQgYWNjZXNzb3JzIG5vciBwcm94aWVzLiBUaGVyZWZvcmUgdGhpc1xuICAgIC8vIGNvcHkgY2Fubm90IHRocm93LiBJZiB3ZSBldmVyIHN1cHBvcnRlZCB0aGlzIHRoZW4gd2UgbXVzdCBoYW5kbGVcbiAgICAvLyBleGNlcHRpb25zIGFuZCBzaWRlLWVmZmVjdHMuIFdlIGRvbid0IHN1cHBvcnQgc3ltYm9scyBzbyB0aGV5IHdvbid0XG4gICAgLy8gYmUgdHJhbnNmZXJyZWQuXG5cbiAgICBmb3IgKHZhciBrZXkgaW4gZnJvbSkge1xuICAgICAgaWYgKGhhc093blByb3BlcnR5LmNhbGwoZnJvbSwga2V5KSkge1xuICAgICAgICB0b1trZXldID0gZnJvbVtrZXldO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiB0bztcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gYXNzaWduO1xuIiwiKGZ1bmN0aW9uIChwcm9jZXNzKXtcbi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBQb29sZWRDbGFzc1xuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgaW52YXJpYW50ID0gcmVxdWlyZShcIi4vaW52YXJpYW50XCIpO1xuXG4vKipcbiAqIFN0YXRpYyBwb29sZXJzLiBTZXZlcmFsIGN1c3RvbSB2ZXJzaW9ucyBmb3IgZWFjaCBwb3RlbnRpYWwgbnVtYmVyIG9mXG4gKiBhcmd1bWVudHMuIEEgY29tcGxldGVseSBnZW5lcmljIHBvb2xlciBpcyBlYXN5IHRvIGltcGxlbWVudCwgYnV0IHdvdWxkXG4gKiByZXF1aXJlIGFjY2Vzc2luZyB0aGUgYGFyZ3VtZW50c2Agb2JqZWN0LiBJbiBlYWNoIG9mIHRoZXNlLCBgdGhpc2AgcmVmZXJzIHRvXG4gKiB0aGUgQ2xhc3MgaXRzZWxmLCBub3QgYW4gaW5zdGFuY2UuIElmIGFueSBvdGhlcnMgYXJlIG5lZWRlZCwgc2ltcGx5IGFkZCB0aGVtXG4gKiBoZXJlLCBvciBpbiB0aGVpciBvd24gZmlsZXMuXG4gKi9cbnZhciBvbmVBcmd1bWVudFBvb2xlciA9IGZ1bmN0aW9uKGNvcHlGaWVsZHNGcm9tKSB7XG4gIHZhciBLbGFzcyA9IHRoaXM7XG4gIGlmIChLbGFzcy5pbnN0YW5jZVBvb2wubGVuZ3RoKSB7XG4gICAgdmFyIGluc3RhbmNlID0gS2xhc3MuaW5zdGFuY2VQb29sLnBvcCgpO1xuICAgIEtsYXNzLmNhbGwoaW5zdGFuY2UsIGNvcHlGaWVsZHNGcm9tKTtcbiAgICByZXR1cm4gaW5zdGFuY2U7XG4gIH0gZWxzZSB7XG4gICAgcmV0dXJuIG5ldyBLbGFzcyhjb3B5RmllbGRzRnJvbSk7XG4gIH1cbn07XG5cbnZhciB0d29Bcmd1bWVudFBvb2xlciA9IGZ1bmN0aW9uKGExLCBhMikge1xuICB2YXIgS2xhc3MgPSB0aGlzO1xuICBpZiAoS2xhc3MuaW5zdGFuY2VQb29sLmxlbmd0aCkge1xuICAgIHZhciBpbnN0YW5jZSA9IEtsYXNzLmluc3RhbmNlUG9vbC5wb3AoKTtcbiAgICBLbGFzcy5jYWxsKGluc3RhbmNlLCBhMSwgYTIpO1xuICAgIHJldHVybiBpbnN0YW5jZTtcbiAgfSBlbHNlIHtcbiAgICByZXR1cm4gbmV3IEtsYXNzKGExLCBhMik7XG4gIH1cbn07XG5cbnZhciB0aHJlZUFyZ3VtZW50UG9vbGVyID0gZnVuY3Rpb24oYTEsIGEyLCBhMykge1xuICB2YXIgS2xhc3MgPSB0aGlzO1xuICBpZiAoS2xhc3MuaW5zdGFuY2VQb29sLmxlbmd0aCkge1xuICAgIHZhciBpbnN0YW5jZSA9IEtsYXNzLmluc3RhbmNlUG9vbC5wb3AoKTtcbiAgICBLbGFzcy5jYWxsKGluc3RhbmNlLCBhMSwgYTIsIGEzKTtcbiAgICByZXR1cm4gaW5zdGFuY2U7XG4gIH0gZWxzZSB7XG4gICAgcmV0dXJuIG5ldyBLbGFzcyhhMSwgYTIsIGEzKTtcbiAgfVxufTtcblxudmFyIGZpdmVBcmd1bWVudFBvb2xlciA9IGZ1bmN0aW9uKGExLCBhMiwgYTMsIGE0LCBhNSkge1xuICB2YXIgS2xhc3MgPSB0aGlzO1xuICBpZiAoS2xhc3MuaW5zdGFuY2VQb29sLmxlbmd0aCkge1xuICAgIHZhciBpbnN0YW5jZSA9IEtsYXNzLmluc3RhbmNlUG9vbC5wb3AoKTtcbiAgICBLbGFzcy5jYWxsKGluc3RhbmNlLCBhMSwgYTIsIGEzLCBhNCwgYTUpO1xuICAgIHJldHVybiBpbnN0YW5jZTtcbiAgfSBlbHNlIHtcbiAgICByZXR1cm4gbmV3IEtsYXNzKGExLCBhMiwgYTMsIGE0LCBhNSk7XG4gIH1cbn07XG5cbnZhciBzdGFuZGFyZFJlbGVhc2VyID0gZnVuY3Rpb24oaW5zdGFuY2UpIHtcbiAgdmFyIEtsYXNzID0gdGhpcztcbiAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICBpbnN0YW5jZSBpbnN0YW5jZW9mIEtsYXNzLFxuICAgICdUcnlpbmcgdG8gcmVsZWFzZSBhbiBpbnN0YW5jZSBpbnRvIGEgcG9vbCBvZiBhIGRpZmZlcmVudCB0eXBlLidcbiAgKSA6IGludmFyaWFudChpbnN0YW5jZSBpbnN0YW5jZW9mIEtsYXNzKSk7XG4gIGlmIChpbnN0YW5jZS5kZXN0cnVjdG9yKSB7XG4gICAgaW5zdGFuY2UuZGVzdHJ1Y3RvcigpO1xuICB9XG4gIGlmIChLbGFzcy5pbnN0YW5jZVBvb2wubGVuZ3RoIDwgS2xhc3MucG9vbFNpemUpIHtcbiAgICBLbGFzcy5pbnN0YW5jZVBvb2wucHVzaChpbnN0YW5jZSk7XG4gIH1cbn07XG5cbnZhciBERUZBVUxUX1BPT0xfU0laRSA9IDEwO1xudmFyIERFRkFVTFRfUE9PTEVSID0gb25lQXJndW1lbnRQb29sZXI7XG5cbi8qKlxuICogQXVnbWVudHMgYENvcHlDb25zdHJ1Y3RvcmAgdG8gYmUgYSBwb29sYWJsZSBjbGFzcywgYXVnbWVudGluZyBvbmx5IHRoZSBjbGFzc1xuICogaXRzZWxmIChzdGF0aWNhbGx5KSBub3QgYWRkaW5nIGFueSBwcm90b3R5cGljYWwgZmllbGRzLiBBbnkgQ29weUNvbnN0cnVjdG9yXG4gKiB5b3UgZ2l2ZSB0aGlzIG1heSBoYXZlIGEgYHBvb2xTaXplYCBwcm9wZXJ0eSwgYW5kIHdpbGwgbG9vayBmb3IgYVxuICogcHJvdG90eXBpY2FsIGBkZXN0cnVjdG9yYCBvbiBpbnN0YW5jZXMgKG9wdGlvbmFsKS5cbiAqXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBDb3B5Q29uc3RydWN0b3IgQ29uc3RydWN0b3IgdGhhdCBjYW4gYmUgdXNlZCB0byByZXNldC5cbiAqIEBwYXJhbSB7RnVuY3Rpb259IHBvb2xlciBDdXN0b21pemFibGUgcG9vbGVyLlxuICovXG52YXIgYWRkUG9vbGluZ1RvID0gZnVuY3Rpb24oQ29weUNvbnN0cnVjdG9yLCBwb29sZXIpIHtcbiAgdmFyIE5ld0tsYXNzID0gQ29weUNvbnN0cnVjdG9yO1xuICBOZXdLbGFzcy5pbnN0YW5jZVBvb2wgPSBbXTtcbiAgTmV3S2xhc3MuZ2V0UG9vbGVkID0gcG9vbGVyIHx8IERFRkFVTFRfUE9PTEVSO1xuICBpZiAoIU5ld0tsYXNzLnBvb2xTaXplKSB7XG4gICAgTmV3S2xhc3MucG9vbFNpemUgPSBERUZBVUxUX1BPT0xfU0laRTtcbiAgfVxuICBOZXdLbGFzcy5yZWxlYXNlID0gc3RhbmRhcmRSZWxlYXNlcjtcbiAgcmV0dXJuIE5ld0tsYXNzO1xufTtcblxudmFyIFBvb2xlZENsYXNzID0ge1xuICBhZGRQb29saW5nVG86IGFkZFBvb2xpbmdUbyxcbiAgb25lQXJndW1lbnRQb29sZXI6IG9uZUFyZ3VtZW50UG9vbGVyLFxuICB0d29Bcmd1bWVudFBvb2xlcjogdHdvQXJndW1lbnRQb29sZXIsXG4gIHRocmVlQXJndW1lbnRQb29sZXI6IHRocmVlQXJndW1lbnRQb29sZXIsXG4gIGZpdmVBcmd1bWVudFBvb2xlcjogZml2ZUFyZ3VtZW50UG9vbGVyXG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFBvb2xlZENsYXNzO1xuXG59KS5jYWxsKHRoaXMscmVxdWlyZSgnX3Byb2Nlc3MnKSkiLCIoZnVuY3Rpb24gKHByb2Nlc3Mpe1xuLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIFJlYWN0XG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBET01Qcm9wZXJ0eU9wZXJhdGlvbnMgPSByZXF1aXJlKFwiLi9ET01Qcm9wZXJ0eU9wZXJhdGlvbnNcIik7XG52YXIgRXZlbnRQbHVnaW5VdGlscyA9IHJlcXVpcmUoXCIuL0V2ZW50UGx1Z2luVXRpbHNcIik7XG52YXIgUmVhY3RDaGlsZHJlbiA9IHJlcXVpcmUoXCIuL1JlYWN0Q2hpbGRyZW5cIik7XG52YXIgUmVhY3RDb21wb25lbnQgPSByZXF1aXJlKFwiLi9SZWFjdENvbXBvbmVudFwiKTtcbnZhciBSZWFjdENvbXBvc2l0ZUNvbXBvbmVudCA9IHJlcXVpcmUoXCIuL1JlYWN0Q29tcG9zaXRlQ29tcG9uZW50XCIpO1xudmFyIFJlYWN0Q29udGV4dCA9IHJlcXVpcmUoXCIuL1JlYWN0Q29udGV4dFwiKTtcbnZhciBSZWFjdEN1cnJlbnRPd25lciA9IHJlcXVpcmUoXCIuL1JlYWN0Q3VycmVudE93bmVyXCIpO1xudmFyIFJlYWN0RWxlbWVudCA9IHJlcXVpcmUoXCIuL1JlYWN0RWxlbWVudFwiKTtcbnZhciBSZWFjdEVsZW1lbnRWYWxpZGF0b3IgPSByZXF1aXJlKFwiLi9SZWFjdEVsZW1lbnRWYWxpZGF0b3JcIik7XG52YXIgUmVhY3RET00gPSByZXF1aXJlKFwiLi9SZWFjdERPTVwiKTtcbnZhciBSZWFjdERPTUNvbXBvbmVudCA9IHJlcXVpcmUoXCIuL1JlYWN0RE9NQ29tcG9uZW50XCIpO1xudmFyIFJlYWN0RGVmYXVsdEluamVjdGlvbiA9IHJlcXVpcmUoXCIuL1JlYWN0RGVmYXVsdEluamVjdGlvblwiKTtcbnZhciBSZWFjdEluc3RhbmNlSGFuZGxlcyA9IHJlcXVpcmUoXCIuL1JlYWN0SW5zdGFuY2VIYW5kbGVzXCIpO1xudmFyIFJlYWN0TGVnYWN5RWxlbWVudCA9IHJlcXVpcmUoXCIuL1JlYWN0TGVnYWN5RWxlbWVudFwiKTtcbnZhciBSZWFjdE1vdW50ID0gcmVxdWlyZShcIi4vUmVhY3RNb3VudFwiKTtcbnZhciBSZWFjdE11bHRpQ2hpbGQgPSByZXF1aXJlKFwiLi9SZWFjdE11bHRpQ2hpbGRcIik7XG52YXIgUmVhY3RQZXJmID0gcmVxdWlyZShcIi4vUmVhY3RQZXJmXCIpO1xudmFyIFJlYWN0UHJvcFR5cGVzID0gcmVxdWlyZShcIi4vUmVhY3RQcm9wVHlwZXNcIik7XG52YXIgUmVhY3RTZXJ2ZXJSZW5kZXJpbmcgPSByZXF1aXJlKFwiLi9SZWFjdFNlcnZlclJlbmRlcmluZ1wiKTtcbnZhciBSZWFjdFRleHRDb21wb25lbnQgPSByZXF1aXJlKFwiLi9SZWFjdFRleHRDb21wb25lbnRcIik7XG5cbnZhciBhc3NpZ24gPSByZXF1aXJlKFwiLi9PYmplY3QuYXNzaWduXCIpO1xudmFyIGRlcHJlY2F0ZWQgPSByZXF1aXJlKFwiLi9kZXByZWNhdGVkXCIpO1xudmFyIG9ubHlDaGlsZCA9IHJlcXVpcmUoXCIuL29ubHlDaGlsZFwiKTtcblxuUmVhY3REZWZhdWx0SW5qZWN0aW9uLmluamVjdCgpO1xuXG52YXIgY3JlYXRlRWxlbWVudCA9IFJlYWN0RWxlbWVudC5jcmVhdGVFbGVtZW50O1xudmFyIGNyZWF0ZUZhY3RvcnkgPSBSZWFjdEVsZW1lbnQuY3JlYXRlRmFjdG9yeTtcblxuaWYgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOVikge1xuICBjcmVhdGVFbGVtZW50ID0gUmVhY3RFbGVtZW50VmFsaWRhdG9yLmNyZWF0ZUVsZW1lbnQ7XG4gIGNyZWF0ZUZhY3RvcnkgPSBSZWFjdEVsZW1lbnRWYWxpZGF0b3IuY3JlYXRlRmFjdG9yeTtcbn1cblxuLy8gVE9ETzogRHJvcCBsZWdhY3kgZWxlbWVudHMgb25jZSBjbGFzc2VzIG5vIGxvbmdlciBleHBvcnQgdGhlc2UgZmFjdG9yaWVzXG5jcmVhdGVFbGVtZW50ID0gUmVhY3RMZWdhY3lFbGVtZW50LndyYXBDcmVhdGVFbGVtZW50KFxuICBjcmVhdGVFbGVtZW50XG4pO1xuY3JlYXRlRmFjdG9yeSA9IFJlYWN0TGVnYWN5RWxlbWVudC53cmFwQ3JlYXRlRmFjdG9yeShcbiAgY3JlYXRlRmFjdG9yeVxuKTtcblxudmFyIHJlbmRlciA9IFJlYWN0UGVyZi5tZWFzdXJlKCdSZWFjdCcsICdyZW5kZXInLCBSZWFjdE1vdW50LnJlbmRlcik7XG5cbnZhciBSZWFjdCA9IHtcbiAgQ2hpbGRyZW46IHtcbiAgICBtYXA6IFJlYWN0Q2hpbGRyZW4ubWFwLFxuICAgIGZvckVhY2g6IFJlYWN0Q2hpbGRyZW4uZm9yRWFjaCxcbiAgICBjb3VudDogUmVhY3RDaGlsZHJlbi5jb3VudCxcbiAgICBvbmx5OiBvbmx5Q2hpbGRcbiAgfSxcbiAgRE9NOiBSZWFjdERPTSxcbiAgUHJvcFR5cGVzOiBSZWFjdFByb3BUeXBlcyxcbiAgaW5pdGlhbGl6ZVRvdWNoRXZlbnRzOiBmdW5jdGlvbihzaG91bGRVc2VUb3VjaCkge1xuICAgIEV2ZW50UGx1Z2luVXRpbHMudXNlVG91Y2hFdmVudHMgPSBzaG91bGRVc2VUb3VjaDtcbiAgfSxcbiAgY3JlYXRlQ2xhc3M6IFJlYWN0Q29tcG9zaXRlQ29tcG9uZW50LmNyZWF0ZUNsYXNzLFxuICBjcmVhdGVFbGVtZW50OiBjcmVhdGVFbGVtZW50LFxuICBjcmVhdGVGYWN0b3J5OiBjcmVhdGVGYWN0b3J5LFxuICBjb25zdHJ1Y3RBbmRSZW5kZXJDb21wb25lbnQ6IFJlYWN0TW91bnQuY29uc3RydWN0QW5kUmVuZGVyQ29tcG9uZW50LFxuICBjb25zdHJ1Y3RBbmRSZW5kZXJDb21wb25lbnRCeUlEOiBSZWFjdE1vdW50LmNvbnN0cnVjdEFuZFJlbmRlckNvbXBvbmVudEJ5SUQsXG4gIHJlbmRlcjogcmVuZGVyLFxuICByZW5kZXJUb1N0cmluZzogUmVhY3RTZXJ2ZXJSZW5kZXJpbmcucmVuZGVyVG9TdHJpbmcsXG4gIHJlbmRlclRvU3RhdGljTWFya3VwOiBSZWFjdFNlcnZlclJlbmRlcmluZy5yZW5kZXJUb1N0YXRpY01hcmt1cCxcbiAgdW5tb3VudENvbXBvbmVudEF0Tm9kZTogUmVhY3RNb3VudC51bm1vdW50Q29tcG9uZW50QXROb2RlLFxuICBpc1ZhbGlkQ2xhc3M6IFJlYWN0TGVnYWN5RWxlbWVudC5pc1ZhbGlkQ2xhc3MsXG4gIGlzVmFsaWRFbGVtZW50OiBSZWFjdEVsZW1lbnQuaXNWYWxpZEVsZW1lbnQsXG4gIHdpdGhDb250ZXh0OiBSZWFjdENvbnRleHQud2l0aENvbnRleHQsXG5cbiAgLy8gSG9vayBmb3IgSlNYIHNwcmVhZCwgZG9uJ3QgdXNlIHRoaXMgZm9yIGFueXRoaW5nIGVsc2UuXG4gIF9fc3ByZWFkOiBhc3NpZ24sXG5cbiAgLy8gRGVwcmVjYXRpb25zIChyZW1vdmUgZm9yIDAuMTMpXG4gIHJlbmRlckNvbXBvbmVudDogZGVwcmVjYXRlZChcbiAgICAnUmVhY3QnLFxuICAgICdyZW5kZXJDb21wb25lbnQnLFxuICAgICdyZW5kZXInLFxuICAgIHRoaXMsXG4gICAgcmVuZGVyXG4gICksXG4gIHJlbmRlckNvbXBvbmVudFRvU3RyaW5nOiBkZXByZWNhdGVkKFxuICAgICdSZWFjdCcsXG4gICAgJ3JlbmRlckNvbXBvbmVudFRvU3RyaW5nJyxcbiAgICAncmVuZGVyVG9TdHJpbmcnLFxuICAgIHRoaXMsXG4gICAgUmVhY3RTZXJ2ZXJSZW5kZXJpbmcucmVuZGVyVG9TdHJpbmdcbiAgKSxcbiAgcmVuZGVyQ29tcG9uZW50VG9TdGF0aWNNYXJrdXA6IGRlcHJlY2F0ZWQoXG4gICAgJ1JlYWN0JyxcbiAgICAncmVuZGVyQ29tcG9uZW50VG9TdGF0aWNNYXJrdXAnLFxuICAgICdyZW5kZXJUb1N0YXRpY01hcmt1cCcsXG4gICAgdGhpcyxcbiAgICBSZWFjdFNlcnZlclJlbmRlcmluZy5yZW5kZXJUb1N0YXRpY01hcmt1cFxuICApLFxuICBpc1ZhbGlkQ29tcG9uZW50OiBkZXByZWNhdGVkKFxuICAgICdSZWFjdCcsXG4gICAgJ2lzVmFsaWRDb21wb25lbnQnLFxuICAgICdpc1ZhbGlkRWxlbWVudCcsXG4gICAgdGhpcyxcbiAgICBSZWFjdEVsZW1lbnQuaXNWYWxpZEVsZW1lbnRcbiAgKVxufTtcblxuLy8gSW5qZWN0IHRoZSBydW50aW1lIGludG8gYSBkZXZ0b29scyBnbG9iYWwgaG9vayByZWdhcmRsZXNzIG9mIGJyb3dzZXIuXG4vLyBBbGxvd3MgZm9yIGRlYnVnZ2luZyB3aGVuIHRoZSBob29rIGlzIGluamVjdGVkIG9uIHRoZSBwYWdlLlxuaWYgKFxuICB0eXBlb2YgX19SRUFDVF9ERVZUT09MU19HTE9CQUxfSE9PS19fICE9PSAndW5kZWZpbmVkJyAmJlxuICB0eXBlb2YgX19SRUFDVF9ERVZUT09MU19HTE9CQUxfSE9PS19fLmluamVjdCA9PT0gJ2Z1bmN0aW9uJykge1xuICBfX1JFQUNUX0RFVlRPT0xTX0dMT0JBTF9IT09LX18uaW5qZWN0KHtcbiAgICBDb21wb25lbnQ6IFJlYWN0Q29tcG9uZW50LFxuICAgIEN1cnJlbnRPd25lcjogUmVhY3RDdXJyZW50T3duZXIsXG4gICAgRE9NQ29tcG9uZW50OiBSZWFjdERPTUNvbXBvbmVudCxcbiAgICBET01Qcm9wZXJ0eU9wZXJhdGlvbnM6IERPTVByb3BlcnR5T3BlcmF0aW9ucyxcbiAgICBJbnN0YW5jZUhhbmRsZXM6IFJlYWN0SW5zdGFuY2VIYW5kbGVzLFxuICAgIE1vdW50OiBSZWFjdE1vdW50LFxuICAgIE11bHRpQ2hpbGQ6IFJlYWN0TXVsdGlDaGlsZCxcbiAgICBUZXh0Q29tcG9uZW50OiBSZWFjdFRleHRDb21wb25lbnRcbiAgfSk7XG59XG5cbmlmIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYpIHtcbiAgdmFyIEV4ZWN1dGlvbkVudmlyb25tZW50ID0gcmVxdWlyZShcIi4vRXhlY3V0aW9uRW52aXJvbm1lbnRcIik7XG4gIGlmIChFeGVjdXRpb25FbnZpcm9ubWVudC5jYW5Vc2VET00gJiYgd2luZG93LnRvcCA9PT0gd2luZG93LnNlbGYpIHtcblxuICAgIC8vIElmIHdlJ3JlIGluIENocm9tZSwgbG9vayBmb3IgdGhlIGRldnRvb2xzIG1hcmtlciBhbmQgcHJvdmlkZSBhIGRvd25sb2FkXG4gICAgLy8gbGluayBpZiBub3QgaW5zdGFsbGVkLlxuICAgIGlmIChuYXZpZ2F0b3IudXNlckFnZW50LmluZGV4T2YoJ0Nocm9tZScpID4gLTEpIHtcbiAgICAgIGlmICh0eXBlb2YgX19SRUFDVF9ERVZUT09MU19HTE9CQUxfSE9PS19fID09PSAndW5kZWZpbmVkJykge1xuICAgICAgICBjb25zb2xlLmRlYnVnKFxuICAgICAgICAgICdEb3dubG9hZCB0aGUgUmVhY3QgRGV2VG9vbHMgZm9yIGEgYmV0dGVyIGRldmVsb3BtZW50IGV4cGVyaWVuY2U6ICcgK1xuICAgICAgICAgICdodHRwOi8vZmIubWUvcmVhY3QtZGV2dG9vbHMnXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgdmFyIGV4cGVjdGVkRmVhdHVyZXMgPSBbXG4gICAgICAvLyBzaGltc1xuICAgICAgQXJyYXkuaXNBcnJheSxcbiAgICAgIEFycmF5LnByb3RvdHlwZS5ldmVyeSxcbiAgICAgIEFycmF5LnByb3RvdHlwZS5mb3JFYWNoLFxuICAgICAgQXJyYXkucHJvdG90eXBlLmluZGV4T2YsXG4gICAgICBBcnJheS5wcm90b3R5cGUubWFwLFxuICAgICAgRGF0ZS5ub3csXG4gICAgICBGdW5jdGlvbi5wcm90b3R5cGUuYmluZCxcbiAgICAgIE9iamVjdC5rZXlzLFxuICAgICAgU3RyaW5nLnByb3RvdHlwZS5zcGxpdCxcbiAgICAgIFN0cmluZy5wcm90b3R5cGUudHJpbSxcblxuICAgICAgLy8gc2hhbXNcbiAgICAgIE9iamVjdC5jcmVhdGUsXG4gICAgICBPYmplY3QuZnJlZXplXG4gICAgXTtcblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgZXhwZWN0ZWRGZWF0dXJlcy5sZW5ndGg7IGkrKykge1xuICAgICAgaWYgKCFleHBlY3RlZEZlYXR1cmVzW2ldKSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoXG4gICAgICAgICAgJ09uZSBvciBtb3JlIEVTNSBzaGltL3NoYW1zIGV4cGVjdGVkIGJ5IFJlYWN0IGFyZSBub3QgYXZhaWxhYmxlOiAnICtcbiAgICAgICAgICAnaHR0cDovL2ZiLm1lL3JlYWN0LXdhcm5pbmctcG9seWZpbGxzJ1xuICAgICAgICApO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9XG4gIH1cbn1cblxuLy8gVmVyc2lvbiBleGlzdHMgb25seSBpbiB0aGUgb3Blbi1zb3VyY2UgdmVyc2lvbiBvZiBSZWFjdCwgbm90IGluIEZhY2Vib29rJ3Ncbi8vIGludGVybmFsIHZlcnNpb24uXG5SZWFjdC52ZXJzaW9uID0gJzAuMTIuMSc7XG5cbm1vZHVsZS5leHBvcnRzID0gUmVhY3Q7XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKCdfcHJvY2VzcycpKSIsIihmdW5jdGlvbiAocHJvY2Vzcyl7XG4vKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgUmVhY3RCcm93c2VyQ29tcG9uZW50TWl4aW5cbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIFJlYWN0RW1wdHlDb21wb25lbnQgPSByZXF1aXJlKFwiLi9SZWFjdEVtcHR5Q29tcG9uZW50XCIpO1xudmFyIFJlYWN0TW91bnQgPSByZXF1aXJlKFwiLi9SZWFjdE1vdW50XCIpO1xuXG52YXIgaW52YXJpYW50ID0gcmVxdWlyZShcIi4vaW52YXJpYW50XCIpO1xuXG52YXIgUmVhY3RCcm93c2VyQ29tcG9uZW50TWl4aW4gPSB7XG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBET00gbm9kZSByZW5kZXJlZCBieSB0aGlzIGNvbXBvbmVudC5cbiAgICpcbiAgICogQHJldHVybiB7RE9NRWxlbWVudH0gVGhlIHJvb3Qgbm9kZSBvZiB0aGlzIGNvbXBvbmVudC5cbiAgICogQGZpbmFsXG4gICAqIEBwcm90ZWN0ZWRcbiAgICovXG4gIGdldERPTU5vZGU6IGZ1bmN0aW9uKCkge1xuICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICB0aGlzLmlzTW91bnRlZCgpLFxuICAgICAgJ2dldERPTU5vZGUoKTogQSBjb21wb25lbnQgbXVzdCBiZSBtb3VudGVkIHRvIGhhdmUgYSBET00gbm9kZS4nXG4gICAgKSA6IGludmFyaWFudCh0aGlzLmlzTW91bnRlZCgpKSk7XG4gICAgaWYgKFJlYWN0RW1wdHlDb21wb25lbnQuaXNOdWxsQ29tcG9uZW50SUQodGhpcy5fcm9vdE5vZGVJRCkpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgICByZXR1cm4gUmVhY3RNb3VudC5nZXROb2RlKHRoaXMuX3Jvb3ROb2RlSUQpO1xuICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJlYWN0QnJvd3NlckNvbXBvbmVudE1peGluO1xuXG59KS5jYWxsKHRoaXMscmVxdWlyZSgnX3Byb2Nlc3MnKSkiLCIvKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgUmVhY3RCcm93c2VyRXZlbnRFbWl0dGVyXG4gKiBAdHlwZWNoZWNrcyBzdGF0aWMtb25seVxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgRXZlbnRDb25zdGFudHMgPSByZXF1aXJlKFwiLi9FdmVudENvbnN0YW50c1wiKTtcbnZhciBFdmVudFBsdWdpbkh1YiA9IHJlcXVpcmUoXCIuL0V2ZW50UGx1Z2luSHViXCIpO1xudmFyIEV2ZW50UGx1Z2luUmVnaXN0cnkgPSByZXF1aXJlKFwiLi9FdmVudFBsdWdpblJlZ2lzdHJ5XCIpO1xudmFyIFJlYWN0RXZlbnRFbWl0dGVyTWl4aW4gPSByZXF1aXJlKFwiLi9SZWFjdEV2ZW50RW1pdHRlck1peGluXCIpO1xudmFyIFZpZXdwb3J0TWV0cmljcyA9IHJlcXVpcmUoXCIuL1ZpZXdwb3J0TWV0cmljc1wiKTtcblxudmFyIGFzc2lnbiA9IHJlcXVpcmUoXCIuL09iamVjdC5hc3NpZ25cIik7XG52YXIgaXNFdmVudFN1cHBvcnRlZCA9IHJlcXVpcmUoXCIuL2lzRXZlbnRTdXBwb3J0ZWRcIik7XG5cbi8qKlxuICogU3VtbWFyeSBvZiBgUmVhY3RCcm93c2VyRXZlbnRFbWl0dGVyYCBldmVudCBoYW5kbGluZzpcbiAqXG4gKiAgLSBUb3AtbGV2ZWwgZGVsZWdhdGlvbiBpcyB1c2VkIHRvIHRyYXAgbW9zdCBuYXRpdmUgYnJvd3NlciBldmVudHMuIFRoaXNcbiAqICAgIG1heSBvbmx5IG9jY3VyIGluIHRoZSBtYWluIHRocmVhZCBhbmQgaXMgdGhlIHJlc3BvbnNpYmlsaXR5IG9mXG4gKiAgICBSZWFjdEV2ZW50TGlzdGVuZXIsIHdoaWNoIGlzIGluamVjdGVkIGFuZCBjYW4gdGhlcmVmb3JlIHN1cHBvcnQgcGx1Z2dhYmxlXG4gKiAgICBldmVudCBzb3VyY2VzLiBUaGlzIGlzIHRoZSBvbmx5IHdvcmsgdGhhdCBvY2N1cnMgaW4gdGhlIG1haW4gdGhyZWFkLlxuICpcbiAqICAtIFdlIG5vcm1hbGl6ZSBhbmQgZGUtZHVwbGljYXRlIGV2ZW50cyB0byBhY2NvdW50IGZvciBicm93c2VyIHF1aXJrcy4gVGhpc1xuICogICAgbWF5IGJlIGRvbmUgaW4gdGhlIHdvcmtlciB0aHJlYWQuXG4gKlxuICogIC0gRm9yd2FyZCB0aGVzZSBuYXRpdmUgZXZlbnRzICh3aXRoIHRoZSBhc3NvY2lhdGVkIHRvcC1sZXZlbCB0eXBlIHVzZWQgdG9cbiAqICAgIHRyYXAgaXQpIHRvIGBFdmVudFBsdWdpbkh1YmAsIHdoaWNoIGluIHR1cm4gd2lsbCBhc2sgcGx1Z2lucyBpZiB0aGV5IHdhbnRcbiAqICAgIHRvIGV4dHJhY3QgYW55IHN5bnRoZXRpYyBldmVudHMuXG4gKlxuICogIC0gVGhlIGBFdmVudFBsdWdpbkh1YmAgd2lsbCB0aGVuIHByb2Nlc3MgZWFjaCBldmVudCBieSBhbm5vdGF0aW5nIHRoZW0gd2l0aFxuICogICAgXCJkaXNwYXRjaGVzXCIsIGEgc2VxdWVuY2Ugb2YgbGlzdGVuZXJzIGFuZCBJRHMgdGhhdCBjYXJlIGFib3V0IHRoYXQgZXZlbnQuXG4gKlxuICogIC0gVGhlIGBFdmVudFBsdWdpbkh1YmAgdGhlbiBkaXNwYXRjaGVzIHRoZSBldmVudHMuXG4gKlxuICogT3ZlcnZpZXcgb2YgUmVhY3QgYW5kIHRoZSBldmVudCBzeXN0ZW06XG4gKlxuICogKy0tLS0tLS0tLS0tLSsgICAgLlxuICogfCAgICBET00gICAgIHwgICAgLlxuICogKy0tLS0tLS0tLS0tLSsgICAgLlxuICogICAgICAgfCAgICAgICAgICAgLlxuICogICAgICAgdiAgICAgICAgICAgLlxuICogKy0tLS0tLS0tLS0tLSsgICAgLlxuICogfCBSZWFjdEV2ZW50IHwgICAgLlxuICogfCAgTGlzdGVuZXIgIHwgICAgLlxuICogKy0tLS0tLS0tLS0tLSsgICAgLiAgICAgICAgICAgICAgICAgICAgICAgICArLS0tLS0tLS0tLS0rXG4gKiAgICAgICB8ICAgICAgICAgICAuICAgICAgICAgICAgICAgKy0tLS0tLS0tK3xTaW1wbGVFdmVudHxcbiAqICAgICAgIHwgICAgICAgICAgIC4gICAgICAgICAgICAgICB8ICAgICAgICAgfFBsdWdpbiAgICAgfFxuICogKy0tLS0tfC0tLS0tLSsgICAgLiAgICAgICAgICAgICAgIHYgICAgICAgICArLS0tLS0tLS0tLS0rXG4gKiB8ICAgICB8ICAgICAgfCAgICAuICAgICstLS0tLS0tLS0tLS0tLSsgICAgICAgICAgICAgICAgICAgICstLS0tLS0tLS0tLS0rXG4gKiB8ICAgICArLS0tLS0tLS0tLS0uLS0tPnxFdmVudFBsdWdpbkh1YnwgICAgICAgICAgICAgICAgICAgIHwgICAgRXZlbnQgICB8XG4gKiB8ICAgICAgICAgICAgfCAgICAuICAgIHwgICAgICAgICAgICAgIHwgICAgICstLS0tLS0tLS0tLSsgIHwgUHJvcGFnYXRvcnN8XG4gKiB8IFJlYWN0RXZlbnQgfCAgICAuICAgIHwgICAgICAgICAgICAgIHwgICAgIHxUYXBFdmVudCAgIHwgIHwtLS0tLS0tLS0tLS18XG4gKiB8ICBFbWl0dGVyICAgfCAgICAuICAgIHwgICAgICAgICAgICAgIHw8LS0tK3xQbHVnaW4gICAgIHwgIHxvdGhlciBwbHVnaW58XG4gKiB8ICAgICAgICAgICAgfCAgICAuICAgIHwgICAgICAgICAgICAgIHwgICAgICstLS0tLS0tLS0tLSsgIHwgIHV0aWxpdGllcyB8XG4gKiB8ICAgICArLS0tLS0tLS0tLS0uLS0tPnwgICAgICAgICAgICAgIHwgICAgICAgICAgICAgICAgICAgICstLS0tLS0tLS0tLS0rXG4gKiB8ICAgICB8ICAgICAgfCAgICAuICAgICstLS0tLS0tLS0tLS0tLStcbiAqICstLS0tLXwtLS0tLS0rICAgIC4gICAgICAgICAgICAgICAgXiAgICAgICAgKy0tLS0tLS0tLS0tK1xuICogICAgICAgfCAgICAgICAgICAgLiAgICAgICAgICAgICAgICB8ICAgICAgICB8RW50ZXIvTGVhdmV8XG4gKiAgICAgICArICAgICAgICAgICAuICAgICAgICAgICAgICAgICstLS0tLS0tK3xQbHVnaW4gICAgIHxcbiAqICstLS0tLS0tLS0tLS0tKyAgIC4gICAgICAgICAgICAgICAgICAgICAgICAgKy0tLS0tLS0tLS0tK1xuICogfCBhcHBsaWNhdGlvbiB8ICAgLlxuICogfC0tLS0tLS0tLS0tLS18ICAgLlxuICogfCAgICAgICAgICAgICB8ICAgLlxuICogfCAgICAgICAgICAgICB8ICAgLlxuICogKy0tLS0tLS0tLS0tLS0rICAgLlxuICogICAgICAgICAgICAgICAgICAgLlxuICogICAgUmVhY3QgQ29yZSAgICAgLiAgR2VuZXJhbCBQdXJwb3NlIEV2ZW50IFBsdWdpbiBTeXN0ZW1cbiAqL1xuXG52YXIgYWxyZWFkeUxpc3RlbmluZ1RvID0ge307XG52YXIgaXNNb25pdG9yaW5nU2Nyb2xsVmFsdWUgPSBmYWxzZTtcbnZhciByZWFjdFRvcExpc3RlbmVyc0NvdW50ZXIgPSAwO1xuXG4vLyBGb3IgZXZlbnRzIGxpa2UgJ3N1Ym1pdCcgd2hpY2ggZG9uJ3QgY29uc2lzdGVudGx5IGJ1YmJsZSAod2hpY2ggd2UgdHJhcCBhdCBhXG4vLyBsb3dlciBub2RlIHRoYW4gYGRvY3VtZW50YCksIGJpbmRpbmcgYXQgYGRvY3VtZW50YCB3b3VsZCBjYXVzZSBkdXBsaWNhdGVcbi8vIGV2ZW50cyBzbyB3ZSBkb24ndCBpbmNsdWRlIHRoZW0gaGVyZVxudmFyIHRvcEV2ZW50TWFwcGluZyA9IHtcbiAgdG9wQmx1cjogJ2JsdXInLFxuICB0b3BDaGFuZ2U6ICdjaGFuZ2UnLFxuICB0b3BDbGljazogJ2NsaWNrJyxcbiAgdG9wQ29tcG9zaXRpb25FbmQ6ICdjb21wb3NpdGlvbmVuZCcsXG4gIHRvcENvbXBvc2l0aW9uU3RhcnQ6ICdjb21wb3NpdGlvbnN0YXJ0JyxcbiAgdG9wQ29tcG9zaXRpb25VcGRhdGU6ICdjb21wb3NpdGlvbnVwZGF0ZScsXG4gIHRvcENvbnRleHRNZW51OiAnY29udGV4dG1lbnUnLFxuICB0b3BDb3B5OiAnY29weScsXG4gIHRvcEN1dDogJ2N1dCcsXG4gIHRvcERvdWJsZUNsaWNrOiAnZGJsY2xpY2snLFxuICB0b3BEcmFnOiAnZHJhZycsXG4gIHRvcERyYWdFbmQ6ICdkcmFnZW5kJyxcbiAgdG9wRHJhZ0VudGVyOiAnZHJhZ2VudGVyJyxcbiAgdG9wRHJhZ0V4aXQ6ICdkcmFnZXhpdCcsXG4gIHRvcERyYWdMZWF2ZTogJ2RyYWdsZWF2ZScsXG4gIHRvcERyYWdPdmVyOiAnZHJhZ292ZXInLFxuICB0b3BEcmFnU3RhcnQ6ICdkcmFnc3RhcnQnLFxuICB0b3BEcm9wOiAnZHJvcCcsXG4gIHRvcEZvY3VzOiAnZm9jdXMnLFxuICB0b3BJbnB1dDogJ2lucHV0JyxcbiAgdG9wS2V5RG93bjogJ2tleWRvd24nLFxuICB0b3BLZXlQcmVzczogJ2tleXByZXNzJyxcbiAgdG9wS2V5VXA6ICdrZXl1cCcsXG4gIHRvcE1vdXNlRG93bjogJ21vdXNlZG93bicsXG4gIHRvcE1vdXNlTW92ZTogJ21vdXNlbW92ZScsXG4gIHRvcE1vdXNlT3V0OiAnbW91c2VvdXQnLFxuICB0b3BNb3VzZU92ZXI6ICdtb3VzZW92ZXInLFxuICB0b3BNb3VzZVVwOiAnbW91c2V1cCcsXG4gIHRvcFBhc3RlOiAncGFzdGUnLFxuICB0b3BTY3JvbGw6ICdzY3JvbGwnLFxuICB0b3BTZWxlY3Rpb25DaGFuZ2U6ICdzZWxlY3Rpb25jaGFuZ2UnLFxuICB0b3BUZXh0SW5wdXQ6ICd0ZXh0SW5wdXQnLFxuICB0b3BUb3VjaENhbmNlbDogJ3RvdWNoY2FuY2VsJyxcbiAgdG9wVG91Y2hFbmQ6ICd0b3VjaGVuZCcsXG4gIHRvcFRvdWNoTW92ZTogJ3RvdWNobW92ZScsXG4gIHRvcFRvdWNoU3RhcnQ6ICd0b3VjaHN0YXJ0JyxcbiAgdG9wV2hlZWw6ICd3aGVlbCdcbn07XG5cbi8qKlxuICogVG8gZW5zdXJlIG5vIGNvbmZsaWN0cyB3aXRoIG90aGVyIHBvdGVudGlhbCBSZWFjdCBpbnN0YW5jZXMgb24gdGhlIHBhZ2VcbiAqL1xudmFyIHRvcExpc3RlbmVyc0lES2V5ID0gXCJfcmVhY3RMaXN0ZW5lcnNJRFwiICsgU3RyaW5nKE1hdGgucmFuZG9tKCkpLnNsaWNlKDIpO1xuXG5mdW5jdGlvbiBnZXRMaXN0ZW5pbmdGb3JEb2N1bWVudChtb3VudEF0KSB7XG4gIC8vIEluIElFOCwgYG1vdW50QXRgIGlzIGEgaG9zdCBvYmplY3QgYW5kIGRvZXNuJ3QgaGF2ZSBgaGFzT3duUHJvcGVydHlgXG4gIC8vIGRpcmVjdGx5LlxuICBpZiAoIU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChtb3VudEF0LCB0b3BMaXN0ZW5lcnNJREtleSkpIHtcbiAgICBtb3VudEF0W3RvcExpc3RlbmVyc0lES2V5XSA9IHJlYWN0VG9wTGlzdGVuZXJzQ291bnRlcisrO1xuICAgIGFscmVhZHlMaXN0ZW5pbmdUb1ttb3VudEF0W3RvcExpc3RlbmVyc0lES2V5XV0gPSB7fTtcbiAgfVxuICByZXR1cm4gYWxyZWFkeUxpc3RlbmluZ1RvW21vdW50QXRbdG9wTGlzdGVuZXJzSURLZXldXTtcbn1cblxuLyoqXG4gKiBgUmVhY3RCcm93c2VyRXZlbnRFbWl0dGVyYCBpcyB1c2VkIHRvIGF0dGFjaCB0b3AtbGV2ZWwgZXZlbnQgbGlzdGVuZXJzLiBGb3JcbiAqIGV4YW1wbGU6XG4gKlxuICogICBSZWFjdEJyb3dzZXJFdmVudEVtaXR0ZXIucHV0TGlzdGVuZXIoJ215SUQnLCAnb25DbGljaycsIG15RnVuY3Rpb24pO1xuICpcbiAqIFRoaXMgd291bGQgYWxsb2NhdGUgYSBcInJlZ2lzdHJhdGlvblwiIG9mIGAoJ29uQ2xpY2snLCBteUZ1bmN0aW9uKWAgb24gJ215SUQnLlxuICpcbiAqIEBpbnRlcm5hbFxuICovXG52YXIgUmVhY3RCcm93c2VyRXZlbnRFbWl0dGVyID0gYXNzaWduKHt9LCBSZWFjdEV2ZW50RW1pdHRlck1peGluLCB7XG5cbiAgLyoqXG4gICAqIEluamVjdGFibGUgZXZlbnQgYmFja2VuZFxuICAgKi9cbiAgUmVhY3RFdmVudExpc3RlbmVyOiBudWxsLFxuXG4gIGluamVjdGlvbjoge1xuICAgIC8qKlxuICAgICAqIEBwYXJhbSB7b2JqZWN0fSBSZWFjdEV2ZW50TGlzdGVuZXJcbiAgICAgKi9cbiAgICBpbmplY3RSZWFjdEV2ZW50TGlzdGVuZXI6IGZ1bmN0aW9uKFJlYWN0RXZlbnRMaXN0ZW5lcikge1xuICAgICAgUmVhY3RFdmVudExpc3RlbmVyLnNldEhhbmRsZVRvcExldmVsKFxuICAgICAgICBSZWFjdEJyb3dzZXJFdmVudEVtaXR0ZXIuaGFuZGxlVG9wTGV2ZWxcbiAgICAgICk7XG4gICAgICBSZWFjdEJyb3dzZXJFdmVudEVtaXR0ZXIuUmVhY3RFdmVudExpc3RlbmVyID0gUmVhY3RFdmVudExpc3RlbmVyO1xuICAgIH1cbiAgfSxcblxuICAvKipcbiAgICogU2V0cyB3aGV0aGVyIG9yIG5vdCBhbnkgY3JlYXRlZCBjYWxsYmFja3Mgc2hvdWxkIGJlIGVuYWJsZWQuXG4gICAqXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gZW5hYmxlZCBUcnVlIGlmIGNhbGxiYWNrcyBzaG91bGQgYmUgZW5hYmxlZC5cbiAgICovXG4gIHNldEVuYWJsZWQ6IGZ1bmN0aW9uKGVuYWJsZWQpIHtcbiAgICBpZiAoUmVhY3RCcm93c2VyRXZlbnRFbWl0dGVyLlJlYWN0RXZlbnRMaXN0ZW5lcikge1xuICAgICAgUmVhY3RCcm93c2VyRXZlbnRFbWl0dGVyLlJlYWN0RXZlbnRMaXN0ZW5lci5zZXRFbmFibGVkKGVuYWJsZWQpO1xuICAgIH1cbiAgfSxcblxuICAvKipcbiAgICogQHJldHVybiB7Ym9vbGVhbn0gVHJ1ZSBpZiBjYWxsYmFja3MgYXJlIGVuYWJsZWQuXG4gICAqL1xuICBpc0VuYWJsZWQ6IGZ1bmN0aW9uKCkge1xuICAgIHJldHVybiAhIShcbiAgICAgIFJlYWN0QnJvd3NlckV2ZW50RW1pdHRlci5SZWFjdEV2ZW50TGlzdGVuZXIgJiZcbiAgICAgIFJlYWN0QnJvd3NlckV2ZW50RW1pdHRlci5SZWFjdEV2ZW50TGlzdGVuZXIuaXNFbmFibGVkKClcbiAgICApO1xuICB9LFxuXG4gIC8qKlxuICAgKiBXZSBsaXN0ZW4gZm9yIGJ1YmJsZWQgdG91Y2ggZXZlbnRzIG9uIHRoZSBkb2N1bWVudCBvYmplY3QuXG4gICAqXG4gICAqIEZpcmVmb3ggdjguMDEgKGFuZCBwb3NzaWJseSBvdGhlcnMpIGV4aGliaXRlZCBzdHJhbmdlIGJlaGF2aW9yIHdoZW5cbiAgICogbW91bnRpbmcgYG9ubW91c2Vtb3ZlYCBldmVudHMgYXQgc29tZSBub2RlIHRoYXQgd2FzIG5vdCB0aGUgZG9jdW1lbnRcbiAgICogZWxlbWVudC4gVGhlIHN5bXB0b21zIHdlcmUgdGhhdCBpZiB5b3VyIG1vdXNlIGlzIG5vdCBtb3Zpbmcgb3ZlciBzb21ldGhpbmdcbiAgICogY29udGFpbmVkIHdpdGhpbiB0aGF0IG1vdW50IHBvaW50IChmb3IgZXhhbXBsZSBvbiB0aGUgYmFja2dyb3VuZCkgdGhlXG4gICAqIHRvcC1sZXZlbCBsaXN0ZW5lcnMgZm9yIGBvbm1vdXNlbW92ZWAgd29uJ3QgYmUgY2FsbGVkLiBIb3dldmVyLCBpZiB5b3VcbiAgICogcmVnaXN0ZXIgdGhlIGBtb3VzZW1vdmVgIG9uIHRoZSBkb2N1bWVudCBvYmplY3QsIHRoZW4gaXQgd2lsbCBvZiBjb3Vyc2VcbiAgICogY2F0Y2ggYWxsIGBtb3VzZW1vdmVgcy4gVGhpcyBhbG9uZyB3aXRoIGlPUyBxdWlya3MsIGp1c3RpZmllcyByZXN0cmljdGluZ1xuICAgKiB0b3AtbGV2ZWwgbGlzdGVuZXJzIHRvIHRoZSBkb2N1bWVudCBvYmplY3Qgb25seSwgYXQgbGVhc3QgZm9yIHRoZXNlXG4gICAqIG1vdmVtZW50IHR5cGVzIG9mIGV2ZW50cyBhbmQgcG9zc2libHkgYWxsIGV2ZW50cy5cbiAgICpcbiAgICogQHNlZSBodHRwOi8vd3d3LnF1aXJrc21vZGUub3JnL2Jsb2cvYXJjaGl2ZXMvMjAxMC8wOS9jbGlja19ldmVudF9kZWwuaHRtbFxuICAgKlxuICAgKiBBbHNvLCBga2V5dXBgL2BrZXlwcmVzc2AvYGtleWRvd25gIGRvIG5vdCBidWJibGUgdG8gdGhlIHdpbmRvdyBvbiBJRSwgYnV0XG4gICAqIHRoZXkgYnViYmxlIHRvIGRvY3VtZW50LlxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gcmVnaXN0cmF0aW9uTmFtZSBOYW1lIG9mIGxpc3RlbmVyIChlLmcuIGBvbkNsaWNrYCkuXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBjb250ZW50RG9jdW1lbnRIYW5kbGUgRG9jdW1lbnQgd2hpY2ggb3ducyB0aGUgY29udGFpbmVyXG4gICAqL1xuICBsaXN0ZW5UbzogZnVuY3Rpb24ocmVnaXN0cmF0aW9uTmFtZSwgY29udGVudERvY3VtZW50SGFuZGxlKSB7XG4gICAgdmFyIG1vdW50QXQgPSBjb250ZW50RG9jdW1lbnRIYW5kbGU7XG4gICAgdmFyIGlzTGlzdGVuaW5nID0gZ2V0TGlzdGVuaW5nRm9yRG9jdW1lbnQobW91bnRBdCk7XG4gICAgdmFyIGRlcGVuZGVuY2llcyA9IEV2ZW50UGx1Z2luUmVnaXN0cnkuXG4gICAgICByZWdpc3RyYXRpb25OYW1lRGVwZW5kZW5jaWVzW3JlZ2lzdHJhdGlvbk5hbWVdO1xuXG4gICAgdmFyIHRvcExldmVsVHlwZXMgPSBFdmVudENvbnN0YW50cy50b3BMZXZlbFR5cGVzO1xuICAgIGZvciAodmFyIGkgPSAwLCBsID0gZGVwZW5kZW5jaWVzLmxlbmd0aDsgaSA8IGw7IGkrKykge1xuICAgICAgdmFyIGRlcGVuZGVuY3kgPSBkZXBlbmRlbmNpZXNbaV07XG4gICAgICBpZiAoIShcbiAgICAgICAgICAgIGlzTGlzdGVuaW5nLmhhc093blByb3BlcnR5KGRlcGVuZGVuY3kpICYmXG4gICAgICAgICAgICBpc0xpc3RlbmluZ1tkZXBlbmRlbmN5XVxuICAgICAgICAgICkpIHtcbiAgICAgICAgaWYgKGRlcGVuZGVuY3kgPT09IHRvcExldmVsVHlwZXMudG9wV2hlZWwpIHtcbiAgICAgICAgICBpZiAoaXNFdmVudFN1cHBvcnRlZCgnd2hlZWwnKSkge1xuICAgICAgICAgICAgUmVhY3RCcm93c2VyRXZlbnRFbWl0dGVyLlJlYWN0RXZlbnRMaXN0ZW5lci50cmFwQnViYmxlZEV2ZW50KFxuICAgICAgICAgICAgICB0b3BMZXZlbFR5cGVzLnRvcFdoZWVsLFxuICAgICAgICAgICAgICAnd2hlZWwnLFxuICAgICAgICAgICAgICBtb3VudEF0XG4gICAgICAgICAgICApO1xuICAgICAgICAgIH0gZWxzZSBpZiAoaXNFdmVudFN1cHBvcnRlZCgnbW91c2V3aGVlbCcpKSB7XG4gICAgICAgICAgICBSZWFjdEJyb3dzZXJFdmVudEVtaXR0ZXIuUmVhY3RFdmVudExpc3RlbmVyLnRyYXBCdWJibGVkRXZlbnQoXG4gICAgICAgICAgICAgIHRvcExldmVsVHlwZXMudG9wV2hlZWwsXG4gICAgICAgICAgICAgICdtb3VzZXdoZWVsJyxcbiAgICAgICAgICAgICAgbW91bnRBdFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gRmlyZWZveCBuZWVkcyB0byBjYXB0dXJlIGEgZGlmZmVyZW50IG1vdXNlIHNjcm9sbCBldmVudC5cbiAgICAgICAgICAgIC8vIEBzZWUgaHR0cDovL3d3dy5xdWlya3Ntb2RlLm9yZy9kb20vZXZlbnRzL3Rlc3RzL3Njcm9sbC5odG1sXG4gICAgICAgICAgICBSZWFjdEJyb3dzZXJFdmVudEVtaXR0ZXIuUmVhY3RFdmVudExpc3RlbmVyLnRyYXBCdWJibGVkRXZlbnQoXG4gICAgICAgICAgICAgIHRvcExldmVsVHlwZXMudG9wV2hlZWwsXG4gICAgICAgICAgICAgICdET01Nb3VzZVNjcm9sbCcsXG4gICAgICAgICAgICAgIG1vdW50QXRcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2UgaWYgKGRlcGVuZGVuY3kgPT09IHRvcExldmVsVHlwZXMudG9wU2Nyb2xsKSB7XG5cbiAgICAgICAgICBpZiAoaXNFdmVudFN1cHBvcnRlZCgnc2Nyb2xsJywgdHJ1ZSkpIHtcbiAgICAgICAgICAgIFJlYWN0QnJvd3NlckV2ZW50RW1pdHRlci5SZWFjdEV2ZW50TGlzdGVuZXIudHJhcENhcHR1cmVkRXZlbnQoXG4gICAgICAgICAgICAgIHRvcExldmVsVHlwZXMudG9wU2Nyb2xsLFxuICAgICAgICAgICAgICAnc2Nyb2xsJyxcbiAgICAgICAgICAgICAgbW91bnRBdFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgUmVhY3RCcm93c2VyRXZlbnRFbWl0dGVyLlJlYWN0RXZlbnRMaXN0ZW5lci50cmFwQnViYmxlZEV2ZW50KFxuICAgICAgICAgICAgICB0b3BMZXZlbFR5cGVzLnRvcFNjcm9sbCxcbiAgICAgICAgICAgICAgJ3Njcm9sbCcsXG4gICAgICAgICAgICAgIFJlYWN0QnJvd3NlckV2ZW50RW1pdHRlci5SZWFjdEV2ZW50TGlzdGVuZXIuV0lORE9XX0hBTkRMRVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSBpZiAoZGVwZW5kZW5jeSA9PT0gdG9wTGV2ZWxUeXBlcy50b3BGb2N1cyB8fFxuICAgICAgICAgICAgZGVwZW5kZW5jeSA9PT0gdG9wTGV2ZWxUeXBlcy50b3BCbHVyKSB7XG5cbiAgICAgICAgICBpZiAoaXNFdmVudFN1cHBvcnRlZCgnZm9jdXMnLCB0cnVlKSkge1xuICAgICAgICAgICAgUmVhY3RCcm93c2VyRXZlbnRFbWl0dGVyLlJlYWN0RXZlbnRMaXN0ZW5lci50cmFwQ2FwdHVyZWRFdmVudChcbiAgICAgICAgICAgICAgdG9wTGV2ZWxUeXBlcy50b3BGb2N1cyxcbiAgICAgICAgICAgICAgJ2ZvY3VzJyxcbiAgICAgICAgICAgICAgbW91bnRBdFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIFJlYWN0QnJvd3NlckV2ZW50RW1pdHRlci5SZWFjdEV2ZW50TGlzdGVuZXIudHJhcENhcHR1cmVkRXZlbnQoXG4gICAgICAgICAgICAgIHRvcExldmVsVHlwZXMudG9wQmx1cixcbiAgICAgICAgICAgICAgJ2JsdXInLFxuICAgICAgICAgICAgICBtb3VudEF0XG4gICAgICAgICAgICApO1xuICAgICAgICAgIH0gZWxzZSBpZiAoaXNFdmVudFN1cHBvcnRlZCgnZm9jdXNpbicpKSB7XG4gICAgICAgICAgICAvLyBJRSBoYXMgYGZvY3VzaW5gIGFuZCBgZm9jdXNvdXRgIGV2ZW50cyB3aGljaCBidWJibGUuXG4gICAgICAgICAgICAvLyBAc2VlIGh0dHA6Ly93d3cucXVpcmtzbW9kZS5vcmcvYmxvZy9hcmNoaXZlcy8yMDA4LzA0L2RlbGVnYXRpbmdfdGhlLmh0bWxcbiAgICAgICAgICAgIFJlYWN0QnJvd3NlckV2ZW50RW1pdHRlci5SZWFjdEV2ZW50TGlzdGVuZXIudHJhcEJ1YmJsZWRFdmVudChcbiAgICAgICAgICAgICAgdG9wTGV2ZWxUeXBlcy50b3BGb2N1cyxcbiAgICAgICAgICAgICAgJ2ZvY3VzaW4nLFxuICAgICAgICAgICAgICBtb3VudEF0XG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgUmVhY3RCcm93c2VyRXZlbnRFbWl0dGVyLlJlYWN0RXZlbnRMaXN0ZW5lci50cmFwQnViYmxlZEV2ZW50KFxuICAgICAgICAgICAgICB0b3BMZXZlbFR5cGVzLnRvcEJsdXIsXG4gICAgICAgICAgICAgICdmb2N1c291dCcsXG4gICAgICAgICAgICAgIG1vdW50QXRcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gdG8gbWFrZSBzdXJlIGJsdXIgYW5kIGZvY3VzIGV2ZW50IGxpc3RlbmVycyBhcmUgb25seSBhdHRhY2hlZCBvbmNlXG4gICAgICAgICAgaXNMaXN0ZW5pbmdbdG9wTGV2ZWxUeXBlcy50b3BCbHVyXSA9IHRydWU7XG4gICAgICAgICAgaXNMaXN0ZW5pbmdbdG9wTGV2ZWxUeXBlcy50b3BGb2N1c10gPSB0cnVlO1xuICAgICAgICB9IGVsc2UgaWYgKHRvcEV2ZW50TWFwcGluZy5oYXNPd25Qcm9wZXJ0eShkZXBlbmRlbmN5KSkge1xuICAgICAgICAgIFJlYWN0QnJvd3NlckV2ZW50RW1pdHRlci5SZWFjdEV2ZW50TGlzdGVuZXIudHJhcEJ1YmJsZWRFdmVudChcbiAgICAgICAgICAgIGRlcGVuZGVuY3ksXG4gICAgICAgICAgICB0b3BFdmVudE1hcHBpbmdbZGVwZW5kZW5jeV0sXG4gICAgICAgICAgICBtb3VudEF0XG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlzTGlzdGVuaW5nW2RlcGVuZGVuY3ldID0gdHJ1ZTtcbiAgICAgIH1cbiAgICB9XG4gIH0sXG5cbiAgdHJhcEJ1YmJsZWRFdmVudDogZnVuY3Rpb24odG9wTGV2ZWxUeXBlLCBoYW5kbGVyQmFzZU5hbWUsIGhhbmRsZSkge1xuICAgIHJldHVybiBSZWFjdEJyb3dzZXJFdmVudEVtaXR0ZXIuUmVhY3RFdmVudExpc3RlbmVyLnRyYXBCdWJibGVkRXZlbnQoXG4gICAgICB0b3BMZXZlbFR5cGUsXG4gICAgICBoYW5kbGVyQmFzZU5hbWUsXG4gICAgICBoYW5kbGVcbiAgICApO1xuICB9LFxuXG4gIHRyYXBDYXB0dXJlZEV2ZW50OiBmdW5jdGlvbih0b3BMZXZlbFR5cGUsIGhhbmRsZXJCYXNlTmFtZSwgaGFuZGxlKSB7XG4gICAgcmV0dXJuIFJlYWN0QnJvd3NlckV2ZW50RW1pdHRlci5SZWFjdEV2ZW50TGlzdGVuZXIudHJhcENhcHR1cmVkRXZlbnQoXG4gICAgICB0b3BMZXZlbFR5cGUsXG4gICAgICBoYW5kbGVyQmFzZU5hbWUsXG4gICAgICBoYW5kbGVcbiAgICApO1xuICB9LFxuXG4gIC8qKlxuICAgKiBMaXN0ZW5zIHRvIHdpbmRvdyBzY3JvbGwgYW5kIHJlc2l6ZSBldmVudHMuIFdlIGNhY2hlIHNjcm9sbCB2YWx1ZXMgc28gdGhhdFxuICAgKiBhcHBsaWNhdGlvbiBjb2RlIGNhbiBhY2Nlc3MgdGhlbSB3aXRob3V0IHRyaWdnZXJpbmcgcmVmbG93cy5cbiAgICpcbiAgICogTk9URTogU2Nyb2xsIGV2ZW50cyBkbyBub3QgYnViYmxlLlxuICAgKlxuICAgKiBAc2VlIGh0dHA6Ly93d3cucXVpcmtzbW9kZS5vcmcvZG9tL2V2ZW50cy9zY3JvbGwuaHRtbFxuICAgKi9cbiAgZW5zdXJlU2Nyb2xsVmFsdWVNb25pdG9yaW5nOiBmdW5jdGlvbigpe1xuICAgIGlmICghaXNNb25pdG9yaW5nU2Nyb2xsVmFsdWUpIHtcbiAgICAgIHZhciByZWZyZXNoID0gVmlld3BvcnRNZXRyaWNzLnJlZnJlc2hTY3JvbGxWYWx1ZXM7XG4gICAgICBSZWFjdEJyb3dzZXJFdmVudEVtaXR0ZXIuUmVhY3RFdmVudExpc3RlbmVyLm1vbml0b3JTY3JvbGxWYWx1ZShyZWZyZXNoKTtcbiAgICAgIGlzTW9uaXRvcmluZ1Njcm9sbFZhbHVlID0gdHJ1ZTtcbiAgICB9XG4gIH0sXG5cbiAgZXZlbnROYW1lRGlzcGF0Y2hDb25maWdzOiBFdmVudFBsdWdpbkh1Yi5ldmVudE5hbWVEaXNwYXRjaENvbmZpZ3MsXG5cbiAgcmVnaXN0cmF0aW9uTmFtZU1vZHVsZXM6IEV2ZW50UGx1Z2luSHViLnJlZ2lzdHJhdGlvbk5hbWVNb2R1bGVzLFxuXG4gIHB1dExpc3RlbmVyOiBFdmVudFBsdWdpbkh1Yi5wdXRMaXN0ZW5lcixcblxuICBnZXRMaXN0ZW5lcjogRXZlbnRQbHVnaW5IdWIuZ2V0TGlzdGVuZXIsXG5cbiAgZGVsZXRlTGlzdGVuZXI6IEV2ZW50UGx1Z2luSHViLmRlbGV0ZUxpc3RlbmVyLFxuXG4gIGRlbGV0ZUFsbExpc3RlbmVyczogRXZlbnRQbHVnaW5IdWIuZGVsZXRlQWxsTGlzdGVuZXJzXG5cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJlYWN0QnJvd3NlckV2ZW50RW1pdHRlcjtcbiIsIihmdW5jdGlvbiAocHJvY2Vzcyl7XG4vKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgUmVhY3RDaGlsZHJlblxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgUG9vbGVkQ2xhc3MgPSByZXF1aXJlKFwiLi9Qb29sZWRDbGFzc1wiKTtcblxudmFyIHRyYXZlcnNlQWxsQ2hpbGRyZW4gPSByZXF1aXJlKFwiLi90cmF2ZXJzZUFsbENoaWxkcmVuXCIpO1xudmFyIHdhcm5pbmcgPSByZXF1aXJlKFwiLi93YXJuaW5nXCIpO1xuXG52YXIgdHdvQXJndW1lbnRQb29sZXIgPSBQb29sZWRDbGFzcy50d29Bcmd1bWVudFBvb2xlcjtcbnZhciB0aHJlZUFyZ3VtZW50UG9vbGVyID0gUG9vbGVkQ2xhc3MudGhyZWVBcmd1bWVudFBvb2xlcjtcblxuLyoqXG4gKiBQb29sZWRDbGFzcyByZXByZXNlbnRpbmcgdGhlIGJvb2trZWVwaW5nIGFzc29jaWF0ZWQgd2l0aCBwZXJmb3JtaW5nIGEgY2hpbGRcbiAqIHRyYXZlcnNhbC4gQWxsb3dzIGF2b2lkaW5nIGJpbmRpbmcgY2FsbGJhY2tzLlxuICpcbiAqIEBjb25zdHJ1Y3RvciBGb3JFYWNoQm9va0tlZXBpbmdcbiAqIEBwYXJhbSB7IWZ1bmN0aW9ufSBmb3JFYWNoRnVuY3Rpb24gRnVuY3Rpb24gdG8gcGVyZm9ybSB0cmF2ZXJzYWwgd2l0aC5cbiAqIEBwYXJhbSB7Pyp9IGZvckVhY2hDb250ZXh0IENvbnRleHQgdG8gcGVyZm9ybSBjb250ZXh0IHdpdGguXG4gKi9cbmZ1bmN0aW9uIEZvckVhY2hCb29rS2VlcGluZyhmb3JFYWNoRnVuY3Rpb24sIGZvckVhY2hDb250ZXh0KSB7XG4gIHRoaXMuZm9yRWFjaEZ1bmN0aW9uID0gZm9yRWFjaEZ1bmN0aW9uO1xuICB0aGlzLmZvckVhY2hDb250ZXh0ID0gZm9yRWFjaENvbnRleHQ7XG59XG5Qb29sZWRDbGFzcy5hZGRQb29saW5nVG8oRm9yRWFjaEJvb2tLZWVwaW5nLCB0d29Bcmd1bWVudFBvb2xlcik7XG5cbmZ1bmN0aW9uIGZvckVhY2hTaW5nbGVDaGlsZCh0cmF2ZXJzZUNvbnRleHQsIGNoaWxkLCBuYW1lLCBpKSB7XG4gIHZhciBmb3JFYWNoQm9va0tlZXBpbmcgPSB0cmF2ZXJzZUNvbnRleHQ7XG4gIGZvckVhY2hCb29rS2VlcGluZy5mb3JFYWNoRnVuY3Rpb24uY2FsbChcbiAgICBmb3JFYWNoQm9va0tlZXBpbmcuZm9yRWFjaENvbnRleHQsIGNoaWxkLCBpKTtcbn1cblxuLyoqXG4gKiBJdGVyYXRlcyB0aHJvdWdoIGNoaWxkcmVuIHRoYXQgYXJlIHR5cGljYWxseSBzcGVjaWZpZWQgYXMgYHByb3BzLmNoaWxkcmVuYC5cbiAqXG4gKiBUaGUgcHJvdmlkZWQgZm9yRWFjaEZ1bmMoY2hpbGQsIGluZGV4KSB3aWxsIGJlIGNhbGxlZCBmb3IgZWFjaFxuICogbGVhZiBjaGlsZC5cbiAqXG4gKiBAcGFyYW0gez8qfSBjaGlsZHJlbiBDaGlsZHJlbiB0cmVlIGNvbnRhaW5lci5cbiAqIEBwYXJhbSB7ZnVuY3Rpb24oKiwgaW50KX0gZm9yRWFjaEZ1bmMuXG4gKiBAcGFyYW0geyp9IGZvckVhY2hDb250ZXh0IENvbnRleHQgZm9yIGZvckVhY2hDb250ZXh0LlxuICovXG5mdW5jdGlvbiBmb3JFYWNoQ2hpbGRyZW4oY2hpbGRyZW4sIGZvckVhY2hGdW5jLCBmb3JFYWNoQ29udGV4dCkge1xuICBpZiAoY2hpbGRyZW4gPT0gbnVsbCkge1xuICAgIHJldHVybiBjaGlsZHJlbjtcbiAgfVxuXG4gIHZhciB0cmF2ZXJzZUNvbnRleHQgPVxuICAgIEZvckVhY2hCb29rS2VlcGluZy5nZXRQb29sZWQoZm9yRWFjaEZ1bmMsIGZvckVhY2hDb250ZXh0KTtcbiAgdHJhdmVyc2VBbGxDaGlsZHJlbihjaGlsZHJlbiwgZm9yRWFjaFNpbmdsZUNoaWxkLCB0cmF2ZXJzZUNvbnRleHQpO1xuICBGb3JFYWNoQm9va0tlZXBpbmcucmVsZWFzZSh0cmF2ZXJzZUNvbnRleHQpO1xufVxuXG4vKipcbiAqIFBvb2xlZENsYXNzIHJlcHJlc2VudGluZyB0aGUgYm9va2tlZXBpbmcgYXNzb2NpYXRlZCB3aXRoIHBlcmZvcm1pbmcgYSBjaGlsZFxuICogbWFwcGluZy4gQWxsb3dzIGF2b2lkaW5nIGJpbmRpbmcgY2FsbGJhY2tzLlxuICpcbiAqIEBjb25zdHJ1Y3RvciBNYXBCb29rS2VlcGluZ1xuICogQHBhcmFtIHshKn0gbWFwUmVzdWx0IE9iamVjdCBjb250YWluaW5nIHRoZSBvcmRlcmVkIG1hcCBvZiByZXN1bHRzLlxuICogQHBhcmFtIHshZnVuY3Rpb259IG1hcEZ1bmN0aW9uIEZ1bmN0aW9uIHRvIHBlcmZvcm0gbWFwcGluZyB3aXRoLlxuICogQHBhcmFtIHs/Kn0gbWFwQ29udGV4dCBDb250ZXh0IHRvIHBlcmZvcm0gbWFwcGluZyB3aXRoLlxuICovXG5mdW5jdGlvbiBNYXBCb29rS2VlcGluZyhtYXBSZXN1bHQsIG1hcEZ1bmN0aW9uLCBtYXBDb250ZXh0KSB7XG4gIHRoaXMubWFwUmVzdWx0ID0gbWFwUmVzdWx0O1xuICB0aGlzLm1hcEZ1bmN0aW9uID0gbWFwRnVuY3Rpb247XG4gIHRoaXMubWFwQ29udGV4dCA9IG1hcENvbnRleHQ7XG59XG5Qb29sZWRDbGFzcy5hZGRQb29saW5nVG8oTWFwQm9va0tlZXBpbmcsIHRocmVlQXJndW1lbnRQb29sZXIpO1xuXG5mdW5jdGlvbiBtYXBTaW5nbGVDaGlsZEludG9Db250ZXh0KHRyYXZlcnNlQ29udGV4dCwgY2hpbGQsIG5hbWUsIGkpIHtcbiAgdmFyIG1hcEJvb2tLZWVwaW5nID0gdHJhdmVyc2VDb250ZXh0O1xuICB2YXIgbWFwUmVzdWx0ID0gbWFwQm9va0tlZXBpbmcubWFwUmVzdWx0O1xuXG4gIHZhciBrZXlVbmlxdWUgPSAhbWFwUmVzdWx0Lmhhc093blByb3BlcnR5KG5hbWUpO1xuICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gd2FybmluZyhcbiAgICBrZXlVbmlxdWUsXG4gICAgJ1JlYWN0Q2hpbGRyZW4ubWFwKC4uLik6IEVuY291bnRlcmVkIHR3byBjaGlsZHJlbiB3aXRoIHRoZSBzYW1lIGtleSwgJyArXG4gICAgJ2Alc2AuIENoaWxkIGtleXMgbXVzdCBiZSB1bmlxdWU7IHdoZW4gdHdvIGNoaWxkcmVuIHNoYXJlIGEga2V5LCBvbmx5ICcgK1xuICAgICd0aGUgZmlyc3QgY2hpbGQgd2lsbCBiZSB1c2VkLicsXG4gICAgbmFtZVxuICApIDogbnVsbCk7XG5cbiAgaWYgKGtleVVuaXF1ZSkge1xuICAgIHZhciBtYXBwZWRDaGlsZCA9XG4gICAgICBtYXBCb29rS2VlcGluZy5tYXBGdW5jdGlvbi5jYWxsKG1hcEJvb2tLZWVwaW5nLm1hcENvbnRleHQsIGNoaWxkLCBpKTtcbiAgICBtYXBSZXN1bHRbbmFtZV0gPSBtYXBwZWRDaGlsZDtcbiAgfVxufVxuXG4vKipcbiAqIE1hcHMgY2hpbGRyZW4gdGhhdCBhcmUgdHlwaWNhbGx5IHNwZWNpZmllZCBhcyBgcHJvcHMuY2hpbGRyZW5gLlxuICpcbiAqIFRoZSBwcm92aWRlZCBtYXBGdW5jdGlvbihjaGlsZCwga2V5LCBpbmRleCkgd2lsbCBiZSBjYWxsZWQgZm9yIGVhY2hcbiAqIGxlYWYgY2hpbGQuXG4gKlxuICogVE9ETzogVGhpcyBtYXkgbGlrZWx5IGJyZWFrIGFueSBjYWxscyB0byBgUmVhY3RDaGlsZHJlbi5tYXBgIHRoYXQgd2VyZVxuICogcHJldmlvdXNseSByZWx5aW5nIG9uIHRoZSBmYWN0IHRoYXQgd2UgZ3VhcmRlZCBhZ2FpbnN0IG51bGwgY2hpbGRyZW4uXG4gKlxuICogQHBhcmFtIHs/Kn0gY2hpbGRyZW4gQ2hpbGRyZW4gdHJlZSBjb250YWluZXIuXG4gKiBAcGFyYW0ge2Z1bmN0aW9uKCosIGludCl9IG1hcEZ1bmN0aW9uLlxuICogQHBhcmFtIHsqfSBtYXBDb250ZXh0IENvbnRleHQgZm9yIG1hcEZ1bmN0aW9uLlxuICogQHJldHVybiB7b2JqZWN0fSBPYmplY3QgY29udGFpbmluZyB0aGUgb3JkZXJlZCBtYXAgb2YgcmVzdWx0cy5cbiAqL1xuZnVuY3Rpb24gbWFwQ2hpbGRyZW4oY2hpbGRyZW4sIGZ1bmMsIGNvbnRleHQpIHtcbiAgaWYgKGNoaWxkcmVuID09IG51bGwpIHtcbiAgICByZXR1cm4gY2hpbGRyZW47XG4gIH1cblxuICB2YXIgbWFwUmVzdWx0ID0ge307XG4gIHZhciB0cmF2ZXJzZUNvbnRleHQgPSBNYXBCb29rS2VlcGluZy5nZXRQb29sZWQobWFwUmVzdWx0LCBmdW5jLCBjb250ZXh0KTtcbiAgdHJhdmVyc2VBbGxDaGlsZHJlbihjaGlsZHJlbiwgbWFwU2luZ2xlQ2hpbGRJbnRvQ29udGV4dCwgdHJhdmVyc2VDb250ZXh0KTtcbiAgTWFwQm9va0tlZXBpbmcucmVsZWFzZSh0cmF2ZXJzZUNvbnRleHQpO1xuICByZXR1cm4gbWFwUmVzdWx0O1xufVxuXG5mdW5jdGlvbiBmb3JFYWNoU2luZ2xlQ2hpbGREdW1teSh0cmF2ZXJzZUNvbnRleHQsIGNoaWxkLCBuYW1lLCBpKSB7XG4gIHJldHVybiBudWxsO1xufVxuXG4vKipcbiAqIENvdW50IHRoZSBudW1iZXIgb2YgY2hpbGRyZW4gdGhhdCBhcmUgdHlwaWNhbGx5IHNwZWNpZmllZCBhc1xuICogYHByb3BzLmNoaWxkcmVuYC5cbiAqXG4gKiBAcGFyYW0gez8qfSBjaGlsZHJlbiBDaGlsZHJlbiB0cmVlIGNvbnRhaW5lci5cbiAqIEByZXR1cm4ge251bWJlcn0gVGhlIG51bWJlciBvZiBjaGlsZHJlbi5cbiAqL1xuZnVuY3Rpb24gY291bnRDaGlsZHJlbihjaGlsZHJlbiwgY29udGV4dCkge1xuICByZXR1cm4gdHJhdmVyc2VBbGxDaGlsZHJlbihjaGlsZHJlbiwgZm9yRWFjaFNpbmdsZUNoaWxkRHVtbXksIG51bGwpO1xufVxuXG52YXIgUmVhY3RDaGlsZHJlbiA9IHtcbiAgZm9yRWFjaDogZm9yRWFjaENoaWxkcmVuLFxuICBtYXA6IG1hcENoaWxkcmVuLFxuICBjb3VudDogY291bnRDaGlsZHJlblxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBSZWFjdENoaWxkcmVuO1xuXG59KS5jYWxsKHRoaXMscmVxdWlyZSgnX3Byb2Nlc3MnKSkiLCIoZnVuY3Rpb24gKHByb2Nlc3Mpe1xuLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIFJlYWN0Q29tcG9uZW50XG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBSZWFjdEVsZW1lbnQgPSByZXF1aXJlKFwiLi9SZWFjdEVsZW1lbnRcIik7XG52YXIgUmVhY3RPd25lciA9IHJlcXVpcmUoXCIuL1JlYWN0T3duZXJcIik7XG52YXIgUmVhY3RVcGRhdGVzID0gcmVxdWlyZShcIi4vUmVhY3RVcGRhdGVzXCIpO1xuXG52YXIgYXNzaWduID0gcmVxdWlyZShcIi4vT2JqZWN0LmFzc2lnblwiKTtcbnZhciBpbnZhcmlhbnQgPSByZXF1aXJlKFwiLi9pbnZhcmlhbnRcIik7XG52YXIga2V5TWlycm9yID0gcmVxdWlyZShcIi4va2V5TWlycm9yXCIpO1xuXG4vKipcbiAqIEV2ZXJ5IFJlYWN0IGNvbXBvbmVudCBpcyBpbiBvbmUgb2YgdGhlc2UgbGlmZSBjeWNsZXMuXG4gKi9cbnZhciBDb21wb25lbnRMaWZlQ3ljbGUgPSBrZXlNaXJyb3Ioe1xuICAvKipcbiAgICogTW91bnRlZCBjb21wb25lbnRzIGhhdmUgYSBET00gbm9kZSByZXByZXNlbnRhdGlvbiBhbmQgYXJlIGNhcGFibGUgb2ZcbiAgICogcmVjZWl2aW5nIG5ldyBwcm9wcy5cbiAgICovXG4gIE1PVU5URUQ6IG51bGwsXG4gIC8qKlxuICAgKiBVbm1vdW50ZWQgY29tcG9uZW50cyBhcmUgaW5hY3RpdmUgYW5kIGNhbm5vdCByZWNlaXZlIG5ldyBwcm9wcy5cbiAgICovXG4gIFVOTU9VTlRFRDogbnVsbFxufSk7XG5cbnZhciBpbmplY3RlZCA9IGZhbHNlO1xuXG4vKipcbiAqIE9wdGlvbmFsbHkgaW5qZWN0YWJsZSBlbnZpcm9ubWVudCBkZXBlbmRlbnQgY2xlYW51cCBob29rLiAoc2VydmVyIHZzLlxuICogYnJvd3NlciBldGMpLiBFeGFtcGxlOiBBIGJyb3dzZXIgc3lzdGVtIGNhY2hlcyBET00gbm9kZXMgYmFzZWQgb24gY29tcG9uZW50XG4gKiBJRCBhbmQgbXVzdCByZW1vdmUgdGhhdCBjYWNoZSBlbnRyeSB3aGVuIHRoaXMgaW5zdGFuY2UgaXMgdW5tb3VudGVkLlxuICpcbiAqIEBwcml2YXRlXG4gKi9cbnZhciB1bm1vdW50SURGcm9tRW52aXJvbm1lbnQgPSBudWxsO1xuXG4vKipcbiAqIFRoZSBcImltYWdlXCIgb2YgYSBjb21wb25lbnQgdHJlZSwgaXMgdGhlIHBsYXRmb3JtIHNwZWNpZmljICh0eXBpY2FsbHlcbiAqIHNlcmlhbGl6ZWQpIGRhdGEgdGhhdCByZXByZXNlbnRzIGEgdHJlZSBvZiBsb3dlciBsZXZlbCBVSSBidWlsZGluZyBibG9ja3MuXG4gKiBPbiB0aGUgd2ViLCB0aGlzIFwiaW1hZ2VcIiBpcyBIVE1MIG1hcmt1cCB3aGljaCBkZXNjcmliZXMgYSBjb25zdHJ1Y3Rpb24gb2ZcbiAqIGxvdyBsZXZlbCBgZGl2YCBhbmQgYHNwYW5gIG5vZGVzLiBPdGhlciBwbGF0Zm9ybXMgbWF5IGhhdmUgZGlmZmVyZW50XG4gKiBlbmNvZGluZyBvZiB0aGlzIFwiaW1hZ2VcIi4gVGhpcyBtdXN0IGJlIGluamVjdGVkLlxuICpcbiAqIEBwcml2YXRlXG4gKi9cbnZhciBtb3VudEltYWdlSW50b05vZGUgPSBudWxsO1xuXG4vKipcbiAqIENvbXBvbmVudHMgYXJlIHRoZSBiYXNpYyB1bml0cyBvZiBjb21wb3NpdGlvbiBpbiBSZWFjdC5cbiAqXG4gKiBFdmVyeSBjb21wb25lbnQgYWNjZXB0cyBhIHNldCBvZiBrZXllZCBpbnB1dCBwYXJhbWV0ZXJzIGtub3duIGFzIFwicHJvcHNcIiB0aGF0XG4gKiBhcmUgaW5pdGlhbGl6ZWQgYnkgdGhlIGNvbnN0cnVjdG9yLiBPbmNlIGEgY29tcG9uZW50IGlzIG1vdW50ZWQsIHRoZSBwcm9wc1xuICogY2FuIGJlIG11dGF0ZWQgdXNpbmcgYHNldFByb3BzYCBvciBgcmVwbGFjZVByb3BzYC5cbiAqXG4gKiBFdmVyeSBjb21wb25lbnQgaXMgY2FwYWJsZSBvZiB0aGUgZm9sbG93aW5nIG9wZXJhdGlvbnM6XG4gKlxuICogICBgbW91bnRDb21wb25lbnRgXG4gKiAgICAgSW5pdGlhbGl6ZXMgdGhlIGNvbXBvbmVudCwgcmVuZGVycyBtYXJrdXAsIGFuZCByZWdpc3RlcnMgZXZlbnQgbGlzdGVuZXJzLlxuICpcbiAqICAgYHJlY2VpdmVDb21wb25lbnRgXG4gKiAgICAgVXBkYXRlcyB0aGUgcmVuZGVyZWQgRE9NIG5vZGVzIHRvIG1hdGNoIHRoZSBnaXZlbiBjb21wb25lbnQuXG4gKlxuICogICBgdW5tb3VudENvbXBvbmVudGBcbiAqICAgICBSZWxlYXNlcyBhbnkgcmVzb3VyY2VzIGFsbG9jYXRlZCBieSB0aGlzIGNvbXBvbmVudC5cbiAqXG4gKiBDb21wb25lbnRzIGNhbiBhbHNvIGJlIFwib3duZWRcIiBieSBvdGhlciBjb21wb25lbnRzLiBCZWluZyBvd25lZCBieSBhbm90aGVyXG4gKiBjb21wb25lbnQgbWVhbnMgYmVpbmcgY29uc3RydWN0ZWQgYnkgdGhhdCBjb21wb25lbnQuIFRoaXMgaXMgZGlmZmVyZW50IGZyb21cbiAqIGJlaW5nIHRoZSBjaGlsZCBvZiBhIGNvbXBvbmVudCwgd2hpY2ggbWVhbnMgaGF2aW5nIGEgRE9NIHJlcHJlc2VudGF0aW9uIHRoYXRcbiAqIGlzIGEgY2hpbGQgb2YgdGhlIERPTSByZXByZXNlbnRhdGlvbiBvZiB0aGF0IGNvbXBvbmVudC5cbiAqXG4gKiBAY2xhc3MgUmVhY3RDb21wb25lbnRcbiAqL1xudmFyIFJlYWN0Q29tcG9uZW50ID0ge1xuXG4gIGluamVjdGlvbjoge1xuICAgIGluamVjdEVudmlyb25tZW50OiBmdW5jdGlvbihSZWFjdENvbXBvbmVudEVudmlyb25tZW50KSB7XG4gICAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgICAhaW5qZWN0ZWQsXG4gICAgICAgICdSZWFjdENvbXBvbmVudDogaW5qZWN0RW52aXJvbm1lbnQoKSBjYW4gb25seSBiZSBjYWxsZWQgb25jZS4nXG4gICAgICApIDogaW52YXJpYW50KCFpbmplY3RlZCkpO1xuICAgICAgbW91bnRJbWFnZUludG9Ob2RlID0gUmVhY3RDb21wb25lbnRFbnZpcm9ubWVudC5tb3VudEltYWdlSW50b05vZGU7XG4gICAgICB1bm1vdW50SURGcm9tRW52aXJvbm1lbnQgPVxuICAgICAgICBSZWFjdENvbXBvbmVudEVudmlyb25tZW50LnVubW91bnRJREZyb21FbnZpcm9ubWVudDtcbiAgICAgIFJlYWN0Q29tcG9uZW50LkJhY2tlbmRJRE9wZXJhdGlvbnMgPVxuICAgICAgICBSZWFjdENvbXBvbmVudEVudmlyb25tZW50LkJhY2tlbmRJRE9wZXJhdGlvbnM7XG4gICAgICBpbmplY3RlZCA9IHRydWU7XG4gICAgfVxuICB9LFxuXG4gIC8qKlxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIExpZmVDeWNsZTogQ29tcG9uZW50TGlmZUN5Y2xlLFxuXG4gIC8qKlxuICAgKiBJbmplY3RlZCBtb2R1bGUgdGhhdCBwcm92aWRlcyBhYmlsaXR5IHRvIG11dGF0ZSBpbmRpdmlkdWFsIHByb3BlcnRpZXMuXG4gICAqIEluamVjdGVkIGludG8gdGhlIGJhc2UgY2xhc3MgYmVjYXVzZSBtYW55IGRpZmZlcmVudCBzdWJjbGFzc2VzIG5lZWQgYWNjZXNzXG4gICAqIHRvIHRoaXMuXG4gICAqXG4gICAqIEBpbnRlcm5hbFxuICAgKi9cbiAgQmFja2VuZElET3BlcmF0aW9uczogbnVsbCxcblxuICAvKipcbiAgICogQmFzZSBmdW5jdGlvbmFsaXR5IGZvciBldmVyeSBSZWFjdENvbXBvbmVudCBjb25zdHJ1Y3Rvci4gTWl4ZWQgaW50byB0aGVcbiAgICogYFJlYWN0Q29tcG9uZW50YCBwcm90b3R5cGUsIGJ1dCBleHBvc2VkIHN0YXRpY2FsbHkgZm9yIGVhc3kgYWNjZXNzLlxuICAgKlxuICAgKiBAbGVuZHMge1JlYWN0Q29tcG9uZW50LnByb3RvdHlwZX1cbiAgICovXG4gIE1peGluOiB7XG5cbiAgICAvKipcbiAgICAgKiBDaGVja3Mgd2hldGhlciBvciBub3QgdGhpcyBjb21wb25lbnQgaXMgbW91bnRlZC5cbiAgICAgKlxuICAgICAqIEByZXR1cm4ge2Jvb2xlYW59IFRydWUgaWYgbW91bnRlZCwgZmFsc2Ugb3RoZXJ3aXNlLlxuICAgICAqIEBmaW5hbFxuICAgICAqIEBwcm90ZWN0ZWRcbiAgICAgKi9cbiAgICBpc01vdW50ZWQ6IGZ1bmN0aW9uKCkge1xuICAgICAgcmV0dXJuIHRoaXMuX2xpZmVDeWNsZVN0YXRlID09PSBDb21wb25lbnRMaWZlQ3ljbGUuTU9VTlRFRDtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogU2V0cyBhIHN1YnNldCBvZiB0aGUgcHJvcHMuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge29iamVjdH0gcGFydGlhbFByb3BzIFN1YnNldCBvZiB0aGUgbmV4dCBwcm9wcy5cbiAgICAgKiBAcGFyYW0gez9mdW5jdGlvbn0gY2FsbGJhY2sgQ2FsbGVkIGFmdGVyIHByb3BzIGFyZSB1cGRhdGVkLlxuICAgICAqIEBmaW5hbFxuICAgICAqIEBwdWJsaWNcbiAgICAgKi9cbiAgICBzZXRQcm9wczogZnVuY3Rpb24ocGFydGlhbFByb3BzLCBjYWxsYmFjaykge1xuICAgICAgLy8gTWVyZ2Ugd2l0aCB0aGUgcGVuZGluZyBlbGVtZW50IGlmIGl0IGV4aXN0cywgb3RoZXJ3aXNlIHdpdGggZXhpc3RpbmdcbiAgICAgIC8vIGVsZW1lbnQgcHJvcHMuXG4gICAgICB2YXIgZWxlbWVudCA9IHRoaXMuX3BlbmRpbmdFbGVtZW50IHx8IHRoaXMuX2N1cnJlbnRFbGVtZW50O1xuICAgICAgdGhpcy5yZXBsYWNlUHJvcHMoXG4gICAgICAgIGFzc2lnbih7fSwgZWxlbWVudC5wcm9wcywgcGFydGlhbFByb3BzKSxcbiAgICAgICAgY2FsbGJhY2tcbiAgICAgICk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFJlcGxhY2VzIGFsbCBvZiB0aGUgcHJvcHMuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge29iamVjdH0gcHJvcHMgTmV3IHByb3BzLlxuICAgICAqIEBwYXJhbSB7P2Z1bmN0aW9ufSBjYWxsYmFjayBDYWxsZWQgYWZ0ZXIgcHJvcHMgYXJlIHVwZGF0ZWQuXG4gICAgICogQGZpbmFsXG4gICAgICogQHB1YmxpY1xuICAgICAqL1xuICAgIHJlcGxhY2VQcm9wczogZnVuY3Rpb24ocHJvcHMsIGNhbGxiYWNrKSB7XG4gICAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgICB0aGlzLmlzTW91bnRlZCgpLFxuICAgICAgICAncmVwbGFjZVByb3BzKC4uLik6IENhbiBvbmx5IHVwZGF0ZSBhIG1vdW50ZWQgY29tcG9uZW50LidcbiAgICAgICkgOiBpbnZhcmlhbnQodGhpcy5pc01vdW50ZWQoKSkpO1xuICAgICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgICAgdGhpcy5fbW91bnREZXB0aCA9PT0gMCxcbiAgICAgICAgJ3JlcGxhY2VQcm9wcyguLi4pOiBZb3UgY2FsbGVkIGBzZXRQcm9wc2Agb3IgYHJlcGxhY2VQcm9wc2Agb24gYSAnICtcbiAgICAgICAgJ2NvbXBvbmVudCB3aXRoIGEgcGFyZW50LiBUaGlzIGlzIGFuIGFudGktcGF0dGVybiBzaW5jZSBwcm9wcyB3aWxsICcgK1xuICAgICAgICAnZ2V0IHJlYWN0aXZlbHkgdXBkYXRlZCB3aGVuIHJlbmRlcmVkLiBJbnN0ZWFkLCBjaGFuZ2UgdGhlIG93bmVyXFwncyAnICtcbiAgICAgICAgJ2ByZW5kZXJgIG1ldGhvZCB0byBwYXNzIHRoZSBjb3JyZWN0IHZhbHVlIGFzIHByb3BzIHRvIHRoZSBjb21wb25lbnQgJyArXG4gICAgICAgICd3aGVyZSBpdCBpcyBjcmVhdGVkLidcbiAgICAgICkgOiBpbnZhcmlhbnQodGhpcy5fbW91bnREZXB0aCA9PT0gMCkpO1xuICAgICAgLy8gVGhpcyBpcyBhIGRlb3B0aW1pemVkIHBhdGguIFdlIG9wdGltaXplIGZvciBhbHdheXMgaGF2aW5nIGEgZWxlbWVudC5cbiAgICAgIC8vIFRoaXMgY3JlYXRlcyBhbiBleHRyYSBpbnRlcm5hbCBlbGVtZW50LlxuICAgICAgdGhpcy5fcGVuZGluZ0VsZW1lbnQgPSBSZWFjdEVsZW1lbnQuY2xvbmVBbmRSZXBsYWNlUHJvcHMoXG4gICAgICAgIHRoaXMuX3BlbmRpbmdFbGVtZW50IHx8IHRoaXMuX2N1cnJlbnRFbGVtZW50LFxuICAgICAgICBwcm9wc1xuICAgICAgKTtcbiAgICAgIFJlYWN0VXBkYXRlcy5lbnF1ZXVlVXBkYXRlKHRoaXMsIGNhbGxiYWNrKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogU2NoZWR1bGUgYSBwYXJ0aWFsIHVwZGF0ZSB0byB0aGUgcHJvcHMuIE9ubHkgdXNlZCBmb3IgaW50ZXJuYWwgdGVzdGluZy5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7b2JqZWN0fSBwYXJ0aWFsUHJvcHMgU3Vic2V0IG9mIHRoZSBuZXh0IHByb3BzLlxuICAgICAqIEBwYXJhbSB7P2Z1bmN0aW9ufSBjYWxsYmFjayBDYWxsZWQgYWZ0ZXIgcHJvcHMgYXJlIHVwZGF0ZWQuXG4gICAgICogQGZpbmFsXG4gICAgICogQGludGVybmFsXG4gICAgICovXG4gICAgX3NldFByb3BzSW50ZXJuYWw6IGZ1bmN0aW9uKHBhcnRpYWxQcm9wcywgY2FsbGJhY2spIHtcbiAgICAgIC8vIFRoaXMgaXMgYSBkZW9wdGltaXplZCBwYXRoLiBXZSBvcHRpbWl6ZSBmb3IgYWx3YXlzIGhhdmluZyBhIGVsZW1lbnQuXG4gICAgICAvLyBUaGlzIGNyZWF0ZXMgYW4gZXh0cmEgaW50ZXJuYWwgZWxlbWVudC5cbiAgICAgIHZhciBlbGVtZW50ID0gdGhpcy5fcGVuZGluZ0VsZW1lbnQgfHwgdGhpcy5fY3VycmVudEVsZW1lbnQ7XG4gICAgICB0aGlzLl9wZW5kaW5nRWxlbWVudCA9IFJlYWN0RWxlbWVudC5jbG9uZUFuZFJlcGxhY2VQcm9wcyhcbiAgICAgICAgZWxlbWVudCxcbiAgICAgICAgYXNzaWduKHt9LCBlbGVtZW50LnByb3BzLCBwYXJ0aWFsUHJvcHMpXG4gICAgICApO1xuICAgICAgUmVhY3RVcGRhdGVzLmVucXVldWVVcGRhdGUodGhpcywgY2FsbGJhY2spO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBCYXNlIGNvbnN0cnVjdG9yIGZvciBhbGwgUmVhY3QgY29tcG9uZW50cy5cbiAgICAgKlxuICAgICAqIFN1YmNsYXNzZXMgdGhhdCBvdmVycmlkZSB0aGlzIG1ldGhvZCBzaG91bGQgbWFrZSBzdXJlIHRvIGludm9rZVxuICAgICAqIGBSZWFjdENvbXBvbmVudC5NaXhpbi5jb25zdHJ1Y3QuY2FsbCh0aGlzLCAuLi4pYC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7UmVhY3RFbGVtZW50fSBlbGVtZW50XG4gICAgICogQGludGVybmFsXG4gICAgICovXG4gICAgY29uc3RydWN0OiBmdW5jdGlvbihlbGVtZW50KSB7XG4gICAgICAvLyBUaGlzIGlzIHRoZSBwdWJsaWMgZXhwb3NlZCBwcm9wcyBvYmplY3QgYWZ0ZXIgaXQgaGFzIGJlZW4gcHJvY2Vzc2VkXG4gICAgICAvLyB3aXRoIGRlZmF1bHQgcHJvcHMuIFRoZSBlbGVtZW50J3MgcHJvcHMgcmVwcmVzZW50cyB0aGUgdHJ1ZSBpbnRlcm5hbFxuICAgICAgLy8gc3RhdGUgb2YgdGhlIHByb3BzLlxuICAgICAgdGhpcy5wcm9wcyA9IGVsZW1lbnQucHJvcHM7XG4gICAgICAvLyBSZWNvcmQgdGhlIGNvbXBvbmVudCByZXNwb25zaWJsZSBmb3IgY3JlYXRpbmcgdGhpcyBjb21wb25lbnQuXG4gICAgICAvLyBUaGlzIGlzIGFjY2Vzc2libGUgdGhyb3VnaCB0aGUgZWxlbWVudCBidXQgd2UgbWFpbnRhaW4gYW4gZXh0cmFcbiAgICAgIC8vIGZpZWxkIGZvciBjb21wYXRpYmlsaXR5IHdpdGggZGV2dG9vbHMgYW5kIGFzIGEgd2F5IHRvIG1ha2UgYW5cbiAgICAgIC8vIGluY3JlbWVudGFsIHVwZGF0ZS4gVE9ETzogQ29uc2lkZXIgZGVwcmVjYXRpbmcgdGhpcyBmaWVsZC5cbiAgICAgIHRoaXMuX293bmVyID0gZWxlbWVudC5fb3duZXI7XG5cbiAgICAgIC8vIEFsbCBjb21wb25lbnRzIHN0YXJ0IHVubW91bnRlZC5cbiAgICAgIHRoaXMuX2xpZmVDeWNsZVN0YXRlID0gQ29tcG9uZW50TGlmZUN5Y2xlLlVOTU9VTlRFRDtcblxuICAgICAgLy8gU2VlIFJlYWN0VXBkYXRlcy5cbiAgICAgIHRoaXMuX3BlbmRpbmdDYWxsYmFja3MgPSBudWxsO1xuXG4gICAgICAvLyBXZSBrZWVwIHRoZSBvbGQgZWxlbWVudCBhbmQgYSByZWZlcmVuY2UgdG8gdGhlIHBlbmRpbmcgZWxlbWVudFxuICAgICAgLy8gdG8gdHJhY2sgdXBkYXRlcy5cbiAgICAgIHRoaXMuX2N1cnJlbnRFbGVtZW50ID0gZWxlbWVudDtcbiAgICAgIHRoaXMuX3BlbmRpbmdFbGVtZW50ID0gbnVsbDtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogSW5pdGlhbGl6ZXMgdGhlIGNvbXBvbmVudCwgcmVuZGVycyBtYXJrdXAsIGFuZCByZWdpc3RlcnMgZXZlbnQgbGlzdGVuZXJzLlxuICAgICAqXG4gICAgICogTk9URTogVGhpcyBkb2VzIG5vdCBpbnNlcnQgYW55IG5vZGVzIGludG8gdGhlIERPTS5cbiAgICAgKlxuICAgICAqIFN1YmNsYXNzZXMgdGhhdCBvdmVycmlkZSB0aGlzIG1ldGhvZCBzaG91bGQgbWFrZSBzdXJlIHRvIGludm9rZVxuICAgICAqIGBSZWFjdENvbXBvbmVudC5NaXhpbi5tb3VudENvbXBvbmVudC5jYWxsKHRoaXMsIC4uLilgLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IHJvb3RJRCBET00gSUQgb2YgdGhlIHJvb3Qgbm9kZS5cbiAgICAgKiBAcGFyYW0ge1JlYWN0UmVjb25jaWxlVHJhbnNhY3Rpb258UmVhY3RTZXJ2ZXJSZW5kZXJpbmdUcmFuc2FjdGlvbn0gdHJhbnNhY3Rpb25cbiAgICAgKiBAcGFyYW0ge251bWJlcn0gbW91bnREZXB0aCBudW1iZXIgb2YgY29tcG9uZW50cyBpbiB0aGUgb3duZXIgaGllcmFyY2h5LlxuICAgICAqIEByZXR1cm4gez9zdHJpbmd9IFJlbmRlcmVkIG1hcmt1cCB0byBiZSBpbnNlcnRlZCBpbnRvIHRoZSBET00uXG4gICAgICogQGludGVybmFsXG4gICAgICovXG4gICAgbW91bnRDb21wb25lbnQ6IGZ1bmN0aW9uKHJvb3RJRCwgdHJhbnNhY3Rpb24sIG1vdW50RGVwdGgpIHtcbiAgICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICAgICF0aGlzLmlzTW91bnRlZCgpLFxuICAgICAgICAnbW91bnRDb21wb25lbnQoJXMsIC4uLik6IENhbiBvbmx5IG1vdW50IGFuIHVubW91bnRlZCBjb21wb25lbnQuICcgK1xuICAgICAgICAnTWFrZSBzdXJlIHRvIGF2b2lkIHN0b3JpbmcgY29tcG9uZW50cyBiZXR3ZWVuIHJlbmRlcnMgb3IgcmV1c2luZyBhICcgK1xuICAgICAgICAnc2luZ2xlIGNvbXBvbmVudCBpbnN0YW5jZSBpbiBtdWx0aXBsZSBwbGFjZXMuJyxcbiAgICAgICAgcm9vdElEXG4gICAgICApIDogaW52YXJpYW50KCF0aGlzLmlzTW91bnRlZCgpKSk7XG4gICAgICB2YXIgcmVmID0gdGhpcy5fY3VycmVudEVsZW1lbnQucmVmO1xuICAgICAgaWYgKHJlZiAhPSBudWxsKSB7XG4gICAgICAgIHZhciBvd25lciA9IHRoaXMuX2N1cnJlbnRFbGVtZW50Ll9vd25lcjtcbiAgICAgICAgUmVhY3RPd25lci5hZGRDb21wb25lbnRBc1JlZlRvKHRoaXMsIHJlZiwgb3duZXIpO1xuICAgICAgfVxuICAgICAgdGhpcy5fcm9vdE5vZGVJRCA9IHJvb3RJRDtcbiAgICAgIHRoaXMuX2xpZmVDeWNsZVN0YXRlID0gQ29tcG9uZW50TGlmZUN5Y2xlLk1PVU5URUQ7XG4gICAgICB0aGlzLl9tb3VudERlcHRoID0gbW91bnREZXB0aDtcbiAgICAgIC8vIEVmZmVjdGl2ZWx5OiByZXR1cm4gJyc7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFJlbGVhc2VzIGFueSByZXNvdXJjZXMgYWxsb2NhdGVkIGJ5IGBtb3VudENvbXBvbmVudGAuXG4gICAgICpcbiAgICAgKiBOT1RFOiBUaGlzIGRvZXMgbm90IHJlbW92ZSBhbnkgbm9kZXMgZnJvbSB0aGUgRE9NLlxuICAgICAqXG4gICAgICogU3ViY2xhc3NlcyB0aGF0IG92ZXJyaWRlIHRoaXMgbWV0aG9kIHNob3VsZCBtYWtlIHN1cmUgdG8gaW52b2tlXG4gICAgICogYFJlYWN0Q29tcG9uZW50Lk1peGluLnVubW91bnRDb21wb25lbnQuY2FsbCh0aGlzKWAuXG4gICAgICpcbiAgICAgKiBAaW50ZXJuYWxcbiAgICAgKi9cbiAgICB1bm1vdW50Q29tcG9uZW50OiBmdW5jdGlvbigpIHtcbiAgICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICAgIHRoaXMuaXNNb3VudGVkKCksXG4gICAgICAgICd1bm1vdW50Q29tcG9uZW50KCk6IENhbiBvbmx5IHVubW91bnQgYSBtb3VudGVkIGNvbXBvbmVudC4nXG4gICAgICApIDogaW52YXJpYW50KHRoaXMuaXNNb3VudGVkKCkpKTtcbiAgICAgIHZhciByZWYgPSB0aGlzLl9jdXJyZW50RWxlbWVudC5yZWY7XG4gICAgICBpZiAocmVmICE9IG51bGwpIHtcbiAgICAgICAgUmVhY3RPd25lci5yZW1vdmVDb21wb25lbnRBc1JlZkZyb20odGhpcywgcmVmLCB0aGlzLl9vd25lcik7XG4gICAgICB9XG4gICAgICB1bm1vdW50SURGcm9tRW52aXJvbm1lbnQodGhpcy5fcm9vdE5vZGVJRCk7XG4gICAgICB0aGlzLl9yb290Tm9kZUlEID0gbnVsbDtcbiAgICAgIHRoaXMuX2xpZmVDeWNsZVN0YXRlID0gQ29tcG9uZW50TGlmZUN5Y2xlLlVOTU9VTlRFRDtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogR2l2ZW4gYSBuZXcgaW5zdGFuY2Ugb2YgdGhpcyBjb21wb25lbnQsIHVwZGF0ZXMgdGhlIHJlbmRlcmVkIERPTSBub2Rlc1xuICAgICAqIGFzIGlmIHRoYXQgaW5zdGFuY2Ugd2FzIHJlbmRlcmVkIGluc3RlYWQuXG4gICAgICpcbiAgICAgKiBTdWJjbGFzc2VzIHRoYXQgb3ZlcnJpZGUgdGhpcyBtZXRob2Qgc2hvdWxkIG1ha2Ugc3VyZSB0byBpbnZva2VcbiAgICAgKiBgUmVhY3RDb21wb25lbnQuTWl4aW4ucmVjZWl2ZUNvbXBvbmVudC5jYWxsKHRoaXMsIC4uLilgLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtvYmplY3R9IG5leHRDb21wb25lbnQgTmV4dCBzZXQgb2YgcHJvcGVydGllcy5cbiAgICAgKiBAcGFyYW0ge1JlYWN0UmVjb25jaWxlVHJhbnNhY3Rpb259IHRyYW5zYWN0aW9uXG4gICAgICogQGludGVybmFsXG4gICAgICovXG4gICAgcmVjZWl2ZUNvbXBvbmVudDogZnVuY3Rpb24obmV4dEVsZW1lbnQsIHRyYW5zYWN0aW9uKSB7XG4gICAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgICB0aGlzLmlzTW91bnRlZCgpLFxuICAgICAgICAncmVjZWl2ZUNvbXBvbmVudCguLi4pOiBDYW4gb25seSB1cGRhdGUgYSBtb3VudGVkIGNvbXBvbmVudC4nXG4gICAgICApIDogaW52YXJpYW50KHRoaXMuaXNNb3VudGVkKCkpKTtcbiAgICAgIHRoaXMuX3BlbmRpbmdFbGVtZW50ID0gbmV4dEVsZW1lbnQ7XG4gICAgICB0aGlzLnBlcmZvcm1VcGRhdGVJZk5lY2Vzc2FyeSh0cmFuc2FjdGlvbik7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIElmIGBfcGVuZGluZ0VsZW1lbnRgIGlzIHNldCwgdXBkYXRlIHRoZSBjb21wb25lbnQuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge1JlYWN0UmVjb25jaWxlVHJhbnNhY3Rpb259IHRyYW5zYWN0aW9uXG4gICAgICogQGludGVybmFsXG4gICAgICovXG4gICAgcGVyZm9ybVVwZGF0ZUlmTmVjZXNzYXJ5OiBmdW5jdGlvbih0cmFuc2FjdGlvbikge1xuICAgICAgaWYgKHRoaXMuX3BlbmRpbmdFbGVtZW50ID09IG51bGwpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgdmFyIHByZXZFbGVtZW50ID0gdGhpcy5fY3VycmVudEVsZW1lbnQ7XG4gICAgICB2YXIgbmV4dEVsZW1lbnQgPSB0aGlzLl9wZW5kaW5nRWxlbWVudDtcbiAgICAgIHRoaXMuX2N1cnJlbnRFbGVtZW50ID0gbmV4dEVsZW1lbnQ7XG4gICAgICB0aGlzLnByb3BzID0gbmV4dEVsZW1lbnQucHJvcHM7XG4gICAgICB0aGlzLl9vd25lciA9IG5leHRFbGVtZW50Ll9vd25lcjtcbiAgICAgIHRoaXMuX3BlbmRpbmdFbGVtZW50ID0gbnVsbDtcbiAgICAgIHRoaXMudXBkYXRlQ29tcG9uZW50KHRyYW5zYWN0aW9uLCBwcmV2RWxlbWVudCk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFVwZGF0ZXMgdGhlIGNvbXBvbmVudCdzIGN1cnJlbnRseSBtb3VudGVkIHJlcHJlc2VudGF0aW9uLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtSZWFjdFJlY29uY2lsZVRyYW5zYWN0aW9ufSB0cmFuc2FjdGlvblxuICAgICAqIEBwYXJhbSB7b2JqZWN0fSBwcmV2RWxlbWVudFxuICAgICAqIEBpbnRlcm5hbFxuICAgICAqL1xuICAgIHVwZGF0ZUNvbXBvbmVudDogZnVuY3Rpb24odHJhbnNhY3Rpb24sIHByZXZFbGVtZW50KSB7XG4gICAgICB2YXIgbmV4dEVsZW1lbnQgPSB0aGlzLl9jdXJyZW50RWxlbWVudDtcblxuICAgICAgLy8gSWYgZWl0aGVyIHRoZSBvd25lciBvciBhIGByZWZgIGhhcyBjaGFuZ2VkLCBtYWtlIHN1cmUgdGhlIG5ld2VzdCBvd25lclxuICAgICAgLy8gaGFzIHN0b3JlZCBhIHJlZmVyZW5jZSB0byBgdGhpc2AsIGFuZCB0aGUgcHJldmlvdXMgb3duZXIgKGlmIGRpZmZlcmVudClcbiAgICAgIC8vIGhhcyBmb3Jnb3R0ZW4gdGhlIHJlZmVyZW5jZSB0byBgdGhpc2AuIFdlIHVzZSB0aGUgZWxlbWVudCBpbnN0ZWFkXG4gICAgICAvLyBvZiB0aGUgcHVibGljIHRoaXMucHJvcHMgYmVjYXVzZSB0aGUgcG9zdCBwcm9jZXNzaW5nIGNhbm5vdCBkZXRlcm1pbmVcbiAgICAgIC8vIGEgcmVmLiBUaGUgcmVmIGNvbmNlcHR1YWxseSBsaXZlcyBvbiB0aGUgZWxlbWVudC5cblxuICAgICAgLy8gVE9ETzogU2hvdWxkIHRoaXMgZXZlbiBiZSBwb3NzaWJsZT8gVGhlIG93bmVyIGNhbm5vdCBjaGFuZ2UgYmVjYXVzZVxuICAgICAgLy8gaXQncyBmb3JiaWRkZW4gYnkgc2hvdWxkVXBkYXRlUmVhY3RDb21wb25lbnQuIFRoZSByZWYgY2FuIGNoYW5nZVxuICAgICAgLy8gaWYgeW91IHN3YXAgdGhlIGtleXMgb2YgYnV0IG5vdCB0aGUgcmVmcy4gUmVjb25zaWRlciB3aGVyZSB0aGlzIGNoZWNrXG4gICAgICAvLyBpcyBtYWRlLiBJdCBwcm9iYWJseSBiZWxvbmdzIHdoZXJlIHRoZSBrZXkgY2hlY2tpbmcgYW5kXG4gICAgICAvLyBpbnN0YW50aWF0ZVJlYWN0Q29tcG9uZW50IGlzIGRvbmUuXG5cbiAgICAgIGlmIChuZXh0RWxlbWVudC5fb3duZXIgIT09IHByZXZFbGVtZW50Ll9vd25lciB8fFxuICAgICAgICAgIG5leHRFbGVtZW50LnJlZiAhPT0gcHJldkVsZW1lbnQucmVmKSB7XG4gICAgICAgIGlmIChwcmV2RWxlbWVudC5yZWYgIT0gbnVsbCkge1xuICAgICAgICAgIFJlYWN0T3duZXIucmVtb3ZlQ29tcG9uZW50QXNSZWZGcm9tKFxuICAgICAgICAgICAgdGhpcywgcHJldkVsZW1lbnQucmVmLCBwcmV2RWxlbWVudC5fb3duZXJcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICAgIC8vIENvcnJlY3QsIGV2ZW4gaWYgdGhlIG93bmVyIGlzIHRoZSBzYW1lLCBhbmQgb25seSB0aGUgcmVmIGhhcyBjaGFuZ2VkLlxuICAgICAgICBpZiAobmV4dEVsZW1lbnQucmVmICE9IG51bGwpIHtcbiAgICAgICAgICBSZWFjdE93bmVyLmFkZENvbXBvbmVudEFzUmVmVG8oXG4gICAgICAgICAgICB0aGlzLFxuICAgICAgICAgICAgbmV4dEVsZW1lbnQucmVmLFxuICAgICAgICAgICAgbmV4dEVsZW1lbnQuX293bmVyXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBNb3VudHMgdGhpcyBjb21wb25lbnQgYW5kIGluc2VydHMgaXQgaW50byB0aGUgRE9NLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IHJvb3RJRCBET00gSUQgb2YgdGhlIHJvb3Qgbm9kZS5cbiAgICAgKiBAcGFyYW0ge0RPTUVsZW1lbnR9IGNvbnRhaW5lciBET00gZWxlbWVudCB0byBtb3VudCBpbnRvLlxuICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gc2hvdWxkUmV1c2VNYXJrdXAgSWYgdHJ1ZSwgZG8gbm90IGluc2VydCBtYXJrdXBcbiAgICAgKiBAZmluYWxcbiAgICAgKiBAaW50ZXJuYWxcbiAgICAgKiBAc2VlIHtSZWFjdE1vdW50LnJlbmRlcn1cbiAgICAgKi9cbiAgICBtb3VudENvbXBvbmVudEludG9Ob2RlOiBmdW5jdGlvbihyb290SUQsIGNvbnRhaW5lciwgc2hvdWxkUmV1c2VNYXJrdXApIHtcbiAgICAgIHZhciB0cmFuc2FjdGlvbiA9IFJlYWN0VXBkYXRlcy5SZWFjdFJlY29uY2lsZVRyYW5zYWN0aW9uLmdldFBvb2xlZCgpO1xuICAgICAgdHJhbnNhY3Rpb24ucGVyZm9ybShcbiAgICAgICAgdGhpcy5fbW91bnRDb21wb25lbnRJbnRvTm9kZSxcbiAgICAgICAgdGhpcyxcbiAgICAgICAgcm9vdElELFxuICAgICAgICBjb250YWluZXIsXG4gICAgICAgIHRyYW5zYWN0aW9uLFxuICAgICAgICBzaG91bGRSZXVzZU1hcmt1cFxuICAgICAgKTtcbiAgICAgIFJlYWN0VXBkYXRlcy5SZWFjdFJlY29uY2lsZVRyYW5zYWN0aW9uLnJlbGVhc2UodHJhbnNhY3Rpb24pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gcm9vdElEIERPTSBJRCBvZiB0aGUgcm9vdCBub2RlLlxuICAgICAqIEBwYXJhbSB7RE9NRWxlbWVudH0gY29udGFpbmVyIERPTSBlbGVtZW50IHRvIG1vdW50IGludG8uXG4gICAgICogQHBhcmFtIHtSZWFjdFJlY29uY2lsZVRyYW5zYWN0aW9ufSB0cmFuc2FjdGlvblxuICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gc2hvdWxkUmV1c2VNYXJrdXAgSWYgdHJ1ZSwgZG8gbm90IGluc2VydCBtYXJrdXBcbiAgICAgKiBAZmluYWxcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIF9tb3VudENvbXBvbmVudEludG9Ob2RlOiBmdW5jdGlvbihcbiAgICAgICAgcm9vdElELFxuICAgICAgICBjb250YWluZXIsXG4gICAgICAgIHRyYW5zYWN0aW9uLFxuICAgICAgICBzaG91bGRSZXVzZU1hcmt1cCkge1xuICAgICAgdmFyIG1hcmt1cCA9IHRoaXMubW91bnRDb21wb25lbnQocm9vdElELCB0cmFuc2FjdGlvbiwgMCk7XG4gICAgICBtb3VudEltYWdlSW50b05vZGUobWFya3VwLCBjb250YWluZXIsIHNob3VsZFJldXNlTWFya3VwKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQ2hlY2tzIGlmIHRoaXMgY29tcG9uZW50IGlzIG93bmVkIGJ5IHRoZSBzdXBwbGllZCBgb3duZXJgIGNvbXBvbmVudC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7UmVhY3RDb21wb25lbnR9IG93bmVyIENvbXBvbmVudCB0byBjaGVjay5cbiAgICAgKiBAcmV0dXJuIHtib29sZWFufSBUcnVlIGlmIGBvd25lcnNgIG93bnMgdGhpcyBjb21wb25lbnQuXG4gICAgICogQGZpbmFsXG4gICAgICogQGludGVybmFsXG4gICAgICovXG4gICAgaXNPd25lZEJ5OiBmdW5jdGlvbihvd25lcikge1xuICAgICAgcmV0dXJuIHRoaXMuX293bmVyID09PSBvd25lcjtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogR2V0cyBhbm90aGVyIGNvbXBvbmVudCwgdGhhdCBzaGFyZXMgdGhlIHNhbWUgb3duZXIgYXMgdGhpcyBvbmUsIGJ5IHJlZi5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSByZWYgb2YgYSBzaWJsaW5nIENvbXBvbmVudC5cbiAgICAgKiBAcmV0dXJuIHs/UmVhY3RDb21wb25lbnR9IHRoZSBhY3R1YWwgc2libGluZyBDb21wb25lbnQuXG4gICAgICogQGZpbmFsXG4gICAgICogQGludGVybmFsXG4gICAgICovXG4gICAgZ2V0U2libGluZ0J5UmVmOiBmdW5jdGlvbihyZWYpIHtcbiAgICAgIHZhciBvd25lciA9IHRoaXMuX293bmVyO1xuICAgICAgaWYgKCFvd25lciB8fCAhb3duZXIucmVmcykge1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgIH1cbiAgICAgIHJldHVybiBvd25lci5yZWZzW3JlZl07XG4gICAgfVxuICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJlYWN0Q29tcG9uZW50O1xuXG59KS5jYWxsKHRoaXMscmVxdWlyZSgnX3Byb2Nlc3MnKSkiLCIoZnVuY3Rpb24gKHByb2Nlc3Mpe1xuLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIFJlYWN0Q29tcG9uZW50QnJvd3NlckVudmlyb25tZW50XG4gKi9cblxuLypqc2xpbnQgZXZpbDogdHJ1ZSAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIFJlYWN0RE9NSURPcGVyYXRpb25zID0gcmVxdWlyZShcIi4vUmVhY3RET01JRE9wZXJhdGlvbnNcIik7XG52YXIgUmVhY3RNYXJrdXBDaGVja3N1bSA9IHJlcXVpcmUoXCIuL1JlYWN0TWFya3VwQ2hlY2tzdW1cIik7XG52YXIgUmVhY3RNb3VudCA9IHJlcXVpcmUoXCIuL1JlYWN0TW91bnRcIik7XG52YXIgUmVhY3RQZXJmID0gcmVxdWlyZShcIi4vUmVhY3RQZXJmXCIpO1xudmFyIFJlYWN0UmVjb25jaWxlVHJhbnNhY3Rpb24gPSByZXF1aXJlKFwiLi9SZWFjdFJlY29uY2lsZVRyYW5zYWN0aW9uXCIpO1xuXG52YXIgZ2V0UmVhY3RSb290RWxlbWVudEluQ29udGFpbmVyID0gcmVxdWlyZShcIi4vZ2V0UmVhY3RSb290RWxlbWVudEluQ29udGFpbmVyXCIpO1xudmFyIGludmFyaWFudCA9IHJlcXVpcmUoXCIuL2ludmFyaWFudFwiKTtcbnZhciBzZXRJbm5lckhUTUwgPSByZXF1aXJlKFwiLi9zZXRJbm5lckhUTUxcIik7XG5cblxudmFyIEVMRU1FTlRfTk9ERV9UWVBFID0gMTtcbnZhciBET0NfTk9ERV9UWVBFID0gOTtcblxuXG4vKipcbiAqIEFic3RyYWN0cyBhd2F5IGFsbCBmdW5jdGlvbmFsaXR5IG9mIGBSZWFjdENvbXBvbmVudGAgcmVxdWlyZXMga25vd2xlZGdlIG9mXG4gKiB0aGUgYnJvd3NlciBjb250ZXh0LlxuICovXG52YXIgUmVhY3RDb21wb25lbnRCcm93c2VyRW52aXJvbm1lbnQgPSB7XG4gIFJlYWN0UmVjb25jaWxlVHJhbnNhY3Rpb246IFJlYWN0UmVjb25jaWxlVHJhbnNhY3Rpb24sXG5cbiAgQmFja2VuZElET3BlcmF0aW9uczogUmVhY3RET01JRE9wZXJhdGlvbnMsXG5cbiAgLyoqXG4gICAqIElmIGEgcGFydGljdWxhciBlbnZpcm9ubWVudCByZXF1aXJlcyB0aGF0IHNvbWUgcmVzb3VyY2VzIGJlIGNsZWFuZWQgdXAsXG4gICAqIHNwZWNpZnkgdGhpcyBpbiB0aGUgaW5qZWN0ZWQgTWl4aW4uIEluIHRoZSBET00sIHdlIHdvdWxkIGxpa2VseSB3YW50IHRvXG4gICAqIHB1cmdlIGFueSBjYWNoZWQgbm9kZSBJRCBsb29rdXBzLlxuICAgKlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgdW5tb3VudElERnJvbUVudmlyb25tZW50OiBmdW5jdGlvbihyb290Tm9kZUlEKSB7XG4gICAgUmVhY3RNb3VudC5wdXJnZUlEKHJvb3ROb2RlSUQpO1xuICB9LFxuXG4gIC8qKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gbWFya3VwIE1hcmt1cCBzdHJpbmcgdG8gcGxhY2UgaW50byB0aGUgRE9NIEVsZW1lbnQuXG4gICAqIEBwYXJhbSB7RE9NRWxlbWVudH0gY29udGFpbmVyIERPTSBFbGVtZW50IHRvIGluc2VydCBtYXJrdXAgaW50by5cbiAgICogQHBhcmFtIHtib29sZWFufSBzaG91bGRSZXVzZU1hcmt1cCBTaG91bGQgcmV1c2UgdGhlIGV4aXN0aW5nIG1hcmt1cCBpbiB0aGVcbiAgICogY29udGFpbmVyIGlmIHBvc3NpYmxlLlxuICAgKi9cbiAgbW91bnRJbWFnZUludG9Ob2RlOiBSZWFjdFBlcmYubWVhc3VyZShcbiAgICAnUmVhY3RDb21wb25lbnRCcm93c2VyRW52aXJvbm1lbnQnLFxuICAgICdtb3VudEltYWdlSW50b05vZGUnLFxuICAgIGZ1bmN0aW9uKG1hcmt1cCwgY29udGFpbmVyLCBzaG91bGRSZXVzZU1hcmt1cCkge1xuICAgICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgICAgY29udGFpbmVyICYmIChcbiAgICAgICAgICBjb250YWluZXIubm9kZVR5cGUgPT09IEVMRU1FTlRfTk9ERV9UWVBFIHx8XG4gICAgICAgICAgICBjb250YWluZXIubm9kZVR5cGUgPT09IERPQ19OT0RFX1RZUEVcbiAgICAgICAgKSxcbiAgICAgICAgJ21vdW50Q29tcG9uZW50SW50b05vZGUoLi4uKTogVGFyZ2V0IGNvbnRhaW5lciBpcyBub3QgdmFsaWQuJ1xuICAgICAgKSA6IGludmFyaWFudChjb250YWluZXIgJiYgKFxuICAgICAgICBjb250YWluZXIubm9kZVR5cGUgPT09IEVMRU1FTlRfTk9ERV9UWVBFIHx8XG4gICAgICAgICAgY29udGFpbmVyLm5vZGVUeXBlID09PSBET0NfTk9ERV9UWVBFXG4gICAgICApKSk7XG5cbiAgICAgIGlmIChzaG91bGRSZXVzZU1hcmt1cCkge1xuICAgICAgICBpZiAoUmVhY3RNYXJrdXBDaGVja3N1bS5jYW5SZXVzZU1hcmt1cChcbiAgICAgICAgICBtYXJrdXAsXG4gICAgICAgICAgZ2V0UmVhY3RSb290RWxlbWVudEluQ29udGFpbmVyKGNvbnRhaW5lcikpKSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICAgICAgICBjb250YWluZXIubm9kZVR5cGUgIT09IERPQ19OT0RFX1RZUEUsXG4gICAgICAgICAgICAnWW91XFwncmUgdHJ5aW5nIHRvIHJlbmRlciBhIGNvbXBvbmVudCB0byB0aGUgZG9jdW1lbnQgdXNpbmcgJyArXG4gICAgICAgICAgICAnc2VydmVyIHJlbmRlcmluZyBidXQgdGhlIGNoZWNrc3VtIHdhcyBpbnZhbGlkLiBUaGlzIHVzdWFsbHkgJyArXG4gICAgICAgICAgICAnbWVhbnMgeW91IHJlbmRlcmVkIGEgZGlmZmVyZW50IGNvbXBvbmVudCB0eXBlIG9yIHByb3BzIG9uICcgK1xuICAgICAgICAgICAgJ3RoZSBjbGllbnQgZnJvbSB0aGUgb25lIG9uIHRoZSBzZXJ2ZXIsIG9yIHlvdXIgcmVuZGVyKCkgJyArXG4gICAgICAgICAgICAnbWV0aG9kcyBhcmUgaW1wdXJlLiBSZWFjdCBjYW5ub3QgaGFuZGxlIHRoaXMgY2FzZSBkdWUgdG8gJyArXG4gICAgICAgICAgICAnY3Jvc3MtYnJvd3NlciBxdWlya3MgYnkgcmVuZGVyaW5nIGF0IHRoZSBkb2N1bWVudCByb290LiBZb3UgJyArXG4gICAgICAgICAgICAnc2hvdWxkIGxvb2sgZm9yIGVudmlyb25tZW50IGRlcGVuZGVudCBjb2RlIGluIHlvdXIgY29tcG9uZW50cyAnICtcbiAgICAgICAgICAgICdhbmQgZW5zdXJlIHRoZSBwcm9wcyBhcmUgdGhlIHNhbWUgY2xpZW50IGFuZCBzZXJ2ZXIgc2lkZS4nXG4gICAgICAgICAgKSA6IGludmFyaWFudChjb250YWluZXIubm9kZVR5cGUgIT09IERPQ19OT0RFX1RZUEUpKTtcblxuICAgICAgICAgIGlmIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYpIHtcbiAgICAgICAgICAgIGNvbnNvbGUud2FybihcbiAgICAgICAgICAgICAgJ1JlYWN0IGF0dGVtcHRlZCB0byB1c2UgcmV1c2UgbWFya3VwIGluIGEgY29udGFpbmVyIGJ1dCB0aGUgJyArXG4gICAgICAgICAgICAgICdjaGVja3N1bSB3YXMgaW52YWxpZC4gVGhpcyBnZW5lcmFsbHkgbWVhbnMgdGhhdCB5b3UgYXJlICcgK1xuICAgICAgICAgICAgICAndXNpbmcgc2VydmVyIHJlbmRlcmluZyBhbmQgdGhlIG1hcmt1cCBnZW5lcmF0ZWQgb24gdGhlICcgK1xuICAgICAgICAgICAgICAnc2VydmVyIHdhcyBub3Qgd2hhdCB0aGUgY2xpZW50IHdhcyBleHBlY3RpbmcuIFJlYWN0IGluamVjdGVkICcgK1xuICAgICAgICAgICAgICAnbmV3IG1hcmt1cCB0byBjb21wZW5zYXRlIHdoaWNoIHdvcmtzIGJ1dCB5b3UgaGF2ZSBsb3N0IG1hbnkgJyArXG4gICAgICAgICAgICAgICdvZiB0aGUgYmVuZWZpdHMgb2Ygc2VydmVyIHJlbmRlcmluZy4gSW5zdGVhZCwgZmlndXJlIG91dCAnICtcbiAgICAgICAgICAgICAgJ3doeSB0aGUgbWFya3VwIGJlaW5nIGdlbmVyYXRlZCBpcyBkaWZmZXJlbnQgb24gdGhlIGNsaWVudCAnICtcbiAgICAgICAgICAgICAgJ29yIHNlcnZlci4nXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgICBjb250YWluZXIubm9kZVR5cGUgIT09IERPQ19OT0RFX1RZUEUsXG4gICAgICAgICdZb3VcXCdyZSB0cnlpbmcgdG8gcmVuZGVyIGEgY29tcG9uZW50IHRvIHRoZSBkb2N1bWVudCBidXQgJyArXG4gICAgICAgICAgJ3lvdSBkaWRuXFwndCB1c2Ugc2VydmVyIHJlbmRlcmluZy4gV2UgY2FuXFwndCBkbyB0aGlzICcgK1xuICAgICAgICAgICd3aXRob3V0IHVzaW5nIHNlcnZlciByZW5kZXJpbmcgZHVlIHRvIGNyb3NzLWJyb3dzZXIgcXVpcmtzLiAnICtcbiAgICAgICAgICAnU2VlIHJlbmRlckNvbXBvbmVudFRvU3RyaW5nKCkgZm9yIHNlcnZlciByZW5kZXJpbmcuJ1xuICAgICAgKSA6IGludmFyaWFudChjb250YWluZXIubm9kZVR5cGUgIT09IERPQ19OT0RFX1RZUEUpKTtcblxuICAgICAgc2V0SW5uZXJIVE1MKGNvbnRhaW5lciwgbWFya3VwKTtcbiAgICB9XG4gIClcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gUmVhY3RDb21wb25lbnRCcm93c2VyRW52aXJvbm1lbnQ7XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKCdfcHJvY2VzcycpKSIsIihmdW5jdGlvbiAocHJvY2Vzcyl7XG4vKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgUmVhY3RDb21wb3NpdGVDb21wb25lbnRcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIFJlYWN0Q29tcG9uZW50ID0gcmVxdWlyZShcIi4vUmVhY3RDb21wb25lbnRcIik7XG52YXIgUmVhY3RDb250ZXh0ID0gcmVxdWlyZShcIi4vUmVhY3RDb250ZXh0XCIpO1xudmFyIFJlYWN0Q3VycmVudE93bmVyID0gcmVxdWlyZShcIi4vUmVhY3RDdXJyZW50T3duZXJcIik7XG52YXIgUmVhY3RFbGVtZW50ID0gcmVxdWlyZShcIi4vUmVhY3RFbGVtZW50XCIpO1xudmFyIFJlYWN0RWxlbWVudFZhbGlkYXRvciA9IHJlcXVpcmUoXCIuL1JlYWN0RWxlbWVudFZhbGlkYXRvclwiKTtcbnZhciBSZWFjdEVtcHR5Q29tcG9uZW50ID0gcmVxdWlyZShcIi4vUmVhY3RFbXB0eUNvbXBvbmVudFwiKTtcbnZhciBSZWFjdEVycm9yVXRpbHMgPSByZXF1aXJlKFwiLi9SZWFjdEVycm9yVXRpbHNcIik7XG52YXIgUmVhY3RMZWdhY3lFbGVtZW50ID0gcmVxdWlyZShcIi4vUmVhY3RMZWdhY3lFbGVtZW50XCIpO1xudmFyIFJlYWN0T3duZXIgPSByZXF1aXJlKFwiLi9SZWFjdE93bmVyXCIpO1xudmFyIFJlYWN0UGVyZiA9IHJlcXVpcmUoXCIuL1JlYWN0UGVyZlwiKTtcbnZhciBSZWFjdFByb3BUcmFuc2ZlcmVyID0gcmVxdWlyZShcIi4vUmVhY3RQcm9wVHJhbnNmZXJlclwiKTtcbnZhciBSZWFjdFByb3BUeXBlTG9jYXRpb25zID0gcmVxdWlyZShcIi4vUmVhY3RQcm9wVHlwZUxvY2F0aW9uc1wiKTtcbnZhciBSZWFjdFByb3BUeXBlTG9jYXRpb25OYW1lcyA9IHJlcXVpcmUoXCIuL1JlYWN0UHJvcFR5cGVMb2NhdGlvbk5hbWVzXCIpO1xudmFyIFJlYWN0VXBkYXRlcyA9IHJlcXVpcmUoXCIuL1JlYWN0VXBkYXRlc1wiKTtcblxudmFyIGFzc2lnbiA9IHJlcXVpcmUoXCIuL09iamVjdC5hc3NpZ25cIik7XG52YXIgaW5zdGFudGlhdGVSZWFjdENvbXBvbmVudCA9IHJlcXVpcmUoXCIuL2luc3RhbnRpYXRlUmVhY3RDb21wb25lbnRcIik7XG52YXIgaW52YXJpYW50ID0gcmVxdWlyZShcIi4vaW52YXJpYW50XCIpO1xudmFyIGtleU1pcnJvciA9IHJlcXVpcmUoXCIuL2tleU1pcnJvclwiKTtcbnZhciBrZXlPZiA9IHJlcXVpcmUoXCIuL2tleU9mXCIpO1xudmFyIG1vbml0b3JDb2RlVXNlID0gcmVxdWlyZShcIi4vbW9uaXRvckNvZGVVc2VcIik7XG52YXIgbWFwT2JqZWN0ID0gcmVxdWlyZShcIi4vbWFwT2JqZWN0XCIpO1xudmFyIHNob3VsZFVwZGF0ZVJlYWN0Q29tcG9uZW50ID0gcmVxdWlyZShcIi4vc2hvdWxkVXBkYXRlUmVhY3RDb21wb25lbnRcIik7XG52YXIgd2FybmluZyA9IHJlcXVpcmUoXCIuL3dhcm5pbmdcIik7XG5cbnZhciBNSVhJTlNfS0VZID0ga2V5T2Yoe21peGluczogbnVsbH0pO1xuXG4vKipcbiAqIFBvbGljaWVzIHRoYXQgZGVzY3JpYmUgbWV0aG9kcyBpbiBgUmVhY3RDb21wb3NpdGVDb21wb25lbnRJbnRlcmZhY2VgLlxuICovXG52YXIgU3BlY1BvbGljeSA9IGtleU1pcnJvcih7XG4gIC8qKlxuICAgKiBUaGVzZSBtZXRob2RzIG1heSBiZSBkZWZpbmVkIG9ubHkgb25jZSBieSB0aGUgY2xhc3Mgc3BlY2lmaWNhdGlvbiBvciBtaXhpbi5cbiAgICovXG4gIERFRklORV9PTkNFOiBudWxsLFxuICAvKipcbiAgICogVGhlc2UgbWV0aG9kcyBtYXkgYmUgZGVmaW5lZCBieSBib3RoIHRoZSBjbGFzcyBzcGVjaWZpY2F0aW9uIGFuZCBtaXhpbnMuXG4gICAqIFN1YnNlcXVlbnQgZGVmaW5pdGlvbnMgd2lsbCBiZSBjaGFpbmVkLiBUaGVzZSBtZXRob2RzIG11c3QgcmV0dXJuIHZvaWQuXG4gICAqL1xuICBERUZJTkVfTUFOWTogbnVsbCxcbiAgLyoqXG4gICAqIFRoZXNlIG1ldGhvZHMgYXJlIG92ZXJyaWRpbmcgdGhlIGJhc2UgUmVhY3RDb21wb3NpdGVDb21wb25lbnQgY2xhc3MuXG4gICAqL1xuICBPVkVSUklERV9CQVNFOiBudWxsLFxuICAvKipcbiAgICogVGhlc2UgbWV0aG9kcyBhcmUgc2ltaWxhciB0byBERUZJTkVfTUFOWSwgZXhjZXB0IHdlIGFzc3VtZSB0aGV5IHJldHVyblxuICAgKiBvYmplY3RzLiBXZSB0cnkgdG8gbWVyZ2UgdGhlIGtleXMgb2YgdGhlIHJldHVybiB2YWx1ZXMgb2YgYWxsIHRoZSBtaXhlZCBpblxuICAgKiBmdW5jdGlvbnMuIElmIHRoZXJlIGlzIGEga2V5IGNvbmZsaWN0IHdlIHRocm93LlxuICAgKi9cbiAgREVGSU5FX01BTllfTUVSR0VEOiBudWxsXG59KTtcblxuXG52YXIgaW5qZWN0ZWRNaXhpbnMgPSBbXTtcblxuLyoqXG4gKiBDb21wb3NpdGUgY29tcG9uZW50cyBhcmUgaGlnaGVyLWxldmVsIGNvbXBvbmVudHMgdGhhdCBjb21wb3NlIG90aGVyIGNvbXBvc2l0ZVxuICogb3IgbmF0aXZlIGNvbXBvbmVudHMuXG4gKlxuICogVG8gY3JlYXRlIGEgbmV3IHR5cGUgb2YgYFJlYWN0Q29tcG9zaXRlQ29tcG9uZW50YCwgcGFzcyBhIHNwZWNpZmljYXRpb24gb2ZcbiAqIHlvdXIgbmV3IGNsYXNzIHRvIGBSZWFjdC5jcmVhdGVDbGFzc2AuIFRoZSBvbmx5IHJlcXVpcmVtZW50IG9mIHlvdXIgY2xhc3NcbiAqIHNwZWNpZmljYXRpb24gaXMgdGhhdCB5b3UgaW1wbGVtZW50IGEgYHJlbmRlcmAgbWV0aG9kLlxuICpcbiAqICAgdmFyIE15Q29tcG9uZW50ID0gUmVhY3QuY3JlYXRlQ2xhc3Moe1xuICogICAgIHJlbmRlcjogZnVuY3Rpb24oKSB7XG4gKiAgICAgICByZXR1cm4gPGRpdj5IZWxsbyBXb3JsZDwvZGl2PjtcbiAqICAgICB9XG4gKiAgIH0pO1xuICpcbiAqIFRoZSBjbGFzcyBzcGVjaWZpY2F0aW9uIHN1cHBvcnRzIGEgc3BlY2lmaWMgcHJvdG9jb2wgb2YgbWV0aG9kcyB0aGF0IGhhdmVcbiAqIHNwZWNpYWwgbWVhbmluZyAoZS5nLiBgcmVuZGVyYCkuIFNlZSBgUmVhY3RDb21wb3NpdGVDb21wb25lbnRJbnRlcmZhY2VgIGZvclxuICogbW9yZSB0aGUgY29tcHJlaGVuc2l2ZSBwcm90b2NvbC4gQW55IG90aGVyIHByb3BlcnRpZXMgYW5kIG1ldGhvZHMgaW4gdGhlXG4gKiBjbGFzcyBzcGVjaWZpY2F0aW9uIHdpbGwgYXZhaWxhYmxlIG9uIHRoZSBwcm90b3R5cGUuXG4gKlxuICogQGludGVyZmFjZSBSZWFjdENvbXBvc2l0ZUNvbXBvbmVudEludGVyZmFjZVxuICogQGludGVybmFsXG4gKi9cbnZhciBSZWFjdENvbXBvc2l0ZUNvbXBvbmVudEludGVyZmFjZSA9IHtcblxuICAvKipcbiAgICogQW4gYXJyYXkgb2YgTWl4aW4gb2JqZWN0cyB0byBpbmNsdWRlIHdoZW4gZGVmaW5pbmcgeW91ciBjb21wb25lbnQuXG4gICAqXG4gICAqIEB0eXBlIHthcnJheX1cbiAgICogQG9wdGlvbmFsXG4gICAqL1xuICBtaXhpbnM6IFNwZWNQb2xpY3kuREVGSU5FX01BTlksXG5cbiAgLyoqXG4gICAqIEFuIG9iamVjdCBjb250YWluaW5nIHByb3BlcnRpZXMgYW5kIG1ldGhvZHMgdGhhdCBzaG91bGQgYmUgZGVmaW5lZCBvblxuICAgKiB0aGUgY29tcG9uZW50J3MgY29uc3RydWN0b3IgaW5zdGVhZCBvZiBpdHMgcHJvdG90eXBlIChzdGF0aWMgbWV0aG9kcykuXG4gICAqXG4gICAqIEB0eXBlIHtvYmplY3R9XG4gICAqIEBvcHRpb25hbFxuICAgKi9cbiAgc3RhdGljczogU3BlY1BvbGljeS5ERUZJTkVfTUFOWSxcblxuICAvKipcbiAgICogRGVmaW5pdGlvbiBvZiBwcm9wIHR5cGVzIGZvciB0aGlzIGNvbXBvbmVudC5cbiAgICpcbiAgICogQHR5cGUge29iamVjdH1cbiAgICogQG9wdGlvbmFsXG4gICAqL1xuICBwcm9wVHlwZXM6IFNwZWNQb2xpY3kuREVGSU5FX01BTlksXG5cbiAgLyoqXG4gICAqIERlZmluaXRpb24gb2YgY29udGV4dCB0eXBlcyBmb3IgdGhpcyBjb21wb25lbnQuXG4gICAqXG4gICAqIEB0eXBlIHtvYmplY3R9XG4gICAqIEBvcHRpb25hbFxuICAgKi9cbiAgY29udGV4dFR5cGVzOiBTcGVjUG9saWN5LkRFRklORV9NQU5ZLFxuXG4gIC8qKlxuICAgKiBEZWZpbml0aW9uIG9mIGNvbnRleHQgdHlwZXMgdGhpcyBjb21wb25lbnQgc2V0cyBmb3IgaXRzIGNoaWxkcmVuLlxuICAgKlxuICAgKiBAdHlwZSB7b2JqZWN0fVxuICAgKiBAb3B0aW9uYWxcbiAgICovXG4gIGNoaWxkQ29udGV4dFR5cGVzOiBTcGVjUG9saWN5LkRFRklORV9NQU5ZLFxuXG4gIC8vID09PT0gRGVmaW5pdGlvbiBtZXRob2RzID09PT1cblxuICAvKipcbiAgICogSW52b2tlZCB3aGVuIHRoZSBjb21wb25lbnQgaXMgbW91bnRlZC4gVmFsdWVzIGluIHRoZSBtYXBwaW5nIHdpbGwgYmUgc2V0IG9uXG4gICAqIGB0aGlzLnByb3BzYCBpZiB0aGF0IHByb3AgaXMgbm90IHNwZWNpZmllZCAoaS5lLiB1c2luZyBhbiBgaW5gIGNoZWNrKS5cbiAgICpcbiAgICogVGhpcyBtZXRob2QgaXMgaW52b2tlZCBiZWZvcmUgYGdldEluaXRpYWxTdGF0ZWAgYW5kIHRoZXJlZm9yZSBjYW5ub3QgcmVseVxuICAgKiBvbiBgdGhpcy5zdGF0ZWAgb3IgdXNlIGB0aGlzLnNldFN0YXRlYC5cbiAgICpcbiAgICogQHJldHVybiB7b2JqZWN0fVxuICAgKiBAb3B0aW9uYWxcbiAgICovXG4gIGdldERlZmF1bHRQcm9wczogU3BlY1BvbGljeS5ERUZJTkVfTUFOWV9NRVJHRUQsXG5cbiAgLyoqXG4gICAqIEludm9rZWQgb25jZSBiZWZvcmUgdGhlIGNvbXBvbmVudCBpcyBtb3VudGVkLiBUaGUgcmV0dXJuIHZhbHVlIHdpbGwgYmUgdXNlZFxuICAgKiBhcyB0aGUgaW5pdGlhbCB2YWx1ZSBvZiBgdGhpcy5zdGF0ZWAuXG4gICAqXG4gICAqICAgZ2V0SW5pdGlhbFN0YXRlOiBmdW5jdGlvbigpIHtcbiAgICogICAgIHJldHVybiB7XG4gICAqICAgICAgIGlzT246IGZhbHNlLFxuICAgKiAgICAgICBmb29CYXo6IG5ldyBCYXpGb28oKVxuICAgKiAgICAgfVxuICAgKiAgIH1cbiAgICpcbiAgICogQHJldHVybiB7b2JqZWN0fVxuICAgKiBAb3B0aW9uYWxcbiAgICovXG4gIGdldEluaXRpYWxTdGF0ZTogU3BlY1BvbGljeS5ERUZJTkVfTUFOWV9NRVJHRUQsXG5cbiAgLyoqXG4gICAqIEByZXR1cm4ge29iamVjdH1cbiAgICogQG9wdGlvbmFsXG4gICAqL1xuICBnZXRDaGlsZENvbnRleHQ6IFNwZWNQb2xpY3kuREVGSU5FX01BTllfTUVSR0VELFxuXG4gIC8qKlxuICAgKiBVc2VzIHByb3BzIGZyb20gYHRoaXMucHJvcHNgIGFuZCBzdGF0ZSBmcm9tIGB0aGlzLnN0YXRlYCB0byByZW5kZXIgdGhlXG4gICAqIHN0cnVjdHVyZSBvZiB0aGUgY29tcG9uZW50LlxuICAgKlxuICAgKiBObyBndWFyYW50ZWVzIGFyZSBtYWRlIGFib3V0IHdoZW4gb3IgaG93IG9mdGVuIHRoaXMgbWV0aG9kIGlzIGludm9rZWQsIHNvXG4gICAqIGl0IG11c3Qgbm90IGhhdmUgc2lkZSBlZmZlY3RzLlxuICAgKlxuICAgKiAgIHJlbmRlcjogZnVuY3Rpb24oKSB7XG4gICAqICAgICB2YXIgbmFtZSA9IHRoaXMucHJvcHMubmFtZTtcbiAgICogICAgIHJldHVybiA8ZGl2PkhlbGxvLCB7bmFtZX0hPC9kaXY+O1xuICAgKiAgIH1cbiAgICpcbiAgICogQHJldHVybiB7UmVhY3RDb21wb25lbnR9XG4gICAqIEBub3NpZGVlZmZlY3RzXG4gICAqIEByZXF1aXJlZFxuICAgKi9cbiAgcmVuZGVyOiBTcGVjUG9saWN5LkRFRklORV9PTkNFLFxuXG5cblxuICAvLyA9PT09IERlbGVnYXRlIG1ldGhvZHMgPT09PVxuXG4gIC8qKlxuICAgKiBJbnZva2VkIHdoZW4gdGhlIGNvbXBvbmVudCBpcyBpbml0aWFsbHkgY3JlYXRlZCBhbmQgYWJvdXQgdG8gYmUgbW91bnRlZC5cbiAgICogVGhpcyBtYXkgaGF2ZSBzaWRlIGVmZmVjdHMsIGJ1dCBhbnkgZXh0ZXJuYWwgc3Vic2NyaXB0aW9ucyBvciBkYXRhIGNyZWF0ZWRcbiAgICogYnkgdGhpcyBtZXRob2QgbXVzdCBiZSBjbGVhbmVkIHVwIGluIGBjb21wb25lbnRXaWxsVW5tb3VudGAuXG4gICAqXG4gICAqIEBvcHRpb25hbFxuICAgKi9cbiAgY29tcG9uZW50V2lsbE1vdW50OiBTcGVjUG9saWN5LkRFRklORV9NQU5ZLFxuXG4gIC8qKlxuICAgKiBJbnZva2VkIHdoZW4gdGhlIGNvbXBvbmVudCBoYXMgYmVlbiBtb3VudGVkIGFuZCBoYXMgYSBET00gcmVwcmVzZW50YXRpb24uXG4gICAqIEhvd2V2ZXIsIHRoZXJlIGlzIG5vIGd1YXJhbnRlZSB0aGF0IHRoZSBET00gbm9kZSBpcyBpbiB0aGUgZG9jdW1lbnQuXG4gICAqXG4gICAqIFVzZSB0aGlzIGFzIGFuIG9wcG9ydHVuaXR5IHRvIG9wZXJhdGUgb24gdGhlIERPTSB3aGVuIHRoZSBjb21wb25lbnQgaGFzXG4gICAqIGJlZW4gbW91bnRlZCAoaW5pdGlhbGl6ZWQgYW5kIHJlbmRlcmVkKSBmb3IgdGhlIGZpcnN0IHRpbWUuXG4gICAqXG4gICAqIEBwYXJhbSB7RE9NRWxlbWVudH0gcm9vdE5vZGUgRE9NIGVsZW1lbnQgcmVwcmVzZW50aW5nIHRoZSBjb21wb25lbnQuXG4gICAqIEBvcHRpb25hbFxuICAgKi9cbiAgY29tcG9uZW50RGlkTW91bnQ6IFNwZWNQb2xpY3kuREVGSU5FX01BTlksXG5cbiAgLyoqXG4gICAqIEludm9rZWQgYmVmb3JlIHRoZSBjb21wb25lbnQgcmVjZWl2ZXMgbmV3IHByb3BzLlxuICAgKlxuICAgKiBVc2UgdGhpcyBhcyBhbiBvcHBvcnR1bml0eSB0byByZWFjdCB0byBhIHByb3AgdHJhbnNpdGlvbiBieSB1cGRhdGluZyB0aGVcbiAgICogc3RhdGUgdXNpbmcgYHRoaXMuc2V0U3RhdGVgLiBDdXJyZW50IHByb3BzIGFyZSBhY2Nlc3NlZCB2aWEgYHRoaXMucHJvcHNgLlxuICAgKlxuICAgKiAgIGNvbXBvbmVudFdpbGxSZWNlaXZlUHJvcHM6IGZ1bmN0aW9uKG5leHRQcm9wcywgbmV4dENvbnRleHQpIHtcbiAgICogICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgKiAgICAgICBsaWtlc0luY3JlYXNpbmc6IG5leHRQcm9wcy5saWtlQ291bnQgPiB0aGlzLnByb3BzLmxpa2VDb3VudFxuICAgKiAgICAgfSk7XG4gICAqICAgfVxuICAgKlxuICAgKiBOT1RFOiBUaGVyZSBpcyBubyBlcXVpdmFsZW50IGBjb21wb25lbnRXaWxsUmVjZWl2ZVN0YXRlYC4gQW4gaW5jb21pbmcgcHJvcFxuICAgKiB0cmFuc2l0aW9uIG1heSBjYXVzZSBhIHN0YXRlIGNoYW5nZSwgYnV0IHRoZSBvcHBvc2l0ZSBpcyBub3QgdHJ1ZS4gSWYgeW91XG4gICAqIG5lZWQgaXQsIHlvdSBhcmUgcHJvYmFibHkgbG9va2luZyBmb3IgYGNvbXBvbmVudFdpbGxVcGRhdGVgLlxuICAgKlxuICAgKiBAcGFyYW0ge29iamVjdH0gbmV4dFByb3BzXG4gICAqIEBvcHRpb25hbFxuICAgKi9cbiAgY29tcG9uZW50V2lsbFJlY2VpdmVQcm9wczogU3BlY1BvbGljeS5ERUZJTkVfTUFOWSxcblxuICAvKipcbiAgICogSW52b2tlZCB3aGlsZSBkZWNpZGluZyBpZiB0aGUgY29tcG9uZW50IHNob3VsZCBiZSB1cGRhdGVkIGFzIGEgcmVzdWx0IG9mXG4gICAqIHJlY2VpdmluZyBuZXcgcHJvcHMsIHN0YXRlIGFuZC9vciBjb250ZXh0LlxuICAgKlxuICAgKiBVc2UgdGhpcyBhcyBhbiBvcHBvcnR1bml0eSB0byBgcmV0dXJuIGZhbHNlYCB3aGVuIHlvdSdyZSBjZXJ0YWluIHRoYXQgdGhlXG4gICAqIHRyYW5zaXRpb24gdG8gdGhlIG5ldyBwcm9wcy9zdGF0ZS9jb250ZXh0IHdpbGwgbm90IHJlcXVpcmUgYSBjb21wb25lbnRcbiAgICogdXBkYXRlLlxuICAgKlxuICAgKiAgIHNob3VsZENvbXBvbmVudFVwZGF0ZTogZnVuY3Rpb24obmV4dFByb3BzLCBuZXh0U3RhdGUsIG5leHRDb250ZXh0KSB7XG4gICAqICAgICByZXR1cm4gIWVxdWFsKG5leHRQcm9wcywgdGhpcy5wcm9wcykgfHxcbiAgICogICAgICAgIWVxdWFsKG5leHRTdGF0ZSwgdGhpcy5zdGF0ZSkgfHxcbiAgICogICAgICAgIWVxdWFsKG5leHRDb250ZXh0LCB0aGlzLmNvbnRleHQpO1xuICAgKiAgIH1cbiAgICpcbiAgICogQHBhcmFtIHtvYmplY3R9IG5leHRQcm9wc1xuICAgKiBAcGFyYW0gez9vYmplY3R9IG5leHRTdGF0ZVxuICAgKiBAcGFyYW0gez9vYmplY3R9IG5leHRDb250ZXh0XG4gICAqIEByZXR1cm4ge2Jvb2xlYW59IFRydWUgaWYgdGhlIGNvbXBvbmVudCBzaG91bGQgdXBkYXRlLlxuICAgKiBAb3B0aW9uYWxcbiAgICovXG4gIHNob3VsZENvbXBvbmVudFVwZGF0ZTogU3BlY1BvbGljeS5ERUZJTkVfT05DRSxcblxuICAvKipcbiAgICogSW52b2tlZCB3aGVuIHRoZSBjb21wb25lbnQgaXMgYWJvdXQgdG8gdXBkYXRlIGR1ZSB0byBhIHRyYW5zaXRpb24gZnJvbVxuICAgKiBgdGhpcy5wcm9wc2AsIGB0aGlzLnN0YXRlYCBhbmQgYHRoaXMuY29udGV4dGAgdG8gYG5leHRQcm9wc2AsIGBuZXh0U3RhdGVgXG4gICAqIGFuZCBgbmV4dENvbnRleHRgLlxuICAgKlxuICAgKiBVc2UgdGhpcyBhcyBhbiBvcHBvcnR1bml0eSB0byBwZXJmb3JtIHByZXBhcmF0aW9uIGJlZm9yZSBhbiB1cGRhdGUgb2NjdXJzLlxuICAgKlxuICAgKiBOT1RFOiBZb3UgKipjYW5ub3QqKiB1c2UgYHRoaXMuc2V0U3RhdGUoKWAgaW4gdGhpcyBtZXRob2QuXG4gICAqXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBuZXh0UHJvcHNcbiAgICogQHBhcmFtIHs/b2JqZWN0fSBuZXh0U3RhdGVcbiAgICogQHBhcmFtIHs/b2JqZWN0fSBuZXh0Q29udGV4dFxuICAgKiBAcGFyYW0ge1JlYWN0UmVjb25jaWxlVHJhbnNhY3Rpb259IHRyYW5zYWN0aW9uXG4gICAqIEBvcHRpb25hbFxuICAgKi9cbiAgY29tcG9uZW50V2lsbFVwZGF0ZTogU3BlY1BvbGljeS5ERUZJTkVfTUFOWSxcblxuICAvKipcbiAgICogSW52b2tlZCB3aGVuIHRoZSBjb21wb25lbnQncyBET00gcmVwcmVzZW50YXRpb24gaGFzIGJlZW4gdXBkYXRlZC5cbiAgICpcbiAgICogVXNlIHRoaXMgYXMgYW4gb3Bwb3J0dW5pdHkgdG8gb3BlcmF0ZSBvbiB0aGUgRE9NIHdoZW4gdGhlIGNvbXBvbmVudCBoYXNcbiAgICogYmVlbiB1cGRhdGVkLlxuICAgKlxuICAgKiBAcGFyYW0ge29iamVjdH0gcHJldlByb3BzXG4gICAqIEBwYXJhbSB7P29iamVjdH0gcHJldlN0YXRlXG4gICAqIEBwYXJhbSB7P29iamVjdH0gcHJldkNvbnRleHRcbiAgICogQHBhcmFtIHtET01FbGVtZW50fSByb290Tm9kZSBET00gZWxlbWVudCByZXByZXNlbnRpbmcgdGhlIGNvbXBvbmVudC5cbiAgICogQG9wdGlvbmFsXG4gICAqL1xuICBjb21wb25lbnREaWRVcGRhdGU6IFNwZWNQb2xpY3kuREVGSU5FX01BTlksXG5cbiAgLyoqXG4gICAqIEludm9rZWQgd2hlbiB0aGUgY29tcG9uZW50IGlzIGFib3V0IHRvIGJlIHJlbW92ZWQgZnJvbSBpdHMgcGFyZW50IGFuZCBoYXZlXG4gICAqIGl0cyBET00gcmVwcmVzZW50YXRpb24gZGVzdHJveWVkLlxuICAgKlxuICAgKiBVc2UgdGhpcyBhcyBhbiBvcHBvcnR1bml0eSB0byBkZWFsbG9jYXRlIGFueSBleHRlcm5hbCByZXNvdXJjZXMuXG4gICAqXG4gICAqIE5PVEU6IFRoZXJlIGlzIG5vIGBjb21wb25lbnREaWRVbm1vdW50YCBzaW5jZSB5b3VyIGNvbXBvbmVudCB3aWxsIGhhdmUgYmVlblxuICAgKiBkZXN0cm95ZWQgYnkgdGhhdCBwb2ludC5cbiAgICpcbiAgICogQG9wdGlvbmFsXG4gICAqL1xuICBjb21wb25lbnRXaWxsVW5tb3VudDogU3BlY1BvbGljeS5ERUZJTkVfTUFOWSxcblxuXG5cbiAgLy8gPT09PSBBZHZhbmNlZCBtZXRob2RzID09PT1cblxuICAvKipcbiAgICogVXBkYXRlcyB0aGUgY29tcG9uZW50J3MgY3VycmVudGx5IG1vdW50ZWQgRE9NIHJlcHJlc2VudGF0aW9uLlxuICAgKlxuICAgKiBCeSBkZWZhdWx0LCB0aGlzIGltcGxlbWVudHMgUmVhY3QncyByZW5kZXJpbmcgYW5kIHJlY29uY2lsaWF0aW9uIGFsZ29yaXRobS5cbiAgICogU29waGlzdGljYXRlZCBjbGllbnRzIG1heSB3aXNoIHRvIG92ZXJyaWRlIHRoaXMuXG4gICAqXG4gICAqIEBwYXJhbSB7UmVhY3RSZWNvbmNpbGVUcmFuc2FjdGlvbn0gdHJhbnNhY3Rpb25cbiAgICogQGludGVybmFsXG4gICAqIEBvdmVycmlkYWJsZVxuICAgKi9cbiAgdXBkYXRlQ29tcG9uZW50OiBTcGVjUG9saWN5Lk9WRVJSSURFX0JBU0VcblxufTtcblxuLyoqXG4gKiBNYXBwaW5nIGZyb20gY2xhc3Mgc3BlY2lmaWNhdGlvbiBrZXlzIHRvIHNwZWNpYWwgcHJvY2Vzc2luZyBmdW5jdGlvbnMuXG4gKlxuICogQWx0aG91Z2ggdGhlc2UgYXJlIGRlY2xhcmVkIGxpa2UgaW5zdGFuY2UgcHJvcGVydGllcyBpbiB0aGUgc3BlY2lmaWNhdGlvblxuICogd2hlbiBkZWZpbmluZyBjbGFzc2VzIHVzaW5nIGBSZWFjdC5jcmVhdGVDbGFzc2AsIHRoZXkgYXJlIGFjdHVhbGx5IHN0YXRpY1xuICogYW5kIGFyZSBhY2Nlc3NpYmxlIG9uIHRoZSBjb25zdHJ1Y3RvciBpbnN0ZWFkIG9mIHRoZSBwcm90b3R5cGUuIERlc3BpdGVcbiAqIGJlaW5nIHN0YXRpYywgdGhleSBtdXN0IGJlIGRlZmluZWQgb3V0c2lkZSBvZiB0aGUgXCJzdGF0aWNzXCIga2V5IHVuZGVyXG4gKiB3aGljaCBhbGwgb3RoZXIgc3RhdGljIG1ldGhvZHMgYXJlIGRlZmluZWQuXG4gKi9cbnZhciBSRVNFUlZFRF9TUEVDX0tFWVMgPSB7XG4gIGRpc3BsYXlOYW1lOiBmdW5jdGlvbihDb25zdHJ1Y3RvciwgZGlzcGxheU5hbWUpIHtcbiAgICBDb25zdHJ1Y3Rvci5kaXNwbGF5TmFtZSA9IGRpc3BsYXlOYW1lO1xuICB9LFxuICBtaXhpbnM6IGZ1bmN0aW9uKENvbnN0cnVjdG9yLCBtaXhpbnMpIHtcbiAgICBpZiAobWl4aW5zKSB7XG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IG1peGlucy5sZW5ndGg7IGkrKykge1xuICAgICAgICBtaXhTcGVjSW50b0NvbXBvbmVudChDb25zdHJ1Y3RvciwgbWl4aW5zW2ldKTtcbiAgICAgIH1cbiAgICB9XG4gIH0sXG4gIGNoaWxkQ29udGV4dFR5cGVzOiBmdW5jdGlvbihDb25zdHJ1Y3RvciwgY2hpbGRDb250ZXh0VHlwZXMpIHtcbiAgICB2YWxpZGF0ZVR5cGVEZWYoXG4gICAgICBDb25zdHJ1Y3RvcixcbiAgICAgIGNoaWxkQ29udGV4dFR5cGVzLFxuICAgICAgUmVhY3RQcm9wVHlwZUxvY2F0aW9ucy5jaGlsZENvbnRleHRcbiAgICApO1xuICAgIENvbnN0cnVjdG9yLmNoaWxkQ29udGV4dFR5cGVzID0gYXNzaWduKFxuICAgICAge30sXG4gICAgICBDb25zdHJ1Y3Rvci5jaGlsZENvbnRleHRUeXBlcyxcbiAgICAgIGNoaWxkQ29udGV4dFR5cGVzXG4gICAgKTtcbiAgfSxcbiAgY29udGV4dFR5cGVzOiBmdW5jdGlvbihDb25zdHJ1Y3RvciwgY29udGV4dFR5cGVzKSB7XG4gICAgdmFsaWRhdGVUeXBlRGVmKFxuICAgICAgQ29uc3RydWN0b3IsXG4gICAgICBjb250ZXh0VHlwZXMsXG4gICAgICBSZWFjdFByb3BUeXBlTG9jYXRpb25zLmNvbnRleHRcbiAgICApO1xuICAgIENvbnN0cnVjdG9yLmNvbnRleHRUeXBlcyA9IGFzc2lnbihcbiAgICAgIHt9LFxuICAgICAgQ29uc3RydWN0b3IuY29udGV4dFR5cGVzLFxuICAgICAgY29udGV4dFR5cGVzXG4gICAgKTtcbiAgfSxcbiAgLyoqXG4gICAqIFNwZWNpYWwgY2FzZSBnZXREZWZhdWx0UHJvcHMgd2hpY2ggc2hvdWxkIG1vdmUgaW50byBzdGF0aWNzIGJ1dCByZXF1aXJlc1xuICAgKiBhdXRvbWF0aWMgbWVyZ2luZy5cbiAgICovXG4gIGdldERlZmF1bHRQcm9wczogZnVuY3Rpb24oQ29uc3RydWN0b3IsIGdldERlZmF1bHRQcm9wcykge1xuICAgIGlmIChDb25zdHJ1Y3Rvci5nZXREZWZhdWx0UHJvcHMpIHtcbiAgICAgIENvbnN0cnVjdG9yLmdldERlZmF1bHRQcm9wcyA9IGNyZWF0ZU1lcmdlZFJlc3VsdEZ1bmN0aW9uKFxuICAgICAgICBDb25zdHJ1Y3Rvci5nZXREZWZhdWx0UHJvcHMsXG4gICAgICAgIGdldERlZmF1bHRQcm9wc1xuICAgICAgKTtcbiAgICB9IGVsc2Uge1xuICAgICAgQ29uc3RydWN0b3IuZ2V0RGVmYXVsdFByb3BzID0gZ2V0RGVmYXVsdFByb3BzO1xuICAgIH1cbiAgfSxcbiAgcHJvcFR5cGVzOiBmdW5jdGlvbihDb25zdHJ1Y3RvciwgcHJvcFR5cGVzKSB7XG4gICAgdmFsaWRhdGVUeXBlRGVmKFxuICAgICAgQ29uc3RydWN0b3IsXG4gICAgICBwcm9wVHlwZXMsXG4gICAgICBSZWFjdFByb3BUeXBlTG9jYXRpb25zLnByb3BcbiAgICApO1xuICAgIENvbnN0cnVjdG9yLnByb3BUeXBlcyA9IGFzc2lnbihcbiAgICAgIHt9LFxuICAgICAgQ29uc3RydWN0b3IucHJvcFR5cGVzLFxuICAgICAgcHJvcFR5cGVzXG4gICAgKTtcbiAgfSxcbiAgc3RhdGljczogZnVuY3Rpb24oQ29uc3RydWN0b3IsIHN0YXRpY3MpIHtcbiAgICBtaXhTdGF0aWNTcGVjSW50b0NvbXBvbmVudChDb25zdHJ1Y3Rvciwgc3RhdGljcyk7XG4gIH1cbn07XG5cbmZ1bmN0aW9uIGdldERlY2xhcmF0aW9uRXJyb3JBZGRlbmR1bShjb21wb25lbnQpIHtcbiAgdmFyIG93bmVyID0gY29tcG9uZW50Ll9vd25lciB8fCBudWxsO1xuICBpZiAob3duZXIgJiYgb3duZXIuY29uc3RydWN0b3IgJiYgb3duZXIuY29uc3RydWN0b3IuZGlzcGxheU5hbWUpIHtcbiAgICByZXR1cm4gJyBDaGVjayB0aGUgcmVuZGVyIG1ldGhvZCBvZiBgJyArIG93bmVyLmNvbnN0cnVjdG9yLmRpc3BsYXlOYW1lICtcbiAgICAgICdgLic7XG4gIH1cbiAgcmV0dXJuICcnO1xufVxuXG5mdW5jdGlvbiB2YWxpZGF0ZVR5cGVEZWYoQ29uc3RydWN0b3IsIHR5cGVEZWYsIGxvY2F0aW9uKSB7XG4gIGZvciAodmFyIHByb3BOYW1lIGluIHR5cGVEZWYpIHtcbiAgICBpZiAodHlwZURlZi5oYXNPd25Qcm9wZXJ0eShwcm9wTmFtZSkpIHtcbiAgICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICAgIHR5cGVvZiB0eXBlRGVmW3Byb3BOYW1lXSA9PSAnZnVuY3Rpb24nLFxuICAgICAgICAnJXM6ICVzIHR5cGUgYCVzYCBpcyBpbnZhbGlkOyBpdCBtdXN0IGJlIGEgZnVuY3Rpb24sIHVzdWFsbHkgZnJvbSAnICtcbiAgICAgICAgJ1JlYWN0LlByb3BUeXBlcy4nLFxuICAgICAgICBDb25zdHJ1Y3Rvci5kaXNwbGF5TmFtZSB8fCAnUmVhY3RDb21wb3NpdGVDb21wb25lbnQnLFxuICAgICAgICBSZWFjdFByb3BUeXBlTG9jYXRpb25OYW1lc1tsb2NhdGlvbl0sXG4gICAgICAgIHByb3BOYW1lXG4gICAgICApIDogaW52YXJpYW50KHR5cGVvZiB0eXBlRGVmW3Byb3BOYW1lXSA9PSAnZnVuY3Rpb24nKSk7XG4gICAgfVxuICB9XG59XG5cbmZ1bmN0aW9uIHZhbGlkYXRlTWV0aG9kT3ZlcnJpZGUocHJvdG8sIG5hbWUpIHtcbiAgdmFyIHNwZWNQb2xpY3kgPSBSZWFjdENvbXBvc2l0ZUNvbXBvbmVudEludGVyZmFjZS5oYXNPd25Qcm9wZXJ0eShuYW1lKSA/XG4gICAgUmVhY3RDb21wb3NpdGVDb21wb25lbnRJbnRlcmZhY2VbbmFtZV0gOlxuICAgIG51bGw7XG5cbiAgLy8gRGlzYWxsb3cgb3ZlcnJpZGluZyBvZiBiYXNlIGNsYXNzIG1ldGhvZHMgdW5sZXNzIGV4cGxpY2l0bHkgYWxsb3dlZC5cbiAgaWYgKFJlYWN0Q29tcG9zaXRlQ29tcG9uZW50TWl4aW4uaGFzT3duUHJvcGVydHkobmFtZSkpIHtcbiAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgc3BlY1BvbGljeSA9PT0gU3BlY1BvbGljeS5PVkVSUklERV9CQVNFLFxuICAgICAgJ1JlYWN0Q29tcG9zaXRlQ29tcG9uZW50SW50ZXJmYWNlOiBZb3UgYXJlIGF0dGVtcHRpbmcgdG8gb3ZlcnJpZGUgJyArXG4gICAgICAnYCVzYCBmcm9tIHlvdXIgY2xhc3Mgc3BlY2lmaWNhdGlvbi4gRW5zdXJlIHRoYXQgeW91ciBtZXRob2QgbmFtZXMgJyArXG4gICAgICAnZG8gbm90IG92ZXJsYXAgd2l0aCBSZWFjdCBtZXRob2RzLicsXG4gICAgICBuYW1lXG4gICAgKSA6IGludmFyaWFudChzcGVjUG9saWN5ID09PSBTcGVjUG9saWN5Lk9WRVJSSURFX0JBU0UpKTtcbiAgfVxuXG4gIC8vIERpc2FsbG93IGRlZmluaW5nIG1ldGhvZHMgbW9yZSB0aGFuIG9uY2UgdW5sZXNzIGV4cGxpY2l0bHkgYWxsb3dlZC5cbiAgaWYgKHByb3RvLmhhc093blByb3BlcnR5KG5hbWUpKSB7XG4gICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgIHNwZWNQb2xpY3kgPT09IFNwZWNQb2xpY3kuREVGSU5FX01BTlkgfHxcbiAgICAgIHNwZWNQb2xpY3kgPT09IFNwZWNQb2xpY3kuREVGSU5FX01BTllfTUVSR0VELFxuICAgICAgJ1JlYWN0Q29tcG9zaXRlQ29tcG9uZW50SW50ZXJmYWNlOiBZb3UgYXJlIGF0dGVtcHRpbmcgdG8gZGVmaW5lICcgK1xuICAgICAgJ2Alc2Agb24geW91ciBjb21wb25lbnQgbW9yZSB0aGFuIG9uY2UuIFRoaXMgY29uZmxpY3QgbWF5IGJlIGR1ZSAnICtcbiAgICAgICd0byBhIG1peGluLicsXG4gICAgICBuYW1lXG4gICAgKSA6IGludmFyaWFudChzcGVjUG9saWN5ID09PSBTcGVjUG9saWN5LkRFRklORV9NQU5ZIHx8XG4gICAgc3BlY1BvbGljeSA9PT0gU3BlY1BvbGljeS5ERUZJTkVfTUFOWV9NRVJHRUQpKTtcbiAgfVxufVxuXG5mdW5jdGlvbiB2YWxpZGF0ZUxpZmVDeWNsZU9uUmVwbGFjZVN0YXRlKGluc3RhbmNlKSB7XG4gIHZhciBjb21wb3NpdGVMaWZlQ3ljbGVTdGF0ZSA9IGluc3RhbmNlLl9jb21wb3NpdGVMaWZlQ3ljbGVTdGF0ZTtcbiAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICBpbnN0YW5jZS5pc01vdW50ZWQoKSB8fFxuICAgICAgY29tcG9zaXRlTGlmZUN5Y2xlU3RhdGUgPT09IENvbXBvc2l0ZUxpZmVDeWNsZS5NT1VOVElORyxcbiAgICAncmVwbGFjZVN0YXRlKC4uLik6IENhbiBvbmx5IHVwZGF0ZSBhIG1vdW50ZWQgb3IgbW91bnRpbmcgY29tcG9uZW50LidcbiAgKSA6IGludmFyaWFudChpbnN0YW5jZS5pc01vdW50ZWQoKSB8fFxuICAgIGNvbXBvc2l0ZUxpZmVDeWNsZVN0YXRlID09PSBDb21wb3NpdGVMaWZlQ3ljbGUuTU9VTlRJTkcpKTtcbiAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICBSZWFjdEN1cnJlbnRPd25lci5jdXJyZW50ID09IG51bGwsXG4gICAgJ3JlcGxhY2VTdGF0ZSguLi4pOiBDYW5ub3QgdXBkYXRlIGR1cmluZyBhbiBleGlzdGluZyBzdGF0ZSB0cmFuc2l0aW9uICcgK1xuICAgICcoc3VjaCBhcyB3aXRoaW4gYHJlbmRlcmApLiBSZW5kZXIgbWV0aG9kcyBzaG91bGQgYmUgYSBwdXJlIGZ1bmN0aW9uICcgK1xuICAgICdvZiBwcm9wcyBhbmQgc3RhdGUuJ1xuICApIDogaW52YXJpYW50KFJlYWN0Q3VycmVudE93bmVyLmN1cnJlbnQgPT0gbnVsbCkpO1xuICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KGNvbXBvc2l0ZUxpZmVDeWNsZVN0YXRlICE9PSBDb21wb3NpdGVMaWZlQ3ljbGUuVU5NT1VOVElORyxcbiAgICAncmVwbGFjZVN0YXRlKC4uLik6IENhbm5vdCB1cGRhdGUgd2hpbGUgdW5tb3VudGluZyBjb21wb25lbnQuIFRoaXMgJyArXG4gICAgJ3VzdWFsbHkgbWVhbnMgeW91IGNhbGxlZCBzZXRTdGF0ZSgpIG9uIGFuIHVubW91bnRlZCBjb21wb25lbnQuJ1xuICApIDogaW52YXJpYW50KGNvbXBvc2l0ZUxpZmVDeWNsZVN0YXRlICE9PSBDb21wb3NpdGVMaWZlQ3ljbGUuVU5NT1VOVElORykpO1xufVxuXG4vKipcbiAqIE1peGluIGhlbHBlciB3aGljaCBoYW5kbGVzIHBvbGljeSB2YWxpZGF0aW9uIGFuZCByZXNlcnZlZFxuICogc3BlY2lmaWNhdGlvbiBrZXlzIHdoZW4gYnVpbGRpbmcgYFJlYWN0Q29tcG9zaXRlQ29tcG9uZW50YCBjbGFzc3Nlcy5cbiAqL1xuZnVuY3Rpb24gbWl4U3BlY0ludG9Db21wb25lbnQoQ29uc3RydWN0b3IsIHNwZWMpIHtcbiAgaWYgKCFzcGVjKSB7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAhUmVhY3RMZWdhY3lFbGVtZW50LmlzVmFsaWRGYWN0b3J5KHNwZWMpLFxuICAgICdSZWFjdENvbXBvc2l0ZUNvbXBvbmVudDogWW91XFwncmUgYXR0ZW1wdGluZyB0byAnICtcbiAgICAndXNlIGEgY29tcG9uZW50IGNsYXNzIGFzIGEgbWl4aW4uIEluc3RlYWQsIGp1c3QgdXNlIGEgcmVndWxhciBvYmplY3QuJ1xuICApIDogaW52YXJpYW50KCFSZWFjdExlZ2FjeUVsZW1lbnQuaXNWYWxpZEZhY3Rvcnkoc3BlYykpKTtcbiAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAhUmVhY3RFbGVtZW50LmlzVmFsaWRFbGVtZW50KHNwZWMpLFxuICAgICdSZWFjdENvbXBvc2l0ZUNvbXBvbmVudDogWW91XFwncmUgYXR0ZW1wdGluZyB0byAnICtcbiAgICAndXNlIGEgY29tcG9uZW50IGFzIGEgbWl4aW4uIEluc3RlYWQsIGp1c3QgdXNlIGEgcmVndWxhciBvYmplY3QuJ1xuICApIDogaW52YXJpYW50KCFSZWFjdEVsZW1lbnQuaXNWYWxpZEVsZW1lbnQoc3BlYykpKTtcblxuICB2YXIgcHJvdG8gPSBDb25zdHJ1Y3Rvci5wcm90b3R5cGU7XG5cbiAgLy8gQnkgaGFuZGxpbmcgbWl4aW5zIGJlZm9yZSBhbnkgb3RoZXIgcHJvcGVydGllcywgd2UgZW5zdXJlIHRoZSBzYW1lXG4gIC8vIGNoYWluaW5nIG9yZGVyIGlzIGFwcGxpZWQgdG8gbWV0aG9kcyB3aXRoIERFRklORV9NQU5ZIHBvbGljeSwgd2hldGhlclxuICAvLyBtaXhpbnMgYXJlIGxpc3RlZCBiZWZvcmUgb3IgYWZ0ZXIgdGhlc2UgbWV0aG9kcyBpbiB0aGUgc3BlYy5cbiAgaWYgKHNwZWMuaGFzT3duUHJvcGVydHkoTUlYSU5TX0tFWSkpIHtcbiAgICBSRVNFUlZFRF9TUEVDX0tFWVMubWl4aW5zKENvbnN0cnVjdG9yLCBzcGVjLm1peGlucyk7XG4gIH1cblxuICBmb3IgKHZhciBuYW1lIGluIHNwZWMpIHtcbiAgICBpZiAoIXNwZWMuaGFzT3duUHJvcGVydHkobmFtZSkpIHtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cblxuICAgIGlmIChuYW1lID09PSBNSVhJTlNfS0VZKSB7XG4gICAgICAvLyBXZSBoYXZlIGFscmVhZHkgaGFuZGxlZCBtaXhpbnMgaW4gYSBzcGVjaWFsIGNhc2UgYWJvdmVcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cblxuICAgIHZhciBwcm9wZXJ0eSA9IHNwZWNbbmFtZV07XG4gICAgdmFsaWRhdGVNZXRob2RPdmVycmlkZShwcm90bywgbmFtZSk7XG5cbiAgICBpZiAoUkVTRVJWRURfU1BFQ19LRVlTLmhhc093blByb3BlcnR5KG5hbWUpKSB7XG4gICAgICBSRVNFUlZFRF9TUEVDX0tFWVNbbmFtZV0oQ29uc3RydWN0b3IsIHByb3BlcnR5KTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gU2V0dXAgbWV0aG9kcyBvbiBwcm90b3R5cGU6XG4gICAgICAvLyBUaGUgZm9sbG93aW5nIG1lbWJlciBtZXRob2RzIHNob3VsZCBub3QgYmUgYXV0b21hdGljYWxseSBib3VuZDpcbiAgICAgIC8vIDEuIEV4cGVjdGVkIFJlYWN0Q29tcG9zaXRlQ29tcG9uZW50IG1ldGhvZHMgKGluIHRoZSBcImludGVyZmFjZVwiKS5cbiAgICAgIC8vIDIuIE92ZXJyaWRkZW4gbWV0aG9kcyAodGhhdCB3ZXJlIG1peGVkIGluKS5cbiAgICAgIHZhciBpc0NvbXBvc2l0ZUNvbXBvbmVudE1ldGhvZCA9XG4gICAgICAgIFJlYWN0Q29tcG9zaXRlQ29tcG9uZW50SW50ZXJmYWNlLmhhc093blByb3BlcnR5KG5hbWUpO1xuICAgICAgdmFyIGlzQWxyZWFkeURlZmluZWQgPSBwcm90by5oYXNPd25Qcm9wZXJ0eShuYW1lKTtcbiAgICAgIHZhciBtYXJrZWREb250QmluZCA9IHByb3BlcnR5ICYmIHByb3BlcnR5Ll9fcmVhY3REb250QmluZDtcbiAgICAgIHZhciBpc0Z1bmN0aW9uID0gdHlwZW9mIHByb3BlcnR5ID09PSAnZnVuY3Rpb24nO1xuICAgICAgdmFyIHNob3VsZEF1dG9CaW5kID1cbiAgICAgICAgaXNGdW5jdGlvbiAmJlxuICAgICAgICAhaXNDb21wb3NpdGVDb21wb25lbnRNZXRob2QgJiZcbiAgICAgICAgIWlzQWxyZWFkeURlZmluZWQgJiZcbiAgICAgICAgIW1hcmtlZERvbnRCaW5kO1xuXG4gICAgICBpZiAoc2hvdWxkQXV0b0JpbmQpIHtcbiAgICAgICAgaWYgKCFwcm90by5fX3JlYWN0QXV0b0JpbmRNYXApIHtcbiAgICAgICAgICBwcm90by5fX3JlYWN0QXV0b0JpbmRNYXAgPSB7fTtcbiAgICAgICAgfVxuICAgICAgICBwcm90by5fX3JlYWN0QXV0b0JpbmRNYXBbbmFtZV0gPSBwcm9wZXJ0eTtcbiAgICAgICAgcHJvdG9bbmFtZV0gPSBwcm9wZXJ0eTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGlmIChpc0FscmVhZHlEZWZpbmVkKSB7XG4gICAgICAgICAgdmFyIHNwZWNQb2xpY3kgPSBSZWFjdENvbXBvc2l0ZUNvbXBvbmVudEludGVyZmFjZVtuYW1lXTtcblxuICAgICAgICAgIC8vIFRoZXNlIGNhc2VzIHNob3VsZCBhbHJlYWR5IGJlIGNhdWdodCBieSB2YWxpZGF0ZU1ldGhvZE92ZXJyaWRlXG4gICAgICAgICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgICAgICAgIGlzQ29tcG9zaXRlQ29tcG9uZW50TWV0aG9kICYmIChcbiAgICAgICAgICAgICAgc3BlY1BvbGljeSA9PT0gU3BlY1BvbGljeS5ERUZJTkVfTUFOWV9NRVJHRUQgfHxcbiAgICAgICAgICAgICAgc3BlY1BvbGljeSA9PT0gU3BlY1BvbGljeS5ERUZJTkVfTUFOWVxuICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICdSZWFjdENvbXBvc2l0ZUNvbXBvbmVudDogVW5leHBlY3RlZCBzcGVjIHBvbGljeSAlcyBmb3Iga2V5ICVzICcgK1xuICAgICAgICAgICAgJ3doZW4gbWl4aW5nIGluIGNvbXBvbmVudCBzcGVjcy4nLFxuICAgICAgICAgICAgc3BlY1BvbGljeSxcbiAgICAgICAgICAgIG5hbWVcbiAgICAgICAgICApIDogaW52YXJpYW50KGlzQ29tcG9zaXRlQ29tcG9uZW50TWV0aG9kICYmIChcbiAgICAgICAgICAgIHNwZWNQb2xpY3kgPT09IFNwZWNQb2xpY3kuREVGSU5FX01BTllfTUVSR0VEIHx8XG4gICAgICAgICAgICBzcGVjUG9saWN5ID09PSBTcGVjUG9saWN5LkRFRklORV9NQU5ZXG4gICAgICAgICAgKSkpO1xuXG4gICAgICAgICAgLy8gRm9yIG1ldGhvZHMgd2hpY2ggYXJlIGRlZmluZWQgbW9yZSB0aGFuIG9uY2UsIGNhbGwgdGhlIGV4aXN0aW5nXG4gICAgICAgICAgLy8gbWV0aG9kcyBiZWZvcmUgY2FsbGluZyB0aGUgbmV3IHByb3BlcnR5LCBtZXJnaW5nIGlmIGFwcHJvcHJpYXRlLlxuICAgICAgICAgIGlmIChzcGVjUG9saWN5ID09PSBTcGVjUG9saWN5LkRFRklORV9NQU5ZX01FUkdFRCkge1xuICAgICAgICAgICAgcHJvdG9bbmFtZV0gPSBjcmVhdGVNZXJnZWRSZXN1bHRGdW5jdGlvbihwcm90b1tuYW1lXSwgcHJvcGVydHkpO1xuICAgICAgICAgIH0gZWxzZSBpZiAoc3BlY1BvbGljeSA9PT0gU3BlY1BvbGljeS5ERUZJTkVfTUFOWSkge1xuICAgICAgICAgICAgcHJvdG9bbmFtZV0gPSBjcmVhdGVDaGFpbmVkRnVuY3Rpb24ocHJvdG9bbmFtZV0sIHByb3BlcnR5KTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgcHJvdG9bbmFtZV0gPSBwcm9wZXJ0eTtcbiAgICAgICAgICBpZiAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WKSB7XG4gICAgICAgICAgICAvLyBBZGQgdmVyYm9zZSBkaXNwbGF5TmFtZSB0byB0aGUgZnVuY3Rpb24sIHdoaWNoIGhlbHBzIHdoZW4gbG9va2luZ1xuICAgICAgICAgICAgLy8gYXQgcHJvZmlsaW5nIHRvb2xzLlxuICAgICAgICAgICAgaWYgKHR5cGVvZiBwcm9wZXJ0eSA9PT0gJ2Z1bmN0aW9uJyAmJiBzcGVjLmRpc3BsYXlOYW1lKSB7XG4gICAgICAgICAgICAgIHByb3RvW25hbWVdLmRpc3BsYXlOYW1lID0gc3BlYy5kaXNwbGF5TmFtZSArICdfJyArIG5hbWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9XG59XG5cbmZ1bmN0aW9uIG1peFN0YXRpY1NwZWNJbnRvQ29tcG9uZW50KENvbnN0cnVjdG9yLCBzdGF0aWNzKSB7XG4gIGlmICghc3RhdGljcykge1xuICAgIHJldHVybjtcbiAgfVxuICBmb3IgKHZhciBuYW1lIGluIHN0YXRpY3MpIHtcbiAgICB2YXIgcHJvcGVydHkgPSBzdGF0aWNzW25hbWVdO1xuICAgIGlmICghc3RhdGljcy5oYXNPd25Qcm9wZXJ0eShuYW1lKSkge1xuICAgICAgY29udGludWU7XG4gICAgfVxuXG4gICAgdmFyIGlzUmVzZXJ2ZWQgPSBuYW1lIGluIFJFU0VSVkVEX1NQRUNfS0VZUztcbiAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgIWlzUmVzZXJ2ZWQsXG4gICAgICAnUmVhY3RDb21wb3NpdGVDb21wb25lbnQ6IFlvdSBhcmUgYXR0ZW1wdGluZyB0byBkZWZpbmUgYSByZXNlcnZlZCAnICtcbiAgICAgICdwcm9wZXJ0eSwgYCVzYCwgdGhhdCBzaG91bGRuXFwndCBiZSBvbiB0aGUgXCJzdGF0aWNzXCIga2V5LiBEZWZpbmUgaXQgJyArXG4gICAgICAnYXMgYW4gaW5zdGFuY2UgcHJvcGVydHkgaW5zdGVhZDsgaXQgd2lsbCBzdGlsbCBiZSBhY2Nlc3NpYmxlIG9uIHRoZSAnICtcbiAgICAgICdjb25zdHJ1Y3Rvci4nLFxuICAgICAgbmFtZVxuICAgICkgOiBpbnZhcmlhbnQoIWlzUmVzZXJ2ZWQpKTtcblxuICAgIHZhciBpc0luaGVyaXRlZCA9IG5hbWUgaW4gQ29uc3RydWN0b3I7XG4gICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgICFpc0luaGVyaXRlZCxcbiAgICAgICdSZWFjdENvbXBvc2l0ZUNvbXBvbmVudDogWW91IGFyZSBhdHRlbXB0aW5nIHRvIGRlZmluZSAnICtcbiAgICAgICdgJXNgIG9uIHlvdXIgY29tcG9uZW50IG1vcmUgdGhhbiBvbmNlLiBUaGlzIGNvbmZsaWN0IG1heSBiZSAnICtcbiAgICAgICdkdWUgdG8gYSBtaXhpbi4nLFxuICAgICAgbmFtZVxuICAgICkgOiBpbnZhcmlhbnQoIWlzSW5oZXJpdGVkKSk7XG4gICAgQ29uc3RydWN0b3JbbmFtZV0gPSBwcm9wZXJ0eTtcbiAgfVxufVxuXG4vKipcbiAqIE1lcmdlIHR3byBvYmplY3RzLCBidXQgdGhyb3cgaWYgYm90aCBjb250YWluIHRoZSBzYW1lIGtleS5cbiAqXG4gKiBAcGFyYW0ge29iamVjdH0gb25lIFRoZSBmaXJzdCBvYmplY3QsIHdoaWNoIGlzIG11dGF0ZWQuXG4gKiBAcGFyYW0ge29iamVjdH0gdHdvIFRoZSBzZWNvbmQgb2JqZWN0XG4gKiBAcmV0dXJuIHtvYmplY3R9IG9uZSBhZnRlciBpdCBoYXMgYmVlbiBtdXRhdGVkIHRvIGNvbnRhaW4gZXZlcnl0aGluZyBpbiB0d28uXG4gKi9cbmZ1bmN0aW9uIG1lcmdlT2JqZWN0c1dpdGhOb0R1cGxpY2F0ZUtleXMob25lLCB0d28pIHtcbiAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICBvbmUgJiYgdHdvICYmIHR5cGVvZiBvbmUgPT09ICdvYmplY3QnICYmIHR5cGVvZiB0d28gPT09ICdvYmplY3QnLFxuICAgICdtZXJnZU9iamVjdHNXaXRoTm9EdXBsaWNhdGVLZXlzKCk6IENhbm5vdCBtZXJnZSBub24tb2JqZWN0cydcbiAgKSA6IGludmFyaWFudChvbmUgJiYgdHdvICYmIHR5cGVvZiBvbmUgPT09ICdvYmplY3QnICYmIHR5cGVvZiB0d28gPT09ICdvYmplY3QnKSk7XG5cbiAgbWFwT2JqZWN0KHR3bywgZnVuY3Rpb24odmFsdWUsIGtleSkge1xuICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICBvbmVba2V5XSA9PT0gdW5kZWZpbmVkLFxuICAgICAgJ21lcmdlT2JqZWN0c1dpdGhOb0R1cGxpY2F0ZUtleXMoKTogJyArXG4gICAgICAnVHJpZWQgdG8gbWVyZ2UgdHdvIG9iamVjdHMgd2l0aCB0aGUgc2FtZSBrZXk6IGAlc2AuIFRoaXMgY29uZmxpY3QgJyArXG4gICAgICAnbWF5IGJlIGR1ZSB0byBhIG1peGluOyBpbiBwYXJ0aWN1bGFyLCB0aGlzIG1heSBiZSBjYXVzZWQgYnkgdHdvICcgK1xuICAgICAgJ2dldEluaXRpYWxTdGF0ZSgpIG9yIGdldERlZmF1bHRQcm9wcygpIG1ldGhvZHMgcmV0dXJuaW5nIG9iamVjdHMgJyArXG4gICAgICAnd2l0aCBjbGFzaGluZyBrZXlzLicsXG4gICAgICBrZXlcbiAgICApIDogaW52YXJpYW50KG9uZVtrZXldID09PSB1bmRlZmluZWQpKTtcbiAgICBvbmVba2V5XSA9IHZhbHVlO1xuICB9KTtcbiAgcmV0dXJuIG9uZTtcbn1cblxuLyoqXG4gKiBDcmVhdGVzIGEgZnVuY3Rpb24gdGhhdCBpbnZva2VzIHR3byBmdW5jdGlvbnMgYW5kIG1lcmdlcyB0aGVpciByZXR1cm4gdmFsdWVzLlxuICpcbiAqIEBwYXJhbSB7ZnVuY3Rpb259IG9uZSBGdW5jdGlvbiB0byBpbnZva2UgZmlyc3QuXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSB0d28gRnVuY3Rpb24gdG8gaW52b2tlIHNlY29uZC5cbiAqIEByZXR1cm4ge2Z1bmN0aW9ufSBGdW5jdGlvbiB0aGF0IGludm9rZXMgdGhlIHR3byBhcmd1bWVudCBmdW5jdGlvbnMuXG4gKiBAcHJpdmF0ZVxuICovXG5mdW5jdGlvbiBjcmVhdGVNZXJnZWRSZXN1bHRGdW5jdGlvbihvbmUsIHR3bykge1xuICByZXR1cm4gZnVuY3Rpb24gbWVyZ2VkUmVzdWx0KCkge1xuICAgIHZhciBhID0gb25lLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgdmFyIGIgPSB0d28uYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICBpZiAoYSA9PSBudWxsKSB7XG4gICAgICByZXR1cm4gYjtcbiAgICB9IGVsc2UgaWYgKGIgPT0gbnVsbCkge1xuICAgICAgcmV0dXJuIGE7XG4gICAgfVxuICAgIHJldHVybiBtZXJnZU9iamVjdHNXaXRoTm9EdXBsaWNhdGVLZXlzKGEsIGIpO1xuICB9O1xufVxuXG4vKipcbiAqIENyZWF0ZXMgYSBmdW5jdGlvbiB0aGF0IGludm9rZXMgdHdvIGZ1bmN0aW9ucyBhbmQgaWdub3JlcyB0aGVpciByZXR1cm4gdmFsZXMuXG4gKlxuICogQHBhcmFtIHtmdW5jdGlvbn0gb25lIEZ1bmN0aW9uIHRvIGludm9rZSBmaXJzdC5cbiAqIEBwYXJhbSB7ZnVuY3Rpb259IHR3byBGdW5jdGlvbiB0byBpbnZva2Ugc2Vjb25kLlxuICogQHJldHVybiB7ZnVuY3Rpb259IEZ1bmN0aW9uIHRoYXQgaW52b2tlcyB0aGUgdHdvIGFyZ3VtZW50IGZ1bmN0aW9ucy5cbiAqIEBwcml2YXRlXG4gKi9cbmZ1bmN0aW9uIGNyZWF0ZUNoYWluZWRGdW5jdGlvbihvbmUsIHR3bykge1xuICByZXR1cm4gZnVuY3Rpb24gY2hhaW5lZEZ1bmN0aW9uKCkge1xuICAgIG9uZS5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgIHR3by5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICB9O1xufVxuXG4vKipcbiAqIGBSZWFjdENvbXBvc2l0ZUNvbXBvbmVudGAgbWFpbnRhaW5zIGFuIGF1eGlsaWFyeSBsaWZlIGN5Y2xlIHN0YXRlIGluXG4gKiBgdGhpcy5fY29tcG9zaXRlTGlmZUN5Y2xlU3RhdGVgICh3aGljaCBjYW4gYmUgbnVsbCkuXG4gKlxuICogVGhpcyBpcyBkaWZmZXJlbnQgZnJvbSB0aGUgbGlmZSBjeWNsZSBzdGF0ZSBtYWludGFpbmVkIGJ5IGBSZWFjdENvbXBvbmVudGAgaW5cbiAqIGB0aGlzLl9saWZlQ3ljbGVTdGF0ZWAuIFRoZSBmb2xsb3dpbmcgZGlhZ3JhbSBzaG93cyBob3cgdGhlIHN0YXRlcyBvdmVybGFwIGluXG4gKiB0aW1lLiBUaGVyZSBhcmUgdGltZXMgd2hlbiB0aGUgQ29tcG9zaXRlTGlmZUN5Y2xlIGlzIG51bGwgLSBhdCB0aG9zZSB0aW1lcyBpdFxuICogaXMgb25seSBtZWFuaW5nZnVsIHRvIGxvb2sgYXQgQ29tcG9uZW50TGlmZUN5Y2xlIGFsb25lLlxuICpcbiAqIFRvcCBSb3c6IFJlYWN0Q29tcG9uZW50LkNvbXBvbmVudExpZmVDeWNsZVxuICogTG93IFJvdzogUmVhY3RDb21wb25lbnQuQ29tcG9zaXRlTGlmZUN5Y2xlXG4gKlxuICogKy0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tK1xuICogfCAgVU4gICB8ICAgICAgICAgICAgIE1PVU5URUQgICAgICAgICAgICAgfCAgIFVOICAgfFxuICogfE1PVU5URUR8ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBNT1VOVEVEfFxuICogKy0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tK1xuICogfCAgICAgICBeLS0tLS0tLS0rICAgKy0tLS0tLS0rICAgKy0tLS0tLS0tXiAgICAgICAgfFxuICogfCAgICAgICB8ICAgICAgICB8ICAgfCAgICAgICB8ICAgfCAgICAgICAgfCAgICAgICAgfFxuICogfCAgICAwLS18TU9VTlRJTkd8LTAtfFJFQ0VJVkV8LTAtfCAgIFVOICAgfC0tLT4wICAgfFxuICogfCAgICAgICB8ICAgICAgICB8ICAgfFBST1BTICB8ICAgfE1PVU5USU5HfCAgICAgICAgfFxuICogfCAgICAgICB8ICAgICAgICB8ICAgfCAgICAgICB8ICAgfCAgICAgICAgfCAgICAgICAgfFxuICogfCAgICAgICB8ICAgICAgICB8ICAgfCAgICAgICB8ICAgfCAgICAgICAgfCAgICAgICAgfFxuICogfCAgICAgICArLS0tLS0tLS0rICAgKy0tLS0tLS0rICAgKy0tLS0tLS0tKyAgICAgICAgfFxuICogfCAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgfFxuICogKy0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tK1xuICovXG52YXIgQ29tcG9zaXRlTGlmZUN5Y2xlID0ga2V5TWlycm9yKHtcbiAgLyoqXG4gICAqIENvbXBvbmVudHMgaW4gdGhlIHByb2Nlc3Mgb2YgYmVpbmcgbW91bnRlZCByZXNwb25kIHRvIHN0YXRlIGNoYW5nZXNcbiAgICogZGlmZmVyZW50bHkuXG4gICAqL1xuICBNT1VOVElORzogbnVsbCxcbiAgLyoqXG4gICAqIENvbXBvbmVudHMgaW4gdGhlIHByb2Nlc3Mgb2YgYmVpbmcgdW5tb3VudGVkIGFyZSBndWFyZGVkIGFnYWluc3Qgc3RhdGVcbiAgICogY2hhbmdlcy5cbiAgICovXG4gIFVOTU9VTlRJTkc6IG51bGwsXG4gIC8qKlxuICAgKiBDb21wb25lbnRzIHRoYXQgYXJlIG1vdW50ZWQgYW5kIHJlY2VpdmluZyBuZXcgcHJvcHMgcmVzcG9uZCB0byBzdGF0ZVxuICAgKiBjaGFuZ2VzIGRpZmZlcmVudGx5LlxuICAgKi9cbiAgUkVDRUlWSU5HX1BST1BTOiBudWxsXG59KTtcblxuLyoqXG4gKiBAbGVuZHMge1JlYWN0Q29tcG9zaXRlQ29tcG9uZW50LnByb3RvdHlwZX1cbiAqL1xudmFyIFJlYWN0Q29tcG9zaXRlQ29tcG9uZW50TWl4aW4gPSB7XG5cbiAgLyoqXG4gICAqIEJhc2UgY29uc3RydWN0b3IgZm9yIGFsbCBjb21wb3NpdGUgY29tcG9uZW50LlxuICAgKlxuICAgKiBAcGFyYW0ge1JlYWN0RWxlbWVudH0gZWxlbWVudFxuICAgKiBAZmluYWxcbiAgICogQGludGVybmFsXG4gICAqL1xuICBjb25zdHJ1Y3Q6IGZ1bmN0aW9uKGVsZW1lbnQpIHtcbiAgICAvLyBDaGlsZHJlbiBjYW4gYmUgZWl0aGVyIGFuIGFycmF5IG9yIG1vcmUgdGhhbiBvbmUgYXJndW1lbnRcbiAgICBSZWFjdENvbXBvbmVudC5NaXhpbi5jb25zdHJ1Y3QuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICBSZWFjdE93bmVyLk1peGluLmNvbnN0cnVjdC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuXG4gICAgdGhpcy5zdGF0ZSA9IG51bGw7XG4gICAgdGhpcy5fcGVuZGluZ1N0YXRlID0gbnVsbDtcblxuICAgIC8vIFRoaXMgaXMgdGhlIHB1YmxpYyBwb3N0LXByb2Nlc3NlZCBjb250ZXh0LiBUaGUgcmVhbCBjb250ZXh0IGFuZCBwZW5kaW5nXG4gICAgLy8gY29udGV4dCBsaXZlcyBvbiB0aGUgZWxlbWVudC5cbiAgICB0aGlzLmNvbnRleHQgPSBudWxsO1xuXG4gICAgdGhpcy5fY29tcG9zaXRlTGlmZUN5Y2xlU3RhdGUgPSBudWxsO1xuICB9LFxuXG4gIC8qKlxuICAgKiBDaGVja3Mgd2hldGhlciBvciBub3QgdGhpcyBjb21wb3NpdGUgY29tcG9uZW50IGlzIG1vdW50ZWQuXG4gICAqIEByZXR1cm4ge2Jvb2xlYW59IFRydWUgaWYgbW91bnRlZCwgZmFsc2Ugb3RoZXJ3aXNlLlxuICAgKiBAcHJvdGVjdGVkXG4gICAqIEBmaW5hbFxuICAgKi9cbiAgaXNNb3VudGVkOiBmdW5jdGlvbigpIHtcbiAgICByZXR1cm4gUmVhY3RDb21wb25lbnQuTWl4aW4uaXNNb3VudGVkLmNhbGwodGhpcykgJiZcbiAgICAgIHRoaXMuX2NvbXBvc2l0ZUxpZmVDeWNsZVN0YXRlICE9PSBDb21wb3NpdGVMaWZlQ3ljbGUuTU9VTlRJTkc7XG4gIH0sXG5cbiAgLyoqXG4gICAqIEluaXRpYWxpemVzIHRoZSBjb21wb25lbnQsIHJlbmRlcnMgbWFya3VwLCBhbmQgcmVnaXN0ZXJzIGV2ZW50IGxpc3RlbmVycy5cbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IHJvb3RJRCBET00gSUQgb2YgdGhlIHJvb3Qgbm9kZS5cbiAgICogQHBhcmFtIHtSZWFjdFJlY29uY2lsZVRyYW5zYWN0aW9ufFJlYWN0U2VydmVyUmVuZGVyaW5nVHJhbnNhY3Rpb259IHRyYW5zYWN0aW9uXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBtb3VudERlcHRoIG51bWJlciBvZiBjb21wb25lbnRzIGluIHRoZSBvd25lciBoaWVyYXJjaHlcbiAgICogQHJldHVybiB7P3N0cmluZ30gUmVuZGVyZWQgbWFya3VwIHRvIGJlIGluc2VydGVkIGludG8gdGhlIERPTS5cbiAgICogQGZpbmFsXG4gICAqIEBpbnRlcm5hbFxuICAgKi9cbiAgbW91bnRDb21wb25lbnQ6IFJlYWN0UGVyZi5tZWFzdXJlKFxuICAgICdSZWFjdENvbXBvc2l0ZUNvbXBvbmVudCcsXG4gICAgJ21vdW50Q29tcG9uZW50JyxcbiAgICBmdW5jdGlvbihyb290SUQsIHRyYW5zYWN0aW9uLCBtb3VudERlcHRoKSB7XG4gICAgICBSZWFjdENvbXBvbmVudC5NaXhpbi5tb3VudENvbXBvbmVudC5jYWxsKFxuICAgICAgICB0aGlzLFxuICAgICAgICByb290SUQsXG4gICAgICAgIHRyYW5zYWN0aW9uLFxuICAgICAgICBtb3VudERlcHRoXG4gICAgICApO1xuICAgICAgdGhpcy5fY29tcG9zaXRlTGlmZUN5Y2xlU3RhdGUgPSBDb21wb3NpdGVMaWZlQ3ljbGUuTU9VTlRJTkc7XG5cbiAgICAgIGlmICh0aGlzLl9fcmVhY3RBdXRvQmluZE1hcCkge1xuICAgICAgICB0aGlzLl9iaW5kQXV0b0JpbmRNZXRob2RzKCk7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuY29udGV4dCA9IHRoaXMuX3Byb2Nlc3NDb250ZXh0KHRoaXMuX2N1cnJlbnRFbGVtZW50Ll9jb250ZXh0KTtcbiAgICAgIHRoaXMucHJvcHMgPSB0aGlzLl9wcm9jZXNzUHJvcHModGhpcy5wcm9wcyk7XG5cbiAgICAgIHRoaXMuc3RhdGUgPSB0aGlzLmdldEluaXRpYWxTdGF0ZSA/IHRoaXMuZ2V0SW5pdGlhbFN0YXRlKCkgOiBudWxsO1xuICAgICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgICAgdHlwZW9mIHRoaXMuc3RhdGUgPT09ICdvYmplY3QnICYmICFBcnJheS5pc0FycmF5KHRoaXMuc3RhdGUpLFxuICAgICAgICAnJXMuZ2V0SW5pdGlhbFN0YXRlKCk6IG11c3QgcmV0dXJuIGFuIG9iamVjdCBvciBudWxsJyxcbiAgICAgICAgdGhpcy5jb25zdHJ1Y3Rvci5kaXNwbGF5TmFtZSB8fCAnUmVhY3RDb21wb3NpdGVDb21wb25lbnQnXG4gICAgICApIDogaW52YXJpYW50KHR5cGVvZiB0aGlzLnN0YXRlID09PSAnb2JqZWN0JyAmJiAhQXJyYXkuaXNBcnJheSh0aGlzLnN0YXRlKSkpO1xuXG4gICAgICB0aGlzLl9wZW5kaW5nU3RhdGUgPSBudWxsO1xuICAgICAgdGhpcy5fcGVuZGluZ0ZvcmNlVXBkYXRlID0gZmFsc2U7XG5cbiAgICAgIGlmICh0aGlzLmNvbXBvbmVudFdpbGxNb3VudCkge1xuICAgICAgICB0aGlzLmNvbXBvbmVudFdpbGxNb3VudCgpO1xuICAgICAgICAvLyBXaGVuIG1vdW50aW5nLCBjYWxscyB0byBgc2V0U3RhdGVgIGJ5IGBjb21wb25lbnRXaWxsTW91bnRgIHdpbGwgc2V0XG4gICAgICAgIC8vIGB0aGlzLl9wZW5kaW5nU3RhdGVgIHdpdGhvdXQgdHJpZ2dlcmluZyBhIHJlLXJlbmRlci5cbiAgICAgICAgaWYgKHRoaXMuX3BlbmRpbmdTdGF0ZSkge1xuICAgICAgICAgIHRoaXMuc3RhdGUgPSB0aGlzLl9wZW5kaW5nU3RhdGU7XG4gICAgICAgICAgdGhpcy5fcGVuZGluZ1N0YXRlID0gbnVsbDtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICB0aGlzLl9yZW5kZXJlZENvbXBvbmVudCA9IGluc3RhbnRpYXRlUmVhY3RDb21wb25lbnQoXG4gICAgICAgIHRoaXMuX3JlbmRlclZhbGlkYXRlZENvbXBvbmVudCgpLFxuICAgICAgICB0aGlzLl9jdXJyZW50RWxlbWVudC50eXBlIC8vIFRoZSB3cmFwcGluZyB0eXBlXG4gICAgICApO1xuXG4gICAgICAvLyBEb25lIHdpdGggbW91bnRpbmcsIGBzZXRTdGF0ZWAgd2lsbCBub3cgdHJpZ2dlciBVSSBjaGFuZ2VzLlxuICAgICAgdGhpcy5fY29tcG9zaXRlTGlmZUN5Y2xlU3RhdGUgPSBudWxsO1xuICAgICAgdmFyIG1hcmt1cCA9IHRoaXMuX3JlbmRlcmVkQ29tcG9uZW50Lm1vdW50Q29tcG9uZW50KFxuICAgICAgICByb290SUQsXG4gICAgICAgIHRyYW5zYWN0aW9uLFxuICAgICAgICBtb3VudERlcHRoICsgMVxuICAgICAgKTtcbiAgICAgIGlmICh0aGlzLmNvbXBvbmVudERpZE1vdW50KSB7XG4gICAgICAgIHRyYW5zYWN0aW9uLmdldFJlYWN0TW91bnRSZWFkeSgpLmVucXVldWUodGhpcy5jb21wb25lbnREaWRNb3VudCwgdGhpcyk7XG4gICAgICB9XG4gICAgICByZXR1cm4gbWFya3VwO1xuICAgIH1cbiAgKSxcblxuICAvKipcbiAgICogUmVsZWFzZXMgYW55IHJlc291cmNlcyBhbGxvY2F0ZWQgYnkgYG1vdW50Q29tcG9uZW50YC5cbiAgICpcbiAgICogQGZpbmFsXG4gICAqIEBpbnRlcm5hbFxuICAgKi9cbiAgdW5tb3VudENvbXBvbmVudDogZnVuY3Rpb24oKSB7XG4gICAgdGhpcy5fY29tcG9zaXRlTGlmZUN5Y2xlU3RhdGUgPSBDb21wb3NpdGVMaWZlQ3ljbGUuVU5NT1VOVElORztcbiAgICBpZiAodGhpcy5jb21wb25lbnRXaWxsVW5tb3VudCkge1xuICAgICAgdGhpcy5jb21wb25lbnRXaWxsVW5tb3VudCgpO1xuICAgIH1cbiAgICB0aGlzLl9jb21wb3NpdGVMaWZlQ3ljbGVTdGF0ZSA9IG51bGw7XG5cbiAgICB0aGlzLl9yZW5kZXJlZENvbXBvbmVudC51bm1vdW50Q29tcG9uZW50KCk7XG4gICAgdGhpcy5fcmVuZGVyZWRDb21wb25lbnQgPSBudWxsO1xuXG4gICAgUmVhY3RDb21wb25lbnQuTWl4aW4udW5tb3VudENvbXBvbmVudC5jYWxsKHRoaXMpO1xuXG4gICAgLy8gU29tZSBleGlzdGluZyBjb21wb25lbnRzIHJlbHkgb24gdGhpcy5wcm9wcyBldmVuIGFmdGVyIHRoZXkndmUgYmVlblxuICAgIC8vIGRlc3Ryb3llZCAoaW4gZXZlbnQgaGFuZGxlcnMpLlxuICAgIC8vIFRPRE86IHRoaXMucHJvcHMgPSBudWxsO1xuICAgIC8vIFRPRE86IHRoaXMuc3RhdGUgPSBudWxsO1xuICB9LFxuXG4gIC8qKlxuICAgKiBTZXRzIGEgc3Vic2V0IG9mIHRoZSBzdGF0ZS4gQWx3YXlzIHVzZSB0aGlzIG9yIGByZXBsYWNlU3RhdGVgIHRvIG11dGF0ZVxuICAgKiBzdGF0ZS4gWW91IHNob3VsZCB0cmVhdCBgdGhpcy5zdGF0ZWAgYXMgaW1tdXRhYmxlLlxuICAgKlxuICAgKiBUaGVyZSBpcyBubyBndWFyYW50ZWUgdGhhdCBgdGhpcy5zdGF0ZWAgd2lsbCBiZSBpbW1lZGlhdGVseSB1cGRhdGVkLCBzb1xuICAgKiBhY2Nlc3NpbmcgYHRoaXMuc3RhdGVgIGFmdGVyIGNhbGxpbmcgdGhpcyBtZXRob2QgbWF5IHJldHVybiB0aGUgb2xkIHZhbHVlLlxuICAgKlxuICAgKiBUaGVyZSBpcyBubyBndWFyYW50ZWUgdGhhdCBjYWxscyB0byBgc2V0U3RhdGVgIHdpbGwgcnVuIHN5bmNocm9ub3VzbHksXG4gICAqIGFzIHRoZXkgbWF5IGV2ZW50dWFsbHkgYmUgYmF0Y2hlZCB0b2dldGhlci4gIFlvdSBjYW4gcHJvdmlkZSBhbiBvcHRpb25hbFxuICAgKiBjYWxsYmFjayB0aGF0IHdpbGwgYmUgZXhlY3V0ZWQgd2hlbiB0aGUgY2FsbCB0byBzZXRTdGF0ZSBpcyBhY3R1YWxseVxuICAgKiBjb21wbGV0ZWQuXG4gICAqXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBwYXJ0aWFsU3RhdGUgTmV4dCBwYXJ0aWFsIHN0YXRlIHRvIGJlIG1lcmdlZCB3aXRoIHN0YXRlLlxuICAgKiBAcGFyYW0gez9mdW5jdGlvbn0gY2FsbGJhY2sgQ2FsbGVkIGFmdGVyIHN0YXRlIGlzIHVwZGF0ZWQuXG4gICAqIEBmaW5hbFxuICAgKiBAcHJvdGVjdGVkXG4gICAqL1xuICBzZXRTdGF0ZTogZnVuY3Rpb24ocGFydGlhbFN0YXRlLCBjYWxsYmFjaykge1xuICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICB0eXBlb2YgcGFydGlhbFN0YXRlID09PSAnb2JqZWN0JyB8fCBwYXJ0aWFsU3RhdGUgPT0gbnVsbCxcbiAgICAgICdzZXRTdGF0ZSguLi4pOiB0YWtlcyBhbiBvYmplY3Qgb2Ygc3RhdGUgdmFyaWFibGVzIHRvIHVwZGF0ZS4nXG4gICAgKSA6IGludmFyaWFudCh0eXBlb2YgcGFydGlhbFN0YXRlID09PSAnb2JqZWN0JyB8fCBwYXJ0aWFsU3RhdGUgPT0gbnVsbCkpO1xuICAgIGlmIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYpe1xuICAgICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IHdhcm5pbmcoXG4gICAgICAgIHBhcnRpYWxTdGF0ZSAhPSBudWxsLFxuICAgICAgICAnc2V0U3RhdGUoLi4uKTogWW91IHBhc3NlZCBhbiB1bmRlZmluZWQgb3IgbnVsbCBzdGF0ZSBvYmplY3Q7ICcgK1xuICAgICAgICAnaW5zdGVhZCwgdXNlIGZvcmNlVXBkYXRlKCkuJ1xuICAgICAgKSA6IG51bGwpO1xuICAgIH1cbiAgICAvLyBNZXJnZSB3aXRoIGBfcGVuZGluZ1N0YXRlYCBpZiBpdCBleGlzdHMsIG90aGVyd2lzZSB3aXRoIGV4aXN0aW5nIHN0YXRlLlxuICAgIHRoaXMucmVwbGFjZVN0YXRlKFxuICAgICAgYXNzaWduKHt9LCB0aGlzLl9wZW5kaW5nU3RhdGUgfHwgdGhpcy5zdGF0ZSwgcGFydGlhbFN0YXRlKSxcbiAgICAgIGNhbGxiYWNrXG4gICAgKTtcbiAgfSxcblxuICAvKipcbiAgICogUmVwbGFjZXMgYWxsIG9mIHRoZSBzdGF0ZS4gQWx3YXlzIHVzZSB0aGlzIG9yIGBzZXRTdGF0ZWAgdG8gbXV0YXRlIHN0YXRlLlxuICAgKiBZb3Ugc2hvdWxkIHRyZWF0IGB0aGlzLnN0YXRlYCBhcyBpbW11dGFibGUuXG4gICAqXG4gICAqIFRoZXJlIGlzIG5vIGd1YXJhbnRlZSB0aGF0IGB0aGlzLnN0YXRlYCB3aWxsIGJlIGltbWVkaWF0ZWx5IHVwZGF0ZWQsIHNvXG4gICAqIGFjY2Vzc2luZyBgdGhpcy5zdGF0ZWAgYWZ0ZXIgY2FsbGluZyB0aGlzIG1ldGhvZCBtYXkgcmV0dXJuIHRoZSBvbGQgdmFsdWUuXG4gICAqXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBjb21wbGV0ZVN0YXRlIE5leHQgc3RhdGUuXG4gICAqIEBwYXJhbSB7P2Z1bmN0aW9ufSBjYWxsYmFjayBDYWxsZWQgYWZ0ZXIgc3RhdGUgaXMgdXBkYXRlZC5cbiAgICogQGZpbmFsXG4gICAqIEBwcm90ZWN0ZWRcbiAgICovXG4gIHJlcGxhY2VTdGF0ZTogZnVuY3Rpb24oY29tcGxldGVTdGF0ZSwgY2FsbGJhY2spIHtcbiAgICB2YWxpZGF0ZUxpZmVDeWNsZU9uUmVwbGFjZVN0YXRlKHRoaXMpO1xuICAgIHRoaXMuX3BlbmRpbmdTdGF0ZSA9IGNvbXBsZXRlU3RhdGU7XG4gICAgaWYgKHRoaXMuX2NvbXBvc2l0ZUxpZmVDeWNsZVN0YXRlICE9PSBDb21wb3NpdGVMaWZlQ3ljbGUuTU9VTlRJTkcpIHtcbiAgICAgIC8vIElmIHdlJ3JlIGluIGEgY29tcG9uZW50V2lsbE1vdW50IGhhbmRsZXIsIGRvbid0IGVucXVldWUgYSByZXJlbmRlclxuICAgICAgLy8gYmVjYXVzZSBSZWFjdFVwZGF0ZXMgYXNzdW1lcyB3ZSdyZSBpbiBhIGJyb3dzZXIgY29udGV4dCAod2hpY2ggaXMgd3JvbmdcbiAgICAgIC8vIGZvciBzZXJ2ZXIgcmVuZGVyaW5nKSBhbmQgd2UncmUgYWJvdXQgdG8gZG8gYSByZW5kZXIgYW55d2F5LlxuICAgICAgLy8gVE9ETzogVGhlIGNhbGxiYWNrIGhlcmUgaXMgaWdub3JlZCB3aGVuIHNldFN0YXRlIGlzIGNhbGxlZCBmcm9tXG4gICAgICAvLyBjb21wb25lbnRXaWxsTW91bnQuIEVpdGhlciBmaXggaXQgb3IgZGlzYWxsb3cgZG9pbmcgc28gY29tcGxldGVseSBpblxuICAgICAgLy8gZmF2b3Igb2YgZ2V0SW5pdGlhbFN0YXRlLlxuICAgICAgUmVhY3RVcGRhdGVzLmVucXVldWVVcGRhdGUodGhpcywgY2FsbGJhY2spO1xuICAgIH1cbiAgfSxcblxuICAvKipcbiAgICogRmlsdGVycyB0aGUgY29udGV4dCBvYmplY3QgdG8gb25seSBjb250YWluIGtleXMgc3BlY2lmaWVkIGluXG4gICAqIGBjb250ZXh0VHlwZXNgLCBhbmQgYXNzZXJ0cyB0aGF0IHRoZXkgYXJlIHZhbGlkLlxuICAgKlxuICAgKiBAcGFyYW0ge29iamVjdH0gY29udGV4dFxuICAgKiBAcmV0dXJuIHs/b2JqZWN0fVxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgX3Byb2Nlc3NDb250ZXh0OiBmdW5jdGlvbihjb250ZXh0KSB7XG4gICAgdmFyIG1hc2tlZENvbnRleHQgPSBudWxsO1xuICAgIHZhciBjb250ZXh0VHlwZXMgPSB0aGlzLmNvbnN0cnVjdG9yLmNvbnRleHRUeXBlcztcbiAgICBpZiAoY29udGV4dFR5cGVzKSB7XG4gICAgICBtYXNrZWRDb250ZXh0ID0ge307XG4gICAgICBmb3IgKHZhciBjb250ZXh0TmFtZSBpbiBjb250ZXh0VHlwZXMpIHtcbiAgICAgICAgbWFza2VkQ29udGV4dFtjb250ZXh0TmFtZV0gPSBjb250ZXh0W2NvbnRleHROYW1lXTtcbiAgICAgIH1cbiAgICAgIGlmIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYpIHtcbiAgICAgICAgdGhpcy5fY2hlY2tQcm9wVHlwZXMoXG4gICAgICAgICAgY29udGV4dFR5cGVzLFxuICAgICAgICAgIG1hc2tlZENvbnRleHQsXG4gICAgICAgICAgUmVhY3RQcm9wVHlwZUxvY2F0aW9ucy5jb250ZXh0XG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBtYXNrZWRDb250ZXh0O1xuICB9LFxuXG4gIC8qKlxuICAgKiBAcGFyYW0ge29iamVjdH0gY3VycmVudENvbnRleHRcbiAgICogQHJldHVybiB7b2JqZWN0fVxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgX3Byb2Nlc3NDaGlsZENvbnRleHQ6IGZ1bmN0aW9uKGN1cnJlbnRDb250ZXh0KSB7XG4gICAgdmFyIGNoaWxkQ29udGV4dCA9IHRoaXMuZ2V0Q2hpbGRDb250ZXh0ICYmIHRoaXMuZ2V0Q2hpbGRDb250ZXh0KCk7XG4gICAgdmFyIGRpc3BsYXlOYW1lID0gdGhpcy5jb25zdHJ1Y3Rvci5kaXNwbGF5TmFtZSB8fCAnUmVhY3RDb21wb3NpdGVDb21wb25lbnQnO1xuICAgIGlmIChjaGlsZENvbnRleHQpIHtcbiAgICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICAgIHR5cGVvZiB0aGlzLmNvbnN0cnVjdG9yLmNoaWxkQ29udGV4dFR5cGVzID09PSAnb2JqZWN0JyxcbiAgICAgICAgJyVzLmdldENoaWxkQ29udGV4dCgpOiBjaGlsZENvbnRleHRUeXBlcyBtdXN0IGJlIGRlZmluZWQgaW4gb3JkZXIgdG8gJyArXG4gICAgICAgICd1c2UgZ2V0Q2hpbGRDb250ZXh0KCkuJyxcbiAgICAgICAgZGlzcGxheU5hbWVcbiAgICAgICkgOiBpbnZhcmlhbnQodHlwZW9mIHRoaXMuY29uc3RydWN0b3IuY2hpbGRDb250ZXh0VHlwZXMgPT09ICdvYmplY3QnKSk7XG4gICAgICBpZiAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WKSB7XG4gICAgICAgIHRoaXMuX2NoZWNrUHJvcFR5cGVzKFxuICAgICAgICAgIHRoaXMuY29uc3RydWN0b3IuY2hpbGRDb250ZXh0VHlwZXMsXG4gICAgICAgICAgY2hpbGRDb250ZXh0LFxuICAgICAgICAgIFJlYWN0UHJvcFR5cGVMb2NhdGlvbnMuY2hpbGRDb250ZXh0XG4gICAgICAgICk7XG4gICAgICB9XG4gICAgICBmb3IgKHZhciBuYW1lIGluIGNoaWxkQ29udGV4dCkge1xuICAgICAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgICAgIG5hbWUgaW4gdGhpcy5jb25zdHJ1Y3Rvci5jaGlsZENvbnRleHRUeXBlcyxcbiAgICAgICAgICAnJXMuZ2V0Q2hpbGRDb250ZXh0KCk6IGtleSBcIiVzXCIgaXMgbm90IGRlZmluZWQgaW4gY2hpbGRDb250ZXh0VHlwZXMuJyxcbiAgICAgICAgICBkaXNwbGF5TmFtZSxcbiAgICAgICAgICBuYW1lXG4gICAgICAgICkgOiBpbnZhcmlhbnQobmFtZSBpbiB0aGlzLmNvbnN0cnVjdG9yLmNoaWxkQ29udGV4dFR5cGVzKSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gYXNzaWduKHt9LCBjdXJyZW50Q29udGV4dCwgY2hpbGRDb250ZXh0KTtcbiAgICB9XG4gICAgcmV0dXJuIGN1cnJlbnRDb250ZXh0O1xuICB9LFxuXG4gIC8qKlxuICAgKiBQcm9jZXNzZXMgcHJvcHMgYnkgc2V0dGluZyBkZWZhdWx0IHZhbHVlcyBmb3IgdW5zcGVjaWZpZWQgcHJvcHMgYW5kXG4gICAqIGFzc2VydGluZyB0aGF0IHRoZSBwcm9wcyBhcmUgdmFsaWQuIERvZXMgbm90IG11dGF0ZSBpdHMgYXJndW1lbnQ7IHJldHVybnNcbiAgICogYSBuZXcgcHJvcHMgb2JqZWN0IHdpdGggZGVmYXVsdHMgbWVyZ2VkIGluLlxuICAgKlxuICAgKiBAcGFyYW0ge29iamVjdH0gbmV3UHJvcHNcbiAgICogQHJldHVybiB7b2JqZWN0fVxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgX3Byb2Nlc3NQcm9wczogZnVuY3Rpb24obmV3UHJvcHMpIHtcbiAgICBpZiAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WKSB7XG4gICAgICB2YXIgcHJvcFR5cGVzID0gdGhpcy5jb25zdHJ1Y3Rvci5wcm9wVHlwZXM7XG4gICAgICBpZiAocHJvcFR5cGVzKSB7XG4gICAgICAgIHRoaXMuX2NoZWNrUHJvcFR5cGVzKHByb3BUeXBlcywgbmV3UHJvcHMsIFJlYWN0UHJvcFR5cGVMb2NhdGlvbnMucHJvcCk7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBuZXdQcm9wcztcbiAgfSxcblxuICAvKipcbiAgICogQXNzZXJ0IHRoYXQgdGhlIHByb3BzIGFyZSB2YWxpZFxuICAgKlxuICAgKiBAcGFyYW0ge29iamVjdH0gcHJvcFR5cGVzIE1hcCBvZiBwcm9wIG5hbWUgdG8gYSBSZWFjdFByb3BUeXBlXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBwcm9wc1xuICAgKiBAcGFyYW0ge3N0cmluZ30gbG9jYXRpb24gZS5nLiBcInByb3BcIiwgXCJjb250ZXh0XCIsIFwiY2hpbGQgY29udGV4dFwiXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBfY2hlY2tQcm9wVHlwZXM6IGZ1bmN0aW9uKHByb3BUeXBlcywgcHJvcHMsIGxvY2F0aW9uKSB7XG4gICAgLy8gVE9ETzogU3RvcCB2YWxpZGF0aW5nIHByb3AgdHlwZXMgaGVyZSBhbmQgb25seSB1c2UgdGhlIGVsZW1lbnRcbiAgICAvLyB2YWxpZGF0aW9uLlxuICAgIHZhciBjb21wb25lbnROYW1lID0gdGhpcy5jb25zdHJ1Y3Rvci5kaXNwbGF5TmFtZTtcbiAgICBmb3IgKHZhciBwcm9wTmFtZSBpbiBwcm9wVHlwZXMpIHtcbiAgICAgIGlmIChwcm9wVHlwZXMuaGFzT3duUHJvcGVydHkocHJvcE5hbWUpKSB7XG4gICAgICAgIHZhciBlcnJvciA9XG4gICAgICAgICAgcHJvcFR5cGVzW3Byb3BOYW1lXShwcm9wcywgcHJvcE5hbWUsIGNvbXBvbmVudE5hbWUsIGxvY2F0aW9uKTtcbiAgICAgICAgaWYgKGVycm9yIGluc3RhbmNlb2YgRXJyb3IpIHtcbiAgICAgICAgICAvLyBXZSBtYXkgd2FudCB0byBleHRlbmQgdGhpcyBsb2dpYyBmb3Igc2ltaWxhciBlcnJvcnMgaW5cbiAgICAgICAgICAvLyByZW5kZXJDb21wb25lbnQgY2FsbHMsIHNvIEknbSBhYnN0cmFjdGluZyBpdCBhd2F5IGludG9cbiAgICAgICAgICAvLyBhIGZ1bmN0aW9uIHRvIG1pbmltaXplIHJlZmFjdG9yaW5nIGluIHRoZSBmdXR1cmVcbiAgICAgICAgICB2YXIgYWRkZW5kdW0gPSBnZXREZWNsYXJhdGlvbkVycm9yQWRkZW5kdW0odGhpcyk7XG4gICAgICAgICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IHdhcm5pbmcoZmFsc2UsIGVycm9yLm1lc3NhZ2UgKyBhZGRlbmR1bSkgOiBudWxsKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfSxcblxuICAvKipcbiAgICogSWYgYW55IG9mIGBfcGVuZGluZ0VsZW1lbnRgLCBgX3BlbmRpbmdTdGF0ZWAsIG9yIGBfcGVuZGluZ0ZvcmNlVXBkYXRlYFxuICAgKiBpcyBzZXQsIHVwZGF0ZSB0aGUgY29tcG9uZW50LlxuICAgKlxuICAgKiBAcGFyYW0ge1JlYWN0UmVjb25jaWxlVHJhbnNhY3Rpb259IHRyYW5zYWN0aW9uXG4gICAqIEBpbnRlcm5hbFxuICAgKi9cbiAgcGVyZm9ybVVwZGF0ZUlmTmVjZXNzYXJ5OiBmdW5jdGlvbih0cmFuc2FjdGlvbikge1xuICAgIHZhciBjb21wb3NpdGVMaWZlQ3ljbGVTdGF0ZSA9IHRoaXMuX2NvbXBvc2l0ZUxpZmVDeWNsZVN0YXRlO1xuICAgIC8vIERvIG5vdCB0cmlnZ2VyIGEgc3RhdGUgdHJhbnNpdGlvbiBpZiB3ZSBhcmUgaW4gdGhlIG1pZGRsZSBvZiBtb3VudGluZyBvclxuICAgIC8vIHJlY2VpdmluZyBwcm9wcyBiZWNhdXNlIGJvdGggb2YgdGhvc2Ugd2lsbCBhbHJlYWR5IGJlIGRvaW5nIHRoaXMuXG4gICAgaWYgKGNvbXBvc2l0ZUxpZmVDeWNsZVN0YXRlID09PSBDb21wb3NpdGVMaWZlQ3ljbGUuTU9VTlRJTkcgfHxcbiAgICAgICAgY29tcG9zaXRlTGlmZUN5Y2xlU3RhdGUgPT09IENvbXBvc2l0ZUxpZmVDeWNsZS5SRUNFSVZJTkdfUFJPUFMpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5fcGVuZGluZ0VsZW1lbnQgPT0gbnVsbCAmJlxuICAgICAgICB0aGlzLl9wZW5kaW5nU3RhdGUgPT0gbnVsbCAmJlxuICAgICAgICAhdGhpcy5fcGVuZGluZ0ZvcmNlVXBkYXRlKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdmFyIG5leHRDb250ZXh0ID0gdGhpcy5jb250ZXh0O1xuICAgIHZhciBuZXh0UHJvcHMgPSB0aGlzLnByb3BzO1xuICAgIHZhciBuZXh0RWxlbWVudCA9IHRoaXMuX2N1cnJlbnRFbGVtZW50O1xuICAgIGlmICh0aGlzLl9wZW5kaW5nRWxlbWVudCAhPSBudWxsKSB7XG4gICAgICBuZXh0RWxlbWVudCA9IHRoaXMuX3BlbmRpbmdFbGVtZW50O1xuICAgICAgbmV4dENvbnRleHQgPSB0aGlzLl9wcm9jZXNzQ29udGV4dChuZXh0RWxlbWVudC5fY29udGV4dCk7XG4gICAgICBuZXh0UHJvcHMgPSB0aGlzLl9wcm9jZXNzUHJvcHMobmV4dEVsZW1lbnQucHJvcHMpO1xuICAgICAgdGhpcy5fcGVuZGluZ0VsZW1lbnQgPSBudWxsO1xuXG4gICAgICB0aGlzLl9jb21wb3NpdGVMaWZlQ3ljbGVTdGF0ZSA9IENvbXBvc2l0ZUxpZmVDeWNsZS5SRUNFSVZJTkdfUFJPUFM7XG4gICAgICBpZiAodGhpcy5jb21wb25lbnRXaWxsUmVjZWl2ZVByb3BzKSB7XG4gICAgICAgIHRoaXMuY29tcG9uZW50V2lsbFJlY2VpdmVQcm9wcyhuZXh0UHJvcHMsIG5leHRDb250ZXh0KTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICB0aGlzLl9jb21wb3NpdGVMaWZlQ3ljbGVTdGF0ZSA9IG51bGw7XG5cbiAgICB2YXIgbmV4dFN0YXRlID0gdGhpcy5fcGVuZGluZ1N0YXRlIHx8IHRoaXMuc3RhdGU7XG4gICAgdGhpcy5fcGVuZGluZ1N0YXRlID0gbnVsbDtcblxuICAgIHZhciBzaG91bGRVcGRhdGUgPVxuICAgICAgdGhpcy5fcGVuZGluZ0ZvcmNlVXBkYXRlIHx8XG4gICAgICAhdGhpcy5zaG91bGRDb21wb25lbnRVcGRhdGUgfHxcbiAgICAgIHRoaXMuc2hvdWxkQ29tcG9uZW50VXBkYXRlKG5leHRQcm9wcywgbmV4dFN0YXRlLCBuZXh0Q29udGV4dCk7XG5cbiAgICBpZiAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WKSB7XG4gICAgICBpZiAodHlwZW9mIHNob3VsZFVwZGF0ZSA9PT0gXCJ1bmRlZmluZWRcIikge1xuICAgICAgICBjb25zb2xlLndhcm4oXG4gICAgICAgICAgKHRoaXMuY29uc3RydWN0b3IuZGlzcGxheU5hbWUgfHwgJ1JlYWN0Q29tcG9zaXRlQ29tcG9uZW50JykgK1xuICAgICAgICAgICcuc2hvdWxkQ29tcG9uZW50VXBkYXRlKCk6IFJldHVybmVkIHVuZGVmaW5lZCBpbnN0ZWFkIG9mIGEgJyArXG4gICAgICAgICAgJ2Jvb2xlYW4gdmFsdWUuIE1ha2Ugc3VyZSB0byByZXR1cm4gdHJ1ZSBvciBmYWxzZS4nXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKHNob3VsZFVwZGF0ZSkge1xuICAgICAgdGhpcy5fcGVuZGluZ0ZvcmNlVXBkYXRlID0gZmFsc2U7XG4gICAgICAvLyBXaWxsIHNldCBgdGhpcy5wcm9wc2AsIGB0aGlzLnN0YXRlYCBhbmQgYHRoaXMuY29udGV4dGAuXG4gICAgICB0aGlzLl9wZXJmb3JtQ29tcG9uZW50VXBkYXRlKFxuICAgICAgICBuZXh0RWxlbWVudCxcbiAgICAgICAgbmV4dFByb3BzLFxuICAgICAgICBuZXh0U3RhdGUsXG4gICAgICAgIG5leHRDb250ZXh0LFxuICAgICAgICB0cmFuc2FjdGlvblxuICAgICAgKTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gSWYgaXQncyBkZXRlcm1pbmVkIHRoYXQgYSBjb21wb25lbnQgc2hvdWxkIG5vdCB1cGRhdGUsIHdlIHN0aWxsIHdhbnRcbiAgICAgIC8vIHRvIHNldCBwcm9wcyBhbmQgc3RhdGUuXG4gICAgICB0aGlzLl9jdXJyZW50RWxlbWVudCA9IG5leHRFbGVtZW50O1xuICAgICAgdGhpcy5wcm9wcyA9IG5leHRQcm9wcztcbiAgICAgIHRoaXMuc3RhdGUgPSBuZXh0U3RhdGU7XG4gICAgICB0aGlzLmNvbnRleHQgPSBuZXh0Q29udGV4dDtcblxuICAgICAgLy8gT3duZXIgY2Fubm90IGNoYW5nZSBiZWNhdXNlIHNob3VsZFVwZGF0ZVJlYWN0Q29tcG9uZW50IGRvZXNuJ3QgYWxsb3dcbiAgICAgIC8vIGl0LiBUT0RPOiBSZW1vdmUgdGhpcy5fb3duZXIgY29tcGxldGVseS5cbiAgICAgIHRoaXMuX293bmVyID0gbmV4dEVsZW1lbnQuX293bmVyO1xuICAgIH1cbiAgfSxcblxuICAvKipcbiAgICogTWVyZ2VzIG5ldyBwcm9wcyBhbmQgc3RhdGUsIG5vdGlmaWVzIGRlbGVnYXRlIG1ldGhvZHMgb2YgdXBkYXRlIGFuZFxuICAgKiBwZXJmb3JtcyB1cGRhdGUuXG4gICAqXG4gICAqIEBwYXJhbSB7UmVhY3RFbGVtZW50fSBuZXh0RWxlbWVudCBOZXh0IGVsZW1lbnRcbiAgICogQHBhcmFtIHtvYmplY3R9IG5leHRQcm9wcyBOZXh0IHB1YmxpYyBvYmplY3QgdG8gc2V0IGFzIHByb3BlcnRpZXMuXG4gICAqIEBwYXJhbSB7P29iamVjdH0gbmV4dFN0YXRlIE5leHQgb2JqZWN0IHRvIHNldCBhcyBzdGF0ZS5cbiAgICogQHBhcmFtIHs/b2JqZWN0fSBuZXh0Q29udGV4dCBOZXh0IHB1YmxpYyBvYmplY3QgdG8gc2V0IGFzIGNvbnRleHQuXG4gICAqIEBwYXJhbSB7UmVhY3RSZWNvbmNpbGVUcmFuc2FjdGlvbn0gdHJhbnNhY3Rpb25cbiAgICogQHByaXZhdGVcbiAgICovXG4gIF9wZXJmb3JtQ29tcG9uZW50VXBkYXRlOiBmdW5jdGlvbihcbiAgICBuZXh0RWxlbWVudCxcbiAgICBuZXh0UHJvcHMsXG4gICAgbmV4dFN0YXRlLFxuICAgIG5leHRDb250ZXh0LFxuICAgIHRyYW5zYWN0aW9uXG4gICkge1xuICAgIHZhciBwcmV2RWxlbWVudCA9IHRoaXMuX2N1cnJlbnRFbGVtZW50O1xuICAgIHZhciBwcmV2UHJvcHMgPSB0aGlzLnByb3BzO1xuICAgIHZhciBwcmV2U3RhdGUgPSB0aGlzLnN0YXRlO1xuICAgIHZhciBwcmV2Q29udGV4dCA9IHRoaXMuY29udGV4dDtcblxuICAgIGlmICh0aGlzLmNvbXBvbmVudFdpbGxVcGRhdGUpIHtcbiAgICAgIHRoaXMuY29tcG9uZW50V2lsbFVwZGF0ZShuZXh0UHJvcHMsIG5leHRTdGF0ZSwgbmV4dENvbnRleHQpO1xuICAgIH1cblxuICAgIHRoaXMuX2N1cnJlbnRFbGVtZW50ID0gbmV4dEVsZW1lbnQ7XG4gICAgdGhpcy5wcm9wcyA9IG5leHRQcm9wcztcbiAgICB0aGlzLnN0YXRlID0gbmV4dFN0YXRlO1xuICAgIHRoaXMuY29udGV4dCA9IG5leHRDb250ZXh0O1xuXG4gICAgLy8gT3duZXIgY2Fubm90IGNoYW5nZSBiZWNhdXNlIHNob3VsZFVwZGF0ZVJlYWN0Q29tcG9uZW50IGRvZXNuJ3QgYWxsb3dcbiAgICAvLyBpdC4gVE9ETzogUmVtb3ZlIHRoaXMuX293bmVyIGNvbXBsZXRlbHkuXG4gICAgdGhpcy5fb3duZXIgPSBuZXh0RWxlbWVudC5fb3duZXI7XG5cbiAgICB0aGlzLnVwZGF0ZUNvbXBvbmVudChcbiAgICAgIHRyYW5zYWN0aW9uLFxuICAgICAgcHJldkVsZW1lbnRcbiAgICApO1xuXG4gICAgaWYgKHRoaXMuY29tcG9uZW50RGlkVXBkYXRlKSB7XG4gICAgICB0cmFuc2FjdGlvbi5nZXRSZWFjdE1vdW50UmVhZHkoKS5lbnF1ZXVlKFxuICAgICAgICB0aGlzLmNvbXBvbmVudERpZFVwZGF0ZS5iaW5kKHRoaXMsIHByZXZQcm9wcywgcHJldlN0YXRlLCBwcmV2Q29udGV4dCksXG4gICAgICAgIHRoaXNcbiAgICAgICk7XG4gICAgfVxuICB9LFxuXG4gIHJlY2VpdmVDb21wb25lbnQ6IGZ1bmN0aW9uKG5leHRFbGVtZW50LCB0cmFuc2FjdGlvbikge1xuICAgIGlmIChuZXh0RWxlbWVudCA9PT0gdGhpcy5fY3VycmVudEVsZW1lbnQgJiZcbiAgICAgICAgbmV4dEVsZW1lbnQuX293bmVyICE9IG51bGwpIHtcbiAgICAgIC8vIFNpbmNlIGVsZW1lbnRzIGFyZSBpbW11dGFibGUgYWZ0ZXIgdGhlIG93bmVyIGlzIHJlbmRlcmVkLFxuICAgICAgLy8gd2UgY2FuIGRvIGEgY2hlYXAgaWRlbnRpdHkgY29tcGFyZSBoZXJlIHRvIGRldGVybWluZSBpZiB0aGlzIGlzIGFcbiAgICAgIC8vIHN1cGVyZmx1b3VzIHJlY29uY2lsZS4gSXQncyBwb3NzaWJsZSBmb3Igc3RhdGUgdG8gYmUgbXV0YWJsZSBidXQgc3VjaFxuICAgICAgLy8gY2hhbmdlIHNob3VsZCB0cmlnZ2VyIGFuIHVwZGF0ZSBvZiB0aGUgb3duZXIgd2hpY2ggd291bGQgcmVjcmVhdGVcbiAgICAgIC8vIHRoZSBlbGVtZW50LiBXZSBleHBsaWNpdGx5IGNoZWNrIGZvciB0aGUgZXhpc3RlbmNlIG9mIGFuIG93bmVyIHNpbmNlXG4gICAgICAvLyBpdCdzIHBvc3NpYmxlIGZvciBhIGVsZW1lbnQgY3JlYXRlZCBvdXRzaWRlIGEgY29tcG9zaXRlIHRvIGJlXG4gICAgICAvLyBkZWVwbHkgbXV0YXRlZCBhbmQgcmV1c2VkLlxuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIFJlYWN0Q29tcG9uZW50Lk1peGluLnJlY2VpdmVDb21wb25lbnQuY2FsbChcbiAgICAgIHRoaXMsXG4gICAgICBuZXh0RWxlbWVudCxcbiAgICAgIHRyYW5zYWN0aW9uXG4gICAgKTtcbiAgfSxcblxuICAvKipcbiAgICogVXBkYXRlcyB0aGUgY29tcG9uZW50J3MgY3VycmVudGx5IG1vdW50ZWQgRE9NIHJlcHJlc2VudGF0aW9uLlxuICAgKlxuICAgKiBCeSBkZWZhdWx0LCB0aGlzIGltcGxlbWVudHMgUmVhY3QncyByZW5kZXJpbmcgYW5kIHJlY29uY2lsaWF0aW9uIGFsZ29yaXRobS5cbiAgICogU29waGlzdGljYXRlZCBjbGllbnRzIG1heSB3aXNoIHRvIG92ZXJyaWRlIHRoaXMuXG4gICAqXG4gICAqIEBwYXJhbSB7UmVhY3RSZWNvbmNpbGVUcmFuc2FjdGlvbn0gdHJhbnNhY3Rpb25cbiAgICogQHBhcmFtIHtSZWFjdEVsZW1lbnR9IHByZXZFbGVtZW50XG4gICAqIEBpbnRlcm5hbFxuICAgKiBAb3ZlcnJpZGFibGVcbiAgICovXG4gIHVwZGF0ZUNvbXBvbmVudDogUmVhY3RQZXJmLm1lYXN1cmUoXG4gICAgJ1JlYWN0Q29tcG9zaXRlQ29tcG9uZW50JyxcbiAgICAndXBkYXRlQ29tcG9uZW50JyxcbiAgICBmdW5jdGlvbih0cmFuc2FjdGlvbiwgcHJldlBhcmVudEVsZW1lbnQpIHtcbiAgICAgIFJlYWN0Q29tcG9uZW50Lk1peGluLnVwZGF0ZUNvbXBvbmVudC5jYWxsKFxuICAgICAgICB0aGlzLFxuICAgICAgICB0cmFuc2FjdGlvbixcbiAgICAgICAgcHJldlBhcmVudEVsZW1lbnRcbiAgICAgICk7XG5cbiAgICAgIHZhciBwcmV2Q29tcG9uZW50SW5zdGFuY2UgPSB0aGlzLl9yZW5kZXJlZENvbXBvbmVudDtcbiAgICAgIHZhciBwcmV2RWxlbWVudCA9IHByZXZDb21wb25lbnRJbnN0YW5jZS5fY3VycmVudEVsZW1lbnQ7XG4gICAgICB2YXIgbmV4dEVsZW1lbnQgPSB0aGlzLl9yZW5kZXJWYWxpZGF0ZWRDb21wb25lbnQoKTtcbiAgICAgIGlmIChzaG91bGRVcGRhdGVSZWFjdENvbXBvbmVudChwcmV2RWxlbWVudCwgbmV4dEVsZW1lbnQpKSB7XG4gICAgICAgIHByZXZDb21wb25lbnRJbnN0YW5jZS5yZWNlaXZlQ29tcG9uZW50KG5leHRFbGVtZW50LCB0cmFuc2FjdGlvbik7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBUaGVzZSB0d28gSURzIGFyZSBhY3R1YWxseSB0aGUgc2FtZSEgQnV0IG5vdGhpbmcgc2hvdWxkIHJlbHkgb24gdGhhdC5cbiAgICAgICAgdmFyIHRoaXNJRCA9IHRoaXMuX3Jvb3ROb2RlSUQ7XG4gICAgICAgIHZhciBwcmV2Q29tcG9uZW50SUQgPSBwcmV2Q29tcG9uZW50SW5zdGFuY2UuX3Jvb3ROb2RlSUQ7XG4gICAgICAgIHByZXZDb21wb25lbnRJbnN0YW5jZS51bm1vdW50Q29tcG9uZW50KCk7XG4gICAgICAgIHRoaXMuX3JlbmRlcmVkQ29tcG9uZW50ID0gaW5zdGFudGlhdGVSZWFjdENvbXBvbmVudChcbiAgICAgICAgICBuZXh0RWxlbWVudCxcbiAgICAgICAgICB0aGlzLl9jdXJyZW50RWxlbWVudC50eXBlXG4gICAgICAgICk7XG4gICAgICAgIHZhciBuZXh0TWFya3VwID0gdGhpcy5fcmVuZGVyZWRDb21wb25lbnQubW91bnRDb21wb25lbnQoXG4gICAgICAgICAgdGhpc0lELFxuICAgICAgICAgIHRyYW5zYWN0aW9uLFxuICAgICAgICAgIHRoaXMuX21vdW50RGVwdGggKyAxXG4gICAgICAgICk7XG4gICAgICAgIFJlYWN0Q29tcG9uZW50LkJhY2tlbmRJRE9wZXJhdGlvbnMuZGFuZ2Vyb3VzbHlSZXBsYWNlTm9kZVdpdGhNYXJrdXBCeUlEKFxuICAgICAgICAgIHByZXZDb21wb25lbnRJRCxcbiAgICAgICAgICBuZXh0TWFya3VwXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuICApLFxuXG4gIC8qKlxuICAgKiBGb3JjZXMgYW4gdXBkYXRlLiBUaGlzIHNob3VsZCBvbmx5IGJlIGludm9rZWQgd2hlbiBpdCBpcyBrbm93biB3aXRoXG4gICAqIGNlcnRhaW50eSB0aGF0IHdlIGFyZSAqKm5vdCoqIGluIGEgRE9NIHRyYW5zYWN0aW9uLlxuICAgKlxuICAgKiBZb3UgbWF5IHdhbnQgdG8gY2FsbCB0aGlzIHdoZW4geW91IGtub3cgdGhhdCBzb21lIGRlZXBlciBhc3BlY3Qgb2YgdGhlXG4gICAqIGNvbXBvbmVudCdzIHN0YXRlIGhhcyBjaGFuZ2VkIGJ1dCBgc2V0U3RhdGVgIHdhcyBub3QgY2FsbGVkLlxuICAgKlxuICAgKiBUaGlzIHdpbGwgbm90IGludm9rZSBgc2hvdWxkVXBkYXRlQ29tcG9uZW50YCwgYnV0IGl0IHdpbGwgaW52b2tlXG4gICAqIGBjb21wb25lbnRXaWxsVXBkYXRlYCBhbmQgYGNvbXBvbmVudERpZFVwZGF0ZWAuXG4gICAqXG4gICAqIEBwYXJhbSB7P2Z1bmN0aW9ufSBjYWxsYmFjayBDYWxsZWQgYWZ0ZXIgdXBkYXRlIGlzIGNvbXBsZXRlLlxuICAgKiBAZmluYWxcbiAgICogQHByb3RlY3RlZFxuICAgKi9cbiAgZm9yY2VVcGRhdGU6IGZ1bmN0aW9uKGNhbGxiYWNrKSB7XG4gICAgdmFyIGNvbXBvc2l0ZUxpZmVDeWNsZVN0YXRlID0gdGhpcy5fY29tcG9zaXRlTGlmZUN5Y2xlU3RhdGU7XG4gICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgIHRoaXMuaXNNb3VudGVkKCkgfHxcbiAgICAgICAgY29tcG9zaXRlTGlmZUN5Y2xlU3RhdGUgPT09IENvbXBvc2l0ZUxpZmVDeWNsZS5NT1VOVElORyxcbiAgICAgICdmb3JjZVVwZGF0ZSguLi4pOiBDYW4gb25seSBmb3JjZSBhbiB1cGRhdGUgb24gbW91bnRlZCBvciBtb3VudGluZyAnICtcbiAgICAgICAgJ2NvbXBvbmVudHMuJ1xuICAgICkgOiBpbnZhcmlhbnQodGhpcy5pc01vdW50ZWQoKSB8fFxuICAgICAgY29tcG9zaXRlTGlmZUN5Y2xlU3RhdGUgPT09IENvbXBvc2l0ZUxpZmVDeWNsZS5NT1VOVElORykpO1xuICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICBjb21wb3NpdGVMaWZlQ3ljbGVTdGF0ZSAhPT0gQ29tcG9zaXRlTGlmZUN5Y2xlLlVOTU9VTlRJTkcgJiZcbiAgICAgIFJlYWN0Q3VycmVudE93bmVyLmN1cnJlbnQgPT0gbnVsbCxcbiAgICAgICdmb3JjZVVwZGF0ZSguLi4pOiBDYW5ub3QgZm9yY2UgYW4gdXBkYXRlIHdoaWxlIHVubW91bnRpbmcgY29tcG9uZW50ICcgK1xuICAgICAgJ29yIHdpdGhpbiBhIGByZW5kZXJgIGZ1bmN0aW9uLidcbiAgICApIDogaW52YXJpYW50KGNvbXBvc2l0ZUxpZmVDeWNsZVN0YXRlICE9PSBDb21wb3NpdGVMaWZlQ3ljbGUuVU5NT1VOVElORyAmJlxuICAgIFJlYWN0Q3VycmVudE93bmVyLmN1cnJlbnQgPT0gbnVsbCkpO1xuICAgIHRoaXMuX3BlbmRpbmdGb3JjZVVwZGF0ZSA9IHRydWU7XG4gICAgUmVhY3RVcGRhdGVzLmVucXVldWVVcGRhdGUodGhpcywgY2FsbGJhY2spO1xuICB9LFxuXG4gIC8qKlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgX3JlbmRlclZhbGlkYXRlZENvbXBvbmVudDogUmVhY3RQZXJmLm1lYXN1cmUoXG4gICAgJ1JlYWN0Q29tcG9zaXRlQ29tcG9uZW50JyxcbiAgICAnX3JlbmRlclZhbGlkYXRlZENvbXBvbmVudCcsXG4gICAgZnVuY3Rpb24oKSB7XG4gICAgICB2YXIgcmVuZGVyZWRDb21wb25lbnQ7XG4gICAgICB2YXIgcHJldmlvdXNDb250ZXh0ID0gUmVhY3RDb250ZXh0LmN1cnJlbnQ7XG4gICAgICBSZWFjdENvbnRleHQuY3VycmVudCA9IHRoaXMuX3Byb2Nlc3NDaGlsZENvbnRleHQoXG4gICAgICAgIHRoaXMuX2N1cnJlbnRFbGVtZW50Ll9jb250ZXh0XG4gICAgICApO1xuICAgICAgUmVhY3RDdXJyZW50T3duZXIuY3VycmVudCA9IHRoaXM7XG4gICAgICB0cnkge1xuICAgICAgICByZW5kZXJlZENvbXBvbmVudCA9IHRoaXMucmVuZGVyKCk7XG4gICAgICAgIGlmIChyZW5kZXJlZENvbXBvbmVudCA9PT0gbnVsbCB8fCByZW5kZXJlZENvbXBvbmVudCA9PT0gZmFsc2UpIHtcbiAgICAgICAgICByZW5kZXJlZENvbXBvbmVudCA9IFJlYWN0RW1wdHlDb21wb25lbnQuZ2V0RW1wdHlDb21wb25lbnQoKTtcbiAgICAgICAgICBSZWFjdEVtcHR5Q29tcG9uZW50LnJlZ2lzdGVyTnVsbENvbXBvbmVudElEKHRoaXMuX3Jvb3ROb2RlSUQpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIFJlYWN0RW1wdHlDb21wb25lbnQuZGVyZWdpc3Rlck51bGxDb21wb25lbnRJRCh0aGlzLl9yb290Tm9kZUlEKTtcbiAgICAgICAgfVxuICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgUmVhY3RDb250ZXh0LmN1cnJlbnQgPSBwcmV2aW91c0NvbnRleHQ7XG4gICAgICAgIFJlYWN0Q3VycmVudE93bmVyLmN1cnJlbnQgPSBudWxsO1xuICAgICAgfVxuICAgICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgICAgUmVhY3RFbGVtZW50LmlzVmFsaWRFbGVtZW50KHJlbmRlcmVkQ29tcG9uZW50KSxcbiAgICAgICAgJyVzLnJlbmRlcigpOiBBIHZhbGlkIFJlYWN0Q29tcG9uZW50IG11c3QgYmUgcmV0dXJuZWQuIFlvdSBtYXkgaGF2ZSAnICtcbiAgICAgICAgICAncmV0dXJuZWQgdW5kZWZpbmVkLCBhbiBhcnJheSBvciBzb21lIG90aGVyIGludmFsaWQgb2JqZWN0LicsXG4gICAgICAgIHRoaXMuY29uc3RydWN0b3IuZGlzcGxheU5hbWUgfHwgJ1JlYWN0Q29tcG9zaXRlQ29tcG9uZW50J1xuICAgICAgKSA6IGludmFyaWFudChSZWFjdEVsZW1lbnQuaXNWYWxpZEVsZW1lbnQocmVuZGVyZWRDb21wb25lbnQpKSk7XG4gICAgICByZXR1cm4gcmVuZGVyZWRDb21wb25lbnQ7XG4gICAgfVxuICApLFxuXG4gIC8qKlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgX2JpbmRBdXRvQmluZE1ldGhvZHM6IGZ1bmN0aW9uKCkge1xuICAgIGZvciAodmFyIGF1dG9CaW5kS2V5IGluIHRoaXMuX19yZWFjdEF1dG9CaW5kTWFwKSB7XG4gICAgICBpZiAoIXRoaXMuX19yZWFjdEF1dG9CaW5kTWFwLmhhc093blByb3BlcnR5KGF1dG9CaW5kS2V5KSkge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cbiAgICAgIHZhciBtZXRob2QgPSB0aGlzLl9fcmVhY3RBdXRvQmluZE1hcFthdXRvQmluZEtleV07XG4gICAgICB0aGlzW2F1dG9CaW5kS2V5XSA9IHRoaXMuX2JpbmRBdXRvQmluZE1ldGhvZChSZWFjdEVycm9yVXRpbHMuZ3VhcmQoXG4gICAgICAgIG1ldGhvZCxcbiAgICAgICAgdGhpcy5jb25zdHJ1Y3Rvci5kaXNwbGF5TmFtZSArICcuJyArIGF1dG9CaW5kS2V5XG4gICAgICApKTtcbiAgICB9XG4gIH0sXG5cbiAgLyoqXG4gICAqIEJpbmRzIGEgbWV0aG9kIHRvIHRoZSBjb21wb25lbnQuXG4gICAqXG4gICAqIEBwYXJhbSB7ZnVuY3Rpb259IG1ldGhvZCBNZXRob2QgdG8gYmUgYm91bmQuXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBfYmluZEF1dG9CaW5kTWV0aG9kOiBmdW5jdGlvbihtZXRob2QpIHtcbiAgICB2YXIgY29tcG9uZW50ID0gdGhpcztcbiAgICB2YXIgYm91bmRNZXRob2QgPSBtZXRob2QuYmluZChjb21wb25lbnQpO1xuICAgIGlmIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYpIHtcbiAgICAgIGJvdW5kTWV0aG9kLl9fcmVhY3RCb3VuZENvbnRleHQgPSBjb21wb25lbnQ7XG4gICAgICBib3VuZE1ldGhvZC5fX3JlYWN0Qm91bmRNZXRob2QgPSBtZXRob2Q7XG4gICAgICBib3VuZE1ldGhvZC5fX3JlYWN0Qm91bmRBcmd1bWVudHMgPSBudWxsO1xuICAgICAgdmFyIGNvbXBvbmVudE5hbWUgPSBjb21wb25lbnQuY29uc3RydWN0b3IuZGlzcGxheU5hbWU7XG4gICAgICB2YXIgX2JpbmQgPSBib3VuZE1ldGhvZC5iaW5kO1xuICAgICAgYm91bmRNZXRob2QuYmluZCA9IGZ1bmN0aW9uKG5ld1RoaXMgKSB7Zm9yICh2YXIgYXJncz1bXSwkX18wPTEsJF9fMT1hcmd1bWVudHMubGVuZ3RoOyRfXzA8JF9fMTskX18wKyspIGFyZ3MucHVzaChhcmd1bWVudHNbJF9fMF0pO1xuICAgICAgICAvLyBVc2VyIGlzIHRyeWluZyB0byBiaW5kKCkgYW4gYXV0b2JvdW5kIG1ldGhvZDsgd2UgZWZmZWN0aXZlbHkgd2lsbFxuICAgICAgICAvLyBpZ25vcmUgdGhlIHZhbHVlIG9mIFwidGhpc1wiIHRoYXQgdGhlIHVzZXIgaXMgdHJ5aW5nIHRvIHVzZSwgc29cbiAgICAgICAgLy8gbGV0J3Mgd2Fybi5cbiAgICAgICAgaWYgKG5ld1RoaXMgIT09IGNvbXBvbmVudCAmJiBuZXdUaGlzICE9PSBudWxsKSB7XG4gICAgICAgICAgbW9uaXRvckNvZGVVc2UoJ3JlYWN0X2JpbmRfd2FybmluZycsIHsgY29tcG9uZW50OiBjb21wb25lbnROYW1lIH0pO1xuICAgICAgICAgIGNvbnNvbGUud2FybihcbiAgICAgICAgICAgICdiaW5kKCk6IFJlYWN0IGNvbXBvbmVudCBtZXRob2RzIG1heSBvbmx5IGJlIGJvdW5kIHRvIHRoZSAnICtcbiAgICAgICAgICAgICdjb21wb25lbnQgaW5zdGFuY2UuIFNlZSAnICsgY29tcG9uZW50TmFtZVxuICAgICAgICAgICk7XG4gICAgICAgIH0gZWxzZSBpZiAoIWFyZ3MubGVuZ3RoKSB7XG4gICAgICAgICAgbW9uaXRvckNvZGVVc2UoJ3JlYWN0X2JpbmRfd2FybmluZycsIHsgY29tcG9uZW50OiBjb21wb25lbnROYW1lIH0pO1xuICAgICAgICAgIGNvbnNvbGUud2FybihcbiAgICAgICAgICAgICdiaW5kKCk6IFlvdSBhcmUgYmluZGluZyBhIGNvbXBvbmVudCBtZXRob2QgdG8gdGhlIGNvbXBvbmVudC4gJyArXG4gICAgICAgICAgICAnUmVhY3QgZG9lcyB0aGlzIGZvciB5b3UgYXV0b21hdGljYWxseSBpbiBhIGhpZ2gtcGVyZm9ybWFuY2UgJyArXG4gICAgICAgICAgICAnd2F5LCBzbyB5b3UgY2FuIHNhZmVseSByZW1vdmUgdGhpcyBjYWxsLiBTZWUgJyArIGNvbXBvbmVudE5hbWVcbiAgICAgICAgICApO1xuICAgICAgICAgIHJldHVybiBib3VuZE1ldGhvZDtcbiAgICAgICAgfVxuICAgICAgICB2YXIgcmVib3VuZE1ldGhvZCA9IF9iaW5kLmFwcGx5KGJvdW5kTWV0aG9kLCBhcmd1bWVudHMpO1xuICAgICAgICByZWJvdW5kTWV0aG9kLl9fcmVhY3RCb3VuZENvbnRleHQgPSBjb21wb25lbnQ7XG4gICAgICAgIHJlYm91bmRNZXRob2QuX19yZWFjdEJvdW5kTWV0aG9kID0gbWV0aG9kO1xuICAgICAgICByZWJvdW5kTWV0aG9kLl9fcmVhY3RCb3VuZEFyZ3VtZW50cyA9IGFyZ3M7XG4gICAgICAgIHJldHVybiByZWJvdW5kTWV0aG9kO1xuICAgICAgfTtcbiAgICB9XG4gICAgcmV0dXJuIGJvdW5kTWV0aG9kO1xuICB9XG59O1xuXG52YXIgUmVhY3RDb21wb3NpdGVDb21wb25lbnRCYXNlID0gZnVuY3Rpb24oKSB7fTtcbmFzc2lnbihcbiAgUmVhY3RDb21wb3NpdGVDb21wb25lbnRCYXNlLnByb3RvdHlwZSxcbiAgUmVhY3RDb21wb25lbnQuTWl4aW4sXG4gIFJlYWN0T3duZXIuTWl4aW4sXG4gIFJlYWN0UHJvcFRyYW5zZmVyZXIuTWl4aW4sXG4gIFJlYWN0Q29tcG9zaXRlQ29tcG9uZW50TWl4aW5cbik7XG5cbi8qKlxuICogTW9kdWxlIGZvciBjcmVhdGluZyBjb21wb3NpdGUgY29tcG9uZW50cy5cbiAqXG4gKiBAY2xhc3MgUmVhY3RDb21wb3NpdGVDb21wb25lbnRcbiAqIEBleHRlbmRzIFJlYWN0Q29tcG9uZW50XG4gKiBAZXh0ZW5kcyBSZWFjdE93bmVyXG4gKiBAZXh0ZW5kcyBSZWFjdFByb3BUcmFuc2ZlcmVyXG4gKi9cbnZhciBSZWFjdENvbXBvc2l0ZUNvbXBvbmVudCA9IHtcblxuICBMaWZlQ3ljbGU6IENvbXBvc2l0ZUxpZmVDeWNsZSxcblxuICBCYXNlOiBSZWFjdENvbXBvc2l0ZUNvbXBvbmVudEJhc2UsXG5cbiAgLyoqXG4gICAqIENyZWF0ZXMgYSBjb21wb3NpdGUgY29tcG9uZW50IGNsYXNzIGdpdmVuIGEgY2xhc3Mgc3BlY2lmaWNhdGlvbi5cbiAgICpcbiAgICogQHBhcmFtIHtvYmplY3R9IHNwZWMgQ2xhc3Mgc3BlY2lmaWNhdGlvbiAod2hpY2ggbXVzdCBkZWZpbmUgYHJlbmRlcmApLlxuICAgKiBAcmV0dXJuIHtmdW5jdGlvbn0gQ29tcG9uZW50IGNvbnN0cnVjdG9yIGZ1bmN0aW9uLlxuICAgKiBAcHVibGljXG4gICAqL1xuICBjcmVhdGVDbGFzczogZnVuY3Rpb24oc3BlYykge1xuICAgIHZhciBDb25zdHJ1Y3RvciA9IGZ1bmN0aW9uKHByb3BzKSB7XG4gICAgICAvLyBUaGlzIGNvbnN0cnVjdG9yIGlzIG92ZXJyaWRkZW4gYnkgbW9ja3MuIFRoZSBhcmd1bWVudCBpcyB1c2VkXG4gICAgICAvLyBieSBtb2NrcyB0byBhc3NlcnQgb24gd2hhdCBnZXRzIG1vdW50ZWQuIFRoaXMgd2lsbCBsYXRlciBiZSB1c2VkXG4gICAgICAvLyBieSB0aGUgc3RhbmQtYWxvbmUgY2xhc3MgaW1wbGVtZW50YXRpb24uXG4gICAgfTtcbiAgICBDb25zdHJ1Y3Rvci5wcm90b3R5cGUgPSBuZXcgUmVhY3RDb21wb3NpdGVDb21wb25lbnRCYXNlKCk7XG4gICAgQ29uc3RydWN0b3IucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gQ29uc3RydWN0b3I7XG5cbiAgICBpbmplY3RlZE1peGlucy5mb3JFYWNoKFxuICAgICAgbWl4U3BlY0ludG9Db21wb25lbnQuYmluZChudWxsLCBDb25zdHJ1Y3RvcilcbiAgICApO1xuXG4gICAgbWl4U3BlY0ludG9Db21wb25lbnQoQ29uc3RydWN0b3IsIHNwZWMpO1xuXG4gICAgLy8gSW5pdGlhbGl6ZSB0aGUgZGVmYXVsdFByb3BzIHByb3BlcnR5IGFmdGVyIGFsbCBtaXhpbnMgaGF2ZSBiZWVuIG1lcmdlZFxuICAgIGlmIChDb25zdHJ1Y3Rvci5nZXREZWZhdWx0UHJvcHMpIHtcbiAgICAgIENvbnN0cnVjdG9yLmRlZmF1bHRQcm9wcyA9IENvbnN0cnVjdG9yLmdldERlZmF1bHRQcm9wcygpO1xuICAgIH1cblxuICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICBDb25zdHJ1Y3Rvci5wcm90b3R5cGUucmVuZGVyLFxuICAgICAgJ2NyZWF0ZUNsYXNzKC4uLik6IENsYXNzIHNwZWNpZmljYXRpb24gbXVzdCBpbXBsZW1lbnQgYSBgcmVuZGVyYCBtZXRob2QuJ1xuICAgICkgOiBpbnZhcmlhbnQoQ29uc3RydWN0b3IucHJvdG90eXBlLnJlbmRlcikpO1xuXG4gICAgaWYgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOVikge1xuICAgICAgaWYgKENvbnN0cnVjdG9yLnByb3RvdHlwZS5jb21wb25lbnRTaG91bGRVcGRhdGUpIHtcbiAgICAgICAgbW9uaXRvckNvZGVVc2UoXG4gICAgICAgICAgJ3JlYWN0X2NvbXBvbmVudF9zaG91bGRfdXBkYXRlX3dhcm5pbmcnLFxuICAgICAgICAgIHsgY29tcG9uZW50OiBzcGVjLmRpc3BsYXlOYW1lIH1cbiAgICAgICAgKTtcbiAgICAgICAgY29uc29sZS53YXJuKFxuICAgICAgICAgIChzcGVjLmRpc3BsYXlOYW1lIHx8ICdBIGNvbXBvbmVudCcpICsgJyBoYXMgYSBtZXRob2QgY2FsbGVkICcgK1xuICAgICAgICAgICdjb21wb25lbnRTaG91bGRVcGRhdGUoKS4gRGlkIHlvdSBtZWFuIHNob3VsZENvbXBvbmVudFVwZGF0ZSgpPyAnICtcbiAgICAgICAgICAnVGhlIG5hbWUgaXMgcGhyYXNlZCBhcyBhIHF1ZXN0aW9uIGJlY2F1c2UgdGhlIGZ1bmN0aW9uIGlzICcgK1xuICAgICAgICAgICdleHBlY3RlZCB0byByZXR1cm4gYSB2YWx1ZS4nXG4gICAgICAgICApO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIFJlZHVjZSB0aW1lIHNwZW50IGRvaW5nIGxvb2t1cHMgYnkgc2V0dGluZyB0aGVzZSBvbiB0aGUgcHJvdG90eXBlLlxuICAgIGZvciAodmFyIG1ldGhvZE5hbWUgaW4gUmVhY3RDb21wb3NpdGVDb21wb25lbnRJbnRlcmZhY2UpIHtcbiAgICAgIGlmICghQ29uc3RydWN0b3IucHJvdG90eXBlW21ldGhvZE5hbWVdKSB7XG4gICAgICAgIENvbnN0cnVjdG9yLnByb3RvdHlwZVttZXRob2ROYW1lXSA9IG51bGw7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOVikge1xuICAgICAgcmV0dXJuIFJlYWN0TGVnYWN5RWxlbWVudC53cmFwRmFjdG9yeShcbiAgICAgICAgUmVhY3RFbGVtZW50VmFsaWRhdG9yLmNyZWF0ZUZhY3RvcnkoQ29uc3RydWN0b3IpXG4gICAgICApO1xuICAgIH1cbiAgICByZXR1cm4gUmVhY3RMZWdhY3lFbGVtZW50LndyYXBGYWN0b3J5KFxuICAgICAgUmVhY3RFbGVtZW50LmNyZWF0ZUZhY3RvcnkoQ29uc3RydWN0b3IpXG4gICAgKTtcbiAgfSxcblxuICBpbmplY3Rpb246IHtcbiAgICBpbmplY3RNaXhpbjogZnVuY3Rpb24obWl4aW4pIHtcbiAgICAgIGluamVjdGVkTWl4aW5zLnB1c2gobWl4aW4pO1xuICAgIH1cbiAgfVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBSZWFjdENvbXBvc2l0ZUNvbXBvbmVudDtcblxufSkuY2FsbCh0aGlzLHJlcXVpcmUoJ19wcm9jZXNzJykpIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIFJlYWN0Q29udGV4dFxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgYXNzaWduID0gcmVxdWlyZShcIi4vT2JqZWN0LmFzc2lnblwiKTtcblxuLyoqXG4gKiBLZWVwcyB0cmFjayBvZiB0aGUgY3VycmVudCBjb250ZXh0LlxuICpcbiAqIFRoZSBjb250ZXh0IGlzIGF1dG9tYXRpY2FsbHkgcGFzc2VkIGRvd24gdGhlIGNvbXBvbmVudCBvd25lcnNoaXAgaGllcmFyY2h5XG4gKiBhbmQgaXMgYWNjZXNzaWJsZSB2aWEgYHRoaXMuY29udGV4dGAgb24gUmVhY3RDb21wb3NpdGVDb21wb25lbnRzLlxuICovXG52YXIgUmVhY3RDb250ZXh0ID0ge1xuXG4gIC8qKlxuICAgKiBAaW50ZXJuYWxcbiAgICogQHR5cGUge29iamVjdH1cbiAgICovXG4gIGN1cnJlbnQ6IHt9LFxuXG4gIC8qKlxuICAgKiBUZW1wb3JhcmlseSBleHRlbmRzIHRoZSBjdXJyZW50IGNvbnRleHQgd2hpbGUgZXhlY3V0aW5nIHNjb3BlZENhbGxiYWNrLlxuICAgKlxuICAgKiBBIHR5cGljYWwgdXNlIGNhc2UgbWlnaHQgbG9vayBsaWtlXG4gICAqXG4gICAqICByZW5kZXI6IGZ1bmN0aW9uKCkge1xuICAgKiAgICB2YXIgY2hpbGRyZW4gPSBSZWFjdENvbnRleHQud2l0aENvbnRleHQoe2ZvbzogJ2Zvbyd9LCAoKSA9PiAoXG4gICAqXG4gICAqICAgICkpO1xuICAgKiAgICByZXR1cm4gPGRpdj57Y2hpbGRyZW59PC9kaXY+O1xuICAgKiAgfVxuICAgKlxuICAgKiBAcGFyYW0ge29iamVjdH0gbmV3Q29udGV4dCBOZXcgY29udGV4dCB0byBtZXJnZSBpbnRvIHRoZSBleGlzdGluZyBjb250ZXh0XG4gICAqIEBwYXJhbSB7ZnVuY3Rpb259IHNjb3BlZENhbGxiYWNrIENhbGxiYWNrIHRvIHJ1biB3aXRoIHRoZSBuZXcgY29udGV4dFxuICAgKiBAcmV0dXJuIHtSZWFjdENvbXBvbmVudHxhcnJheTxSZWFjdENvbXBvbmVudD59XG4gICAqL1xuICB3aXRoQ29udGV4dDogZnVuY3Rpb24obmV3Q29udGV4dCwgc2NvcGVkQ2FsbGJhY2spIHtcbiAgICB2YXIgcmVzdWx0O1xuICAgIHZhciBwcmV2aW91c0NvbnRleHQgPSBSZWFjdENvbnRleHQuY3VycmVudDtcbiAgICBSZWFjdENvbnRleHQuY3VycmVudCA9IGFzc2lnbih7fSwgcHJldmlvdXNDb250ZXh0LCBuZXdDb250ZXh0KTtcbiAgICB0cnkge1xuICAgICAgcmVzdWx0ID0gc2NvcGVkQ2FsbGJhY2soKTtcbiAgICB9IGZpbmFsbHkge1xuICAgICAgUmVhY3RDb250ZXh0LmN1cnJlbnQgPSBwcmV2aW91c0NvbnRleHQ7XG4gICAgfVxuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cblxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBSZWFjdENvbnRleHQ7XG4iLCIvKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgUmVhY3RDdXJyZW50T3duZXJcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxuLyoqXG4gKiBLZWVwcyB0cmFjayBvZiB0aGUgY3VycmVudCBvd25lci5cbiAqXG4gKiBUaGUgY3VycmVudCBvd25lciBpcyB0aGUgY29tcG9uZW50IHdobyBzaG91bGQgb3duIGFueSBjb21wb25lbnRzIHRoYXQgYXJlXG4gKiBjdXJyZW50bHkgYmVpbmcgY29uc3RydWN0ZWQuXG4gKlxuICogVGhlIGRlcHRoIGluZGljYXRlIGhvdyBtYW55IGNvbXBvc2l0ZSBjb21wb25lbnRzIGFyZSBhYm92ZSB0aGlzIHJlbmRlciBsZXZlbC5cbiAqL1xudmFyIFJlYWN0Q3VycmVudE93bmVyID0ge1xuXG4gIC8qKlxuICAgKiBAaW50ZXJuYWxcbiAgICogQHR5cGUge1JlYWN0Q29tcG9uZW50fVxuICAgKi9cbiAgY3VycmVudDogbnVsbFxuXG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJlYWN0Q3VycmVudE93bmVyO1xuIiwiKGZ1bmN0aW9uIChwcm9jZXNzKXtcbi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBSZWFjdERPTVxuICogQHR5cGVjaGVja3Mgc3RhdGljLW9ubHlcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIFJlYWN0RWxlbWVudCA9IHJlcXVpcmUoXCIuL1JlYWN0RWxlbWVudFwiKTtcbnZhciBSZWFjdEVsZW1lbnRWYWxpZGF0b3IgPSByZXF1aXJlKFwiLi9SZWFjdEVsZW1lbnRWYWxpZGF0b3JcIik7XG52YXIgUmVhY3RMZWdhY3lFbGVtZW50ID0gcmVxdWlyZShcIi4vUmVhY3RMZWdhY3lFbGVtZW50XCIpO1xuXG52YXIgbWFwT2JqZWN0ID0gcmVxdWlyZShcIi4vbWFwT2JqZWN0XCIpO1xuXG4vKipcbiAqIENyZWF0ZSBhIGZhY3RvcnkgdGhhdCBjcmVhdGVzIEhUTUwgdGFnIGVsZW1lbnRzLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSB0YWcgVGFnIG5hbWUgKGUuZy4gYGRpdmApLlxuICogQHByaXZhdGVcbiAqL1xuZnVuY3Rpb24gY3JlYXRlRE9NRmFjdG9yeSh0YWcpIHtcbiAgaWYgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOVikge1xuICAgIHJldHVybiBSZWFjdExlZ2FjeUVsZW1lbnQubWFya05vbkxlZ2FjeUZhY3RvcnkoXG4gICAgICBSZWFjdEVsZW1lbnRWYWxpZGF0b3IuY3JlYXRlRmFjdG9yeSh0YWcpXG4gICAgKTtcbiAgfVxuICByZXR1cm4gUmVhY3RMZWdhY3lFbGVtZW50Lm1hcmtOb25MZWdhY3lGYWN0b3J5KFxuICAgIFJlYWN0RWxlbWVudC5jcmVhdGVGYWN0b3J5KHRhZylcbiAgKTtcbn1cblxuLyoqXG4gKiBDcmVhdGVzIGEgbWFwcGluZyBmcm9tIHN1cHBvcnRlZCBIVE1MIHRhZ3MgdG8gYFJlYWN0RE9NQ29tcG9uZW50YCBjbGFzc2VzLlxuICogVGhpcyBpcyBhbHNvIGFjY2Vzc2libGUgdmlhIGBSZWFjdC5ET01gLlxuICpcbiAqIEBwdWJsaWNcbiAqL1xudmFyIFJlYWN0RE9NID0gbWFwT2JqZWN0KHtcbiAgYTogJ2EnLFxuICBhYmJyOiAnYWJicicsXG4gIGFkZHJlc3M6ICdhZGRyZXNzJyxcbiAgYXJlYTogJ2FyZWEnLFxuICBhcnRpY2xlOiAnYXJ0aWNsZScsXG4gIGFzaWRlOiAnYXNpZGUnLFxuICBhdWRpbzogJ2F1ZGlvJyxcbiAgYjogJ2InLFxuICBiYXNlOiAnYmFzZScsXG4gIGJkaTogJ2JkaScsXG4gIGJkbzogJ2JkbycsXG4gIGJpZzogJ2JpZycsXG4gIGJsb2NrcXVvdGU6ICdibG9ja3F1b3RlJyxcbiAgYm9keTogJ2JvZHknLFxuICBicjogJ2JyJyxcbiAgYnV0dG9uOiAnYnV0dG9uJyxcbiAgY2FudmFzOiAnY2FudmFzJyxcbiAgY2FwdGlvbjogJ2NhcHRpb24nLFxuICBjaXRlOiAnY2l0ZScsXG4gIGNvZGU6ICdjb2RlJyxcbiAgY29sOiAnY29sJyxcbiAgY29sZ3JvdXA6ICdjb2xncm91cCcsXG4gIGRhdGE6ICdkYXRhJyxcbiAgZGF0YWxpc3Q6ICdkYXRhbGlzdCcsXG4gIGRkOiAnZGQnLFxuICBkZWw6ICdkZWwnLFxuICBkZXRhaWxzOiAnZGV0YWlscycsXG4gIGRmbjogJ2RmbicsXG4gIGRpYWxvZzogJ2RpYWxvZycsXG4gIGRpdjogJ2RpdicsXG4gIGRsOiAnZGwnLFxuICBkdDogJ2R0JyxcbiAgZW06ICdlbScsXG4gIGVtYmVkOiAnZW1iZWQnLFxuICBmaWVsZHNldDogJ2ZpZWxkc2V0JyxcbiAgZmlnY2FwdGlvbjogJ2ZpZ2NhcHRpb24nLFxuICBmaWd1cmU6ICdmaWd1cmUnLFxuICBmb290ZXI6ICdmb290ZXInLFxuICBmb3JtOiAnZm9ybScsXG4gIGgxOiAnaDEnLFxuICBoMjogJ2gyJyxcbiAgaDM6ICdoMycsXG4gIGg0OiAnaDQnLFxuICBoNTogJ2g1JyxcbiAgaDY6ICdoNicsXG4gIGhlYWQ6ICdoZWFkJyxcbiAgaGVhZGVyOiAnaGVhZGVyJyxcbiAgaHI6ICdocicsXG4gIGh0bWw6ICdodG1sJyxcbiAgaTogJ2knLFxuICBpZnJhbWU6ICdpZnJhbWUnLFxuICBpbWc6ICdpbWcnLFxuICBpbnB1dDogJ2lucHV0JyxcbiAgaW5zOiAnaW5zJyxcbiAga2JkOiAna2JkJyxcbiAga2V5Z2VuOiAna2V5Z2VuJyxcbiAgbGFiZWw6ICdsYWJlbCcsXG4gIGxlZ2VuZDogJ2xlZ2VuZCcsXG4gIGxpOiAnbGknLFxuICBsaW5rOiAnbGluaycsXG4gIG1haW46ICdtYWluJyxcbiAgbWFwOiAnbWFwJyxcbiAgbWFyazogJ21hcmsnLFxuICBtZW51OiAnbWVudScsXG4gIG1lbnVpdGVtOiAnbWVudWl0ZW0nLFxuICBtZXRhOiAnbWV0YScsXG4gIG1ldGVyOiAnbWV0ZXInLFxuICBuYXY6ICduYXYnLFxuICBub3NjcmlwdDogJ25vc2NyaXB0JyxcbiAgb2JqZWN0OiAnb2JqZWN0JyxcbiAgb2w6ICdvbCcsXG4gIG9wdGdyb3VwOiAnb3B0Z3JvdXAnLFxuICBvcHRpb246ICdvcHRpb24nLFxuICBvdXRwdXQ6ICdvdXRwdXQnLFxuICBwOiAncCcsXG4gIHBhcmFtOiAncGFyYW0nLFxuICBwaWN0dXJlOiAncGljdHVyZScsXG4gIHByZTogJ3ByZScsXG4gIHByb2dyZXNzOiAncHJvZ3Jlc3MnLFxuICBxOiAncScsXG4gIHJwOiAncnAnLFxuICBydDogJ3J0JyxcbiAgcnVieTogJ3J1YnknLFxuICBzOiAncycsXG4gIHNhbXA6ICdzYW1wJyxcbiAgc2NyaXB0OiAnc2NyaXB0JyxcbiAgc2VjdGlvbjogJ3NlY3Rpb24nLFxuICBzZWxlY3Q6ICdzZWxlY3QnLFxuICBzbWFsbDogJ3NtYWxsJyxcbiAgc291cmNlOiAnc291cmNlJyxcbiAgc3BhbjogJ3NwYW4nLFxuICBzdHJvbmc6ICdzdHJvbmcnLFxuICBzdHlsZTogJ3N0eWxlJyxcbiAgc3ViOiAnc3ViJyxcbiAgc3VtbWFyeTogJ3N1bW1hcnknLFxuICBzdXA6ICdzdXAnLFxuICB0YWJsZTogJ3RhYmxlJyxcbiAgdGJvZHk6ICd0Ym9keScsXG4gIHRkOiAndGQnLFxuICB0ZXh0YXJlYTogJ3RleHRhcmVhJyxcbiAgdGZvb3Q6ICd0Zm9vdCcsXG4gIHRoOiAndGgnLFxuICB0aGVhZDogJ3RoZWFkJyxcbiAgdGltZTogJ3RpbWUnLFxuICB0aXRsZTogJ3RpdGxlJyxcbiAgdHI6ICd0cicsXG4gIHRyYWNrOiAndHJhY2snLFxuICB1OiAndScsXG4gIHVsOiAndWwnLFxuICAndmFyJzogJ3ZhcicsXG4gIHZpZGVvOiAndmlkZW8nLFxuICB3YnI6ICd3YnInLFxuXG4gIC8vIFNWR1xuICBjaXJjbGU6ICdjaXJjbGUnLFxuICBkZWZzOiAnZGVmcycsXG4gIGVsbGlwc2U6ICdlbGxpcHNlJyxcbiAgZzogJ2cnLFxuICBsaW5lOiAnbGluZScsXG4gIGxpbmVhckdyYWRpZW50OiAnbGluZWFyR3JhZGllbnQnLFxuICBtYXNrOiAnbWFzaycsXG4gIHBhdGg6ICdwYXRoJyxcbiAgcGF0dGVybjogJ3BhdHRlcm4nLFxuICBwb2x5Z29uOiAncG9seWdvbicsXG4gIHBvbHlsaW5lOiAncG9seWxpbmUnLFxuICByYWRpYWxHcmFkaWVudDogJ3JhZGlhbEdyYWRpZW50JyxcbiAgcmVjdDogJ3JlY3QnLFxuICBzdG9wOiAnc3RvcCcsXG4gIHN2ZzogJ3N2ZycsXG4gIHRleHQ6ICd0ZXh0JyxcbiAgdHNwYW46ICd0c3BhbidcblxufSwgY3JlYXRlRE9NRmFjdG9yeSk7XG5cbm1vZHVsZS5leHBvcnRzID0gUmVhY3RET007XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKCdfcHJvY2VzcycpKSIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBSZWFjdERPTUJ1dHRvblxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgQXV0b0ZvY3VzTWl4aW4gPSByZXF1aXJlKFwiLi9BdXRvRm9jdXNNaXhpblwiKTtcbnZhciBSZWFjdEJyb3dzZXJDb21wb25lbnRNaXhpbiA9IHJlcXVpcmUoXCIuL1JlYWN0QnJvd3NlckNvbXBvbmVudE1peGluXCIpO1xudmFyIFJlYWN0Q29tcG9zaXRlQ29tcG9uZW50ID0gcmVxdWlyZShcIi4vUmVhY3RDb21wb3NpdGVDb21wb25lbnRcIik7XG52YXIgUmVhY3RFbGVtZW50ID0gcmVxdWlyZShcIi4vUmVhY3RFbGVtZW50XCIpO1xudmFyIFJlYWN0RE9NID0gcmVxdWlyZShcIi4vUmVhY3RET01cIik7XG5cbnZhciBrZXlNaXJyb3IgPSByZXF1aXJlKFwiLi9rZXlNaXJyb3JcIik7XG5cbi8vIFN0b3JlIGEgcmVmZXJlbmNlIHRvIHRoZSA8YnV0dG9uPiBgUmVhY3RET01Db21wb25lbnRgLiBUT0RPOiB1c2Ugc3RyaW5nXG52YXIgYnV0dG9uID0gUmVhY3RFbGVtZW50LmNyZWF0ZUZhY3RvcnkoUmVhY3RET00uYnV0dG9uLnR5cGUpO1xuXG52YXIgbW91c2VMaXN0ZW5lck5hbWVzID0ga2V5TWlycm9yKHtcbiAgb25DbGljazogdHJ1ZSxcbiAgb25Eb3VibGVDbGljazogdHJ1ZSxcbiAgb25Nb3VzZURvd246IHRydWUsXG4gIG9uTW91c2VNb3ZlOiB0cnVlLFxuICBvbk1vdXNlVXA6IHRydWUsXG4gIG9uQ2xpY2tDYXB0dXJlOiB0cnVlLFxuICBvbkRvdWJsZUNsaWNrQ2FwdHVyZTogdHJ1ZSxcbiAgb25Nb3VzZURvd25DYXB0dXJlOiB0cnVlLFxuICBvbk1vdXNlTW92ZUNhcHR1cmU6IHRydWUsXG4gIG9uTW91c2VVcENhcHR1cmU6IHRydWVcbn0pO1xuXG4vKipcbiAqIEltcGxlbWVudHMgYSA8YnV0dG9uPiBuYXRpdmUgY29tcG9uZW50IHRoYXQgZG9lcyBub3QgcmVjZWl2ZSBtb3VzZSBldmVudHNcbiAqIHdoZW4gYGRpc2FibGVkYCBpcyBzZXQuXG4gKi9cbnZhciBSZWFjdERPTUJ1dHRvbiA9IFJlYWN0Q29tcG9zaXRlQ29tcG9uZW50LmNyZWF0ZUNsYXNzKHtcbiAgZGlzcGxheU5hbWU6ICdSZWFjdERPTUJ1dHRvbicsXG5cbiAgbWl4aW5zOiBbQXV0b0ZvY3VzTWl4aW4sIFJlYWN0QnJvd3NlckNvbXBvbmVudE1peGluXSxcblxuICByZW5kZXI6IGZ1bmN0aW9uKCkge1xuICAgIHZhciBwcm9wcyA9IHt9O1xuXG4gICAgLy8gQ29weSB0aGUgcHJvcHM7IGV4Y2VwdCB0aGUgbW91c2UgbGlzdGVuZXJzIGlmIHdlJ3JlIGRpc2FibGVkXG4gICAgZm9yICh2YXIga2V5IGluIHRoaXMucHJvcHMpIHtcbiAgICAgIGlmICh0aGlzLnByb3BzLmhhc093blByb3BlcnR5KGtleSkgJiZcbiAgICAgICAgICAoIXRoaXMucHJvcHMuZGlzYWJsZWQgfHwgIW1vdXNlTGlzdGVuZXJOYW1lc1trZXldKSkge1xuICAgICAgICBwcm9wc1trZXldID0gdGhpcy5wcm9wc1trZXldO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBidXR0b24ocHJvcHMsIHRoaXMucHJvcHMuY2hpbGRyZW4pO1xuICB9XG5cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJlYWN0RE9NQnV0dG9uO1xuIiwiKGZ1bmN0aW9uIChwcm9jZXNzKXtcbi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBSZWFjdERPTUNvbXBvbmVudFxuICogQHR5cGVjaGVja3Mgc3RhdGljLW9ubHlcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIENTU1Byb3BlcnR5T3BlcmF0aW9ucyA9IHJlcXVpcmUoXCIuL0NTU1Byb3BlcnR5T3BlcmF0aW9uc1wiKTtcbnZhciBET01Qcm9wZXJ0eSA9IHJlcXVpcmUoXCIuL0RPTVByb3BlcnR5XCIpO1xudmFyIERPTVByb3BlcnR5T3BlcmF0aW9ucyA9IHJlcXVpcmUoXCIuL0RPTVByb3BlcnR5T3BlcmF0aW9uc1wiKTtcbnZhciBSZWFjdEJyb3dzZXJDb21wb25lbnRNaXhpbiA9IHJlcXVpcmUoXCIuL1JlYWN0QnJvd3NlckNvbXBvbmVudE1peGluXCIpO1xudmFyIFJlYWN0Q29tcG9uZW50ID0gcmVxdWlyZShcIi4vUmVhY3RDb21wb25lbnRcIik7XG52YXIgUmVhY3RCcm93c2VyRXZlbnRFbWl0dGVyID0gcmVxdWlyZShcIi4vUmVhY3RCcm93c2VyRXZlbnRFbWl0dGVyXCIpO1xudmFyIFJlYWN0TW91bnQgPSByZXF1aXJlKFwiLi9SZWFjdE1vdW50XCIpO1xudmFyIFJlYWN0TXVsdGlDaGlsZCA9IHJlcXVpcmUoXCIuL1JlYWN0TXVsdGlDaGlsZFwiKTtcbnZhciBSZWFjdFBlcmYgPSByZXF1aXJlKFwiLi9SZWFjdFBlcmZcIik7XG5cbnZhciBhc3NpZ24gPSByZXF1aXJlKFwiLi9PYmplY3QuYXNzaWduXCIpO1xudmFyIGVzY2FwZVRleHRGb3JCcm93c2VyID0gcmVxdWlyZShcIi4vZXNjYXBlVGV4dEZvckJyb3dzZXJcIik7XG52YXIgaW52YXJpYW50ID0gcmVxdWlyZShcIi4vaW52YXJpYW50XCIpO1xudmFyIGlzRXZlbnRTdXBwb3J0ZWQgPSByZXF1aXJlKFwiLi9pc0V2ZW50U3VwcG9ydGVkXCIpO1xudmFyIGtleU9mID0gcmVxdWlyZShcIi4va2V5T2ZcIik7XG52YXIgbW9uaXRvckNvZGVVc2UgPSByZXF1aXJlKFwiLi9tb25pdG9yQ29kZVVzZVwiKTtcblxudmFyIGRlbGV0ZUxpc3RlbmVyID0gUmVhY3RCcm93c2VyRXZlbnRFbWl0dGVyLmRlbGV0ZUxpc3RlbmVyO1xudmFyIGxpc3RlblRvID0gUmVhY3RCcm93c2VyRXZlbnRFbWl0dGVyLmxpc3RlblRvO1xudmFyIHJlZ2lzdHJhdGlvbk5hbWVNb2R1bGVzID0gUmVhY3RCcm93c2VyRXZlbnRFbWl0dGVyLnJlZ2lzdHJhdGlvbk5hbWVNb2R1bGVzO1xuXG4vLyBGb3IgcXVpY2tseSBtYXRjaGluZyBjaGlsZHJlbiB0eXBlLCB0byB0ZXN0IGlmIGNhbiBiZSB0cmVhdGVkIGFzIGNvbnRlbnQuXG52YXIgQ09OVEVOVF9UWVBFUyA9IHsnc3RyaW5nJzogdHJ1ZSwgJ251bWJlcic6IHRydWV9O1xuXG52YXIgU1RZTEUgPSBrZXlPZih7c3R5bGU6IG51bGx9KTtcblxudmFyIEVMRU1FTlRfTk9ERV9UWVBFID0gMTtcblxuLyoqXG4gKiBAcGFyYW0gez9vYmplY3R9IHByb3BzXG4gKi9cbmZ1bmN0aW9uIGFzc2VydFZhbGlkUHJvcHMocHJvcHMpIHtcbiAgaWYgKCFwcm9wcykge1xuICAgIHJldHVybjtcbiAgfVxuICAvLyBOb3RlIHRoZSB1c2Ugb2YgYD09YCB3aGljaCBjaGVja3MgZm9yIG51bGwgb3IgdW5kZWZpbmVkLlxuICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgIHByb3BzLmNoaWxkcmVuID09IG51bGwgfHwgcHJvcHMuZGFuZ2Vyb3VzbHlTZXRJbm5lckhUTUwgPT0gbnVsbCxcbiAgICAnQ2FuIG9ubHkgc2V0IG9uZSBvZiBgY2hpbGRyZW5gIG9yIGBwcm9wcy5kYW5nZXJvdXNseVNldElubmVySFRNTGAuJ1xuICApIDogaW52YXJpYW50KHByb3BzLmNoaWxkcmVuID09IG51bGwgfHwgcHJvcHMuZGFuZ2Vyb3VzbHlTZXRJbm5lckhUTUwgPT0gbnVsbCkpO1xuICBpZiAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WKSB7XG4gICAgaWYgKHByb3BzLmNvbnRlbnRFZGl0YWJsZSAmJiBwcm9wcy5jaGlsZHJlbiAhPSBudWxsKSB7XG4gICAgICBjb25zb2xlLndhcm4oXG4gICAgICAgICdBIGNvbXBvbmVudCBpcyBgY29udGVudEVkaXRhYmxlYCBhbmQgY29udGFpbnMgYGNoaWxkcmVuYCBtYW5hZ2VkIGJ5ICcgK1xuICAgICAgICAnUmVhY3QuIEl0IGlzIG5vdyB5b3VyIHJlc3BvbnNpYmlsaXR5IHRvIGd1YXJhbnRlZSB0aGF0IG5vbmUgb2YgdGhvc2UgJytcbiAgICAgICAgJ25vZGVzIGFyZSB1bmV4cGVjdGVkbHkgbW9kaWZpZWQgb3IgZHVwbGljYXRlZC4gVGhpcyBpcyBwcm9iYWJseSBub3QgJyArXG4gICAgICAgICdpbnRlbnRpb25hbC4nXG4gICAgICApO1xuICAgIH1cbiAgfVxuICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgIHByb3BzLnN0eWxlID09IG51bGwgfHwgdHlwZW9mIHByb3BzLnN0eWxlID09PSAnb2JqZWN0JyxcbiAgICAnVGhlIGBzdHlsZWAgcHJvcCBleHBlY3RzIGEgbWFwcGluZyBmcm9tIHN0eWxlIHByb3BlcnRpZXMgdG8gdmFsdWVzLCAnICtcbiAgICAnbm90IGEgc3RyaW5nLidcbiAgKSA6IGludmFyaWFudChwcm9wcy5zdHlsZSA9PSBudWxsIHx8IHR5cGVvZiBwcm9wcy5zdHlsZSA9PT0gJ29iamVjdCcpKTtcbn1cblxuZnVuY3Rpb24gcHV0TGlzdGVuZXIoaWQsIHJlZ2lzdHJhdGlvbk5hbWUsIGxpc3RlbmVyLCB0cmFuc2FjdGlvbikge1xuICBpZiAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WKSB7XG4gICAgLy8gSUU4IGhhcyBubyBBUEkgZm9yIGV2ZW50IGNhcHR1cmluZyBhbmQgdGhlIGBvblNjcm9sbGAgZXZlbnQgZG9lc24ndFxuICAgIC8vIGJ1YmJsZS5cbiAgICBpZiAocmVnaXN0cmF0aW9uTmFtZSA9PT0gJ29uU2Nyb2xsJyAmJlxuICAgICAgICAhaXNFdmVudFN1cHBvcnRlZCgnc2Nyb2xsJywgdHJ1ZSkpIHtcbiAgICAgIG1vbml0b3JDb2RlVXNlKCdyZWFjdF9ub19zY3JvbGxfZXZlbnQnKTtcbiAgICAgIGNvbnNvbGUud2FybignVGhpcyBicm93c2VyIGRvZXNuXFwndCBzdXBwb3J0IHRoZSBgb25TY3JvbGxgIGV2ZW50Jyk7XG4gICAgfVxuICB9XG4gIHZhciBjb250YWluZXIgPSBSZWFjdE1vdW50LmZpbmRSZWFjdENvbnRhaW5lckZvcklEKGlkKTtcbiAgaWYgKGNvbnRhaW5lcikge1xuICAgIHZhciBkb2MgPSBjb250YWluZXIubm9kZVR5cGUgPT09IEVMRU1FTlRfTk9ERV9UWVBFID9cbiAgICAgIGNvbnRhaW5lci5vd25lckRvY3VtZW50IDpcbiAgICAgIGNvbnRhaW5lcjtcbiAgICBsaXN0ZW5UbyhyZWdpc3RyYXRpb25OYW1lLCBkb2MpO1xuICB9XG4gIHRyYW5zYWN0aW9uLmdldFB1dExpc3RlbmVyUXVldWUoKS5lbnF1ZXVlUHV0TGlzdGVuZXIoXG4gICAgaWQsXG4gICAgcmVnaXN0cmF0aW9uTmFtZSxcbiAgICBsaXN0ZW5lclxuICApO1xufVxuXG4vLyBGb3IgSFRNTCwgY2VydGFpbiB0YWdzIHNob3VsZCBvbWl0IHRoZWlyIGNsb3NlIHRhZy4gV2Uga2VlcCBhIHdoaXRlbGlzdCBmb3Jcbi8vIHRob3NlIHNwZWNpYWwgY2FzZWQgdGFncy5cblxudmFyIG9taXR0ZWRDbG9zZVRhZ3MgPSB7XG4gICdhcmVhJzogdHJ1ZSxcbiAgJ2Jhc2UnOiB0cnVlLFxuICAnYnInOiB0cnVlLFxuICAnY29sJzogdHJ1ZSxcbiAgJ2VtYmVkJzogdHJ1ZSxcbiAgJ2hyJzogdHJ1ZSxcbiAgJ2ltZyc6IHRydWUsXG4gICdpbnB1dCc6IHRydWUsXG4gICdrZXlnZW4nOiB0cnVlLFxuICAnbGluayc6IHRydWUsXG4gICdtZXRhJzogdHJ1ZSxcbiAgJ3BhcmFtJzogdHJ1ZSxcbiAgJ3NvdXJjZSc6IHRydWUsXG4gICd0cmFjayc6IHRydWUsXG4gICd3YnInOiB0cnVlXG4gIC8vIE5PVEU6IG1lbnVpdGVtJ3MgY2xvc2UgdGFnIHNob3VsZCBiZSBvbWl0dGVkLCBidXQgdGhhdCBjYXVzZXMgcHJvYmxlbXMuXG59O1xuXG4vLyBXZSBhY2NlcHQgYW55IHRhZyB0byBiZSByZW5kZXJlZCBidXQgc2luY2UgdGhpcyBnZXRzIGluamVjdGVkIGludG8gYWJpdHJhcnlcbi8vIEhUTUwsIHdlIHdhbnQgdG8gbWFrZSBzdXJlIHRoYXQgaXQncyBhIHNhZmUgdGFnLlxuLy8gaHR0cDovL3d3dy53My5vcmcvVFIvUkVDLXhtbC8jTlQtTmFtZVxuXG52YXIgVkFMSURfVEFHX1JFR0VYID0gL15bYS16QS1aXVthLXpBLVo6X1xcLlxcLVxcZF0qJC87IC8vIFNpbXBsaWZpZWQgc3Vic2V0XG52YXIgdmFsaWRhdGVkVGFnQ2FjaGUgPSB7fTtcbnZhciBoYXNPd25Qcm9wZXJ0eSA9IHt9Lmhhc093blByb3BlcnR5O1xuXG5mdW5jdGlvbiB2YWxpZGF0ZURhbmdlcm91c1RhZyh0YWcpIHtcbiAgaWYgKCFoYXNPd25Qcm9wZXJ0eS5jYWxsKHZhbGlkYXRlZFRhZ0NhY2hlLCB0YWcpKSB7XG4gICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChWQUxJRF9UQUdfUkVHRVgudGVzdCh0YWcpLCAnSW52YWxpZCB0YWc6ICVzJywgdGFnKSA6IGludmFyaWFudChWQUxJRF9UQUdfUkVHRVgudGVzdCh0YWcpKSk7XG4gICAgdmFsaWRhdGVkVGFnQ2FjaGVbdGFnXSA9IHRydWU7XG4gIH1cbn1cblxuLyoqXG4gKiBDcmVhdGVzIGEgbmV3IFJlYWN0IGNsYXNzIHRoYXQgaXMgaWRlbXBvdGVudCBhbmQgY2FwYWJsZSBvZiBjb250YWluaW5nIG90aGVyXG4gKiBSZWFjdCBjb21wb25lbnRzLiBJdCBhY2NlcHRzIGV2ZW50IGxpc3RlbmVycyBhbmQgRE9NIHByb3BlcnRpZXMgdGhhdCBhcmVcbiAqIHZhbGlkIGFjY29yZGluZyB0byBgRE9NUHJvcGVydHlgLlxuICpcbiAqICAtIEV2ZW50IGxpc3RlbmVyczogYG9uQ2xpY2tgLCBgb25Nb3VzZURvd25gLCBldGMuXG4gKiAgLSBET00gcHJvcGVydGllczogYGNsYXNzTmFtZWAsIGBuYW1lYCwgYHRpdGxlYCwgZXRjLlxuICpcbiAqIFRoZSBgc3R5bGVgIHByb3BlcnR5IGZ1bmN0aW9ucyBkaWZmZXJlbnRseSBmcm9tIHRoZSBET00gQVBJLiBJdCBhY2NlcHRzIGFuXG4gKiBvYmplY3QgbWFwcGluZyBvZiBzdHlsZSBwcm9wZXJ0aWVzIHRvIHZhbHVlcy5cbiAqXG4gKiBAY29uc3RydWN0b3IgUmVhY3RET01Db21wb25lbnRcbiAqIEBleHRlbmRzIFJlYWN0Q29tcG9uZW50XG4gKiBAZXh0ZW5kcyBSZWFjdE11bHRpQ2hpbGRcbiAqL1xuZnVuY3Rpb24gUmVhY3RET01Db21wb25lbnQodGFnKSB7XG4gIHZhbGlkYXRlRGFuZ2Vyb3VzVGFnKHRhZyk7XG4gIHRoaXMuX3RhZyA9IHRhZztcbiAgdGhpcy50YWdOYW1lID0gdGFnLnRvVXBwZXJDYXNlKCk7XG59XG5cblJlYWN0RE9NQ29tcG9uZW50LmRpc3BsYXlOYW1lID0gJ1JlYWN0RE9NQ29tcG9uZW50JztcblxuUmVhY3RET01Db21wb25lbnQuTWl4aW4gPSB7XG5cbiAgLyoqXG4gICAqIEdlbmVyYXRlcyByb290IHRhZyBtYXJrdXAgdGhlbiByZWN1cnNlcy4gVGhpcyBtZXRob2QgaGFzIHNpZGUgZWZmZWN0cyBhbmRcbiAgICogaXMgbm90IGlkZW1wb3RlbnQuXG4gICAqXG4gICAqIEBpbnRlcm5hbFxuICAgKiBAcGFyYW0ge3N0cmluZ30gcm9vdElEIFRoZSByb290IERPTSBJRCBmb3IgdGhpcyBub2RlLlxuICAgKiBAcGFyYW0ge1JlYWN0UmVjb25jaWxlVHJhbnNhY3Rpb258UmVhY3RTZXJ2ZXJSZW5kZXJpbmdUcmFuc2FjdGlvbn0gdHJhbnNhY3Rpb25cbiAgICogQHBhcmFtIHtudW1iZXJ9IG1vdW50RGVwdGggbnVtYmVyIG9mIGNvbXBvbmVudHMgaW4gdGhlIG93bmVyIGhpZXJhcmNoeVxuICAgKiBAcmV0dXJuIHtzdHJpbmd9IFRoZSBjb21wdXRlZCBtYXJrdXAuXG4gICAqL1xuICBtb3VudENvbXBvbmVudDogUmVhY3RQZXJmLm1lYXN1cmUoXG4gICAgJ1JlYWN0RE9NQ29tcG9uZW50JyxcbiAgICAnbW91bnRDb21wb25lbnQnLFxuICAgIGZ1bmN0aW9uKHJvb3RJRCwgdHJhbnNhY3Rpb24sIG1vdW50RGVwdGgpIHtcbiAgICAgIFJlYWN0Q29tcG9uZW50Lk1peGluLm1vdW50Q29tcG9uZW50LmNhbGwoXG4gICAgICAgIHRoaXMsXG4gICAgICAgIHJvb3RJRCxcbiAgICAgICAgdHJhbnNhY3Rpb24sXG4gICAgICAgIG1vdW50RGVwdGhcbiAgICAgICk7XG4gICAgICBhc3NlcnRWYWxpZFByb3BzKHRoaXMucHJvcHMpO1xuICAgICAgdmFyIGNsb3NlVGFnID0gb21pdHRlZENsb3NlVGFnc1t0aGlzLl90YWddID8gJycgOiAnPC8nICsgdGhpcy5fdGFnICsgJz4nO1xuICAgICAgcmV0dXJuIChcbiAgICAgICAgdGhpcy5fY3JlYXRlT3BlblRhZ01hcmt1cEFuZFB1dExpc3RlbmVycyh0cmFuc2FjdGlvbikgK1xuICAgICAgICB0aGlzLl9jcmVhdGVDb250ZW50TWFya3VwKHRyYW5zYWN0aW9uKSArXG4gICAgICAgIGNsb3NlVGFnXG4gICAgICApO1xuICAgIH1cbiAgKSxcblxuICAvKipcbiAgICogQ3JlYXRlcyBtYXJrdXAgZm9yIHRoZSBvcGVuIHRhZyBhbmQgYWxsIGF0dHJpYnV0ZXMuXG4gICAqXG4gICAqIFRoaXMgbWV0aG9kIGhhcyBzaWRlIGVmZmVjdHMgYmVjYXVzZSBldmVudHMgZ2V0IHJlZ2lzdGVyZWQuXG4gICAqXG4gICAqIEl0ZXJhdGluZyBvdmVyIG9iamVjdCBwcm9wZXJ0aWVzIGlzIGZhc3RlciB0aGFuIGl0ZXJhdGluZyBvdmVyIGFycmF5cy5cbiAgICogQHNlZSBodHRwOi8vanNwZXJmLmNvbS9vYmotdnMtYXJyLWl0ZXJhdGlvblxuICAgKlxuICAgKiBAcHJpdmF0ZVxuICAgKiBAcGFyYW0ge1JlYWN0UmVjb25jaWxlVHJhbnNhY3Rpb258UmVhY3RTZXJ2ZXJSZW5kZXJpbmdUcmFuc2FjdGlvbn0gdHJhbnNhY3Rpb25cbiAgICogQHJldHVybiB7c3RyaW5nfSBNYXJrdXAgb2Ygb3BlbmluZyB0YWcuXG4gICAqL1xuICBfY3JlYXRlT3BlblRhZ01hcmt1cEFuZFB1dExpc3RlbmVyczogZnVuY3Rpb24odHJhbnNhY3Rpb24pIHtcbiAgICB2YXIgcHJvcHMgPSB0aGlzLnByb3BzO1xuICAgIHZhciByZXQgPSAnPCcgKyB0aGlzLl90YWc7XG5cbiAgICBmb3IgKHZhciBwcm9wS2V5IGluIHByb3BzKSB7XG4gICAgICBpZiAoIXByb3BzLmhhc093blByb3BlcnR5KHByb3BLZXkpKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgdmFyIHByb3BWYWx1ZSA9IHByb3BzW3Byb3BLZXldO1xuICAgICAgaWYgKHByb3BWYWx1ZSA9PSBudWxsKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgaWYgKHJlZ2lzdHJhdGlvbk5hbWVNb2R1bGVzLmhhc093blByb3BlcnR5KHByb3BLZXkpKSB7XG4gICAgICAgIHB1dExpc3RlbmVyKHRoaXMuX3Jvb3ROb2RlSUQsIHByb3BLZXksIHByb3BWYWx1ZSwgdHJhbnNhY3Rpb24pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgaWYgKHByb3BLZXkgPT09IFNUWUxFKSB7XG4gICAgICAgICAgaWYgKHByb3BWYWx1ZSkge1xuICAgICAgICAgICAgcHJvcFZhbHVlID0gcHJvcHMuc3R5bGUgPSBhc3NpZ24oe30sIHByb3BzLnN0eWxlKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcHJvcFZhbHVlID0gQ1NTUHJvcGVydHlPcGVyYXRpb25zLmNyZWF0ZU1hcmt1cEZvclN0eWxlcyhwcm9wVmFsdWUpO1xuICAgICAgICB9XG4gICAgICAgIHZhciBtYXJrdXAgPVxuICAgICAgICAgIERPTVByb3BlcnR5T3BlcmF0aW9ucy5jcmVhdGVNYXJrdXBGb3JQcm9wZXJ0eShwcm9wS2V5LCBwcm9wVmFsdWUpO1xuICAgICAgICBpZiAobWFya3VwKSB7XG4gICAgICAgICAgcmV0ICs9ICcgJyArIG1hcmt1cDtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIC8vIEZvciBzdGF0aWMgcGFnZXMsIG5vIG5lZWQgdG8gcHV0IFJlYWN0IElEIGFuZCBjaGVja3N1bS4gU2F2ZXMgbG90cyBvZlxuICAgIC8vIGJ5dGVzLlxuICAgIGlmICh0cmFuc2FjdGlvbi5yZW5kZXJUb1N0YXRpY01hcmt1cCkge1xuICAgICAgcmV0dXJuIHJldCArICc+JztcbiAgICB9XG5cbiAgICB2YXIgbWFya3VwRm9ySUQgPSBET01Qcm9wZXJ0eU9wZXJhdGlvbnMuY3JlYXRlTWFya3VwRm9ySUQodGhpcy5fcm9vdE5vZGVJRCk7XG4gICAgcmV0dXJuIHJldCArICcgJyArIG1hcmt1cEZvcklEICsgJz4nO1xuICB9LFxuXG4gIC8qKlxuICAgKiBDcmVhdGVzIG1hcmt1cCBmb3IgdGhlIGNvbnRlbnQgYmV0d2VlbiB0aGUgdGFncy5cbiAgICpcbiAgICogQHByaXZhdGVcbiAgICogQHBhcmFtIHtSZWFjdFJlY29uY2lsZVRyYW5zYWN0aW9ufFJlYWN0U2VydmVyUmVuZGVyaW5nVHJhbnNhY3Rpb259IHRyYW5zYWN0aW9uXG4gICAqIEByZXR1cm4ge3N0cmluZ30gQ29udGVudCBtYXJrdXAuXG4gICAqL1xuICBfY3JlYXRlQ29udGVudE1hcmt1cDogZnVuY3Rpb24odHJhbnNhY3Rpb24pIHtcbiAgICAvLyBJbnRlbnRpb25hbCB1c2Ugb2YgIT0gdG8gYXZvaWQgY2F0Y2hpbmcgemVyby9mYWxzZS5cbiAgICB2YXIgaW5uZXJIVE1MID0gdGhpcy5wcm9wcy5kYW5nZXJvdXNseVNldElubmVySFRNTDtcbiAgICBpZiAoaW5uZXJIVE1MICE9IG51bGwpIHtcbiAgICAgIGlmIChpbm5lckhUTUwuX19odG1sICE9IG51bGwpIHtcbiAgICAgICAgcmV0dXJuIGlubmVySFRNTC5fX2h0bWw7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHZhciBjb250ZW50VG9Vc2UgPVxuICAgICAgICBDT05URU5UX1RZUEVTW3R5cGVvZiB0aGlzLnByb3BzLmNoaWxkcmVuXSA/IHRoaXMucHJvcHMuY2hpbGRyZW4gOiBudWxsO1xuICAgICAgdmFyIGNoaWxkcmVuVG9Vc2UgPSBjb250ZW50VG9Vc2UgIT0gbnVsbCA/IG51bGwgOiB0aGlzLnByb3BzLmNoaWxkcmVuO1xuICAgICAgaWYgKGNvbnRlbnRUb1VzZSAhPSBudWxsKSB7XG4gICAgICAgIHJldHVybiBlc2NhcGVUZXh0Rm9yQnJvd3Nlcihjb250ZW50VG9Vc2UpO1xuICAgICAgfSBlbHNlIGlmIChjaGlsZHJlblRvVXNlICE9IG51bGwpIHtcbiAgICAgICAgdmFyIG1vdW50SW1hZ2VzID0gdGhpcy5tb3VudENoaWxkcmVuKFxuICAgICAgICAgIGNoaWxkcmVuVG9Vc2UsXG4gICAgICAgICAgdHJhbnNhY3Rpb25cbiAgICAgICAgKTtcbiAgICAgICAgcmV0dXJuIG1vdW50SW1hZ2VzLmpvaW4oJycpO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gJyc7XG4gIH0sXG5cbiAgcmVjZWl2ZUNvbXBvbmVudDogZnVuY3Rpb24obmV4dEVsZW1lbnQsIHRyYW5zYWN0aW9uKSB7XG4gICAgaWYgKG5leHRFbGVtZW50ID09PSB0aGlzLl9jdXJyZW50RWxlbWVudCAmJlxuICAgICAgICBuZXh0RWxlbWVudC5fb3duZXIgIT0gbnVsbCkge1xuICAgICAgLy8gU2luY2UgZWxlbWVudHMgYXJlIGltbXV0YWJsZSBhZnRlciB0aGUgb3duZXIgaXMgcmVuZGVyZWQsXG4gICAgICAvLyB3ZSBjYW4gZG8gYSBjaGVhcCBpZGVudGl0eSBjb21wYXJlIGhlcmUgdG8gZGV0ZXJtaW5lIGlmIHRoaXMgaXMgYVxuICAgICAgLy8gc3VwZXJmbHVvdXMgcmVjb25jaWxlLiBJdCdzIHBvc3NpYmxlIGZvciBzdGF0ZSB0byBiZSBtdXRhYmxlIGJ1dCBzdWNoXG4gICAgICAvLyBjaGFuZ2Ugc2hvdWxkIHRyaWdnZXIgYW4gdXBkYXRlIG9mIHRoZSBvd25lciB3aGljaCB3b3VsZCByZWNyZWF0ZVxuICAgICAgLy8gdGhlIGVsZW1lbnQuIFdlIGV4cGxpY2l0bHkgY2hlY2sgZm9yIHRoZSBleGlzdGVuY2Ugb2YgYW4gb3duZXIgc2luY2VcbiAgICAgIC8vIGl0J3MgcG9zc2libGUgZm9yIGEgZWxlbWVudCBjcmVhdGVkIG91dHNpZGUgYSBjb21wb3NpdGUgdG8gYmVcbiAgICAgIC8vIGRlZXBseSBtdXRhdGVkIGFuZCByZXVzZWQuXG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgUmVhY3RDb21wb25lbnQuTWl4aW4ucmVjZWl2ZUNvbXBvbmVudC5jYWxsKFxuICAgICAgdGhpcyxcbiAgICAgIG5leHRFbGVtZW50LFxuICAgICAgdHJhbnNhY3Rpb25cbiAgICApO1xuICB9LFxuXG4gIC8qKlxuICAgKiBVcGRhdGVzIGEgbmF0aXZlIERPTSBjb21wb25lbnQgYWZ0ZXIgaXQgaGFzIGFscmVhZHkgYmVlbiBhbGxvY2F0ZWQgYW5kXG4gICAqIGF0dGFjaGVkIHRvIHRoZSBET00uIFJlY29uY2lsZXMgdGhlIHJvb3QgRE9NIG5vZGUsIHRoZW4gcmVjdXJzZXMuXG4gICAqXG4gICAqIEBwYXJhbSB7UmVhY3RSZWNvbmNpbGVUcmFuc2FjdGlvbn0gdHJhbnNhY3Rpb25cbiAgICogQHBhcmFtIHtSZWFjdEVsZW1lbnR9IHByZXZFbGVtZW50XG4gICAqIEBpbnRlcm5hbFxuICAgKiBAb3ZlcnJpZGFibGVcbiAgICovXG4gIHVwZGF0ZUNvbXBvbmVudDogUmVhY3RQZXJmLm1lYXN1cmUoXG4gICAgJ1JlYWN0RE9NQ29tcG9uZW50JyxcbiAgICAndXBkYXRlQ29tcG9uZW50JyxcbiAgICBmdW5jdGlvbih0cmFuc2FjdGlvbiwgcHJldkVsZW1lbnQpIHtcbiAgICAgIGFzc2VydFZhbGlkUHJvcHModGhpcy5fY3VycmVudEVsZW1lbnQucHJvcHMpO1xuICAgICAgUmVhY3RDb21wb25lbnQuTWl4aW4udXBkYXRlQ29tcG9uZW50LmNhbGwoXG4gICAgICAgIHRoaXMsXG4gICAgICAgIHRyYW5zYWN0aW9uLFxuICAgICAgICBwcmV2RWxlbWVudFxuICAgICAgKTtcbiAgICAgIHRoaXMuX3VwZGF0ZURPTVByb3BlcnRpZXMocHJldkVsZW1lbnQucHJvcHMsIHRyYW5zYWN0aW9uKTtcbiAgICAgIHRoaXMuX3VwZGF0ZURPTUNoaWxkcmVuKHByZXZFbGVtZW50LnByb3BzLCB0cmFuc2FjdGlvbik7XG4gICAgfVxuICApLFxuXG4gIC8qKlxuICAgKiBSZWNvbmNpbGVzIHRoZSBwcm9wZXJ0aWVzIGJ5IGRldGVjdGluZyBkaWZmZXJlbmNlcyBpbiBwcm9wZXJ0eSB2YWx1ZXMgYW5kXG4gICAqIHVwZGF0aW5nIHRoZSBET00gYXMgbmVjZXNzYXJ5LiBUaGlzIGZ1bmN0aW9uIGlzIHByb2JhYmx5IHRoZSBzaW5nbGUgbW9zdFxuICAgKiBjcml0aWNhbCBwYXRoIGZvciBwZXJmb3JtYW5jZSBvcHRpbWl6YXRpb24uXG4gICAqXG4gICAqIFRPRE86IEJlbmNobWFyayB3aGV0aGVyIGNoZWNraW5nIGZvciBjaGFuZ2VkIHZhbHVlcyBpbiBtZW1vcnkgYWN0dWFsbHlcbiAgICogICAgICAgaW1wcm92ZXMgcGVyZm9ybWFuY2UgKGVzcGVjaWFsbHkgc3RhdGljYWxseSBwb3NpdGlvbmVkIGVsZW1lbnRzKS5cbiAgICogVE9ETzogQmVuY2htYXJrIHRoZSBlZmZlY3RzIG9mIHB1dHRpbmcgdGhpcyBhdCB0aGUgdG9wIHNpbmNlIDk5JSBvZiBwcm9wc1xuICAgKiAgICAgICBkbyBub3QgY2hhbmdlIGZvciBhIGdpdmVuIHJlY29uY2lsaWF0aW9uLlxuICAgKiBUT0RPOiBCZW5jaG1hcmsgYXJlYXMgdGhhdCBjYW4gYmUgaW1wcm92ZWQgd2l0aCBjYWNoaW5nLlxuICAgKlxuICAgKiBAcHJpdmF0ZVxuICAgKiBAcGFyYW0ge29iamVjdH0gbGFzdFByb3BzXG4gICAqIEBwYXJhbSB7UmVhY3RSZWNvbmNpbGVUcmFuc2FjdGlvbn0gdHJhbnNhY3Rpb25cbiAgICovXG4gIF91cGRhdGVET01Qcm9wZXJ0aWVzOiBmdW5jdGlvbihsYXN0UHJvcHMsIHRyYW5zYWN0aW9uKSB7XG4gICAgdmFyIG5leHRQcm9wcyA9IHRoaXMucHJvcHM7XG4gICAgdmFyIHByb3BLZXk7XG4gICAgdmFyIHN0eWxlTmFtZTtcbiAgICB2YXIgc3R5bGVVcGRhdGVzO1xuICAgIGZvciAocHJvcEtleSBpbiBsYXN0UHJvcHMpIHtcbiAgICAgIGlmIChuZXh0UHJvcHMuaGFzT3duUHJvcGVydHkocHJvcEtleSkgfHxcbiAgICAgICAgICFsYXN0UHJvcHMuaGFzT3duUHJvcGVydHkocHJvcEtleSkpIHtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG4gICAgICBpZiAocHJvcEtleSA9PT0gU1RZTEUpIHtcbiAgICAgICAgdmFyIGxhc3RTdHlsZSA9IGxhc3RQcm9wc1twcm9wS2V5XTtcbiAgICAgICAgZm9yIChzdHlsZU5hbWUgaW4gbGFzdFN0eWxlKSB7XG4gICAgICAgICAgaWYgKGxhc3RTdHlsZS5oYXNPd25Qcm9wZXJ0eShzdHlsZU5hbWUpKSB7XG4gICAgICAgICAgICBzdHlsZVVwZGF0ZXMgPSBzdHlsZVVwZGF0ZXMgfHwge307XG4gICAgICAgICAgICBzdHlsZVVwZGF0ZXNbc3R5bGVOYW1lXSA9ICcnO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmIChyZWdpc3RyYXRpb25OYW1lTW9kdWxlcy5oYXNPd25Qcm9wZXJ0eShwcm9wS2V5KSkge1xuICAgICAgICBkZWxldGVMaXN0ZW5lcih0aGlzLl9yb290Tm9kZUlELCBwcm9wS2V5KTtcbiAgICAgIH0gZWxzZSBpZiAoXG4gICAgICAgICAgRE9NUHJvcGVydHkuaXNTdGFuZGFyZE5hbWVbcHJvcEtleV0gfHxcbiAgICAgICAgICBET01Qcm9wZXJ0eS5pc0N1c3RvbUF0dHJpYnV0ZShwcm9wS2V5KSkge1xuICAgICAgICBSZWFjdENvbXBvbmVudC5CYWNrZW5kSURPcGVyYXRpb25zLmRlbGV0ZVByb3BlcnR5QnlJRChcbiAgICAgICAgICB0aGlzLl9yb290Tm9kZUlELFxuICAgICAgICAgIHByb3BLZXlcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG4gICAgZm9yIChwcm9wS2V5IGluIG5leHRQcm9wcykge1xuICAgICAgdmFyIG5leHRQcm9wID0gbmV4dFByb3BzW3Byb3BLZXldO1xuICAgICAgdmFyIGxhc3RQcm9wID0gbGFzdFByb3BzW3Byb3BLZXldO1xuICAgICAgaWYgKCFuZXh0UHJvcHMuaGFzT3duUHJvcGVydHkocHJvcEtleSkgfHwgbmV4dFByb3AgPT09IGxhc3RQcm9wKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgaWYgKHByb3BLZXkgPT09IFNUWUxFKSB7XG4gICAgICAgIGlmIChuZXh0UHJvcCkge1xuICAgICAgICAgIG5leHRQcm9wID0gbmV4dFByb3BzLnN0eWxlID0gYXNzaWduKHt9LCBuZXh0UHJvcCk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGxhc3RQcm9wKSB7XG4gICAgICAgICAgLy8gVW5zZXQgc3R5bGVzIG9uIGBsYXN0UHJvcGAgYnV0IG5vdCBvbiBgbmV4dFByb3BgLlxuICAgICAgICAgIGZvciAoc3R5bGVOYW1lIGluIGxhc3RQcm9wKSB7XG4gICAgICAgICAgICBpZiAobGFzdFByb3AuaGFzT3duUHJvcGVydHkoc3R5bGVOYW1lKSAmJlxuICAgICAgICAgICAgICAgICghbmV4dFByb3AgfHwgIW5leHRQcm9wLmhhc093blByb3BlcnR5KHN0eWxlTmFtZSkpKSB7XG4gICAgICAgICAgICAgIHN0eWxlVXBkYXRlcyA9IHN0eWxlVXBkYXRlcyB8fCB7fTtcbiAgICAgICAgICAgICAgc3R5bGVVcGRhdGVzW3N0eWxlTmFtZV0gPSAnJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICAgLy8gVXBkYXRlIHN0eWxlcyB0aGF0IGNoYW5nZWQgc2luY2UgYGxhc3RQcm9wYC5cbiAgICAgICAgICBmb3IgKHN0eWxlTmFtZSBpbiBuZXh0UHJvcCkge1xuICAgICAgICAgICAgaWYgKG5leHRQcm9wLmhhc093blByb3BlcnR5KHN0eWxlTmFtZSkgJiZcbiAgICAgICAgICAgICAgICBsYXN0UHJvcFtzdHlsZU5hbWVdICE9PSBuZXh0UHJvcFtzdHlsZU5hbWVdKSB7XG4gICAgICAgICAgICAgIHN0eWxlVXBkYXRlcyA9IHN0eWxlVXBkYXRlcyB8fCB7fTtcbiAgICAgICAgICAgICAgc3R5bGVVcGRhdGVzW3N0eWxlTmFtZV0gPSBuZXh0UHJvcFtzdHlsZU5hbWVdO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAvLyBSZWxpZXMgb24gYHVwZGF0ZVN0eWxlc0J5SURgIG5vdCBtdXRhdGluZyBgc3R5bGVVcGRhdGVzYC5cbiAgICAgICAgICBzdHlsZVVwZGF0ZXMgPSBuZXh0UHJvcDtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmIChyZWdpc3RyYXRpb25OYW1lTW9kdWxlcy5oYXNPd25Qcm9wZXJ0eShwcm9wS2V5KSkge1xuICAgICAgICBwdXRMaXN0ZW5lcih0aGlzLl9yb290Tm9kZUlELCBwcm9wS2V5LCBuZXh0UHJvcCwgdHJhbnNhY3Rpb24pO1xuICAgICAgfSBlbHNlIGlmIChcbiAgICAgICAgICBET01Qcm9wZXJ0eS5pc1N0YW5kYXJkTmFtZVtwcm9wS2V5XSB8fFxuICAgICAgICAgIERPTVByb3BlcnR5LmlzQ3VzdG9tQXR0cmlidXRlKHByb3BLZXkpKSB7XG4gICAgICAgIFJlYWN0Q29tcG9uZW50LkJhY2tlbmRJRE9wZXJhdGlvbnMudXBkYXRlUHJvcGVydHlCeUlEKFxuICAgICAgICAgIHRoaXMuX3Jvb3ROb2RlSUQsXG4gICAgICAgICAgcHJvcEtleSxcbiAgICAgICAgICBuZXh0UHJvcFxuICAgICAgICApO1xuICAgICAgfVxuICAgIH1cbiAgICBpZiAoc3R5bGVVcGRhdGVzKSB7XG4gICAgICBSZWFjdENvbXBvbmVudC5CYWNrZW5kSURPcGVyYXRpb25zLnVwZGF0ZVN0eWxlc0J5SUQoXG4gICAgICAgIHRoaXMuX3Jvb3ROb2RlSUQsXG4gICAgICAgIHN0eWxlVXBkYXRlc1xuICAgICAgKTtcbiAgICB9XG4gIH0sXG5cbiAgLyoqXG4gICAqIFJlY29uY2lsZXMgdGhlIGNoaWxkcmVuIHdpdGggdGhlIHZhcmlvdXMgcHJvcGVydGllcyB0aGF0IGFmZmVjdCB0aGVcbiAgICogY2hpbGRyZW4gY29udGVudC5cbiAgICpcbiAgICogQHBhcmFtIHtvYmplY3R9IGxhc3RQcm9wc1xuICAgKiBAcGFyYW0ge1JlYWN0UmVjb25jaWxlVHJhbnNhY3Rpb259IHRyYW5zYWN0aW9uXG4gICAqL1xuICBfdXBkYXRlRE9NQ2hpbGRyZW46IGZ1bmN0aW9uKGxhc3RQcm9wcywgdHJhbnNhY3Rpb24pIHtcbiAgICB2YXIgbmV4dFByb3BzID0gdGhpcy5wcm9wcztcblxuICAgIHZhciBsYXN0Q29udGVudCA9XG4gICAgICBDT05URU5UX1RZUEVTW3R5cGVvZiBsYXN0UHJvcHMuY2hpbGRyZW5dID8gbGFzdFByb3BzLmNoaWxkcmVuIDogbnVsbDtcbiAgICB2YXIgbmV4dENvbnRlbnQgPVxuICAgICAgQ09OVEVOVF9UWVBFU1t0eXBlb2YgbmV4dFByb3BzLmNoaWxkcmVuXSA/IG5leHRQcm9wcy5jaGlsZHJlbiA6IG51bGw7XG5cbiAgICB2YXIgbGFzdEh0bWwgPVxuICAgICAgbGFzdFByb3BzLmRhbmdlcm91c2x5U2V0SW5uZXJIVE1MICYmXG4gICAgICBsYXN0UHJvcHMuZGFuZ2Vyb3VzbHlTZXRJbm5lckhUTUwuX19odG1sO1xuICAgIHZhciBuZXh0SHRtbCA9XG4gICAgICBuZXh0UHJvcHMuZGFuZ2Vyb3VzbHlTZXRJbm5lckhUTUwgJiZcbiAgICAgIG5leHRQcm9wcy5kYW5nZXJvdXNseVNldElubmVySFRNTC5fX2h0bWw7XG5cbiAgICAvLyBOb3RlIHRoZSB1c2Ugb2YgYCE9YCB3aGljaCBjaGVja3MgZm9yIG51bGwgb3IgdW5kZWZpbmVkLlxuICAgIHZhciBsYXN0Q2hpbGRyZW4gPSBsYXN0Q29udGVudCAhPSBudWxsID8gbnVsbCA6IGxhc3RQcm9wcy5jaGlsZHJlbjtcbiAgICB2YXIgbmV4dENoaWxkcmVuID0gbmV4dENvbnRlbnQgIT0gbnVsbCA/IG51bGwgOiBuZXh0UHJvcHMuY2hpbGRyZW47XG5cbiAgICAvLyBJZiB3ZSdyZSBzd2l0Y2hpbmcgZnJvbSBjaGlsZHJlbiB0byBjb250ZW50L2h0bWwgb3IgdmljZSB2ZXJzYSwgcmVtb3ZlXG4gICAgLy8gdGhlIG9sZCBjb250ZW50XG4gICAgdmFyIGxhc3RIYXNDb250ZW50T3JIdG1sID0gbGFzdENvbnRlbnQgIT0gbnVsbCB8fCBsYXN0SHRtbCAhPSBudWxsO1xuICAgIHZhciBuZXh0SGFzQ29udGVudE9ySHRtbCA9IG5leHRDb250ZW50ICE9IG51bGwgfHwgbmV4dEh0bWwgIT0gbnVsbDtcbiAgICBpZiAobGFzdENoaWxkcmVuICE9IG51bGwgJiYgbmV4dENoaWxkcmVuID09IG51bGwpIHtcbiAgICAgIHRoaXMudXBkYXRlQ2hpbGRyZW4obnVsbCwgdHJhbnNhY3Rpb24pO1xuICAgIH0gZWxzZSBpZiAobGFzdEhhc0NvbnRlbnRPckh0bWwgJiYgIW5leHRIYXNDb250ZW50T3JIdG1sKSB7XG4gICAgICB0aGlzLnVwZGF0ZVRleHRDb250ZW50KCcnKTtcbiAgICB9XG5cbiAgICBpZiAobmV4dENvbnRlbnQgIT0gbnVsbCkge1xuICAgICAgaWYgKGxhc3RDb250ZW50ICE9PSBuZXh0Q29udGVudCkge1xuICAgICAgICB0aGlzLnVwZGF0ZVRleHRDb250ZW50KCcnICsgbmV4dENvbnRlbnQpO1xuICAgICAgfVxuICAgIH0gZWxzZSBpZiAobmV4dEh0bWwgIT0gbnVsbCkge1xuICAgICAgaWYgKGxhc3RIdG1sICE9PSBuZXh0SHRtbCkge1xuICAgICAgICBSZWFjdENvbXBvbmVudC5CYWNrZW5kSURPcGVyYXRpb25zLnVwZGF0ZUlubmVySFRNTEJ5SUQoXG4gICAgICAgICAgdGhpcy5fcm9vdE5vZGVJRCxcbiAgICAgICAgICBuZXh0SHRtbFxuICAgICAgICApO1xuICAgICAgfVxuICAgIH0gZWxzZSBpZiAobmV4dENoaWxkcmVuICE9IG51bGwpIHtcbiAgICAgIHRoaXMudXBkYXRlQ2hpbGRyZW4obmV4dENoaWxkcmVuLCB0cmFuc2FjdGlvbik7XG4gICAgfVxuICB9LFxuXG4gIC8qKlxuICAgKiBEZXN0cm95cyBhbGwgZXZlbnQgcmVnaXN0cmF0aW9ucyBmb3IgdGhpcyBpbnN0YW5jZS4gRG9lcyBub3QgcmVtb3ZlIGZyb21cbiAgICogdGhlIERPTS4gVGhhdCBtdXN0IGJlIGRvbmUgYnkgdGhlIHBhcmVudC5cbiAgICpcbiAgICogQGludGVybmFsXG4gICAqL1xuICB1bm1vdW50Q29tcG9uZW50OiBmdW5jdGlvbigpIHtcbiAgICB0aGlzLnVubW91bnRDaGlsZHJlbigpO1xuICAgIFJlYWN0QnJvd3NlckV2ZW50RW1pdHRlci5kZWxldGVBbGxMaXN0ZW5lcnModGhpcy5fcm9vdE5vZGVJRCk7XG4gICAgUmVhY3RDb21wb25lbnQuTWl4aW4udW5tb3VudENvbXBvbmVudC5jYWxsKHRoaXMpO1xuICB9XG5cbn07XG5cbmFzc2lnbihcbiAgUmVhY3RET01Db21wb25lbnQucHJvdG90eXBlLFxuICBSZWFjdENvbXBvbmVudC5NaXhpbixcbiAgUmVhY3RET01Db21wb25lbnQuTWl4aW4sXG4gIFJlYWN0TXVsdGlDaGlsZC5NaXhpbixcbiAgUmVhY3RCcm93c2VyQ29tcG9uZW50TWl4aW5cbik7XG5cbm1vZHVsZS5leHBvcnRzID0gUmVhY3RET01Db21wb25lbnQ7XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKCdfcHJvY2VzcycpKSIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBSZWFjdERPTUZvcm1cbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIEV2ZW50Q29uc3RhbnRzID0gcmVxdWlyZShcIi4vRXZlbnRDb25zdGFudHNcIik7XG52YXIgTG9jYWxFdmVudFRyYXBNaXhpbiA9IHJlcXVpcmUoXCIuL0xvY2FsRXZlbnRUcmFwTWl4aW5cIik7XG52YXIgUmVhY3RCcm93c2VyQ29tcG9uZW50TWl4aW4gPSByZXF1aXJlKFwiLi9SZWFjdEJyb3dzZXJDb21wb25lbnRNaXhpblwiKTtcbnZhciBSZWFjdENvbXBvc2l0ZUNvbXBvbmVudCA9IHJlcXVpcmUoXCIuL1JlYWN0Q29tcG9zaXRlQ29tcG9uZW50XCIpO1xudmFyIFJlYWN0RWxlbWVudCA9IHJlcXVpcmUoXCIuL1JlYWN0RWxlbWVudFwiKTtcbnZhciBSZWFjdERPTSA9IHJlcXVpcmUoXCIuL1JlYWN0RE9NXCIpO1xuXG4vLyBTdG9yZSBhIHJlZmVyZW5jZSB0byB0aGUgPGZvcm0+IGBSZWFjdERPTUNvbXBvbmVudGAuIFRPRE86IHVzZSBzdHJpbmdcbnZhciBmb3JtID0gUmVhY3RFbGVtZW50LmNyZWF0ZUZhY3RvcnkoUmVhY3RET00uZm9ybS50eXBlKTtcblxuLyoqXG4gKiBTaW5jZSBvblN1Ym1pdCBkb2Vzbid0IGJ1YmJsZSBPUiBjYXB0dXJlIG9uIHRoZSB0b3AgbGV2ZWwgaW4gSUU4LCB3ZSBuZWVkXG4gKiB0byBjYXB0dXJlIGl0IG9uIHRoZSA8Zm9ybT4gZWxlbWVudCBpdHNlbGYuIFRoZXJlIGFyZSBsb3RzIG9mIGhhY2tzIHdlIGNvdWxkXG4gKiBkbyB0byBhY2NvbXBsaXNoIHRoaXMsIGJ1dCB0aGUgbW9zdCByZWxpYWJsZSBpcyB0byBtYWtlIDxmb3JtPiBhXG4gKiBjb21wb3NpdGUgY29tcG9uZW50IGFuZCB1c2UgYGNvbXBvbmVudERpZE1vdW50YCB0byBhdHRhY2ggdGhlIGV2ZW50IGhhbmRsZXJzLlxuICovXG52YXIgUmVhY3RET01Gb3JtID0gUmVhY3RDb21wb3NpdGVDb21wb25lbnQuY3JlYXRlQ2xhc3Moe1xuICBkaXNwbGF5TmFtZTogJ1JlYWN0RE9NRm9ybScsXG5cbiAgbWl4aW5zOiBbUmVhY3RCcm93c2VyQ29tcG9uZW50TWl4aW4sIExvY2FsRXZlbnRUcmFwTWl4aW5dLFxuXG4gIHJlbmRlcjogZnVuY3Rpb24oKSB7XG4gICAgLy8gVE9ETzogSW5zdGVhZCBvZiB1c2luZyBgUmVhY3RET01gIGRpcmVjdGx5LCB3ZSBzaG91bGQgdXNlIEpTWC4gSG93ZXZlcixcbiAgICAvLyBganNoaW50YCBmYWlscyB0byBwYXJzZSBKU1ggc28gaW4gb3JkZXIgZm9yIGxpbnRpbmcgdG8gd29yayBpbiB0aGUgb3BlblxuICAgIC8vIHNvdXJjZSByZXBvLCB3ZSBuZWVkIHRvIGp1c3QgdXNlIGBSZWFjdERPTS5mb3JtYC5cbiAgICByZXR1cm4gZm9ybSh0aGlzLnByb3BzKTtcbiAgfSxcblxuICBjb21wb25lbnREaWRNb3VudDogZnVuY3Rpb24oKSB7XG4gICAgdGhpcy50cmFwQnViYmxlZEV2ZW50KEV2ZW50Q29uc3RhbnRzLnRvcExldmVsVHlwZXMudG9wUmVzZXQsICdyZXNldCcpO1xuICAgIHRoaXMudHJhcEJ1YmJsZWRFdmVudChFdmVudENvbnN0YW50cy50b3BMZXZlbFR5cGVzLnRvcFN1Ym1pdCwgJ3N1Ym1pdCcpO1xuICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBSZWFjdERPTUZvcm07XG4iLCIoZnVuY3Rpb24gKHByb2Nlc3Mpe1xuLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIFJlYWN0RE9NSURPcGVyYXRpb25zXG4gKiBAdHlwZWNoZWNrcyBzdGF0aWMtb25seVxuICovXG5cbi8qanNsaW50IGV2aWw6IHRydWUgKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBDU1NQcm9wZXJ0eU9wZXJhdGlvbnMgPSByZXF1aXJlKFwiLi9DU1NQcm9wZXJ0eU9wZXJhdGlvbnNcIik7XG52YXIgRE9NQ2hpbGRyZW5PcGVyYXRpb25zID0gcmVxdWlyZShcIi4vRE9NQ2hpbGRyZW5PcGVyYXRpb25zXCIpO1xudmFyIERPTVByb3BlcnR5T3BlcmF0aW9ucyA9IHJlcXVpcmUoXCIuL0RPTVByb3BlcnR5T3BlcmF0aW9uc1wiKTtcbnZhciBSZWFjdE1vdW50ID0gcmVxdWlyZShcIi4vUmVhY3RNb3VudFwiKTtcbnZhciBSZWFjdFBlcmYgPSByZXF1aXJlKFwiLi9SZWFjdFBlcmZcIik7XG5cbnZhciBpbnZhcmlhbnQgPSByZXF1aXJlKFwiLi9pbnZhcmlhbnRcIik7XG52YXIgc2V0SW5uZXJIVE1MID0gcmVxdWlyZShcIi4vc2V0SW5uZXJIVE1MXCIpO1xuXG4vKipcbiAqIEVycm9ycyBmb3IgcHJvcGVydGllcyB0aGF0IHNob3VsZCBub3QgYmUgdXBkYXRlZCB3aXRoIGB1cGRhdGVQcm9wZXJ0eUJ5SWQoKWAuXG4gKlxuICogQHR5cGUge29iamVjdH1cbiAqIEBwcml2YXRlXG4gKi9cbnZhciBJTlZBTElEX1BST1BFUlRZX0VSUk9SUyA9IHtcbiAgZGFuZ2Vyb3VzbHlTZXRJbm5lckhUTUw6XG4gICAgJ2BkYW5nZXJvdXNseVNldElubmVySFRNTGAgbXVzdCBiZSBzZXQgdXNpbmcgYHVwZGF0ZUlubmVySFRNTEJ5SUQoKWAuJyxcbiAgc3R5bGU6ICdgc3R5bGVgIG11c3QgYmUgc2V0IHVzaW5nIGB1cGRhdGVTdHlsZXNCeUlEKClgLidcbn07XG5cbi8qKlxuICogT3BlcmF0aW9ucyB1c2VkIHRvIHByb2Nlc3MgdXBkYXRlcyB0byBET00gbm9kZXMuIFRoaXMgaXMgbWFkZSBpbmplY3RhYmxlIHZpYVxuICogYFJlYWN0Q29tcG9uZW50LkJhY2tlbmRJRE9wZXJhdGlvbnNgLlxuICovXG52YXIgUmVhY3RET01JRE9wZXJhdGlvbnMgPSB7XG5cbiAgLyoqXG4gICAqIFVwZGF0ZXMgYSBET00gbm9kZSB3aXRoIG5ldyBwcm9wZXJ0eSB2YWx1ZXMuIFRoaXMgc2hvdWxkIG9ubHkgYmUgdXNlZCB0b1xuICAgKiB1cGRhdGUgRE9NIHByb3BlcnRpZXMgaW4gYERPTVByb3BlcnR5YC5cbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IGlkIElEIG9mIHRoZSBub2RlIHRvIHVwZGF0ZS5cbiAgICogQHBhcmFtIHtzdHJpbmd9IG5hbWUgQSB2YWxpZCBwcm9wZXJ0eSBuYW1lLCBzZWUgYERPTVByb3BlcnR5YC5cbiAgICogQHBhcmFtIHsqfSB2YWx1ZSBOZXcgdmFsdWUgb2YgdGhlIHByb3BlcnR5LlxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIHVwZGF0ZVByb3BlcnR5QnlJRDogUmVhY3RQZXJmLm1lYXN1cmUoXG4gICAgJ1JlYWN0RE9NSURPcGVyYXRpb25zJyxcbiAgICAndXBkYXRlUHJvcGVydHlCeUlEJyxcbiAgICBmdW5jdGlvbihpZCwgbmFtZSwgdmFsdWUpIHtcbiAgICAgIHZhciBub2RlID0gUmVhY3RNb3VudC5nZXROb2RlKGlkKTtcbiAgICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICAgICFJTlZBTElEX1BST1BFUlRZX0VSUk9SUy5oYXNPd25Qcm9wZXJ0eShuYW1lKSxcbiAgICAgICAgJ3VwZGF0ZVByb3BlcnR5QnlJRCguLi4pOiAlcycsXG4gICAgICAgIElOVkFMSURfUFJPUEVSVFlfRVJST1JTW25hbWVdXG4gICAgICApIDogaW52YXJpYW50KCFJTlZBTElEX1BST1BFUlRZX0VSUk9SUy5oYXNPd25Qcm9wZXJ0eShuYW1lKSkpO1xuXG4gICAgICAvLyBJZiB3ZSdyZSB1cGRhdGluZyB0byBudWxsIG9yIHVuZGVmaW5lZCwgd2Ugc2hvdWxkIHJlbW92ZSB0aGUgcHJvcGVydHlcbiAgICAgIC8vIGZyb20gdGhlIERPTSBub2RlIGluc3RlYWQgb2YgaW5hZHZlcnRhbnRseSBzZXR0aW5nIHRvIGEgc3RyaW5nLiBUaGlzXG4gICAgICAvLyBicmluZ3MgdXMgaW4gbGluZSB3aXRoIHRoZSBzYW1lIGJlaGF2aW9yIHdlIGhhdmUgb24gaW5pdGlhbCByZW5kZXIuXG4gICAgICBpZiAodmFsdWUgIT0gbnVsbCkge1xuICAgICAgICBET01Qcm9wZXJ0eU9wZXJhdGlvbnMuc2V0VmFsdWVGb3JQcm9wZXJ0eShub2RlLCBuYW1lLCB2YWx1ZSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBET01Qcm9wZXJ0eU9wZXJhdGlvbnMuZGVsZXRlVmFsdWVGb3JQcm9wZXJ0eShub2RlLCBuYW1lKTtcbiAgICAgIH1cbiAgICB9XG4gICksXG5cbiAgLyoqXG4gICAqIFVwZGF0ZXMgYSBET00gbm9kZSB0byByZW1vdmUgYSBwcm9wZXJ0eS4gVGhpcyBzaG91bGQgb25seSBiZSB1c2VkIHRvIHJlbW92ZVxuICAgKiBET00gcHJvcGVydGllcyBpbiBgRE9NUHJvcGVydHlgLlxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gaWQgSUQgb2YgdGhlIG5vZGUgdG8gdXBkYXRlLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gbmFtZSBBIHByb3BlcnR5IG5hbWUgdG8gcmVtb3ZlLCBzZWUgYERPTVByb3BlcnR5YC5cbiAgICogQGludGVybmFsXG4gICAqL1xuICBkZWxldGVQcm9wZXJ0eUJ5SUQ6IFJlYWN0UGVyZi5tZWFzdXJlKFxuICAgICdSZWFjdERPTUlET3BlcmF0aW9ucycsXG4gICAgJ2RlbGV0ZVByb3BlcnR5QnlJRCcsXG4gICAgZnVuY3Rpb24oaWQsIG5hbWUsIHZhbHVlKSB7XG4gICAgICB2YXIgbm9kZSA9IFJlYWN0TW91bnQuZ2V0Tm9kZShpZCk7XG4gICAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgICAhSU5WQUxJRF9QUk9QRVJUWV9FUlJPUlMuaGFzT3duUHJvcGVydHkobmFtZSksXG4gICAgICAgICd1cGRhdGVQcm9wZXJ0eUJ5SUQoLi4uKTogJXMnLFxuICAgICAgICBJTlZBTElEX1BST1BFUlRZX0VSUk9SU1tuYW1lXVxuICAgICAgKSA6IGludmFyaWFudCghSU5WQUxJRF9QUk9QRVJUWV9FUlJPUlMuaGFzT3duUHJvcGVydHkobmFtZSkpKTtcbiAgICAgIERPTVByb3BlcnR5T3BlcmF0aW9ucy5kZWxldGVWYWx1ZUZvclByb3BlcnR5KG5vZGUsIG5hbWUsIHZhbHVlKTtcbiAgICB9XG4gICksXG5cbiAgLyoqXG4gICAqIFVwZGF0ZXMgYSBET00gbm9kZSB3aXRoIG5ldyBzdHlsZSB2YWx1ZXMuIElmIGEgdmFsdWUgaXMgc3BlY2lmaWVkIGFzICcnLFxuICAgKiB0aGUgY29ycmVzcG9uZGluZyBzdHlsZSBwcm9wZXJ0eSB3aWxsIGJlIHVuc2V0LlxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gaWQgSUQgb2YgdGhlIG5vZGUgdG8gdXBkYXRlLlxuICAgKiBAcGFyYW0ge29iamVjdH0gc3R5bGVzIE1hcHBpbmcgZnJvbSBzdHlsZXMgdG8gdmFsdWVzLlxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIHVwZGF0ZVN0eWxlc0J5SUQ6IFJlYWN0UGVyZi5tZWFzdXJlKFxuICAgICdSZWFjdERPTUlET3BlcmF0aW9ucycsXG4gICAgJ3VwZGF0ZVN0eWxlc0J5SUQnLFxuICAgIGZ1bmN0aW9uKGlkLCBzdHlsZXMpIHtcbiAgICAgIHZhciBub2RlID0gUmVhY3RNb3VudC5nZXROb2RlKGlkKTtcbiAgICAgIENTU1Byb3BlcnR5T3BlcmF0aW9ucy5zZXRWYWx1ZUZvclN0eWxlcyhub2RlLCBzdHlsZXMpO1xuICAgIH1cbiAgKSxcblxuICAvKipcbiAgICogVXBkYXRlcyBhIERPTSBub2RlJ3MgaW5uZXJIVE1MLlxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gaWQgSUQgb2YgdGhlIG5vZGUgdG8gdXBkYXRlLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gaHRtbCBBbiBIVE1MIHN0cmluZy5cbiAgICogQGludGVybmFsXG4gICAqL1xuICB1cGRhdGVJbm5lckhUTUxCeUlEOiBSZWFjdFBlcmYubWVhc3VyZShcbiAgICAnUmVhY3RET01JRE9wZXJhdGlvbnMnLFxuICAgICd1cGRhdGVJbm5lckhUTUxCeUlEJyxcbiAgICBmdW5jdGlvbihpZCwgaHRtbCkge1xuICAgICAgdmFyIG5vZGUgPSBSZWFjdE1vdW50LmdldE5vZGUoaWQpO1xuICAgICAgc2V0SW5uZXJIVE1MKG5vZGUsIGh0bWwpO1xuICAgIH1cbiAgKSxcblxuICAvKipcbiAgICogVXBkYXRlcyBhIERPTSBub2RlJ3MgdGV4dCBjb250ZW50IHNldCBieSBgcHJvcHMuY29udGVudGAuXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBpZCBJRCBvZiB0aGUgbm9kZSB0byB1cGRhdGUuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBjb250ZW50IFRleHQgY29udGVudC5cbiAgICogQGludGVybmFsXG4gICAqL1xuICB1cGRhdGVUZXh0Q29udGVudEJ5SUQ6IFJlYWN0UGVyZi5tZWFzdXJlKFxuICAgICdSZWFjdERPTUlET3BlcmF0aW9ucycsXG4gICAgJ3VwZGF0ZVRleHRDb250ZW50QnlJRCcsXG4gICAgZnVuY3Rpb24oaWQsIGNvbnRlbnQpIHtcbiAgICAgIHZhciBub2RlID0gUmVhY3RNb3VudC5nZXROb2RlKGlkKTtcbiAgICAgIERPTUNoaWxkcmVuT3BlcmF0aW9ucy51cGRhdGVUZXh0Q29udGVudChub2RlLCBjb250ZW50KTtcbiAgICB9XG4gICksXG5cbiAgLyoqXG4gICAqIFJlcGxhY2VzIGEgRE9NIG5vZGUgdGhhdCBleGlzdHMgaW4gdGhlIGRvY3VtZW50IHdpdGggbWFya3VwLlxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gaWQgSUQgb2YgY2hpbGQgdG8gYmUgcmVwbGFjZWQuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBtYXJrdXAgRGFuZ2Vyb3VzIG1hcmt1cCB0byBpbmplY3QgaW4gcGxhY2Ugb2YgY2hpbGQuXG4gICAqIEBpbnRlcm5hbFxuICAgKiBAc2VlIHtEYW5nZXIuZGFuZ2Vyb3VzbHlSZXBsYWNlTm9kZVdpdGhNYXJrdXB9XG4gICAqL1xuICBkYW5nZXJvdXNseVJlcGxhY2VOb2RlV2l0aE1hcmt1cEJ5SUQ6IFJlYWN0UGVyZi5tZWFzdXJlKFxuICAgICdSZWFjdERPTUlET3BlcmF0aW9ucycsXG4gICAgJ2Rhbmdlcm91c2x5UmVwbGFjZU5vZGVXaXRoTWFya3VwQnlJRCcsXG4gICAgZnVuY3Rpb24oaWQsIG1hcmt1cCkge1xuICAgICAgdmFyIG5vZGUgPSBSZWFjdE1vdW50LmdldE5vZGUoaWQpO1xuICAgICAgRE9NQ2hpbGRyZW5PcGVyYXRpb25zLmRhbmdlcm91c2x5UmVwbGFjZU5vZGVXaXRoTWFya3VwKG5vZGUsIG1hcmt1cCk7XG4gICAgfVxuICApLFxuXG4gIC8qKlxuICAgKiBVcGRhdGVzIGEgY29tcG9uZW50J3MgY2hpbGRyZW4gYnkgcHJvY2Vzc2luZyBhIHNlcmllcyBvZiB1cGRhdGVzLlxuICAgKlxuICAgKiBAcGFyYW0ge2FycmF5PG9iamVjdD59IHVwZGF0ZXMgTGlzdCBvZiB1cGRhdGUgY29uZmlndXJhdGlvbnMuXG4gICAqIEBwYXJhbSB7YXJyYXk8c3RyaW5nPn0gbWFya3VwIExpc3Qgb2YgbWFya3VwIHN0cmluZ3MuXG4gICAqIEBpbnRlcm5hbFxuICAgKi9cbiAgZGFuZ2Vyb3VzbHlQcm9jZXNzQ2hpbGRyZW5VcGRhdGVzOiBSZWFjdFBlcmYubWVhc3VyZShcbiAgICAnUmVhY3RET01JRE9wZXJhdGlvbnMnLFxuICAgICdkYW5nZXJvdXNseVByb2Nlc3NDaGlsZHJlblVwZGF0ZXMnLFxuICAgIGZ1bmN0aW9uKHVwZGF0ZXMsIG1hcmt1cCkge1xuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB1cGRhdGVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHVwZGF0ZXNbaV0ucGFyZW50Tm9kZSA9IFJlYWN0TW91bnQuZ2V0Tm9kZSh1cGRhdGVzW2ldLnBhcmVudElEKTtcbiAgICAgIH1cbiAgICAgIERPTUNoaWxkcmVuT3BlcmF0aW9ucy5wcm9jZXNzVXBkYXRlcyh1cGRhdGVzLCBtYXJrdXApO1xuICAgIH1cbiAgKVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBSZWFjdERPTUlET3BlcmF0aW9ucztcblxufSkuY2FsbCh0aGlzLHJlcXVpcmUoJ19wcm9jZXNzJykpIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIFJlYWN0RE9NSW1nXG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBFdmVudENvbnN0YW50cyA9IHJlcXVpcmUoXCIuL0V2ZW50Q29uc3RhbnRzXCIpO1xudmFyIExvY2FsRXZlbnRUcmFwTWl4aW4gPSByZXF1aXJlKFwiLi9Mb2NhbEV2ZW50VHJhcE1peGluXCIpO1xudmFyIFJlYWN0QnJvd3NlckNvbXBvbmVudE1peGluID0gcmVxdWlyZShcIi4vUmVhY3RCcm93c2VyQ29tcG9uZW50TWl4aW5cIik7XG52YXIgUmVhY3RDb21wb3NpdGVDb21wb25lbnQgPSByZXF1aXJlKFwiLi9SZWFjdENvbXBvc2l0ZUNvbXBvbmVudFwiKTtcbnZhciBSZWFjdEVsZW1lbnQgPSByZXF1aXJlKFwiLi9SZWFjdEVsZW1lbnRcIik7XG52YXIgUmVhY3RET00gPSByZXF1aXJlKFwiLi9SZWFjdERPTVwiKTtcblxuLy8gU3RvcmUgYSByZWZlcmVuY2UgdG8gdGhlIDxpbWc+IGBSZWFjdERPTUNvbXBvbmVudGAuIFRPRE86IHVzZSBzdHJpbmdcbnZhciBpbWcgPSBSZWFjdEVsZW1lbnQuY3JlYXRlRmFjdG9yeShSZWFjdERPTS5pbWcudHlwZSk7XG5cbi8qKlxuICogU2luY2Ugb25Mb2FkIGRvZXNuJ3QgYnViYmxlIE9SIGNhcHR1cmUgb24gdGhlIHRvcCBsZXZlbCBpbiBJRTgsIHdlIG5lZWQgdG9cbiAqIGNhcHR1cmUgaXQgb24gdGhlIDxpbWc+IGVsZW1lbnQgaXRzZWxmLiBUaGVyZSBhcmUgbG90cyBvZiBoYWNrcyB3ZSBjb3VsZCBkb1xuICogdG8gYWNjb21wbGlzaCB0aGlzLCBidXQgdGhlIG1vc3QgcmVsaWFibGUgaXMgdG8gbWFrZSA8aW1nPiBhIGNvbXBvc2l0ZVxuICogY29tcG9uZW50IGFuZCB1c2UgYGNvbXBvbmVudERpZE1vdW50YCB0byBhdHRhY2ggdGhlIGV2ZW50IGhhbmRsZXJzLlxuICovXG52YXIgUmVhY3RET01JbWcgPSBSZWFjdENvbXBvc2l0ZUNvbXBvbmVudC5jcmVhdGVDbGFzcyh7XG4gIGRpc3BsYXlOYW1lOiAnUmVhY3RET01JbWcnLFxuICB0YWdOYW1lOiAnSU1HJyxcblxuICBtaXhpbnM6IFtSZWFjdEJyb3dzZXJDb21wb25lbnRNaXhpbiwgTG9jYWxFdmVudFRyYXBNaXhpbl0sXG5cbiAgcmVuZGVyOiBmdW5jdGlvbigpIHtcbiAgICByZXR1cm4gaW1nKHRoaXMucHJvcHMpO1xuICB9LFxuXG4gIGNvbXBvbmVudERpZE1vdW50OiBmdW5jdGlvbigpIHtcbiAgICB0aGlzLnRyYXBCdWJibGVkRXZlbnQoRXZlbnRDb25zdGFudHMudG9wTGV2ZWxUeXBlcy50b3BMb2FkLCAnbG9hZCcpO1xuICAgIHRoaXMudHJhcEJ1YmJsZWRFdmVudChFdmVudENvbnN0YW50cy50b3BMZXZlbFR5cGVzLnRvcEVycm9yLCAnZXJyb3InKTtcbiAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gUmVhY3RET01JbWc7XG4iLCIoZnVuY3Rpb24gKHByb2Nlc3Mpe1xuLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIFJlYWN0RE9NSW5wdXRcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIEF1dG9Gb2N1c01peGluID0gcmVxdWlyZShcIi4vQXV0b0ZvY3VzTWl4aW5cIik7XG52YXIgRE9NUHJvcGVydHlPcGVyYXRpb25zID0gcmVxdWlyZShcIi4vRE9NUHJvcGVydHlPcGVyYXRpb25zXCIpO1xudmFyIExpbmtlZFZhbHVlVXRpbHMgPSByZXF1aXJlKFwiLi9MaW5rZWRWYWx1ZVV0aWxzXCIpO1xudmFyIFJlYWN0QnJvd3NlckNvbXBvbmVudE1peGluID0gcmVxdWlyZShcIi4vUmVhY3RCcm93c2VyQ29tcG9uZW50TWl4aW5cIik7XG52YXIgUmVhY3RDb21wb3NpdGVDb21wb25lbnQgPSByZXF1aXJlKFwiLi9SZWFjdENvbXBvc2l0ZUNvbXBvbmVudFwiKTtcbnZhciBSZWFjdEVsZW1lbnQgPSByZXF1aXJlKFwiLi9SZWFjdEVsZW1lbnRcIik7XG52YXIgUmVhY3RET00gPSByZXF1aXJlKFwiLi9SZWFjdERPTVwiKTtcbnZhciBSZWFjdE1vdW50ID0gcmVxdWlyZShcIi4vUmVhY3RNb3VudFwiKTtcbnZhciBSZWFjdFVwZGF0ZXMgPSByZXF1aXJlKFwiLi9SZWFjdFVwZGF0ZXNcIik7XG5cbnZhciBhc3NpZ24gPSByZXF1aXJlKFwiLi9PYmplY3QuYXNzaWduXCIpO1xudmFyIGludmFyaWFudCA9IHJlcXVpcmUoXCIuL2ludmFyaWFudFwiKTtcblxuLy8gU3RvcmUgYSByZWZlcmVuY2UgdG8gdGhlIDxpbnB1dD4gYFJlYWN0RE9NQ29tcG9uZW50YC4gVE9ETzogdXNlIHN0cmluZ1xudmFyIGlucHV0ID0gUmVhY3RFbGVtZW50LmNyZWF0ZUZhY3RvcnkoUmVhY3RET00uaW5wdXQudHlwZSk7XG5cbnZhciBpbnN0YW5jZXNCeVJlYWN0SUQgPSB7fTtcblxuZnVuY3Rpb24gZm9yY2VVcGRhdGVJZk1vdW50ZWQoKSB7XG4gIC8qanNoaW50IHZhbGlkdGhpczp0cnVlICovXG4gIGlmICh0aGlzLmlzTW91bnRlZCgpKSB7XG4gICAgdGhpcy5mb3JjZVVwZGF0ZSgpO1xuICB9XG59XG5cbi8qKlxuICogSW1wbGVtZW50cyBhbiA8aW5wdXQ+IG5hdGl2ZSBjb21wb25lbnQgdGhhdCBhbGxvd3Mgc2V0dGluZyB0aGVzZSBvcHRpb25hbFxuICogcHJvcHM6IGBjaGVja2VkYCwgYHZhbHVlYCwgYGRlZmF1bHRDaGVja2VkYCwgYW5kIGBkZWZhdWx0VmFsdWVgLlxuICpcbiAqIElmIGBjaGVja2VkYCBvciBgdmFsdWVgIGFyZSBub3Qgc3VwcGxpZWQgKG9yIG51bGwvdW5kZWZpbmVkKSwgdXNlciBhY3Rpb25zXG4gKiB0aGF0IGFmZmVjdCB0aGUgY2hlY2tlZCBzdGF0ZSBvciB2YWx1ZSB3aWxsIHRyaWdnZXIgdXBkYXRlcyB0byB0aGUgZWxlbWVudC5cbiAqXG4gKiBJZiB0aGV5IGFyZSBzdXBwbGllZCAoYW5kIG5vdCBudWxsL3VuZGVmaW5lZCksIHRoZSByZW5kZXJlZCBlbGVtZW50IHdpbGwgbm90XG4gKiB0cmlnZ2VyIHVwZGF0ZXMgdG8gdGhlIGVsZW1lbnQuIEluc3RlYWQsIHRoZSBwcm9wcyBtdXN0IGNoYW5nZSBpbiBvcmRlciBmb3JcbiAqIHRoZSByZW5kZXJlZCBlbGVtZW50IHRvIGJlIHVwZGF0ZWQuXG4gKlxuICogVGhlIHJlbmRlcmVkIGVsZW1lbnQgd2lsbCBiZSBpbml0aWFsaXplZCBhcyB1bmNoZWNrZWQgKG9yIGBkZWZhdWx0Q2hlY2tlZGApXG4gKiB3aXRoIGFuIGVtcHR5IHZhbHVlIChvciBgZGVmYXVsdFZhbHVlYCkuXG4gKlxuICogQHNlZSBodHRwOi8vd3d3LnczLm9yZy9UUi8yMDEyL1dELWh0bWw1LTIwMTIxMDI1L3RoZS1pbnB1dC1lbGVtZW50Lmh0bWxcbiAqL1xudmFyIFJlYWN0RE9NSW5wdXQgPSBSZWFjdENvbXBvc2l0ZUNvbXBvbmVudC5jcmVhdGVDbGFzcyh7XG4gIGRpc3BsYXlOYW1lOiAnUmVhY3RET01JbnB1dCcsXG5cbiAgbWl4aW5zOiBbQXV0b0ZvY3VzTWl4aW4sIExpbmtlZFZhbHVlVXRpbHMuTWl4aW4sIFJlYWN0QnJvd3NlckNvbXBvbmVudE1peGluXSxcblxuICBnZXRJbml0aWFsU3RhdGU6IGZ1bmN0aW9uKCkge1xuICAgIHZhciBkZWZhdWx0VmFsdWUgPSB0aGlzLnByb3BzLmRlZmF1bHRWYWx1ZTtcbiAgICByZXR1cm4ge1xuICAgICAgaW5pdGlhbENoZWNrZWQ6IHRoaXMucHJvcHMuZGVmYXVsdENoZWNrZWQgfHwgZmFsc2UsXG4gICAgICBpbml0aWFsVmFsdWU6IGRlZmF1bHRWYWx1ZSAhPSBudWxsID8gZGVmYXVsdFZhbHVlIDogbnVsbFxuICAgIH07XG4gIH0sXG5cbiAgcmVuZGVyOiBmdW5jdGlvbigpIHtcbiAgICAvLyBDbG9uZSBgdGhpcy5wcm9wc2Agc28gd2UgZG9uJ3QgbXV0YXRlIHRoZSBpbnB1dC5cbiAgICB2YXIgcHJvcHMgPSBhc3NpZ24oe30sIHRoaXMucHJvcHMpO1xuXG4gICAgcHJvcHMuZGVmYXVsdENoZWNrZWQgPSBudWxsO1xuICAgIHByb3BzLmRlZmF1bHRWYWx1ZSA9IG51bGw7XG5cbiAgICB2YXIgdmFsdWUgPSBMaW5rZWRWYWx1ZVV0aWxzLmdldFZhbHVlKHRoaXMpO1xuICAgIHByb3BzLnZhbHVlID0gdmFsdWUgIT0gbnVsbCA/IHZhbHVlIDogdGhpcy5zdGF0ZS5pbml0aWFsVmFsdWU7XG5cbiAgICB2YXIgY2hlY2tlZCA9IExpbmtlZFZhbHVlVXRpbHMuZ2V0Q2hlY2tlZCh0aGlzKTtcbiAgICBwcm9wcy5jaGVja2VkID0gY2hlY2tlZCAhPSBudWxsID8gY2hlY2tlZCA6IHRoaXMuc3RhdGUuaW5pdGlhbENoZWNrZWQ7XG5cbiAgICBwcm9wcy5vbkNoYW5nZSA9IHRoaXMuX2hhbmRsZUNoYW5nZTtcblxuICAgIHJldHVybiBpbnB1dChwcm9wcywgdGhpcy5wcm9wcy5jaGlsZHJlbik7XG4gIH0sXG5cbiAgY29tcG9uZW50RGlkTW91bnQ6IGZ1bmN0aW9uKCkge1xuICAgIHZhciBpZCA9IFJlYWN0TW91bnQuZ2V0SUQodGhpcy5nZXRET01Ob2RlKCkpO1xuICAgIGluc3RhbmNlc0J5UmVhY3RJRFtpZF0gPSB0aGlzO1xuICB9LFxuXG4gIGNvbXBvbmVudFdpbGxVbm1vdW50OiBmdW5jdGlvbigpIHtcbiAgICB2YXIgcm9vdE5vZGUgPSB0aGlzLmdldERPTU5vZGUoKTtcbiAgICB2YXIgaWQgPSBSZWFjdE1vdW50LmdldElEKHJvb3ROb2RlKTtcbiAgICBkZWxldGUgaW5zdGFuY2VzQnlSZWFjdElEW2lkXTtcbiAgfSxcblxuICBjb21wb25lbnREaWRVcGRhdGU6IGZ1bmN0aW9uKHByZXZQcm9wcywgcHJldlN0YXRlLCBwcmV2Q29udGV4dCkge1xuICAgIHZhciByb290Tm9kZSA9IHRoaXMuZ2V0RE9NTm9kZSgpO1xuICAgIGlmICh0aGlzLnByb3BzLmNoZWNrZWQgIT0gbnVsbCkge1xuICAgICAgRE9NUHJvcGVydHlPcGVyYXRpb25zLnNldFZhbHVlRm9yUHJvcGVydHkoXG4gICAgICAgIHJvb3ROb2RlLFxuICAgICAgICAnY2hlY2tlZCcsXG4gICAgICAgIHRoaXMucHJvcHMuY2hlY2tlZCB8fCBmYWxzZVxuICAgICAgKTtcbiAgICB9XG5cbiAgICB2YXIgdmFsdWUgPSBMaW5rZWRWYWx1ZVV0aWxzLmdldFZhbHVlKHRoaXMpO1xuICAgIGlmICh2YWx1ZSAhPSBudWxsKSB7XG4gICAgICAvLyBDYXN0IGB2YWx1ZWAgdG8gYSBzdHJpbmcgdG8gZW5zdXJlIHRoZSB2YWx1ZSBpcyBzZXQgY29ycmVjdGx5LiBXaGlsZVxuICAgICAgLy8gYnJvd3NlcnMgdHlwaWNhbGx5IGRvIHRoaXMgYXMgbmVjZXNzYXJ5LCBqc2RvbSBkb2Vzbid0LlxuICAgICAgRE9NUHJvcGVydHlPcGVyYXRpb25zLnNldFZhbHVlRm9yUHJvcGVydHkocm9vdE5vZGUsICd2YWx1ZScsICcnICsgdmFsdWUpO1xuICAgIH1cbiAgfSxcblxuICBfaGFuZGxlQ2hhbmdlOiBmdW5jdGlvbihldmVudCkge1xuICAgIHZhciByZXR1cm5WYWx1ZTtcbiAgICB2YXIgb25DaGFuZ2UgPSBMaW5rZWRWYWx1ZVV0aWxzLmdldE9uQ2hhbmdlKHRoaXMpO1xuICAgIGlmIChvbkNoYW5nZSkge1xuICAgICAgcmV0dXJuVmFsdWUgPSBvbkNoYW5nZS5jYWxsKHRoaXMsIGV2ZW50KTtcbiAgICB9XG4gICAgLy8gSGVyZSB3ZSB1c2UgYXNhcCB0byB3YWl0IHVudGlsIGFsbCB1cGRhdGVzIGhhdmUgcHJvcGFnYXRlZCwgd2hpY2hcbiAgICAvLyBpcyBpbXBvcnRhbnQgd2hlbiB1c2luZyBjb250cm9sbGVkIGNvbXBvbmVudHMgd2l0aGluIGxheWVyczpcbiAgICAvLyBodHRwczovL2dpdGh1Yi5jb20vZmFjZWJvb2svcmVhY3QvaXNzdWVzLzE2OThcbiAgICBSZWFjdFVwZGF0ZXMuYXNhcChmb3JjZVVwZGF0ZUlmTW91bnRlZCwgdGhpcyk7XG5cbiAgICB2YXIgbmFtZSA9IHRoaXMucHJvcHMubmFtZTtcbiAgICBpZiAodGhpcy5wcm9wcy50eXBlID09PSAncmFkaW8nICYmIG5hbWUgIT0gbnVsbCkge1xuICAgICAgdmFyIHJvb3ROb2RlID0gdGhpcy5nZXRET01Ob2RlKCk7XG4gICAgICB2YXIgcXVlcnlSb290ID0gcm9vdE5vZGU7XG5cbiAgICAgIHdoaWxlIChxdWVyeVJvb3QucGFyZW50Tm9kZSkge1xuICAgICAgICBxdWVyeVJvb3QgPSBxdWVyeVJvb3QucGFyZW50Tm9kZTtcbiAgICAgIH1cblxuICAgICAgLy8gSWYgYHJvb3ROb2RlLmZvcm1gIHdhcyBub24tbnVsbCwgdGhlbiB3ZSBjb3VsZCB0cnkgYGZvcm0uZWxlbWVudHNgLFxuICAgICAgLy8gYnV0IHRoYXQgc29tZXRpbWVzIGJlaGF2ZXMgc3RyYW5nZWx5IGluIElFOC4gV2UgY291bGQgYWxzbyB0cnkgdXNpbmdcbiAgICAgIC8vIGBmb3JtLmdldEVsZW1lbnRzQnlOYW1lYCwgYnV0IHRoYXQgd2lsbCBvbmx5IHJldHVybiBkaXJlY3QgY2hpbGRyZW5cbiAgICAgIC8vIGFuZCB3b24ndCBpbmNsdWRlIGlucHV0cyB0aGF0IHVzZSB0aGUgSFRNTDUgYGZvcm09YCBhdHRyaWJ1dGUuIFNpbmNlXG4gICAgICAvLyB0aGUgaW5wdXQgbWlnaHQgbm90IGV2ZW4gYmUgaW4gYSBmb3JtLCBsZXQncyBqdXN0IHVzZSB0aGUgZ2xvYmFsXG4gICAgICAvLyBgcXVlcnlTZWxlY3RvckFsbGAgdG8gZW5zdXJlIHdlIGRvbid0IG1pc3MgYW55dGhpbmcuXG4gICAgICB2YXIgZ3JvdXAgPSBxdWVyeVJvb3QucXVlcnlTZWxlY3RvckFsbChcbiAgICAgICAgJ2lucHV0W25hbWU9JyArIEpTT04uc3RyaW5naWZ5KCcnICsgbmFtZSkgKyAnXVt0eXBlPVwicmFkaW9cIl0nKTtcblxuICAgICAgZm9yICh2YXIgaSA9IDAsIGdyb3VwTGVuID0gZ3JvdXAubGVuZ3RoOyBpIDwgZ3JvdXBMZW47IGkrKykge1xuICAgICAgICB2YXIgb3RoZXJOb2RlID0gZ3JvdXBbaV07XG4gICAgICAgIGlmIChvdGhlck5vZGUgPT09IHJvb3ROb2RlIHx8XG4gICAgICAgICAgICBvdGhlck5vZGUuZm9ybSAhPT0gcm9vdE5vZGUuZm9ybSkge1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG4gICAgICAgIHZhciBvdGhlcklEID0gUmVhY3RNb3VudC5nZXRJRChvdGhlck5vZGUpO1xuICAgICAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgICAgIG90aGVySUQsXG4gICAgICAgICAgJ1JlYWN0RE9NSW5wdXQ6IE1peGluZyBSZWFjdCBhbmQgbm9uLVJlYWN0IHJhZGlvIGlucHV0cyB3aXRoIHRoZSAnICtcbiAgICAgICAgICAnc2FtZSBgbmFtZWAgaXMgbm90IHN1cHBvcnRlZC4nXG4gICAgICAgICkgOiBpbnZhcmlhbnQob3RoZXJJRCkpO1xuICAgICAgICB2YXIgb3RoZXJJbnN0YW5jZSA9IGluc3RhbmNlc0J5UmVhY3RJRFtvdGhlcklEXTtcbiAgICAgICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgICAgICBvdGhlckluc3RhbmNlLFxuICAgICAgICAgICdSZWFjdERPTUlucHV0OiBVbmtub3duIHJhZGlvIGJ1dHRvbiBJRCAlcy4nLFxuICAgICAgICAgIG90aGVySURcbiAgICAgICAgKSA6IGludmFyaWFudChvdGhlckluc3RhbmNlKSk7XG4gICAgICAgIC8vIElmIHRoaXMgaXMgYSBjb250cm9sbGVkIHJhZGlvIGJ1dHRvbiBncm91cCwgZm9yY2luZyB0aGUgaW5wdXQgdGhhdFxuICAgICAgICAvLyB3YXMgcHJldmlvdXNseSBjaGVja2VkIHRvIHVwZGF0ZSB3aWxsIGNhdXNlIGl0IHRvIGJlIGNvbWUgcmUtY2hlY2tlZFxuICAgICAgICAvLyBhcyBhcHByb3ByaWF0ZS5cbiAgICAgICAgUmVhY3RVcGRhdGVzLmFzYXAoZm9yY2VVcGRhdGVJZk1vdW50ZWQsIG90aGVySW5zdGFuY2UpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiByZXR1cm5WYWx1ZTtcbiAgfVxuXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBSZWFjdERPTUlucHV0O1xuXG59KS5jYWxsKHRoaXMscmVxdWlyZSgnX3Byb2Nlc3MnKSkiLCIoZnVuY3Rpb24gKHByb2Nlc3Mpe1xuLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIFJlYWN0RE9NT3B0aW9uXG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBSZWFjdEJyb3dzZXJDb21wb25lbnRNaXhpbiA9IHJlcXVpcmUoXCIuL1JlYWN0QnJvd3NlckNvbXBvbmVudE1peGluXCIpO1xudmFyIFJlYWN0Q29tcG9zaXRlQ29tcG9uZW50ID0gcmVxdWlyZShcIi4vUmVhY3RDb21wb3NpdGVDb21wb25lbnRcIik7XG52YXIgUmVhY3RFbGVtZW50ID0gcmVxdWlyZShcIi4vUmVhY3RFbGVtZW50XCIpO1xudmFyIFJlYWN0RE9NID0gcmVxdWlyZShcIi4vUmVhY3RET01cIik7XG5cbnZhciB3YXJuaW5nID0gcmVxdWlyZShcIi4vd2FybmluZ1wiKTtcblxuLy8gU3RvcmUgYSByZWZlcmVuY2UgdG8gdGhlIDxvcHRpb24+IGBSZWFjdERPTUNvbXBvbmVudGAuIFRPRE86IHVzZSBzdHJpbmdcbnZhciBvcHRpb24gPSBSZWFjdEVsZW1lbnQuY3JlYXRlRmFjdG9yeShSZWFjdERPTS5vcHRpb24udHlwZSk7XG5cbi8qKlxuICogSW1wbGVtZW50cyBhbiA8b3B0aW9uPiBuYXRpdmUgY29tcG9uZW50IHRoYXQgd2FybnMgd2hlbiBgc2VsZWN0ZWRgIGlzIHNldC5cbiAqL1xudmFyIFJlYWN0RE9NT3B0aW9uID0gUmVhY3RDb21wb3NpdGVDb21wb25lbnQuY3JlYXRlQ2xhc3Moe1xuICBkaXNwbGF5TmFtZTogJ1JlYWN0RE9NT3B0aW9uJyxcblxuICBtaXhpbnM6IFtSZWFjdEJyb3dzZXJDb21wb25lbnRNaXhpbl0sXG5cbiAgY29tcG9uZW50V2lsbE1vdW50OiBmdW5jdGlvbigpIHtcbiAgICAvLyBUT0RPICh5dW5nc3RlcnMpOiBSZW1vdmUgc3VwcG9ydCBmb3IgYHNlbGVjdGVkYCBpbiA8b3B0aW9uPi5cbiAgICBpZiAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WKSB7XG4gICAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gd2FybmluZyhcbiAgICAgICAgdGhpcy5wcm9wcy5zZWxlY3RlZCA9PSBudWxsLFxuICAgICAgICAnVXNlIHRoZSBgZGVmYXVsdFZhbHVlYCBvciBgdmFsdWVgIHByb3BzIG9uIDxzZWxlY3Q+IGluc3RlYWQgb2YgJyArXG4gICAgICAgICdzZXR0aW5nIGBzZWxlY3RlZGAgb24gPG9wdGlvbj4uJ1xuICAgICAgKSA6IG51bGwpO1xuICAgIH1cbiAgfSxcblxuICByZW5kZXI6IGZ1bmN0aW9uKCkge1xuICAgIHJldHVybiBvcHRpb24odGhpcy5wcm9wcywgdGhpcy5wcm9wcy5jaGlsZHJlbik7XG4gIH1cblxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gUmVhY3RET01PcHRpb247XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKCdfcHJvY2VzcycpKSIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBSZWFjdERPTVNlbGVjdFxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgQXV0b0ZvY3VzTWl4aW4gPSByZXF1aXJlKFwiLi9BdXRvRm9jdXNNaXhpblwiKTtcbnZhciBMaW5rZWRWYWx1ZVV0aWxzID0gcmVxdWlyZShcIi4vTGlua2VkVmFsdWVVdGlsc1wiKTtcbnZhciBSZWFjdEJyb3dzZXJDb21wb25lbnRNaXhpbiA9IHJlcXVpcmUoXCIuL1JlYWN0QnJvd3NlckNvbXBvbmVudE1peGluXCIpO1xudmFyIFJlYWN0Q29tcG9zaXRlQ29tcG9uZW50ID0gcmVxdWlyZShcIi4vUmVhY3RDb21wb3NpdGVDb21wb25lbnRcIik7XG52YXIgUmVhY3RFbGVtZW50ID0gcmVxdWlyZShcIi4vUmVhY3RFbGVtZW50XCIpO1xudmFyIFJlYWN0RE9NID0gcmVxdWlyZShcIi4vUmVhY3RET01cIik7XG52YXIgUmVhY3RVcGRhdGVzID0gcmVxdWlyZShcIi4vUmVhY3RVcGRhdGVzXCIpO1xuXG52YXIgYXNzaWduID0gcmVxdWlyZShcIi4vT2JqZWN0LmFzc2lnblwiKTtcblxuLy8gU3RvcmUgYSByZWZlcmVuY2UgdG8gdGhlIDxzZWxlY3Q+IGBSZWFjdERPTUNvbXBvbmVudGAuIFRPRE86IHVzZSBzdHJpbmdcbnZhciBzZWxlY3QgPSBSZWFjdEVsZW1lbnQuY3JlYXRlRmFjdG9yeShSZWFjdERPTS5zZWxlY3QudHlwZSk7XG5cbmZ1bmN0aW9uIHVwZGF0ZVdpdGhQZW5kaW5nVmFsdWVJZk1vdW50ZWQoKSB7XG4gIC8qanNoaW50IHZhbGlkdGhpczp0cnVlICovXG4gIGlmICh0aGlzLmlzTW91bnRlZCgpKSB7XG4gICAgdGhpcy5zZXRTdGF0ZSh7dmFsdWU6IHRoaXMuX3BlbmRpbmdWYWx1ZX0pO1xuICAgIHRoaXMuX3BlbmRpbmdWYWx1ZSA9IDA7XG4gIH1cbn1cblxuLyoqXG4gKiBWYWxpZGF0aW9uIGZ1bmN0aW9uIGZvciBgdmFsdWVgIGFuZCBgZGVmYXVsdFZhbHVlYC5cbiAqIEBwcml2YXRlXG4gKi9cbmZ1bmN0aW9uIHNlbGVjdFZhbHVlVHlwZShwcm9wcywgcHJvcE5hbWUsIGNvbXBvbmVudE5hbWUpIHtcbiAgaWYgKHByb3BzW3Byb3BOYW1lXSA9PSBudWxsKSB7XG4gICAgcmV0dXJuO1xuICB9XG4gIGlmIChwcm9wcy5tdWx0aXBsZSkge1xuICAgIGlmICghQXJyYXkuaXNBcnJheShwcm9wc1twcm9wTmFtZV0pKSB7XG4gICAgICByZXR1cm4gbmV3IEVycm9yKFxuICAgICAgICAoXCJUaGUgYFwiICsgcHJvcE5hbWUgKyBcImAgcHJvcCBzdXBwbGllZCB0byA8c2VsZWN0PiBtdXN0IGJlIGFuIGFycmF5IGlmIFwiKSArXG4gICAgICAgIChcImBtdWx0aXBsZWAgaXMgdHJ1ZS5cIilcbiAgICAgICk7XG4gICAgfVxuICB9IGVsc2Uge1xuICAgIGlmIChBcnJheS5pc0FycmF5KHByb3BzW3Byb3BOYW1lXSkpIHtcbiAgICAgIHJldHVybiBuZXcgRXJyb3IoXG4gICAgICAgIChcIlRoZSBgXCIgKyBwcm9wTmFtZSArIFwiYCBwcm9wIHN1cHBsaWVkIHRvIDxzZWxlY3Q+IG11c3QgYmUgYSBzY2FsYXIgXCIpICtcbiAgICAgICAgKFwidmFsdWUgaWYgYG11bHRpcGxlYCBpcyBmYWxzZS5cIilcbiAgICAgICk7XG4gICAgfVxuICB9XG59XG5cbi8qKlxuICogSWYgYHZhbHVlYCBpcyBzdXBwbGllZCwgdXBkYXRlcyA8b3B0aW9uPiBlbGVtZW50cyBvbiBtb3VudCBhbmQgdXBkYXRlLlxuICogQHBhcmFtIHtSZWFjdENvbXBvbmVudH0gY29tcG9uZW50IEluc3RhbmNlIG9mIFJlYWN0RE9NU2VsZWN0XG4gKiBAcGFyYW0gez8qfSBwcm9wVmFsdWUgRm9yIHVuY29udHJvbGxlZCBjb21wb25lbnRzLCBudWxsL3VuZGVmaW5lZC4gRm9yXG4gKiBjb250cm9sbGVkIGNvbXBvbmVudHMsIGEgc3RyaW5nIChvciB3aXRoIGBtdWx0aXBsZWAsIGEgbGlzdCBvZiBzdHJpbmdzKS5cbiAqIEBwcml2YXRlXG4gKi9cbmZ1bmN0aW9uIHVwZGF0ZU9wdGlvbnMoY29tcG9uZW50LCBwcm9wVmFsdWUpIHtcbiAgdmFyIG11bHRpcGxlID0gY29tcG9uZW50LnByb3BzLm11bHRpcGxlO1xuICB2YXIgdmFsdWUgPSBwcm9wVmFsdWUgIT0gbnVsbCA/IHByb3BWYWx1ZSA6IGNvbXBvbmVudC5zdGF0ZS52YWx1ZTtcbiAgdmFyIG9wdGlvbnMgPSBjb21wb25lbnQuZ2V0RE9NTm9kZSgpLm9wdGlvbnM7XG4gIHZhciBzZWxlY3RlZFZhbHVlLCBpLCBsO1xuICBpZiAobXVsdGlwbGUpIHtcbiAgICBzZWxlY3RlZFZhbHVlID0ge307XG4gICAgZm9yIChpID0gMCwgbCA9IHZhbHVlLmxlbmd0aDsgaSA8IGw7ICsraSkge1xuICAgICAgc2VsZWN0ZWRWYWx1ZVsnJyArIHZhbHVlW2ldXSA9IHRydWU7XG4gICAgfVxuICB9IGVsc2Uge1xuICAgIHNlbGVjdGVkVmFsdWUgPSAnJyArIHZhbHVlO1xuICB9XG4gIGZvciAoaSA9IDAsIGwgPSBvcHRpb25zLmxlbmd0aDsgaSA8IGw7IGkrKykge1xuICAgIHZhciBzZWxlY3RlZCA9IG11bHRpcGxlID9cbiAgICAgIHNlbGVjdGVkVmFsdWUuaGFzT3duUHJvcGVydHkob3B0aW9uc1tpXS52YWx1ZSkgOlxuICAgICAgb3B0aW9uc1tpXS52YWx1ZSA9PT0gc2VsZWN0ZWRWYWx1ZTtcblxuICAgIGlmIChzZWxlY3RlZCAhPT0gb3B0aW9uc1tpXS5zZWxlY3RlZCkge1xuICAgICAgb3B0aW9uc1tpXS5zZWxlY3RlZCA9IHNlbGVjdGVkO1xuICAgIH1cbiAgfVxufVxuXG4vKipcbiAqIEltcGxlbWVudHMgYSA8c2VsZWN0PiBuYXRpdmUgY29tcG9uZW50IHRoYXQgYWxsb3dzIG9wdGlvbmFsbHkgc2V0dGluZyB0aGVcbiAqIHByb3BzIGB2YWx1ZWAgYW5kIGBkZWZhdWx0VmFsdWVgLiBJZiBgbXVsdGlwbGVgIGlzIGZhbHNlLCB0aGUgcHJvcCBtdXN0IGJlIGFcbiAqIHN0cmluZy4gSWYgYG11bHRpcGxlYCBpcyB0cnVlLCB0aGUgcHJvcCBtdXN0IGJlIGFuIGFycmF5IG9mIHN0cmluZ3MuXG4gKlxuICogSWYgYHZhbHVlYCBpcyBub3Qgc3VwcGxpZWQgKG9yIG51bGwvdW5kZWZpbmVkKSwgdXNlciBhY3Rpb25zIHRoYXQgY2hhbmdlIHRoZVxuICogc2VsZWN0ZWQgb3B0aW9uIHdpbGwgdHJpZ2dlciB1cGRhdGVzIHRvIHRoZSByZW5kZXJlZCBvcHRpb25zLlxuICpcbiAqIElmIGl0IGlzIHN1cHBsaWVkIChhbmQgbm90IG51bGwvdW5kZWZpbmVkKSwgdGhlIHJlbmRlcmVkIG9wdGlvbnMgd2lsbCBub3RcbiAqIHVwZGF0ZSBpbiByZXNwb25zZSB0byB1c2VyIGFjdGlvbnMuIEluc3RlYWQsIHRoZSBgdmFsdWVgIHByb3AgbXVzdCBjaGFuZ2UgaW5cbiAqIG9yZGVyIGZvciB0aGUgcmVuZGVyZWQgb3B0aW9ucyB0byB1cGRhdGUuXG4gKlxuICogSWYgYGRlZmF1bHRWYWx1ZWAgaXMgcHJvdmlkZWQsIGFueSBvcHRpb25zIHdpdGggdGhlIHN1cHBsaWVkIHZhbHVlcyB3aWxsIGJlXG4gKiBzZWxlY3RlZC5cbiAqL1xudmFyIFJlYWN0RE9NU2VsZWN0ID0gUmVhY3RDb21wb3NpdGVDb21wb25lbnQuY3JlYXRlQ2xhc3Moe1xuICBkaXNwbGF5TmFtZTogJ1JlYWN0RE9NU2VsZWN0JyxcblxuICBtaXhpbnM6IFtBdXRvRm9jdXNNaXhpbiwgTGlua2VkVmFsdWVVdGlscy5NaXhpbiwgUmVhY3RCcm93c2VyQ29tcG9uZW50TWl4aW5dLFxuXG4gIHByb3BUeXBlczoge1xuICAgIGRlZmF1bHRWYWx1ZTogc2VsZWN0VmFsdWVUeXBlLFxuICAgIHZhbHVlOiBzZWxlY3RWYWx1ZVR5cGVcbiAgfSxcblxuICBnZXRJbml0aWFsU3RhdGU6IGZ1bmN0aW9uKCkge1xuICAgIHJldHVybiB7dmFsdWU6IHRoaXMucHJvcHMuZGVmYXVsdFZhbHVlIHx8ICh0aGlzLnByb3BzLm11bHRpcGxlID8gW10gOiAnJyl9O1xuICB9LFxuXG4gIGNvbXBvbmVudFdpbGxNb3VudDogZnVuY3Rpb24oKSB7XG4gICAgdGhpcy5fcGVuZGluZ1ZhbHVlID0gbnVsbDtcbiAgfSxcblxuICBjb21wb25lbnRXaWxsUmVjZWl2ZVByb3BzOiBmdW5jdGlvbihuZXh0UHJvcHMpIHtcbiAgICBpZiAoIXRoaXMucHJvcHMubXVsdGlwbGUgJiYgbmV4dFByb3BzLm11bHRpcGxlKSB7XG4gICAgICB0aGlzLnNldFN0YXRlKHt2YWx1ZTogW3RoaXMuc3RhdGUudmFsdWVdfSk7XG4gICAgfSBlbHNlIGlmICh0aGlzLnByb3BzLm11bHRpcGxlICYmICFuZXh0UHJvcHMubXVsdGlwbGUpIHtcbiAgICAgIHRoaXMuc2V0U3RhdGUoe3ZhbHVlOiB0aGlzLnN0YXRlLnZhbHVlWzBdfSk7XG4gICAgfVxuICB9LFxuXG4gIHJlbmRlcjogZnVuY3Rpb24oKSB7XG4gICAgLy8gQ2xvbmUgYHRoaXMucHJvcHNgIHNvIHdlIGRvbid0IG11dGF0ZSB0aGUgaW5wdXQuXG4gICAgdmFyIHByb3BzID0gYXNzaWduKHt9LCB0aGlzLnByb3BzKTtcblxuICAgIHByb3BzLm9uQ2hhbmdlID0gdGhpcy5faGFuZGxlQ2hhbmdlO1xuICAgIHByb3BzLnZhbHVlID0gbnVsbDtcblxuICAgIHJldHVybiBzZWxlY3QocHJvcHMsIHRoaXMucHJvcHMuY2hpbGRyZW4pO1xuICB9LFxuXG4gIGNvbXBvbmVudERpZE1vdW50OiBmdW5jdGlvbigpIHtcbiAgICB1cGRhdGVPcHRpb25zKHRoaXMsIExpbmtlZFZhbHVlVXRpbHMuZ2V0VmFsdWUodGhpcykpO1xuICB9LFxuXG4gIGNvbXBvbmVudERpZFVwZGF0ZTogZnVuY3Rpb24ocHJldlByb3BzKSB7XG4gICAgdmFyIHZhbHVlID0gTGlua2VkVmFsdWVVdGlscy5nZXRWYWx1ZSh0aGlzKTtcbiAgICB2YXIgcHJldk11bHRpcGxlID0gISFwcmV2UHJvcHMubXVsdGlwbGU7XG4gICAgdmFyIG11bHRpcGxlID0gISF0aGlzLnByb3BzLm11bHRpcGxlO1xuICAgIGlmICh2YWx1ZSAhPSBudWxsIHx8IHByZXZNdWx0aXBsZSAhPT0gbXVsdGlwbGUpIHtcbiAgICAgIHVwZGF0ZU9wdGlvbnModGhpcywgdmFsdWUpO1xuICAgIH1cbiAgfSxcblxuICBfaGFuZGxlQ2hhbmdlOiBmdW5jdGlvbihldmVudCkge1xuICAgIHZhciByZXR1cm5WYWx1ZTtcbiAgICB2YXIgb25DaGFuZ2UgPSBMaW5rZWRWYWx1ZVV0aWxzLmdldE9uQ2hhbmdlKHRoaXMpO1xuICAgIGlmIChvbkNoYW5nZSkge1xuICAgICAgcmV0dXJuVmFsdWUgPSBvbkNoYW5nZS5jYWxsKHRoaXMsIGV2ZW50KTtcbiAgICB9XG5cbiAgICB2YXIgc2VsZWN0ZWRWYWx1ZTtcbiAgICBpZiAodGhpcy5wcm9wcy5tdWx0aXBsZSkge1xuICAgICAgc2VsZWN0ZWRWYWx1ZSA9IFtdO1xuICAgICAgdmFyIG9wdGlvbnMgPSBldmVudC50YXJnZXQub3B0aW9ucztcbiAgICAgIGZvciAodmFyIGkgPSAwLCBsID0gb3B0aW9ucy5sZW5ndGg7IGkgPCBsOyBpKyspIHtcbiAgICAgICAgaWYgKG9wdGlvbnNbaV0uc2VsZWN0ZWQpIHtcbiAgICAgICAgICBzZWxlY3RlZFZhbHVlLnB1c2gob3B0aW9uc1tpXS52YWx1ZSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgc2VsZWN0ZWRWYWx1ZSA9IGV2ZW50LnRhcmdldC52YWx1ZTtcbiAgICB9XG5cbiAgICB0aGlzLl9wZW5kaW5nVmFsdWUgPSBzZWxlY3RlZFZhbHVlO1xuICAgIFJlYWN0VXBkYXRlcy5hc2FwKHVwZGF0ZVdpdGhQZW5kaW5nVmFsdWVJZk1vdW50ZWQsIHRoaXMpO1xuICAgIHJldHVybiByZXR1cm5WYWx1ZTtcbiAgfVxuXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBSZWFjdERPTVNlbGVjdDtcbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBSZWFjdERPTVNlbGVjdGlvblxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgRXhlY3V0aW9uRW52aXJvbm1lbnQgPSByZXF1aXJlKFwiLi9FeGVjdXRpb25FbnZpcm9ubWVudFwiKTtcblxudmFyIGdldE5vZGVGb3JDaGFyYWN0ZXJPZmZzZXQgPSByZXF1aXJlKFwiLi9nZXROb2RlRm9yQ2hhcmFjdGVyT2Zmc2V0XCIpO1xudmFyIGdldFRleHRDb250ZW50QWNjZXNzb3IgPSByZXF1aXJlKFwiLi9nZXRUZXh0Q29udGVudEFjY2Vzc29yXCIpO1xuXG4vKipcbiAqIFdoaWxlIGBpc0NvbGxhcHNlZGAgaXMgYXZhaWxhYmxlIG9uIHRoZSBTZWxlY3Rpb24gb2JqZWN0IGFuZCBgY29sbGFwc2VkYFxuICogaXMgYXZhaWxhYmxlIG9uIHRoZSBSYW5nZSBvYmplY3QsIElFMTEgc29tZXRpbWVzIGdldHMgdGhlbSB3cm9uZy5cbiAqIElmIHRoZSBhbmNob3IvZm9jdXMgbm9kZXMgYW5kIG9mZnNldHMgYXJlIHRoZSBzYW1lLCB0aGUgcmFuZ2UgaXMgY29sbGFwc2VkLlxuICovXG5mdW5jdGlvbiBpc0NvbGxhcHNlZChhbmNob3JOb2RlLCBhbmNob3JPZmZzZXQsIGZvY3VzTm9kZSwgZm9jdXNPZmZzZXQpIHtcbiAgcmV0dXJuIGFuY2hvck5vZGUgPT09IGZvY3VzTm9kZSAmJiBhbmNob3JPZmZzZXQgPT09IGZvY3VzT2Zmc2V0O1xufVxuXG4vKipcbiAqIEdldCB0aGUgYXBwcm9wcmlhdGUgYW5jaG9yIGFuZCBmb2N1cyBub2RlL29mZnNldCBwYWlycyBmb3IgSUUuXG4gKlxuICogVGhlIGNhdGNoIGhlcmUgaXMgdGhhdCBJRSdzIHNlbGVjdGlvbiBBUEkgZG9lc24ndCBwcm92aWRlIGluZm9ybWF0aW9uXG4gKiBhYm91dCB3aGV0aGVyIHRoZSBzZWxlY3Rpb24gaXMgZm9yd2FyZCBvciBiYWNrd2FyZCwgc28gd2UgaGF2ZSB0b1xuICogYmVoYXZlIGFzIHRob3VnaCBpdCdzIGFsd2F5cyBmb3J3YXJkLlxuICpcbiAqIElFIHRleHQgZGlmZmVycyBmcm9tIG1vZGVybiBzZWxlY3Rpb24gaW4gdGhhdCBpdCBiZWhhdmVzIGFzIHRob3VnaFxuICogYmxvY2sgZWxlbWVudHMgZW5kIHdpdGggYSBuZXcgbGluZS4gVGhpcyBtZWFucyBjaGFyYWN0ZXIgb2Zmc2V0cyB3aWxsXG4gKiBkaWZmZXIgYmV0d2VlbiB0aGUgdHdvIEFQSXMuXG4gKlxuICogQHBhcmFtIHtET01FbGVtZW50fSBub2RlXG4gKiBAcmV0dXJuIHtvYmplY3R9XG4gKi9cbmZ1bmN0aW9uIGdldElFT2Zmc2V0cyhub2RlKSB7XG4gIHZhciBzZWxlY3Rpb24gPSBkb2N1bWVudC5zZWxlY3Rpb247XG4gIHZhciBzZWxlY3RlZFJhbmdlID0gc2VsZWN0aW9uLmNyZWF0ZVJhbmdlKCk7XG4gIHZhciBzZWxlY3RlZExlbmd0aCA9IHNlbGVjdGVkUmFuZ2UudGV4dC5sZW5ndGg7XG5cbiAgLy8gRHVwbGljYXRlIHNlbGVjdGlvbiBzbyB3ZSBjYW4gbW92ZSByYW5nZSB3aXRob3V0IGJyZWFraW5nIHVzZXIgc2VsZWN0aW9uLlxuICB2YXIgZnJvbVN0YXJ0ID0gc2VsZWN0ZWRSYW5nZS5kdXBsaWNhdGUoKTtcbiAgZnJvbVN0YXJ0Lm1vdmVUb0VsZW1lbnRUZXh0KG5vZGUpO1xuICBmcm9tU3RhcnQuc2V0RW5kUG9pbnQoJ0VuZFRvU3RhcnQnLCBzZWxlY3RlZFJhbmdlKTtcblxuICB2YXIgc3RhcnRPZmZzZXQgPSBmcm9tU3RhcnQudGV4dC5sZW5ndGg7XG4gIHZhciBlbmRPZmZzZXQgPSBzdGFydE9mZnNldCArIHNlbGVjdGVkTGVuZ3RoO1xuXG4gIHJldHVybiB7XG4gICAgc3RhcnQ6IHN0YXJ0T2Zmc2V0LFxuICAgIGVuZDogZW5kT2Zmc2V0XG4gIH07XG59XG5cbi8qKlxuICogQHBhcmFtIHtET01FbGVtZW50fSBub2RlXG4gKiBAcmV0dXJuIHs/b2JqZWN0fVxuICovXG5mdW5jdGlvbiBnZXRNb2Rlcm5PZmZzZXRzKG5vZGUpIHtcbiAgdmFyIHNlbGVjdGlvbiA9IHdpbmRvdy5nZXRTZWxlY3Rpb24gJiYgd2luZG93LmdldFNlbGVjdGlvbigpO1xuXG4gIGlmICghc2VsZWN0aW9uIHx8IHNlbGVjdGlvbi5yYW5nZUNvdW50ID09PSAwKSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICB2YXIgYW5jaG9yTm9kZSA9IHNlbGVjdGlvbi5hbmNob3JOb2RlO1xuICB2YXIgYW5jaG9yT2Zmc2V0ID0gc2VsZWN0aW9uLmFuY2hvck9mZnNldDtcbiAgdmFyIGZvY3VzTm9kZSA9IHNlbGVjdGlvbi5mb2N1c05vZGU7XG4gIHZhciBmb2N1c09mZnNldCA9IHNlbGVjdGlvbi5mb2N1c09mZnNldDtcblxuICB2YXIgY3VycmVudFJhbmdlID0gc2VsZWN0aW9uLmdldFJhbmdlQXQoMCk7XG5cbiAgLy8gSWYgdGhlIG5vZGUgYW5kIG9mZnNldCB2YWx1ZXMgYXJlIHRoZSBzYW1lLCB0aGUgc2VsZWN0aW9uIGlzIGNvbGxhcHNlZC5cbiAgLy8gYFNlbGVjdGlvbi5pc0NvbGxhcHNlZGAgaXMgYXZhaWxhYmxlIG5hdGl2ZWx5LCBidXQgSUUgc29tZXRpbWVzIGdldHNcbiAgLy8gdGhpcyB2YWx1ZSB3cm9uZy5cbiAgdmFyIGlzU2VsZWN0aW9uQ29sbGFwc2VkID0gaXNDb2xsYXBzZWQoXG4gICAgc2VsZWN0aW9uLmFuY2hvck5vZGUsXG4gICAgc2VsZWN0aW9uLmFuY2hvck9mZnNldCxcbiAgICBzZWxlY3Rpb24uZm9jdXNOb2RlLFxuICAgIHNlbGVjdGlvbi5mb2N1c09mZnNldFxuICApO1xuXG4gIHZhciByYW5nZUxlbmd0aCA9IGlzU2VsZWN0aW9uQ29sbGFwc2VkID8gMCA6IGN1cnJlbnRSYW5nZS50b1N0cmluZygpLmxlbmd0aDtcblxuICB2YXIgdGVtcFJhbmdlID0gY3VycmVudFJhbmdlLmNsb25lUmFuZ2UoKTtcbiAgdGVtcFJhbmdlLnNlbGVjdE5vZGVDb250ZW50cyhub2RlKTtcbiAgdGVtcFJhbmdlLnNldEVuZChjdXJyZW50UmFuZ2Uuc3RhcnRDb250YWluZXIsIGN1cnJlbnRSYW5nZS5zdGFydE9mZnNldCk7XG5cbiAgdmFyIGlzVGVtcFJhbmdlQ29sbGFwc2VkID0gaXNDb2xsYXBzZWQoXG4gICAgdGVtcFJhbmdlLnN0YXJ0Q29udGFpbmVyLFxuICAgIHRlbXBSYW5nZS5zdGFydE9mZnNldCxcbiAgICB0ZW1wUmFuZ2UuZW5kQ29udGFpbmVyLFxuICAgIHRlbXBSYW5nZS5lbmRPZmZzZXRcbiAgKTtcblxuICB2YXIgc3RhcnQgPSBpc1RlbXBSYW5nZUNvbGxhcHNlZCA/IDAgOiB0ZW1wUmFuZ2UudG9TdHJpbmcoKS5sZW5ndGg7XG4gIHZhciBlbmQgPSBzdGFydCArIHJhbmdlTGVuZ3RoO1xuXG4gIC8vIERldGVjdCB3aGV0aGVyIHRoZSBzZWxlY3Rpb24gaXMgYmFja3dhcmQuXG4gIHZhciBkZXRlY3Rpb25SYW5nZSA9IGRvY3VtZW50LmNyZWF0ZVJhbmdlKCk7XG4gIGRldGVjdGlvblJhbmdlLnNldFN0YXJ0KGFuY2hvck5vZGUsIGFuY2hvck9mZnNldCk7XG4gIGRldGVjdGlvblJhbmdlLnNldEVuZChmb2N1c05vZGUsIGZvY3VzT2Zmc2V0KTtcbiAgdmFyIGlzQmFja3dhcmQgPSBkZXRlY3Rpb25SYW5nZS5jb2xsYXBzZWQ7XG5cbiAgcmV0dXJuIHtcbiAgICBzdGFydDogaXNCYWNrd2FyZCA/IGVuZCA6IHN0YXJ0LFxuICAgIGVuZDogaXNCYWNrd2FyZCA/IHN0YXJ0IDogZW5kXG4gIH07XG59XG5cbi8qKlxuICogQHBhcmFtIHtET01FbGVtZW50fERPTVRleHROb2RlfSBub2RlXG4gKiBAcGFyYW0ge29iamVjdH0gb2Zmc2V0c1xuICovXG5mdW5jdGlvbiBzZXRJRU9mZnNldHMobm9kZSwgb2Zmc2V0cykge1xuICB2YXIgcmFuZ2UgPSBkb2N1bWVudC5zZWxlY3Rpb24uY3JlYXRlUmFuZ2UoKS5kdXBsaWNhdGUoKTtcbiAgdmFyIHN0YXJ0LCBlbmQ7XG5cbiAgaWYgKHR5cGVvZiBvZmZzZXRzLmVuZCA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICBzdGFydCA9IG9mZnNldHMuc3RhcnQ7XG4gICAgZW5kID0gc3RhcnQ7XG4gIH0gZWxzZSBpZiAob2Zmc2V0cy5zdGFydCA+IG9mZnNldHMuZW5kKSB7XG4gICAgc3RhcnQgPSBvZmZzZXRzLmVuZDtcbiAgICBlbmQgPSBvZmZzZXRzLnN0YXJ0O1xuICB9IGVsc2Uge1xuICAgIHN0YXJ0ID0gb2Zmc2V0cy5zdGFydDtcbiAgICBlbmQgPSBvZmZzZXRzLmVuZDtcbiAgfVxuXG4gIHJhbmdlLm1vdmVUb0VsZW1lbnRUZXh0KG5vZGUpO1xuICByYW5nZS5tb3ZlU3RhcnQoJ2NoYXJhY3RlcicsIHN0YXJ0KTtcbiAgcmFuZ2Uuc2V0RW5kUG9pbnQoJ0VuZFRvU3RhcnQnLCByYW5nZSk7XG4gIHJhbmdlLm1vdmVFbmQoJ2NoYXJhY3RlcicsIGVuZCAtIHN0YXJ0KTtcbiAgcmFuZ2Uuc2VsZWN0KCk7XG59XG5cbi8qKlxuICogSW4gbW9kZXJuIG5vbi1JRSBicm93c2Vycywgd2UgY2FuIHN1cHBvcnQgYm90aCBmb3J3YXJkIGFuZCBiYWNrd2FyZFxuICogc2VsZWN0aW9ucy5cbiAqXG4gKiBOb3RlOiBJRTEwKyBzdXBwb3J0cyB0aGUgU2VsZWN0aW9uIG9iamVjdCwgYnV0IGl0IGRvZXMgbm90IHN1cHBvcnRcbiAqIHRoZSBgZXh0ZW5kYCBtZXRob2QsIHdoaWNoIG1lYW5zIHRoYXQgZXZlbiBpbiBtb2Rlcm4gSUUsIGl0J3Mgbm90IHBvc3NpYmxlXG4gKiB0byBwcm9ncmFtYXRpY2FsbHkgY3JlYXRlIGEgYmFja3dhcmQgc2VsZWN0aW9uLiBUaHVzLCBmb3IgYWxsIElFXG4gKiB2ZXJzaW9ucywgd2UgdXNlIHRoZSBvbGQgSUUgQVBJIHRvIGNyZWF0ZSBvdXIgc2VsZWN0aW9ucy5cbiAqXG4gKiBAcGFyYW0ge0RPTUVsZW1lbnR8RE9NVGV4dE5vZGV9IG5vZGVcbiAqIEBwYXJhbSB7b2JqZWN0fSBvZmZzZXRzXG4gKi9cbmZ1bmN0aW9uIHNldE1vZGVybk9mZnNldHMobm9kZSwgb2Zmc2V0cykge1xuICBpZiAoIXdpbmRvdy5nZXRTZWxlY3Rpb24pIHtcbiAgICByZXR1cm47XG4gIH1cblxuICB2YXIgc2VsZWN0aW9uID0gd2luZG93LmdldFNlbGVjdGlvbigpO1xuICB2YXIgbGVuZ3RoID0gbm9kZVtnZXRUZXh0Q29udGVudEFjY2Vzc29yKCldLmxlbmd0aDtcbiAgdmFyIHN0YXJ0ID0gTWF0aC5taW4ob2Zmc2V0cy5zdGFydCwgbGVuZ3RoKTtcbiAgdmFyIGVuZCA9IHR5cGVvZiBvZmZzZXRzLmVuZCA9PT0gJ3VuZGVmaW5lZCcgP1xuICAgICAgICAgICAgc3RhcnQgOiBNYXRoLm1pbihvZmZzZXRzLmVuZCwgbGVuZ3RoKTtcblxuICAvLyBJRSAxMSB1c2VzIG1vZGVybiBzZWxlY3Rpb24sIGJ1dCBkb2Vzbid0IHN1cHBvcnQgdGhlIGV4dGVuZCBtZXRob2QuXG4gIC8vIEZsaXAgYmFja3dhcmQgc2VsZWN0aW9ucywgc28gd2UgY2FuIHNldCB3aXRoIGEgc2luZ2xlIHJhbmdlLlxuICBpZiAoIXNlbGVjdGlvbi5leHRlbmQgJiYgc3RhcnQgPiBlbmQpIHtcbiAgICB2YXIgdGVtcCA9IGVuZDtcbiAgICBlbmQgPSBzdGFydDtcbiAgICBzdGFydCA9IHRlbXA7XG4gIH1cblxuICB2YXIgc3RhcnRNYXJrZXIgPSBnZXROb2RlRm9yQ2hhcmFjdGVyT2Zmc2V0KG5vZGUsIHN0YXJ0KTtcbiAgdmFyIGVuZE1hcmtlciA9IGdldE5vZGVGb3JDaGFyYWN0ZXJPZmZzZXQobm9kZSwgZW5kKTtcblxuICBpZiAoc3RhcnRNYXJrZXIgJiYgZW5kTWFya2VyKSB7XG4gICAgdmFyIHJhbmdlID0gZG9jdW1lbnQuY3JlYXRlUmFuZ2UoKTtcbiAgICByYW5nZS5zZXRTdGFydChzdGFydE1hcmtlci5ub2RlLCBzdGFydE1hcmtlci5vZmZzZXQpO1xuICAgIHNlbGVjdGlvbi5yZW1vdmVBbGxSYW5nZXMoKTtcblxuICAgIGlmIChzdGFydCA+IGVuZCkge1xuICAgICAgc2VsZWN0aW9uLmFkZFJhbmdlKHJhbmdlKTtcbiAgICAgIHNlbGVjdGlvbi5leHRlbmQoZW5kTWFya2VyLm5vZGUsIGVuZE1hcmtlci5vZmZzZXQpO1xuICAgIH0gZWxzZSB7XG4gICAgICByYW5nZS5zZXRFbmQoZW5kTWFya2VyLm5vZGUsIGVuZE1hcmtlci5vZmZzZXQpO1xuICAgICAgc2VsZWN0aW9uLmFkZFJhbmdlKHJhbmdlKTtcbiAgICB9XG4gIH1cbn1cblxudmFyIHVzZUlFT2Zmc2V0cyA9IEV4ZWN1dGlvbkVudmlyb25tZW50LmNhblVzZURPTSAmJiBkb2N1bWVudC5zZWxlY3Rpb247XG5cbnZhciBSZWFjdERPTVNlbGVjdGlvbiA9IHtcbiAgLyoqXG4gICAqIEBwYXJhbSB7RE9NRWxlbWVudH0gbm9kZVxuICAgKi9cbiAgZ2V0T2Zmc2V0czogdXNlSUVPZmZzZXRzID8gZ2V0SUVPZmZzZXRzIDogZ2V0TW9kZXJuT2Zmc2V0cyxcblxuICAvKipcbiAgICogQHBhcmFtIHtET01FbGVtZW50fERPTVRleHROb2RlfSBub2RlXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBvZmZzZXRzXG4gICAqL1xuICBzZXRPZmZzZXRzOiB1c2VJRU9mZnNldHMgPyBzZXRJRU9mZnNldHMgOiBzZXRNb2Rlcm5PZmZzZXRzXG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJlYWN0RE9NU2VsZWN0aW9uO1xuIiwiKGZ1bmN0aW9uIChwcm9jZXNzKXtcbi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBSZWFjdERPTVRleHRhcmVhXG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBBdXRvRm9jdXNNaXhpbiA9IHJlcXVpcmUoXCIuL0F1dG9Gb2N1c01peGluXCIpO1xudmFyIERPTVByb3BlcnR5T3BlcmF0aW9ucyA9IHJlcXVpcmUoXCIuL0RPTVByb3BlcnR5T3BlcmF0aW9uc1wiKTtcbnZhciBMaW5rZWRWYWx1ZVV0aWxzID0gcmVxdWlyZShcIi4vTGlua2VkVmFsdWVVdGlsc1wiKTtcbnZhciBSZWFjdEJyb3dzZXJDb21wb25lbnRNaXhpbiA9IHJlcXVpcmUoXCIuL1JlYWN0QnJvd3NlckNvbXBvbmVudE1peGluXCIpO1xudmFyIFJlYWN0Q29tcG9zaXRlQ29tcG9uZW50ID0gcmVxdWlyZShcIi4vUmVhY3RDb21wb3NpdGVDb21wb25lbnRcIik7XG52YXIgUmVhY3RFbGVtZW50ID0gcmVxdWlyZShcIi4vUmVhY3RFbGVtZW50XCIpO1xudmFyIFJlYWN0RE9NID0gcmVxdWlyZShcIi4vUmVhY3RET01cIik7XG52YXIgUmVhY3RVcGRhdGVzID0gcmVxdWlyZShcIi4vUmVhY3RVcGRhdGVzXCIpO1xuXG52YXIgYXNzaWduID0gcmVxdWlyZShcIi4vT2JqZWN0LmFzc2lnblwiKTtcbnZhciBpbnZhcmlhbnQgPSByZXF1aXJlKFwiLi9pbnZhcmlhbnRcIik7XG5cbnZhciB3YXJuaW5nID0gcmVxdWlyZShcIi4vd2FybmluZ1wiKTtcblxuLy8gU3RvcmUgYSByZWZlcmVuY2UgdG8gdGhlIDx0ZXh0YXJlYT4gYFJlYWN0RE9NQ29tcG9uZW50YC4gVE9ETzogdXNlIHN0cmluZ1xudmFyIHRleHRhcmVhID0gUmVhY3RFbGVtZW50LmNyZWF0ZUZhY3RvcnkoUmVhY3RET00udGV4dGFyZWEudHlwZSk7XG5cbmZ1bmN0aW9uIGZvcmNlVXBkYXRlSWZNb3VudGVkKCkge1xuICAvKmpzaGludCB2YWxpZHRoaXM6dHJ1ZSAqL1xuICBpZiAodGhpcy5pc01vdW50ZWQoKSkge1xuICAgIHRoaXMuZm9yY2VVcGRhdGUoKTtcbiAgfVxufVxuXG4vKipcbiAqIEltcGxlbWVudHMgYSA8dGV4dGFyZWE+IG5hdGl2ZSBjb21wb25lbnQgdGhhdCBhbGxvd3Mgc2V0dGluZyBgdmFsdWVgLCBhbmRcbiAqIGBkZWZhdWx0VmFsdWVgLiBUaGlzIGRpZmZlcnMgZnJvbSB0aGUgdHJhZGl0aW9uYWwgRE9NIEFQSSBiZWNhdXNlIHZhbHVlIGlzXG4gKiB1c3VhbGx5IHNldCBhcyBQQ0RBVEEgY2hpbGRyZW4uXG4gKlxuICogSWYgYHZhbHVlYCBpcyBub3Qgc3VwcGxpZWQgKG9yIG51bGwvdW5kZWZpbmVkKSwgdXNlciBhY3Rpb25zIHRoYXQgYWZmZWN0IHRoZVxuICogdmFsdWUgd2lsbCB0cmlnZ2VyIHVwZGF0ZXMgdG8gdGhlIGVsZW1lbnQuXG4gKlxuICogSWYgYHZhbHVlYCBpcyBzdXBwbGllZCAoYW5kIG5vdCBudWxsL3VuZGVmaW5lZCksIHRoZSByZW5kZXJlZCBlbGVtZW50IHdpbGxcbiAqIG5vdCB0cmlnZ2VyIHVwZGF0ZXMgdG8gdGhlIGVsZW1lbnQuIEluc3RlYWQsIHRoZSBgdmFsdWVgIHByb3AgbXVzdCBjaGFuZ2UgaW5cbiAqIG9yZGVyIGZvciB0aGUgcmVuZGVyZWQgZWxlbWVudCB0byBiZSB1cGRhdGVkLlxuICpcbiAqIFRoZSByZW5kZXJlZCBlbGVtZW50IHdpbGwgYmUgaW5pdGlhbGl6ZWQgd2l0aCBhbiBlbXB0eSB2YWx1ZSwgdGhlIHByb3BcbiAqIGBkZWZhdWx0VmFsdWVgIGlmIHNwZWNpZmllZCwgb3IgdGhlIGNoaWxkcmVuIGNvbnRlbnQgKGRlcHJlY2F0ZWQpLlxuICovXG52YXIgUmVhY3RET01UZXh0YXJlYSA9IFJlYWN0Q29tcG9zaXRlQ29tcG9uZW50LmNyZWF0ZUNsYXNzKHtcbiAgZGlzcGxheU5hbWU6ICdSZWFjdERPTVRleHRhcmVhJyxcblxuICBtaXhpbnM6IFtBdXRvRm9jdXNNaXhpbiwgTGlua2VkVmFsdWVVdGlscy5NaXhpbiwgUmVhY3RCcm93c2VyQ29tcG9uZW50TWl4aW5dLFxuXG4gIGdldEluaXRpYWxTdGF0ZTogZnVuY3Rpb24oKSB7XG4gICAgdmFyIGRlZmF1bHRWYWx1ZSA9IHRoaXMucHJvcHMuZGVmYXVsdFZhbHVlO1xuICAgIC8vIFRPRE8gKHl1bmdzdGVycyk6IFJlbW92ZSBzdXBwb3J0IGZvciBjaGlsZHJlbiBjb250ZW50IGluIDx0ZXh0YXJlYT4uXG4gICAgdmFyIGNoaWxkcmVuID0gdGhpcy5wcm9wcy5jaGlsZHJlbjtcbiAgICBpZiAoY2hpbGRyZW4gIT0gbnVsbCkge1xuICAgICAgaWYgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOVikge1xuICAgICAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gd2FybmluZyhcbiAgICAgICAgICBmYWxzZSxcbiAgICAgICAgICAnVXNlIHRoZSBgZGVmYXVsdFZhbHVlYCBvciBgdmFsdWVgIHByb3BzIGluc3RlYWQgb2Ygc2V0dGluZyAnICtcbiAgICAgICAgICAnY2hpbGRyZW4gb24gPHRleHRhcmVhPi4nXG4gICAgICAgICkgOiBudWxsKTtcbiAgICAgIH1cbiAgICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICAgIGRlZmF1bHRWYWx1ZSA9PSBudWxsLFxuICAgICAgICAnSWYgeW91IHN1cHBseSBgZGVmYXVsdFZhbHVlYCBvbiBhIDx0ZXh0YXJlYT4sIGRvIG5vdCBwYXNzIGNoaWxkcmVuLidcbiAgICAgICkgOiBpbnZhcmlhbnQoZGVmYXVsdFZhbHVlID09IG51bGwpKTtcbiAgICAgIGlmIChBcnJheS5pc0FycmF5KGNoaWxkcmVuKSkge1xuICAgICAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgICAgIGNoaWxkcmVuLmxlbmd0aCA8PSAxLFxuICAgICAgICAgICc8dGV4dGFyZWE+IGNhbiBvbmx5IGhhdmUgYXQgbW9zdCBvbmUgY2hpbGQuJ1xuICAgICAgICApIDogaW52YXJpYW50KGNoaWxkcmVuLmxlbmd0aCA8PSAxKSk7XG4gICAgICAgIGNoaWxkcmVuID0gY2hpbGRyZW5bMF07XG4gICAgICB9XG5cbiAgICAgIGRlZmF1bHRWYWx1ZSA9ICcnICsgY2hpbGRyZW47XG4gICAgfVxuICAgIGlmIChkZWZhdWx0VmFsdWUgPT0gbnVsbCkge1xuICAgICAgZGVmYXVsdFZhbHVlID0gJyc7XG4gICAgfVxuICAgIHZhciB2YWx1ZSA9IExpbmtlZFZhbHVlVXRpbHMuZ2V0VmFsdWUodGhpcyk7XG4gICAgcmV0dXJuIHtcbiAgICAgIC8vIFdlIHNhdmUgdGhlIGluaXRpYWwgdmFsdWUgc28gdGhhdCBgUmVhY3RET01Db21wb25lbnRgIGRvZXNuJ3QgdXBkYXRlXG4gICAgICAvLyBgdGV4dENvbnRlbnRgICh1bm5lY2Vzc2FyeSBzaW5jZSB3ZSB1cGRhdGUgdmFsdWUpLlxuICAgICAgLy8gVGhlIGluaXRpYWwgdmFsdWUgY2FuIGJlIGEgYm9vbGVhbiBvciBvYmplY3Qgc28gdGhhdCdzIHdoeSBpdCdzXG4gICAgICAvLyBmb3JjZWQgdG8gYmUgYSBzdHJpbmcuXG4gICAgICBpbml0aWFsVmFsdWU6ICcnICsgKHZhbHVlICE9IG51bGwgPyB2YWx1ZSA6IGRlZmF1bHRWYWx1ZSlcbiAgICB9O1xuICB9LFxuXG4gIHJlbmRlcjogZnVuY3Rpb24oKSB7XG4gICAgLy8gQ2xvbmUgYHRoaXMucHJvcHNgIHNvIHdlIGRvbid0IG11dGF0ZSB0aGUgaW5wdXQuXG4gICAgdmFyIHByb3BzID0gYXNzaWduKHt9LCB0aGlzLnByb3BzKTtcblxuICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICBwcm9wcy5kYW5nZXJvdXNseVNldElubmVySFRNTCA9PSBudWxsLFxuICAgICAgJ2BkYW5nZXJvdXNseVNldElubmVySFRNTGAgZG9lcyBub3QgbWFrZSBzZW5zZSBvbiA8dGV4dGFyZWE+LidcbiAgICApIDogaW52YXJpYW50KHByb3BzLmRhbmdlcm91c2x5U2V0SW5uZXJIVE1MID09IG51bGwpKTtcblxuICAgIHByb3BzLmRlZmF1bHRWYWx1ZSA9IG51bGw7XG4gICAgcHJvcHMudmFsdWUgPSBudWxsO1xuICAgIHByb3BzLm9uQ2hhbmdlID0gdGhpcy5faGFuZGxlQ2hhbmdlO1xuXG4gICAgLy8gQWx3YXlzIHNldCBjaGlsZHJlbiB0byB0aGUgc2FtZSB0aGluZy4gSW4gSUU5LCB0aGUgc2VsZWN0aW9uIHJhbmdlIHdpbGxcbiAgICAvLyBnZXQgcmVzZXQgaWYgYHRleHRDb250ZW50YCBpcyBtdXRhdGVkLlxuICAgIHJldHVybiB0ZXh0YXJlYShwcm9wcywgdGhpcy5zdGF0ZS5pbml0aWFsVmFsdWUpO1xuICB9LFxuXG4gIGNvbXBvbmVudERpZFVwZGF0ZTogZnVuY3Rpb24ocHJldlByb3BzLCBwcmV2U3RhdGUsIHByZXZDb250ZXh0KSB7XG4gICAgdmFyIHZhbHVlID0gTGlua2VkVmFsdWVVdGlscy5nZXRWYWx1ZSh0aGlzKTtcbiAgICBpZiAodmFsdWUgIT0gbnVsbCkge1xuICAgICAgdmFyIHJvb3ROb2RlID0gdGhpcy5nZXRET01Ob2RlKCk7XG4gICAgICAvLyBDYXN0IGB2YWx1ZWAgdG8gYSBzdHJpbmcgdG8gZW5zdXJlIHRoZSB2YWx1ZSBpcyBzZXQgY29ycmVjdGx5LiBXaGlsZVxuICAgICAgLy8gYnJvd3NlcnMgdHlwaWNhbGx5IGRvIHRoaXMgYXMgbmVjZXNzYXJ5LCBqc2RvbSBkb2Vzbid0LlxuICAgICAgRE9NUHJvcGVydHlPcGVyYXRpb25zLnNldFZhbHVlRm9yUHJvcGVydHkocm9vdE5vZGUsICd2YWx1ZScsICcnICsgdmFsdWUpO1xuICAgIH1cbiAgfSxcblxuICBfaGFuZGxlQ2hhbmdlOiBmdW5jdGlvbihldmVudCkge1xuICAgIHZhciByZXR1cm5WYWx1ZTtcbiAgICB2YXIgb25DaGFuZ2UgPSBMaW5rZWRWYWx1ZVV0aWxzLmdldE9uQ2hhbmdlKHRoaXMpO1xuICAgIGlmIChvbkNoYW5nZSkge1xuICAgICAgcmV0dXJuVmFsdWUgPSBvbkNoYW5nZS5jYWxsKHRoaXMsIGV2ZW50KTtcbiAgICB9XG4gICAgUmVhY3RVcGRhdGVzLmFzYXAoZm9yY2VVcGRhdGVJZk1vdW50ZWQsIHRoaXMpO1xuICAgIHJldHVybiByZXR1cm5WYWx1ZTtcbiAgfVxuXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBSZWFjdERPTVRleHRhcmVhO1xuXG59KS5jYWxsKHRoaXMscmVxdWlyZSgnX3Byb2Nlc3MnKSkiLCIvKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgUmVhY3REZWZhdWx0QmF0Y2hpbmdTdHJhdGVneVxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgUmVhY3RVcGRhdGVzID0gcmVxdWlyZShcIi4vUmVhY3RVcGRhdGVzXCIpO1xudmFyIFRyYW5zYWN0aW9uID0gcmVxdWlyZShcIi4vVHJhbnNhY3Rpb25cIik7XG5cbnZhciBhc3NpZ24gPSByZXF1aXJlKFwiLi9PYmplY3QuYXNzaWduXCIpO1xudmFyIGVtcHR5RnVuY3Rpb24gPSByZXF1aXJlKFwiLi9lbXB0eUZ1bmN0aW9uXCIpO1xuXG52YXIgUkVTRVRfQkFUQ0hFRF9VUERBVEVTID0ge1xuICBpbml0aWFsaXplOiBlbXB0eUZ1bmN0aW9uLFxuICBjbG9zZTogZnVuY3Rpb24oKSB7XG4gICAgUmVhY3REZWZhdWx0QmF0Y2hpbmdTdHJhdGVneS5pc0JhdGNoaW5nVXBkYXRlcyA9IGZhbHNlO1xuICB9XG59O1xuXG52YXIgRkxVU0hfQkFUQ0hFRF9VUERBVEVTID0ge1xuICBpbml0aWFsaXplOiBlbXB0eUZ1bmN0aW9uLFxuICBjbG9zZTogUmVhY3RVcGRhdGVzLmZsdXNoQmF0Y2hlZFVwZGF0ZXMuYmluZChSZWFjdFVwZGF0ZXMpXG59O1xuXG52YXIgVFJBTlNBQ1RJT05fV1JBUFBFUlMgPSBbRkxVU0hfQkFUQ0hFRF9VUERBVEVTLCBSRVNFVF9CQVRDSEVEX1VQREFURVNdO1xuXG5mdW5jdGlvbiBSZWFjdERlZmF1bHRCYXRjaGluZ1N0cmF0ZWd5VHJhbnNhY3Rpb24oKSB7XG4gIHRoaXMucmVpbml0aWFsaXplVHJhbnNhY3Rpb24oKTtcbn1cblxuYXNzaWduKFxuICBSZWFjdERlZmF1bHRCYXRjaGluZ1N0cmF0ZWd5VHJhbnNhY3Rpb24ucHJvdG90eXBlLFxuICBUcmFuc2FjdGlvbi5NaXhpbixcbiAge1xuICAgIGdldFRyYW5zYWN0aW9uV3JhcHBlcnM6IGZ1bmN0aW9uKCkge1xuICAgICAgcmV0dXJuIFRSQU5TQUNUSU9OX1dSQVBQRVJTO1xuICAgIH1cbiAgfVxuKTtcblxudmFyIHRyYW5zYWN0aW9uID0gbmV3IFJlYWN0RGVmYXVsdEJhdGNoaW5nU3RyYXRlZ3lUcmFuc2FjdGlvbigpO1xuXG52YXIgUmVhY3REZWZhdWx0QmF0Y2hpbmdTdHJhdGVneSA9IHtcbiAgaXNCYXRjaGluZ1VwZGF0ZXM6IGZhbHNlLFxuXG4gIC8qKlxuICAgKiBDYWxsIHRoZSBwcm92aWRlZCBmdW5jdGlvbiBpbiBhIGNvbnRleHQgd2l0aGluIHdoaWNoIGNhbGxzIHRvIGBzZXRTdGF0ZWBcbiAgICogYW5kIGZyaWVuZHMgYXJlIGJhdGNoZWQgc3VjaCB0aGF0IGNvbXBvbmVudHMgYXJlbid0IHVwZGF0ZWQgdW5uZWNlc3NhcmlseS5cbiAgICovXG4gIGJhdGNoZWRVcGRhdGVzOiBmdW5jdGlvbihjYWxsYmFjaywgYSwgYikge1xuICAgIHZhciBhbHJlYWR5QmF0Y2hpbmdVcGRhdGVzID0gUmVhY3REZWZhdWx0QmF0Y2hpbmdTdHJhdGVneS5pc0JhdGNoaW5nVXBkYXRlcztcblxuICAgIFJlYWN0RGVmYXVsdEJhdGNoaW5nU3RyYXRlZ3kuaXNCYXRjaGluZ1VwZGF0ZXMgPSB0cnVlO1xuXG4gICAgLy8gVGhlIGNvZGUgaXMgd3JpdHRlbiB0aGlzIHdheSB0byBhdm9pZCBleHRyYSBhbGxvY2F0aW9uc1xuICAgIGlmIChhbHJlYWR5QmF0Y2hpbmdVcGRhdGVzKSB7XG4gICAgICBjYWxsYmFjayhhLCBiKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdHJhbnNhY3Rpb24ucGVyZm9ybShjYWxsYmFjaywgbnVsbCwgYSwgYik7XG4gICAgfVxuICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJlYWN0RGVmYXVsdEJhdGNoaW5nU3RyYXRlZ3k7XG4iLCIoZnVuY3Rpb24gKHByb2Nlc3Mpe1xuLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIFJlYWN0RGVmYXVsdEluamVjdGlvblxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgQmVmb3JlSW5wdXRFdmVudFBsdWdpbiA9IHJlcXVpcmUoXCIuL0JlZm9yZUlucHV0RXZlbnRQbHVnaW5cIik7XG52YXIgQ2hhbmdlRXZlbnRQbHVnaW4gPSByZXF1aXJlKFwiLi9DaGFuZ2VFdmVudFBsdWdpblwiKTtcbnZhciBDbGllbnRSZWFjdFJvb3RJbmRleCA9IHJlcXVpcmUoXCIuL0NsaWVudFJlYWN0Um9vdEluZGV4XCIpO1xudmFyIENvbXBvc2l0aW9uRXZlbnRQbHVnaW4gPSByZXF1aXJlKFwiLi9Db21wb3NpdGlvbkV2ZW50UGx1Z2luXCIpO1xudmFyIERlZmF1bHRFdmVudFBsdWdpbk9yZGVyID0gcmVxdWlyZShcIi4vRGVmYXVsdEV2ZW50UGx1Z2luT3JkZXJcIik7XG52YXIgRW50ZXJMZWF2ZUV2ZW50UGx1Z2luID0gcmVxdWlyZShcIi4vRW50ZXJMZWF2ZUV2ZW50UGx1Z2luXCIpO1xudmFyIEV4ZWN1dGlvbkVudmlyb25tZW50ID0gcmVxdWlyZShcIi4vRXhlY3V0aW9uRW52aXJvbm1lbnRcIik7XG52YXIgSFRNTERPTVByb3BlcnR5Q29uZmlnID0gcmVxdWlyZShcIi4vSFRNTERPTVByb3BlcnR5Q29uZmlnXCIpO1xudmFyIE1vYmlsZVNhZmFyaUNsaWNrRXZlbnRQbHVnaW4gPSByZXF1aXJlKFwiLi9Nb2JpbGVTYWZhcmlDbGlja0V2ZW50UGx1Z2luXCIpO1xudmFyIFJlYWN0QnJvd3NlckNvbXBvbmVudE1peGluID0gcmVxdWlyZShcIi4vUmVhY3RCcm93c2VyQ29tcG9uZW50TWl4aW5cIik7XG52YXIgUmVhY3RDb21wb25lbnRCcm93c2VyRW52aXJvbm1lbnQgPVxuICByZXF1aXJlKFwiLi9SZWFjdENvbXBvbmVudEJyb3dzZXJFbnZpcm9ubWVudFwiKTtcbnZhciBSZWFjdERlZmF1bHRCYXRjaGluZ1N0cmF0ZWd5ID0gcmVxdWlyZShcIi4vUmVhY3REZWZhdWx0QmF0Y2hpbmdTdHJhdGVneVwiKTtcbnZhciBSZWFjdERPTUNvbXBvbmVudCA9IHJlcXVpcmUoXCIuL1JlYWN0RE9NQ29tcG9uZW50XCIpO1xudmFyIFJlYWN0RE9NQnV0dG9uID0gcmVxdWlyZShcIi4vUmVhY3RET01CdXR0b25cIik7XG52YXIgUmVhY3RET01Gb3JtID0gcmVxdWlyZShcIi4vUmVhY3RET01Gb3JtXCIpO1xudmFyIFJlYWN0RE9NSW1nID0gcmVxdWlyZShcIi4vUmVhY3RET01JbWdcIik7XG52YXIgUmVhY3RET01JbnB1dCA9IHJlcXVpcmUoXCIuL1JlYWN0RE9NSW5wdXRcIik7XG52YXIgUmVhY3RET01PcHRpb24gPSByZXF1aXJlKFwiLi9SZWFjdERPTU9wdGlvblwiKTtcbnZhciBSZWFjdERPTVNlbGVjdCA9IHJlcXVpcmUoXCIuL1JlYWN0RE9NU2VsZWN0XCIpO1xudmFyIFJlYWN0RE9NVGV4dGFyZWEgPSByZXF1aXJlKFwiLi9SZWFjdERPTVRleHRhcmVhXCIpO1xudmFyIFJlYWN0RXZlbnRMaXN0ZW5lciA9IHJlcXVpcmUoXCIuL1JlYWN0RXZlbnRMaXN0ZW5lclwiKTtcbnZhciBSZWFjdEluamVjdGlvbiA9IHJlcXVpcmUoXCIuL1JlYWN0SW5qZWN0aW9uXCIpO1xudmFyIFJlYWN0SW5zdGFuY2VIYW5kbGVzID0gcmVxdWlyZShcIi4vUmVhY3RJbnN0YW5jZUhhbmRsZXNcIik7XG52YXIgUmVhY3RNb3VudCA9IHJlcXVpcmUoXCIuL1JlYWN0TW91bnRcIik7XG52YXIgU2VsZWN0RXZlbnRQbHVnaW4gPSByZXF1aXJlKFwiLi9TZWxlY3RFdmVudFBsdWdpblwiKTtcbnZhciBTZXJ2ZXJSZWFjdFJvb3RJbmRleCA9IHJlcXVpcmUoXCIuL1NlcnZlclJlYWN0Um9vdEluZGV4XCIpO1xudmFyIFNpbXBsZUV2ZW50UGx1Z2luID0gcmVxdWlyZShcIi4vU2ltcGxlRXZlbnRQbHVnaW5cIik7XG52YXIgU1ZHRE9NUHJvcGVydHlDb25maWcgPSByZXF1aXJlKFwiLi9TVkdET01Qcm9wZXJ0eUNvbmZpZ1wiKTtcblxudmFyIGNyZWF0ZUZ1bGxQYWdlQ29tcG9uZW50ID0gcmVxdWlyZShcIi4vY3JlYXRlRnVsbFBhZ2VDb21wb25lbnRcIik7XG5cbmZ1bmN0aW9uIGluamVjdCgpIHtcbiAgUmVhY3RJbmplY3Rpb24uRXZlbnRFbWl0dGVyLmluamVjdFJlYWN0RXZlbnRMaXN0ZW5lcihcbiAgICBSZWFjdEV2ZW50TGlzdGVuZXJcbiAgKTtcblxuICAvKipcbiAgICogSW5qZWN0IG1vZHVsZXMgZm9yIHJlc29sdmluZyBET00gaGllcmFyY2h5IGFuZCBwbHVnaW4gb3JkZXJpbmcuXG4gICAqL1xuICBSZWFjdEluamVjdGlvbi5FdmVudFBsdWdpbkh1Yi5pbmplY3RFdmVudFBsdWdpbk9yZGVyKERlZmF1bHRFdmVudFBsdWdpbk9yZGVyKTtcbiAgUmVhY3RJbmplY3Rpb24uRXZlbnRQbHVnaW5IdWIuaW5qZWN0SW5zdGFuY2VIYW5kbGUoUmVhY3RJbnN0YW5jZUhhbmRsZXMpO1xuICBSZWFjdEluamVjdGlvbi5FdmVudFBsdWdpbkh1Yi5pbmplY3RNb3VudChSZWFjdE1vdW50KTtcblxuICAvKipcbiAgICogU29tZSBpbXBvcnRhbnQgZXZlbnQgcGx1Z2lucyBpbmNsdWRlZCBieSBkZWZhdWx0ICh3aXRob3V0IGhhdmluZyB0byByZXF1aXJlXG4gICAqIHRoZW0pLlxuICAgKi9cbiAgUmVhY3RJbmplY3Rpb24uRXZlbnRQbHVnaW5IdWIuaW5qZWN0RXZlbnRQbHVnaW5zQnlOYW1lKHtcbiAgICBTaW1wbGVFdmVudFBsdWdpbjogU2ltcGxlRXZlbnRQbHVnaW4sXG4gICAgRW50ZXJMZWF2ZUV2ZW50UGx1Z2luOiBFbnRlckxlYXZlRXZlbnRQbHVnaW4sXG4gICAgQ2hhbmdlRXZlbnRQbHVnaW46IENoYW5nZUV2ZW50UGx1Z2luLFxuICAgIENvbXBvc2l0aW9uRXZlbnRQbHVnaW46IENvbXBvc2l0aW9uRXZlbnRQbHVnaW4sXG4gICAgTW9iaWxlU2FmYXJpQ2xpY2tFdmVudFBsdWdpbjogTW9iaWxlU2FmYXJpQ2xpY2tFdmVudFBsdWdpbixcbiAgICBTZWxlY3RFdmVudFBsdWdpbjogU2VsZWN0RXZlbnRQbHVnaW4sXG4gICAgQmVmb3JlSW5wdXRFdmVudFBsdWdpbjogQmVmb3JlSW5wdXRFdmVudFBsdWdpblxuICB9KTtcblxuICBSZWFjdEluamVjdGlvbi5OYXRpdmVDb21wb25lbnQuaW5qZWN0R2VuZXJpY0NvbXBvbmVudENsYXNzKFxuICAgIFJlYWN0RE9NQ29tcG9uZW50XG4gICk7XG5cbiAgUmVhY3RJbmplY3Rpb24uTmF0aXZlQ29tcG9uZW50LmluamVjdENvbXBvbmVudENsYXNzZXMoe1xuICAgICdidXR0b24nOiBSZWFjdERPTUJ1dHRvbixcbiAgICAnZm9ybSc6IFJlYWN0RE9NRm9ybSxcbiAgICAnaW1nJzogUmVhY3RET01JbWcsXG4gICAgJ2lucHV0JzogUmVhY3RET01JbnB1dCxcbiAgICAnb3B0aW9uJzogUmVhY3RET01PcHRpb24sXG4gICAgJ3NlbGVjdCc6IFJlYWN0RE9NU2VsZWN0LFxuICAgICd0ZXh0YXJlYSc6IFJlYWN0RE9NVGV4dGFyZWEsXG5cbiAgICAnaHRtbCc6IGNyZWF0ZUZ1bGxQYWdlQ29tcG9uZW50KCdodG1sJyksXG4gICAgJ2hlYWQnOiBjcmVhdGVGdWxsUGFnZUNvbXBvbmVudCgnaGVhZCcpLFxuICAgICdib2R5JzogY3JlYXRlRnVsbFBhZ2VDb21wb25lbnQoJ2JvZHknKVxuICB9KTtcblxuICAvLyBUaGlzIG5lZWRzIHRvIGhhcHBlbiBhZnRlciBjcmVhdGVGdWxsUGFnZUNvbXBvbmVudCgpIG90aGVyd2lzZSB0aGUgbWl4aW5cbiAgLy8gZ2V0cyBkb3VibGUgaW5qZWN0ZWQuXG4gIFJlYWN0SW5qZWN0aW9uLkNvbXBvc2l0ZUNvbXBvbmVudC5pbmplY3RNaXhpbihSZWFjdEJyb3dzZXJDb21wb25lbnRNaXhpbik7XG5cbiAgUmVhY3RJbmplY3Rpb24uRE9NUHJvcGVydHkuaW5qZWN0RE9NUHJvcGVydHlDb25maWcoSFRNTERPTVByb3BlcnR5Q29uZmlnKTtcbiAgUmVhY3RJbmplY3Rpb24uRE9NUHJvcGVydHkuaW5qZWN0RE9NUHJvcGVydHlDb25maWcoU1ZHRE9NUHJvcGVydHlDb25maWcpO1xuXG4gIFJlYWN0SW5qZWN0aW9uLkVtcHR5Q29tcG9uZW50LmluamVjdEVtcHR5Q29tcG9uZW50KCdub3NjcmlwdCcpO1xuXG4gIFJlYWN0SW5qZWN0aW9uLlVwZGF0ZXMuaW5qZWN0UmVjb25jaWxlVHJhbnNhY3Rpb24oXG4gICAgUmVhY3RDb21wb25lbnRCcm93c2VyRW52aXJvbm1lbnQuUmVhY3RSZWNvbmNpbGVUcmFuc2FjdGlvblxuICApO1xuICBSZWFjdEluamVjdGlvbi5VcGRhdGVzLmluamVjdEJhdGNoaW5nU3RyYXRlZ3koXG4gICAgUmVhY3REZWZhdWx0QmF0Y2hpbmdTdHJhdGVneVxuICApO1xuXG4gIFJlYWN0SW5qZWN0aW9uLlJvb3RJbmRleC5pbmplY3RDcmVhdGVSZWFjdFJvb3RJbmRleChcbiAgICBFeGVjdXRpb25FbnZpcm9ubWVudC5jYW5Vc2VET00gP1xuICAgICAgQ2xpZW50UmVhY3RSb290SW5kZXguY3JlYXRlUmVhY3RSb290SW5kZXggOlxuICAgICAgU2VydmVyUmVhY3RSb290SW5kZXguY3JlYXRlUmVhY3RSb290SW5kZXhcbiAgKTtcblxuICBSZWFjdEluamVjdGlvbi5Db21wb25lbnQuaW5qZWN0RW52aXJvbm1lbnQoUmVhY3RDb21wb25lbnRCcm93c2VyRW52aXJvbm1lbnQpO1xuXG4gIGlmIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYpIHtcbiAgICB2YXIgdXJsID0gKEV4ZWN1dGlvbkVudmlyb25tZW50LmNhblVzZURPTSAmJiB3aW5kb3cubG9jYXRpb24uaHJlZikgfHwgJyc7XG4gICAgaWYgKCgvWz8mXXJlYWN0X3BlcmZcXGIvKS50ZXN0KHVybCkpIHtcbiAgICAgIHZhciBSZWFjdERlZmF1bHRQZXJmID0gcmVxdWlyZShcIi4vUmVhY3REZWZhdWx0UGVyZlwiKTtcbiAgICAgIFJlYWN0RGVmYXVsdFBlcmYuc3RhcnQoKTtcbiAgICB9XG4gIH1cbn1cblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gIGluamVjdDogaW5qZWN0XG59O1xuXG59KS5jYWxsKHRoaXMscmVxdWlyZSgnX3Byb2Nlc3MnKSkiLCIvKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgUmVhY3REZWZhdWx0UGVyZlxuICogQHR5cGVjaGVja3Mgc3RhdGljLW9ubHlcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIERPTVByb3BlcnR5ID0gcmVxdWlyZShcIi4vRE9NUHJvcGVydHlcIik7XG52YXIgUmVhY3REZWZhdWx0UGVyZkFuYWx5c2lzID0gcmVxdWlyZShcIi4vUmVhY3REZWZhdWx0UGVyZkFuYWx5c2lzXCIpO1xudmFyIFJlYWN0TW91bnQgPSByZXF1aXJlKFwiLi9SZWFjdE1vdW50XCIpO1xudmFyIFJlYWN0UGVyZiA9IHJlcXVpcmUoXCIuL1JlYWN0UGVyZlwiKTtcblxudmFyIHBlcmZvcm1hbmNlTm93ID0gcmVxdWlyZShcIi4vcGVyZm9ybWFuY2VOb3dcIik7XG5cbmZ1bmN0aW9uIHJvdW5kRmxvYXQodmFsKSB7XG4gIHJldHVybiBNYXRoLmZsb29yKHZhbCAqIDEwMCkgLyAxMDA7XG59XG5cbmZ1bmN0aW9uIGFkZFZhbHVlKG9iaiwga2V5LCB2YWwpIHtcbiAgb2JqW2tleV0gPSAob2JqW2tleV0gfHwgMCkgKyB2YWw7XG59XG5cbnZhciBSZWFjdERlZmF1bHRQZXJmID0ge1xuICBfYWxsTWVhc3VyZW1lbnRzOiBbXSwgLy8gbGFzdCBpdGVtIGluIHRoZSBsaXN0IGlzIHRoZSBjdXJyZW50IG9uZVxuICBfbW91bnRTdGFjazogWzBdLFxuICBfaW5qZWN0ZWQ6IGZhbHNlLFxuXG4gIHN0YXJ0OiBmdW5jdGlvbigpIHtcbiAgICBpZiAoIVJlYWN0RGVmYXVsdFBlcmYuX2luamVjdGVkKSB7XG4gICAgICBSZWFjdFBlcmYuaW5qZWN0aW9uLmluamVjdE1lYXN1cmUoUmVhY3REZWZhdWx0UGVyZi5tZWFzdXJlKTtcbiAgICB9XG5cbiAgICBSZWFjdERlZmF1bHRQZXJmLl9hbGxNZWFzdXJlbWVudHMubGVuZ3RoID0gMDtcbiAgICBSZWFjdFBlcmYuZW5hYmxlTWVhc3VyZSA9IHRydWU7XG4gIH0sXG5cbiAgc3RvcDogZnVuY3Rpb24oKSB7XG4gICAgUmVhY3RQZXJmLmVuYWJsZU1lYXN1cmUgPSBmYWxzZTtcbiAgfSxcblxuICBnZXRMYXN0TWVhc3VyZW1lbnRzOiBmdW5jdGlvbigpIHtcbiAgICByZXR1cm4gUmVhY3REZWZhdWx0UGVyZi5fYWxsTWVhc3VyZW1lbnRzO1xuICB9LFxuXG4gIHByaW50RXhjbHVzaXZlOiBmdW5jdGlvbihtZWFzdXJlbWVudHMpIHtcbiAgICBtZWFzdXJlbWVudHMgPSBtZWFzdXJlbWVudHMgfHwgUmVhY3REZWZhdWx0UGVyZi5fYWxsTWVhc3VyZW1lbnRzO1xuICAgIHZhciBzdW1tYXJ5ID0gUmVhY3REZWZhdWx0UGVyZkFuYWx5c2lzLmdldEV4Y2x1c2l2ZVN1bW1hcnkobWVhc3VyZW1lbnRzKTtcbiAgICBjb25zb2xlLnRhYmxlKHN1bW1hcnkubWFwKGZ1bmN0aW9uKGl0ZW0pIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgICdDb21wb25lbnQgY2xhc3MgbmFtZSc6IGl0ZW0uY29tcG9uZW50TmFtZSxcbiAgICAgICAgJ1RvdGFsIGluY2x1c2l2ZSB0aW1lIChtcyknOiByb3VuZEZsb2F0KGl0ZW0uaW5jbHVzaXZlKSxcbiAgICAgICAgJ0V4Y2x1c2l2ZSBtb3VudCB0aW1lIChtcyknOiByb3VuZEZsb2F0KGl0ZW0uZXhjbHVzaXZlKSxcbiAgICAgICAgJ0V4Y2x1c2l2ZSByZW5kZXIgdGltZSAobXMpJzogcm91bmRGbG9hdChpdGVtLnJlbmRlciksXG4gICAgICAgICdNb3VudCB0aW1lIHBlciBpbnN0YW5jZSAobXMpJzogcm91bmRGbG9hdChpdGVtLmV4Y2x1c2l2ZSAvIGl0ZW0uY291bnQpLFxuICAgICAgICAnUmVuZGVyIHRpbWUgcGVyIGluc3RhbmNlIChtcyknOiByb3VuZEZsb2F0KGl0ZW0ucmVuZGVyIC8gaXRlbS5jb3VudCksXG4gICAgICAgICdJbnN0YW5jZXMnOiBpdGVtLmNvdW50XG4gICAgICB9O1xuICAgIH0pKTtcbiAgICAvLyBUT0RPOiBSZWFjdERlZmF1bHRQZXJmQW5hbHlzaXMuZ2V0VG90YWxUaW1lKCkgZG9lcyBub3QgcmV0dXJuIHRoZSBjb3JyZWN0XG4gICAgLy8gbnVtYmVyLlxuICB9LFxuXG4gIHByaW50SW5jbHVzaXZlOiBmdW5jdGlvbihtZWFzdXJlbWVudHMpIHtcbiAgICBtZWFzdXJlbWVudHMgPSBtZWFzdXJlbWVudHMgfHwgUmVhY3REZWZhdWx0UGVyZi5fYWxsTWVhc3VyZW1lbnRzO1xuICAgIHZhciBzdW1tYXJ5ID0gUmVhY3REZWZhdWx0UGVyZkFuYWx5c2lzLmdldEluY2x1c2l2ZVN1bW1hcnkobWVhc3VyZW1lbnRzKTtcbiAgICBjb25zb2xlLnRhYmxlKHN1bW1hcnkubWFwKGZ1bmN0aW9uKGl0ZW0pIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgICdPd25lciA+IGNvbXBvbmVudCc6IGl0ZW0uY29tcG9uZW50TmFtZSxcbiAgICAgICAgJ0luY2x1c2l2ZSB0aW1lIChtcyknOiByb3VuZEZsb2F0KGl0ZW0udGltZSksXG4gICAgICAgICdJbnN0YW5jZXMnOiBpdGVtLmNvdW50XG4gICAgICB9O1xuICAgIH0pKTtcbiAgICBjb25zb2xlLmxvZyhcbiAgICAgICdUb3RhbCB0aW1lOicsXG4gICAgICBSZWFjdERlZmF1bHRQZXJmQW5hbHlzaXMuZ2V0VG90YWxUaW1lKG1lYXN1cmVtZW50cykudG9GaXhlZCgyKSArICcgbXMnXG4gICAgKTtcbiAgfSxcblxuICBnZXRNZWFzdXJlbWVudHNTdW1tYXJ5TWFwOiBmdW5jdGlvbihtZWFzdXJlbWVudHMpIHtcbiAgICB2YXIgc3VtbWFyeSA9IFJlYWN0RGVmYXVsdFBlcmZBbmFseXNpcy5nZXRJbmNsdXNpdmVTdW1tYXJ5KFxuICAgICAgbWVhc3VyZW1lbnRzLFxuICAgICAgdHJ1ZVxuICAgICk7XG4gICAgcmV0dXJuIHN1bW1hcnkubWFwKGZ1bmN0aW9uKGl0ZW0pIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgICdPd25lciA+IGNvbXBvbmVudCc6IGl0ZW0uY29tcG9uZW50TmFtZSxcbiAgICAgICAgJ1dhc3RlZCB0aW1lIChtcyknOiBpdGVtLnRpbWUsXG4gICAgICAgICdJbnN0YW5jZXMnOiBpdGVtLmNvdW50XG4gICAgICB9O1xuICAgIH0pO1xuICB9LFxuXG4gIHByaW50V2FzdGVkOiBmdW5jdGlvbihtZWFzdXJlbWVudHMpIHtcbiAgICBtZWFzdXJlbWVudHMgPSBtZWFzdXJlbWVudHMgfHwgUmVhY3REZWZhdWx0UGVyZi5fYWxsTWVhc3VyZW1lbnRzO1xuICAgIGNvbnNvbGUudGFibGUoUmVhY3REZWZhdWx0UGVyZi5nZXRNZWFzdXJlbWVudHNTdW1tYXJ5TWFwKG1lYXN1cmVtZW50cykpO1xuICAgIGNvbnNvbGUubG9nKFxuICAgICAgJ1RvdGFsIHRpbWU6JyxcbiAgICAgIFJlYWN0RGVmYXVsdFBlcmZBbmFseXNpcy5nZXRUb3RhbFRpbWUobWVhc3VyZW1lbnRzKS50b0ZpeGVkKDIpICsgJyBtcydcbiAgICApO1xuICB9LFxuXG4gIHByaW50RE9NOiBmdW5jdGlvbihtZWFzdXJlbWVudHMpIHtcbiAgICBtZWFzdXJlbWVudHMgPSBtZWFzdXJlbWVudHMgfHwgUmVhY3REZWZhdWx0UGVyZi5fYWxsTWVhc3VyZW1lbnRzO1xuICAgIHZhciBzdW1tYXJ5ID0gUmVhY3REZWZhdWx0UGVyZkFuYWx5c2lzLmdldERPTVN1bW1hcnkobWVhc3VyZW1lbnRzKTtcbiAgICBjb25zb2xlLnRhYmxlKHN1bW1hcnkubWFwKGZ1bmN0aW9uKGl0ZW0pIHtcbiAgICAgIHZhciByZXN1bHQgPSB7fTtcbiAgICAgIHJlc3VsdFtET01Qcm9wZXJ0eS5JRF9BVFRSSUJVVEVfTkFNRV0gPSBpdGVtLmlkO1xuICAgICAgcmVzdWx0Wyd0eXBlJ10gPSBpdGVtLnR5cGU7XG4gICAgICByZXN1bHRbJ2FyZ3MnXSA9IEpTT04uc3RyaW5naWZ5KGl0ZW0uYXJncyk7XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH0pKTtcbiAgICBjb25zb2xlLmxvZyhcbiAgICAgICdUb3RhbCB0aW1lOicsXG4gICAgICBSZWFjdERlZmF1bHRQZXJmQW5hbHlzaXMuZ2V0VG90YWxUaW1lKG1lYXN1cmVtZW50cykudG9GaXhlZCgyKSArICcgbXMnXG4gICAgKTtcbiAgfSxcblxuICBfcmVjb3JkV3JpdGU6IGZ1bmN0aW9uKGlkLCBmbk5hbWUsIHRvdGFsVGltZSwgYXJncykge1xuICAgIC8vIFRPRE86IHRvdGFsVGltZSBpc24ndCB0aGF0IHVzZWZ1bCBzaW5jZSBpdCBkb2Vzbid0IGNvdW50IHBhaW50cy9yZWZsb3dzXG4gICAgdmFyIHdyaXRlcyA9XG4gICAgICBSZWFjdERlZmF1bHRQZXJmXG4gICAgICAgIC5fYWxsTWVhc3VyZW1lbnRzW1JlYWN0RGVmYXVsdFBlcmYuX2FsbE1lYXN1cmVtZW50cy5sZW5ndGggLSAxXVxuICAgICAgICAud3JpdGVzO1xuICAgIHdyaXRlc1tpZF0gPSB3cml0ZXNbaWRdIHx8IFtdO1xuICAgIHdyaXRlc1tpZF0ucHVzaCh7XG4gICAgICB0eXBlOiBmbk5hbWUsXG4gICAgICB0aW1lOiB0b3RhbFRpbWUsXG4gICAgICBhcmdzOiBhcmdzXG4gICAgfSk7XG4gIH0sXG5cbiAgbWVhc3VyZTogZnVuY3Rpb24obW9kdWxlTmFtZSwgZm5OYW1lLCBmdW5jKSB7XG4gICAgcmV0dXJuIGZ1bmN0aW9uKCkge2ZvciAodmFyIGFyZ3M9W10sJF9fMD0wLCRfXzE9YXJndW1lbnRzLmxlbmd0aDskX18wPCRfXzE7JF9fMCsrKSBhcmdzLnB1c2goYXJndW1lbnRzWyRfXzBdKTtcbiAgICAgIHZhciB0b3RhbFRpbWU7XG4gICAgICB2YXIgcnY7XG4gICAgICB2YXIgc3RhcnQ7XG5cbiAgICAgIGlmIChmbk5hbWUgPT09ICdfcmVuZGVyTmV3Um9vdENvbXBvbmVudCcgfHxcbiAgICAgICAgICBmbk5hbWUgPT09ICdmbHVzaEJhdGNoZWRVcGRhdGVzJykge1xuICAgICAgICAvLyBBIFwibWVhc3VyZW1lbnRcIiBpcyBhIHNldCBvZiBtZXRyaWNzIHJlY29yZGVkIGZvciBlYWNoIGZsdXNoLiBXZSB3YW50XG4gICAgICAgIC8vIHRvIGdyb3VwIHRoZSBtZXRyaWNzIGZvciBhIGdpdmVuIGZsdXNoIHRvZ2V0aGVyIHNvIHdlIGNhbiBsb29rIGF0IHRoZVxuICAgICAgICAvLyBjb21wb25lbnRzIHRoYXQgcmVuZGVyZWQgYW5kIHRoZSBET00gb3BlcmF0aW9ucyB0aGF0IGFjdHVhbGx5XG4gICAgICAgIC8vIGhhcHBlbmVkIHRvIGRldGVybWluZSB0aGUgYW1vdW50IG9mIFwid2FzdGVkIHdvcmtcIiBwZXJmb3JtZWQuXG4gICAgICAgIFJlYWN0RGVmYXVsdFBlcmYuX2FsbE1lYXN1cmVtZW50cy5wdXNoKHtcbiAgICAgICAgICBleGNsdXNpdmU6IHt9LFxuICAgICAgICAgIGluY2x1c2l2ZToge30sXG4gICAgICAgICAgcmVuZGVyOiB7fSxcbiAgICAgICAgICBjb3VudHM6IHt9LFxuICAgICAgICAgIHdyaXRlczoge30sXG4gICAgICAgICAgZGlzcGxheU5hbWVzOiB7fSxcbiAgICAgICAgICB0b3RhbFRpbWU6IDBcbiAgICAgICAgfSk7XG4gICAgICAgIHN0YXJ0ID0gcGVyZm9ybWFuY2VOb3coKTtcbiAgICAgICAgcnYgPSBmdW5jLmFwcGx5KHRoaXMsIGFyZ3MpO1xuICAgICAgICBSZWFjdERlZmF1bHRQZXJmLl9hbGxNZWFzdXJlbWVudHNbXG4gICAgICAgICAgUmVhY3REZWZhdWx0UGVyZi5fYWxsTWVhc3VyZW1lbnRzLmxlbmd0aCAtIDFcbiAgICAgICAgXS50b3RhbFRpbWUgPSBwZXJmb3JtYW5jZU5vdygpIC0gc3RhcnQ7XG4gICAgICAgIHJldHVybiBydjtcbiAgICAgIH0gZWxzZSBpZiAobW9kdWxlTmFtZSA9PT0gJ1JlYWN0RE9NSURPcGVyYXRpb25zJyB8fFxuICAgICAgICBtb2R1bGVOYW1lID09PSAnUmVhY3RDb21wb25lbnRCcm93c2VyRW52aXJvbm1lbnQnKSB7XG4gICAgICAgIHN0YXJ0ID0gcGVyZm9ybWFuY2VOb3coKTtcbiAgICAgICAgcnYgPSBmdW5jLmFwcGx5KHRoaXMsIGFyZ3MpO1xuICAgICAgICB0b3RhbFRpbWUgPSBwZXJmb3JtYW5jZU5vdygpIC0gc3RhcnQ7XG5cbiAgICAgICAgaWYgKGZuTmFtZSA9PT0gJ21vdW50SW1hZ2VJbnRvTm9kZScpIHtcbiAgICAgICAgICB2YXIgbW91bnRJRCA9IFJlYWN0TW91bnQuZ2V0SUQoYXJnc1sxXSk7XG4gICAgICAgICAgUmVhY3REZWZhdWx0UGVyZi5fcmVjb3JkV3JpdGUobW91bnRJRCwgZm5OYW1lLCB0b3RhbFRpbWUsIGFyZ3NbMF0pO1xuICAgICAgICB9IGVsc2UgaWYgKGZuTmFtZSA9PT0gJ2Rhbmdlcm91c2x5UHJvY2Vzc0NoaWxkcmVuVXBkYXRlcycpIHtcbiAgICAgICAgICAvLyBzcGVjaWFsIGZvcm1hdFxuICAgICAgICAgIGFyZ3NbMF0uZm9yRWFjaChmdW5jdGlvbih1cGRhdGUpIHtcbiAgICAgICAgICAgIHZhciB3cml0ZUFyZ3MgPSB7fTtcbiAgICAgICAgICAgIGlmICh1cGRhdGUuZnJvbUluZGV4ICE9PSBudWxsKSB7XG4gICAgICAgICAgICAgIHdyaXRlQXJncy5mcm9tSW5kZXggPSB1cGRhdGUuZnJvbUluZGV4O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHVwZGF0ZS50b0luZGV4ICE9PSBudWxsKSB7XG4gICAgICAgICAgICAgIHdyaXRlQXJncy50b0luZGV4ID0gdXBkYXRlLnRvSW5kZXg7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAodXBkYXRlLnRleHRDb250ZW50ICE9PSBudWxsKSB7XG4gICAgICAgICAgICAgIHdyaXRlQXJncy50ZXh0Q29udGVudCA9IHVwZGF0ZS50ZXh0Q29udGVudDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICh1cGRhdGUubWFya3VwSW5kZXggIT09IG51bGwpIHtcbiAgICAgICAgICAgICAgd3JpdGVBcmdzLm1hcmt1cCA9IGFyZ3NbMV1bdXBkYXRlLm1hcmt1cEluZGV4XTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIFJlYWN0RGVmYXVsdFBlcmYuX3JlY29yZFdyaXRlKFxuICAgICAgICAgICAgICB1cGRhdGUucGFyZW50SUQsXG4gICAgICAgICAgICAgIHVwZGF0ZS50eXBlLFxuICAgICAgICAgICAgICB0b3RhbFRpbWUsXG4gICAgICAgICAgICAgIHdyaXRlQXJnc1xuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAvLyBiYXNpYyBmb3JtYXRcbiAgICAgICAgICBSZWFjdERlZmF1bHRQZXJmLl9yZWNvcmRXcml0ZShcbiAgICAgICAgICAgIGFyZ3NbMF0sXG4gICAgICAgICAgICBmbk5hbWUsXG4gICAgICAgICAgICB0b3RhbFRpbWUsXG4gICAgICAgICAgICBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmdzLCAxKVxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHJ2O1xuICAgICAgfSBlbHNlIGlmIChtb2R1bGVOYW1lID09PSAnUmVhY3RDb21wb3NpdGVDb21wb25lbnQnICYmIChcbiAgICAgICAgZm5OYW1lID09PSAnbW91bnRDb21wb25lbnQnIHx8XG4gICAgICAgIGZuTmFtZSA9PT0gJ3VwZGF0ZUNvbXBvbmVudCcgfHwgLy8gVE9ETzogcmVjZWl2ZUNvbXBvbmVudCgpP1xuICAgICAgICBmbk5hbWUgPT09ICdfcmVuZGVyVmFsaWRhdGVkQ29tcG9uZW50JykpIHtcblxuICAgICAgICB2YXIgcm9vdE5vZGVJRCA9IGZuTmFtZSA9PT0gJ21vdW50Q29tcG9uZW50JyA/XG4gICAgICAgICAgYXJnc1swXSA6XG4gICAgICAgICAgdGhpcy5fcm9vdE5vZGVJRDtcbiAgICAgICAgdmFyIGlzUmVuZGVyID0gZm5OYW1lID09PSAnX3JlbmRlclZhbGlkYXRlZENvbXBvbmVudCc7XG4gICAgICAgIHZhciBpc01vdW50ID0gZm5OYW1lID09PSAnbW91bnRDb21wb25lbnQnO1xuXG4gICAgICAgIHZhciBtb3VudFN0YWNrID0gUmVhY3REZWZhdWx0UGVyZi5fbW91bnRTdGFjaztcbiAgICAgICAgdmFyIGVudHJ5ID0gUmVhY3REZWZhdWx0UGVyZi5fYWxsTWVhc3VyZW1lbnRzW1xuICAgICAgICAgIFJlYWN0RGVmYXVsdFBlcmYuX2FsbE1lYXN1cmVtZW50cy5sZW5ndGggLSAxXG4gICAgICAgIF07XG5cbiAgICAgICAgaWYgKGlzUmVuZGVyKSB7XG4gICAgICAgICAgYWRkVmFsdWUoZW50cnkuY291bnRzLCByb290Tm9kZUlELCAxKTtcbiAgICAgICAgfSBlbHNlIGlmIChpc01vdW50KSB7XG4gICAgICAgICAgbW91bnRTdGFjay5wdXNoKDApO1xuICAgICAgICB9XG5cbiAgICAgICAgc3RhcnQgPSBwZXJmb3JtYW5jZU5vdygpO1xuICAgICAgICBydiA9IGZ1bmMuYXBwbHkodGhpcywgYXJncyk7XG4gICAgICAgIHRvdGFsVGltZSA9IHBlcmZvcm1hbmNlTm93KCkgLSBzdGFydDtcblxuICAgICAgICBpZiAoaXNSZW5kZXIpIHtcbiAgICAgICAgICBhZGRWYWx1ZShlbnRyeS5yZW5kZXIsIHJvb3ROb2RlSUQsIHRvdGFsVGltZSk7XG4gICAgICAgIH0gZWxzZSBpZiAoaXNNb3VudCkge1xuICAgICAgICAgIHZhciBzdWJNb3VudFRpbWUgPSBtb3VudFN0YWNrLnBvcCgpO1xuICAgICAgICAgIG1vdW50U3RhY2tbbW91bnRTdGFjay5sZW5ndGggLSAxXSArPSB0b3RhbFRpbWU7XG4gICAgICAgICAgYWRkVmFsdWUoZW50cnkuZXhjbHVzaXZlLCByb290Tm9kZUlELCB0b3RhbFRpbWUgLSBzdWJNb3VudFRpbWUpO1xuICAgICAgICAgIGFkZFZhbHVlKGVudHJ5LmluY2x1c2l2ZSwgcm9vdE5vZGVJRCwgdG90YWxUaW1lKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBhZGRWYWx1ZShlbnRyeS5pbmNsdXNpdmUsIHJvb3ROb2RlSUQsIHRvdGFsVGltZSk7XG4gICAgICAgIH1cblxuICAgICAgICBlbnRyeS5kaXNwbGF5TmFtZXNbcm9vdE5vZGVJRF0gPSB7XG4gICAgICAgICAgY3VycmVudDogdGhpcy5jb25zdHJ1Y3Rvci5kaXNwbGF5TmFtZSxcbiAgICAgICAgICBvd25lcjogdGhpcy5fb3duZXIgPyB0aGlzLl9vd25lci5jb25zdHJ1Y3Rvci5kaXNwbGF5TmFtZSA6ICc8cm9vdD4nXG4gICAgICAgIH07XG5cbiAgICAgICAgcmV0dXJuIHJ2O1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuIGZ1bmMuYXBwbHkodGhpcywgYXJncyk7XG4gICAgICB9XG4gICAgfTtcbiAgfVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBSZWFjdERlZmF1bHRQZXJmO1xuIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIFJlYWN0RGVmYXVsdFBlcmZBbmFseXNpc1xuICovXG5cbnZhciBhc3NpZ24gPSByZXF1aXJlKFwiLi9PYmplY3QuYXNzaWduXCIpO1xuXG4vLyBEb24ndCB0cnkgdG8gc2F2ZSB1c2VycyBsZXNzIHRoYW4gMS4ybXMgKGEgbnVtYmVyIEkgbWFkZSB1cClcbnZhciBET05UX0NBUkVfVEhSRVNIT0xEID0gMS4yO1xudmFyIERPTV9PUEVSQVRJT05fVFlQRVMgPSB7XG4gICdtb3VudEltYWdlSW50b05vZGUnOiAnc2V0IGlubmVySFRNTCcsXG4gIElOU0VSVF9NQVJLVVA6ICdzZXQgaW5uZXJIVE1MJyxcbiAgTU9WRV9FWElTVElORzogJ21vdmUnLFxuICBSRU1PVkVfTk9ERTogJ3JlbW92ZScsXG4gIFRFWFRfQ09OVEVOVDogJ3NldCB0ZXh0Q29udGVudCcsXG4gICd1cGRhdGVQcm9wZXJ0eUJ5SUQnOiAndXBkYXRlIGF0dHJpYnV0ZScsXG4gICdkZWxldGVQcm9wZXJ0eUJ5SUQnOiAnZGVsZXRlIGF0dHJpYnV0ZScsXG4gICd1cGRhdGVTdHlsZXNCeUlEJzogJ3VwZGF0ZSBzdHlsZXMnLFxuICAndXBkYXRlSW5uZXJIVE1MQnlJRCc6ICdzZXQgaW5uZXJIVE1MJyxcbiAgJ2Rhbmdlcm91c2x5UmVwbGFjZU5vZGVXaXRoTWFya3VwQnlJRCc6ICdyZXBsYWNlJ1xufTtcblxuZnVuY3Rpb24gZ2V0VG90YWxUaW1lKG1lYXN1cmVtZW50cykge1xuICAvLyBUT0RPOiByZXR1cm4gbnVtYmVyIG9mIERPTSBvcHM/IGNvdWxkIGJlIG1pc2xlYWRpbmcuXG4gIC8vIFRPRE86IG1lYXN1cmUgZHJvcHBlZCBmcmFtZXMgYWZ0ZXIgcmVjb25jaWxlP1xuICAvLyBUT0RPOiBsb2cgdG90YWwgdGltZSBvZiBlYWNoIHJlY29uY2lsZSBhbmQgdGhlIHRvcC1sZXZlbCBjb21wb25lbnRcbiAgLy8gY2xhc3MgdGhhdCB0cmlnZ2VyZWQgaXQuXG4gIHZhciB0b3RhbFRpbWUgPSAwO1xuICBmb3IgKHZhciBpID0gMDsgaSA8IG1lYXN1cmVtZW50cy5sZW5ndGg7IGkrKykge1xuICAgIHZhciBtZWFzdXJlbWVudCA9IG1lYXN1cmVtZW50c1tpXTtcbiAgICB0b3RhbFRpbWUgKz0gbWVhc3VyZW1lbnQudG90YWxUaW1lO1xuICB9XG4gIHJldHVybiB0b3RhbFRpbWU7XG59XG5cbmZ1bmN0aW9uIGdldERPTVN1bW1hcnkobWVhc3VyZW1lbnRzKSB7XG4gIHZhciBpdGVtcyA9IFtdO1xuICBmb3IgKHZhciBpID0gMDsgaSA8IG1lYXN1cmVtZW50cy5sZW5ndGg7IGkrKykge1xuICAgIHZhciBtZWFzdXJlbWVudCA9IG1lYXN1cmVtZW50c1tpXTtcbiAgICB2YXIgaWQ7XG5cbiAgICBmb3IgKGlkIGluIG1lYXN1cmVtZW50LndyaXRlcykge1xuICAgICAgbWVhc3VyZW1lbnQud3JpdGVzW2lkXS5mb3JFYWNoKGZ1bmN0aW9uKHdyaXRlKSB7XG4gICAgICAgIGl0ZW1zLnB1c2goe1xuICAgICAgICAgIGlkOiBpZCxcbiAgICAgICAgICB0eXBlOiBET01fT1BFUkFUSU9OX1RZUEVTW3dyaXRlLnR5cGVdIHx8IHdyaXRlLnR5cGUsXG4gICAgICAgICAgYXJnczogd3JpdGUuYXJnc1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuICByZXR1cm4gaXRlbXM7XG59XG5cbmZ1bmN0aW9uIGdldEV4Y2x1c2l2ZVN1bW1hcnkobWVhc3VyZW1lbnRzKSB7XG4gIHZhciBjYW5kaWRhdGVzID0ge307XG4gIHZhciBkaXNwbGF5TmFtZTtcblxuICBmb3IgKHZhciBpID0gMDsgaSA8IG1lYXN1cmVtZW50cy5sZW5ndGg7IGkrKykge1xuICAgIHZhciBtZWFzdXJlbWVudCA9IG1lYXN1cmVtZW50c1tpXTtcbiAgICB2YXIgYWxsSURzID0gYXNzaWduKFxuICAgICAge30sXG4gICAgICBtZWFzdXJlbWVudC5leGNsdXNpdmUsXG4gICAgICBtZWFzdXJlbWVudC5pbmNsdXNpdmVcbiAgICApO1xuXG4gICAgZm9yICh2YXIgaWQgaW4gYWxsSURzKSB7XG4gICAgICBkaXNwbGF5TmFtZSA9IG1lYXN1cmVtZW50LmRpc3BsYXlOYW1lc1tpZF0uY3VycmVudDtcblxuICAgICAgY2FuZGlkYXRlc1tkaXNwbGF5TmFtZV0gPSBjYW5kaWRhdGVzW2Rpc3BsYXlOYW1lXSB8fCB7XG4gICAgICAgIGNvbXBvbmVudE5hbWU6IGRpc3BsYXlOYW1lLFxuICAgICAgICBpbmNsdXNpdmU6IDAsXG4gICAgICAgIGV4Y2x1c2l2ZTogMCxcbiAgICAgICAgcmVuZGVyOiAwLFxuICAgICAgICBjb3VudDogMFxuICAgICAgfTtcbiAgICAgIGlmIChtZWFzdXJlbWVudC5yZW5kZXJbaWRdKSB7XG4gICAgICAgIGNhbmRpZGF0ZXNbZGlzcGxheU5hbWVdLnJlbmRlciArPSBtZWFzdXJlbWVudC5yZW5kZXJbaWRdO1xuICAgICAgfVxuICAgICAgaWYgKG1lYXN1cmVtZW50LmV4Y2x1c2l2ZVtpZF0pIHtcbiAgICAgICAgY2FuZGlkYXRlc1tkaXNwbGF5TmFtZV0uZXhjbHVzaXZlICs9IG1lYXN1cmVtZW50LmV4Y2x1c2l2ZVtpZF07XG4gICAgICB9XG4gICAgICBpZiAobWVhc3VyZW1lbnQuaW5jbHVzaXZlW2lkXSkge1xuICAgICAgICBjYW5kaWRhdGVzW2Rpc3BsYXlOYW1lXS5pbmNsdXNpdmUgKz0gbWVhc3VyZW1lbnQuaW5jbHVzaXZlW2lkXTtcbiAgICAgIH1cbiAgICAgIGlmIChtZWFzdXJlbWVudC5jb3VudHNbaWRdKSB7XG4gICAgICAgIGNhbmRpZGF0ZXNbZGlzcGxheU5hbWVdLmNvdW50ICs9IG1lYXN1cmVtZW50LmNvdW50c1tpZF07XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLy8gTm93IG1ha2UgYSBzb3J0ZWQgYXJyYXkgd2l0aCB0aGUgcmVzdWx0cy5cbiAgdmFyIGFyciA9IFtdO1xuICBmb3IgKGRpc3BsYXlOYW1lIGluIGNhbmRpZGF0ZXMpIHtcbiAgICBpZiAoY2FuZGlkYXRlc1tkaXNwbGF5TmFtZV0uZXhjbHVzaXZlID49IERPTlRfQ0FSRV9USFJFU0hPTEQpIHtcbiAgICAgIGFyci5wdXNoKGNhbmRpZGF0ZXNbZGlzcGxheU5hbWVdKTtcbiAgICB9XG4gIH1cblxuICBhcnIuc29ydChmdW5jdGlvbihhLCBiKSB7XG4gICAgcmV0dXJuIGIuZXhjbHVzaXZlIC0gYS5leGNsdXNpdmU7XG4gIH0pO1xuXG4gIHJldHVybiBhcnI7XG59XG5cbmZ1bmN0aW9uIGdldEluY2x1c2l2ZVN1bW1hcnkobWVhc3VyZW1lbnRzLCBvbmx5Q2xlYW4pIHtcbiAgdmFyIGNhbmRpZGF0ZXMgPSB7fTtcbiAgdmFyIGluY2x1c2l2ZUtleTtcblxuICBmb3IgKHZhciBpID0gMDsgaSA8IG1lYXN1cmVtZW50cy5sZW5ndGg7IGkrKykge1xuICAgIHZhciBtZWFzdXJlbWVudCA9IG1lYXN1cmVtZW50c1tpXTtcbiAgICB2YXIgYWxsSURzID0gYXNzaWduKFxuICAgICAge30sXG4gICAgICBtZWFzdXJlbWVudC5leGNsdXNpdmUsXG4gICAgICBtZWFzdXJlbWVudC5pbmNsdXNpdmVcbiAgICApO1xuICAgIHZhciBjbGVhbkNvbXBvbmVudHM7XG5cbiAgICBpZiAob25seUNsZWFuKSB7XG4gICAgICBjbGVhbkNvbXBvbmVudHMgPSBnZXRVbmNoYW5nZWRDb21wb25lbnRzKG1lYXN1cmVtZW50KTtcbiAgICB9XG5cbiAgICBmb3IgKHZhciBpZCBpbiBhbGxJRHMpIHtcbiAgICAgIGlmIChvbmx5Q2xlYW4gJiYgIWNsZWFuQ29tcG9uZW50c1tpZF0pIHtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG5cbiAgICAgIHZhciBkaXNwbGF5TmFtZSA9IG1lYXN1cmVtZW50LmRpc3BsYXlOYW1lc1tpZF07XG5cbiAgICAgIC8vIEluY2x1c2l2ZSB0aW1lIGlzIG5vdCB1c2VmdWwgZm9yIG1hbnkgY29tcG9uZW50cyB3aXRob3V0IGtub3dpbmcgd2hlcmVcbiAgICAgIC8vIHRoZXkgYXJlIGluc3RhbnRpYXRlZC4gU28gd2UgYWdncmVnYXRlIGluY2x1c2l2ZSB0aW1lIHdpdGggYm90aCB0aGVcbiAgICAgIC8vIG93bmVyIGFuZCBjdXJyZW50IGRpc3BsYXlOYW1lIGFzIHRoZSBrZXkuXG4gICAgICBpbmNsdXNpdmVLZXkgPSBkaXNwbGF5TmFtZS5vd25lciArICcgPiAnICsgZGlzcGxheU5hbWUuY3VycmVudDtcblxuICAgICAgY2FuZGlkYXRlc1tpbmNsdXNpdmVLZXldID0gY2FuZGlkYXRlc1tpbmNsdXNpdmVLZXldIHx8IHtcbiAgICAgICAgY29tcG9uZW50TmFtZTogaW5jbHVzaXZlS2V5LFxuICAgICAgICB0aW1lOiAwLFxuICAgICAgICBjb3VudDogMFxuICAgICAgfTtcblxuICAgICAgaWYgKG1lYXN1cmVtZW50LmluY2x1c2l2ZVtpZF0pIHtcbiAgICAgICAgY2FuZGlkYXRlc1tpbmNsdXNpdmVLZXldLnRpbWUgKz0gbWVhc3VyZW1lbnQuaW5jbHVzaXZlW2lkXTtcbiAgICAgIH1cbiAgICAgIGlmIChtZWFzdXJlbWVudC5jb3VudHNbaWRdKSB7XG4gICAgICAgIGNhbmRpZGF0ZXNbaW5jbHVzaXZlS2V5XS5jb3VudCArPSBtZWFzdXJlbWVudC5jb3VudHNbaWRdO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8vIE5vdyBtYWtlIGEgc29ydGVkIGFycmF5IHdpdGggdGhlIHJlc3VsdHMuXG4gIHZhciBhcnIgPSBbXTtcbiAgZm9yIChpbmNsdXNpdmVLZXkgaW4gY2FuZGlkYXRlcykge1xuICAgIGlmIChjYW5kaWRhdGVzW2luY2x1c2l2ZUtleV0udGltZSA+PSBET05UX0NBUkVfVEhSRVNIT0xEKSB7XG4gICAgICBhcnIucHVzaChjYW5kaWRhdGVzW2luY2x1c2l2ZUtleV0pO1xuICAgIH1cbiAgfVxuXG4gIGFyci5zb3J0KGZ1bmN0aW9uKGEsIGIpIHtcbiAgICByZXR1cm4gYi50aW1lIC0gYS50aW1lO1xuICB9KTtcblxuICByZXR1cm4gYXJyO1xufVxuXG5mdW5jdGlvbiBnZXRVbmNoYW5nZWRDb21wb25lbnRzKG1lYXN1cmVtZW50KSB7XG4gIC8vIEZvciBhIGdpdmVuIHJlY29uY2lsZSwgbG9vayBhdCB3aGljaCBjb21wb25lbnRzIGRpZCBub3QgYWN0dWFsbHlcbiAgLy8gcmVuZGVyIGFueXRoaW5nIHRvIHRoZSBET00gYW5kIHJldHVybiBhIG1hcHBpbmcgb2YgdGhlaXIgSUQgdG9cbiAgLy8gdGhlIGFtb3VudCBvZiB0aW1lIGl0IHRvb2sgdG8gcmVuZGVyIHRoZSBlbnRpcmUgc3VidHJlZS5cbiAgdmFyIGNsZWFuQ29tcG9uZW50cyA9IHt9O1xuICB2YXIgZGlydHlMZWFmSURzID0gT2JqZWN0LmtleXMobWVhc3VyZW1lbnQud3JpdGVzKTtcbiAgdmFyIGFsbElEcyA9IGFzc2lnbih7fSwgbWVhc3VyZW1lbnQuZXhjbHVzaXZlLCBtZWFzdXJlbWVudC5pbmNsdXNpdmUpO1xuXG4gIGZvciAodmFyIGlkIGluIGFsbElEcykge1xuICAgIHZhciBpc0RpcnR5ID0gZmFsc2U7XG4gICAgLy8gRm9yIGVhY2ggY29tcG9uZW50IHRoYXQgcmVuZGVyZWQsIHNlZSBpZiBhIGNvbXBvbmVudCB0aGF0IHRyaWdnZXJlZFxuICAgIC8vIGEgRE9NIG9wIGlzIGluIGl0cyBzdWJ0cmVlLlxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgZGlydHlMZWFmSURzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBpZiAoZGlydHlMZWFmSURzW2ldLmluZGV4T2YoaWQpID09PSAwKSB7XG4gICAgICAgIGlzRGlydHkgPSB0cnVlO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9XG4gICAgaWYgKCFpc0RpcnR5ICYmIG1lYXN1cmVtZW50LmNvdW50c1tpZF0gPiAwKSB7XG4gICAgICBjbGVhbkNvbXBvbmVudHNbaWRdID0gdHJ1ZTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIGNsZWFuQ29tcG9uZW50cztcbn1cblxudmFyIFJlYWN0RGVmYXVsdFBlcmZBbmFseXNpcyA9IHtcbiAgZ2V0RXhjbHVzaXZlU3VtbWFyeTogZ2V0RXhjbHVzaXZlU3VtbWFyeSxcbiAgZ2V0SW5jbHVzaXZlU3VtbWFyeTogZ2V0SW5jbHVzaXZlU3VtbWFyeSxcbiAgZ2V0RE9NU3VtbWFyeTogZ2V0RE9NU3VtbWFyeSxcbiAgZ2V0VG90YWxUaW1lOiBnZXRUb3RhbFRpbWVcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gUmVhY3REZWZhdWx0UGVyZkFuYWx5c2lzO1xuIiwiKGZ1bmN0aW9uIChwcm9jZXNzKXtcbi8qKlxuICogQ29weXJpZ2h0IDIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgUmVhY3RFbGVtZW50XG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBSZWFjdENvbnRleHQgPSByZXF1aXJlKFwiLi9SZWFjdENvbnRleHRcIik7XG52YXIgUmVhY3RDdXJyZW50T3duZXIgPSByZXF1aXJlKFwiLi9SZWFjdEN1cnJlbnRPd25lclwiKTtcblxudmFyIHdhcm5pbmcgPSByZXF1aXJlKFwiLi93YXJuaW5nXCIpO1xuXG52YXIgUkVTRVJWRURfUFJPUFMgPSB7XG4gIGtleTogdHJ1ZSxcbiAgcmVmOiB0cnVlXG59O1xuXG4vKipcbiAqIFdhcm4gZm9yIG11dGF0aW9ucy5cbiAqXG4gKiBAaW50ZXJuYWxcbiAqIEBwYXJhbSB7b2JqZWN0fSBvYmplY3RcbiAqIEBwYXJhbSB7c3RyaW5nfSBrZXlcbiAqL1xuZnVuY3Rpb24gZGVmaW5lV2FybmluZ1Byb3BlcnR5KG9iamVjdCwga2V5KSB7XG4gIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShvYmplY3QsIGtleSwge1xuXG4gICAgY29uZmlndXJhYmxlOiBmYWxzZSxcbiAgICBlbnVtZXJhYmxlOiB0cnVlLFxuXG4gICAgZ2V0OiBmdW5jdGlvbigpIHtcbiAgICAgIGlmICghdGhpcy5fc3RvcmUpIHtcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICB9XG4gICAgICByZXR1cm4gdGhpcy5fc3RvcmVba2V5XTtcbiAgICB9LFxuXG4gICAgc2V0OiBmdW5jdGlvbih2YWx1ZSkge1xuICAgICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IHdhcm5pbmcoXG4gICAgICAgIGZhbHNlLFxuICAgICAgICAnRG9uXFwndCBzZXQgdGhlICcgKyBrZXkgKyAnIHByb3BlcnR5IG9mIHRoZSBjb21wb25lbnQuICcgK1xuICAgICAgICAnTXV0YXRlIHRoZSBleGlzdGluZyBwcm9wcyBvYmplY3QgaW5zdGVhZC4nXG4gICAgICApIDogbnVsbCk7XG4gICAgICB0aGlzLl9zdG9yZVtrZXldID0gdmFsdWU7XG4gICAgfVxuXG4gIH0pO1xufVxuXG4vKipcbiAqIFRoaXMgaXMgdXBkYXRlZCB0byB0cnVlIGlmIHRoZSBtZW1icmFuZSBpcyBzdWNjZXNzZnVsbHkgY3JlYXRlZC5cbiAqL1xudmFyIHVzZU11dGF0aW9uTWVtYnJhbmUgPSBmYWxzZTtcblxuLyoqXG4gKiBXYXJuIGZvciBtdXRhdGlvbnMuXG4gKlxuICogQGludGVybmFsXG4gKiBAcGFyYW0ge29iamVjdH0gZWxlbWVudFxuICovXG5mdW5jdGlvbiBkZWZpbmVNdXRhdGlvbk1lbWJyYW5lKHByb3RvdHlwZSkge1xuICB0cnkge1xuICAgIHZhciBwc2V1ZG9Gcm96ZW5Qcm9wZXJ0aWVzID0ge1xuICAgICAgcHJvcHM6IHRydWVcbiAgICB9O1xuICAgIGZvciAodmFyIGtleSBpbiBwc2V1ZG9Gcm96ZW5Qcm9wZXJ0aWVzKSB7XG4gICAgICBkZWZpbmVXYXJuaW5nUHJvcGVydHkocHJvdG90eXBlLCBrZXkpO1xuICAgIH1cbiAgICB1c2VNdXRhdGlvbk1lbWJyYW5lID0gdHJ1ZTtcbiAgfSBjYXRjaCAoeCkge1xuICAgIC8vIElFIHdpbGwgZmFpbCBvbiBkZWZpbmVQcm9wZXJ0eVxuICB9XG59XG5cbi8qKlxuICogQmFzZSBjb25zdHJ1Y3RvciBmb3IgYWxsIFJlYWN0IGVsZW1lbnRzLiBUaGlzIGlzIG9ubHkgdXNlZCB0byBtYWtlIHRoaXNcbiAqIHdvcmsgd2l0aCBhIGR5bmFtaWMgaW5zdGFuY2VvZiBjaGVjay4gTm90aGluZyBzaG91bGQgbGl2ZSBvbiB0aGlzIHByb3RvdHlwZS5cbiAqXG4gKiBAcGFyYW0geyp9IHR5cGVcbiAqIEBwYXJhbSB7c3RyaW5nfG9iamVjdH0gcmVmXG4gKiBAcGFyYW0geyp9IGtleVxuICogQHBhcmFtIHsqfSBwcm9wc1xuICogQGludGVybmFsXG4gKi9cbnZhciBSZWFjdEVsZW1lbnQgPSBmdW5jdGlvbih0eXBlLCBrZXksIHJlZiwgb3duZXIsIGNvbnRleHQsIHByb3BzKSB7XG4gIC8vIEJ1aWx0LWluIHByb3BlcnRpZXMgdGhhdCBiZWxvbmcgb24gdGhlIGVsZW1lbnRcbiAgdGhpcy50eXBlID0gdHlwZTtcbiAgdGhpcy5rZXkgPSBrZXk7XG4gIHRoaXMucmVmID0gcmVmO1xuXG4gIC8vIFJlY29yZCB0aGUgY29tcG9uZW50IHJlc3BvbnNpYmxlIGZvciBjcmVhdGluZyB0aGlzIGVsZW1lbnQuXG4gIHRoaXMuX293bmVyID0gb3duZXI7XG5cbiAgLy8gVE9ETzogRGVwcmVjYXRlIHdpdGhDb250ZXh0LCBhbmQgdGhlbiB0aGUgY29udGV4dCBiZWNvbWVzIGFjY2Vzc2libGVcbiAgLy8gdGhyb3VnaCB0aGUgb3duZXIuXG4gIHRoaXMuX2NvbnRleHQgPSBjb250ZXh0O1xuXG4gIGlmIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYpIHtcbiAgICAvLyBUaGUgdmFsaWRhdGlvbiBmbGFnIGFuZCBwcm9wcyBhcmUgY3VycmVudGx5IG11dGF0aXZlLiBXZSBwdXQgdGhlbSBvblxuICAgIC8vIGFuIGV4dGVybmFsIGJhY2tpbmcgc3RvcmUgc28gdGhhdCB3ZSBjYW4gZnJlZXplIHRoZSB3aG9sZSBvYmplY3QuXG4gICAgLy8gVGhpcyBjYW4gYmUgcmVwbGFjZWQgd2l0aCBhIFdlYWtNYXAgb25jZSB0aGV5IGFyZSBpbXBsZW1lbnRlZCBpblxuICAgIC8vIGNvbW1vbmx5IHVzZWQgZGV2ZWxvcG1lbnQgZW52aXJvbm1lbnRzLlxuICAgIHRoaXMuX3N0b3JlID0geyB2YWxpZGF0ZWQ6IGZhbHNlLCBwcm9wczogcHJvcHMgfTtcblxuICAgIC8vIFdlJ3JlIG5vdCBhbGxvd2VkIHRvIHNldCBwcm9wcyBkaXJlY3RseSBvbiB0aGUgb2JqZWN0IHNvIHdlIGVhcmx5XG4gICAgLy8gcmV0dXJuIGFuZCByZWx5IG9uIHRoZSBwcm90b3R5cGUgbWVtYnJhbmUgdG8gZm9yd2FyZCB0byB0aGUgYmFja2luZ1xuICAgIC8vIHN0b3JlLlxuICAgIGlmICh1c2VNdXRhdGlvbk1lbWJyYW5lKSB7XG4gICAgICBPYmplY3QuZnJlZXplKHRoaXMpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgfVxuXG4gIHRoaXMucHJvcHMgPSBwcm9wcztcbn07XG5cbi8vIFdlIGludGVudGlvbmFsbHkgZG9uJ3QgZXhwb3NlIHRoZSBmdW5jdGlvbiBvbiB0aGUgY29uc3RydWN0b3IgcHJvcGVydHkuXG4vLyBSZWFjdEVsZW1lbnQgc2hvdWxkIGJlIGluZGlzdGluZ3Vpc2hhYmxlIGZyb20gYSBwbGFpbiBvYmplY3QuXG5SZWFjdEVsZW1lbnQucHJvdG90eXBlID0ge1xuICBfaXNSZWFjdEVsZW1lbnQ6IHRydWVcbn07XG5cbmlmIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYpIHtcbiAgZGVmaW5lTXV0YXRpb25NZW1icmFuZShSZWFjdEVsZW1lbnQucHJvdG90eXBlKTtcbn1cblxuUmVhY3RFbGVtZW50LmNyZWF0ZUVsZW1lbnQgPSBmdW5jdGlvbih0eXBlLCBjb25maWcsIGNoaWxkcmVuKSB7XG4gIHZhciBwcm9wTmFtZTtcblxuICAvLyBSZXNlcnZlZCBuYW1lcyBhcmUgZXh0cmFjdGVkXG4gIHZhciBwcm9wcyA9IHt9O1xuXG4gIHZhciBrZXkgPSBudWxsO1xuICB2YXIgcmVmID0gbnVsbDtcblxuICBpZiAoY29uZmlnICE9IG51bGwpIHtcbiAgICByZWYgPSBjb25maWcucmVmID09PSB1bmRlZmluZWQgPyBudWxsIDogY29uZmlnLnJlZjtcbiAgICBpZiAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WKSB7XG4gICAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gd2FybmluZyhcbiAgICAgICAgY29uZmlnLmtleSAhPT0gbnVsbCxcbiAgICAgICAgJ2NyZWF0ZUVsZW1lbnQoLi4uKTogRW5jb3VudGVyZWQgY29tcG9uZW50IHdpdGggYSBga2V5YCBvZiBudWxsLiBJbiAnICtcbiAgICAgICAgJ2EgZnV0dXJlIHZlcnNpb24sIHRoaXMgd2lsbCBiZSB0cmVhdGVkIGFzIGVxdWl2YWxlbnQgdG8gdGhlIHN0cmluZyAnICtcbiAgICAgICAgJ1xcJ251bGxcXCc7IGluc3RlYWQsIHByb3ZpZGUgYW4gZXhwbGljaXQga2V5IG9yIHVzZSB1bmRlZmluZWQuJ1xuICAgICAgKSA6IG51bGwpO1xuICAgIH1cbiAgICAvLyBUT0RPOiBDaGFuZ2UgdGhpcyBiYWNrIHRvIGBjb25maWcua2V5ID09PSB1bmRlZmluZWRgXG4gICAga2V5ID0gY29uZmlnLmtleSA9PSBudWxsID8gbnVsbCA6ICcnICsgY29uZmlnLmtleTtcbiAgICAvLyBSZW1haW5pbmcgcHJvcGVydGllcyBhcmUgYWRkZWQgdG8gYSBuZXcgcHJvcHMgb2JqZWN0XG4gICAgZm9yIChwcm9wTmFtZSBpbiBjb25maWcpIHtcbiAgICAgIGlmIChjb25maWcuaGFzT3duUHJvcGVydHkocHJvcE5hbWUpICYmXG4gICAgICAgICAgIVJFU0VSVkVEX1BST1BTLmhhc093blByb3BlcnR5KHByb3BOYW1lKSkge1xuICAgICAgICBwcm9wc1twcm9wTmFtZV0gPSBjb25maWdbcHJvcE5hbWVdO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8vIENoaWxkcmVuIGNhbiBiZSBtb3JlIHRoYW4gb25lIGFyZ3VtZW50LCBhbmQgdGhvc2UgYXJlIHRyYW5zZmVycmVkIG9udG9cbiAgLy8gdGhlIG5ld2x5IGFsbG9jYXRlZCBwcm9wcyBvYmplY3QuXG4gIHZhciBjaGlsZHJlbkxlbmd0aCA9IGFyZ3VtZW50cy5sZW5ndGggLSAyO1xuICBpZiAoY2hpbGRyZW5MZW5ndGggPT09IDEpIHtcbiAgICBwcm9wcy5jaGlsZHJlbiA9IGNoaWxkcmVuO1xuICB9IGVsc2UgaWYgKGNoaWxkcmVuTGVuZ3RoID4gMSkge1xuICAgIHZhciBjaGlsZEFycmF5ID0gQXJyYXkoY2hpbGRyZW5MZW5ndGgpO1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgY2hpbGRyZW5MZW5ndGg7IGkrKykge1xuICAgICAgY2hpbGRBcnJheVtpXSA9IGFyZ3VtZW50c1tpICsgMl07XG4gICAgfVxuICAgIHByb3BzLmNoaWxkcmVuID0gY2hpbGRBcnJheTtcbiAgfVxuXG4gIC8vIFJlc29sdmUgZGVmYXVsdCBwcm9wc1xuICBpZiAodHlwZS5kZWZhdWx0UHJvcHMpIHtcbiAgICB2YXIgZGVmYXVsdFByb3BzID0gdHlwZS5kZWZhdWx0UHJvcHM7XG4gICAgZm9yIChwcm9wTmFtZSBpbiBkZWZhdWx0UHJvcHMpIHtcbiAgICAgIGlmICh0eXBlb2YgcHJvcHNbcHJvcE5hbWVdID09PSAndW5kZWZpbmVkJykge1xuICAgICAgICBwcm9wc1twcm9wTmFtZV0gPSBkZWZhdWx0UHJvcHNbcHJvcE5hbWVdO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiBuZXcgUmVhY3RFbGVtZW50KFxuICAgIHR5cGUsXG4gICAga2V5LFxuICAgIHJlZixcbiAgICBSZWFjdEN1cnJlbnRPd25lci5jdXJyZW50LFxuICAgIFJlYWN0Q29udGV4dC5jdXJyZW50LFxuICAgIHByb3BzXG4gICk7XG59O1xuXG5SZWFjdEVsZW1lbnQuY3JlYXRlRmFjdG9yeSA9IGZ1bmN0aW9uKHR5cGUpIHtcbiAgdmFyIGZhY3RvcnkgPSBSZWFjdEVsZW1lbnQuY3JlYXRlRWxlbWVudC5iaW5kKG51bGwsIHR5cGUpO1xuICAvLyBFeHBvc2UgdGhlIHR5cGUgb24gdGhlIGZhY3RvcnkgYW5kIHRoZSBwcm90b3R5cGUgc28gdGhhdCBpdCBjYW4gYmVcbiAgLy8gZWFzaWx5IGFjY2Vzc2VkIG9uIGVsZW1lbnRzLiBFLmcuIDxGb28gLz4udHlwZSA9PT0gRm9vLnR5cGUuXG4gIC8vIFRoaXMgc2hvdWxkIG5vdCBiZSBuYW1lZCBgY29uc3RydWN0b3JgIHNpbmNlIHRoaXMgbWF5IG5vdCBiZSB0aGUgZnVuY3Rpb25cbiAgLy8gdGhhdCBjcmVhdGVkIHRoZSBlbGVtZW50LCBhbmQgaXQgbWF5IG5vdCBldmVuIGJlIGEgY29uc3RydWN0b3IuXG4gIGZhY3RvcnkudHlwZSA9IHR5cGU7XG4gIHJldHVybiBmYWN0b3J5O1xufTtcblxuUmVhY3RFbGVtZW50LmNsb25lQW5kUmVwbGFjZVByb3BzID0gZnVuY3Rpb24ob2xkRWxlbWVudCwgbmV3UHJvcHMpIHtcbiAgdmFyIG5ld0VsZW1lbnQgPSBuZXcgUmVhY3RFbGVtZW50KFxuICAgIG9sZEVsZW1lbnQudHlwZSxcbiAgICBvbGRFbGVtZW50LmtleSxcbiAgICBvbGRFbGVtZW50LnJlZixcbiAgICBvbGRFbGVtZW50Ll9vd25lcixcbiAgICBvbGRFbGVtZW50Ll9jb250ZXh0LFxuICAgIG5ld1Byb3BzXG4gICk7XG5cbiAgaWYgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOVikge1xuICAgIC8vIElmIHRoZSBrZXkgb24gdGhlIG9yaWdpbmFsIGlzIHZhbGlkLCB0aGVuIHRoZSBjbG9uZSBpcyB2YWxpZFxuICAgIG5ld0VsZW1lbnQuX3N0b3JlLnZhbGlkYXRlZCA9IG9sZEVsZW1lbnQuX3N0b3JlLnZhbGlkYXRlZDtcbiAgfVxuICByZXR1cm4gbmV3RWxlbWVudDtcbn07XG5cbi8qKlxuICogQHBhcmFtIHs/b2JqZWN0fSBvYmplY3RcbiAqIEByZXR1cm4ge2Jvb2xlYW59IFRydWUgaWYgYG9iamVjdGAgaXMgYSB2YWxpZCBjb21wb25lbnQuXG4gKiBAZmluYWxcbiAqL1xuUmVhY3RFbGVtZW50LmlzVmFsaWRFbGVtZW50ID0gZnVuY3Rpb24ob2JqZWN0KSB7XG4gIC8vIFJlYWN0VGVzdFV0aWxzIGlzIG9mdGVuIHVzZWQgb3V0c2lkZSBvZiBiZWZvcmVFYWNoIHdoZXJlIGFzIFJlYWN0IGlzXG4gIC8vIHdpdGhpbiBpdC4gVGhpcyBsZWFkcyB0byB0d28gZGlmZmVyZW50IGluc3RhbmNlcyBvZiBSZWFjdCBvbiB0aGUgc2FtZVxuICAvLyBwYWdlLiBUbyBpZGVudGlmeSBhIGVsZW1lbnQgZnJvbSBhIGRpZmZlcmVudCBSZWFjdCBpbnN0YW5jZSB3ZSB1c2VcbiAgLy8gYSBmbGFnIGluc3RlYWQgb2YgYW4gaW5zdGFuY2VvZiBjaGVjay5cbiAgdmFyIGlzRWxlbWVudCA9ICEhKG9iamVjdCAmJiBvYmplY3QuX2lzUmVhY3RFbGVtZW50KTtcbiAgLy8gaWYgKGlzRWxlbWVudCAmJiAhKG9iamVjdCBpbnN0YW5jZW9mIFJlYWN0RWxlbWVudCkpIHtcbiAgLy8gVGhpcyBpcyBhbiBpbmRpY2F0b3IgdGhhdCB5b3UncmUgdXNpbmcgbXVsdGlwbGUgdmVyc2lvbnMgb2YgUmVhY3QgYXQgdGhlXG4gIC8vIHNhbWUgdGltZS4gVGhpcyB3aWxsIHNjcmV3IHdpdGggb3duZXJzaGlwIGFuZCBzdHVmZi4gRml4IGl0LCBwbGVhc2UuXG4gIC8vIFRPRE86IFdlIGNvdWxkIHBvc3NpYmx5IHdhcm4gaGVyZS5cbiAgLy8gfVxuICByZXR1cm4gaXNFbGVtZW50O1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSBSZWFjdEVsZW1lbnQ7XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKCdfcHJvY2VzcycpKSIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgUmVhY3RFbGVtZW50VmFsaWRhdG9yXG4gKi9cblxuLyoqXG4gKiBSZWFjdEVsZW1lbnRWYWxpZGF0b3IgcHJvdmlkZXMgYSB3cmFwcGVyIGFyb3VuZCBhIGVsZW1lbnQgZmFjdG9yeVxuICogd2hpY2ggdmFsaWRhdGVzIHRoZSBwcm9wcyBwYXNzZWQgdG8gdGhlIGVsZW1lbnQuIFRoaXMgaXMgaW50ZW5kZWQgdG8gYmVcbiAqIHVzZWQgb25seSBpbiBERVYgYW5kIGNvdWxkIGJlIHJlcGxhY2VkIGJ5IGEgc3RhdGljIHR5cGUgY2hlY2tlciBmb3IgbGFuZ3VhZ2VzXG4gKiB0aGF0IHN1cHBvcnQgaXQuXG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBSZWFjdEVsZW1lbnQgPSByZXF1aXJlKFwiLi9SZWFjdEVsZW1lbnRcIik7XG52YXIgUmVhY3RQcm9wVHlwZUxvY2F0aW9ucyA9IHJlcXVpcmUoXCIuL1JlYWN0UHJvcFR5cGVMb2NhdGlvbnNcIik7XG52YXIgUmVhY3RDdXJyZW50T3duZXIgPSByZXF1aXJlKFwiLi9SZWFjdEN1cnJlbnRPd25lclwiKTtcblxudmFyIG1vbml0b3JDb2RlVXNlID0gcmVxdWlyZShcIi4vbW9uaXRvckNvZGVVc2VcIik7XG5cbi8qKlxuICogV2FybiBpZiB0aGVyZSdzIG5vIGtleSBleHBsaWNpdGx5IHNldCBvbiBkeW5hbWljIGFycmF5cyBvZiBjaGlsZHJlbiBvclxuICogb2JqZWN0IGtleXMgYXJlIG5vdCB2YWxpZC4gVGhpcyBhbGxvd3MgdXMgdG8ga2VlcCB0cmFjayBvZiBjaGlsZHJlbiBiZXR3ZWVuXG4gKiB1cGRhdGVzLlxuICovXG52YXIgb3duZXJIYXNLZXlVc2VXYXJuaW5nID0ge1xuICAncmVhY3Rfa2V5X3dhcm5pbmcnOiB7fSxcbiAgJ3JlYWN0X251bWVyaWNfa2V5X3dhcm5pbmcnOiB7fVxufTtcbnZhciBvd25lckhhc01vbml0b3JlZE9iamVjdE1hcCA9IHt9O1xuXG52YXIgbG9nZ2VkVHlwZUZhaWx1cmVzID0ge307XG5cbnZhciBOVU1FUklDX1BST1BFUlRZX1JFR0VYID0gL15cXGQrJC87XG5cbi8qKlxuICogR2V0cyB0aGUgY3VycmVudCBvd25lcidzIGRpc3BsYXlOYW1lIGZvciB1c2UgaW4gd2FybmluZ3MuXG4gKlxuICogQGludGVybmFsXG4gKiBAcmV0dXJuIHs/c3RyaW5nfSBEaXNwbGF5IG5hbWUgb3IgdW5kZWZpbmVkXG4gKi9cbmZ1bmN0aW9uIGdldEN1cnJlbnRPd25lckRpc3BsYXlOYW1lKCkge1xuICB2YXIgY3VycmVudCA9IFJlYWN0Q3VycmVudE93bmVyLmN1cnJlbnQ7XG4gIHJldHVybiBjdXJyZW50ICYmIGN1cnJlbnQuY29uc3RydWN0b3IuZGlzcGxheU5hbWUgfHwgdW5kZWZpbmVkO1xufVxuXG4vKipcbiAqIFdhcm4gaWYgdGhlIGNvbXBvbmVudCBkb2Vzbid0IGhhdmUgYW4gZXhwbGljaXQga2V5IGFzc2lnbmVkIHRvIGl0LlxuICogVGhpcyBjb21wb25lbnQgaXMgaW4gYW4gYXJyYXkuIFRoZSBhcnJheSBjb3VsZCBncm93IGFuZCBzaHJpbmsgb3IgYmVcbiAqIHJlb3JkZXJlZC4gQWxsIGNoaWxkcmVuIHRoYXQgaGF2ZW4ndCBhbHJlYWR5IGJlZW4gdmFsaWRhdGVkIGFyZSByZXF1aXJlZCB0b1xuICogaGF2ZSBhIFwia2V5XCIgcHJvcGVydHkgYXNzaWduZWQgdG8gaXQuXG4gKlxuICogQGludGVybmFsXG4gKiBAcGFyYW0ge1JlYWN0Q29tcG9uZW50fSBjb21wb25lbnQgQ29tcG9uZW50IHRoYXQgcmVxdWlyZXMgYSBrZXkuXG4gKiBAcGFyYW0geyp9IHBhcmVudFR5cGUgY29tcG9uZW50J3MgcGFyZW50J3MgdHlwZS5cbiAqL1xuZnVuY3Rpb24gdmFsaWRhdGVFeHBsaWNpdEtleShjb21wb25lbnQsIHBhcmVudFR5cGUpIHtcbiAgaWYgKGNvbXBvbmVudC5fc3RvcmUudmFsaWRhdGVkIHx8IGNvbXBvbmVudC5rZXkgIT0gbnVsbCkge1xuICAgIHJldHVybjtcbiAgfVxuICBjb21wb25lbnQuX3N0b3JlLnZhbGlkYXRlZCA9IHRydWU7XG5cbiAgd2FybkFuZE1vbml0b3JGb3JLZXlVc2UoXG4gICAgJ3JlYWN0X2tleV93YXJuaW5nJyxcbiAgICAnRWFjaCBjaGlsZCBpbiBhbiBhcnJheSBzaG91bGQgaGF2ZSBhIHVuaXF1ZSBcImtleVwiIHByb3AuJyxcbiAgICBjb21wb25lbnQsXG4gICAgcGFyZW50VHlwZVxuICApO1xufVxuXG4vKipcbiAqIFdhcm4gaWYgdGhlIGtleSBpcyBiZWluZyBkZWZpbmVkIGFzIGFuIG9iamVjdCBwcm9wZXJ0eSBidXQgaGFzIGFuIGluY29ycmVjdFxuICogdmFsdWUuXG4gKlxuICogQGludGVybmFsXG4gKiBAcGFyYW0ge3N0cmluZ30gbmFtZSBQcm9wZXJ0eSBuYW1lIG9mIHRoZSBrZXkuXG4gKiBAcGFyYW0ge1JlYWN0Q29tcG9uZW50fSBjb21wb25lbnQgQ29tcG9uZW50IHRoYXQgcmVxdWlyZXMgYSBrZXkuXG4gKiBAcGFyYW0geyp9IHBhcmVudFR5cGUgY29tcG9uZW50J3MgcGFyZW50J3MgdHlwZS5cbiAqL1xuZnVuY3Rpb24gdmFsaWRhdGVQcm9wZXJ0eUtleShuYW1lLCBjb21wb25lbnQsIHBhcmVudFR5cGUpIHtcbiAgaWYgKCFOVU1FUklDX1BST1BFUlRZX1JFR0VYLnRlc3QobmFtZSkpIHtcbiAgICByZXR1cm47XG4gIH1cbiAgd2FybkFuZE1vbml0b3JGb3JLZXlVc2UoXG4gICAgJ3JlYWN0X251bWVyaWNfa2V5X3dhcm5pbmcnLFxuICAgICdDaGlsZCBvYmplY3RzIHNob3VsZCBoYXZlIG5vbi1udW1lcmljIGtleXMgc28gb3JkZXJpbmcgaXMgcHJlc2VydmVkLicsXG4gICAgY29tcG9uZW50LFxuICAgIHBhcmVudFR5cGVcbiAgKTtcbn1cblxuLyoqXG4gKiBTaGFyZWQgd2FybmluZyBhbmQgbW9uaXRvcmluZyBjb2RlIGZvciB0aGUga2V5IHdhcm5pbmdzLlxuICpcbiAqIEBpbnRlcm5hbFxuICogQHBhcmFtIHtzdHJpbmd9IHdhcm5pbmdJRCBUaGUgaWQgdXNlZCB3aGVuIGxvZ2dpbmcuXG4gKiBAcGFyYW0ge3N0cmluZ30gbWVzc2FnZSBUaGUgYmFzZSB3YXJuaW5nIHRoYXQgZ2V0cyBvdXRwdXQuXG4gKiBAcGFyYW0ge1JlYWN0Q29tcG9uZW50fSBjb21wb25lbnQgQ29tcG9uZW50IHRoYXQgcmVxdWlyZXMgYSBrZXkuXG4gKiBAcGFyYW0geyp9IHBhcmVudFR5cGUgY29tcG9uZW50J3MgcGFyZW50J3MgdHlwZS5cbiAqL1xuZnVuY3Rpb24gd2FybkFuZE1vbml0b3JGb3JLZXlVc2Uod2FybmluZ0lELCBtZXNzYWdlLCBjb21wb25lbnQsIHBhcmVudFR5cGUpIHtcbiAgdmFyIG93bmVyTmFtZSA9IGdldEN1cnJlbnRPd25lckRpc3BsYXlOYW1lKCk7XG4gIHZhciBwYXJlbnROYW1lID0gcGFyZW50VHlwZS5kaXNwbGF5TmFtZTtcblxuICB2YXIgdXNlTmFtZSA9IG93bmVyTmFtZSB8fCBwYXJlbnROYW1lO1xuICB2YXIgbWVtb2l6ZXIgPSBvd25lckhhc0tleVVzZVdhcm5pbmdbd2FybmluZ0lEXTtcbiAgaWYgKG1lbW9pemVyLmhhc093blByb3BlcnR5KHVzZU5hbWUpKSB7XG4gICAgcmV0dXJuO1xuICB9XG4gIG1lbW9pemVyW3VzZU5hbWVdID0gdHJ1ZTtcblxuICBtZXNzYWdlICs9IG93bmVyTmFtZSA/XG4gICAgKFwiIENoZWNrIHRoZSByZW5kZXIgbWV0aG9kIG9mIFwiICsgb3duZXJOYW1lICsgXCIuXCIpIDpcbiAgICAoXCIgQ2hlY2sgdGhlIHJlbmRlckNvbXBvbmVudCBjYWxsIHVzaW5nIDxcIiArIHBhcmVudE5hbWUgKyBcIj4uXCIpO1xuXG4gIC8vIFVzdWFsbHkgdGhlIGN1cnJlbnQgb3duZXIgaXMgdGhlIG9mZmVuZGVyLCBidXQgaWYgaXQgYWNjZXB0cyBjaGlsZHJlbiBhcyBhXG4gIC8vIHByb3BlcnR5LCBpdCBtYXkgYmUgdGhlIGNyZWF0b3Igb2YgdGhlIGNoaWxkIHRoYXQncyByZXNwb25zaWJsZSBmb3JcbiAgLy8gYXNzaWduaW5nIGl0IGEga2V5LlxuICB2YXIgY2hpbGRPd25lck5hbWUgPSBudWxsO1xuICBpZiAoY29tcG9uZW50Ll9vd25lciAmJiBjb21wb25lbnQuX293bmVyICE9PSBSZWFjdEN1cnJlbnRPd25lci5jdXJyZW50KSB7XG4gICAgLy8gTmFtZSBvZiB0aGUgY29tcG9uZW50IHRoYXQgb3JpZ2luYWxseSBjcmVhdGVkIHRoaXMgY2hpbGQuXG4gICAgY2hpbGRPd25lck5hbWUgPSBjb21wb25lbnQuX293bmVyLmNvbnN0cnVjdG9yLmRpc3BsYXlOYW1lO1xuXG4gICAgbWVzc2FnZSArPSAoXCIgSXQgd2FzIHBhc3NlZCBhIGNoaWxkIGZyb20gXCIgKyBjaGlsZE93bmVyTmFtZSArIFwiLlwiKTtcbiAgfVxuXG4gIG1lc3NhZ2UgKz0gJyBTZWUgaHR0cDovL2ZiLm1lL3JlYWN0LXdhcm5pbmcta2V5cyBmb3IgbW9yZSBpbmZvcm1hdGlvbi4nO1xuICBtb25pdG9yQ29kZVVzZSh3YXJuaW5nSUQsIHtcbiAgICBjb21wb25lbnQ6IHVzZU5hbWUsXG4gICAgY29tcG9uZW50T3duZXI6IGNoaWxkT3duZXJOYW1lXG4gIH0pO1xuICBjb25zb2xlLndhcm4obWVzc2FnZSk7XG59XG5cbi8qKlxuICogTG9nIHRoYXQgd2UncmUgdXNpbmcgYW4gb2JqZWN0IG1hcC4gV2UncmUgY29uc2lkZXJpbmcgZGVwcmVjYXRpbmcgdGhpc1xuICogZmVhdHVyZSBhbmQgcmVwbGFjZSBpdCB3aXRoIHByb3BlciBNYXAgYW5kIEltbXV0YWJsZU1hcCBkYXRhIHN0cnVjdHVyZXMuXG4gKlxuICogQGludGVybmFsXG4gKi9cbmZ1bmN0aW9uIG1vbml0b3JVc2VPZk9iamVjdE1hcCgpIHtcbiAgdmFyIGN1cnJlbnROYW1lID0gZ2V0Q3VycmVudE93bmVyRGlzcGxheU5hbWUoKSB8fCAnJztcbiAgaWYgKG93bmVySGFzTW9uaXRvcmVkT2JqZWN0TWFwLmhhc093blByb3BlcnR5KGN1cnJlbnROYW1lKSkge1xuICAgIHJldHVybjtcbiAgfVxuICBvd25lckhhc01vbml0b3JlZE9iamVjdE1hcFtjdXJyZW50TmFtZV0gPSB0cnVlO1xuICBtb25pdG9yQ29kZVVzZSgncmVhY3Rfb2JqZWN0X21hcF9jaGlsZHJlbicpO1xufVxuXG4vKipcbiAqIEVuc3VyZSB0aGF0IGV2ZXJ5IGNvbXBvbmVudCBlaXRoZXIgaXMgcGFzc2VkIGluIGEgc3RhdGljIGxvY2F0aW9uLCBpbiBhblxuICogYXJyYXkgd2l0aCBhbiBleHBsaWNpdCBrZXlzIHByb3BlcnR5IGRlZmluZWQsIG9yIGluIGFuIG9iamVjdCBsaXRlcmFsXG4gKiB3aXRoIHZhbGlkIGtleSBwcm9wZXJ0eS5cbiAqXG4gKiBAaW50ZXJuYWxcbiAqIEBwYXJhbSB7Kn0gY29tcG9uZW50IFN0YXRpY2FsbHkgcGFzc2VkIGNoaWxkIG9mIGFueSB0eXBlLlxuICogQHBhcmFtIHsqfSBwYXJlbnRUeXBlIGNvbXBvbmVudCdzIHBhcmVudCdzIHR5cGUuXG4gKiBAcmV0dXJuIHtib29sZWFufVxuICovXG5mdW5jdGlvbiB2YWxpZGF0ZUNoaWxkS2V5cyhjb21wb25lbnQsIHBhcmVudFR5cGUpIHtcbiAgaWYgKEFycmF5LmlzQXJyYXkoY29tcG9uZW50KSkge1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgY29tcG9uZW50Lmxlbmd0aDsgaSsrKSB7XG4gICAgICB2YXIgY2hpbGQgPSBjb21wb25lbnRbaV07XG4gICAgICBpZiAoUmVhY3RFbGVtZW50LmlzVmFsaWRFbGVtZW50KGNoaWxkKSkge1xuICAgICAgICB2YWxpZGF0ZUV4cGxpY2l0S2V5KGNoaWxkLCBwYXJlbnRUeXBlKTtcbiAgICAgIH1cbiAgICB9XG4gIH0gZWxzZSBpZiAoUmVhY3RFbGVtZW50LmlzVmFsaWRFbGVtZW50KGNvbXBvbmVudCkpIHtcbiAgICAvLyBUaGlzIGNvbXBvbmVudCB3YXMgcGFzc2VkIGluIGEgdmFsaWQgbG9jYXRpb24uXG4gICAgY29tcG9uZW50Ll9zdG9yZS52YWxpZGF0ZWQgPSB0cnVlO1xuICB9IGVsc2UgaWYgKGNvbXBvbmVudCAmJiB0eXBlb2YgY29tcG9uZW50ID09PSAnb2JqZWN0Jykge1xuICAgIG1vbml0b3JVc2VPZk9iamVjdE1hcCgpO1xuICAgIGZvciAodmFyIG5hbWUgaW4gY29tcG9uZW50KSB7XG4gICAgICB2YWxpZGF0ZVByb3BlcnR5S2V5KG5hbWUsIGNvbXBvbmVudFtuYW1lXSwgcGFyZW50VHlwZSk7XG4gICAgfVxuICB9XG59XG5cbi8qKlxuICogQXNzZXJ0IHRoYXQgdGhlIHByb3BzIGFyZSB2YWxpZFxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBjb21wb25lbnROYW1lIE5hbWUgb2YgdGhlIGNvbXBvbmVudCBmb3IgZXJyb3IgbWVzc2FnZXMuXG4gKiBAcGFyYW0ge29iamVjdH0gcHJvcFR5cGVzIE1hcCBvZiBwcm9wIG5hbWUgdG8gYSBSZWFjdFByb3BUeXBlXG4gKiBAcGFyYW0ge29iamVjdH0gcHJvcHNcbiAqIEBwYXJhbSB7c3RyaW5nfSBsb2NhdGlvbiBlLmcuIFwicHJvcFwiLCBcImNvbnRleHRcIiwgXCJjaGlsZCBjb250ZXh0XCJcbiAqIEBwcml2YXRlXG4gKi9cbmZ1bmN0aW9uIGNoZWNrUHJvcFR5cGVzKGNvbXBvbmVudE5hbWUsIHByb3BUeXBlcywgcHJvcHMsIGxvY2F0aW9uKSB7XG4gIGZvciAodmFyIHByb3BOYW1lIGluIHByb3BUeXBlcykge1xuICAgIGlmIChwcm9wVHlwZXMuaGFzT3duUHJvcGVydHkocHJvcE5hbWUpKSB7XG4gICAgICB2YXIgZXJyb3I7XG4gICAgICAvLyBQcm9wIHR5cGUgdmFsaWRhdGlvbiBtYXkgdGhyb3cuIEluIGNhc2UgdGhleSBkbywgd2UgZG9uJ3Qgd2FudCB0b1xuICAgICAgLy8gZmFpbCB0aGUgcmVuZGVyIHBoYXNlIHdoZXJlIGl0IGRpZG4ndCBmYWlsIGJlZm9yZS4gU28gd2UgbG9nIGl0LlxuICAgICAgLy8gQWZ0ZXIgdGhlc2UgaGF2ZSBiZWVuIGNsZWFuZWQgdXAsIHdlJ2xsIGxldCB0aGVtIHRocm93LlxuICAgICAgdHJ5IHtcbiAgICAgICAgZXJyb3IgPSBwcm9wVHlwZXNbcHJvcE5hbWVdKHByb3BzLCBwcm9wTmFtZSwgY29tcG9uZW50TmFtZSwgbG9jYXRpb24pO1xuICAgICAgfSBjYXRjaCAoZXgpIHtcbiAgICAgICAgZXJyb3IgPSBleDtcbiAgICAgIH1cbiAgICAgIGlmIChlcnJvciBpbnN0YW5jZW9mIEVycm9yICYmICEoZXJyb3IubWVzc2FnZSBpbiBsb2dnZWRUeXBlRmFpbHVyZXMpKSB7XG4gICAgICAgIC8vIE9ubHkgbW9uaXRvciB0aGlzIGZhaWx1cmUgb25jZSBiZWNhdXNlIHRoZXJlIHRlbmRzIHRvIGJlIGEgbG90IG9mIHRoZVxuICAgICAgICAvLyBzYW1lIGVycm9yLlxuICAgICAgICBsb2dnZWRUeXBlRmFpbHVyZXNbZXJyb3IubWVzc2FnZV0gPSB0cnVlO1xuICAgICAgICAvLyBUaGlzIHdpbGwgc29vbiB1c2UgdGhlIHdhcm5pbmcgbW9kdWxlXG4gICAgICAgIG1vbml0b3JDb2RlVXNlKFxuICAgICAgICAgICdyZWFjdF9mYWlsZWRfZGVzY3JpcHRvcl90eXBlX2NoZWNrJyxcbiAgICAgICAgICB7IG1lc3NhZ2U6IGVycm9yLm1lc3NhZ2UgfVxuICAgICAgICApO1xuICAgICAgfVxuICAgIH1cbiAgfVxufVxuXG52YXIgUmVhY3RFbGVtZW50VmFsaWRhdG9yID0ge1xuXG4gIGNyZWF0ZUVsZW1lbnQ6IGZ1bmN0aW9uKHR5cGUsIHByb3BzLCBjaGlsZHJlbikge1xuICAgIHZhciBlbGVtZW50ID0gUmVhY3RFbGVtZW50LmNyZWF0ZUVsZW1lbnQuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcblxuICAgIC8vIFRoZSByZXN1bHQgY2FuIGJlIG51bGxpc2ggaWYgYSBtb2NrIG9yIGEgY3VzdG9tIGZ1bmN0aW9uIGlzIHVzZWQuXG4gICAgLy8gVE9ETzogRHJvcCB0aGlzIHdoZW4gdGhlc2UgYXJlIG5vIGxvbmdlciBhbGxvd2VkIGFzIHRoZSB0eXBlIGFyZ3VtZW50LlxuICAgIGlmIChlbGVtZW50ID09IG51bGwpIHtcbiAgICAgIHJldHVybiBlbGVtZW50O1xuICAgIH1cblxuICAgIGZvciAodmFyIGkgPSAyOyBpIDwgYXJndW1lbnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICB2YWxpZGF0ZUNoaWxkS2V5cyhhcmd1bWVudHNbaV0sIHR5cGUpO1xuICAgIH1cblxuICAgIHZhciBuYW1lID0gdHlwZS5kaXNwbGF5TmFtZTtcbiAgICBpZiAodHlwZS5wcm9wVHlwZXMpIHtcbiAgICAgIGNoZWNrUHJvcFR5cGVzKFxuICAgICAgICBuYW1lLFxuICAgICAgICB0eXBlLnByb3BUeXBlcyxcbiAgICAgICAgZWxlbWVudC5wcm9wcyxcbiAgICAgICAgUmVhY3RQcm9wVHlwZUxvY2F0aW9ucy5wcm9wXG4gICAgICApO1xuICAgIH1cbiAgICBpZiAodHlwZS5jb250ZXh0VHlwZXMpIHtcbiAgICAgIGNoZWNrUHJvcFR5cGVzKFxuICAgICAgICBuYW1lLFxuICAgICAgICB0eXBlLmNvbnRleHRUeXBlcyxcbiAgICAgICAgZWxlbWVudC5fY29udGV4dCxcbiAgICAgICAgUmVhY3RQcm9wVHlwZUxvY2F0aW9ucy5jb250ZXh0XG4gICAgICApO1xuICAgIH1cbiAgICByZXR1cm4gZWxlbWVudDtcbiAgfSxcblxuICBjcmVhdGVGYWN0b3J5OiBmdW5jdGlvbih0eXBlKSB7XG4gICAgdmFyIHZhbGlkYXRlZEZhY3RvcnkgPSBSZWFjdEVsZW1lbnRWYWxpZGF0b3IuY3JlYXRlRWxlbWVudC5iaW5kKFxuICAgICAgbnVsbCxcbiAgICAgIHR5cGVcbiAgICApO1xuICAgIHZhbGlkYXRlZEZhY3RvcnkudHlwZSA9IHR5cGU7XG4gICAgcmV0dXJuIHZhbGlkYXRlZEZhY3Rvcnk7XG4gIH1cblxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBSZWFjdEVsZW1lbnRWYWxpZGF0b3I7XG4iLCIoZnVuY3Rpb24gKHByb2Nlc3Mpe1xuLyoqXG4gKiBDb3B5cmlnaHQgMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBSZWFjdEVtcHR5Q29tcG9uZW50XG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBSZWFjdEVsZW1lbnQgPSByZXF1aXJlKFwiLi9SZWFjdEVsZW1lbnRcIik7XG5cbnZhciBpbnZhcmlhbnQgPSByZXF1aXJlKFwiLi9pbnZhcmlhbnRcIik7XG5cbnZhciBjb21wb25lbnQ7XG4vLyBUaGlzIHJlZ2lzdHJ5IGtlZXBzIHRyYWNrIG9mIHRoZSBSZWFjdCBJRHMgb2YgdGhlIGNvbXBvbmVudHMgdGhhdCByZW5kZXJlZCB0b1xuLy8gYG51bGxgIChpbiByZWFsaXR5IGEgcGxhY2Vob2xkZXIgc3VjaCBhcyBgbm9zY3JpcHRgKVxudmFyIG51bGxDb21wb25lbnRJZHNSZWdpc3RyeSA9IHt9O1xuXG52YXIgUmVhY3RFbXB0eUNvbXBvbmVudEluamVjdGlvbiA9IHtcbiAgaW5qZWN0RW1wdHlDb21wb25lbnQ6IGZ1bmN0aW9uKGVtcHR5Q29tcG9uZW50KSB7XG4gICAgY29tcG9uZW50ID0gUmVhY3RFbGVtZW50LmNyZWF0ZUZhY3RvcnkoZW1wdHlDb21wb25lbnQpO1xuICB9XG59O1xuXG4vKipcbiAqIEByZXR1cm4ge1JlYWN0Q29tcG9uZW50fSBjb21wb25lbnQgVGhlIGluamVjdGVkIGVtcHR5IGNvbXBvbmVudC5cbiAqL1xuZnVuY3Rpb24gZ2V0RW1wdHlDb21wb25lbnQoKSB7XG4gIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgY29tcG9uZW50LFxuICAgICdUcnlpbmcgdG8gcmV0dXJuIG51bGwgZnJvbSBhIHJlbmRlciwgYnV0IG5vIG51bGwgcGxhY2Vob2xkZXIgY29tcG9uZW50ICcgK1xuICAgICd3YXMgaW5qZWN0ZWQuJ1xuICApIDogaW52YXJpYW50KGNvbXBvbmVudCkpO1xuICByZXR1cm4gY29tcG9uZW50KCk7XG59XG5cbi8qKlxuICogTWFyayB0aGUgY29tcG9uZW50IGFzIGhhdmluZyByZW5kZXJlZCB0byBudWxsLlxuICogQHBhcmFtIHtzdHJpbmd9IGlkIENvbXBvbmVudCdzIGBfcm9vdE5vZGVJRGAuXG4gKi9cbmZ1bmN0aW9uIHJlZ2lzdGVyTnVsbENvbXBvbmVudElEKGlkKSB7XG4gIG51bGxDb21wb25lbnRJZHNSZWdpc3RyeVtpZF0gPSB0cnVlO1xufVxuXG4vKipcbiAqIFVubWFyayB0aGUgY29tcG9uZW50IGFzIGhhdmluZyByZW5kZXJlZCB0byBudWxsOiBpdCByZW5kZXJzIHRvIHNvbWV0aGluZyBub3cuXG4gKiBAcGFyYW0ge3N0cmluZ30gaWQgQ29tcG9uZW50J3MgYF9yb290Tm9kZUlEYC5cbiAqL1xuZnVuY3Rpb24gZGVyZWdpc3Rlck51bGxDb21wb25lbnRJRChpZCkge1xuICBkZWxldGUgbnVsbENvbXBvbmVudElkc1JlZ2lzdHJ5W2lkXTtcbn1cblxuLyoqXG4gKiBAcGFyYW0ge3N0cmluZ30gaWQgQ29tcG9uZW50J3MgYF9yb290Tm9kZUlEYC5cbiAqIEByZXR1cm4ge2Jvb2xlYW59IFRydWUgaWYgdGhlIGNvbXBvbmVudCBpcyByZW5kZXJlZCB0byBudWxsLlxuICovXG5mdW5jdGlvbiBpc051bGxDb21wb25lbnRJRChpZCkge1xuICByZXR1cm4gbnVsbENvbXBvbmVudElkc1JlZ2lzdHJ5W2lkXTtcbn1cblxudmFyIFJlYWN0RW1wdHlDb21wb25lbnQgPSB7XG4gIGRlcmVnaXN0ZXJOdWxsQ29tcG9uZW50SUQ6IGRlcmVnaXN0ZXJOdWxsQ29tcG9uZW50SUQsXG4gIGdldEVtcHR5Q29tcG9uZW50OiBnZXRFbXB0eUNvbXBvbmVudCxcbiAgaW5qZWN0aW9uOiBSZWFjdEVtcHR5Q29tcG9uZW50SW5qZWN0aW9uLFxuICBpc051bGxDb21wb25lbnRJRDogaXNOdWxsQ29tcG9uZW50SUQsXG4gIHJlZ2lzdGVyTnVsbENvbXBvbmVudElEOiByZWdpc3Rlck51bGxDb21wb25lbnRJRFxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBSZWFjdEVtcHR5Q29tcG9uZW50O1xuXG59KS5jYWxsKHRoaXMscmVxdWlyZSgnX3Byb2Nlc3MnKSkiLCIvKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgUmVhY3RFcnJvclV0aWxzXG4gKiBAdHlwZWNoZWNrc1xuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgUmVhY3RFcnJvclV0aWxzID0ge1xuICAvKipcbiAgICogQ3JlYXRlcyBhIGd1YXJkZWQgdmVyc2lvbiBvZiBhIGZ1bmN0aW9uLiBUaGlzIGlzIHN1cHBvc2VkIHRvIG1ha2UgZGVidWdnaW5nXG4gICAqIG9mIGV2ZW50IGhhbmRsZXJzIGVhc2llci4gVG8gYWlkIGRlYnVnZ2luZyB3aXRoIHRoZSBicm93c2VyJ3MgZGVidWdnZXIsXG4gICAqIHRoaXMgY3VycmVudGx5IHNpbXBseSByZXR1cm5zIHRoZSBvcmlnaW5hbCBmdW5jdGlvbi5cbiAgICpcbiAgICogQHBhcmFtIHtmdW5jdGlvbn0gZnVuYyBGdW5jdGlvbiB0byBiZSBleGVjdXRlZFxuICAgKiBAcGFyYW0ge3N0cmluZ30gbmFtZSBUaGUgbmFtZSBvZiB0aGUgZ3VhcmRcbiAgICogQHJldHVybiB7ZnVuY3Rpb259XG4gICAqL1xuICBndWFyZDogZnVuY3Rpb24oZnVuYywgbmFtZSkge1xuICAgIHJldHVybiBmdW5jO1xuICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJlYWN0RXJyb3JVdGlscztcbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBSZWFjdEV2ZW50RW1pdHRlck1peGluXG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBFdmVudFBsdWdpbkh1YiA9IHJlcXVpcmUoXCIuL0V2ZW50UGx1Z2luSHViXCIpO1xuXG5mdW5jdGlvbiBydW5FdmVudFF1ZXVlSW5CYXRjaChldmVudHMpIHtcbiAgRXZlbnRQbHVnaW5IdWIuZW5xdWV1ZUV2ZW50cyhldmVudHMpO1xuICBFdmVudFBsdWdpbkh1Yi5wcm9jZXNzRXZlbnRRdWV1ZSgpO1xufVxuXG52YXIgUmVhY3RFdmVudEVtaXR0ZXJNaXhpbiA9IHtcblxuICAvKipcbiAgICogU3RyZWFtcyBhIGZpcmVkIHRvcC1sZXZlbCBldmVudCB0byBgRXZlbnRQbHVnaW5IdWJgIHdoZXJlIHBsdWdpbnMgaGF2ZSB0aGVcbiAgICogb3Bwb3J0dW5pdHkgdG8gY3JlYXRlIGBSZWFjdEV2ZW50YHMgdG8gYmUgZGlzcGF0Y2hlZC5cbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IHRvcExldmVsVHlwZSBSZWNvcmQgZnJvbSBgRXZlbnRDb25zdGFudHNgLlxuICAgKiBAcGFyYW0ge29iamVjdH0gdG9wTGV2ZWxUYXJnZXQgVGhlIGxpc3RlbmluZyBjb21wb25lbnQgcm9vdCBub2RlLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gdG9wTGV2ZWxUYXJnZXRJRCBJRCBvZiBgdG9wTGV2ZWxUYXJnZXRgLlxuICAgKiBAcGFyYW0ge29iamVjdH0gbmF0aXZlRXZlbnQgTmF0aXZlIGVudmlyb25tZW50IGV2ZW50LlxuICAgKi9cbiAgaGFuZGxlVG9wTGV2ZWw6IGZ1bmN0aW9uKFxuICAgICAgdG9wTGV2ZWxUeXBlLFxuICAgICAgdG9wTGV2ZWxUYXJnZXQsXG4gICAgICB0b3BMZXZlbFRhcmdldElELFxuICAgICAgbmF0aXZlRXZlbnQpIHtcbiAgICB2YXIgZXZlbnRzID0gRXZlbnRQbHVnaW5IdWIuZXh0cmFjdEV2ZW50cyhcbiAgICAgIHRvcExldmVsVHlwZSxcbiAgICAgIHRvcExldmVsVGFyZ2V0LFxuICAgICAgdG9wTGV2ZWxUYXJnZXRJRCxcbiAgICAgIG5hdGl2ZUV2ZW50XG4gICAgKTtcblxuICAgIHJ1bkV2ZW50UXVldWVJbkJhdGNoKGV2ZW50cyk7XG4gIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gUmVhY3RFdmVudEVtaXR0ZXJNaXhpbjtcbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBSZWFjdEV2ZW50TGlzdGVuZXJcbiAqIEB0eXBlY2hlY2tzIHN0YXRpYy1vbmx5XG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBFdmVudExpc3RlbmVyID0gcmVxdWlyZShcIi4vRXZlbnRMaXN0ZW5lclwiKTtcbnZhciBFeGVjdXRpb25FbnZpcm9ubWVudCA9IHJlcXVpcmUoXCIuL0V4ZWN1dGlvbkVudmlyb25tZW50XCIpO1xudmFyIFBvb2xlZENsYXNzID0gcmVxdWlyZShcIi4vUG9vbGVkQ2xhc3NcIik7XG52YXIgUmVhY3RJbnN0YW5jZUhhbmRsZXMgPSByZXF1aXJlKFwiLi9SZWFjdEluc3RhbmNlSGFuZGxlc1wiKTtcbnZhciBSZWFjdE1vdW50ID0gcmVxdWlyZShcIi4vUmVhY3RNb3VudFwiKTtcbnZhciBSZWFjdFVwZGF0ZXMgPSByZXF1aXJlKFwiLi9SZWFjdFVwZGF0ZXNcIik7XG5cbnZhciBhc3NpZ24gPSByZXF1aXJlKFwiLi9PYmplY3QuYXNzaWduXCIpO1xudmFyIGdldEV2ZW50VGFyZ2V0ID0gcmVxdWlyZShcIi4vZ2V0RXZlbnRUYXJnZXRcIik7XG52YXIgZ2V0VW5ib3VuZGVkU2Nyb2xsUG9zaXRpb24gPSByZXF1aXJlKFwiLi9nZXRVbmJvdW5kZWRTY3JvbGxQb3NpdGlvblwiKTtcblxuLyoqXG4gKiBGaW5kcyB0aGUgcGFyZW50IFJlYWN0IGNvbXBvbmVudCBvZiBgbm9kZWAuXG4gKlxuICogQHBhcmFtIHsqfSBub2RlXG4gKiBAcmV0dXJuIHs/RE9NRXZlbnRUYXJnZXR9IFBhcmVudCBjb250YWluZXIsIG9yIGBudWxsYCBpZiB0aGUgc3BlY2lmaWVkIG5vZGVcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgaXMgbm90IG5lc3RlZC5cbiAqL1xuZnVuY3Rpb24gZmluZFBhcmVudChub2RlKSB7XG4gIC8vIFRPRE86IEl0IG1heSBiZSBhIGdvb2QgaWRlYSB0byBjYWNoZSB0aGlzIHRvIHByZXZlbnQgdW5uZWNlc3NhcnkgRE9NXG4gIC8vIHRyYXZlcnNhbCwgYnV0IGNhY2hpbmcgaXMgZGlmZmljdWx0IHRvIGRvIGNvcnJlY3RseSB3aXRob3V0IHVzaW5nIGFcbiAgLy8gbXV0YXRpb24gb2JzZXJ2ZXIgdG8gbGlzdGVuIGZvciBhbGwgRE9NIGNoYW5nZXMuXG4gIHZhciBub2RlSUQgPSBSZWFjdE1vdW50LmdldElEKG5vZGUpO1xuICB2YXIgcm9vdElEID0gUmVhY3RJbnN0YW5jZUhhbmRsZXMuZ2V0UmVhY3RSb290SURGcm9tTm9kZUlEKG5vZGVJRCk7XG4gIHZhciBjb250YWluZXIgPSBSZWFjdE1vdW50LmZpbmRSZWFjdENvbnRhaW5lckZvcklEKHJvb3RJRCk7XG4gIHZhciBwYXJlbnQgPSBSZWFjdE1vdW50LmdldEZpcnN0UmVhY3RET00oY29udGFpbmVyKTtcbiAgcmV0dXJuIHBhcmVudDtcbn1cblxuLy8gVXNlZCB0byBzdG9yZSBhbmNlc3RvciBoaWVyYXJjaHkgaW4gdG9wIGxldmVsIGNhbGxiYWNrXG5mdW5jdGlvbiBUb3BMZXZlbENhbGxiYWNrQm9va0tlZXBpbmcodG9wTGV2ZWxUeXBlLCBuYXRpdmVFdmVudCkge1xuICB0aGlzLnRvcExldmVsVHlwZSA9IHRvcExldmVsVHlwZTtcbiAgdGhpcy5uYXRpdmVFdmVudCA9IG5hdGl2ZUV2ZW50O1xuICB0aGlzLmFuY2VzdG9ycyA9IFtdO1xufVxuYXNzaWduKFRvcExldmVsQ2FsbGJhY2tCb29rS2VlcGluZy5wcm90b3R5cGUsIHtcbiAgZGVzdHJ1Y3RvcjogZnVuY3Rpb24oKSB7XG4gICAgdGhpcy50b3BMZXZlbFR5cGUgPSBudWxsO1xuICAgIHRoaXMubmF0aXZlRXZlbnQgPSBudWxsO1xuICAgIHRoaXMuYW5jZXN0b3JzLmxlbmd0aCA9IDA7XG4gIH1cbn0pO1xuUG9vbGVkQ2xhc3MuYWRkUG9vbGluZ1RvKFxuICBUb3BMZXZlbENhbGxiYWNrQm9va0tlZXBpbmcsXG4gIFBvb2xlZENsYXNzLnR3b0FyZ3VtZW50UG9vbGVyXG4pO1xuXG5mdW5jdGlvbiBoYW5kbGVUb3BMZXZlbEltcGwoYm9va0tlZXBpbmcpIHtcbiAgdmFyIHRvcExldmVsVGFyZ2V0ID0gUmVhY3RNb3VudC5nZXRGaXJzdFJlYWN0RE9NKFxuICAgIGdldEV2ZW50VGFyZ2V0KGJvb2tLZWVwaW5nLm5hdGl2ZUV2ZW50KVxuICApIHx8IHdpbmRvdztcblxuICAvLyBMb29wIHRocm91Z2ggdGhlIGhpZXJhcmNoeSwgaW4gY2FzZSB0aGVyZSdzIGFueSBuZXN0ZWQgY29tcG9uZW50cy5cbiAgLy8gSXQncyBpbXBvcnRhbnQgdGhhdCB3ZSBidWlsZCB0aGUgYXJyYXkgb2YgYW5jZXN0b3JzIGJlZm9yZSBjYWxsaW5nIGFueVxuICAvLyBldmVudCBoYW5kbGVycywgYmVjYXVzZSBldmVudCBoYW5kbGVycyBjYW4gbW9kaWZ5IHRoZSBET00sIGxlYWRpbmcgdG9cbiAgLy8gaW5jb25zaXN0ZW5jaWVzIHdpdGggUmVhY3RNb3VudCdzIG5vZGUgY2FjaGUuIFNlZSAjMTEwNS5cbiAgdmFyIGFuY2VzdG9yID0gdG9wTGV2ZWxUYXJnZXQ7XG4gIHdoaWxlIChhbmNlc3Rvcikge1xuICAgIGJvb2tLZWVwaW5nLmFuY2VzdG9ycy5wdXNoKGFuY2VzdG9yKTtcbiAgICBhbmNlc3RvciA9IGZpbmRQYXJlbnQoYW5jZXN0b3IpO1xuICB9XG5cbiAgZm9yICh2YXIgaSA9IDAsIGwgPSBib29rS2VlcGluZy5hbmNlc3RvcnMubGVuZ3RoOyBpIDwgbDsgaSsrKSB7XG4gICAgdG9wTGV2ZWxUYXJnZXQgPSBib29rS2VlcGluZy5hbmNlc3RvcnNbaV07XG4gICAgdmFyIHRvcExldmVsVGFyZ2V0SUQgPSBSZWFjdE1vdW50LmdldElEKHRvcExldmVsVGFyZ2V0KSB8fCAnJztcbiAgICBSZWFjdEV2ZW50TGlzdGVuZXIuX2hhbmRsZVRvcExldmVsKFxuICAgICAgYm9va0tlZXBpbmcudG9wTGV2ZWxUeXBlLFxuICAgICAgdG9wTGV2ZWxUYXJnZXQsXG4gICAgICB0b3BMZXZlbFRhcmdldElELFxuICAgICAgYm9va0tlZXBpbmcubmF0aXZlRXZlbnRcbiAgICApO1xuICB9XG59XG5cbmZ1bmN0aW9uIHNjcm9sbFZhbHVlTW9uaXRvcihjYikge1xuICB2YXIgc2Nyb2xsUG9zaXRpb24gPSBnZXRVbmJvdW5kZWRTY3JvbGxQb3NpdGlvbih3aW5kb3cpO1xuICBjYihzY3JvbGxQb3NpdGlvbik7XG59XG5cbnZhciBSZWFjdEV2ZW50TGlzdGVuZXIgPSB7XG4gIF9lbmFibGVkOiB0cnVlLFxuICBfaGFuZGxlVG9wTGV2ZWw6IG51bGwsXG5cbiAgV0lORE9XX0hBTkRMRTogRXhlY3V0aW9uRW52aXJvbm1lbnQuY2FuVXNlRE9NID8gd2luZG93IDogbnVsbCxcblxuICBzZXRIYW5kbGVUb3BMZXZlbDogZnVuY3Rpb24oaGFuZGxlVG9wTGV2ZWwpIHtcbiAgICBSZWFjdEV2ZW50TGlzdGVuZXIuX2hhbmRsZVRvcExldmVsID0gaGFuZGxlVG9wTGV2ZWw7XG4gIH0sXG5cbiAgc2V0RW5hYmxlZDogZnVuY3Rpb24oZW5hYmxlZCkge1xuICAgIFJlYWN0RXZlbnRMaXN0ZW5lci5fZW5hYmxlZCA9ICEhZW5hYmxlZDtcbiAgfSxcblxuICBpc0VuYWJsZWQ6IGZ1bmN0aW9uKCkge1xuICAgIHJldHVybiBSZWFjdEV2ZW50TGlzdGVuZXIuX2VuYWJsZWQ7XG4gIH0sXG5cblxuICAvKipcbiAgICogVHJhcHMgdG9wLWxldmVsIGV2ZW50cyBieSB1c2luZyBldmVudCBidWJibGluZy5cbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IHRvcExldmVsVHlwZSBSZWNvcmQgZnJvbSBgRXZlbnRDb25zdGFudHNgLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gaGFuZGxlckJhc2VOYW1lIEV2ZW50IG5hbWUgKGUuZy4gXCJjbGlja1wiKS5cbiAgICogQHBhcmFtIHtvYmplY3R9IGhhbmRsZSBFbGVtZW50IG9uIHdoaWNoIHRvIGF0dGFjaCBsaXN0ZW5lci5cbiAgICogQHJldHVybiB7b2JqZWN0fSBBbiBvYmplY3Qgd2l0aCBhIHJlbW92ZSBmdW5jdGlvbiB3aGljaCB3aWxsIGZvcmNlZnVsbHlcbiAgICogICAgICAgICAgICAgICAgICByZW1vdmUgdGhlIGxpc3RlbmVyLlxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIHRyYXBCdWJibGVkRXZlbnQ6IGZ1bmN0aW9uKHRvcExldmVsVHlwZSwgaGFuZGxlckJhc2VOYW1lLCBoYW5kbGUpIHtcbiAgICB2YXIgZWxlbWVudCA9IGhhbmRsZTtcbiAgICBpZiAoIWVsZW1lbnQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgcmV0dXJuIEV2ZW50TGlzdGVuZXIubGlzdGVuKFxuICAgICAgZWxlbWVudCxcbiAgICAgIGhhbmRsZXJCYXNlTmFtZSxcbiAgICAgIFJlYWN0RXZlbnRMaXN0ZW5lci5kaXNwYXRjaEV2ZW50LmJpbmQobnVsbCwgdG9wTGV2ZWxUeXBlKVxuICAgICk7XG4gIH0sXG5cbiAgLyoqXG4gICAqIFRyYXBzIGEgdG9wLWxldmVsIGV2ZW50IGJ5IHVzaW5nIGV2ZW50IGNhcHR1cmluZy5cbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IHRvcExldmVsVHlwZSBSZWNvcmQgZnJvbSBgRXZlbnRDb25zdGFudHNgLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gaGFuZGxlckJhc2VOYW1lIEV2ZW50IG5hbWUgKGUuZy4gXCJjbGlja1wiKS5cbiAgICogQHBhcmFtIHtvYmplY3R9IGhhbmRsZSBFbGVtZW50IG9uIHdoaWNoIHRvIGF0dGFjaCBsaXN0ZW5lci5cbiAgICogQHJldHVybiB7b2JqZWN0fSBBbiBvYmplY3Qgd2l0aCBhIHJlbW92ZSBmdW5jdGlvbiB3aGljaCB3aWxsIGZvcmNlZnVsbHlcbiAgICogICAgICAgICAgICAgICAgICByZW1vdmUgdGhlIGxpc3RlbmVyLlxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIHRyYXBDYXB0dXJlZEV2ZW50OiBmdW5jdGlvbih0b3BMZXZlbFR5cGUsIGhhbmRsZXJCYXNlTmFtZSwgaGFuZGxlKSB7XG4gICAgdmFyIGVsZW1lbnQgPSBoYW5kbGU7XG4gICAgaWYgKCFlbGVtZW50KSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHJldHVybiBFdmVudExpc3RlbmVyLmNhcHR1cmUoXG4gICAgICBlbGVtZW50LFxuICAgICAgaGFuZGxlckJhc2VOYW1lLFxuICAgICAgUmVhY3RFdmVudExpc3RlbmVyLmRpc3BhdGNoRXZlbnQuYmluZChudWxsLCB0b3BMZXZlbFR5cGUpXG4gICAgKTtcbiAgfSxcblxuICBtb25pdG9yU2Nyb2xsVmFsdWU6IGZ1bmN0aW9uKHJlZnJlc2gpIHtcbiAgICB2YXIgY2FsbGJhY2sgPSBzY3JvbGxWYWx1ZU1vbml0b3IuYmluZChudWxsLCByZWZyZXNoKTtcbiAgICBFdmVudExpc3RlbmVyLmxpc3Rlbih3aW5kb3csICdzY3JvbGwnLCBjYWxsYmFjayk7XG4gICAgRXZlbnRMaXN0ZW5lci5saXN0ZW4od2luZG93LCAncmVzaXplJywgY2FsbGJhY2spO1xuICB9LFxuXG4gIGRpc3BhdGNoRXZlbnQ6IGZ1bmN0aW9uKHRvcExldmVsVHlwZSwgbmF0aXZlRXZlbnQpIHtcbiAgICBpZiAoIVJlYWN0RXZlbnRMaXN0ZW5lci5fZW5hYmxlZCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHZhciBib29rS2VlcGluZyA9IFRvcExldmVsQ2FsbGJhY2tCb29rS2VlcGluZy5nZXRQb29sZWQoXG4gICAgICB0b3BMZXZlbFR5cGUsXG4gICAgICBuYXRpdmVFdmVudFxuICAgICk7XG4gICAgdHJ5IHtcbiAgICAgIC8vIEV2ZW50IHF1ZXVlIGJlaW5nIHByb2Nlc3NlZCBpbiB0aGUgc2FtZSBjeWNsZSBhbGxvd3NcbiAgICAgIC8vIGBwcmV2ZW50RGVmYXVsdGAuXG4gICAgICBSZWFjdFVwZGF0ZXMuYmF0Y2hlZFVwZGF0ZXMoaGFuZGxlVG9wTGV2ZWxJbXBsLCBib29rS2VlcGluZyk7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIFRvcExldmVsQ2FsbGJhY2tCb29rS2VlcGluZy5yZWxlYXNlKGJvb2tLZWVwaW5nKTtcbiAgICB9XG4gIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gUmVhY3RFdmVudExpc3RlbmVyO1xuIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIFJlYWN0SW5qZWN0aW9uXG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBET01Qcm9wZXJ0eSA9IHJlcXVpcmUoXCIuL0RPTVByb3BlcnR5XCIpO1xudmFyIEV2ZW50UGx1Z2luSHViID0gcmVxdWlyZShcIi4vRXZlbnRQbHVnaW5IdWJcIik7XG52YXIgUmVhY3RDb21wb25lbnQgPSByZXF1aXJlKFwiLi9SZWFjdENvbXBvbmVudFwiKTtcbnZhciBSZWFjdENvbXBvc2l0ZUNvbXBvbmVudCA9IHJlcXVpcmUoXCIuL1JlYWN0Q29tcG9zaXRlQ29tcG9uZW50XCIpO1xudmFyIFJlYWN0RW1wdHlDb21wb25lbnQgPSByZXF1aXJlKFwiLi9SZWFjdEVtcHR5Q29tcG9uZW50XCIpO1xudmFyIFJlYWN0QnJvd3NlckV2ZW50RW1pdHRlciA9IHJlcXVpcmUoXCIuL1JlYWN0QnJvd3NlckV2ZW50RW1pdHRlclwiKTtcbnZhciBSZWFjdE5hdGl2ZUNvbXBvbmVudCA9IHJlcXVpcmUoXCIuL1JlYWN0TmF0aXZlQ29tcG9uZW50XCIpO1xudmFyIFJlYWN0UGVyZiA9IHJlcXVpcmUoXCIuL1JlYWN0UGVyZlwiKTtcbnZhciBSZWFjdFJvb3RJbmRleCA9IHJlcXVpcmUoXCIuL1JlYWN0Um9vdEluZGV4XCIpO1xudmFyIFJlYWN0VXBkYXRlcyA9IHJlcXVpcmUoXCIuL1JlYWN0VXBkYXRlc1wiKTtcblxudmFyIFJlYWN0SW5qZWN0aW9uID0ge1xuICBDb21wb25lbnQ6IFJlYWN0Q29tcG9uZW50LmluamVjdGlvbixcbiAgQ29tcG9zaXRlQ29tcG9uZW50OiBSZWFjdENvbXBvc2l0ZUNvbXBvbmVudC5pbmplY3Rpb24sXG4gIERPTVByb3BlcnR5OiBET01Qcm9wZXJ0eS5pbmplY3Rpb24sXG4gIEVtcHR5Q29tcG9uZW50OiBSZWFjdEVtcHR5Q29tcG9uZW50LmluamVjdGlvbixcbiAgRXZlbnRQbHVnaW5IdWI6IEV2ZW50UGx1Z2luSHViLmluamVjdGlvbixcbiAgRXZlbnRFbWl0dGVyOiBSZWFjdEJyb3dzZXJFdmVudEVtaXR0ZXIuaW5qZWN0aW9uLFxuICBOYXRpdmVDb21wb25lbnQ6IFJlYWN0TmF0aXZlQ29tcG9uZW50LmluamVjdGlvbixcbiAgUGVyZjogUmVhY3RQZXJmLmluamVjdGlvbixcbiAgUm9vdEluZGV4OiBSZWFjdFJvb3RJbmRleC5pbmplY3Rpb24sXG4gIFVwZGF0ZXM6IFJlYWN0VXBkYXRlcy5pbmplY3Rpb25cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gUmVhY3RJbmplY3Rpb247XG4iLCIvKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgUmVhY3RJbnB1dFNlbGVjdGlvblxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgUmVhY3RET01TZWxlY3Rpb24gPSByZXF1aXJlKFwiLi9SZWFjdERPTVNlbGVjdGlvblwiKTtcblxudmFyIGNvbnRhaW5zTm9kZSA9IHJlcXVpcmUoXCIuL2NvbnRhaW5zTm9kZVwiKTtcbnZhciBmb2N1c05vZGUgPSByZXF1aXJlKFwiLi9mb2N1c05vZGVcIik7XG52YXIgZ2V0QWN0aXZlRWxlbWVudCA9IHJlcXVpcmUoXCIuL2dldEFjdGl2ZUVsZW1lbnRcIik7XG5cbmZ1bmN0aW9uIGlzSW5Eb2N1bWVudChub2RlKSB7XG4gIHJldHVybiBjb250YWluc05vZGUoZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LCBub2RlKTtcbn1cblxuLyoqXG4gKiBAUmVhY3RJbnB1dFNlbGVjdGlvbjogUmVhY3QgaW5wdXQgc2VsZWN0aW9uIG1vZHVsZS4gQmFzZWQgb24gU2VsZWN0aW9uLmpzLFxuICogYnV0IG1vZGlmaWVkIHRvIGJlIHN1aXRhYmxlIGZvciByZWFjdCBhbmQgaGFzIGEgY291cGxlIG9mIGJ1ZyBmaXhlcyAoZG9lc24ndFxuICogYXNzdW1lIGJ1dHRvbnMgaGF2ZSByYW5nZSBzZWxlY3Rpb25zIGFsbG93ZWQpLlxuICogSW5wdXQgc2VsZWN0aW9uIG1vZHVsZSBmb3IgUmVhY3QuXG4gKi9cbnZhciBSZWFjdElucHV0U2VsZWN0aW9uID0ge1xuXG4gIGhhc1NlbGVjdGlvbkNhcGFiaWxpdGllczogZnVuY3Rpb24oZWxlbSkge1xuICAgIHJldHVybiBlbGVtICYmIChcbiAgICAgIChlbGVtLm5vZGVOYW1lID09PSAnSU5QVVQnICYmIGVsZW0udHlwZSA9PT0gJ3RleHQnKSB8fFxuICAgICAgZWxlbS5ub2RlTmFtZSA9PT0gJ1RFWFRBUkVBJyB8fFxuICAgICAgZWxlbS5jb250ZW50RWRpdGFibGUgPT09ICd0cnVlJ1xuICAgICk7XG4gIH0sXG5cbiAgZ2V0U2VsZWN0aW9uSW5mb3JtYXRpb246IGZ1bmN0aW9uKCkge1xuICAgIHZhciBmb2N1c2VkRWxlbSA9IGdldEFjdGl2ZUVsZW1lbnQoKTtcbiAgICByZXR1cm4ge1xuICAgICAgZm9jdXNlZEVsZW06IGZvY3VzZWRFbGVtLFxuICAgICAgc2VsZWN0aW9uUmFuZ2U6XG4gICAgICAgICAgUmVhY3RJbnB1dFNlbGVjdGlvbi5oYXNTZWxlY3Rpb25DYXBhYmlsaXRpZXMoZm9jdXNlZEVsZW0pID9cbiAgICAgICAgICBSZWFjdElucHV0U2VsZWN0aW9uLmdldFNlbGVjdGlvbihmb2N1c2VkRWxlbSkgOlxuICAgICAgICAgIG51bGxcbiAgICB9O1xuICB9LFxuXG4gIC8qKlxuICAgKiBAcmVzdG9yZVNlbGVjdGlvbjogSWYgYW55IHNlbGVjdGlvbiBpbmZvcm1hdGlvbiB3YXMgcG90ZW50aWFsbHkgbG9zdCxcbiAgICogcmVzdG9yZSBpdC4gVGhpcyBpcyB1c2VmdWwgd2hlbiBwZXJmb3JtaW5nIG9wZXJhdGlvbnMgdGhhdCBjb3VsZCByZW1vdmUgZG9tXG4gICAqIG5vZGVzIGFuZCBwbGFjZSB0aGVtIGJhY2sgaW4sIHJlc3VsdGluZyBpbiBmb2N1cyBiZWluZyBsb3N0LlxuICAgKi9cbiAgcmVzdG9yZVNlbGVjdGlvbjogZnVuY3Rpb24ocHJpb3JTZWxlY3Rpb25JbmZvcm1hdGlvbikge1xuICAgIHZhciBjdXJGb2N1c2VkRWxlbSA9IGdldEFjdGl2ZUVsZW1lbnQoKTtcbiAgICB2YXIgcHJpb3JGb2N1c2VkRWxlbSA9IHByaW9yU2VsZWN0aW9uSW5mb3JtYXRpb24uZm9jdXNlZEVsZW07XG4gICAgdmFyIHByaW9yU2VsZWN0aW9uUmFuZ2UgPSBwcmlvclNlbGVjdGlvbkluZm9ybWF0aW9uLnNlbGVjdGlvblJhbmdlO1xuICAgIGlmIChjdXJGb2N1c2VkRWxlbSAhPT0gcHJpb3JGb2N1c2VkRWxlbSAmJlxuICAgICAgICBpc0luRG9jdW1lbnQocHJpb3JGb2N1c2VkRWxlbSkpIHtcbiAgICAgIGlmIChSZWFjdElucHV0U2VsZWN0aW9uLmhhc1NlbGVjdGlvbkNhcGFiaWxpdGllcyhwcmlvckZvY3VzZWRFbGVtKSkge1xuICAgICAgICBSZWFjdElucHV0U2VsZWN0aW9uLnNldFNlbGVjdGlvbihcbiAgICAgICAgICBwcmlvckZvY3VzZWRFbGVtLFxuICAgICAgICAgIHByaW9yU2VsZWN0aW9uUmFuZ2VcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICAgIGZvY3VzTm9kZShwcmlvckZvY3VzZWRFbGVtKTtcbiAgICB9XG4gIH0sXG5cbiAgLyoqXG4gICAqIEBnZXRTZWxlY3Rpb246IEdldHMgdGhlIHNlbGVjdGlvbiBib3VuZHMgb2YgYSBmb2N1c2VkIHRleHRhcmVhLCBpbnB1dCBvclxuICAgKiBjb250ZW50RWRpdGFibGUgbm9kZS5cbiAgICogLUBpbnB1dDogTG9vayB1cCBzZWxlY3Rpb24gYm91bmRzIG9mIHRoaXMgaW5wdXRcbiAgICogLUByZXR1cm4ge3N0YXJ0OiBzZWxlY3Rpb25TdGFydCwgZW5kOiBzZWxlY3Rpb25FbmR9XG4gICAqL1xuICBnZXRTZWxlY3Rpb246IGZ1bmN0aW9uKGlucHV0KSB7XG4gICAgdmFyIHNlbGVjdGlvbjtcblxuICAgIGlmICgnc2VsZWN0aW9uU3RhcnQnIGluIGlucHV0KSB7XG4gICAgICAvLyBNb2Rlcm4gYnJvd3NlciB3aXRoIGlucHV0IG9yIHRleHRhcmVhLlxuICAgICAgc2VsZWN0aW9uID0ge1xuICAgICAgICBzdGFydDogaW5wdXQuc2VsZWN0aW9uU3RhcnQsXG4gICAgICAgIGVuZDogaW5wdXQuc2VsZWN0aW9uRW5kXG4gICAgICB9O1xuICAgIH0gZWxzZSBpZiAoZG9jdW1lbnQuc2VsZWN0aW9uICYmIGlucHV0Lm5vZGVOYW1lID09PSAnSU5QVVQnKSB7XG4gICAgICAvLyBJRTggaW5wdXQuXG4gICAgICB2YXIgcmFuZ2UgPSBkb2N1bWVudC5zZWxlY3Rpb24uY3JlYXRlUmFuZ2UoKTtcbiAgICAgIC8vIFRoZXJlIGNhbiBvbmx5IGJlIG9uZSBzZWxlY3Rpb24gcGVyIGRvY3VtZW50IGluIElFLCBzbyBpdCBtdXN0XG4gICAgICAvLyBiZSBpbiBvdXIgZWxlbWVudC5cbiAgICAgIGlmIChyYW5nZS5wYXJlbnRFbGVtZW50KCkgPT09IGlucHV0KSB7XG4gICAgICAgIHNlbGVjdGlvbiA9IHtcbiAgICAgICAgICBzdGFydDogLXJhbmdlLm1vdmVTdGFydCgnY2hhcmFjdGVyJywgLWlucHV0LnZhbHVlLmxlbmd0aCksXG4gICAgICAgICAgZW5kOiAtcmFuZ2UubW92ZUVuZCgnY2hhcmFjdGVyJywgLWlucHV0LnZhbHVlLmxlbmd0aClcbiAgICAgICAgfTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgLy8gQ29udGVudCBlZGl0YWJsZSBvciBvbGQgSUUgdGV4dGFyZWEuXG4gICAgICBzZWxlY3Rpb24gPSBSZWFjdERPTVNlbGVjdGlvbi5nZXRPZmZzZXRzKGlucHV0KTtcbiAgICB9XG5cbiAgICByZXR1cm4gc2VsZWN0aW9uIHx8IHtzdGFydDogMCwgZW5kOiAwfTtcbiAgfSxcblxuICAvKipcbiAgICogQHNldFNlbGVjdGlvbjogU2V0cyB0aGUgc2VsZWN0aW9uIGJvdW5kcyBvZiBhIHRleHRhcmVhIG9yIGlucHV0IGFuZCBmb2N1c2VzXG4gICAqIHRoZSBpbnB1dC5cbiAgICogLUBpbnB1dCAgICAgU2V0IHNlbGVjdGlvbiBib3VuZHMgb2YgdGhpcyBpbnB1dCBvciB0ZXh0YXJlYVxuICAgKiAtQG9mZnNldHMgICBPYmplY3Qgb2Ygc2FtZSBmb3JtIHRoYXQgaXMgcmV0dXJuZWQgZnJvbSBnZXQqXG4gICAqL1xuICBzZXRTZWxlY3Rpb246IGZ1bmN0aW9uKGlucHV0LCBvZmZzZXRzKSB7XG4gICAgdmFyIHN0YXJ0ID0gb2Zmc2V0cy5zdGFydDtcbiAgICB2YXIgZW5kID0gb2Zmc2V0cy5lbmQ7XG4gICAgaWYgKHR5cGVvZiBlbmQgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICBlbmQgPSBzdGFydDtcbiAgICB9XG5cbiAgICBpZiAoJ3NlbGVjdGlvblN0YXJ0JyBpbiBpbnB1dCkge1xuICAgICAgaW5wdXQuc2VsZWN0aW9uU3RhcnQgPSBzdGFydDtcbiAgICAgIGlucHV0LnNlbGVjdGlvbkVuZCA9IE1hdGgubWluKGVuZCwgaW5wdXQudmFsdWUubGVuZ3RoKTtcbiAgICB9IGVsc2UgaWYgKGRvY3VtZW50LnNlbGVjdGlvbiAmJiBpbnB1dC5ub2RlTmFtZSA9PT0gJ0lOUFVUJykge1xuICAgICAgdmFyIHJhbmdlID0gaW5wdXQuY3JlYXRlVGV4dFJhbmdlKCk7XG4gICAgICByYW5nZS5jb2xsYXBzZSh0cnVlKTtcbiAgICAgIHJhbmdlLm1vdmVTdGFydCgnY2hhcmFjdGVyJywgc3RhcnQpO1xuICAgICAgcmFuZ2UubW92ZUVuZCgnY2hhcmFjdGVyJywgZW5kIC0gc3RhcnQpO1xuICAgICAgcmFuZ2Uuc2VsZWN0KCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIFJlYWN0RE9NU2VsZWN0aW9uLnNldE9mZnNldHMoaW5wdXQsIG9mZnNldHMpO1xuICAgIH1cbiAgfVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBSZWFjdElucHV0U2VsZWN0aW9uO1xuIiwiKGZ1bmN0aW9uIChwcm9jZXNzKXtcbi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBSZWFjdEluc3RhbmNlSGFuZGxlc1xuICogQHR5cGVjaGVja3Mgc3RhdGljLW9ubHlcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIFJlYWN0Um9vdEluZGV4ID0gcmVxdWlyZShcIi4vUmVhY3RSb290SW5kZXhcIik7XG5cbnZhciBpbnZhcmlhbnQgPSByZXF1aXJlKFwiLi9pbnZhcmlhbnRcIik7XG5cbnZhciBTRVBBUkFUT1IgPSAnLic7XG52YXIgU0VQQVJBVE9SX0xFTkdUSCA9IFNFUEFSQVRPUi5sZW5ndGg7XG5cbi8qKlxuICogTWF4aW11bSBkZXB0aCBvZiB0cmF2ZXJzYWxzIGJlZm9yZSB3ZSBjb25zaWRlciB0aGUgcG9zc2liaWxpdHkgb2YgYSBiYWQgSUQuXG4gKi9cbnZhciBNQVhfVFJFRV9ERVBUSCA9IDEwMDtcblxuLyoqXG4gKiBDcmVhdGVzIGEgRE9NIElEIHByZWZpeCB0byB1c2Ugd2hlbiBtb3VudGluZyBSZWFjdCBjb21wb25lbnRzLlxuICpcbiAqIEBwYXJhbSB7bnVtYmVyfSBpbmRleCBBIHVuaXF1ZSBpbnRlZ2VyXG4gKiBAcmV0dXJuIHtzdHJpbmd9IFJlYWN0IHJvb3QgSUQuXG4gKiBAaW50ZXJuYWxcbiAqL1xuZnVuY3Rpb24gZ2V0UmVhY3RSb290SURTdHJpbmcoaW5kZXgpIHtcbiAgcmV0dXJuIFNFUEFSQVRPUiArIGluZGV4LnRvU3RyaW5nKDM2KTtcbn1cblxuLyoqXG4gKiBDaGVja3MgaWYgYSBjaGFyYWN0ZXIgaW4gdGhlIHN1cHBsaWVkIElEIGlzIGEgc2VwYXJhdG9yIG9yIHRoZSBlbmQuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IGlkIEEgUmVhY3QgRE9NIElELlxuICogQHBhcmFtIHtudW1iZXJ9IGluZGV4IEluZGV4IG9mIHRoZSBjaGFyYWN0ZXIgdG8gY2hlY2suXG4gKiBAcmV0dXJuIHtib29sZWFufSBUcnVlIGlmIHRoZSBjaGFyYWN0ZXIgaXMgYSBzZXBhcmF0b3Igb3IgZW5kIG9mIHRoZSBJRC5cbiAqIEBwcml2YXRlXG4gKi9cbmZ1bmN0aW9uIGlzQm91bmRhcnkoaWQsIGluZGV4KSB7XG4gIHJldHVybiBpZC5jaGFyQXQoaW5kZXgpID09PSBTRVBBUkFUT1IgfHwgaW5kZXggPT09IGlkLmxlbmd0aDtcbn1cblxuLyoqXG4gKiBDaGVja3MgaWYgdGhlIHN1cHBsaWVkIHN0cmluZyBpcyBhIHZhbGlkIFJlYWN0IERPTSBJRC5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gaWQgQSBSZWFjdCBET00gSUQsIG1heWJlLlxuICogQHJldHVybiB7Ym9vbGVhbn0gVHJ1ZSBpZiB0aGUgc3RyaW5nIGlzIGEgdmFsaWQgUmVhY3QgRE9NIElELlxuICogQHByaXZhdGVcbiAqL1xuZnVuY3Rpb24gaXNWYWxpZElEKGlkKSB7XG4gIHJldHVybiBpZCA9PT0gJycgfHwgKFxuICAgIGlkLmNoYXJBdCgwKSA9PT0gU0VQQVJBVE9SICYmIGlkLmNoYXJBdChpZC5sZW5ndGggLSAxKSAhPT0gU0VQQVJBVE9SXG4gICk7XG59XG5cbi8qKlxuICogQ2hlY2tzIGlmIHRoZSBmaXJzdCBJRCBpcyBhbiBhbmNlc3RvciBvZiBvciBlcXVhbCB0byB0aGUgc2Vjb25kIElELlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBhbmNlc3RvcklEXG4gKiBAcGFyYW0ge3N0cmluZ30gZGVzY2VuZGFudElEXG4gKiBAcmV0dXJuIHtib29sZWFufSBUcnVlIGlmIGBhbmNlc3RvcklEYCBpcyBhbiBhbmNlc3RvciBvZiBgZGVzY2VuZGFudElEYC5cbiAqIEBpbnRlcm5hbFxuICovXG5mdW5jdGlvbiBpc0FuY2VzdG9ySURPZihhbmNlc3RvcklELCBkZXNjZW5kYW50SUQpIHtcbiAgcmV0dXJuIChcbiAgICBkZXNjZW5kYW50SUQuaW5kZXhPZihhbmNlc3RvcklEKSA9PT0gMCAmJlxuICAgIGlzQm91bmRhcnkoZGVzY2VuZGFudElELCBhbmNlc3RvcklELmxlbmd0aClcbiAgKTtcbn1cblxuLyoqXG4gKiBHZXRzIHRoZSBwYXJlbnQgSUQgb2YgdGhlIHN1cHBsaWVkIFJlYWN0IERPTSBJRCwgYGlkYC5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gaWQgSUQgb2YgYSBjb21wb25lbnQuXG4gKiBAcmV0dXJuIHtzdHJpbmd9IElEIG9mIHRoZSBwYXJlbnQsIG9yIGFuIGVtcHR5IHN0cmluZy5cbiAqIEBwcml2YXRlXG4gKi9cbmZ1bmN0aW9uIGdldFBhcmVudElEKGlkKSB7XG4gIHJldHVybiBpZCA/IGlkLnN1YnN0cigwLCBpZC5sYXN0SW5kZXhPZihTRVBBUkFUT1IpKSA6ICcnO1xufVxuXG4vKipcbiAqIEdldHMgdGhlIG5leHQgRE9NIElEIG9uIHRoZSB0cmVlIHBhdGggZnJvbSB0aGUgc3VwcGxpZWQgYGFuY2VzdG9ySURgIHRvIHRoZVxuICogc3VwcGxpZWQgYGRlc3RpbmF0aW9uSURgLiBJZiB0aGV5IGFyZSBlcXVhbCwgdGhlIElEIGlzIHJldHVybmVkLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBhbmNlc3RvcklEIElEIG9mIGFuIGFuY2VzdG9yIG5vZGUgb2YgYGRlc3RpbmF0aW9uSURgLlxuICogQHBhcmFtIHtzdHJpbmd9IGRlc3RpbmF0aW9uSUQgSUQgb2YgdGhlIGRlc3RpbmF0aW9uIG5vZGUuXG4gKiBAcmV0dXJuIHtzdHJpbmd9IE5leHQgSUQgb24gdGhlIHBhdGggZnJvbSBgYW5jZXN0b3JJRGAgdG8gYGRlc3RpbmF0aW9uSURgLlxuICogQHByaXZhdGVcbiAqL1xuZnVuY3Rpb24gZ2V0TmV4dERlc2NlbmRhbnRJRChhbmNlc3RvcklELCBkZXN0aW5hdGlvbklEKSB7XG4gIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgaXNWYWxpZElEKGFuY2VzdG9ySUQpICYmIGlzVmFsaWRJRChkZXN0aW5hdGlvbklEKSxcbiAgICAnZ2V0TmV4dERlc2NlbmRhbnRJRCglcywgJXMpOiBSZWNlaXZlZCBhbiBpbnZhbGlkIFJlYWN0IERPTSBJRC4nLFxuICAgIGFuY2VzdG9ySUQsXG4gICAgZGVzdGluYXRpb25JRFxuICApIDogaW52YXJpYW50KGlzVmFsaWRJRChhbmNlc3RvcklEKSAmJiBpc1ZhbGlkSUQoZGVzdGluYXRpb25JRCkpKTtcbiAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICBpc0FuY2VzdG9ySURPZihhbmNlc3RvcklELCBkZXN0aW5hdGlvbklEKSxcbiAgICAnZ2V0TmV4dERlc2NlbmRhbnRJRCguLi4pOiBSZWFjdCBoYXMgbWFkZSBhbiBpbnZhbGlkIGFzc3VtcHRpb24gYWJvdXQgJyArXG4gICAgJ3RoZSBET00gaGllcmFyY2h5LiBFeHBlY3RlZCBgJXNgIHRvIGJlIGFuIGFuY2VzdG9yIG9mIGAlc2AuJyxcbiAgICBhbmNlc3RvcklELFxuICAgIGRlc3RpbmF0aW9uSURcbiAgKSA6IGludmFyaWFudChpc0FuY2VzdG9ySURPZihhbmNlc3RvcklELCBkZXN0aW5hdGlvbklEKSkpO1xuICBpZiAoYW5jZXN0b3JJRCA9PT0gZGVzdGluYXRpb25JRCkge1xuICAgIHJldHVybiBhbmNlc3RvcklEO1xuICB9XG4gIC8vIFNraXAgb3ZlciB0aGUgYW5jZXN0b3IgYW5kIHRoZSBpbW1lZGlhdGUgc2VwYXJhdG9yLiBUcmF2ZXJzZSB1bnRpbCB3ZSBoaXRcbiAgLy8gYW5vdGhlciBzZXBhcmF0b3Igb3Igd2UgcmVhY2ggdGhlIGVuZCBvZiBgZGVzdGluYXRpb25JRGAuXG4gIHZhciBzdGFydCA9IGFuY2VzdG9ySUQubGVuZ3RoICsgU0VQQVJBVE9SX0xFTkdUSDtcbiAgZm9yICh2YXIgaSA9IHN0YXJ0OyBpIDwgZGVzdGluYXRpb25JRC5sZW5ndGg7IGkrKykge1xuICAgIGlmIChpc0JvdW5kYXJ5KGRlc3RpbmF0aW9uSUQsIGkpKSB7XG4gICAgICBicmVhaztcbiAgICB9XG4gIH1cbiAgcmV0dXJuIGRlc3RpbmF0aW9uSUQuc3Vic3RyKDAsIGkpO1xufVxuXG4vKipcbiAqIEdldHMgdGhlIG5lYXJlc3QgY29tbW9uIGFuY2VzdG9yIElEIG9mIHR3byBJRHMuXG4gKlxuICogVXNpbmcgdGhpcyBJRCBzY2hlbWUsIHRoZSBuZWFyZXN0IGNvbW1vbiBhbmNlc3RvciBJRCBpcyB0aGUgbG9uZ2VzdCBjb21tb25cbiAqIHByZWZpeCBvZiB0aGUgdHdvIElEcyB0aGF0IGltbWVkaWF0ZWx5IHByZWNlZGVkIGEgXCJtYXJrZXJcIiBpbiBib3RoIHN0cmluZ3MuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IG9uZUlEXG4gKiBAcGFyYW0ge3N0cmluZ30gdHdvSURcbiAqIEByZXR1cm4ge3N0cmluZ30gTmVhcmVzdCBjb21tb24gYW5jZXN0b3IgSUQsIG9yIHRoZSBlbXB0eSBzdHJpbmcgaWYgbm9uZS5cbiAqIEBwcml2YXRlXG4gKi9cbmZ1bmN0aW9uIGdldEZpcnN0Q29tbW9uQW5jZXN0b3JJRChvbmVJRCwgdHdvSUQpIHtcbiAgdmFyIG1pbkxlbmd0aCA9IE1hdGgubWluKG9uZUlELmxlbmd0aCwgdHdvSUQubGVuZ3RoKTtcbiAgaWYgKG1pbkxlbmd0aCA9PT0gMCkge1xuICAgIHJldHVybiAnJztcbiAgfVxuICB2YXIgbGFzdENvbW1vbk1hcmtlckluZGV4ID0gMDtcbiAgLy8gVXNlIGA8PWAgdG8gdHJhdmVyc2UgdW50aWwgdGhlIFwiRU9MXCIgb2YgdGhlIHNob3J0ZXIgc3RyaW5nLlxuICBmb3IgKHZhciBpID0gMDsgaSA8PSBtaW5MZW5ndGg7IGkrKykge1xuICAgIGlmIChpc0JvdW5kYXJ5KG9uZUlELCBpKSAmJiBpc0JvdW5kYXJ5KHR3b0lELCBpKSkge1xuICAgICAgbGFzdENvbW1vbk1hcmtlckluZGV4ID0gaTtcbiAgICB9IGVsc2UgaWYgKG9uZUlELmNoYXJBdChpKSAhPT0gdHdvSUQuY2hhckF0KGkpKSB7XG4gICAgICBicmVhaztcbiAgICB9XG4gIH1cbiAgdmFyIGxvbmdlc3RDb21tb25JRCA9IG9uZUlELnN1YnN0cigwLCBsYXN0Q29tbW9uTWFya2VySW5kZXgpO1xuICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgIGlzVmFsaWRJRChsb25nZXN0Q29tbW9uSUQpLFxuICAgICdnZXRGaXJzdENvbW1vbkFuY2VzdG9ySUQoJXMsICVzKTogRXhwZWN0ZWQgYSB2YWxpZCBSZWFjdCBET00gSUQ6ICVzJyxcbiAgICBvbmVJRCxcbiAgICB0d29JRCxcbiAgICBsb25nZXN0Q29tbW9uSURcbiAgKSA6IGludmFyaWFudChpc1ZhbGlkSUQobG9uZ2VzdENvbW1vbklEKSkpO1xuICByZXR1cm4gbG9uZ2VzdENvbW1vbklEO1xufVxuXG4vKipcbiAqIFRyYXZlcnNlcyB0aGUgcGFyZW50IHBhdGggYmV0d2VlbiB0d28gSURzIChlaXRoZXIgdXAgb3IgZG93bikuIFRoZSBJRHMgbXVzdFxuICogbm90IGJlIHRoZSBzYW1lLCBhbmQgdGhlcmUgbXVzdCBleGlzdCBhIHBhcmVudCBwYXRoIGJldHdlZW4gdGhlbS4gSWYgdGhlXG4gKiBjYWxsYmFjayByZXR1cm5zIGBmYWxzZWAsIHRyYXZlcnNhbCBpcyBzdG9wcGVkLlxuICpcbiAqIEBwYXJhbSB7P3N0cmluZ30gc3RhcnQgSUQgYXQgd2hpY2ggdG8gc3RhcnQgdHJhdmVyc2FsLlxuICogQHBhcmFtIHs/c3RyaW5nfSBzdG9wIElEIGF0IHdoaWNoIHRvIGVuZCB0cmF2ZXJzYWwuXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSBjYiBDYWxsYmFjayB0byBpbnZva2UgZWFjaCBJRCB3aXRoLlxuICogQHBhcmFtIHs/Ym9vbGVhbn0gc2tpcEZpcnN0IFdoZXRoZXIgb3Igbm90IHRvIHNraXAgdGhlIGZpcnN0IG5vZGUuXG4gKiBAcGFyYW0gez9ib29sZWFufSBza2lwTGFzdCBXaGV0aGVyIG9yIG5vdCB0byBza2lwIHRoZSBsYXN0IG5vZGUuXG4gKiBAcHJpdmF0ZVxuICovXG5mdW5jdGlvbiB0cmF2ZXJzZVBhcmVudFBhdGgoc3RhcnQsIHN0b3AsIGNiLCBhcmcsIHNraXBGaXJzdCwgc2tpcExhc3QpIHtcbiAgc3RhcnQgPSBzdGFydCB8fCAnJztcbiAgc3RvcCA9IHN0b3AgfHwgJyc7XG4gIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgc3RhcnQgIT09IHN0b3AsXG4gICAgJ3RyYXZlcnNlUGFyZW50UGF0aCguLi4pOiBDYW5ub3QgdHJhdmVyc2UgZnJvbSBhbmQgdG8gdGhlIHNhbWUgSUQsIGAlc2AuJyxcbiAgICBzdGFydFxuICApIDogaW52YXJpYW50KHN0YXJ0ICE9PSBzdG9wKSk7XG4gIHZhciB0cmF2ZXJzZVVwID0gaXNBbmNlc3RvcklET2Yoc3RvcCwgc3RhcnQpO1xuICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgIHRyYXZlcnNlVXAgfHwgaXNBbmNlc3RvcklET2Yoc3RhcnQsIHN0b3ApLFxuICAgICd0cmF2ZXJzZVBhcmVudFBhdGgoJXMsICVzLCAuLi4pOiBDYW5ub3QgdHJhdmVyc2UgZnJvbSB0d28gSURzIHRoYXQgZG8gJyArXG4gICAgJ25vdCBoYXZlIGEgcGFyZW50IHBhdGguJyxcbiAgICBzdGFydCxcbiAgICBzdG9wXG4gICkgOiBpbnZhcmlhbnQodHJhdmVyc2VVcCB8fCBpc0FuY2VzdG9ySURPZihzdGFydCwgc3RvcCkpKTtcbiAgLy8gVHJhdmVyc2UgZnJvbSBgc3RhcnRgIHRvIGBzdG9wYCBvbmUgZGVwdGggYXQgYSB0aW1lLlxuICB2YXIgZGVwdGggPSAwO1xuICB2YXIgdHJhdmVyc2UgPSB0cmF2ZXJzZVVwID8gZ2V0UGFyZW50SUQgOiBnZXROZXh0RGVzY2VuZGFudElEO1xuICBmb3IgKHZhciBpZCA9IHN0YXJ0OyAvKiB1bnRpbCBicmVhayAqLzsgaWQgPSB0cmF2ZXJzZShpZCwgc3RvcCkpIHtcbiAgICB2YXIgcmV0O1xuICAgIGlmICgoIXNraXBGaXJzdCB8fCBpZCAhPT0gc3RhcnQpICYmICghc2tpcExhc3QgfHwgaWQgIT09IHN0b3ApKSB7XG4gICAgICByZXQgPSBjYihpZCwgdHJhdmVyc2VVcCwgYXJnKTtcbiAgICB9XG4gICAgaWYgKHJldCA9PT0gZmFsc2UgfHwgaWQgPT09IHN0b3ApIHtcbiAgICAgIC8vIE9ubHkgYnJlYWsgLy9hZnRlci8vIHZpc2l0aW5nIGBzdG9wYC5cbiAgICAgIGJyZWFrO1xuICAgIH1cbiAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgZGVwdGgrKyA8IE1BWF9UUkVFX0RFUFRILFxuICAgICAgJ3RyYXZlcnNlUGFyZW50UGF0aCglcywgJXMsIC4uLik6IERldGVjdGVkIGFuIGluZmluaXRlIGxvb3Agd2hpbGUgJyArXG4gICAgICAndHJhdmVyc2luZyB0aGUgUmVhY3QgRE9NIElEIHRyZWUuIFRoaXMgbWF5IGJlIGR1ZSB0byBtYWxmb3JtZWQgSURzOiAlcycsXG4gICAgICBzdGFydCwgc3RvcFxuICAgICkgOiBpbnZhcmlhbnQoZGVwdGgrKyA8IE1BWF9UUkVFX0RFUFRIKSk7XG4gIH1cbn1cblxuLyoqXG4gKiBNYW5hZ2VzIHRoZSBJRHMgYXNzaWduZWQgdG8gRE9NIHJlcHJlc2VudGF0aW9ucyBvZiBSZWFjdCBjb21wb25lbnRzLiBUaGlzXG4gKiB1c2VzIGEgc3BlY2lmaWMgc2NoZW1lIGluIG9yZGVyIHRvIHRyYXZlcnNlIHRoZSBET00gZWZmaWNpZW50bHkgKGUuZy4gaW5cbiAqIG9yZGVyIHRvIHNpbXVsYXRlIGV2ZW50cykuXG4gKlxuICogQGludGVybmFsXG4gKi9cbnZhciBSZWFjdEluc3RhbmNlSGFuZGxlcyA9IHtcblxuICAvKipcbiAgICogQ29uc3RydWN0cyBhIFJlYWN0IHJvb3QgSURcbiAgICogQHJldHVybiB7c3RyaW5nfSBBIFJlYWN0IHJvb3QgSUQuXG4gICAqL1xuICBjcmVhdGVSZWFjdFJvb3RJRDogZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIGdldFJlYWN0Um9vdElEU3RyaW5nKFJlYWN0Um9vdEluZGV4LmNyZWF0ZVJlYWN0Um9vdEluZGV4KCkpO1xuICB9LFxuXG4gIC8qKlxuICAgKiBDb25zdHJ1Y3RzIGEgUmVhY3QgSUQgYnkgam9pbmluZyBhIHJvb3QgSUQgd2l0aCBhIG5hbWUuXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSByb290SUQgUm9vdCBJRCBvZiBhIHBhcmVudCBjb21wb25lbnQuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lIEEgY29tcG9uZW50J3MgbmFtZSAoYXMgZmxhdHRlbmVkIGNoaWxkcmVuKS5cbiAgICogQHJldHVybiB7c3RyaW5nfSBBIFJlYWN0IElELlxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIGNyZWF0ZVJlYWN0SUQ6IGZ1bmN0aW9uKHJvb3RJRCwgbmFtZSkge1xuICAgIHJldHVybiByb290SUQgKyBuYW1lO1xuICB9LFxuXG4gIC8qKlxuICAgKiBHZXRzIHRoZSBET00gSUQgb2YgdGhlIFJlYWN0IGNvbXBvbmVudCB0aGF0IGlzIHRoZSByb290IG9mIHRoZSB0cmVlIHRoYXRcbiAgICogY29udGFpbnMgdGhlIFJlYWN0IGNvbXBvbmVudCB3aXRoIHRoZSBzdXBwbGllZCBET00gSUQuXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBpZCBET00gSUQgb2YgYSBSZWFjdCBjb21wb25lbnQuXG4gICAqIEByZXR1cm4gez9zdHJpbmd9IERPTSBJRCBvZiB0aGUgUmVhY3QgY29tcG9uZW50IHRoYXQgaXMgdGhlIHJvb3QuXG4gICAqIEBpbnRlcm5hbFxuICAgKi9cbiAgZ2V0UmVhY3RSb290SURGcm9tTm9kZUlEOiBmdW5jdGlvbihpZCkge1xuICAgIGlmIChpZCAmJiBpZC5jaGFyQXQoMCkgPT09IFNFUEFSQVRPUiAmJiBpZC5sZW5ndGggPiAxKSB7XG4gICAgICB2YXIgaW5kZXggPSBpZC5pbmRleE9mKFNFUEFSQVRPUiwgMSk7XG4gICAgICByZXR1cm4gaW5kZXggPiAtMSA/IGlkLnN1YnN0cigwLCBpbmRleCkgOiBpZDtcbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG4gIH0sXG5cbiAgLyoqXG4gICAqIFRyYXZlcnNlcyB0aGUgSUQgaGllcmFyY2h5IGFuZCBpbnZva2VzIHRoZSBzdXBwbGllZCBgY2JgIG9uIGFueSBJRHMgdGhhdFxuICAgKiBzaG91bGQgd291bGQgcmVjZWl2ZSBhIGBtb3VzZUVudGVyYCBvciBgbW91c2VMZWF2ZWAgZXZlbnQuXG4gICAqXG4gICAqIE5PVEU6IERvZXMgbm90IGludm9rZSB0aGUgY2FsbGJhY2sgb24gdGhlIG5lYXJlc3QgY29tbW9uIGFuY2VzdG9yIGJlY2F1c2VcbiAgICogbm90aGluZyBcImVudGVyZWRcIiBvciBcImxlZnRcIiB0aGF0IGVsZW1lbnQuXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBsZWF2ZUlEIElEIGJlaW5nIGxlZnQuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBlbnRlcklEIElEIGJlaW5nIGVudGVyZWQuXG4gICAqIEBwYXJhbSB7ZnVuY3Rpb259IGNiIENhbGxiYWNrIHRvIGludm9rZSBvbiBlYWNoIGVudGVyZWQvbGVmdCBJRC5cbiAgICogQHBhcmFtIHsqfSB1cEFyZyBBcmd1bWVudCB0byBpbnZva2UgdGhlIGNhbGxiYWNrIHdpdGggb24gbGVmdCBJRHMuXG4gICAqIEBwYXJhbSB7Kn0gZG93bkFyZyBBcmd1bWVudCB0byBpbnZva2UgdGhlIGNhbGxiYWNrIHdpdGggb24gZW50ZXJlZCBJRHMuXG4gICAqIEBpbnRlcm5hbFxuICAgKi9cbiAgdHJhdmVyc2VFbnRlckxlYXZlOiBmdW5jdGlvbihsZWF2ZUlELCBlbnRlcklELCBjYiwgdXBBcmcsIGRvd25BcmcpIHtcbiAgICB2YXIgYW5jZXN0b3JJRCA9IGdldEZpcnN0Q29tbW9uQW5jZXN0b3JJRChsZWF2ZUlELCBlbnRlcklEKTtcbiAgICBpZiAoYW5jZXN0b3JJRCAhPT0gbGVhdmVJRCkge1xuICAgICAgdHJhdmVyc2VQYXJlbnRQYXRoKGxlYXZlSUQsIGFuY2VzdG9ySUQsIGNiLCB1cEFyZywgZmFsc2UsIHRydWUpO1xuICAgIH1cbiAgICBpZiAoYW5jZXN0b3JJRCAhPT0gZW50ZXJJRCkge1xuICAgICAgdHJhdmVyc2VQYXJlbnRQYXRoKGFuY2VzdG9ySUQsIGVudGVySUQsIGNiLCBkb3duQXJnLCB0cnVlLCBmYWxzZSk7XG4gICAgfVxuICB9LFxuXG4gIC8qKlxuICAgKiBTaW11bGF0ZXMgdGhlIHRyYXZlcnNhbCBvZiBhIHR3by1waGFzZSwgY2FwdHVyZS9idWJibGUgZXZlbnQgZGlzcGF0Y2guXG4gICAqXG4gICAqIE5PVEU6IFRoaXMgdHJhdmVyc2FsIGhhcHBlbnMgb24gSURzIHdpdGhvdXQgdG91Y2hpbmcgdGhlIERPTS5cbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IHRhcmdldElEIElEIG9mIHRoZSB0YXJnZXQgbm9kZS5cbiAgICogQHBhcmFtIHtmdW5jdGlvbn0gY2IgQ2FsbGJhY2sgdG8gaW52b2tlLlxuICAgKiBAcGFyYW0geyp9IGFyZyBBcmd1bWVudCB0byBpbnZva2UgdGhlIGNhbGxiYWNrIHdpdGguXG4gICAqIEBpbnRlcm5hbFxuICAgKi9cbiAgdHJhdmVyc2VUd29QaGFzZTogZnVuY3Rpb24odGFyZ2V0SUQsIGNiLCBhcmcpIHtcbiAgICBpZiAodGFyZ2V0SUQpIHtcbiAgICAgIHRyYXZlcnNlUGFyZW50UGF0aCgnJywgdGFyZ2V0SUQsIGNiLCBhcmcsIHRydWUsIGZhbHNlKTtcbiAgICAgIHRyYXZlcnNlUGFyZW50UGF0aCh0YXJnZXRJRCwgJycsIGNiLCBhcmcsIGZhbHNlLCB0cnVlKTtcbiAgICB9XG4gIH0sXG5cbiAgLyoqXG4gICAqIFRyYXZlcnNlIGEgbm9kZSBJRCwgY2FsbGluZyB0aGUgc3VwcGxpZWQgYGNiYCBmb3IgZWFjaCBhbmNlc3RvciBJRC4gRm9yXG4gICAqIGV4YW1wbGUsIHBhc3NpbmcgYC4wLiRyb3ctMC4xYCB3b3VsZCByZXN1bHQgaW4gYGNiYCBnZXR0aW5nIGNhbGxlZFxuICAgKiB3aXRoIGAuMGAsIGAuMC4kcm93LTBgLCBhbmQgYC4wLiRyb3ctMC4xYC5cbiAgICpcbiAgICogTk9URTogVGhpcyB0cmF2ZXJzYWwgaGFwcGVucyBvbiBJRHMgd2l0aG91dCB0b3VjaGluZyB0aGUgRE9NLlxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gdGFyZ2V0SUQgSUQgb2YgdGhlIHRhcmdldCBub2RlLlxuICAgKiBAcGFyYW0ge2Z1bmN0aW9ufSBjYiBDYWxsYmFjayB0byBpbnZva2UuXG4gICAqIEBwYXJhbSB7Kn0gYXJnIEFyZ3VtZW50IHRvIGludm9rZSB0aGUgY2FsbGJhY2sgd2l0aC5cbiAgICogQGludGVybmFsXG4gICAqL1xuICB0cmF2ZXJzZUFuY2VzdG9yczogZnVuY3Rpb24odGFyZ2V0SUQsIGNiLCBhcmcpIHtcbiAgICB0cmF2ZXJzZVBhcmVudFBhdGgoJycsIHRhcmdldElELCBjYiwgYXJnLCB0cnVlLCBmYWxzZSk7XG4gIH0sXG5cbiAgLyoqXG4gICAqIEV4cG9zZWQgZm9yIHVuaXQgdGVzdGluZy5cbiAgICogQHByaXZhdGVcbiAgICovXG4gIF9nZXRGaXJzdENvbW1vbkFuY2VzdG9ySUQ6IGdldEZpcnN0Q29tbW9uQW5jZXN0b3JJRCxcblxuICAvKipcbiAgICogRXhwb3NlZCBmb3IgdW5pdCB0ZXN0aW5nLlxuICAgKiBAcHJpdmF0ZVxuICAgKi9cbiAgX2dldE5leHREZXNjZW5kYW50SUQ6IGdldE5leHREZXNjZW5kYW50SUQsXG5cbiAgaXNBbmNlc3RvcklET2Y6IGlzQW5jZXN0b3JJRE9mLFxuXG4gIFNFUEFSQVRPUjogU0VQQVJBVE9SXG5cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gUmVhY3RJbnN0YW5jZUhhbmRsZXM7XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKCdfcHJvY2VzcycpKSIsIihmdW5jdGlvbiAocHJvY2Vzcyl7XG4vKipcbiAqIENvcHlyaWdodCAyMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIFJlYWN0TGVnYWN5RWxlbWVudFxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgUmVhY3RDdXJyZW50T3duZXIgPSByZXF1aXJlKFwiLi9SZWFjdEN1cnJlbnRPd25lclwiKTtcblxudmFyIGludmFyaWFudCA9IHJlcXVpcmUoXCIuL2ludmFyaWFudFwiKTtcbnZhciBtb25pdG9yQ29kZVVzZSA9IHJlcXVpcmUoXCIuL21vbml0b3JDb2RlVXNlXCIpO1xudmFyIHdhcm5pbmcgPSByZXF1aXJlKFwiLi93YXJuaW5nXCIpO1xuXG52YXIgbGVnYWN5RmFjdG9yeUxvZ3MgPSB7fTtcbmZ1bmN0aW9uIHdhcm5Gb3JMZWdhY3lGYWN0b3J5Q2FsbCgpIHtcbiAgaWYgKCFSZWFjdExlZ2FjeUVsZW1lbnRGYWN0b3J5Ll9pc0xlZ2FjeUNhbGxXYXJuaW5nRW5hYmxlZCkge1xuICAgIHJldHVybjtcbiAgfVxuICB2YXIgb3duZXIgPSBSZWFjdEN1cnJlbnRPd25lci5jdXJyZW50O1xuICB2YXIgbmFtZSA9IG93bmVyICYmIG93bmVyLmNvbnN0cnVjdG9yID8gb3duZXIuY29uc3RydWN0b3IuZGlzcGxheU5hbWUgOiAnJztcbiAgaWYgKCFuYW1lKSB7XG4gICAgbmFtZSA9ICdTb21ldGhpbmcnO1xuICB9XG4gIGlmIChsZWdhY3lGYWN0b3J5TG9ncy5oYXNPd25Qcm9wZXJ0eShuYW1lKSkge1xuICAgIHJldHVybjtcbiAgfVxuICBsZWdhY3lGYWN0b3J5TG9nc1tuYW1lXSA9IHRydWU7XG4gIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyB3YXJuaW5nKFxuICAgIGZhbHNlLFxuICAgIG5hbWUgKyAnIGlzIGNhbGxpbmcgYSBSZWFjdCBjb21wb25lbnQgZGlyZWN0bHkuICcgK1xuICAgICdVc2UgYSBmYWN0b3J5IG9yIEpTWCBpbnN0ZWFkLiBTZWU6IGh0dHA6Ly9mYi5tZS9yZWFjdC1sZWdhY3lmYWN0b3J5J1xuICApIDogbnVsbCk7XG4gIG1vbml0b3JDb2RlVXNlKCdyZWFjdF9sZWdhY3lfZmFjdG9yeV9jYWxsJywgeyB2ZXJzaW9uOiAzLCBuYW1lOiBuYW1lIH0pO1xufVxuXG5mdW5jdGlvbiB3YXJuRm9yUGxhaW5GdW5jdGlvblR5cGUodHlwZSkge1xuICB2YXIgaXNSZWFjdENsYXNzID1cbiAgICB0eXBlLnByb3RvdHlwZSAmJlxuICAgIHR5cGVvZiB0eXBlLnByb3RvdHlwZS5tb3VudENvbXBvbmVudCA9PT0gJ2Z1bmN0aW9uJyAmJlxuICAgIHR5cGVvZiB0eXBlLnByb3RvdHlwZS5yZWNlaXZlQ29tcG9uZW50ID09PSAnZnVuY3Rpb24nO1xuICBpZiAoaXNSZWFjdENsYXNzKSB7XG4gICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IHdhcm5pbmcoXG4gICAgICBmYWxzZSxcbiAgICAgICdEaWQgbm90IGV4cGVjdCB0byBnZXQgYSBSZWFjdCBjbGFzcyBoZXJlLiBVc2UgYENvbXBvbmVudGAgaW5zdGVhZCAnICtcbiAgICAgICdvZiBgQ29tcG9uZW50LnR5cGVgIG9yIGB0aGlzLmNvbnN0cnVjdG9yYC4nXG4gICAgKSA6IG51bGwpO1xuICB9IGVsc2Uge1xuICAgIGlmICghdHlwZS5fcmVhY3RXYXJuZWRGb3JUaGlzVHlwZSkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgdHlwZS5fcmVhY3RXYXJuZWRGb3JUaGlzVHlwZSA9IHRydWU7XG4gICAgICB9IGNhdGNoICh4KSB7XG4gICAgICAgIC8vIGp1c3QgaW5jYXNlIHRoaXMgaXMgYSBmcm96ZW4gb2JqZWN0IG9yIHNvbWUgc3BlY2lhbCBvYmplY3RcbiAgICAgIH1cbiAgICAgIG1vbml0b3JDb2RlVXNlKFxuICAgICAgICAncmVhY3Rfbm9uX2NvbXBvbmVudF9pbl9qc3gnLFxuICAgICAgICB7IHZlcnNpb246IDMsIG5hbWU6IHR5cGUubmFtZSB9XG4gICAgICApO1xuICAgIH1cbiAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gd2FybmluZyhcbiAgICAgIGZhbHNlLFxuICAgICAgJ1RoaXMgSlNYIHVzZXMgYSBwbGFpbiBmdW5jdGlvbi4gT25seSBSZWFjdCBjb21wb25lbnRzIGFyZSAnICtcbiAgICAgICd2YWxpZCBpbiBSZWFjdFxcJ3MgSlNYIHRyYW5zZm9ybS4nXG4gICAgKSA6IG51bGwpO1xuICB9XG59XG5cbmZ1bmN0aW9uIHdhcm5Gb3JOb25MZWdhY3lGYWN0b3J5KHR5cGUpIHtcbiAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IHdhcm5pbmcoXG4gICAgZmFsc2UsXG4gICAgJ0RvIG5vdCBwYXNzIFJlYWN0LkRPTS4nICsgdHlwZS50eXBlICsgJyB0byBKU1ggb3IgY3JlYXRlRmFjdG9yeS4gJyArXG4gICAgJ1VzZSB0aGUgc3RyaW5nIFwiJyArIHR5cGUudHlwZSArICdcIiBpbnN0ZWFkLidcbiAgKSA6IG51bGwpO1xufVxuXG4vKipcbiAqIFRyYW5zZmVyIHN0YXRpYyBwcm9wZXJ0aWVzIGZyb20gdGhlIHNvdXJjZSB0byB0aGUgdGFyZ2V0LiBGdW5jdGlvbnMgYXJlXG4gKiByZWJvdW5kIHRvIGhhdmUgdGhpcyByZWZsZWN0IHRoZSBvcmlnaW5hbCBzb3VyY2UuXG4gKi9cbmZ1bmN0aW9uIHByb3h5U3RhdGljTWV0aG9kcyh0YXJnZXQsIHNvdXJjZSkge1xuICBpZiAodHlwZW9mIHNvdXJjZSAhPT0gJ2Z1bmN0aW9uJykge1xuICAgIHJldHVybjtcbiAgfVxuICBmb3IgKHZhciBrZXkgaW4gc291cmNlKSB7XG4gICAgaWYgKHNvdXJjZS5oYXNPd25Qcm9wZXJ0eShrZXkpKSB7XG4gICAgICB2YXIgdmFsdWUgPSBzb3VyY2Vba2V5XTtcbiAgICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgdmFyIGJvdW5kID0gdmFsdWUuYmluZChzb3VyY2UpO1xuICAgICAgICAvLyBDb3B5IGFueSBwcm9wZXJ0aWVzIGRlZmluZWQgb24gdGhlIGZ1bmN0aW9uLCBzdWNoIGFzIGBpc1JlcXVpcmVkYCBvblxuICAgICAgICAvLyBhIFByb3BUeXBlcyB2YWxpZGF0b3IuXG4gICAgICAgIGZvciAodmFyIGsgaW4gdmFsdWUpIHtcbiAgICAgICAgICBpZiAodmFsdWUuaGFzT3duUHJvcGVydHkoaykpIHtcbiAgICAgICAgICAgIGJvdW5kW2tdID0gdmFsdWVba107XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHRhcmdldFtrZXldID0gYm91bmQ7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0YXJnZXRba2V5XSA9IHZhbHVlO1xuICAgICAgfVxuICAgIH1cbiAgfVxufVxuXG4vLyBXZSB1c2UgYW4gb2JqZWN0IGluc3RlYWQgb2YgYSBib29sZWFuIGJlY2F1c2UgYm9vbGVhbnMgYXJlIGlnbm9yZWQgYnkgb3VyXG4vLyBtb2NraW5nIGxpYnJhcmllcyB3aGVuIHRoZXNlIGZhY3RvcmllcyBnZXRzIG1vY2tlZC5cbnZhciBMRUdBQ1lfTUFSS0VSID0ge307XG52YXIgTk9OX0xFR0FDWV9NQVJLRVIgPSB7fTtcblxudmFyIFJlYWN0TGVnYWN5RWxlbWVudEZhY3RvcnkgPSB7fTtcblxuUmVhY3RMZWdhY3lFbGVtZW50RmFjdG9yeS53cmFwQ3JlYXRlRmFjdG9yeSA9IGZ1bmN0aW9uKGNyZWF0ZUZhY3RvcnkpIHtcbiAgdmFyIGxlZ2FjeUNyZWF0ZUZhY3RvcnkgPSBmdW5jdGlvbih0eXBlKSB7XG4gICAgaWYgKHR5cGVvZiB0eXBlICE9PSAnZnVuY3Rpb24nKSB7XG4gICAgICAvLyBOb24tZnVuY3Rpb24gdHlwZXMgY2Fubm90IGJlIGxlZ2FjeSBmYWN0b3JpZXNcbiAgICAgIHJldHVybiBjcmVhdGVGYWN0b3J5KHR5cGUpO1xuICAgIH1cblxuICAgIGlmICh0eXBlLmlzUmVhY3ROb25MZWdhY3lGYWN0b3J5KSB7XG4gICAgICAvLyBUaGlzIGlzIHByb2JhYmx5IGEgZmFjdG9yeSBjcmVhdGVkIGJ5IFJlYWN0RE9NIHdlIHVud3JhcCBpdCB0byBnZXQgdG9cbiAgICAgIC8vIHRoZSB1bmRlcmx5aW5nIHN0cmluZyB0eXBlLiBJdCBzaG91bGRuJ3QgaGF2ZSBiZWVuIHBhc3NlZCBoZXJlIHNvIHdlXG4gICAgICAvLyB3YXJuLlxuICAgICAgaWYgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOVikge1xuICAgICAgICB3YXJuRm9yTm9uTGVnYWN5RmFjdG9yeSh0eXBlKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBjcmVhdGVGYWN0b3J5KHR5cGUudHlwZSk7XG4gICAgfVxuXG4gICAgaWYgKHR5cGUuaXNSZWFjdExlZ2FjeUZhY3RvcnkpIHtcbiAgICAgIC8vIFRoaXMgaXMgcHJvYmFibHkgYSBsZWdhY3kgZmFjdG9yeSBjcmVhdGVkIGJ5IFJlYWN0Q29tcG9zaXRlQ29tcG9uZW50LlxuICAgICAgLy8gV2UgdW53cmFwIGl0IHRvIGdldCB0byB0aGUgdW5kZXJseWluZyBjbGFzcy5cbiAgICAgIHJldHVybiBjcmVhdGVGYWN0b3J5KHR5cGUudHlwZSk7XG4gICAgfVxuXG4gICAgaWYgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOVikge1xuICAgICAgd2FybkZvclBsYWluRnVuY3Rpb25UeXBlKHR5cGUpO1xuICAgIH1cblxuICAgIC8vIFVubGVzcyBpdCdzIGEgbGVnYWN5IGZhY3RvcnksIHRoZW4gdGhpcyBpcyBwcm9iYWJseSBhIHBsYWluIGZ1bmN0aW9uLFxuICAgIC8vIHRoYXQgaXMgZXhwZWN0aW5nIHRvIGJlIGludm9rZWQgYnkgSlNYLiBXZSBjYW4ganVzdCByZXR1cm4gaXQgYXMgaXMuXG4gICAgcmV0dXJuIHR5cGU7XG4gIH07XG4gIHJldHVybiBsZWdhY3lDcmVhdGVGYWN0b3J5O1xufTtcblxuUmVhY3RMZWdhY3lFbGVtZW50RmFjdG9yeS53cmFwQ3JlYXRlRWxlbWVudCA9IGZ1bmN0aW9uKGNyZWF0ZUVsZW1lbnQpIHtcbiAgdmFyIGxlZ2FjeUNyZWF0ZUVsZW1lbnQgPSBmdW5jdGlvbih0eXBlLCBwcm9wcywgY2hpbGRyZW4pIHtcbiAgICBpZiAodHlwZW9mIHR5cGUgIT09ICdmdW5jdGlvbicpIHtcbiAgICAgIC8vIE5vbi1mdW5jdGlvbiB0eXBlcyBjYW5ub3QgYmUgbGVnYWN5IGZhY3Rvcmllc1xuICAgICAgcmV0dXJuIGNyZWF0ZUVsZW1lbnQuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICB9XG5cbiAgICB2YXIgYXJncztcblxuICAgIGlmICh0eXBlLmlzUmVhY3ROb25MZWdhY3lGYWN0b3J5KSB7XG4gICAgICAvLyBUaGlzIGlzIHByb2JhYmx5IGEgZmFjdG9yeSBjcmVhdGVkIGJ5IFJlYWN0RE9NIHdlIHVud3JhcCBpdCB0byBnZXQgdG9cbiAgICAgIC8vIHRoZSB1bmRlcmx5aW5nIHN0cmluZyB0eXBlLiBJdCBzaG91bGRuJ3QgaGF2ZSBiZWVuIHBhc3NlZCBoZXJlIHNvIHdlXG4gICAgICAvLyB3YXJuLlxuICAgICAgaWYgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOVikge1xuICAgICAgICB3YXJuRm9yTm9uTGVnYWN5RmFjdG9yeSh0eXBlKTtcbiAgICAgIH1cbiAgICAgIGFyZ3MgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsIDApO1xuICAgICAgYXJnc1swXSA9IHR5cGUudHlwZTtcbiAgICAgIHJldHVybiBjcmVhdGVFbGVtZW50LmFwcGx5KHRoaXMsIGFyZ3MpO1xuICAgIH1cblxuICAgIGlmICh0eXBlLmlzUmVhY3RMZWdhY3lGYWN0b3J5KSB7XG4gICAgICAvLyBUaGlzIGlzIHByb2JhYmx5IGEgbGVnYWN5IGZhY3RvcnkgY3JlYXRlZCBieSBSZWFjdENvbXBvc2l0ZUNvbXBvbmVudC5cbiAgICAgIC8vIFdlIHVud3JhcCBpdCB0byBnZXQgdG8gdGhlIHVuZGVybHlpbmcgY2xhc3MuXG4gICAgICBpZiAodHlwZS5faXNNb2NrRnVuY3Rpb24pIHtcbiAgICAgICAgLy8gSWYgdGhpcyBpcyBhIG1vY2sgZnVuY3Rpb24sIHBlb3BsZSB3aWxsIGV4cGVjdCBpdCB0byBiZSBjYWxsZWQuIFdlXG4gICAgICAgIC8vIHdpbGwgYWN0dWFsbHkgY2FsbCB0aGUgb3JpZ2luYWwgbW9jayBmYWN0b3J5IGZ1bmN0aW9uIGluc3RlYWQuIFRoaXNcbiAgICAgICAgLy8gZnV0dXJlIHByb29mcyB1bml0IHRlc3RpbmcgdGhhdCBhc3N1bWUgdGhhdCB0aGVzZSBhcmUgY2xhc3Nlcy5cbiAgICAgICAgdHlwZS50eXBlLl9tb2NrZWRSZWFjdENsYXNzQ29uc3RydWN0b3IgPSB0eXBlO1xuICAgICAgfVxuICAgICAgYXJncyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cywgMCk7XG4gICAgICBhcmdzWzBdID0gdHlwZS50eXBlO1xuICAgICAgcmV0dXJuIGNyZWF0ZUVsZW1lbnQuYXBwbHkodGhpcywgYXJncyk7XG4gICAgfVxuXG4gICAgaWYgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOVikge1xuICAgICAgd2FybkZvclBsYWluRnVuY3Rpb25UeXBlKHR5cGUpO1xuICAgIH1cblxuICAgIC8vIFRoaXMgaXMgYmVpbmcgY2FsbGVkIHdpdGggYSBwbGFpbiBmdW5jdGlvbiB3ZSBzaG91bGQgaW52b2tlIGl0XG4gICAgLy8gaW1tZWRpYXRlbHkgYXMgaWYgdGhpcyB3YXMgdXNlZCB3aXRoIGxlZ2FjeSBKU1guXG4gICAgcmV0dXJuIHR5cGUuYXBwbHkobnVsbCwgQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKSk7XG4gIH07XG4gIHJldHVybiBsZWdhY3lDcmVhdGVFbGVtZW50O1xufTtcblxuUmVhY3RMZWdhY3lFbGVtZW50RmFjdG9yeS53cmFwRmFjdG9yeSA9IGZ1bmN0aW9uKGZhY3RvcnkpIHtcbiAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICB0eXBlb2YgZmFjdG9yeSA9PT0gJ2Z1bmN0aW9uJyxcbiAgICAnVGhpcyBpcyBzdXBwb3NlIHRvIGFjY2VwdCBhIGVsZW1lbnQgZmFjdG9yeSdcbiAgKSA6IGludmFyaWFudCh0eXBlb2YgZmFjdG9yeSA9PT0gJ2Z1bmN0aW9uJykpO1xuICB2YXIgbGVnYWN5RWxlbWVudEZhY3RvcnkgPSBmdW5jdGlvbihjb25maWcsIGNoaWxkcmVuKSB7XG4gICAgLy8gVGhpcyBmYWN0b3J5IHNob3VsZCBub3QgYmUgY2FsbGVkIHdoZW4gSlNYIGlzIHVzZWQuIFVzZSBKU1ggaW5zdGVhZC5cbiAgICBpZiAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WKSB7XG4gICAgICB3YXJuRm9yTGVnYWN5RmFjdG9yeUNhbGwoKTtcbiAgICB9XG4gICAgcmV0dXJuIGZhY3RvcnkuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgfTtcbiAgcHJveHlTdGF0aWNNZXRob2RzKGxlZ2FjeUVsZW1lbnRGYWN0b3J5LCBmYWN0b3J5LnR5cGUpO1xuICBsZWdhY3lFbGVtZW50RmFjdG9yeS5pc1JlYWN0TGVnYWN5RmFjdG9yeSA9IExFR0FDWV9NQVJLRVI7XG4gIGxlZ2FjeUVsZW1lbnRGYWN0b3J5LnR5cGUgPSBmYWN0b3J5LnR5cGU7XG4gIHJldHVybiBsZWdhY3lFbGVtZW50RmFjdG9yeTtcbn07XG5cbi8vIFRoaXMgaXMgdXNlZCB0byBtYXJrIGEgZmFjdG9yeSB0aGF0IHdpbGwgcmVtYWluLiBFLmcuIHdlJ3JlIGFsbG93ZWQgdG8gY2FsbFxuLy8gaXQgYXMgYSBmdW5jdGlvbi4gSG93ZXZlciwgeW91J3JlIG5vdCBzdXBwb3NlIHRvIHBhc3MgaXQgdG8gY3JlYXRlRWxlbWVudFxuLy8gb3IgY3JlYXRlRmFjdG9yeSwgc28gaXQgd2lsbCB3YXJuIHlvdSBpZiB5b3UgZG8uXG5SZWFjdExlZ2FjeUVsZW1lbnRGYWN0b3J5Lm1hcmtOb25MZWdhY3lGYWN0b3J5ID0gZnVuY3Rpb24oZmFjdG9yeSkge1xuICBmYWN0b3J5LmlzUmVhY3ROb25MZWdhY3lGYWN0b3J5ID0gTk9OX0xFR0FDWV9NQVJLRVI7XG4gIHJldHVybiBmYWN0b3J5O1xufTtcblxuLy8gQ2hlY2tzIGlmIGEgZmFjdG9yeSBmdW5jdGlvbiBpcyBhY3R1YWxseSBhIGxlZ2FjeSBmYWN0b3J5IHByZXRlbmRpbmcgdG9cbi8vIGJlIGEgY2xhc3MuXG5SZWFjdExlZ2FjeUVsZW1lbnRGYWN0b3J5LmlzVmFsaWRGYWN0b3J5ID0gZnVuY3Rpb24oZmFjdG9yeSkge1xuICAvLyBUT0RPOiBUaGlzIHdpbGwgYmUgcmVtb3ZlZCBhbmQgbW92ZWQgaW50byBhIGNsYXNzIHZhbGlkYXRvciBvciBzb21ldGhpbmcuXG4gIHJldHVybiB0eXBlb2YgZmFjdG9yeSA9PT0gJ2Z1bmN0aW9uJyAmJlxuICAgIGZhY3RvcnkuaXNSZWFjdExlZ2FjeUZhY3RvcnkgPT09IExFR0FDWV9NQVJLRVI7XG59O1xuXG5SZWFjdExlZ2FjeUVsZW1lbnRGYWN0b3J5LmlzVmFsaWRDbGFzcyA9IGZ1bmN0aW9uKGZhY3RvcnkpIHtcbiAgaWYgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOVikge1xuICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyB3YXJuaW5nKFxuICAgICAgZmFsc2UsXG4gICAgICAnaXNWYWxpZENsYXNzIGlzIGRlcHJlY2F0ZWQgYW5kIHdpbGwgYmUgcmVtb3ZlZCBpbiBhIGZ1dHVyZSByZWxlYXNlLiAnICtcbiAgICAgICdVc2UgYSBtb3JlIHNwZWNpZmljIHZhbGlkYXRvciBpbnN0ZWFkLidcbiAgICApIDogbnVsbCk7XG4gIH1cbiAgcmV0dXJuIFJlYWN0TGVnYWN5RWxlbWVudEZhY3RvcnkuaXNWYWxpZEZhY3RvcnkoZmFjdG9yeSk7XG59O1xuXG5SZWFjdExlZ2FjeUVsZW1lbnRGYWN0b3J5Ll9pc0xlZ2FjeUNhbGxXYXJuaW5nRW5hYmxlZCA9IHRydWU7XG5cbm1vZHVsZS5leHBvcnRzID0gUmVhY3RMZWdhY3lFbGVtZW50RmFjdG9yeTtcblxufSkuY2FsbCh0aGlzLHJlcXVpcmUoJ19wcm9jZXNzJykpIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIFJlYWN0TWFya3VwQ2hlY2tzdW1cbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIGFkbGVyMzIgPSByZXF1aXJlKFwiLi9hZGxlcjMyXCIpO1xuXG52YXIgUmVhY3RNYXJrdXBDaGVja3N1bSA9IHtcbiAgQ0hFQ0tTVU1fQVRUUl9OQU1FOiAnZGF0YS1yZWFjdC1jaGVja3N1bScsXG5cbiAgLyoqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBtYXJrdXAgTWFya3VwIHN0cmluZ1xuICAgKiBAcmV0dXJuIHtzdHJpbmd9IE1hcmt1cCBzdHJpbmcgd2l0aCBjaGVja3N1bSBhdHRyaWJ1dGUgYXR0YWNoZWRcbiAgICovXG4gIGFkZENoZWNrc3VtVG9NYXJrdXA6IGZ1bmN0aW9uKG1hcmt1cCkge1xuICAgIHZhciBjaGVja3N1bSA9IGFkbGVyMzIobWFya3VwKTtcbiAgICByZXR1cm4gbWFya3VwLnJlcGxhY2UoXG4gICAgICAnPicsXG4gICAgICAnICcgKyBSZWFjdE1hcmt1cENoZWNrc3VtLkNIRUNLU1VNX0FUVFJfTkFNRSArICc9XCInICsgY2hlY2tzdW0gKyAnXCI+J1xuICAgICk7XG4gIH0sXG5cbiAgLyoqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBtYXJrdXAgdG8gdXNlXG4gICAqIEBwYXJhbSB7RE9NRWxlbWVudH0gZWxlbWVudCByb290IFJlYWN0IGVsZW1lbnRcbiAgICogQHJldHVybnMge2Jvb2xlYW59IHdoZXRoZXIgb3Igbm90IHRoZSBtYXJrdXAgaXMgdGhlIHNhbWVcbiAgICovXG4gIGNhblJldXNlTWFya3VwOiBmdW5jdGlvbihtYXJrdXAsIGVsZW1lbnQpIHtcbiAgICB2YXIgZXhpc3RpbmdDaGVja3N1bSA9IGVsZW1lbnQuZ2V0QXR0cmlidXRlKFxuICAgICAgUmVhY3RNYXJrdXBDaGVja3N1bS5DSEVDS1NVTV9BVFRSX05BTUVcbiAgICApO1xuICAgIGV4aXN0aW5nQ2hlY2tzdW0gPSBleGlzdGluZ0NoZWNrc3VtICYmIHBhcnNlSW50KGV4aXN0aW5nQ2hlY2tzdW0sIDEwKTtcbiAgICB2YXIgbWFya3VwQ2hlY2tzdW0gPSBhZGxlcjMyKG1hcmt1cCk7XG4gICAgcmV0dXJuIG1hcmt1cENoZWNrc3VtID09PSBleGlzdGluZ0NoZWNrc3VtO1xuICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJlYWN0TWFya3VwQ2hlY2tzdW07XG4iLCIoZnVuY3Rpb24gKHByb2Nlc3Mpe1xuLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIFJlYWN0TW91bnRcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIERPTVByb3BlcnR5ID0gcmVxdWlyZShcIi4vRE9NUHJvcGVydHlcIik7XG52YXIgUmVhY3RCcm93c2VyRXZlbnRFbWl0dGVyID0gcmVxdWlyZShcIi4vUmVhY3RCcm93c2VyRXZlbnRFbWl0dGVyXCIpO1xudmFyIFJlYWN0Q3VycmVudE93bmVyID0gcmVxdWlyZShcIi4vUmVhY3RDdXJyZW50T3duZXJcIik7XG52YXIgUmVhY3RFbGVtZW50ID0gcmVxdWlyZShcIi4vUmVhY3RFbGVtZW50XCIpO1xudmFyIFJlYWN0TGVnYWN5RWxlbWVudCA9IHJlcXVpcmUoXCIuL1JlYWN0TGVnYWN5RWxlbWVudFwiKTtcbnZhciBSZWFjdEluc3RhbmNlSGFuZGxlcyA9IHJlcXVpcmUoXCIuL1JlYWN0SW5zdGFuY2VIYW5kbGVzXCIpO1xudmFyIFJlYWN0UGVyZiA9IHJlcXVpcmUoXCIuL1JlYWN0UGVyZlwiKTtcblxudmFyIGNvbnRhaW5zTm9kZSA9IHJlcXVpcmUoXCIuL2NvbnRhaW5zTm9kZVwiKTtcbnZhciBkZXByZWNhdGVkID0gcmVxdWlyZShcIi4vZGVwcmVjYXRlZFwiKTtcbnZhciBnZXRSZWFjdFJvb3RFbGVtZW50SW5Db250YWluZXIgPSByZXF1aXJlKFwiLi9nZXRSZWFjdFJvb3RFbGVtZW50SW5Db250YWluZXJcIik7XG52YXIgaW5zdGFudGlhdGVSZWFjdENvbXBvbmVudCA9IHJlcXVpcmUoXCIuL2luc3RhbnRpYXRlUmVhY3RDb21wb25lbnRcIik7XG52YXIgaW52YXJpYW50ID0gcmVxdWlyZShcIi4vaW52YXJpYW50XCIpO1xudmFyIHNob3VsZFVwZGF0ZVJlYWN0Q29tcG9uZW50ID0gcmVxdWlyZShcIi4vc2hvdWxkVXBkYXRlUmVhY3RDb21wb25lbnRcIik7XG52YXIgd2FybmluZyA9IHJlcXVpcmUoXCIuL3dhcm5pbmdcIik7XG5cbnZhciBjcmVhdGVFbGVtZW50ID0gUmVhY3RMZWdhY3lFbGVtZW50LndyYXBDcmVhdGVFbGVtZW50KFxuICBSZWFjdEVsZW1lbnQuY3JlYXRlRWxlbWVudFxuKTtcblxudmFyIFNFUEFSQVRPUiA9IFJlYWN0SW5zdGFuY2VIYW5kbGVzLlNFUEFSQVRPUjtcblxudmFyIEFUVFJfTkFNRSA9IERPTVByb3BlcnR5LklEX0FUVFJJQlVURV9OQU1FO1xudmFyIG5vZGVDYWNoZSA9IHt9O1xuXG52YXIgRUxFTUVOVF9OT0RFX1RZUEUgPSAxO1xudmFyIERPQ19OT0RFX1RZUEUgPSA5O1xuXG4vKiogTWFwcGluZyBmcm9tIHJlYWN0Um9vdElEIHRvIFJlYWN0IGNvbXBvbmVudCBpbnN0YW5jZS4gKi9cbnZhciBpbnN0YW5jZXNCeVJlYWN0Um9vdElEID0ge307XG5cbi8qKiBNYXBwaW5nIGZyb20gcmVhY3RSb290SUQgdG8gYGNvbnRhaW5lcmAgbm9kZXMuICovXG52YXIgY29udGFpbmVyc0J5UmVhY3RSb290SUQgPSB7fTtcblxuaWYgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOVikge1xuICAvKiogX19ERVZfXy1vbmx5IG1hcHBpbmcgZnJvbSByZWFjdFJvb3RJRCB0byByb290IGVsZW1lbnRzLiAqL1xuICB2YXIgcm9vdEVsZW1lbnRzQnlSZWFjdFJvb3RJRCA9IHt9O1xufVxuXG4vLyBVc2VkIHRvIHN0b3JlIGJyZWFkdGgtZmlyc3Qgc2VhcmNoIHN0YXRlIGluIGZpbmRDb21wb25lbnRSb290LlxudmFyIGZpbmRDb21wb25lbnRSb290UmV1c2FibGVBcnJheSA9IFtdO1xuXG4vKipcbiAqIEBwYXJhbSB7RE9NRWxlbWVudH0gY29udGFpbmVyIERPTSBlbGVtZW50IHRoYXQgbWF5IGNvbnRhaW4gYSBSZWFjdCBjb21wb25lbnQuXG4gKiBAcmV0dXJuIHs/c3RyaW5nfSBBIFwicmVhY3RSb290XCIgSUQsIGlmIGEgUmVhY3QgY29tcG9uZW50IGlzIHJlbmRlcmVkLlxuICovXG5mdW5jdGlvbiBnZXRSZWFjdFJvb3RJRChjb250YWluZXIpIHtcbiAgdmFyIHJvb3RFbGVtZW50ID0gZ2V0UmVhY3RSb290RWxlbWVudEluQ29udGFpbmVyKGNvbnRhaW5lcik7XG4gIHJldHVybiByb290RWxlbWVudCAmJiBSZWFjdE1vdW50LmdldElEKHJvb3RFbGVtZW50KTtcbn1cblxuLyoqXG4gKiBBY2Nlc3Npbmcgbm9kZVtBVFRSX05BTUVdIG9yIGNhbGxpbmcgZ2V0QXR0cmlidXRlKEFUVFJfTkFNRSkgb24gYSBmb3JtXG4gKiBlbGVtZW50IGNhbiByZXR1cm4gaXRzIGNvbnRyb2wgd2hvc2UgbmFtZSBvciBJRCBlcXVhbHMgQVRUUl9OQU1FLiBBbGxcbiAqIERPTSBub2RlcyBzdXBwb3J0IGBnZXRBdHRyaWJ1dGVOb2RlYCBidXQgdGhpcyBjYW4gYWxzbyBnZXQgY2FsbGVkIG9uXG4gKiBvdGhlciBvYmplY3RzIHNvIGp1c3QgcmV0dXJuICcnIGlmIHdlJ3JlIGdpdmVuIHNvbWV0aGluZyBvdGhlciB0aGFuIGFcbiAqIERPTSBub2RlIChzdWNoIGFzIHdpbmRvdykuXG4gKlxuICogQHBhcmFtIHs/RE9NRWxlbWVudHxET01XaW5kb3d8RE9NRG9jdW1lbnR8RE9NVGV4dE5vZGV9IG5vZGUgRE9NIG5vZGUuXG4gKiBAcmV0dXJuIHtzdHJpbmd9IElEIG9mIHRoZSBzdXBwbGllZCBgZG9tTm9kZWAuXG4gKi9cbmZ1bmN0aW9uIGdldElEKG5vZGUpIHtcbiAgdmFyIGlkID0gaW50ZXJuYWxHZXRJRChub2RlKTtcbiAgaWYgKGlkKSB7XG4gICAgaWYgKG5vZGVDYWNoZS5oYXNPd25Qcm9wZXJ0eShpZCkpIHtcbiAgICAgIHZhciBjYWNoZWQgPSBub2RlQ2FjaGVbaWRdO1xuICAgICAgaWYgKGNhY2hlZCAhPT0gbm9kZSkge1xuICAgICAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgICAgICFpc1ZhbGlkKGNhY2hlZCwgaWQpLFxuICAgICAgICAgICdSZWFjdE1vdW50OiBUd28gdmFsaWQgYnV0IHVuZXF1YWwgbm9kZXMgd2l0aCB0aGUgc2FtZSBgJXNgOiAlcycsXG4gICAgICAgICAgQVRUUl9OQU1FLCBpZFxuICAgICAgICApIDogaW52YXJpYW50KCFpc1ZhbGlkKGNhY2hlZCwgaWQpKSk7XG5cbiAgICAgICAgbm9kZUNhY2hlW2lkXSA9IG5vZGU7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIG5vZGVDYWNoZVtpZF0gPSBub2RlO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiBpZDtcbn1cblxuZnVuY3Rpb24gaW50ZXJuYWxHZXRJRChub2RlKSB7XG4gIC8vIElmIG5vZGUgaXMgc29tZXRoaW5nIGxpa2UgYSB3aW5kb3csIGRvY3VtZW50LCBvciB0ZXh0IG5vZGUsIG5vbmUgb2ZcbiAgLy8gd2hpY2ggc3VwcG9ydCBhdHRyaWJ1dGVzIG9yIGEgLmdldEF0dHJpYnV0ZSBtZXRob2QsIGdyYWNlZnVsbHkgcmV0dXJuXG4gIC8vIHRoZSBlbXB0eSBzdHJpbmcsIGFzIGlmIHRoZSBhdHRyaWJ1dGUgd2VyZSBtaXNzaW5nLlxuICByZXR1cm4gbm9kZSAmJiBub2RlLmdldEF0dHJpYnV0ZSAmJiBub2RlLmdldEF0dHJpYnV0ZShBVFRSX05BTUUpIHx8ICcnO1xufVxuXG4vKipcbiAqIFNldHMgdGhlIFJlYWN0LXNwZWNpZmljIElEIG9mIHRoZSBnaXZlbiBub2RlLlxuICpcbiAqIEBwYXJhbSB7RE9NRWxlbWVudH0gbm9kZSBUaGUgRE9NIG5vZGUgd2hvc2UgSUQgd2lsbCBiZSBzZXQuXG4gKiBAcGFyYW0ge3N0cmluZ30gaWQgVGhlIHZhbHVlIG9mIHRoZSBJRCBhdHRyaWJ1dGUuXG4gKi9cbmZ1bmN0aW9uIHNldElEKG5vZGUsIGlkKSB7XG4gIHZhciBvbGRJRCA9IGludGVybmFsR2V0SUQobm9kZSk7XG4gIGlmIChvbGRJRCAhPT0gaWQpIHtcbiAgICBkZWxldGUgbm9kZUNhY2hlW29sZElEXTtcbiAgfVxuICBub2RlLnNldEF0dHJpYnV0ZShBVFRSX05BTUUsIGlkKTtcbiAgbm9kZUNhY2hlW2lkXSA9IG5vZGU7XG59XG5cbi8qKlxuICogRmluZHMgdGhlIG5vZGUgd2l0aCB0aGUgc3VwcGxpZWQgUmVhY3QtZ2VuZXJhdGVkIERPTSBJRC5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gaWQgQSBSZWFjdC1nZW5lcmF0ZWQgRE9NIElELlxuICogQHJldHVybiB7RE9NRWxlbWVudH0gRE9NIG5vZGUgd2l0aCB0aGUgc3VwcGxlZCBgaWRgLlxuICogQGludGVybmFsXG4gKi9cbmZ1bmN0aW9uIGdldE5vZGUoaWQpIHtcbiAgaWYgKCFub2RlQ2FjaGUuaGFzT3duUHJvcGVydHkoaWQpIHx8ICFpc1ZhbGlkKG5vZGVDYWNoZVtpZF0sIGlkKSkge1xuICAgIG5vZGVDYWNoZVtpZF0gPSBSZWFjdE1vdW50LmZpbmRSZWFjdE5vZGVCeUlEKGlkKTtcbiAgfVxuICByZXR1cm4gbm9kZUNhY2hlW2lkXTtcbn1cblxuLyoqXG4gKiBBIG5vZGUgaXMgXCJ2YWxpZFwiIGlmIGl0IGlzIGNvbnRhaW5lZCBieSBhIGN1cnJlbnRseSBtb3VudGVkIGNvbnRhaW5lci5cbiAqXG4gKiBUaGlzIG1lYW5zIHRoYXQgdGhlIG5vZGUgZG9lcyBub3QgaGF2ZSB0byBiZSBjb250YWluZWQgYnkgYSBkb2N1bWVudCBpblxuICogb3JkZXIgdG8gYmUgY29uc2lkZXJlZCB2YWxpZC5cbiAqXG4gKiBAcGFyYW0gez9ET01FbGVtZW50fSBub2RlIFRoZSBjYW5kaWRhdGUgRE9NIG5vZGUuXG4gKiBAcGFyYW0ge3N0cmluZ30gaWQgVGhlIGV4cGVjdGVkIElEIG9mIHRoZSBub2RlLlxuICogQHJldHVybiB7Ym9vbGVhbn0gV2hldGhlciB0aGUgbm9kZSBpcyBjb250YWluZWQgYnkgYSBtb3VudGVkIGNvbnRhaW5lci5cbiAqL1xuZnVuY3Rpb24gaXNWYWxpZChub2RlLCBpZCkge1xuICBpZiAobm9kZSkge1xuICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICBpbnRlcm5hbEdldElEKG5vZGUpID09PSBpZCxcbiAgICAgICdSZWFjdE1vdW50OiBVbmV4cGVjdGVkIG1vZGlmaWNhdGlvbiBvZiBgJXNgJyxcbiAgICAgIEFUVFJfTkFNRVxuICAgICkgOiBpbnZhcmlhbnQoaW50ZXJuYWxHZXRJRChub2RlKSA9PT0gaWQpKTtcblxuICAgIHZhciBjb250YWluZXIgPSBSZWFjdE1vdW50LmZpbmRSZWFjdENvbnRhaW5lckZvcklEKGlkKTtcbiAgICBpZiAoY29udGFpbmVyICYmIGNvbnRhaW5zTm9kZShjb250YWluZXIsIG5vZGUpKSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gZmFsc2U7XG59XG5cbi8qKlxuICogQ2F1c2VzIHRoZSBjYWNoZSB0byBmb3JnZXQgYWJvdXQgb25lIFJlYWN0LXNwZWNpZmljIElELlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBpZCBUaGUgSUQgdG8gZm9yZ2V0LlxuICovXG5mdW5jdGlvbiBwdXJnZUlEKGlkKSB7XG4gIGRlbGV0ZSBub2RlQ2FjaGVbaWRdO1xufVxuXG52YXIgZGVlcGVzdE5vZGVTb0ZhciA9IG51bGw7XG5mdW5jdGlvbiBmaW5kRGVlcGVzdENhY2hlZEFuY2VzdG9ySW1wbChhbmNlc3RvcklEKSB7XG4gIHZhciBhbmNlc3RvciA9IG5vZGVDYWNoZVthbmNlc3RvcklEXTtcbiAgaWYgKGFuY2VzdG9yICYmIGlzVmFsaWQoYW5jZXN0b3IsIGFuY2VzdG9ySUQpKSB7XG4gICAgZGVlcGVzdE5vZGVTb0ZhciA9IGFuY2VzdG9yO1xuICB9IGVsc2Uge1xuICAgIC8vIFRoaXMgbm9kZSBpc24ndCBwb3B1bGF0ZWQgaW4gdGhlIGNhY2hlLCBzbyBwcmVzdW1hYmx5IG5vbmUgb2YgaXRzXG4gICAgLy8gZGVzY2VuZGFudHMgYXJlLiBCcmVhayBvdXQgb2YgdGhlIGxvb3AuXG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG59XG5cbi8qKlxuICogUmV0dXJuIHRoZSBkZWVwZXN0IGNhY2hlZCBub2RlIHdob3NlIElEIGlzIGEgcHJlZml4IG9mIGB0YXJnZXRJRGAuXG4gKi9cbmZ1bmN0aW9uIGZpbmREZWVwZXN0Q2FjaGVkQW5jZXN0b3IodGFyZ2V0SUQpIHtcbiAgZGVlcGVzdE5vZGVTb0ZhciA9IG51bGw7XG4gIFJlYWN0SW5zdGFuY2VIYW5kbGVzLnRyYXZlcnNlQW5jZXN0b3JzKFxuICAgIHRhcmdldElELFxuICAgIGZpbmREZWVwZXN0Q2FjaGVkQW5jZXN0b3JJbXBsXG4gICk7XG5cbiAgdmFyIGZvdW5kTm9kZSA9IGRlZXBlc3ROb2RlU29GYXI7XG4gIGRlZXBlc3ROb2RlU29GYXIgPSBudWxsO1xuICByZXR1cm4gZm91bmROb2RlO1xufVxuXG4vKipcbiAqIE1vdW50aW5nIGlzIHRoZSBwcm9jZXNzIG9mIGluaXRpYWxpemluZyBhIFJlYWN0IGNvbXBvbmVudCBieSBjcmVhdGluZ3MgaXRzXG4gKiByZXByZXNlbnRhdGl2ZSBET00gZWxlbWVudHMgYW5kIGluc2VydGluZyB0aGVtIGludG8gYSBzdXBwbGllZCBgY29udGFpbmVyYC5cbiAqIEFueSBwcmlvciBjb250ZW50IGluc2lkZSBgY29udGFpbmVyYCBpcyBkZXN0cm95ZWQgaW4gdGhlIHByb2Nlc3MuXG4gKlxuICogICBSZWFjdE1vdW50LnJlbmRlcihcbiAqICAgICBjb21wb25lbnQsXG4gKiAgICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2NvbnRhaW5lcicpXG4gKiAgICk7XG4gKlxuICogICA8ZGl2IGlkPVwiY29udGFpbmVyXCI+ICAgICAgICAgICAgICAgICAgIDwtLSBTdXBwbGllZCBgY29udGFpbmVyYC5cbiAqICAgICA8ZGl2IGRhdGEtcmVhY3RpZD1cIi4zXCI+ICAgICAgICAgICAgICA8LS0gUmVuZGVyZWQgcmVhY3RSb290IG9mIFJlYWN0XG4gKiAgICAgICAvLyAuLi4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb21wb25lbnQuXG4gKiAgICAgPC9kaXY+XG4gKiAgIDwvZGl2PlxuICpcbiAqIEluc2lkZSBvZiBgY29udGFpbmVyYCwgdGhlIGZpcnN0IGVsZW1lbnQgcmVuZGVyZWQgaXMgdGhlIFwicmVhY3RSb290XCIuXG4gKi9cbnZhciBSZWFjdE1vdW50ID0ge1xuICAvKiogRXhwb3NlZCBmb3IgZGVidWdnaW5nIHB1cnBvc2VzICoqL1xuICBfaW5zdGFuY2VzQnlSZWFjdFJvb3RJRDogaW5zdGFuY2VzQnlSZWFjdFJvb3RJRCxcblxuICAvKipcbiAgICogVGhpcyBpcyBhIGhvb2sgcHJvdmlkZWQgdG8gc3VwcG9ydCByZW5kZXJpbmcgUmVhY3QgY29tcG9uZW50cyB3aGlsZVxuICAgKiBlbnN1cmluZyB0aGF0IHRoZSBhcHBhcmVudCBzY3JvbGwgcG9zaXRpb24gb2YgaXRzIGBjb250YWluZXJgIGRvZXMgbm90XG4gICAqIGNoYW5nZS5cbiAgICpcbiAgICogQHBhcmFtIHtET01FbGVtZW50fSBjb250YWluZXIgVGhlIGBjb250YWluZXJgIGJlaW5nIHJlbmRlcmVkIGludG8uXG4gICAqIEBwYXJhbSB7ZnVuY3Rpb259IHJlbmRlckNhbGxiYWNrIFRoaXMgbXVzdCBiZSBjYWxsZWQgb25jZSB0byBkbyB0aGUgcmVuZGVyLlxuICAgKi9cbiAgc2Nyb2xsTW9uaXRvcjogZnVuY3Rpb24oY29udGFpbmVyLCByZW5kZXJDYWxsYmFjaykge1xuICAgIHJlbmRlckNhbGxiYWNrKCk7XG4gIH0sXG5cbiAgLyoqXG4gICAqIFRha2UgYSBjb21wb25lbnQgdGhhdCdzIGFscmVhZHkgbW91bnRlZCBpbnRvIHRoZSBET00gYW5kIHJlcGxhY2UgaXRzIHByb3BzXG4gICAqIEBwYXJhbSB7UmVhY3RDb21wb25lbnR9IHByZXZDb21wb25lbnQgY29tcG9uZW50IGluc3RhbmNlIGFscmVhZHkgaW4gdGhlIERPTVxuICAgKiBAcGFyYW0ge1JlYWN0Q29tcG9uZW50fSBuZXh0Q29tcG9uZW50IGNvbXBvbmVudCBpbnN0YW5jZSB0byByZW5kZXJcbiAgICogQHBhcmFtIHtET01FbGVtZW50fSBjb250YWluZXIgY29udGFpbmVyIHRvIHJlbmRlciBpbnRvXG4gICAqIEBwYXJhbSB7P2Z1bmN0aW9ufSBjYWxsYmFjayBmdW5jdGlvbiB0cmlnZ2VyZWQgb24gY29tcGxldGlvblxuICAgKi9cbiAgX3VwZGF0ZVJvb3RDb21wb25lbnQ6IGZ1bmN0aW9uKFxuICAgICAgcHJldkNvbXBvbmVudCxcbiAgICAgIG5leHRDb21wb25lbnQsXG4gICAgICBjb250YWluZXIsXG4gICAgICBjYWxsYmFjaykge1xuICAgIHZhciBuZXh0UHJvcHMgPSBuZXh0Q29tcG9uZW50LnByb3BzO1xuICAgIFJlYWN0TW91bnQuc2Nyb2xsTW9uaXRvcihjb250YWluZXIsIGZ1bmN0aW9uKCkge1xuICAgICAgcHJldkNvbXBvbmVudC5yZXBsYWNlUHJvcHMobmV4dFByb3BzLCBjYWxsYmFjayk7XG4gICAgfSk7XG5cbiAgICBpZiAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WKSB7XG4gICAgICAvLyBSZWNvcmQgdGhlIHJvb3QgZWxlbWVudCBpbiBjYXNlIGl0IGxhdGVyIGdldHMgdHJhbnNwbGFudGVkLlxuICAgICAgcm9vdEVsZW1lbnRzQnlSZWFjdFJvb3RJRFtnZXRSZWFjdFJvb3RJRChjb250YWluZXIpXSA9XG4gICAgICAgIGdldFJlYWN0Um9vdEVsZW1lbnRJbkNvbnRhaW5lcihjb250YWluZXIpO1xuICAgIH1cblxuICAgIHJldHVybiBwcmV2Q29tcG9uZW50O1xuICB9LFxuXG4gIC8qKlxuICAgKiBSZWdpc3RlciBhIGNvbXBvbmVudCBpbnRvIHRoZSBpbnN0YW5jZSBtYXAgYW5kIHN0YXJ0cyBzY3JvbGwgdmFsdWVcbiAgICogbW9uaXRvcmluZ1xuICAgKiBAcGFyYW0ge1JlYWN0Q29tcG9uZW50fSBuZXh0Q29tcG9uZW50IGNvbXBvbmVudCBpbnN0YW5jZSB0byByZW5kZXJcbiAgICogQHBhcmFtIHtET01FbGVtZW50fSBjb250YWluZXIgY29udGFpbmVyIHRvIHJlbmRlciBpbnRvXG4gICAqIEByZXR1cm4ge3N0cmluZ30gcmVhY3RSb290IElEIHByZWZpeFxuICAgKi9cbiAgX3JlZ2lzdGVyQ29tcG9uZW50OiBmdW5jdGlvbihuZXh0Q29tcG9uZW50LCBjb250YWluZXIpIHtcbiAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgY29udGFpbmVyICYmIChcbiAgICAgICAgY29udGFpbmVyLm5vZGVUeXBlID09PSBFTEVNRU5UX05PREVfVFlQRSB8fFxuICAgICAgICBjb250YWluZXIubm9kZVR5cGUgPT09IERPQ19OT0RFX1RZUEVcbiAgICAgICksXG4gICAgICAnX3JlZ2lzdGVyQ29tcG9uZW50KC4uLik6IFRhcmdldCBjb250YWluZXIgaXMgbm90IGEgRE9NIGVsZW1lbnQuJ1xuICAgICkgOiBpbnZhcmlhbnQoY29udGFpbmVyICYmIChcbiAgICAgIGNvbnRhaW5lci5ub2RlVHlwZSA9PT0gRUxFTUVOVF9OT0RFX1RZUEUgfHxcbiAgICAgIGNvbnRhaW5lci5ub2RlVHlwZSA9PT0gRE9DX05PREVfVFlQRVxuICAgICkpKTtcblxuICAgIFJlYWN0QnJvd3NlckV2ZW50RW1pdHRlci5lbnN1cmVTY3JvbGxWYWx1ZU1vbml0b3JpbmcoKTtcblxuICAgIHZhciByZWFjdFJvb3RJRCA9IFJlYWN0TW91bnQucmVnaXN0ZXJDb250YWluZXIoY29udGFpbmVyKTtcbiAgICBpbnN0YW5jZXNCeVJlYWN0Um9vdElEW3JlYWN0Um9vdElEXSA9IG5leHRDb21wb25lbnQ7XG4gICAgcmV0dXJuIHJlYWN0Um9vdElEO1xuICB9LFxuXG4gIC8qKlxuICAgKiBSZW5kZXIgYSBuZXcgY29tcG9uZW50IGludG8gdGhlIERPTS5cbiAgICogQHBhcmFtIHtSZWFjdENvbXBvbmVudH0gbmV4dENvbXBvbmVudCBjb21wb25lbnQgaW5zdGFuY2UgdG8gcmVuZGVyXG4gICAqIEBwYXJhbSB7RE9NRWxlbWVudH0gY29udGFpbmVyIGNvbnRhaW5lciB0byByZW5kZXIgaW50b1xuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHNob3VsZFJldXNlTWFya3VwIGlmIHdlIHNob3VsZCBza2lwIHRoZSBtYXJrdXAgaW5zZXJ0aW9uXG4gICAqIEByZXR1cm4ge1JlYWN0Q29tcG9uZW50fSBuZXh0Q29tcG9uZW50XG4gICAqL1xuICBfcmVuZGVyTmV3Um9vdENvbXBvbmVudDogUmVhY3RQZXJmLm1lYXN1cmUoXG4gICAgJ1JlYWN0TW91bnQnLFxuICAgICdfcmVuZGVyTmV3Um9vdENvbXBvbmVudCcsXG4gICAgZnVuY3Rpb24oXG4gICAgICAgIG5leHRDb21wb25lbnQsXG4gICAgICAgIGNvbnRhaW5lcixcbiAgICAgICAgc2hvdWxkUmV1c2VNYXJrdXApIHtcbiAgICAgIC8vIFZhcmlvdXMgcGFydHMgb2Ygb3VyIGNvZGUgKHN1Y2ggYXMgUmVhY3RDb21wb3NpdGVDb21wb25lbnQnc1xuICAgICAgLy8gX3JlbmRlclZhbGlkYXRlZENvbXBvbmVudCkgYXNzdW1lIHRoYXQgY2FsbHMgdG8gcmVuZGVyIGFyZW4ndCBuZXN0ZWQ7XG4gICAgICAvLyB2ZXJpZnkgdGhhdCB0aGF0J3MgdGhlIGNhc2UuXG4gICAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gd2FybmluZyhcbiAgICAgICAgUmVhY3RDdXJyZW50T3duZXIuY3VycmVudCA9PSBudWxsLFxuICAgICAgICAnX3JlbmRlck5ld1Jvb3RDb21wb25lbnQoKTogUmVuZGVyIG1ldGhvZHMgc2hvdWxkIGJlIGEgcHVyZSBmdW5jdGlvbiAnICtcbiAgICAgICAgJ29mIHByb3BzIGFuZCBzdGF0ZTsgdHJpZ2dlcmluZyBuZXN0ZWQgY29tcG9uZW50IHVwZGF0ZXMgZnJvbSAnICtcbiAgICAgICAgJ3JlbmRlciBpcyBub3QgYWxsb3dlZC4gSWYgbmVjZXNzYXJ5LCB0cmlnZ2VyIG5lc3RlZCB1cGRhdGVzIGluICcgK1xuICAgICAgICAnY29tcG9uZW50RGlkVXBkYXRlLidcbiAgICAgICkgOiBudWxsKTtcblxuICAgICAgdmFyIGNvbXBvbmVudEluc3RhbmNlID0gaW5zdGFudGlhdGVSZWFjdENvbXBvbmVudChuZXh0Q29tcG9uZW50LCBudWxsKTtcbiAgICAgIHZhciByZWFjdFJvb3RJRCA9IFJlYWN0TW91bnQuX3JlZ2lzdGVyQ29tcG9uZW50KFxuICAgICAgICBjb21wb25lbnRJbnN0YW5jZSxcbiAgICAgICAgY29udGFpbmVyXG4gICAgICApO1xuICAgICAgY29tcG9uZW50SW5zdGFuY2UubW91bnRDb21wb25lbnRJbnRvTm9kZShcbiAgICAgICAgcmVhY3RSb290SUQsXG4gICAgICAgIGNvbnRhaW5lcixcbiAgICAgICAgc2hvdWxkUmV1c2VNYXJrdXBcbiAgICAgICk7XG5cbiAgICAgIGlmIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYpIHtcbiAgICAgICAgLy8gUmVjb3JkIHRoZSByb290IGVsZW1lbnQgaW4gY2FzZSBpdCBsYXRlciBnZXRzIHRyYW5zcGxhbnRlZC5cbiAgICAgICAgcm9vdEVsZW1lbnRzQnlSZWFjdFJvb3RJRFtyZWFjdFJvb3RJRF0gPVxuICAgICAgICAgIGdldFJlYWN0Um9vdEVsZW1lbnRJbkNvbnRhaW5lcihjb250YWluZXIpO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gY29tcG9uZW50SW5zdGFuY2U7XG4gICAgfVxuICApLFxuXG4gIC8qKlxuICAgKiBSZW5kZXJzIGEgUmVhY3QgY29tcG9uZW50IGludG8gdGhlIERPTSBpbiB0aGUgc3VwcGxpZWQgYGNvbnRhaW5lcmAuXG4gICAqXG4gICAqIElmIHRoZSBSZWFjdCBjb21wb25lbnQgd2FzIHByZXZpb3VzbHkgcmVuZGVyZWQgaW50byBgY29udGFpbmVyYCwgdGhpcyB3aWxsXG4gICAqIHBlcmZvcm0gYW4gdXBkYXRlIG9uIGl0IGFuZCBvbmx5IG11dGF0ZSB0aGUgRE9NIGFzIG5lY2Vzc2FyeSB0byByZWZsZWN0IHRoZVxuICAgKiBsYXRlc3QgUmVhY3QgY29tcG9uZW50LlxuICAgKlxuICAgKiBAcGFyYW0ge1JlYWN0RWxlbWVudH0gbmV4dEVsZW1lbnQgQ29tcG9uZW50IGVsZW1lbnQgdG8gcmVuZGVyLlxuICAgKiBAcGFyYW0ge0RPTUVsZW1lbnR9IGNvbnRhaW5lciBET00gZWxlbWVudCB0byByZW5kZXIgaW50by5cbiAgICogQHBhcmFtIHs/ZnVuY3Rpb259IGNhbGxiYWNrIGZ1bmN0aW9uIHRyaWdnZXJlZCBvbiBjb21wbGV0aW9uXG4gICAqIEByZXR1cm4ge1JlYWN0Q29tcG9uZW50fSBDb21wb25lbnQgaW5zdGFuY2UgcmVuZGVyZWQgaW4gYGNvbnRhaW5lcmAuXG4gICAqL1xuICByZW5kZXI6IGZ1bmN0aW9uKG5leHRFbGVtZW50LCBjb250YWluZXIsIGNhbGxiYWNrKSB7XG4gICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgIFJlYWN0RWxlbWVudC5pc1ZhbGlkRWxlbWVudChuZXh0RWxlbWVudCksXG4gICAgICAncmVuZGVyQ29tcG9uZW50KCk6IEludmFsaWQgY29tcG9uZW50IGVsZW1lbnQuJXMnLFxuICAgICAgKFxuICAgICAgICB0eXBlb2YgbmV4dEVsZW1lbnQgPT09ICdzdHJpbmcnID9cbiAgICAgICAgICAnIEluc3RlYWQgb2YgcGFzc2luZyBhbiBlbGVtZW50IHN0cmluZywgbWFrZSBzdXJlIHRvIGluc3RhbnRpYXRlICcgK1xuICAgICAgICAgICdpdCBieSBwYXNzaW5nIGl0IHRvIFJlYWN0LmNyZWF0ZUVsZW1lbnQuJyA6XG4gICAgICAgIFJlYWN0TGVnYWN5RWxlbWVudC5pc1ZhbGlkRmFjdG9yeShuZXh0RWxlbWVudCkgP1xuICAgICAgICAgICcgSW5zdGVhZCBvZiBwYXNzaW5nIGEgY29tcG9uZW50IGNsYXNzLCBtYWtlIHN1cmUgdG8gaW5zdGFudGlhdGUgJyArXG4gICAgICAgICAgJ2l0IGJ5IHBhc3NpbmcgaXQgdG8gUmVhY3QuY3JlYXRlRWxlbWVudC4nIDpcbiAgICAgICAgLy8gQ2hlY2sgaWYgaXQgcXVhY2tzIGxpa2UgYSBlbGVtZW50XG4gICAgICAgIHR5cGVvZiBuZXh0RWxlbWVudC5wcm9wcyAhPT0gXCJ1bmRlZmluZWRcIiA/XG4gICAgICAgICAgJyBUaGlzIG1heSBiZSBjYXVzZWQgYnkgdW5pbnRlbnRpb25hbGx5IGxvYWRpbmcgdHdvIGluZGVwZW5kZW50ICcgK1xuICAgICAgICAgICdjb3BpZXMgb2YgUmVhY3QuJyA6XG4gICAgICAgICAgJydcbiAgICAgIClcbiAgICApIDogaW52YXJpYW50KFJlYWN0RWxlbWVudC5pc1ZhbGlkRWxlbWVudChuZXh0RWxlbWVudCkpKTtcblxuICAgIHZhciBwcmV2Q29tcG9uZW50ID0gaW5zdGFuY2VzQnlSZWFjdFJvb3RJRFtnZXRSZWFjdFJvb3RJRChjb250YWluZXIpXTtcblxuICAgIGlmIChwcmV2Q29tcG9uZW50KSB7XG4gICAgICB2YXIgcHJldkVsZW1lbnQgPSBwcmV2Q29tcG9uZW50Ll9jdXJyZW50RWxlbWVudDtcbiAgICAgIGlmIChzaG91bGRVcGRhdGVSZWFjdENvbXBvbmVudChwcmV2RWxlbWVudCwgbmV4dEVsZW1lbnQpKSB7XG4gICAgICAgIHJldHVybiBSZWFjdE1vdW50Ll91cGRhdGVSb290Q29tcG9uZW50KFxuICAgICAgICAgIHByZXZDb21wb25lbnQsXG4gICAgICAgICAgbmV4dEVsZW1lbnQsXG4gICAgICAgICAgY29udGFpbmVyLFxuICAgICAgICAgIGNhbGxiYWNrXG4gICAgICAgICk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBSZWFjdE1vdW50LnVubW91bnRDb21wb25lbnRBdE5vZGUoY29udGFpbmVyKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICB2YXIgcmVhY3RSb290RWxlbWVudCA9IGdldFJlYWN0Um9vdEVsZW1lbnRJbkNvbnRhaW5lcihjb250YWluZXIpO1xuICAgIHZhciBjb250YWluZXJIYXNSZWFjdE1hcmt1cCA9XG4gICAgICByZWFjdFJvb3RFbGVtZW50ICYmIFJlYWN0TW91bnQuaXNSZW5kZXJlZEJ5UmVhY3QocmVhY3RSb290RWxlbWVudCk7XG5cbiAgICB2YXIgc2hvdWxkUmV1c2VNYXJrdXAgPSBjb250YWluZXJIYXNSZWFjdE1hcmt1cCAmJiAhcHJldkNvbXBvbmVudDtcblxuICAgIHZhciBjb21wb25lbnQgPSBSZWFjdE1vdW50Ll9yZW5kZXJOZXdSb290Q29tcG9uZW50KFxuICAgICAgbmV4dEVsZW1lbnQsXG4gICAgICBjb250YWluZXIsXG4gICAgICBzaG91bGRSZXVzZU1hcmt1cFxuICAgICk7XG4gICAgY2FsbGJhY2sgJiYgY2FsbGJhY2suY2FsbChjb21wb25lbnQpO1xuICAgIHJldHVybiBjb21wb25lbnQ7XG4gIH0sXG5cbiAgLyoqXG4gICAqIENvbnN0cnVjdHMgYSBjb21wb25lbnQgaW5zdGFuY2Ugb2YgYGNvbnN0cnVjdG9yYCB3aXRoIGBpbml0aWFsUHJvcHNgIGFuZFxuICAgKiByZW5kZXJzIGl0IGludG8gdGhlIHN1cHBsaWVkIGBjb250YWluZXJgLlxuICAgKlxuICAgKiBAcGFyYW0ge2Z1bmN0aW9ufSBjb25zdHJ1Y3RvciBSZWFjdCBjb21wb25lbnQgY29uc3RydWN0b3IuXG4gICAqIEBwYXJhbSB7P29iamVjdH0gcHJvcHMgSW5pdGlhbCBwcm9wcyBvZiB0aGUgY29tcG9uZW50IGluc3RhbmNlLlxuICAgKiBAcGFyYW0ge0RPTUVsZW1lbnR9IGNvbnRhaW5lciBET00gZWxlbWVudCB0byByZW5kZXIgaW50by5cbiAgICogQHJldHVybiB7UmVhY3RDb21wb25lbnR9IENvbXBvbmVudCBpbnN0YW5jZSByZW5kZXJlZCBpbiBgY29udGFpbmVyYC5cbiAgICovXG4gIGNvbnN0cnVjdEFuZFJlbmRlckNvbXBvbmVudDogZnVuY3Rpb24oY29uc3RydWN0b3IsIHByb3BzLCBjb250YWluZXIpIHtcbiAgICB2YXIgZWxlbWVudCA9IGNyZWF0ZUVsZW1lbnQoY29uc3RydWN0b3IsIHByb3BzKTtcbiAgICByZXR1cm4gUmVhY3RNb3VudC5yZW5kZXIoZWxlbWVudCwgY29udGFpbmVyKTtcbiAgfSxcblxuICAvKipcbiAgICogQ29uc3RydWN0cyBhIGNvbXBvbmVudCBpbnN0YW5jZSBvZiBgY29uc3RydWN0b3JgIHdpdGggYGluaXRpYWxQcm9wc2AgYW5kXG4gICAqIHJlbmRlcnMgaXQgaW50byBhIGNvbnRhaW5lciBub2RlIGlkZW50aWZpZWQgYnkgc3VwcGxpZWQgYGlkYC5cbiAgICpcbiAgICogQHBhcmFtIHtmdW5jdGlvbn0gY29tcG9uZW50Q29uc3RydWN0b3IgUmVhY3QgY29tcG9uZW50IGNvbnN0cnVjdG9yXG4gICAqIEBwYXJhbSB7P29iamVjdH0gcHJvcHMgSW5pdGlhbCBwcm9wcyBvZiB0aGUgY29tcG9uZW50IGluc3RhbmNlLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gaWQgSUQgb2YgdGhlIERPTSBlbGVtZW50IHRvIHJlbmRlciBpbnRvLlxuICAgKiBAcmV0dXJuIHtSZWFjdENvbXBvbmVudH0gQ29tcG9uZW50IGluc3RhbmNlIHJlbmRlcmVkIGluIHRoZSBjb250YWluZXIgbm9kZS5cbiAgICovXG4gIGNvbnN0cnVjdEFuZFJlbmRlckNvbXBvbmVudEJ5SUQ6IGZ1bmN0aW9uKGNvbnN0cnVjdG9yLCBwcm9wcywgaWQpIHtcbiAgICB2YXIgZG9tTm9kZSA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKGlkKTtcbiAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgZG9tTm9kZSxcbiAgICAgICdUcmllZCB0byBnZXQgZWxlbWVudCB3aXRoIGlkIG9mIFwiJXNcIiBidXQgaXQgaXMgbm90IHByZXNlbnQgb24gdGhlIHBhZ2UuJyxcbiAgICAgIGlkXG4gICAgKSA6IGludmFyaWFudChkb21Ob2RlKSk7XG4gICAgcmV0dXJuIFJlYWN0TW91bnQuY29uc3RydWN0QW5kUmVuZGVyQ29tcG9uZW50KGNvbnN0cnVjdG9yLCBwcm9wcywgZG9tTm9kZSk7XG4gIH0sXG5cbiAgLyoqXG4gICAqIFJlZ2lzdGVycyBhIGNvbnRhaW5lciBub2RlIGludG8gd2hpY2ggUmVhY3QgY29tcG9uZW50cyB3aWxsIGJlIHJlbmRlcmVkLlxuICAgKiBUaGlzIGFsc28gY3JlYXRlcyB0aGUgXCJyZWFjdFJvb3RcIiBJRCB0aGF0IHdpbGwgYmUgYXNzaWduZWQgdG8gdGhlIGVsZW1lbnRcbiAgICogcmVuZGVyZWQgd2l0aGluLlxuICAgKlxuICAgKiBAcGFyYW0ge0RPTUVsZW1lbnR9IGNvbnRhaW5lciBET00gZWxlbWVudCB0byByZWdpc3RlciBhcyBhIGNvbnRhaW5lci5cbiAgICogQHJldHVybiB7c3RyaW5nfSBUaGUgXCJyZWFjdFJvb3RcIiBJRCBvZiBlbGVtZW50cyByZW5kZXJlZCB3aXRoaW4uXG4gICAqL1xuICByZWdpc3RlckNvbnRhaW5lcjogZnVuY3Rpb24oY29udGFpbmVyKSB7XG4gICAgdmFyIHJlYWN0Um9vdElEID0gZ2V0UmVhY3RSb290SUQoY29udGFpbmVyKTtcbiAgICBpZiAocmVhY3RSb290SUQpIHtcbiAgICAgIC8vIElmIG9uZSBleGlzdHMsIG1ha2Ugc3VyZSBpdCBpcyBhIHZhbGlkIFwicmVhY3RSb290XCIgSUQuXG4gICAgICByZWFjdFJvb3RJRCA9IFJlYWN0SW5zdGFuY2VIYW5kbGVzLmdldFJlYWN0Um9vdElERnJvbU5vZGVJRChyZWFjdFJvb3RJRCk7XG4gICAgfVxuICAgIGlmICghcmVhY3RSb290SUQpIHtcbiAgICAgIC8vIE5vIHZhbGlkIFwicmVhY3RSb290XCIgSUQgZm91bmQsIGNyZWF0ZSBvbmUuXG4gICAgICByZWFjdFJvb3RJRCA9IFJlYWN0SW5zdGFuY2VIYW5kbGVzLmNyZWF0ZVJlYWN0Um9vdElEKCk7XG4gICAgfVxuICAgIGNvbnRhaW5lcnNCeVJlYWN0Um9vdElEW3JlYWN0Um9vdElEXSA9IGNvbnRhaW5lcjtcbiAgICByZXR1cm4gcmVhY3RSb290SUQ7XG4gIH0sXG5cbiAgLyoqXG4gICAqIFVubW91bnRzIGFuZCBkZXN0cm95cyB0aGUgUmVhY3QgY29tcG9uZW50IHJlbmRlcmVkIGluIHRoZSBgY29udGFpbmVyYC5cbiAgICpcbiAgICogQHBhcmFtIHtET01FbGVtZW50fSBjb250YWluZXIgRE9NIGVsZW1lbnQgY29udGFpbmluZyBhIFJlYWN0IGNvbXBvbmVudC5cbiAgICogQHJldHVybiB7Ym9vbGVhbn0gVHJ1ZSBpZiBhIGNvbXBvbmVudCB3YXMgZm91bmQgaW4gYW5kIHVubW91bnRlZCBmcm9tXG4gICAqICAgICAgICAgICAgICAgICAgIGBjb250YWluZXJgXG4gICAqL1xuICB1bm1vdW50Q29tcG9uZW50QXROb2RlOiBmdW5jdGlvbihjb250YWluZXIpIHtcbiAgICAvLyBWYXJpb3VzIHBhcnRzIG9mIG91ciBjb2RlIChzdWNoIGFzIFJlYWN0Q29tcG9zaXRlQ29tcG9uZW50J3NcbiAgICAvLyBfcmVuZGVyVmFsaWRhdGVkQ29tcG9uZW50KSBhc3N1bWUgdGhhdCBjYWxscyB0byByZW5kZXIgYXJlbid0IG5lc3RlZDtcbiAgICAvLyB2ZXJpZnkgdGhhdCB0aGF0J3MgdGhlIGNhc2UuIChTdHJpY3RseSBzcGVha2luZywgdW5tb3VudGluZyB3b24ndCBjYXVzZSBhXG4gICAgLy8gcmVuZGVyIGJ1dCB3ZSBzdGlsbCBkb24ndCBleHBlY3QgdG8gYmUgaW4gYSByZW5kZXIgY2FsbCBoZXJlLilcbiAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gd2FybmluZyhcbiAgICAgIFJlYWN0Q3VycmVudE93bmVyLmN1cnJlbnQgPT0gbnVsbCxcbiAgICAgICd1bm1vdW50Q29tcG9uZW50QXROb2RlKCk6IFJlbmRlciBtZXRob2RzIHNob3VsZCBiZSBhIHB1cmUgZnVuY3Rpb24gb2YgJyArXG4gICAgICAncHJvcHMgYW5kIHN0YXRlOyB0cmlnZ2VyaW5nIG5lc3RlZCBjb21wb25lbnQgdXBkYXRlcyBmcm9tIHJlbmRlciBpcyAnICtcbiAgICAgICdub3QgYWxsb3dlZC4gSWYgbmVjZXNzYXJ5LCB0cmlnZ2VyIG5lc3RlZCB1cGRhdGVzIGluICcgK1xuICAgICAgJ2NvbXBvbmVudERpZFVwZGF0ZS4nXG4gICAgKSA6IG51bGwpO1xuXG4gICAgdmFyIHJlYWN0Um9vdElEID0gZ2V0UmVhY3RSb290SUQoY29udGFpbmVyKTtcbiAgICB2YXIgY29tcG9uZW50ID0gaW5zdGFuY2VzQnlSZWFjdFJvb3RJRFtyZWFjdFJvb3RJRF07XG4gICAgaWYgKCFjb21wb25lbnQpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgUmVhY3RNb3VudC51bm1vdW50Q29tcG9uZW50RnJvbU5vZGUoY29tcG9uZW50LCBjb250YWluZXIpO1xuICAgIGRlbGV0ZSBpbnN0YW5jZXNCeVJlYWN0Um9vdElEW3JlYWN0Um9vdElEXTtcbiAgICBkZWxldGUgY29udGFpbmVyc0J5UmVhY3RSb290SURbcmVhY3RSb290SURdO1xuICAgIGlmIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYpIHtcbiAgICAgIGRlbGV0ZSByb290RWxlbWVudHNCeVJlYWN0Um9vdElEW3JlYWN0Um9vdElEXTtcbiAgICB9XG4gICAgcmV0dXJuIHRydWU7XG4gIH0sXG5cbiAgLyoqXG4gICAqIFVubW91bnRzIGEgY29tcG9uZW50IGFuZCByZW1vdmVzIGl0IGZyb20gdGhlIERPTS5cbiAgICpcbiAgICogQHBhcmFtIHtSZWFjdENvbXBvbmVudH0gaW5zdGFuY2UgUmVhY3QgY29tcG9uZW50IGluc3RhbmNlLlxuICAgKiBAcGFyYW0ge0RPTUVsZW1lbnR9IGNvbnRhaW5lciBET00gZWxlbWVudCB0byB1bm1vdW50IGZyb20uXG4gICAqIEBmaW5hbFxuICAgKiBAaW50ZXJuYWxcbiAgICogQHNlZSB7UmVhY3RNb3VudC51bm1vdW50Q29tcG9uZW50QXROb2RlfVxuICAgKi9cbiAgdW5tb3VudENvbXBvbmVudEZyb21Ob2RlOiBmdW5jdGlvbihpbnN0YW5jZSwgY29udGFpbmVyKSB7XG4gICAgaW5zdGFuY2UudW5tb3VudENvbXBvbmVudCgpO1xuXG4gICAgaWYgKGNvbnRhaW5lci5ub2RlVHlwZSA9PT0gRE9DX05PREVfVFlQRSkge1xuICAgICAgY29udGFpbmVyID0gY29udGFpbmVyLmRvY3VtZW50RWxlbWVudDtcbiAgICB9XG5cbiAgICAvLyBodHRwOi8vanNwZXJmLmNvbS9lbXB0eWluZy1hLW5vZGVcbiAgICB3aGlsZSAoY29udGFpbmVyLmxhc3RDaGlsZCkge1xuICAgICAgY29udGFpbmVyLnJlbW92ZUNoaWxkKGNvbnRhaW5lci5sYXN0Q2hpbGQpO1xuICAgIH1cbiAgfSxcblxuICAvKipcbiAgICogRmluZHMgdGhlIGNvbnRhaW5lciBET00gZWxlbWVudCB0aGF0IGNvbnRhaW5zIFJlYWN0IGNvbXBvbmVudCB0byB3aGljaCB0aGVcbiAgICogc3VwcGxpZWQgRE9NIGBpZGAgYmVsb25ncy5cbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IGlkIFRoZSBJRCBvZiBhbiBlbGVtZW50IHJlbmRlcmVkIGJ5IGEgUmVhY3QgY29tcG9uZW50LlxuICAgKiBAcmV0dXJuIHs/RE9NRWxlbWVudH0gRE9NIGVsZW1lbnQgdGhhdCBjb250YWlucyB0aGUgYGlkYC5cbiAgICovXG4gIGZpbmRSZWFjdENvbnRhaW5lckZvcklEOiBmdW5jdGlvbihpZCkge1xuICAgIHZhciByZWFjdFJvb3RJRCA9IFJlYWN0SW5zdGFuY2VIYW5kbGVzLmdldFJlYWN0Um9vdElERnJvbU5vZGVJRChpZCk7XG4gICAgdmFyIGNvbnRhaW5lciA9IGNvbnRhaW5lcnNCeVJlYWN0Um9vdElEW3JlYWN0Um9vdElEXTtcblxuICAgIGlmIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYpIHtcbiAgICAgIHZhciByb290RWxlbWVudCA9IHJvb3RFbGVtZW50c0J5UmVhY3RSb290SURbcmVhY3RSb290SURdO1xuICAgICAgaWYgKHJvb3RFbGVtZW50ICYmIHJvb3RFbGVtZW50LnBhcmVudE5vZGUgIT09IGNvbnRhaW5lcikge1xuICAgICAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgICAgIC8vIENhbGwgaW50ZXJuYWxHZXRJRCBoZXJlIGJlY2F1c2UgZ2V0SUQgY2FsbHMgaXNWYWxpZCB3aGljaCBjYWxsc1xuICAgICAgICAgIC8vIGZpbmRSZWFjdENvbnRhaW5lckZvcklEICh0aGlzIGZ1bmN0aW9uKS5cbiAgICAgICAgICBpbnRlcm5hbEdldElEKHJvb3RFbGVtZW50KSA9PT0gcmVhY3RSb290SUQsXG4gICAgICAgICAgJ1JlYWN0TW91bnQ6IFJvb3QgZWxlbWVudCBJRCBkaWZmZXJlZCBmcm9tIHJlYWN0Um9vdElELidcbiAgICAgICAgKSA6IGludmFyaWFudCgvLyBDYWxsIGludGVybmFsR2V0SUQgaGVyZSBiZWNhdXNlIGdldElEIGNhbGxzIGlzVmFsaWQgd2hpY2ggY2FsbHNcbiAgICAgICAgLy8gZmluZFJlYWN0Q29udGFpbmVyRm9ySUQgKHRoaXMgZnVuY3Rpb24pLlxuICAgICAgICBpbnRlcm5hbEdldElEKHJvb3RFbGVtZW50KSA9PT0gcmVhY3RSb290SUQpKTtcblxuICAgICAgICB2YXIgY29udGFpbmVyQ2hpbGQgPSBjb250YWluZXIuZmlyc3RDaGlsZDtcbiAgICAgICAgaWYgKGNvbnRhaW5lckNoaWxkICYmXG4gICAgICAgICAgICByZWFjdFJvb3RJRCA9PT0gaW50ZXJuYWxHZXRJRChjb250YWluZXJDaGlsZCkpIHtcbiAgICAgICAgICAvLyBJZiB0aGUgY29udGFpbmVyIGhhcyBhIG5ldyBjaGlsZCB3aXRoIHRoZSBzYW1lIElEIGFzIHRoZSBvbGRcbiAgICAgICAgICAvLyByb290IGVsZW1lbnQsIHRoZW4gcm9vdEVsZW1lbnRzQnlSZWFjdFJvb3RJRFtyZWFjdFJvb3RJRF0gaXNcbiAgICAgICAgICAvLyBqdXN0IHN0YWxlIGFuZCBuZWVkcyB0byBiZSB1cGRhdGVkLiBUaGUgY2FzZSB0aGF0IGRlc2VydmVzIGFcbiAgICAgICAgICAvLyB3YXJuaW5nIGlzIHdoZW4gdGhlIGNvbnRhaW5lciBpcyBlbXB0eS5cbiAgICAgICAgICByb290RWxlbWVudHNCeVJlYWN0Um9vdElEW3JlYWN0Um9vdElEXSA9IGNvbnRhaW5lckNoaWxkO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGNvbnNvbGUud2FybihcbiAgICAgICAgICAgICdSZWFjdE1vdW50OiBSb290IGVsZW1lbnQgaGFzIGJlZW4gcmVtb3ZlZCBmcm9tIGl0cyBvcmlnaW5hbCAnICtcbiAgICAgICAgICAgICdjb250YWluZXIuIE5ldyBjb250YWluZXI6Jywgcm9vdEVsZW1lbnQucGFyZW50Tm9kZVxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gY29udGFpbmVyO1xuICB9LFxuXG4gIC8qKlxuICAgKiBGaW5kcyBhbiBlbGVtZW50IHJlbmRlcmVkIGJ5IFJlYWN0IHdpdGggdGhlIHN1cHBsaWVkIElELlxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gaWQgSUQgb2YgYSBET00gbm9kZSBpbiB0aGUgUmVhY3QgY29tcG9uZW50LlxuICAgKiBAcmV0dXJuIHtET01FbGVtZW50fSBSb290IERPTSBub2RlIG9mIHRoZSBSZWFjdCBjb21wb25lbnQuXG4gICAqL1xuICBmaW5kUmVhY3ROb2RlQnlJRDogZnVuY3Rpb24oaWQpIHtcbiAgICB2YXIgcmVhY3RSb290ID0gUmVhY3RNb3VudC5maW5kUmVhY3RDb250YWluZXJGb3JJRChpZCk7XG4gICAgcmV0dXJuIFJlYWN0TW91bnQuZmluZENvbXBvbmVudFJvb3QocmVhY3RSb290LCBpZCk7XG4gIH0sXG5cbiAgLyoqXG4gICAqIFRydWUgaWYgdGhlIHN1cHBsaWVkIGBub2RlYCBpcyByZW5kZXJlZCBieSBSZWFjdC5cbiAgICpcbiAgICogQHBhcmFtIHsqfSBub2RlIERPTSBFbGVtZW50IHRvIGNoZWNrLlxuICAgKiBAcmV0dXJuIHtib29sZWFufSBUcnVlIGlmIHRoZSBET00gRWxlbWVudCBhcHBlYXJzIHRvIGJlIHJlbmRlcmVkIGJ5IFJlYWN0LlxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIGlzUmVuZGVyZWRCeVJlYWN0OiBmdW5jdGlvbihub2RlKSB7XG4gICAgaWYgKG5vZGUubm9kZVR5cGUgIT09IDEpIHtcbiAgICAgIC8vIE5vdCBhIERPTUVsZW1lbnQsIHRoZXJlZm9yZSBub3QgYSBSZWFjdCBjb21wb25lbnRcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgdmFyIGlkID0gUmVhY3RNb3VudC5nZXRJRChub2RlKTtcbiAgICByZXR1cm4gaWQgPyBpZC5jaGFyQXQoMCkgPT09IFNFUEFSQVRPUiA6IGZhbHNlO1xuICB9LFxuXG4gIC8qKlxuICAgKiBUcmF2ZXJzZXMgdXAgdGhlIGFuY2VzdG9ycyBvZiB0aGUgc3VwcGxpZWQgbm9kZSB0byBmaW5kIGEgbm9kZSB0aGF0IGlzIGFcbiAgICogRE9NIHJlcHJlc2VudGF0aW9uIG9mIGEgUmVhY3QgY29tcG9uZW50LlxuICAgKlxuICAgKiBAcGFyYW0geyp9IG5vZGVcbiAgICogQHJldHVybiB7P0RPTUV2ZW50VGFyZ2V0fVxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIGdldEZpcnN0UmVhY3RET006IGZ1bmN0aW9uKG5vZGUpIHtcbiAgICB2YXIgY3VycmVudCA9IG5vZGU7XG4gICAgd2hpbGUgKGN1cnJlbnQgJiYgY3VycmVudC5wYXJlbnROb2RlICE9PSBjdXJyZW50KSB7XG4gICAgICBpZiAoUmVhY3RNb3VudC5pc1JlbmRlcmVkQnlSZWFjdChjdXJyZW50KSkge1xuICAgICAgICByZXR1cm4gY3VycmVudDtcbiAgICAgIH1cbiAgICAgIGN1cnJlbnQgPSBjdXJyZW50LnBhcmVudE5vZGU7XG4gICAgfVxuICAgIHJldHVybiBudWxsO1xuICB9LFxuXG4gIC8qKlxuICAgKiBGaW5kcyBhIG5vZGUgd2l0aCB0aGUgc3VwcGxpZWQgYHRhcmdldElEYCBpbnNpZGUgb2YgdGhlIHN1cHBsaWVkXG4gICAqIGBhbmNlc3Rvck5vZGVgLiAgRXhwbG9pdHMgdGhlIElEIG5hbWluZyBzY2hlbWUgdG8gcGVyZm9ybSB0aGUgc2VhcmNoXG4gICAqIHF1aWNrbHkuXG4gICAqXG4gICAqIEBwYXJhbSB7RE9NRXZlbnRUYXJnZXR9IGFuY2VzdG9yTm9kZSBTZWFyY2ggZnJvbSB0aGlzIHJvb3QuXG4gICAqIEBwYXJhcm0ge3N0cmluZ30gdGFyZ2V0SUQgSUQgb2YgdGhlIERPTSByZXByZXNlbnRhdGlvbiBvZiB0aGUgY29tcG9uZW50LlxuICAgKiBAcmV0dXJuIHtET01FdmVudFRhcmdldH0gRE9NIG5vZGUgd2l0aCB0aGUgc3VwcGxpZWQgYHRhcmdldElEYC5cbiAgICogQGludGVybmFsXG4gICAqL1xuICBmaW5kQ29tcG9uZW50Um9vdDogZnVuY3Rpb24oYW5jZXN0b3JOb2RlLCB0YXJnZXRJRCkge1xuICAgIHZhciBmaXJzdENoaWxkcmVuID0gZmluZENvbXBvbmVudFJvb3RSZXVzYWJsZUFycmF5O1xuICAgIHZhciBjaGlsZEluZGV4ID0gMDtcblxuICAgIHZhciBkZWVwZXN0QW5jZXN0b3IgPSBmaW5kRGVlcGVzdENhY2hlZEFuY2VzdG9yKHRhcmdldElEKSB8fCBhbmNlc3Rvck5vZGU7XG5cbiAgICBmaXJzdENoaWxkcmVuWzBdID0gZGVlcGVzdEFuY2VzdG9yLmZpcnN0Q2hpbGQ7XG4gICAgZmlyc3RDaGlsZHJlbi5sZW5ndGggPSAxO1xuXG4gICAgd2hpbGUgKGNoaWxkSW5kZXggPCBmaXJzdENoaWxkcmVuLmxlbmd0aCkge1xuICAgICAgdmFyIGNoaWxkID0gZmlyc3RDaGlsZHJlbltjaGlsZEluZGV4KytdO1xuICAgICAgdmFyIHRhcmdldENoaWxkO1xuXG4gICAgICB3aGlsZSAoY2hpbGQpIHtcbiAgICAgICAgdmFyIGNoaWxkSUQgPSBSZWFjdE1vdW50LmdldElEKGNoaWxkKTtcbiAgICAgICAgaWYgKGNoaWxkSUQpIHtcbiAgICAgICAgICAvLyBFdmVuIGlmIHdlIGZpbmQgdGhlIG5vZGUgd2UncmUgbG9va2luZyBmb3IsIHdlIGZpbmlzaCBsb29waW5nXG4gICAgICAgICAgLy8gdGhyb3VnaCBpdHMgc2libGluZ3MgdG8gZW5zdXJlIHRoZXkncmUgY2FjaGVkIHNvIHRoYXQgd2UgZG9uJ3QgaGF2ZVxuICAgICAgICAgIC8vIHRvIHJldmlzaXQgdGhpcyBub2RlIGFnYWluLiBPdGhlcndpc2UsIHdlIG1ha2Ugbl4yIGNhbGxzIHRvIGdldElEXG4gICAgICAgICAgLy8gd2hlbiB2aXNpdGluZyB0aGUgbWFueSBjaGlsZHJlbiBvZiBhIHNpbmdsZSBub2RlIGluIG9yZGVyLlxuXG4gICAgICAgICAgaWYgKHRhcmdldElEID09PSBjaGlsZElEKSB7XG4gICAgICAgICAgICB0YXJnZXRDaGlsZCA9IGNoaWxkO1xuICAgICAgICAgIH0gZWxzZSBpZiAoUmVhY3RJbnN0YW5jZUhhbmRsZXMuaXNBbmNlc3RvcklET2YoY2hpbGRJRCwgdGFyZ2V0SUQpKSB7XG4gICAgICAgICAgICAvLyBJZiB3ZSBmaW5kIGEgY2hpbGQgd2hvc2UgSUQgaXMgYW4gYW5jZXN0b3Igb2YgdGhlIGdpdmVuIElELFxuICAgICAgICAgICAgLy8gdGhlbiB3ZSBjYW4gYmUgc3VyZSB0aGF0IHdlIG9ubHkgd2FudCB0byBzZWFyY2ggdGhlIHN1YnRyZWVcbiAgICAgICAgICAgIC8vIHJvb3RlZCBhdCB0aGlzIGNoaWxkLCBzbyB3ZSBjYW4gdGhyb3cgb3V0IHRoZSByZXN0IG9mIHRoZVxuICAgICAgICAgICAgLy8gc2VhcmNoIHN0YXRlLlxuICAgICAgICAgICAgZmlyc3RDaGlsZHJlbi5sZW5ndGggPSBjaGlsZEluZGV4ID0gMDtcbiAgICAgICAgICAgIGZpcnN0Q2hpbGRyZW4ucHVzaChjaGlsZC5maXJzdENoaWxkKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAvLyBJZiB0aGlzIGNoaWxkIGhhZCBubyBJRCwgdGhlbiB0aGVyZSdzIGEgY2hhbmNlIHRoYXQgaXQgd2FzXG4gICAgICAgICAgLy8gaW5qZWN0ZWQgYXV0b21hdGljYWxseSBieSB0aGUgYnJvd3NlciwgYXMgd2hlbiBhIGA8dGFibGU+YFxuICAgICAgICAgIC8vIGVsZW1lbnQgc3Byb3V0cyBhbiBleHRyYSBgPHRib2R5PmAgY2hpbGQgYXMgYSBzaWRlIGVmZmVjdCBvZlxuICAgICAgICAgIC8vIGAuaW5uZXJIVE1MYCBwYXJzaW5nLiBPcHRpbWlzdGljYWxseSBjb250aW51ZSBkb3duIHRoaXNcbiAgICAgICAgICAvLyBicmFuY2gsIGJ1dCBub3QgYmVmb3JlIGV4YW1pbmluZyB0aGUgb3RoZXIgc2libGluZ3MuXG4gICAgICAgICAgZmlyc3RDaGlsZHJlbi5wdXNoKGNoaWxkLmZpcnN0Q2hpbGQpO1xuICAgICAgICB9XG5cbiAgICAgICAgY2hpbGQgPSBjaGlsZC5uZXh0U2libGluZztcbiAgICAgIH1cblxuICAgICAgaWYgKHRhcmdldENoaWxkKSB7XG4gICAgICAgIC8vIEVtcHR5aW5nIGZpcnN0Q2hpbGRyZW4vZmluZENvbXBvbmVudFJvb3RSZXVzYWJsZUFycmF5IGlzXG4gICAgICAgIC8vIG5vdCBuZWNlc3NhcnkgZm9yIGNvcnJlY3RuZXNzLCBidXQgaXQgaGVscHMgdGhlIEdDIHJlY2xhaW1cbiAgICAgICAgLy8gYW55IG5vZGVzIHRoYXQgd2VyZSBsZWZ0IGF0IHRoZSBlbmQgb2YgdGhlIHNlYXJjaC5cbiAgICAgICAgZmlyc3RDaGlsZHJlbi5sZW5ndGggPSAwO1xuXG4gICAgICAgIHJldHVybiB0YXJnZXRDaGlsZDtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBmaXJzdENoaWxkcmVuLmxlbmd0aCA9IDA7XG5cbiAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgZmFsc2UsXG4gICAgICAnZmluZENvbXBvbmVudFJvb3QoLi4uLCAlcyk6IFVuYWJsZSB0byBmaW5kIGVsZW1lbnQuIFRoaXMgcHJvYmFibHkgJyArXG4gICAgICAnbWVhbnMgdGhlIERPTSB3YXMgdW5leHBlY3RlZGx5IG11dGF0ZWQgKGUuZy4sIGJ5IHRoZSBicm93c2VyKSwgJyArXG4gICAgICAndXN1YWxseSBkdWUgdG8gZm9yZ2V0dGluZyBhIDx0Ym9keT4gd2hlbiB1c2luZyB0YWJsZXMsIG5lc3RpbmcgdGFncyAnICtcbiAgICAgICdsaWtlIDxmb3JtPiwgPHA+LCBvciA8YT4sIG9yIHVzaW5nIG5vbi1TVkcgZWxlbWVudHMgaW4gYW4gPHN2Zz4gJyArXG4gICAgICAncGFyZW50LiAnICtcbiAgICAgICdUcnkgaW5zcGVjdGluZyB0aGUgY2hpbGQgbm9kZXMgb2YgdGhlIGVsZW1lbnQgd2l0aCBSZWFjdCBJRCBgJXNgLicsXG4gICAgICB0YXJnZXRJRCxcbiAgICAgIFJlYWN0TW91bnQuZ2V0SUQoYW5jZXN0b3JOb2RlKVxuICAgICkgOiBpbnZhcmlhbnQoZmFsc2UpKTtcbiAgfSxcblxuXG4gIC8qKlxuICAgKiBSZWFjdCBJRCB1dGlsaXRpZXMuXG4gICAqL1xuXG4gIGdldFJlYWN0Um9vdElEOiBnZXRSZWFjdFJvb3RJRCxcblxuICBnZXRJRDogZ2V0SUQsXG5cbiAgc2V0SUQ6IHNldElELFxuXG4gIGdldE5vZGU6IGdldE5vZGUsXG5cbiAgcHVyZ2VJRDogcHVyZ2VJRFxufTtcblxuLy8gRGVwcmVjYXRpb25zIChyZW1vdmUgZm9yIDAuMTMpXG5SZWFjdE1vdW50LnJlbmRlckNvbXBvbmVudCA9IGRlcHJlY2F0ZWQoXG4gICdSZWFjdE1vdW50JyxcbiAgJ3JlbmRlckNvbXBvbmVudCcsXG4gICdyZW5kZXInLFxuICB0aGlzLFxuICBSZWFjdE1vdW50LnJlbmRlclxuKTtcblxubW9kdWxlLmV4cG9ydHMgPSBSZWFjdE1vdW50O1xuXG59KS5jYWxsKHRoaXMscmVxdWlyZSgnX3Byb2Nlc3MnKSkiLCIvKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgUmVhY3RNdWx0aUNoaWxkXG4gKiBAdHlwZWNoZWNrcyBzdGF0aWMtb25seVxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgUmVhY3RDb21wb25lbnQgPSByZXF1aXJlKFwiLi9SZWFjdENvbXBvbmVudFwiKTtcbnZhciBSZWFjdE11bHRpQ2hpbGRVcGRhdGVUeXBlcyA9IHJlcXVpcmUoXCIuL1JlYWN0TXVsdGlDaGlsZFVwZGF0ZVR5cGVzXCIpO1xuXG52YXIgZmxhdHRlbkNoaWxkcmVuID0gcmVxdWlyZShcIi4vZmxhdHRlbkNoaWxkcmVuXCIpO1xudmFyIGluc3RhbnRpYXRlUmVhY3RDb21wb25lbnQgPSByZXF1aXJlKFwiLi9pbnN0YW50aWF0ZVJlYWN0Q29tcG9uZW50XCIpO1xudmFyIHNob3VsZFVwZGF0ZVJlYWN0Q29tcG9uZW50ID0gcmVxdWlyZShcIi4vc2hvdWxkVXBkYXRlUmVhY3RDb21wb25lbnRcIik7XG5cbi8qKlxuICogVXBkYXRpbmcgY2hpbGRyZW4gb2YgYSBjb21wb25lbnQgbWF5IHRyaWdnZXIgcmVjdXJzaXZlIHVwZGF0ZXMuIFRoZSBkZXB0aCBpc1xuICogdXNlZCB0byBiYXRjaCByZWN1cnNpdmUgdXBkYXRlcyB0byByZW5kZXIgbWFya3VwIG1vcmUgZWZmaWNpZW50bHkuXG4gKlxuICogQHR5cGUge251bWJlcn1cbiAqIEBwcml2YXRlXG4gKi9cbnZhciB1cGRhdGVEZXB0aCA9IDA7XG5cbi8qKlxuICogUXVldWUgb2YgdXBkYXRlIGNvbmZpZ3VyYXRpb24gb2JqZWN0cy5cbiAqXG4gKiBFYWNoIG9iamVjdCBoYXMgYSBgdHlwZWAgcHJvcGVydHkgdGhhdCBpcyBpbiBgUmVhY3RNdWx0aUNoaWxkVXBkYXRlVHlwZXNgLlxuICpcbiAqIEB0eXBlIHthcnJheTxvYmplY3Q+fVxuICogQHByaXZhdGVcbiAqL1xudmFyIHVwZGF0ZVF1ZXVlID0gW107XG5cbi8qKlxuICogUXVldWUgb2YgbWFya3VwIHRvIGJlIHJlbmRlcmVkLlxuICpcbiAqIEB0eXBlIHthcnJheTxzdHJpbmc+fVxuICogQHByaXZhdGVcbiAqL1xudmFyIG1hcmt1cFF1ZXVlID0gW107XG5cbi8qKlxuICogRW5xdWV1ZXMgbWFya3VwIHRvIGJlIHJlbmRlcmVkIGFuZCBpbnNlcnRlZCBhdCBhIHN1cHBsaWVkIGluZGV4LlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXJlbnRJRCBJRCBvZiB0aGUgcGFyZW50IGNvbXBvbmVudC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBtYXJrdXAgTWFya3VwIHRoYXQgcmVuZGVycyBpbnRvIGFuIGVsZW1lbnQuXG4gKiBAcGFyYW0ge251bWJlcn0gdG9JbmRleCBEZXN0aW5hdGlvbiBpbmRleC5cbiAqIEBwcml2YXRlXG4gKi9cbmZ1bmN0aW9uIGVucXVldWVNYXJrdXAocGFyZW50SUQsIG1hcmt1cCwgdG9JbmRleCkge1xuICAvLyBOT1RFOiBOdWxsIHZhbHVlcyByZWR1Y2UgaGlkZGVuIGNsYXNzZXMuXG4gIHVwZGF0ZVF1ZXVlLnB1c2goe1xuICAgIHBhcmVudElEOiBwYXJlbnRJRCxcbiAgICBwYXJlbnROb2RlOiBudWxsLFxuICAgIHR5cGU6IFJlYWN0TXVsdGlDaGlsZFVwZGF0ZVR5cGVzLklOU0VSVF9NQVJLVVAsXG4gICAgbWFya3VwSW5kZXg6IG1hcmt1cFF1ZXVlLnB1c2gobWFya3VwKSAtIDEsXG4gICAgdGV4dENvbnRlbnQ6IG51bGwsXG4gICAgZnJvbUluZGV4OiBudWxsLFxuICAgIHRvSW5kZXg6IHRvSW5kZXhcbiAgfSk7XG59XG5cbi8qKlxuICogRW5xdWV1ZXMgbW92aW5nIGFuIGV4aXN0aW5nIGVsZW1lbnQgdG8gYW5vdGhlciBpbmRleC5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gcGFyZW50SUQgSUQgb2YgdGhlIHBhcmVudCBjb21wb25lbnQuXG4gKiBAcGFyYW0ge251bWJlcn0gZnJvbUluZGV4IFNvdXJjZSBpbmRleCBvZiB0aGUgZXhpc3RpbmcgZWxlbWVudC5cbiAqIEBwYXJhbSB7bnVtYmVyfSB0b0luZGV4IERlc3RpbmF0aW9uIGluZGV4IG9mIHRoZSBlbGVtZW50LlxuICogQHByaXZhdGVcbiAqL1xuZnVuY3Rpb24gZW5xdWV1ZU1vdmUocGFyZW50SUQsIGZyb21JbmRleCwgdG9JbmRleCkge1xuICAvLyBOT1RFOiBOdWxsIHZhbHVlcyByZWR1Y2UgaGlkZGVuIGNsYXNzZXMuXG4gIHVwZGF0ZVF1ZXVlLnB1c2goe1xuICAgIHBhcmVudElEOiBwYXJlbnRJRCxcbiAgICBwYXJlbnROb2RlOiBudWxsLFxuICAgIHR5cGU6IFJlYWN0TXVsdGlDaGlsZFVwZGF0ZVR5cGVzLk1PVkVfRVhJU1RJTkcsXG4gICAgbWFya3VwSW5kZXg6IG51bGwsXG4gICAgdGV4dENvbnRlbnQ6IG51bGwsXG4gICAgZnJvbUluZGV4OiBmcm9tSW5kZXgsXG4gICAgdG9JbmRleDogdG9JbmRleFxuICB9KTtcbn1cblxuLyoqXG4gKiBFbnF1ZXVlcyByZW1vdmluZyBhbiBlbGVtZW50IGF0IGFuIGluZGV4LlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXJlbnRJRCBJRCBvZiB0aGUgcGFyZW50IGNvbXBvbmVudC5cbiAqIEBwYXJhbSB7bnVtYmVyfSBmcm9tSW5kZXggSW5kZXggb2YgdGhlIGVsZW1lbnQgdG8gcmVtb3ZlLlxuICogQHByaXZhdGVcbiAqL1xuZnVuY3Rpb24gZW5xdWV1ZVJlbW92ZShwYXJlbnRJRCwgZnJvbUluZGV4KSB7XG4gIC8vIE5PVEU6IE51bGwgdmFsdWVzIHJlZHVjZSBoaWRkZW4gY2xhc3Nlcy5cbiAgdXBkYXRlUXVldWUucHVzaCh7XG4gICAgcGFyZW50SUQ6IHBhcmVudElELFxuICAgIHBhcmVudE5vZGU6IG51bGwsXG4gICAgdHlwZTogUmVhY3RNdWx0aUNoaWxkVXBkYXRlVHlwZXMuUkVNT1ZFX05PREUsXG4gICAgbWFya3VwSW5kZXg6IG51bGwsXG4gICAgdGV4dENvbnRlbnQ6IG51bGwsXG4gICAgZnJvbUluZGV4OiBmcm9tSW5kZXgsXG4gICAgdG9JbmRleDogbnVsbFxuICB9KTtcbn1cblxuLyoqXG4gKiBFbnF1ZXVlcyBzZXR0aW5nIHRoZSB0ZXh0IGNvbnRlbnQuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IHBhcmVudElEIElEIG9mIHRoZSBwYXJlbnQgY29tcG9uZW50LlxuICogQHBhcmFtIHtzdHJpbmd9IHRleHRDb250ZW50IFRleHQgY29udGVudCB0byBzZXQuXG4gKiBAcHJpdmF0ZVxuICovXG5mdW5jdGlvbiBlbnF1ZXVlVGV4dENvbnRlbnQocGFyZW50SUQsIHRleHRDb250ZW50KSB7XG4gIC8vIE5PVEU6IE51bGwgdmFsdWVzIHJlZHVjZSBoaWRkZW4gY2xhc3Nlcy5cbiAgdXBkYXRlUXVldWUucHVzaCh7XG4gICAgcGFyZW50SUQ6IHBhcmVudElELFxuICAgIHBhcmVudE5vZGU6IG51bGwsXG4gICAgdHlwZTogUmVhY3RNdWx0aUNoaWxkVXBkYXRlVHlwZXMuVEVYVF9DT05URU5ULFxuICAgIG1hcmt1cEluZGV4OiBudWxsLFxuICAgIHRleHRDb250ZW50OiB0ZXh0Q29udGVudCxcbiAgICBmcm9tSW5kZXg6IG51bGwsXG4gICAgdG9JbmRleDogbnVsbFxuICB9KTtcbn1cblxuLyoqXG4gKiBQcm9jZXNzZXMgYW55IGVucXVldWVkIHVwZGF0ZXMuXG4gKlxuICogQHByaXZhdGVcbiAqL1xuZnVuY3Rpb24gcHJvY2Vzc1F1ZXVlKCkge1xuICBpZiAodXBkYXRlUXVldWUubGVuZ3RoKSB7XG4gICAgUmVhY3RDb21wb25lbnQuQmFja2VuZElET3BlcmF0aW9ucy5kYW5nZXJvdXNseVByb2Nlc3NDaGlsZHJlblVwZGF0ZXMoXG4gICAgICB1cGRhdGVRdWV1ZSxcbiAgICAgIG1hcmt1cFF1ZXVlXG4gICAgKTtcbiAgICBjbGVhclF1ZXVlKCk7XG4gIH1cbn1cblxuLyoqXG4gKiBDbGVhcnMgYW55IGVucXVldWVkIHVwZGF0ZXMuXG4gKlxuICogQHByaXZhdGVcbiAqL1xuZnVuY3Rpb24gY2xlYXJRdWV1ZSgpIHtcbiAgdXBkYXRlUXVldWUubGVuZ3RoID0gMDtcbiAgbWFya3VwUXVldWUubGVuZ3RoID0gMDtcbn1cblxuLyoqXG4gKiBSZWFjdE11bHRpQ2hpbGQgYXJlIGNhcGFibGUgb2YgcmVjb25jaWxpbmcgbXVsdGlwbGUgY2hpbGRyZW4uXG4gKlxuICogQGNsYXNzIFJlYWN0TXVsdGlDaGlsZFxuICogQGludGVybmFsXG4gKi9cbnZhciBSZWFjdE11bHRpQ2hpbGQgPSB7XG5cbiAgLyoqXG4gICAqIFByb3ZpZGVzIGNvbW1vbiBmdW5jdGlvbmFsaXR5IGZvciBjb21wb25lbnRzIHRoYXQgbXVzdCByZWNvbmNpbGUgbXVsdGlwbGVcbiAgICogY2hpbGRyZW4uIFRoaXMgaXMgdXNlZCBieSBgUmVhY3RET01Db21wb25lbnRgIHRvIG1vdW50LCB1cGRhdGUsIGFuZFxuICAgKiB1bm1vdW50IGNoaWxkIGNvbXBvbmVudHMuXG4gICAqXG4gICAqIEBsZW5kcyB7UmVhY3RNdWx0aUNoaWxkLnByb3RvdHlwZX1cbiAgICovXG4gIE1peGluOiB7XG5cbiAgICAvKipcbiAgICAgKiBHZW5lcmF0ZXMgYSBcIm1vdW50IGltYWdlXCIgZm9yIGVhY2ggb2YgdGhlIHN1cHBsaWVkIGNoaWxkcmVuLiBJbiB0aGUgY2FzZVxuICAgICAqIG9mIGBSZWFjdERPTUNvbXBvbmVudGAsIGEgbW91bnQgaW1hZ2UgaXMgYSBzdHJpbmcgb2YgbWFya3VwLlxuICAgICAqXG4gICAgICogQHBhcmFtIHs/b2JqZWN0fSBuZXN0ZWRDaGlsZHJlbiBOZXN0ZWQgY2hpbGQgbWFwcy5cbiAgICAgKiBAcmV0dXJuIHthcnJheX0gQW4gYXJyYXkgb2YgbW91bnRlZCByZXByZXNlbnRhdGlvbnMuXG4gICAgICogQGludGVybmFsXG4gICAgICovXG4gICAgbW91bnRDaGlsZHJlbjogZnVuY3Rpb24obmVzdGVkQ2hpbGRyZW4sIHRyYW5zYWN0aW9uKSB7XG4gICAgICB2YXIgY2hpbGRyZW4gPSBmbGF0dGVuQ2hpbGRyZW4obmVzdGVkQ2hpbGRyZW4pO1xuICAgICAgdmFyIG1vdW50SW1hZ2VzID0gW107XG4gICAgICB2YXIgaW5kZXggPSAwO1xuICAgICAgdGhpcy5fcmVuZGVyZWRDaGlsZHJlbiA9IGNoaWxkcmVuO1xuICAgICAgZm9yICh2YXIgbmFtZSBpbiBjaGlsZHJlbikge1xuICAgICAgICB2YXIgY2hpbGQgPSBjaGlsZHJlbltuYW1lXTtcbiAgICAgICAgaWYgKGNoaWxkcmVuLmhhc093blByb3BlcnR5KG5hbWUpKSB7XG4gICAgICAgICAgLy8gVGhlIHJlbmRlcmVkIGNoaWxkcmVuIG11c3QgYmUgdHVybmVkIGludG8gaW5zdGFuY2VzIGFzIHRoZXkncmVcbiAgICAgICAgICAvLyBtb3VudGVkLlxuICAgICAgICAgIHZhciBjaGlsZEluc3RhbmNlID0gaW5zdGFudGlhdGVSZWFjdENvbXBvbmVudChjaGlsZCwgbnVsbCk7XG4gICAgICAgICAgY2hpbGRyZW5bbmFtZV0gPSBjaGlsZEluc3RhbmNlO1xuICAgICAgICAgIC8vIElubGluZWQgZm9yIHBlcmZvcm1hbmNlLCBzZWUgYFJlYWN0SW5zdGFuY2VIYW5kbGVzLmNyZWF0ZVJlYWN0SURgLlxuICAgICAgICAgIHZhciByb290SUQgPSB0aGlzLl9yb290Tm9kZUlEICsgbmFtZTtcbiAgICAgICAgICB2YXIgbW91bnRJbWFnZSA9IGNoaWxkSW5zdGFuY2UubW91bnRDb21wb25lbnQoXG4gICAgICAgICAgICByb290SUQsXG4gICAgICAgICAgICB0cmFuc2FjdGlvbixcbiAgICAgICAgICAgIHRoaXMuX21vdW50RGVwdGggKyAxXG4gICAgICAgICAgKTtcbiAgICAgICAgICBjaGlsZEluc3RhbmNlLl9tb3VudEluZGV4ID0gaW5kZXg7XG4gICAgICAgICAgbW91bnRJbWFnZXMucHVzaChtb3VudEltYWdlKTtcbiAgICAgICAgICBpbmRleCsrO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICByZXR1cm4gbW91bnRJbWFnZXM7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFJlcGxhY2VzIGFueSByZW5kZXJlZCBjaGlsZHJlbiB3aXRoIGEgdGV4dCBjb250ZW50IHN0cmluZy5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBuZXh0Q29udGVudCBTdHJpbmcgb2YgY29udGVudC5cbiAgICAgKiBAaW50ZXJuYWxcbiAgICAgKi9cbiAgICB1cGRhdGVUZXh0Q29udGVudDogZnVuY3Rpb24obmV4dENvbnRlbnQpIHtcbiAgICAgIHVwZGF0ZURlcHRoKys7XG4gICAgICB2YXIgZXJyb3JUaHJvd24gPSB0cnVlO1xuICAgICAgdHJ5IHtcbiAgICAgICAgdmFyIHByZXZDaGlsZHJlbiA9IHRoaXMuX3JlbmRlcmVkQ2hpbGRyZW47XG4gICAgICAgIC8vIFJlbW92ZSBhbnkgcmVuZGVyZWQgY2hpbGRyZW4uXG4gICAgICAgIGZvciAodmFyIG5hbWUgaW4gcHJldkNoaWxkcmVuKSB7XG4gICAgICAgICAgaWYgKHByZXZDaGlsZHJlbi5oYXNPd25Qcm9wZXJ0eShuYW1lKSkge1xuICAgICAgICAgICAgdGhpcy5fdW5tb3VudENoaWxkQnlOYW1lKHByZXZDaGlsZHJlbltuYW1lXSwgbmFtZSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIC8vIFNldCBuZXcgdGV4dCBjb250ZW50LlxuICAgICAgICB0aGlzLnNldFRleHRDb250ZW50KG5leHRDb250ZW50KTtcbiAgICAgICAgZXJyb3JUaHJvd24gPSBmYWxzZTtcbiAgICAgIH0gZmluYWxseSB7XG4gICAgICAgIHVwZGF0ZURlcHRoLS07XG4gICAgICAgIGlmICghdXBkYXRlRGVwdGgpIHtcbiAgICAgICAgICBlcnJvclRocm93biA/IGNsZWFyUXVldWUoKSA6IHByb2Nlc3NRdWV1ZSgpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFVwZGF0ZXMgdGhlIHJlbmRlcmVkIGNoaWxkcmVuIHdpdGggbmV3IGNoaWxkcmVuLlxuICAgICAqXG4gICAgICogQHBhcmFtIHs/b2JqZWN0fSBuZXh0TmVzdGVkQ2hpbGRyZW4gTmVzdGVkIGNoaWxkIG1hcHMuXG4gICAgICogQHBhcmFtIHtSZWFjdFJlY29uY2lsZVRyYW5zYWN0aW9ufSB0cmFuc2FjdGlvblxuICAgICAqIEBpbnRlcm5hbFxuICAgICAqL1xuICAgIHVwZGF0ZUNoaWxkcmVuOiBmdW5jdGlvbihuZXh0TmVzdGVkQ2hpbGRyZW4sIHRyYW5zYWN0aW9uKSB7XG4gICAgICB1cGRhdGVEZXB0aCsrO1xuICAgICAgdmFyIGVycm9yVGhyb3duID0gdHJ1ZTtcbiAgICAgIHRyeSB7XG4gICAgICAgIHRoaXMuX3VwZGF0ZUNoaWxkcmVuKG5leHROZXN0ZWRDaGlsZHJlbiwgdHJhbnNhY3Rpb24pO1xuICAgICAgICBlcnJvclRocm93biA9IGZhbHNlO1xuICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgdXBkYXRlRGVwdGgtLTtcbiAgICAgICAgaWYgKCF1cGRhdGVEZXB0aCkge1xuICAgICAgICAgIGVycm9yVGhyb3duID8gY2xlYXJRdWV1ZSgpIDogcHJvY2Vzc1F1ZXVlKCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogSW1wcm92ZSBwZXJmb3JtYW5jZSBieSBpc29sYXRpbmcgdGhpcyBob3QgY29kZSBwYXRoIGZyb20gdGhlIHRyeS9jYXRjaFxuICAgICAqIGJsb2NrIGluIGB1cGRhdGVDaGlsZHJlbmAuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gez9vYmplY3R9IG5leHROZXN0ZWRDaGlsZHJlbiBOZXN0ZWQgY2hpbGQgbWFwcy5cbiAgICAgKiBAcGFyYW0ge1JlYWN0UmVjb25jaWxlVHJhbnNhY3Rpb259IHRyYW5zYWN0aW9uXG4gICAgICogQGZpbmFsXG4gICAgICogQHByb3RlY3RlZFxuICAgICAqL1xuICAgIF91cGRhdGVDaGlsZHJlbjogZnVuY3Rpb24obmV4dE5lc3RlZENoaWxkcmVuLCB0cmFuc2FjdGlvbikge1xuICAgICAgdmFyIG5leHRDaGlsZHJlbiA9IGZsYXR0ZW5DaGlsZHJlbihuZXh0TmVzdGVkQ2hpbGRyZW4pO1xuICAgICAgdmFyIHByZXZDaGlsZHJlbiA9IHRoaXMuX3JlbmRlcmVkQ2hpbGRyZW47XG4gICAgICBpZiAoIW5leHRDaGlsZHJlbiAmJiAhcHJldkNoaWxkcmVuKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIHZhciBuYW1lO1xuICAgICAgLy8gYG5leHRJbmRleGAgd2lsbCBpbmNyZW1lbnQgZm9yIGVhY2ggY2hpbGQgaW4gYG5leHRDaGlsZHJlbmAsIGJ1dFxuICAgICAgLy8gYGxhc3RJbmRleGAgd2lsbCBiZSB0aGUgbGFzdCBpbmRleCB2aXNpdGVkIGluIGBwcmV2Q2hpbGRyZW5gLlxuICAgICAgdmFyIGxhc3RJbmRleCA9IDA7XG4gICAgICB2YXIgbmV4dEluZGV4ID0gMDtcbiAgICAgIGZvciAobmFtZSBpbiBuZXh0Q2hpbGRyZW4pIHtcbiAgICAgICAgaWYgKCFuZXh0Q2hpbGRyZW4uaGFzT3duUHJvcGVydHkobmFtZSkpIHtcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuICAgICAgICB2YXIgcHJldkNoaWxkID0gcHJldkNoaWxkcmVuICYmIHByZXZDaGlsZHJlbltuYW1lXTtcbiAgICAgICAgdmFyIHByZXZFbGVtZW50ID0gcHJldkNoaWxkICYmIHByZXZDaGlsZC5fY3VycmVudEVsZW1lbnQ7XG4gICAgICAgIHZhciBuZXh0RWxlbWVudCA9IG5leHRDaGlsZHJlbltuYW1lXTtcbiAgICAgICAgaWYgKHNob3VsZFVwZGF0ZVJlYWN0Q29tcG9uZW50KHByZXZFbGVtZW50LCBuZXh0RWxlbWVudCkpIHtcbiAgICAgICAgICB0aGlzLm1vdmVDaGlsZChwcmV2Q2hpbGQsIG5leHRJbmRleCwgbGFzdEluZGV4KTtcbiAgICAgICAgICBsYXN0SW5kZXggPSBNYXRoLm1heChwcmV2Q2hpbGQuX21vdW50SW5kZXgsIGxhc3RJbmRleCk7XG4gICAgICAgICAgcHJldkNoaWxkLnJlY2VpdmVDb21wb25lbnQobmV4dEVsZW1lbnQsIHRyYW5zYWN0aW9uKTtcbiAgICAgICAgICBwcmV2Q2hpbGQuX21vdW50SW5kZXggPSBuZXh0SW5kZXg7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgaWYgKHByZXZDaGlsZCkge1xuICAgICAgICAgICAgLy8gVXBkYXRlIGBsYXN0SW5kZXhgIGJlZm9yZSBgX21vdW50SW5kZXhgIGdldHMgdW5zZXQgYnkgdW5tb3VudGluZy5cbiAgICAgICAgICAgIGxhc3RJbmRleCA9IE1hdGgubWF4KHByZXZDaGlsZC5fbW91bnRJbmRleCwgbGFzdEluZGV4KTtcbiAgICAgICAgICAgIHRoaXMuX3VubW91bnRDaGlsZEJ5TmFtZShwcmV2Q2hpbGQsIG5hbWUpO1xuICAgICAgICAgIH1cbiAgICAgICAgICAvLyBUaGUgY2hpbGQgbXVzdCBiZSBpbnN0YW50aWF0ZWQgYmVmb3JlIGl0J3MgbW91bnRlZC5cbiAgICAgICAgICB2YXIgbmV4dENoaWxkSW5zdGFuY2UgPSBpbnN0YW50aWF0ZVJlYWN0Q29tcG9uZW50KFxuICAgICAgICAgICAgbmV4dEVsZW1lbnQsXG4gICAgICAgICAgICBudWxsXG4gICAgICAgICAgKTtcbiAgICAgICAgICB0aGlzLl9tb3VudENoaWxkQnlOYW1lQXRJbmRleChcbiAgICAgICAgICAgIG5leHRDaGlsZEluc3RhbmNlLCBuYW1lLCBuZXh0SW5kZXgsIHRyYW5zYWN0aW9uXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgICBuZXh0SW5kZXgrKztcbiAgICAgIH1cbiAgICAgIC8vIFJlbW92ZSBjaGlsZHJlbiB0aGF0IGFyZSBubyBsb25nZXIgcHJlc2VudC5cbiAgICAgIGZvciAobmFtZSBpbiBwcmV2Q2hpbGRyZW4pIHtcbiAgICAgICAgaWYgKHByZXZDaGlsZHJlbi5oYXNPd25Qcm9wZXJ0eShuYW1lKSAmJlxuICAgICAgICAgICAgIShuZXh0Q2hpbGRyZW4gJiYgbmV4dENoaWxkcmVuW25hbWVdKSkge1xuICAgICAgICAgIHRoaXMuX3VubW91bnRDaGlsZEJ5TmFtZShwcmV2Q2hpbGRyZW5bbmFtZV0sIG5hbWUpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFVubW91bnRzIGFsbCByZW5kZXJlZCBjaGlsZHJlbi4gVGhpcyBzaG91bGQgYmUgdXNlZCB0byBjbGVhbiB1cCBjaGlsZHJlblxuICAgICAqIHdoZW4gdGhpcyBjb21wb25lbnQgaXMgdW5tb3VudGVkLlxuICAgICAqXG4gICAgICogQGludGVybmFsXG4gICAgICovXG4gICAgdW5tb3VudENoaWxkcmVuOiBmdW5jdGlvbigpIHtcbiAgICAgIHZhciByZW5kZXJlZENoaWxkcmVuID0gdGhpcy5fcmVuZGVyZWRDaGlsZHJlbjtcbiAgICAgIGZvciAodmFyIG5hbWUgaW4gcmVuZGVyZWRDaGlsZHJlbikge1xuICAgICAgICB2YXIgcmVuZGVyZWRDaGlsZCA9IHJlbmRlcmVkQ2hpbGRyZW5bbmFtZV07XG4gICAgICAgIC8vIFRPRE86IFdoZW4gaXMgdGhpcyBub3QgdHJ1ZT9cbiAgICAgICAgaWYgKHJlbmRlcmVkQ2hpbGQudW5tb3VudENvbXBvbmVudCkge1xuICAgICAgICAgIHJlbmRlcmVkQ2hpbGQudW5tb3VudENvbXBvbmVudCgpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICB0aGlzLl9yZW5kZXJlZENoaWxkcmVuID0gbnVsbDtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogTW92ZXMgYSBjaGlsZCBjb21wb25lbnQgdG8gdGhlIHN1cHBsaWVkIGluZGV4LlxuICAgICAqXG4gICAgICogQHBhcmFtIHtSZWFjdENvbXBvbmVudH0gY2hpbGQgQ29tcG9uZW50IHRvIG1vdmUuXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IHRvSW5kZXggRGVzdGluYXRpb24gaW5kZXggb2YgdGhlIGVsZW1lbnQuXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IGxhc3RJbmRleCBMYXN0IGluZGV4IHZpc2l0ZWQgb2YgdGhlIHNpYmxpbmdzIG9mIGBjaGlsZGAuXG4gICAgICogQHByb3RlY3RlZFxuICAgICAqL1xuICAgIG1vdmVDaGlsZDogZnVuY3Rpb24oY2hpbGQsIHRvSW5kZXgsIGxhc3RJbmRleCkge1xuICAgICAgLy8gSWYgdGhlIGluZGV4IG9mIGBjaGlsZGAgaXMgbGVzcyB0aGFuIGBsYXN0SW5kZXhgLCB0aGVuIGl0IG5lZWRzIHRvXG4gICAgICAvLyBiZSBtb3ZlZC4gT3RoZXJ3aXNlLCB3ZSBkbyBub3QgbmVlZCB0byBtb3ZlIGl0IGJlY2F1c2UgYSBjaGlsZCB3aWxsIGJlXG4gICAgICAvLyBpbnNlcnRlZCBvciBtb3ZlZCBiZWZvcmUgYGNoaWxkYC5cbiAgICAgIGlmIChjaGlsZC5fbW91bnRJbmRleCA8IGxhc3RJbmRleCkge1xuICAgICAgICBlbnF1ZXVlTW92ZSh0aGlzLl9yb290Tm9kZUlELCBjaGlsZC5fbW91bnRJbmRleCwgdG9JbmRleCk7XG4gICAgICB9XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYSBjaGlsZCBjb21wb25lbnQuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge1JlYWN0Q29tcG9uZW50fSBjaGlsZCBDb21wb25lbnQgdG8gY3JlYXRlLlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBtb3VudEltYWdlIE1hcmt1cCB0byBpbnNlcnQuXG4gICAgICogQHByb3RlY3RlZFxuICAgICAqL1xuICAgIGNyZWF0ZUNoaWxkOiBmdW5jdGlvbihjaGlsZCwgbW91bnRJbWFnZSkge1xuICAgICAgZW5xdWV1ZU1hcmt1cCh0aGlzLl9yb290Tm9kZUlELCBtb3VudEltYWdlLCBjaGlsZC5fbW91bnRJbmRleCk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFJlbW92ZXMgYSBjaGlsZCBjb21wb25lbnQuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge1JlYWN0Q29tcG9uZW50fSBjaGlsZCBDaGlsZCB0byByZW1vdmUuXG4gICAgICogQHByb3RlY3RlZFxuICAgICAqL1xuICAgIHJlbW92ZUNoaWxkOiBmdW5jdGlvbihjaGlsZCkge1xuICAgICAgZW5xdWV1ZVJlbW92ZSh0aGlzLl9yb290Tm9kZUlELCBjaGlsZC5fbW91bnRJbmRleCk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFNldHMgdGhpcyB0ZXh0IGNvbnRlbnQgc3RyaW5nLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IHRleHRDb250ZW50IFRleHQgY29udGVudCB0byBzZXQuXG4gICAgICogQHByb3RlY3RlZFxuICAgICAqL1xuICAgIHNldFRleHRDb250ZW50OiBmdW5jdGlvbih0ZXh0Q29udGVudCkge1xuICAgICAgZW5xdWV1ZVRleHRDb250ZW50KHRoaXMuX3Jvb3ROb2RlSUQsIHRleHRDb250ZW50KTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogTW91bnRzIGEgY2hpbGQgd2l0aCB0aGUgc3VwcGxpZWQgbmFtZS5cbiAgICAgKlxuICAgICAqIE5PVEU6IFRoaXMgaXMgcGFydCBvZiBgdXBkYXRlQ2hpbGRyZW5gIGFuZCBpcyBoZXJlIGZvciByZWFkYWJpbGl0eS5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7UmVhY3RDb21wb25lbnR9IGNoaWxkIENvbXBvbmVudCB0byBtb3VudC5cbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gbmFtZSBOYW1lIG9mIHRoZSBjaGlsZC5cbiAgICAgKiBAcGFyYW0ge251bWJlcn0gaW5kZXggSW5kZXggYXQgd2hpY2ggdG8gaW5zZXJ0IHRoZSBjaGlsZC5cbiAgICAgKiBAcGFyYW0ge1JlYWN0UmVjb25jaWxlVHJhbnNhY3Rpb259IHRyYW5zYWN0aW9uXG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICBfbW91bnRDaGlsZEJ5TmFtZUF0SW5kZXg6IGZ1bmN0aW9uKGNoaWxkLCBuYW1lLCBpbmRleCwgdHJhbnNhY3Rpb24pIHtcbiAgICAgIC8vIElubGluZWQgZm9yIHBlcmZvcm1hbmNlLCBzZWUgYFJlYWN0SW5zdGFuY2VIYW5kbGVzLmNyZWF0ZVJlYWN0SURgLlxuICAgICAgdmFyIHJvb3RJRCA9IHRoaXMuX3Jvb3ROb2RlSUQgKyBuYW1lO1xuICAgICAgdmFyIG1vdW50SW1hZ2UgPSBjaGlsZC5tb3VudENvbXBvbmVudChcbiAgICAgICAgcm9vdElELFxuICAgICAgICB0cmFuc2FjdGlvbixcbiAgICAgICAgdGhpcy5fbW91bnREZXB0aCArIDFcbiAgICAgICk7XG4gICAgICBjaGlsZC5fbW91bnRJbmRleCA9IGluZGV4O1xuICAgICAgdGhpcy5jcmVhdGVDaGlsZChjaGlsZCwgbW91bnRJbWFnZSk7XG4gICAgICB0aGlzLl9yZW5kZXJlZENoaWxkcmVuID0gdGhpcy5fcmVuZGVyZWRDaGlsZHJlbiB8fCB7fTtcbiAgICAgIHRoaXMuX3JlbmRlcmVkQ2hpbGRyZW5bbmFtZV0gPSBjaGlsZDtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogVW5tb3VudHMgYSByZW5kZXJlZCBjaGlsZCBieSBuYW1lLlxuICAgICAqXG4gICAgICogTk9URTogVGhpcyBpcyBwYXJ0IG9mIGB1cGRhdGVDaGlsZHJlbmAgYW5kIGlzIGhlcmUgZm9yIHJlYWRhYmlsaXR5LlxuICAgICAqXG4gICAgICogQHBhcmFtIHtSZWFjdENvbXBvbmVudH0gY2hpbGQgQ29tcG9uZW50IHRvIHVubW91bnQuXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IG5hbWUgTmFtZSBvZiB0aGUgY2hpbGQgaW4gYHRoaXMuX3JlbmRlcmVkQ2hpbGRyZW5gLlxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgX3VubW91bnRDaGlsZEJ5TmFtZTogZnVuY3Rpb24oY2hpbGQsIG5hbWUpIHtcbiAgICAgIHRoaXMucmVtb3ZlQ2hpbGQoY2hpbGQpO1xuICAgICAgY2hpbGQuX21vdW50SW5kZXggPSBudWxsO1xuICAgICAgY2hpbGQudW5tb3VudENvbXBvbmVudCgpO1xuICAgICAgZGVsZXRlIHRoaXMuX3JlbmRlcmVkQ2hpbGRyZW5bbmFtZV07XG4gICAgfVxuXG4gIH1cblxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBSZWFjdE11bHRpQ2hpbGQ7XG4iLCIvKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgUmVhY3RNdWx0aUNoaWxkVXBkYXRlVHlwZXNcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIGtleU1pcnJvciA9IHJlcXVpcmUoXCIuL2tleU1pcnJvclwiKTtcblxuLyoqXG4gKiBXaGVuIGEgY29tcG9uZW50J3MgY2hpbGRyZW4gYXJlIHVwZGF0ZWQsIGEgc2VyaWVzIG9mIHVwZGF0ZSBjb25maWd1cmF0aW9uXG4gKiBvYmplY3RzIGFyZSBjcmVhdGVkIGluIG9yZGVyIHRvIGJhdGNoIGFuZCBzZXJpYWxpemUgdGhlIHJlcXVpcmVkIGNoYW5nZXMuXG4gKlxuICogRW51bWVyYXRlcyBhbGwgdGhlIHBvc3NpYmxlIHR5cGVzIG9mIHVwZGF0ZSBjb25maWd1cmF0aW9ucy5cbiAqXG4gKiBAaW50ZXJuYWxcbiAqL1xudmFyIFJlYWN0TXVsdGlDaGlsZFVwZGF0ZVR5cGVzID0ga2V5TWlycm9yKHtcbiAgSU5TRVJUX01BUktVUDogbnVsbCxcbiAgTU9WRV9FWElTVElORzogbnVsbCxcbiAgUkVNT1ZFX05PREU6IG51bGwsXG4gIFRFWFRfQ09OVEVOVDogbnVsbFxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gUmVhY3RNdWx0aUNoaWxkVXBkYXRlVHlwZXM7XG4iLCIoZnVuY3Rpb24gKHByb2Nlc3Mpe1xuLyoqXG4gKiBDb3B5cmlnaHQgMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBSZWFjdE5hdGl2ZUNvbXBvbmVudFxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgYXNzaWduID0gcmVxdWlyZShcIi4vT2JqZWN0LmFzc2lnblwiKTtcbnZhciBpbnZhcmlhbnQgPSByZXF1aXJlKFwiLi9pbnZhcmlhbnRcIik7XG5cbnZhciBnZW5lcmljQ29tcG9uZW50Q2xhc3MgPSBudWxsO1xuLy8gVGhpcyByZWdpc3RyeSBrZWVwcyB0cmFjayBvZiB3cmFwcGVyIGNsYXNzZXMgYXJvdW5kIG5hdGl2ZSB0YWdzXG52YXIgdGFnVG9Db21wb25lbnRDbGFzcyA9IHt9O1xuXG52YXIgUmVhY3ROYXRpdmVDb21wb25lbnRJbmplY3Rpb24gPSB7XG4gIC8vIFRoaXMgYWNjZXB0cyBhIGNsYXNzIHRoYXQgcmVjZWl2ZXMgdGhlIHRhZyBzdHJpbmcuIFRoaXMgaXMgYSBjYXRjaCBhbGxcbiAgLy8gdGhhdCBjYW4gcmVuZGVyIGFueSBraW5kIG9mIHRhZy5cbiAgaW5qZWN0R2VuZXJpY0NvbXBvbmVudENsYXNzOiBmdW5jdGlvbihjb21wb25lbnRDbGFzcykge1xuICAgIGdlbmVyaWNDb21wb25lbnRDbGFzcyA9IGNvbXBvbmVudENsYXNzO1xuICB9LFxuICAvLyBUaGlzIGFjY2VwdHMgYSBrZXllZCBvYmplY3Qgd2l0aCBjbGFzc2VzIGFzIHZhbHVlcy4gRWFjaCBrZXkgcmVwcmVzZW50cyBhXG4gIC8vIHRhZy4gVGhhdCBwYXJ0aWN1bGFyIHRhZyB3aWxsIHVzZSB0aGlzIGNsYXNzIGluc3RlYWQgb2YgdGhlIGdlbmVyaWMgb25lLlxuICBpbmplY3RDb21wb25lbnRDbGFzc2VzOiBmdW5jdGlvbihjb21wb25lbnRDbGFzc2VzKSB7XG4gICAgYXNzaWduKHRhZ1RvQ29tcG9uZW50Q2xhc3MsIGNvbXBvbmVudENsYXNzZXMpO1xuICB9XG59O1xuXG4vKipcbiAqIENyZWF0ZSBhbiBpbnRlcm5hbCBjbGFzcyBmb3IgYSBzcGVjaWZpYyB0YWcuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IHRhZyBUaGUgdGFnIGZvciB3aGljaCB0byBjcmVhdGUgYW4gaW50ZXJuYWwgaW5zdGFuY2UuXG4gKiBAcGFyYW0ge2FueX0gcHJvcHMgVGhlIHByb3BzIHBhc3NlZCB0byB0aGUgaW5zdGFuY2UgY29uc3RydWN0b3IuXG4gKiBAcmV0dXJuIHtSZWFjdENvbXBvbmVudH0gY29tcG9uZW50IFRoZSBpbmplY3RlZCBlbXB0eSBjb21wb25lbnQuXG4gKi9cbmZ1bmN0aW9uIGNyZWF0ZUluc3RhbmNlRm9yVGFnKHRhZywgcHJvcHMsIHBhcmVudFR5cGUpIHtcbiAgdmFyIGNvbXBvbmVudENsYXNzID0gdGFnVG9Db21wb25lbnRDbGFzc1t0YWddO1xuICBpZiAoY29tcG9uZW50Q2xhc3MgPT0gbnVsbCkge1xuICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICBnZW5lcmljQ29tcG9uZW50Q2xhc3MsXG4gICAgICAnVGhlcmUgaXMgbm8gcmVnaXN0ZXJlZCBjb21wb25lbnQgZm9yIHRoZSB0YWcgJXMnLFxuICAgICAgdGFnXG4gICAgKSA6IGludmFyaWFudChnZW5lcmljQ29tcG9uZW50Q2xhc3MpKTtcbiAgICByZXR1cm4gbmV3IGdlbmVyaWNDb21wb25lbnRDbGFzcyh0YWcsIHByb3BzKTtcbiAgfVxuICBpZiAocGFyZW50VHlwZSA9PT0gdGFnKSB7XG4gICAgLy8gQXZvaWQgcmVjdXJzaW9uXG4gICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgIGdlbmVyaWNDb21wb25lbnRDbGFzcyxcbiAgICAgICdUaGVyZSBpcyBubyByZWdpc3RlcmVkIGNvbXBvbmVudCBmb3IgdGhlIHRhZyAlcycsXG4gICAgICB0YWdcbiAgICApIDogaW52YXJpYW50KGdlbmVyaWNDb21wb25lbnRDbGFzcykpO1xuICAgIHJldHVybiBuZXcgZ2VuZXJpY0NvbXBvbmVudENsYXNzKHRhZywgcHJvcHMpO1xuICB9XG4gIC8vIFVud3JhcCBsZWdhY3kgZmFjdG9yaWVzXG4gIHJldHVybiBuZXcgY29tcG9uZW50Q2xhc3MudHlwZShwcm9wcyk7XG59XG5cbnZhciBSZWFjdE5hdGl2ZUNvbXBvbmVudCA9IHtcbiAgY3JlYXRlSW5zdGFuY2VGb3JUYWc6IGNyZWF0ZUluc3RhbmNlRm9yVGFnLFxuICBpbmplY3Rpb246IFJlYWN0TmF0aXZlQ29tcG9uZW50SW5qZWN0aW9uLFxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBSZWFjdE5hdGl2ZUNvbXBvbmVudDtcblxufSkuY2FsbCh0aGlzLHJlcXVpcmUoJ19wcm9jZXNzJykpIiwiKGZ1bmN0aW9uIChwcm9jZXNzKXtcbi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBSZWFjdE93bmVyXG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBlbXB0eU9iamVjdCA9IHJlcXVpcmUoXCIuL2VtcHR5T2JqZWN0XCIpO1xudmFyIGludmFyaWFudCA9IHJlcXVpcmUoXCIuL2ludmFyaWFudFwiKTtcblxuLyoqXG4gKiBSZWFjdE93bmVycyBhcmUgY2FwYWJsZSBvZiBzdG9yaW5nIHJlZmVyZW5jZXMgdG8gb3duZWQgY29tcG9uZW50cy5cbiAqXG4gKiBBbGwgY29tcG9uZW50cyBhcmUgY2FwYWJsZSBvZiAvL2JlaW5nLy8gcmVmZXJlbmNlZCBieSBvd25lciBjb21wb25lbnRzLCBidXRcbiAqIG9ubHkgUmVhY3RPd25lciBjb21wb25lbnRzIGFyZSBjYXBhYmxlIG9mIC8vcmVmZXJlbmNpbmcvLyBvd25lZCBjb21wb25lbnRzLlxuICogVGhlIG5hbWVkIHJlZmVyZW5jZSBpcyBrbm93biBhcyBhIFwicmVmXCIuXG4gKlxuICogUmVmcyBhcmUgYXZhaWxhYmxlIHdoZW4gbW91bnRlZCBhbmQgdXBkYXRlZCBkdXJpbmcgcmVjb25jaWxpYXRpb24uXG4gKlxuICogICB2YXIgTXlDb21wb25lbnQgPSBSZWFjdC5jcmVhdGVDbGFzcyh7XG4gKiAgICAgcmVuZGVyOiBmdW5jdGlvbigpIHtcbiAqICAgICAgIHJldHVybiAoXG4gKiAgICAgICAgIDxkaXYgb25DbGljaz17dGhpcy5oYW5kbGVDbGlja30+XG4gKiAgICAgICAgICAgPEN1c3RvbUNvbXBvbmVudCByZWY9XCJjdXN0b21cIiAvPlxuICogICAgICAgICA8L2Rpdj5cbiAqICAgICAgICk7XG4gKiAgICAgfSxcbiAqICAgICBoYW5kbGVDbGljazogZnVuY3Rpb24oKSB7XG4gKiAgICAgICB0aGlzLnJlZnMuY3VzdG9tLmhhbmRsZUNsaWNrKCk7XG4gKiAgICAgfSxcbiAqICAgICBjb21wb25lbnREaWRNb3VudDogZnVuY3Rpb24oKSB7XG4gKiAgICAgICB0aGlzLnJlZnMuY3VzdG9tLmluaXRpYWxpemUoKTtcbiAqICAgICB9XG4gKiAgIH0pO1xuICpcbiAqIFJlZnMgc2hvdWxkIHJhcmVseSBiZSB1c2VkLiBXaGVuIHJlZnMgYXJlIHVzZWQsIHRoZXkgc2hvdWxkIG9ubHkgYmUgZG9uZSB0b1xuICogY29udHJvbCBkYXRhIHRoYXQgaXMgbm90IGhhbmRsZWQgYnkgUmVhY3QncyBkYXRhIGZsb3cuXG4gKlxuICogQGNsYXNzIFJlYWN0T3duZXJcbiAqL1xudmFyIFJlYWN0T3duZXIgPSB7XG5cbiAgLyoqXG4gICAqIEBwYXJhbSB7P29iamVjdH0gb2JqZWN0XG4gICAqIEByZXR1cm4ge2Jvb2xlYW59IFRydWUgaWYgYG9iamVjdGAgaXMgYSB2YWxpZCBvd25lci5cbiAgICogQGZpbmFsXG4gICAqL1xuICBpc1ZhbGlkT3duZXI6IGZ1bmN0aW9uKG9iamVjdCkge1xuICAgIHJldHVybiAhIShcbiAgICAgIG9iamVjdCAmJlxuICAgICAgdHlwZW9mIG9iamVjdC5hdHRhY2hSZWYgPT09ICdmdW5jdGlvbicgJiZcbiAgICAgIHR5cGVvZiBvYmplY3QuZGV0YWNoUmVmID09PSAnZnVuY3Rpb24nXG4gICAgKTtcbiAgfSxcblxuICAvKipcbiAgICogQWRkcyBhIGNvbXBvbmVudCBieSByZWYgdG8gYW4gb3duZXIgY29tcG9uZW50LlxuICAgKlxuICAgKiBAcGFyYW0ge1JlYWN0Q29tcG9uZW50fSBjb21wb25lbnQgQ29tcG9uZW50IHRvIHJlZmVyZW5jZS5cbiAgICogQHBhcmFtIHtzdHJpbmd9IHJlZiBOYW1lIGJ5IHdoaWNoIHRvIHJlZmVyIHRvIHRoZSBjb21wb25lbnQuXG4gICAqIEBwYXJhbSB7UmVhY3RPd25lcn0gb3duZXIgQ29tcG9uZW50IG9uIHdoaWNoIHRvIHJlY29yZCB0aGUgcmVmLlxuICAgKiBAZmluYWxcbiAgICogQGludGVybmFsXG4gICAqL1xuICBhZGRDb21wb25lbnRBc1JlZlRvOiBmdW5jdGlvbihjb21wb25lbnQsIHJlZiwgb3duZXIpIHtcbiAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgUmVhY3RPd25lci5pc1ZhbGlkT3duZXIob3duZXIpLFxuICAgICAgJ2FkZENvbXBvbmVudEFzUmVmVG8oLi4uKTogT25seSBhIFJlYWN0T3duZXIgY2FuIGhhdmUgcmVmcy4gVGhpcyAnICtcbiAgICAgICd1c3VhbGx5IG1lYW5zIHRoYXQgeW91XFwncmUgdHJ5aW5nIHRvIGFkZCBhIHJlZiB0byBhIGNvbXBvbmVudCB0aGF0ICcgK1xuICAgICAgJ2RvZXNuXFwndCBoYXZlIGFuIG93bmVyICh0aGF0IGlzLCB3YXMgbm90IGNyZWF0ZWQgaW5zaWRlIG9mIGFub3RoZXIgJyArXG4gICAgICAnY29tcG9uZW50XFwncyBgcmVuZGVyYCBtZXRob2QpLiBUcnkgcmVuZGVyaW5nIHRoaXMgY29tcG9uZW50IGluc2lkZSBvZiAnICtcbiAgICAgICdhIG5ldyB0b3AtbGV2ZWwgY29tcG9uZW50IHdoaWNoIHdpbGwgaG9sZCB0aGUgcmVmLidcbiAgICApIDogaW52YXJpYW50KFJlYWN0T3duZXIuaXNWYWxpZE93bmVyKG93bmVyKSkpO1xuICAgIG93bmVyLmF0dGFjaFJlZihyZWYsIGNvbXBvbmVudCk7XG4gIH0sXG5cbiAgLyoqXG4gICAqIFJlbW92ZXMgYSBjb21wb25lbnQgYnkgcmVmIGZyb20gYW4gb3duZXIgY29tcG9uZW50LlxuICAgKlxuICAgKiBAcGFyYW0ge1JlYWN0Q29tcG9uZW50fSBjb21wb25lbnQgQ29tcG9uZW50IHRvIGRlcmVmZXJlbmNlLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gcmVmIE5hbWUgb2YgdGhlIHJlZiB0byByZW1vdmUuXG4gICAqIEBwYXJhbSB7UmVhY3RPd25lcn0gb3duZXIgQ29tcG9uZW50IG9uIHdoaWNoIHRoZSByZWYgaXMgcmVjb3JkZWQuXG4gICAqIEBmaW5hbFxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIHJlbW92ZUNvbXBvbmVudEFzUmVmRnJvbTogZnVuY3Rpb24oY29tcG9uZW50LCByZWYsIG93bmVyKSB7XG4gICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgIFJlYWN0T3duZXIuaXNWYWxpZE93bmVyKG93bmVyKSxcbiAgICAgICdyZW1vdmVDb21wb25lbnRBc1JlZkZyb20oLi4uKTogT25seSBhIFJlYWN0T3duZXIgY2FuIGhhdmUgcmVmcy4gVGhpcyAnICtcbiAgICAgICd1c3VhbGx5IG1lYW5zIHRoYXQgeW91XFwncmUgdHJ5aW5nIHRvIHJlbW92ZSBhIHJlZiB0byBhIGNvbXBvbmVudCB0aGF0ICcgK1xuICAgICAgJ2RvZXNuXFwndCBoYXZlIGFuIG93bmVyICh0aGF0IGlzLCB3YXMgbm90IGNyZWF0ZWQgaW5zaWRlIG9mIGFub3RoZXIgJyArXG4gICAgICAnY29tcG9uZW50XFwncyBgcmVuZGVyYCBtZXRob2QpLiBUcnkgcmVuZGVyaW5nIHRoaXMgY29tcG9uZW50IGluc2lkZSBvZiAnICtcbiAgICAgICdhIG5ldyB0b3AtbGV2ZWwgY29tcG9uZW50IHdoaWNoIHdpbGwgaG9sZCB0aGUgcmVmLidcbiAgICApIDogaW52YXJpYW50KFJlYWN0T3duZXIuaXNWYWxpZE93bmVyKG93bmVyKSkpO1xuICAgIC8vIENoZWNrIHRoYXQgYGNvbXBvbmVudGAgaXMgc3RpbGwgdGhlIGN1cnJlbnQgcmVmIGJlY2F1c2Ugd2UgZG8gbm90IHdhbnQgdG9cbiAgICAvLyBkZXRhY2ggdGhlIHJlZiBpZiBhbm90aGVyIGNvbXBvbmVudCBzdG9sZSBpdC5cbiAgICBpZiAob3duZXIucmVmc1tyZWZdID09PSBjb21wb25lbnQpIHtcbiAgICAgIG93bmVyLmRldGFjaFJlZihyZWYpO1xuICAgIH1cbiAgfSxcblxuICAvKipcbiAgICogQSBSZWFjdENvbXBvbmVudCBtdXN0IG1peCB0aGlzIGluIHRvIGhhdmUgcmVmcy5cbiAgICpcbiAgICogQGxlbmRzIHtSZWFjdE93bmVyLnByb3RvdHlwZX1cbiAgICovXG4gIE1peGluOiB7XG5cbiAgICBjb25zdHJ1Y3Q6IGZ1bmN0aW9uKCkge1xuICAgICAgdGhpcy5yZWZzID0gZW1wdHlPYmplY3Q7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIExhemlseSBhbGxvY2F0ZXMgdGhlIHJlZnMgb2JqZWN0IGFuZCBzdG9yZXMgYGNvbXBvbmVudGAgYXMgYHJlZmAuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gcmVmIFJlZmVyZW5jZSBuYW1lLlxuICAgICAqIEBwYXJhbSB7Y29tcG9uZW50fSBjb21wb25lbnQgQ29tcG9uZW50IHRvIHN0b3JlIGFzIGByZWZgLlxuICAgICAqIEBmaW5hbFxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgYXR0YWNoUmVmOiBmdW5jdGlvbihyZWYsIGNvbXBvbmVudCkge1xuICAgICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgICAgY29tcG9uZW50LmlzT3duZWRCeSh0aGlzKSxcbiAgICAgICAgJ2F0dGFjaFJlZiglcywgLi4uKTogT25seSBhIGNvbXBvbmVudFxcJ3Mgb3duZXIgY2FuIHN0b3JlIGEgcmVmIHRvIGl0LicsXG4gICAgICAgIHJlZlxuICAgICAgKSA6IGludmFyaWFudChjb21wb25lbnQuaXNPd25lZEJ5KHRoaXMpKSk7XG4gICAgICB2YXIgcmVmcyA9IHRoaXMucmVmcyA9PT0gZW1wdHlPYmplY3QgPyAodGhpcy5yZWZzID0ge30pIDogdGhpcy5yZWZzO1xuICAgICAgcmVmc1tyZWZdID0gY29tcG9uZW50O1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBEZXRhY2hlcyBhIHJlZmVyZW5jZSBuYW1lLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IHJlZiBOYW1lIHRvIGRlcmVmZXJlbmNlLlxuICAgICAqIEBmaW5hbFxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgZGV0YWNoUmVmOiBmdW5jdGlvbihyZWYpIHtcbiAgICAgIGRlbGV0ZSB0aGlzLnJlZnNbcmVmXTtcbiAgICB9XG5cbiAgfVxuXG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJlYWN0T3duZXI7XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKCdfcHJvY2VzcycpKSIsIihmdW5jdGlvbiAocHJvY2Vzcyl7XG4vKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgUmVhY3RQZXJmXG4gKiBAdHlwZWNoZWNrcyBzdGF0aWMtb25seVxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG4vKipcbiAqIFJlYWN0UGVyZiBpcyBhIGdlbmVyYWwgQU9QIHN5c3RlbSBkZXNpZ25lZCB0byBtZWFzdXJlIHBlcmZvcm1hbmNlLiBUaGlzXG4gKiBtb2R1bGUgb25seSBoYXMgdGhlIGhvb2tzOiBzZWUgUmVhY3REZWZhdWx0UGVyZiBmb3IgdGhlIGFuYWx5c2lzIHRvb2wuXG4gKi9cbnZhciBSZWFjdFBlcmYgPSB7XG4gIC8qKlxuICAgKiBCb29sZWFuIHRvIGVuYWJsZS9kaXNhYmxlIG1lYXN1cmVtZW50LiBTZXQgdG8gZmFsc2UgYnkgZGVmYXVsdCB0byBwcmV2ZW50XG4gICAqIGFjY2lkZW50YWwgbG9nZ2luZyBhbmQgcGVyZiBsb3NzLlxuICAgKi9cbiAgZW5hYmxlTWVhc3VyZTogZmFsc2UsXG5cbiAgLyoqXG4gICAqIEhvbGRzIG9udG8gdGhlIG1lYXN1cmUgZnVuY3Rpb24gaW4gdXNlLiBCeSBkZWZhdWx0LCBkb24ndCBtZWFzdXJlXG4gICAqIGFueXRoaW5nLCBidXQgd2UnbGwgb3ZlcnJpZGUgdGhpcyBpZiB3ZSBpbmplY3QgYSBtZWFzdXJlIGZ1bmN0aW9uLlxuICAgKi9cbiAgc3RvcmVkTWVhc3VyZTogX25vTWVhc3VyZSxcblxuICAvKipcbiAgICogVXNlIHRoaXMgdG8gd3JhcCBtZXRob2RzIHlvdSB3YW50IHRvIG1lYXN1cmUuIFplcm8gb3ZlcmhlYWQgaW4gcHJvZHVjdGlvbi5cbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IG9iak5hbWVcbiAgICogQHBhcmFtIHtzdHJpbmd9IGZuTmFtZVxuICAgKiBAcGFyYW0ge2Z1bmN0aW9ufSBmdW5jXG4gICAqIEByZXR1cm4ge2Z1bmN0aW9ufVxuICAgKi9cbiAgbWVhc3VyZTogZnVuY3Rpb24ob2JqTmFtZSwgZm5OYW1lLCBmdW5jKSB7XG4gICAgaWYgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOVikge1xuICAgICAgdmFyIG1lYXN1cmVkRnVuYyA9IG51bGw7XG4gICAgICB2YXIgd3JhcHBlciA9IGZ1bmN0aW9uKCkge1xuICAgICAgICBpZiAoUmVhY3RQZXJmLmVuYWJsZU1lYXN1cmUpIHtcbiAgICAgICAgICBpZiAoIW1lYXN1cmVkRnVuYykge1xuICAgICAgICAgICAgbWVhc3VyZWRGdW5jID0gUmVhY3RQZXJmLnN0b3JlZE1lYXN1cmUob2JqTmFtZSwgZm5OYW1lLCBmdW5jKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIG1lYXN1cmVkRnVuYy5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBmdW5jLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICB9O1xuICAgICAgd3JhcHBlci5kaXNwbGF5TmFtZSA9IG9iak5hbWUgKyAnXycgKyBmbk5hbWU7XG4gICAgICByZXR1cm4gd3JhcHBlcjtcbiAgICB9XG4gICAgcmV0dXJuIGZ1bmM7XG4gIH0sXG5cbiAgaW5qZWN0aW9uOiB7XG4gICAgLyoqXG4gICAgICogQHBhcmFtIHtmdW5jdGlvbn0gbWVhc3VyZVxuICAgICAqL1xuICAgIGluamVjdE1lYXN1cmU6IGZ1bmN0aW9uKG1lYXN1cmUpIHtcbiAgICAgIFJlYWN0UGVyZi5zdG9yZWRNZWFzdXJlID0gbWVhc3VyZTtcbiAgICB9XG4gIH1cbn07XG5cbi8qKlxuICogU2ltcGx5IHBhc3NlcyB0aHJvdWdoIHRoZSBtZWFzdXJlZCBmdW5jdGlvbiwgd2l0aG91dCBtZWFzdXJpbmcgaXQuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IG9iak5hbWVcbiAqIEBwYXJhbSB7c3RyaW5nfSBmbk5hbWVcbiAqIEBwYXJhbSB7ZnVuY3Rpb259IGZ1bmNcbiAqIEByZXR1cm4ge2Z1bmN0aW9ufVxuICovXG5mdW5jdGlvbiBfbm9NZWFzdXJlKG9iak5hbWUsIGZuTmFtZSwgZnVuYykge1xuICByZXR1cm4gZnVuYztcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBSZWFjdFBlcmY7XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKCdfcHJvY2VzcycpKSIsIihmdW5jdGlvbiAocHJvY2Vzcyl7XG4vKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgUmVhY3RQcm9wVHJhbnNmZXJlclxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgYXNzaWduID0gcmVxdWlyZShcIi4vT2JqZWN0LmFzc2lnblwiKTtcbnZhciBlbXB0eUZ1bmN0aW9uID0gcmVxdWlyZShcIi4vZW1wdHlGdW5jdGlvblwiKTtcbnZhciBpbnZhcmlhbnQgPSByZXF1aXJlKFwiLi9pbnZhcmlhbnRcIik7XG52YXIgam9pbkNsYXNzZXMgPSByZXF1aXJlKFwiLi9qb2luQ2xhc3Nlc1wiKTtcbnZhciB3YXJuaW5nID0gcmVxdWlyZShcIi4vd2FybmluZ1wiKTtcblxudmFyIGRpZFdhcm4gPSBmYWxzZTtcblxuLyoqXG4gKiBDcmVhdGVzIGEgdHJhbnNmZXIgc3RyYXRlZ3kgdGhhdCB3aWxsIG1lcmdlIHByb3AgdmFsdWVzIHVzaW5nIHRoZSBzdXBwbGllZFxuICogYG1lcmdlU3RyYXRlZ3lgLiBJZiBhIHByb3Agd2FzIHByZXZpb3VzbHkgdW5zZXQsIHRoaXMganVzdCBzZXRzIGl0LlxuICpcbiAqIEBwYXJhbSB7ZnVuY3Rpb259IG1lcmdlU3RyYXRlZ3lcbiAqIEByZXR1cm4ge2Z1bmN0aW9ufVxuICovXG5mdW5jdGlvbiBjcmVhdGVUcmFuc2ZlclN0cmF0ZWd5KG1lcmdlU3RyYXRlZ3kpIHtcbiAgcmV0dXJuIGZ1bmN0aW9uKHByb3BzLCBrZXksIHZhbHVlKSB7XG4gICAgaWYgKCFwcm9wcy5oYXNPd25Qcm9wZXJ0eShrZXkpKSB7XG4gICAgICBwcm9wc1trZXldID0gdmFsdWU7XG4gICAgfSBlbHNlIHtcbiAgICAgIHByb3BzW2tleV0gPSBtZXJnZVN0cmF0ZWd5KHByb3BzW2tleV0sIHZhbHVlKTtcbiAgICB9XG4gIH07XG59XG5cbnZhciB0cmFuc2ZlclN0cmF0ZWd5TWVyZ2UgPSBjcmVhdGVUcmFuc2ZlclN0cmF0ZWd5KGZ1bmN0aW9uKGEsIGIpIHtcbiAgLy8gYG1lcmdlYCBvdmVycmlkZXMgdGhlIGZpcnN0IG9iamVjdCdzIChgcHJvcHNba2V5XWAgYWJvdmUpIGtleXMgdXNpbmcgdGhlXG4gIC8vIHNlY29uZCBvYmplY3QncyAoYHZhbHVlYCkga2V5cy4gQW4gb2JqZWN0J3Mgc3R5bGUncyBleGlzdGluZyBgcHJvcEFgIHdvdWxkXG4gIC8vIGdldCBvdmVycmlkZGVuLiBGbGlwIHRoZSBvcmRlciBoZXJlLlxuICByZXR1cm4gYXNzaWduKHt9LCBiLCBhKTtcbn0pO1xuXG4vKipcbiAqIFRyYW5zZmVyIHN0cmF0ZWdpZXMgZGljdGF0ZSBob3cgcHJvcHMgYXJlIHRyYW5zZmVycmVkIGJ5IGB0cmFuc2ZlclByb3BzVG9gLlxuICogTk9URTogaWYgeW91IGFkZCBhbnkgbW9yZSBleGNlcHRpb25zIHRvIHRoaXMgbGlzdCB5b3Ugc2hvdWxkIGJlIHN1cmUgdG9cbiAqIHVwZGF0ZSBgY2xvbmVXaXRoUHJvcHMoKWAgYWNjb3JkaW5nbHkuXG4gKi9cbnZhciBUcmFuc2ZlclN0cmF0ZWdpZXMgPSB7XG4gIC8qKlxuICAgKiBOZXZlciB0cmFuc2ZlciBgY2hpbGRyZW5gLlxuICAgKi9cbiAgY2hpbGRyZW46IGVtcHR5RnVuY3Rpb24sXG4gIC8qKlxuICAgKiBUcmFuc2ZlciB0aGUgYGNsYXNzTmFtZWAgcHJvcCBieSBtZXJnaW5nIHRoZW0uXG4gICAqL1xuICBjbGFzc05hbWU6IGNyZWF0ZVRyYW5zZmVyU3RyYXRlZ3koam9pbkNsYXNzZXMpLFxuICAvKipcbiAgICogVHJhbnNmZXIgdGhlIGBzdHlsZWAgcHJvcCAod2hpY2ggaXMgYW4gb2JqZWN0KSBieSBtZXJnaW5nIHRoZW0uXG4gICAqL1xuICBzdHlsZTogdHJhbnNmZXJTdHJhdGVneU1lcmdlXG59O1xuXG4vKipcbiAqIE11dGF0ZXMgdGhlIGZpcnN0IGFyZ3VtZW50IGJ5IHRyYW5zZmVycmluZyB0aGUgcHJvcGVydGllcyBmcm9tIHRoZSBzZWNvbmRcbiAqIGFyZ3VtZW50LlxuICpcbiAqIEBwYXJhbSB7b2JqZWN0fSBwcm9wc1xuICogQHBhcmFtIHtvYmplY3R9IG5ld1Byb3BzXG4gKiBAcmV0dXJuIHtvYmplY3R9XG4gKi9cbmZ1bmN0aW9uIHRyYW5zZmVySW50byhwcm9wcywgbmV3UHJvcHMpIHtcbiAgZm9yICh2YXIgdGhpc0tleSBpbiBuZXdQcm9wcykge1xuICAgIGlmICghbmV3UHJvcHMuaGFzT3duUHJvcGVydHkodGhpc0tleSkpIHtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cblxuICAgIHZhciB0cmFuc2ZlclN0cmF0ZWd5ID0gVHJhbnNmZXJTdHJhdGVnaWVzW3RoaXNLZXldO1xuXG4gICAgaWYgKHRyYW5zZmVyU3RyYXRlZ3kgJiYgVHJhbnNmZXJTdHJhdGVnaWVzLmhhc093blByb3BlcnR5KHRoaXNLZXkpKSB7XG4gICAgICB0cmFuc2ZlclN0cmF0ZWd5KHByb3BzLCB0aGlzS2V5LCBuZXdQcm9wc1t0aGlzS2V5XSk7XG4gICAgfSBlbHNlIGlmICghcHJvcHMuaGFzT3duUHJvcGVydHkodGhpc0tleSkpIHtcbiAgICAgIHByb3BzW3RoaXNLZXldID0gbmV3UHJvcHNbdGhpc0tleV07XG4gICAgfVxuICB9XG4gIHJldHVybiBwcm9wcztcbn1cblxuLyoqXG4gKiBSZWFjdFByb3BUcmFuc2ZlcmVyIGFyZSBjYXBhYmxlIG9mIHRyYW5zZmVycmluZyBwcm9wcyB0byBhbm90aGVyIGNvbXBvbmVudFxuICogdXNpbmcgYSBgdHJhbnNmZXJQcm9wc1RvYCBtZXRob2QuXG4gKlxuICogQGNsYXNzIFJlYWN0UHJvcFRyYW5zZmVyZXJcbiAqL1xudmFyIFJlYWN0UHJvcFRyYW5zZmVyZXIgPSB7XG5cbiAgVHJhbnNmZXJTdHJhdGVnaWVzOiBUcmFuc2ZlclN0cmF0ZWdpZXMsXG5cbiAgLyoqXG4gICAqIE1lcmdlIHR3byBwcm9wcyBvYmplY3RzIHVzaW5nIFRyYW5zZmVyU3RyYXRlZ2llcy5cbiAgICpcbiAgICogQHBhcmFtIHtvYmplY3R9IG9sZFByb3BzIG9yaWdpbmFsIHByb3BzICh0aGV5IHRha2UgcHJlY2VkZW5jZSlcbiAgICogQHBhcmFtIHtvYmplY3R9IG5ld1Byb3BzIG5ldyBwcm9wcyB0byBtZXJnZSBpblxuICAgKiBAcmV0dXJuIHtvYmplY3R9IGEgbmV3IG9iamVjdCBjb250YWluaW5nIGJvdGggc2V0cyBvZiBwcm9wcyBtZXJnZWQuXG4gICAqL1xuICBtZXJnZVByb3BzOiBmdW5jdGlvbihvbGRQcm9wcywgbmV3UHJvcHMpIHtcbiAgICByZXR1cm4gdHJhbnNmZXJJbnRvKGFzc2lnbih7fSwgb2xkUHJvcHMpLCBuZXdQcm9wcyk7XG4gIH0sXG5cbiAgLyoqXG4gICAqIEBsZW5kcyB7UmVhY3RQcm9wVHJhbnNmZXJlci5wcm90b3R5cGV9XG4gICAqL1xuICBNaXhpbjoge1xuXG4gICAgLyoqXG4gICAgICogVHJhbnNmZXIgcHJvcHMgZnJvbSB0aGlzIGNvbXBvbmVudCB0byBhIHRhcmdldCBjb21wb25lbnQuXG4gICAgICpcbiAgICAgKiBQcm9wcyB0aGF0IGRvIG5vdCBoYXZlIGFuIGV4cGxpY2l0IHRyYW5zZmVyIHN0cmF0ZWd5IHdpbGwgYmUgdHJhbnNmZXJyZWRcbiAgICAgKiBvbmx5IGlmIHRoZSB0YXJnZXQgY29tcG9uZW50IGRvZXMgbm90IGFscmVhZHkgaGF2ZSB0aGUgcHJvcCBzZXQuXG4gICAgICpcbiAgICAgKiBUaGlzIGlzIHVzdWFsbHkgdXNlZCB0byBwYXNzIGRvd24gcHJvcHMgdG8gYSByZXR1cm5lZCByb290IGNvbXBvbmVudC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7UmVhY3RFbGVtZW50fSBlbGVtZW50IENvbXBvbmVudCByZWNlaXZpbmcgdGhlIHByb3BlcnRpZXMuXG4gICAgICogQHJldHVybiB7UmVhY3RFbGVtZW50fSBUaGUgc3VwcGxpZWQgYGNvbXBvbmVudGAuXG4gICAgICogQGZpbmFsXG4gICAgICogQHByb3RlY3RlZFxuICAgICAqL1xuICAgIHRyYW5zZmVyUHJvcHNUbzogZnVuY3Rpb24oZWxlbWVudCkge1xuICAgICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgICAgZWxlbWVudC5fb3duZXIgPT09IHRoaXMsXG4gICAgICAgICclczogWW91IGNhblxcJ3QgY2FsbCB0cmFuc2ZlclByb3BzVG8oKSBvbiBhIGNvbXBvbmVudCB0aGF0IHlvdSAnICtcbiAgICAgICAgJ2RvblxcJ3Qgb3duLCAlcy4gVGhpcyB1c3VhbGx5IG1lYW5zIHlvdSBhcmUgY2FsbGluZyAnICtcbiAgICAgICAgJ3RyYW5zZmVyUHJvcHNUbygpIG9uIGEgY29tcG9uZW50IHBhc3NlZCBpbiBhcyBwcm9wcyBvciBjaGlsZHJlbi4nLFxuICAgICAgICB0aGlzLmNvbnN0cnVjdG9yLmRpc3BsYXlOYW1lLFxuICAgICAgICB0eXBlb2YgZWxlbWVudC50eXBlID09PSAnc3RyaW5nJyA/XG4gICAgICAgIGVsZW1lbnQudHlwZSA6XG4gICAgICAgIGVsZW1lbnQudHlwZS5kaXNwbGF5TmFtZVxuICAgICAgKSA6IGludmFyaWFudChlbGVtZW50Ll9vd25lciA9PT0gdGhpcykpO1xuXG4gICAgICBpZiAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WKSB7XG4gICAgICAgIGlmICghZGlkV2Fybikge1xuICAgICAgICAgIGRpZFdhcm4gPSB0cnVlO1xuICAgICAgICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyB3YXJuaW5nKFxuICAgICAgICAgICAgZmFsc2UsXG4gICAgICAgICAgICAndHJhbnNmZXJQcm9wc1RvIGlzIGRlcHJlY2F0ZWQuICcgK1xuICAgICAgICAgICAgJ1NlZSBodHRwOi8vZmIubWUvcmVhY3QtdHJhbnNmZXJwcm9wc3RvIGZvciBtb3JlIGluZm9ybWF0aW9uLidcbiAgICAgICAgICApIDogbnVsbCk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgLy8gQmVjYXVzZSBlbGVtZW50cyBhcmUgaW1tdXRhYmxlIHdlIGhhdmUgdG8gbWVyZ2UgaW50byB0aGUgZXhpc3RpbmdcbiAgICAgIC8vIHByb3BzIG9iamVjdCByYXRoZXIgdGhhbiBjbG9uZSBpdC5cbiAgICAgIHRyYW5zZmVySW50byhlbGVtZW50LnByb3BzLCB0aGlzLnByb3BzKTtcblxuICAgICAgcmV0dXJuIGVsZW1lbnQ7XG4gICAgfVxuXG4gIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gUmVhY3RQcm9wVHJhbnNmZXJlcjtcblxufSkuY2FsbCh0aGlzLHJlcXVpcmUoJ19wcm9jZXNzJykpIiwiKGZ1bmN0aW9uIChwcm9jZXNzKXtcbi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBSZWFjdFByb3BUeXBlTG9jYXRpb25OYW1lc1xuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgUmVhY3RQcm9wVHlwZUxvY2F0aW9uTmFtZXMgPSB7fTtcblxuaWYgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOVikge1xuICBSZWFjdFByb3BUeXBlTG9jYXRpb25OYW1lcyA9IHtcbiAgICBwcm9wOiAncHJvcCcsXG4gICAgY29udGV4dDogJ2NvbnRleHQnLFxuICAgIGNoaWxkQ29udGV4dDogJ2NoaWxkIGNvbnRleHQnXG4gIH07XG59XG5cbm1vZHVsZS5leHBvcnRzID0gUmVhY3RQcm9wVHlwZUxvY2F0aW9uTmFtZXM7XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKCdfcHJvY2VzcycpKSIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBSZWFjdFByb3BUeXBlTG9jYXRpb25zXG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBrZXlNaXJyb3IgPSByZXF1aXJlKFwiLi9rZXlNaXJyb3JcIik7XG5cbnZhciBSZWFjdFByb3BUeXBlTG9jYXRpb25zID0ga2V5TWlycm9yKHtcbiAgcHJvcDogbnVsbCxcbiAgY29udGV4dDogbnVsbCxcbiAgY2hpbGRDb250ZXh0OiBudWxsXG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBSZWFjdFByb3BUeXBlTG9jYXRpb25zO1xuIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIFJlYWN0UHJvcFR5cGVzXG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBSZWFjdEVsZW1lbnQgPSByZXF1aXJlKFwiLi9SZWFjdEVsZW1lbnRcIik7XG52YXIgUmVhY3RQcm9wVHlwZUxvY2F0aW9uTmFtZXMgPSByZXF1aXJlKFwiLi9SZWFjdFByb3BUeXBlTG9jYXRpb25OYW1lc1wiKTtcblxudmFyIGRlcHJlY2F0ZWQgPSByZXF1aXJlKFwiLi9kZXByZWNhdGVkXCIpO1xudmFyIGVtcHR5RnVuY3Rpb24gPSByZXF1aXJlKFwiLi9lbXB0eUZ1bmN0aW9uXCIpO1xuXG4vKipcbiAqIENvbGxlY3Rpb24gb2YgbWV0aG9kcyB0aGF0IGFsbG93IGRlY2xhcmF0aW9uIGFuZCB2YWxpZGF0aW9uIG9mIHByb3BzIHRoYXQgYXJlXG4gKiBzdXBwbGllZCB0byBSZWFjdCBjb21wb25lbnRzLiBFeGFtcGxlIHVzYWdlOlxuICpcbiAqICAgdmFyIFByb3BzID0gcmVxdWlyZSgnUmVhY3RQcm9wVHlwZXMnKTtcbiAqICAgdmFyIE15QXJ0aWNsZSA9IFJlYWN0LmNyZWF0ZUNsYXNzKHtcbiAqICAgICBwcm9wVHlwZXM6IHtcbiAqICAgICAgIC8vIEFuIG9wdGlvbmFsIHN0cmluZyBwcm9wIG5hbWVkIFwiZGVzY3JpcHRpb25cIi5cbiAqICAgICAgIGRlc2NyaXB0aW9uOiBQcm9wcy5zdHJpbmcsXG4gKlxuICogICAgICAgLy8gQSByZXF1aXJlZCBlbnVtIHByb3AgbmFtZWQgXCJjYXRlZ29yeVwiLlxuICogICAgICAgY2F0ZWdvcnk6IFByb3BzLm9uZU9mKFsnTmV3cycsJ1Bob3RvcyddKS5pc1JlcXVpcmVkLFxuICpcbiAqICAgICAgIC8vIEEgcHJvcCBuYW1lZCBcImRpYWxvZ1wiIHRoYXQgcmVxdWlyZXMgYW4gaW5zdGFuY2Ugb2YgRGlhbG9nLlxuICogICAgICAgZGlhbG9nOiBQcm9wcy5pbnN0YW5jZU9mKERpYWxvZykuaXNSZXF1aXJlZFxuICogICAgIH0sXG4gKiAgICAgcmVuZGVyOiBmdW5jdGlvbigpIHsgLi4uIH1cbiAqICAgfSk7XG4gKlxuICogQSBtb3JlIGZvcm1hbCBzcGVjaWZpY2F0aW9uIG9mIGhvdyB0aGVzZSBtZXRob2RzIGFyZSB1c2VkOlxuICpcbiAqICAgdHlwZSA6PSBhcnJheXxib29sfGZ1bmN8b2JqZWN0fG51bWJlcnxzdHJpbmd8b25lT2YoWy4uLl0pfGluc3RhbmNlT2YoLi4uKVxuICogICBkZWNsIDo9IFJlYWN0UHJvcFR5cGVzLnt0eXBlfSguaXNSZXF1aXJlZCk/XG4gKlxuICogRWFjaCBhbmQgZXZlcnkgZGVjbGFyYXRpb24gcHJvZHVjZXMgYSBmdW5jdGlvbiB3aXRoIHRoZSBzYW1lIHNpZ25hdHVyZS4gVGhpc1xuICogYWxsb3dzIHRoZSBjcmVhdGlvbiBvZiBjdXN0b20gdmFsaWRhdGlvbiBmdW5jdGlvbnMuIEZvciBleGFtcGxlOlxuICpcbiAqICB2YXIgTXlMaW5rID0gUmVhY3QuY3JlYXRlQ2xhc3Moe1xuICogICAgcHJvcFR5cGVzOiB7XG4gKiAgICAgIC8vIEFuIG9wdGlvbmFsIHN0cmluZyBvciBVUkkgcHJvcCBuYW1lZCBcImhyZWZcIi5cbiAqICAgICAgaHJlZjogZnVuY3Rpb24ocHJvcHMsIHByb3BOYW1lLCBjb21wb25lbnROYW1lKSB7XG4gKiAgICAgICAgdmFyIHByb3BWYWx1ZSA9IHByb3BzW3Byb3BOYW1lXTtcbiAqICAgICAgICBpZiAocHJvcFZhbHVlICE9IG51bGwgJiYgdHlwZW9mIHByb3BWYWx1ZSAhPT0gJ3N0cmluZycgJiZcbiAqICAgICAgICAgICAgIShwcm9wVmFsdWUgaW5zdGFuY2VvZiBVUkkpKSB7XG4gKiAgICAgICAgICByZXR1cm4gbmV3IEVycm9yKFxuICogICAgICAgICAgICAnRXhwZWN0ZWQgYSBzdHJpbmcgb3IgYW4gVVJJIGZvciAnICsgcHJvcE5hbWUgKyAnIGluICcgK1xuICogICAgICAgICAgICBjb21wb25lbnROYW1lXG4gKiAgICAgICAgICApO1xuICogICAgICAgIH1cbiAqICAgICAgfVxuICogICAgfSxcbiAqICAgIHJlbmRlcjogZnVuY3Rpb24oKSB7Li4ufVxuICogIH0pO1xuICpcbiAqIEBpbnRlcm5hbFxuICovXG5cbnZhciBBTk9OWU1PVVMgPSAnPDxhbm9ueW1vdXM+Pic7XG5cbnZhciBlbGVtZW50VHlwZUNoZWNrZXIgPSBjcmVhdGVFbGVtZW50VHlwZUNoZWNrZXIoKTtcbnZhciBub2RlVHlwZUNoZWNrZXIgPSBjcmVhdGVOb2RlQ2hlY2tlcigpO1xuXG52YXIgUmVhY3RQcm9wVHlwZXMgPSB7XG4gIGFycmF5OiBjcmVhdGVQcmltaXRpdmVUeXBlQ2hlY2tlcignYXJyYXknKSxcbiAgYm9vbDogY3JlYXRlUHJpbWl0aXZlVHlwZUNoZWNrZXIoJ2Jvb2xlYW4nKSxcbiAgZnVuYzogY3JlYXRlUHJpbWl0aXZlVHlwZUNoZWNrZXIoJ2Z1bmN0aW9uJyksXG4gIG51bWJlcjogY3JlYXRlUHJpbWl0aXZlVHlwZUNoZWNrZXIoJ251bWJlcicpLFxuICBvYmplY3Q6IGNyZWF0ZVByaW1pdGl2ZVR5cGVDaGVja2VyKCdvYmplY3QnKSxcbiAgc3RyaW5nOiBjcmVhdGVQcmltaXRpdmVUeXBlQ2hlY2tlcignc3RyaW5nJyksXG5cbiAgYW55OiBjcmVhdGVBbnlUeXBlQ2hlY2tlcigpLFxuICBhcnJheU9mOiBjcmVhdGVBcnJheU9mVHlwZUNoZWNrZXIsXG4gIGVsZW1lbnQ6IGVsZW1lbnRUeXBlQ2hlY2tlcixcbiAgaW5zdGFuY2VPZjogY3JlYXRlSW5zdGFuY2VUeXBlQ2hlY2tlcixcbiAgbm9kZTogbm9kZVR5cGVDaGVja2VyLFxuICBvYmplY3RPZjogY3JlYXRlT2JqZWN0T2ZUeXBlQ2hlY2tlcixcbiAgb25lT2Y6IGNyZWF0ZUVudW1UeXBlQ2hlY2tlcixcbiAgb25lT2ZUeXBlOiBjcmVhdGVVbmlvblR5cGVDaGVja2VyLFxuICBzaGFwZTogY3JlYXRlU2hhcGVUeXBlQ2hlY2tlcixcblxuICBjb21wb25lbnQ6IGRlcHJlY2F0ZWQoXG4gICAgJ1JlYWN0LlByb3BUeXBlcycsXG4gICAgJ2NvbXBvbmVudCcsXG4gICAgJ2VsZW1lbnQnLFxuICAgIHRoaXMsXG4gICAgZWxlbWVudFR5cGVDaGVja2VyXG4gICksXG4gIHJlbmRlcmFibGU6IGRlcHJlY2F0ZWQoXG4gICAgJ1JlYWN0LlByb3BUeXBlcycsXG4gICAgJ3JlbmRlcmFibGUnLFxuICAgICdub2RlJyxcbiAgICB0aGlzLFxuICAgIG5vZGVUeXBlQ2hlY2tlclxuICApXG59O1xuXG5mdW5jdGlvbiBjcmVhdGVDaGFpbmFibGVUeXBlQ2hlY2tlcih2YWxpZGF0ZSkge1xuICBmdW5jdGlvbiBjaGVja1R5cGUoaXNSZXF1aXJlZCwgcHJvcHMsIHByb3BOYW1lLCBjb21wb25lbnROYW1lLCBsb2NhdGlvbikge1xuICAgIGNvbXBvbmVudE5hbWUgPSBjb21wb25lbnROYW1lIHx8IEFOT05ZTU9VUztcbiAgICBpZiAocHJvcHNbcHJvcE5hbWVdID09IG51bGwpIHtcbiAgICAgIHZhciBsb2NhdGlvbk5hbWUgPSBSZWFjdFByb3BUeXBlTG9jYXRpb25OYW1lc1tsb2NhdGlvbl07XG4gICAgICBpZiAoaXNSZXF1aXJlZCkge1xuICAgICAgICByZXR1cm4gbmV3IEVycm9yKFxuICAgICAgICAgIChcIlJlcXVpcmVkIFwiICsgbG9jYXRpb25OYW1lICsgXCIgYFwiICsgcHJvcE5hbWUgKyBcImAgd2FzIG5vdCBzcGVjaWZpZWQgaW4gXCIpK1xuICAgICAgICAgIChcImBcIiArIGNvbXBvbmVudE5hbWUgKyBcImAuXCIpXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiB2YWxpZGF0ZShwcm9wcywgcHJvcE5hbWUsIGNvbXBvbmVudE5hbWUsIGxvY2F0aW9uKTtcbiAgICB9XG4gIH1cblxuICB2YXIgY2hhaW5lZENoZWNrVHlwZSA9IGNoZWNrVHlwZS5iaW5kKG51bGwsIGZhbHNlKTtcbiAgY2hhaW5lZENoZWNrVHlwZS5pc1JlcXVpcmVkID0gY2hlY2tUeXBlLmJpbmQobnVsbCwgdHJ1ZSk7XG5cbiAgcmV0dXJuIGNoYWluZWRDaGVja1R5cGU7XG59XG5cbmZ1bmN0aW9uIGNyZWF0ZVByaW1pdGl2ZVR5cGVDaGVja2VyKGV4cGVjdGVkVHlwZSkge1xuICBmdW5jdGlvbiB2YWxpZGF0ZShwcm9wcywgcHJvcE5hbWUsIGNvbXBvbmVudE5hbWUsIGxvY2F0aW9uKSB7XG4gICAgdmFyIHByb3BWYWx1ZSA9IHByb3BzW3Byb3BOYW1lXTtcbiAgICB2YXIgcHJvcFR5cGUgPSBnZXRQcm9wVHlwZShwcm9wVmFsdWUpO1xuICAgIGlmIChwcm9wVHlwZSAhPT0gZXhwZWN0ZWRUeXBlKSB7XG4gICAgICB2YXIgbG9jYXRpb25OYW1lID0gUmVhY3RQcm9wVHlwZUxvY2F0aW9uTmFtZXNbbG9jYXRpb25dO1xuICAgICAgLy8gYHByb3BWYWx1ZWAgYmVpbmcgaW5zdGFuY2Ugb2YsIHNheSwgZGF0ZS9yZWdleHAsIHBhc3MgdGhlICdvYmplY3QnXG4gICAgICAvLyBjaGVjaywgYnV0IHdlIGNhbiBvZmZlciBhIG1vcmUgcHJlY2lzZSBlcnJvciBtZXNzYWdlIGhlcmUgcmF0aGVyIHRoYW5cbiAgICAgIC8vICdvZiB0eXBlIGBvYmplY3RgJy5cbiAgICAgIHZhciBwcmVjaXNlVHlwZSA9IGdldFByZWNpc2VUeXBlKHByb3BWYWx1ZSk7XG5cbiAgICAgIHJldHVybiBuZXcgRXJyb3IoXG4gICAgICAgIChcIkludmFsaWQgXCIgKyBsb2NhdGlvbk5hbWUgKyBcIiBgXCIgKyBwcm9wTmFtZSArIFwiYCBvZiB0eXBlIGBcIiArIHByZWNpc2VUeXBlICsgXCJgIFwiKSArXG4gICAgICAgIChcInN1cHBsaWVkIHRvIGBcIiArIGNvbXBvbmVudE5hbWUgKyBcImAsIGV4cGVjdGVkIGBcIiArIGV4cGVjdGVkVHlwZSArIFwiYC5cIilcbiAgICAgICk7XG4gICAgfVxuICB9XG4gIHJldHVybiBjcmVhdGVDaGFpbmFibGVUeXBlQ2hlY2tlcih2YWxpZGF0ZSk7XG59XG5cbmZ1bmN0aW9uIGNyZWF0ZUFueVR5cGVDaGVja2VyKCkge1xuICByZXR1cm4gY3JlYXRlQ2hhaW5hYmxlVHlwZUNoZWNrZXIoZW1wdHlGdW5jdGlvbi50aGF0UmV0dXJucygpKTtcbn1cblxuZnVuY3Rpb24gY3JlYXRlQXJyYXlPZlR5cGVDaGVja2VyKHR5cGVDaGVja2VyKSB7XG4gIGZ1bmN0aW9uIHZhbGlkYXRlKHByb3BzLCBwcm9wTmFtZSwgY29tcG9uZW50TmFtZSwgbG9jYXRpb24pIHtcbiAgICB2YXIgcHJvcFZhbHVlID0gcHJvcHNbcHJvcE5hbWVdO1xuICAgIGlmICghQXJyYXkuaXNBcnJheShwcm9wVmFsdWUpKSB7XG4gICAgICB2YXIgbG9jYXRpb25OYW1lID0gUmVhY3RQcm9wVHlwZUxvY2F0aW9uTmFtZXNbbG9jYXRpb25dO1xuICAgICAgdmFyIHByb3BUeXBlID0gZ2V0UHJvcFR5cGUocHJvcFZhbHVlKTtcbiAgICAgIHJldHVybiBuZXcgRXJyb3IoXG4gICAgICAgIChcIkludmFsaWQgXCIgKyBsb2NhdGlvbk5hbWUgKyBcIiBgXCIgKyBwcm9wTmFtZSArIFwiYCBvZiB0eXBlIFwiKSArXG4gICAgICAgIChcImBcIiArIHByb3BUeXBlICsgXCJgIHN1cHBsaWVkIHRvIGBcIiArIGNvbXBvbmVudE5hbWUgKyBcImAsIGV4cGVjdGVkIGFuIGFycmF5LlwiKVxuICAgICAgKTtcbiAgICB9XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBwcm9wVmFsdWUubGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciBlcnJvciA9IHR5cGVDaGVja2VyKHByb3BWYWx1ZSwgaSwgY29tcG9uZW50TmFtZSwgbG9jYXRpb24pO1xuICAgICAgaWYgKGVycm9yIGluc3RhbmNlb2YgRXJyb3IpIHtcbiAgICAgICAgcmV0dXJuIGVycm9yO1xuICAgICAgfVxuICAgIH1cbiAgfVxuICByZXR1cm4gY3JlYXRlQ2hhaW5hYmxlVHlwZUNoZWNrZXIodmFsaWRhdGUpO1xufVxuXG5mdW5jdGlvbiBjcmVhdGVFbGVtZW50VHlwZUNoZWNrZXIoKSB7XG4gIGZ1bmN0aW9uIHZhbGlkYXRlKHByb3BzLCBwcm9wTmFtZSwgY29tcG9uZW50TmFtZSwgbG9jYXRpb24pIHtcbiAgICBpZiAoIVJlYWN0RWxlbWVudC5pc1ZhbGlkRWxlbWVudChwcm9wc1twcm9wTmFtZV0pKSB7XG4gICAgICB2YXIgbG9jYXRpb25OYW1lID0gUmVhY3RQcm9wVHlwZUxvY2F0aW9uTmFtZXNbbG9jYXRpb25dO1xuICAgICAgcmV0dXJuIG5ldyBFcnJvcihcbiAgICAgICAgKFwiSW52YWxpZCBcIiArIGxvY2F0aW9uTmFtZSArIFwiIGBcIiArIHByb3BOYW1lICsgXCJgIHN1cHBsaWVkIHRvIFwiKSArXG4gICAgICAgIChcImBcIiArIGNvbXBvbmVudE5hbWUgKyBcImAsIGV4cGVjdGVkIGEgUmVhY3RFbGVtZW50LlwiKVxuICAgICAgKTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIGNyZWF0ZUNoYWluYWJsZVR5cGVDaGVja2VyKHZhbGlkYXRlKTtcbn1cblxuZnVuY3Rpb24gY3JlYXRlSW5zdGFuY2VUeXBlQ2hlY2tlcihleHBlY3RlZENsYXNzKSB7XG4gIGZ1bmN0aW9uIHZhbGlkYXRlKHByb3BzLCBwcm9wTmFtZSwgY29tcG9uZW50TmFtZSwgbG9jYXRpb24pIHtcbiAgICBpZiAoIShwcm9wc1twcm9wTmFtZV0gaW5zdGFuY2VvZiBleHBlY3RlZENsYXNzKSkge1xuICAgICAgdmFyIGxvY2F0aW9uTmFtZSA9IFJlYWN0UHJvcFR5cGVMb2NhdGlvbk5hbWVzW2xvY2F0aW9uXTtcbiAgICAgIHZhciBleHBlY3RlZENsYXNzTmFtZSA9IGV4cGVjdGVkQ2xhc3MubmFtZSB8fCBBTk9OWU1PVVM7XG4gICAgICByZXR1cm4gbmV3IEVycm9yKFxuICAgICAgICAoXCJJbnZhbGlkIFwiICsgbG9jYXRpb25OYW1lICsgXCIgYFwiICsgcHJvcE5hbWUgKyBcImAgc3VwcGxpZWQgdG8gXCIpICtcbiAgICAgICAgKFwiYFwiICsgY29tcG9uZW50TmFtZSArIFwiYCwgZXhwZWN0ZWQgaW5zdGFuY2Ugb2YgYFwiICsgZXhwZWN0ZWRDbGFzc05hbWUgKyBcImAuXCIpXG4gICAgICApO1xuICAgIH1cbiAgfVxuICByZXR1cm4gY3JlYXRlQ2hhaW5hYmxlVHlwZUNoZWNrZXIodmFsaWRhdGUpO1xufVxuXG5mdW5jdGlvbiBjcmVhdGVFbnVtVHlwZUNoZWNrZXIoZXhwZWN0ZWRWYWx1ZXMpIHtcbiAgZnVuY3Rpb24gdmFsaWRhdGUocHJvcHMsIHByb3BOYW1lLCBjb21wb25lbnROYW1lLCBsb2NhdGlvbikge1xuICAgIHZhciBwcm9wVmFsdWUgPSBwcm9wc1twcm9wTmFtZV07XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBleHBlY3RlZFZhbHVlcy5sZW5ndGg7IGkrKykge1xuICAgICAgaWYgKHByb3BWYWx1ZSA9PT0gZXhwZWN0ZWRWYWx1ZXNbaV0pIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgIH1cblxuICAgIHZhciBsb2NhdGlvbk5hbWUgPSBSZWFjdFByb3BUeXBlTG9jYXRpb25OYW1lc1tsb2NhdGlvbl07XG4gICAgdmFyIHZhbHVlc1N0cmluZyA9IEpTT04uc3RyaW5naWZ5KGV4cGVjdGVkVmFsdWVzKTtcbiAgICByZXR1cm4gbmV3IEVycm9yKFxuICAgICAgKFwiSW52YWxpZCBcIiArIGxvY2F0aW9uTmFtZSArIFwiIGBcIiArIHByb3BOYW1lICsgXCJgIG9mIHZhbHVlIGBcIiArIHByb3BWYWx1ZSArIFwiYCBcIikgK1xuICAgICAgKFwic3VwcGxpZWQgdG8gYFwiICsgY29tcG9uZW50TmFtZSArIFwiYCwgZXhwZWN0ZWQgb25lIG9mIFwiICsgdmFsdWVzU3RyaW5nICsgXCIuXCIpXG4gICAgKTtcbiAgfVxuICByZXR1cm4gY3JlYXRlQ2hhaW5hYmxlVHlwZUNoZWNrZXIodmFsaWRhdGUpO1xufVxuXG5mdW5jdGlvbiBjcmVhdGVPYmplY3RPZlR5cGVDaGVja2VyKHR5cGVDaGVja2VyKSB7XG4gIGZ1bmN0aW9uIHZhbGlkYXRlKHByb3BzLCBwcm9wTmFtZSwgY29tcG9uZW50TmFtZSwgbG9jYXRpb24pIHtcbiAgICB2YXIgcHJvcFZhbHVlID0gcHJvcHNbcHJvcE5hbWVdO1xuICAgIHZhciBwcm9wVHlwZSA9IGdldFByb3BUeXBlKHByb3BWYWx1ZSk7XG4gICAgaWYgKHByb3BUeXBlICE9PSAnb2JqZWN0Jykge1xuICAgICAgdmFyIGxvY2F0aW9uTmFtZSA9IFJlYWN0UHJvcFR5cGVMb2NhdGlvbk5hbWVzW2xvY2F0aW9uXTtcbiAgICAgIHJldHVybiBuZXcgRXJyb3IoXG4gICAgICAgIChcIkludmFsaWQgXCIgKyBsb2NhdGlvbk5hbWUgKyBcIiBgXCIgKyBwcm9wTmFtZSArIFwiYCBvZiB0eXBlIFwiKSArXG4gICAgICAgIChcImBcIiArIHByb3BUeXBlICsgXCJgIHN1cHBsaWVkIHRvIGBcIiArIGNvbXBvbmVudE5hbWUgKyBcImAsIGV4cGVjdGVkIGFuIG9iamVjdC5cIilcbiAgICAgICk7XG4gICAgfVxuICAgIGZvciAodmFyIGtleSBpbiBwcm9wVmFsdWUpIHtcbiAgICAgIGlmIChwcm9wVmFsdWUuaGFzT3duUHJvcGVydHkoa2V5KSkge1xuICAgICAgICB2YXIgZXJyb3IgPSB0eXBlQ2hlY2tlcihwcm9wVmFsdWUsIGtleSwgY29tcG9uZW50TmFtZSwgbG9jYXRpb24pO1xuICAgICAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBFcnJvcikge1xuICAgICAgICAgIHJldHVybiBlcnJvcjtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfVxuICByZXR1cm4gY3JlYXRlQ2hhaW5hYmxlVHlwZUNoZWNrZXIodmFsaWRhdGUpO1xufVxuXG5mdW5jdGlvbiBjcmVhdGVVbmlvblR5cGVDaGVja2VyKGFycmF5T2ZUeXBlQ2hlY2tlcnMpIHtcbiAgZnVuY3Rpb24gdmFsaWRhdGUocHJvcHMsIHByb3BOYW1lLCBjb21wb25lbnROYW1lLCBsb2NhdGlvbikge1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgYXJyYXlPZlR5cGVDaGVja2Vycy5sZW5ndGg7IGkrKykge1xuICAgICAgdmFyIGNoZWNrZXIgPSBhcnJheU9mVHlwZUNoZWNrZXJzW2ldO1xuICAgICAgaWYgKGNoZWNrZXIocHJvcHMsIHByb3BOYW1lLCBjb21wb25lbnROYW1lLCBsb2NhdGlvbikgPT0gbnVsbCkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgfVxuXG4gICAgdmFyIGxvY2F0aW9uTmFtZSA9IFJlYWN0UHJvcFR5cGVMb2NhdGlvbk5hbWVzW2xvY2F0aW9uXTtcbiAgICByZXR1cm4gbmV3IEVycm9yKFxuICAgICAgKFwiSW52YWxpZCBcIiArIGxvY2F0aW9uTmFtZSArIFwiIGBcIiArIHByb3BOYW1lICsgXCJgIHN1cHBsaWVkIHRvIFwiKSArXG4gICAgICAoXCJgXCIgKyBjb21wb25lbnROYW1lICsgXCJgLlwiKVxuICAgICk7XG4gIH1cbiAgcmV0dXJuIGNyZWF0ZUNoYWluYWJsZVR5cGVDaGVja2VyKHZhbGlkYXRlKTtcbn1cblxuZnVuY3Rpb24gY3JlYXRlTm9kZUNoZWNrZXIoKSB7XG4gIGZ1bmN0aW9uIHZhbGlkYXRlKHByb3BzLCBwcm9wTmFtZSwgY29tcG9uZW50TmFtZSwgbG9jYXRpb24pIHtcbiAgICBpZiAoIWlzTm9kZShwcm9wc1twcm9wTmFtZV0pKSB7XG4gICAgICB2YXIgbG9jYXRpb25OYW1lID0gUmVhY3RQcm9wVHlwZUxvY2F0aW9uTmFtZXNbbG9jYXRpb25dO1xuICAgICAgcmV0dXJuIG5ldyBFcnJvcihcbiAgICAgICAgKFwiSW52YWxpZCBcIiArIGxvY2F0aW9uTmFtZSArIFwiIGBcIiArIHByb3BOYW1lICsgXCJgIHN1cHBsaWVkIHRvIFwiKSArXG4gICAgICAgIChcImBcIiArIGNvbXBvbmVudE5hbWUgKyBcImAsIGV4cGVjdGVkIGEgUmVhY3ROb2RlLlwiKVxuICAgICAgKTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIGNyZWF0ZUNoYWluYWJsZVR5cGVDaGVja2VyKHZhbGlkYXRlKTtcbn1cblxuZnVuY3Rpb24gY3JlYXRlU2hhcGVUeXBlQ2hlY2tlcihzaGFwZVR5cGVzKSB7XG4gIGZ1bmN0aW9uIHZhbGlkYXRlKHByb3BzLCBwcm9wTmFtZSwgY29tcG9uZW50TmFtZSwgbG9jYXRpb24pIHtcbiAgICB2YXIgcHJvcFZhbHVlID0gcHJvcHNbcHJvcE5hbWVdO1xuICAgIHZhciBwcm9wVHlwZSA9IGdldFByb3BUeXBlKHByb3BWYWx1ZSk7XG4gICAgaWYgKHByb3BUeXBlICE9PSAnb2JqZWN0Jykge1xuICAgICAgdmFyIGxvY2F0aW9uTmFtZSA9IFJlYWN0UHJvcFR5cGVMb2NhdGlvbk5hbWVzW2xvY2F0aW9uXTtcbiAgICAgIHJldHVybiBuZXcgRXJyb3IoXG4gICAgICAgIChcIkludmFsaWQgXCIgKyBsb2NhdGlvbk5hbWUgKyBcIiBgXCIgKyBwcm9wTmFtZSArIFwiYCBvZiB0eXBlIGBcIiArIHByb3BUeXBlICsgXCJgIFwiKSArXG4gICAgICAgIChcInN1cHBsaWVkIHRvIGBcIiArIGNvbXBvbmVudE5hbWUgKyBcImAsIGV4cGVjdGVkIGBvYmplY3RgLlwiKVxuICAgICAgKTtcbiAgICB9XG4gICAgZm9yICh2YXIga2V5IGluIHNoYXBlVHlwZXMpIHtcbiAgICAgIHZhciBjaGVja2VyID0gc2hhcGVUeXBlc1trZXldO1xuICAgICAgaWYgKCFjaGVja2VyKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgdmFyIGVycm9yID0gY2hlY2tlcihwcm9wVmFsdWUsIGtleSwgY29tcG9uZW50TmFtZSwgbG9jYXRpb24pO1xuICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgIHJldHVybiBlcnJvcjtcbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgcmV0dXJuIGNyZWF0ZUNoYWluYWJsZVR5cGVDaGVja2VyKHZhbGlkYXRlLCAnZXhwZWN0ZWQgYG9iamVjdGAnKTtcbn1cblxuZnVuY3Rpb24gaXNOb2RlKHByb3BWYWx1ZSkge1xuICBzd2l0Y2godHlwZW9mIHByb3BWYWx1ZSkge1xuICAgIGNhc2UgJ251bWJlcic6XG4gICAgY2FzZSAnc3RyaW5nJzpcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIGNhc2UgJ2Jvb2xlYW4nOlxuICAgICAgcmV0dXJuICFwcm9wVmFsdWU7XG4gICAgY2FzZSAnb2JqZWN0JzpcbiAgICAgIGlmIChBcnJheS5pc0FycmF5KHByb3BWYWx1ZSkpIHtcbiAgICAgICAgcmV0dXJuIHByb3BWYWx1ZS5ldmVyeShpc05vZGUpO1xuICAgICAgfVxuICAgICAgaWYgKFJlYWN0RWxlbWVudC5pc1ZhbGlkRWxlbWVudChwcm9wVmFsdWUpKSB7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgfVxuICAgICAgZm9yICh2YXIgayBpbiBwcm9wVmFsdWUpIHtcbiAgICAgICAgaWYgKCFpc05vZGUocHJvcFZhbHVlW2tdKSkge1xuICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgcmV0dXJuIHRydWU7XG4gICAgZGVmYXVsdDpcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgfVxufVxuXG4vLyBFcXVpdmFsZW50IG9mIGB0eXBlb2ZgIGJ1dCB3aXRoIHNwZWNpYWwgaGFuZGxpbmcgZm9yIGFycmF5IGFuZCByZWdleHAuXG5mdW5jdGlvbiBnZXRQcm9wVHlwZShwcm9wVmFsdWUpIHtcbiAgdmFyIHByb3BUeXBlID0gdHlwZW9mIHByb3BWYWx1ZTtcbiAgaWYgKEFycmF5LmlzQXJyYXkocHJvcFZhbHVlKSkge1xuICAgIHJldHVybiAnYXJyYXknO1xuICB9XG4gIGlmIChwcm9wVmFsdWUgaW5zdGFuY2VvZiBSZWdFeHApIHtcbiAgICAvLyBPbGQgd2Via2l0cyAoYXQgbGVhc3QgdW50aWwgQW5kcm9pZCA0LjApIHJldHVybiAnZnVuY3Rpb24nIHJhdGhlciB0aGFuXG4gICAgLy8gJ29iamVjdCcgZm9yIHR5cGVvZiBhIFJlZ0V4cC4gV2UnbGwgbm9ybWFsaXplIHRoaXMgaGVyZSBzbyB0aGF0IC9ibGEvXG4gICAgLy8gcGFzc2VzIFByb3BUeXBlcy5vYmplY3QuXG4gICAgcmV0dXJuICdvYmplY3QnO1xuICB9XG4gIHJldHVybiBwcm9wVHlwZTtcbn1cblxuLy8gVGhpcyBoYW5kbGVzIG1vcmUgdHlwZXMgdGhhbiBgZ2V0UHJvcFR5cGVgLiBPbmx5IHVzZWQgZm9yIGVycm9yIG1lc3NhZ2VzLlxuLy8gU2VlIGBjcmVhdGVQcmltaXRpdmVUeXBlQ2hlY2tlcmAuXG5mdW5jdGlvbiBnZXRQcmVjaXNlVHlwZShwcm9wVmFsdWUpIHtcbiAgdmFyIHByb3BUeXBlID0gZ2V0UHJvcFR5cGUocHJvcFZhbHVlKTtcbiAgaWYgKHByb3BUeXBlID09PSAnb2JqZWN0Jykge1xuICAgIGlmIChwcm9wVmFsdWUgaW5zdGFuY2VvZiBEYXRlKSB7XG4gICAgICByZXR1cm4gJ2RhdGUnO1xuICAgIH0gZWxzZSBpZiAocHJvcFZhbHVlIGluc3RhbmNlb2YgUmVnRXhwKSB7XG4gICAgICByZXR1cm4gJ3JlZ2V4cCc7XG4gICAgfVxuICB9XG4gIHJldHVybiBwcm9wVHlwZTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBSZWFjdFByb3BUeXBlcztcbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBSZWFjdFB1dExpc3RlbmVyUXVldWVcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIFBvb2xlZENsYXNzID0gcmVxdWlyZShcIi4vUG9vbGVkQ2xhc3NcIik7XG52YXIgUmVhY3RCcm93c2VyRXZlbnRFbWl0dGVyID0gcmVxdWlyZShcIi4vUmVhY3RCcm93c2VyRXZlbnRFbWl0dGVyXCIpO1xuXG52YXIgYXNzaWduID0gcmVxdWlyZShcIi4vT2JqZWN0LmFzc2lnblwiKTtcblxuZnVuY3Rpb24gUmVhY3RQdXRMaXN0ZW5lclF1ZXVlKCkge1xuICB0aGlzLmxpc3RlbmVyc1RvUHV0ID0gW107XG59XG5cbmFzc2lnbihSZWFjdFB1dExpc3RlbmVyUXVldWUucHJvdG90eXBlLCB7XG4gIGVucXVldWVQdXRMaXN0ZW5lcjogZnVuY3Rpb24ocm9vdE5vZGVJRCwgcHJvcEtleSwgcHJvcFZhbHVlKSB7XG4gICAgdGhpcy5saXN0ZW5lcnNUb1B1dC5wdXNoKHtcbiAgICAgIHJvb3ROb2RlSUQ6IHJvb3ROb2RlSUQsXG4gICAgICBwcm9wS2V5OiBwcm9wS2V5LFxuICAgICAgcHJvcFZhbHVlOiBwcm9wVmFsdWVcbiAgICB9KTtcbiAgfSxcblxuICBwdXRMaXN0ZW5lcnM6IGZ1bmN0aW9uKCkge1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5saXN0ZW5lcnNUb1B1dC5sZW5ndGg7IGkrKykge1xuICAgICAgdmFyIGxpc3RlbmVyVG9QdXQgPSB0aGlzLmxpc3RlbmVyc1RvUHV0W2ldO1xuICAgICAgUmVhY3RCcm93c2VyRXZlbnRFbWl0dGVyLnB1dExpc3RlbmVyKFxuICAgICAgICBsaXN0ZW5lclRvUHV0LnJvb3ROb2RlSUQsXG4gICAgICAgIGxpc3RlbmVyVG9QdXQucHJvcEtleSxcbiAgICAgICAgbGlzdGVuZXJUb1B1dC5wcm9wVmFsdWVcbiAgICAgICk7XG4gICAgfVxuICB9LFxuXG4gIHJlc2V0OiBmdW5jdGlvbigpIHtcbiAgICB0aGlzLmxpc3RlbmVyc1RvUHV0Lmxlbmd0aCA9IDA7XG4gIH0sXG5cbiAgZGVzdHJ1Y3RvcjogZnVuY3Rpb24oKSB7XG4gICAgdGhpcy5yZXNldCgpO1xuICB9XG59KTtcblxuUG9vbGVkQ2xhc3MuYWRkUG9vbGluZ1RvKFJlYWN0UHV0TGlzdGVuZXJRdWV1ZSk7XG5cbm1vZHVsZS5leHBvcnRzID0gUmVhY3RQdXRMaXN0ZW5lclF1ZXVlO1xuIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIFJlYWN0UmVjb25jaWxlVHJhbnNhY3Rpb25cbiAqIEB0eXBlY2hlY2tzIHN0YXRpYy1vbmx5XG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBDYWxsYmFja1F1ZXVlID0gcmVxdWlyZShcIi4vQ2FsbGJhY2tRdWV1ZVwiKTtcbnZhciBQb29sZWRDbGFzcyA9IHJlcXVpcmUoXCIuL1Bvb2xlZENsYXNzXCIpO1xudmFyIFJlYWN0QnJvd3NlckV2ZW50RW1pdHRlciA9IHJlcXVpcmUoXCIuL1JlYWN0QnJvd3NlckV2ZW50RW1pdHRlclwiKTtcbnZhciBSZWFjdElucHV0U2VsZWN0aW9uID0gcmVxdWlyZShcIi4vUmVhY3RJbnB1dFNlbGVjdGlvblwiKTtcbnZhciBSZWFjdFB1dExpc3RlbmVyUXVldWUgPSByZXF1aXJlKFwiLi9SZWFjdFB1dExpc3RlbmVyUXVldWVcIik7XG52YXIgVHJhbnNhY3Rpb24gPSByZXF1aXJlKFwiLi9UcmFuc2FjdGlvblwiKTtcblxudmFyIGFzc2lnbiA9IHJlcXVpcmUoXCIuL09iamVjdC5hc3NpZ25cIik7XG5cbi8qKlxuICogRW5zdXJlcyB0aGF0LCB3aGVuIHBvc3NpYmxlLCB0aGUgc2VsZWN0aW9uIHJhbmdlIChjdXJyZW50bHkgc2VsZWN0ZWQgdGV4dFxuICogaW5wdXQpIGlzIG5vdCBkaXN0dXJiZWQgYnkgcGVyZm9ybWluZyB0aGUgdHJhbnNhY3Rpb24uXG4gKi9cbnZhciBTRUxFQ1RJT05fUkVTVE9SQVRJT04gPSB7XG4gIC8qKlxuICAgKiBAcmV0dXJuIHtTZWxlY3Rpb259IFNlbGVjdGlvbiBpbmZvcm1hdGlvbi5cbiAgICovXG4gIGluaXRpYWxpemU6IFJlYWN0SW5wdXRTZWxlY3Rpb24uZ2V0U2VsZWN0aW9uSW5mb3JtYXRpb24sXG4gIC8qKlxuICAgKiBAcGFyYW0ge1NlbGVjdGlvbn0gc2VsIFNlbGVjdGlvbiBpbmZvcm1hdGlvbiByZXR1cm5lZCBmcm9tIGBpbml0aWFsaXplYC5cbiAgICovXG4gIGNsb3NlOiBSZWFjdElucHV0U2VsZWN0aW9uLnJlc3RvcmVTZWxlY3Rpb25cbn07XG5cbi8qKlxuICogU3VwcHJlc3NlcyBldmVudHMgKGJsdXIvZm9jdXMpIHRoYXQgY291bGQgYmUgaW5hZHZlcnRlbnRseSBkaXNwYXRjaGVkIGR1ZSB0b1xuICogaGlnaCBsZXZlbCBET00gbWFuaXB1bGF0aW9ucyAobGlrZSB0ZW1wb3JhcmlseSByZW1vdmluZyBhIHRleHQgaW5wdXQgZnJvbSB0aGVcbiAqIERPTSkuXG4gKi9cbnZhciBFVkVOVF9TVVBQUkVTU0lPTiA9IHtcbiAgLyoqXG4gICAqIEByZXR1cm4ge2Jvb2xlYW59IFRoZSBlbmFibGVkIHN0YXR1cyBvZiBgUmVhY3RCcm93c2VyRXZlbnRFbWl0dGVyYCBiZWZvcmVcbiAgICogdGhlIHJlY29uY2lsaWF0aW9uLlxuICAgKi9cbiAgaW5pdGlhbGl6ZTogZnVuY3Rpb24oKSB7XG4gICAgdmFyIGN1cnJlbnRseUVuYWJsZWQgPSBSZWFjdEJyb3dzZXJFdmVudEVtaXR0ZXIuaXNFbmFibGVkKCk7XG4gICAgUmVhY3RCcm93c2VyRXZlbnRFbWl0dGVyLnNldEVuYWJsZWQoZmFsc2UpO1xuICAgIHJldHVybiBjdXJyZW50bHlFbmFibGVkO1xuICB9LFxuXG4gIC8qKlxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHByZXZpb3VzbHlFbmFibGVkIEVuYWJsZWQgc3RhdHVzIG9mXG4gICAqICAgYFJlYWN0QnJvd3NlckV2ZW50RW1pdHRlcmAgYmVmb3JlIHRoZSByZWNvbmNpbGlhdGlvbiBvY2N1cmVkLiBgY2xvc2VgXG4gICAqICAgcmVzdG9yZXMgdGhlIHByZXZpb3VzIHZhbHVlLlxuICAgKi9cbiAgY2xvc2U6IGZ1bmN0aW9uKHByZXZpb3VzbHlFbmFibGVkKSB7XG4gICAgUmVhY3RCcm93c2VyRXZlbnRFbWl0dGVyLnNldEVuYWJsZWQocHJldmlvdXNseUVuYWJsZWQpO1xuICB9XG59O1xuXG4vKipcbiAqIFByb3ZpZGVzIGEgcXVldWUgZm9yIGNvbGxlY3RpbmcgYGNvbXBvbmVudERpZE1vdW50YCBhbmRcbiAqIGBjb21wb25lbnREaWRVcGRhdGVgIGNhbGxiYWNrcyBkdXJpbmcgdGhlIHRoZSB0cmFuc2FjdGlvbi5cbiAqL1xudmFyIE9OX0RPTV9SRUFEWV9RVUVVRUlORyA9IHtcbiAgLyoqXG4gICAqIEluaXRpYWxpemVzIHRoZSBpbnRlcm5hbCBgb25ET01SZWFkeWAgcXVldWUuXG4gICAqL1xuICBpbml0aWFsaXplOiBmdW5jdGlvbigpIHtcbiAgICB0aGlzLnJlYWN0TW91bnRSZWFkeS5yZXNldCgpO1xuICB9LFxuXG4gIC8qKlxuICAgKiBBZnRlciBET00gaXMgZmx1c2hlZCwgaW52b2tlIGFsbCByZWdpc3RlcmVkIGBvbkRPTVJlYWR5YCBjYWxsYmFja3MuXG4gICAqL1xuICBjbG9zZTogZnVuY3Rpb24oKSB7XG4gICAgdGhpcy5yZWFjdE1vdW50UmVhZHkubm90aWZ5QWxsKCk7XG4gIH1cbn07XG5cbnZhciBQVVRfTElTVEVORVJfUVVFVUVJTkcgPSB7XG4gIGluaXRpYWxpemU6IGZ1bmN0aW9uKCkge1xuICAgIHRoaXMucHV0TGlzdGVuZXJRdWV1ZS5yZXNldCgpO1xuICB9LFxuXG4gIGNsb3NlOiBmdW5jdGlvbigpIHtcbiAgICB0aGlzLnB1dExpc3RlbmVyUXVldWUucHV0TGlzdGVuZXJzKCk7XG4gIH1cbn07XG5cbi8qKlxuICogRXhlY3V0ZWQgd2l0aGluIHRoZSBzY29wZSBvZiB0aGUgYFRyYW5zYWN0aW9uYCBpbnN0YW5jZS4gQ29uc2lkZXIgdGhlc2UgYXNcbiAqIGJlaW5nIG1lbWJlciBtZXRob2RzLCBidXQgd2l0aCBhbiBpbXBsaWVkIG9yZGVyaW5nIHdoaWxlIGJlaW5nIGlzb2xhdGVkIGZyb21cbiAqIGVhY2ggb3RoZXIuXG4gKi9cbnZhciBUUkFOU0FDVElPTl9XUkFQUEVSUyA9IFtcbiAgUFVUX0xJU1RFTkVSX1FVRVVFSU5HLFxuICBTRUxFQ1RJT05fUkVTVE9SQVRJT04sXG4gIEVWRU5UX1NVUFBSRVNTSU9OLFxuICBPTl9ET01fUkVBRFlfUVVFVUVJTkdcbl07XG5cbi8qKlxuICogQ3VycmVudGx5OlxuICogLSBUaGUgb3JkZXIgdGhhdCB0aGVzZSBhcmUgbGlzdGVkIGluIHRoZSB0cmFuc2FjdGlvbiBpcyBjcml0aWNhbDpcbiAqIC0gU3VwcHJlc3NlcyBldmVudHMuXG4gKiAtIFJlc3RvcmVzIHNlbGVjdGlvbiByYW5nZS5cbiAqXG4gKiBGdXR1cmU6XG4gKiAtIFJlc3RvcmUgZG9jdW1lbnQvb3ZlcmZsb3cgc2Nyb2xsIHBvc2l0aW9ucyB0aGF0IHdlcmUgdW5pbnRlbnRpb25hbGx5XG4gKiAgIG1vZGlmaWVkIHZpYSBET00gaW5zZXJ0aW9ucyBhYm92ZSB0aGUgdG9wIHZpZXdwb3J0IGJvdW5kYXJ5LlxuICogLSBJbXBsZW1lbnQvaW50ZWdyYXRlIHdpdGggY3VzdG9taXplZCBjb25zdHJhaW50IGJhc2VkIGxheW91dCBzeXN0ZW0gYW5kIGtlZXBcbiAqICAgdHJhY2sgb2Ygd2hpY2ggZGltZW5zaW9ucyBtdXN0IGJlIHJlbWVhc3VyZWQuXG4gKlxuICogQGNsYXNzIFJlYWN0UmVjb25jaWxlVHJhbnNhY3Rpb25cbiAqL1xuZnVuY3Rpb24gUmVhY3RSZWNvbmNpbGVUcmFuc2FjdGlvbigpIHtcbiAgdGhpcy5yZWluaXRpYWxpemVUcmFuc2FjdGlvbigpO1xuICAvLyBPbmx5IHNlcnZlci1zaWRlIHJlbmRlcmluZyByZWFsbHkgbmVlZHMgdGhpcyBvcHRpb24gKHNlZVxuICAvLyBgUmVhY3RTZXJ2ZXJSZW5kZXJpbmdgKSwgYnV0IHNlcnZlci1zaWRlIHVzZXNcbiAgLy8gYFJlYWN0U2VydmVyUmVuZGVyaW5nVHJhbnNhY3Rpb25gIGluc3RlYWQuIFRoaXMgb3B0aW9uIGlzIGhlcmUgc28gdGhhdCBpdCdzXG4gIC8vIGFjY2Vzc2libGUgYW5kIGRlZmF1bHRzIHRvIGZhbHNlIHdoZW4gYFJlYWN0RE9NQ29tcG9uZW50YCBhbmRcbiAgLy8gYFJlYWN0VGV4dENvbXBvbmVudGAgY2hlY2tzIGl0IGluIGBtb3VudENvbXBvbmVudGAuYFxuICB0aGlzLnJlbmRlclRvU3RhdGljTWFya3VwID0gZmFsc2U7XG4gIHRoaXMucmVhY3RNb3VudFJlYWR5ID0gQ2FsbGJhY2tRdWV1ZS5nZXRQb29sZWQobnVsbCk7XG4gIHRoaXMucHV0TGlzdGVuZXJRdWV1ZSA9IFJlYWN0UHV0TGlzdGVuZXJRdWV1ZS5nZXRQb29sZWQoKTtcbn1cblxudmFyIE1peGluID0ge1xuICAvKipcbiAgICogQHNlZSBUcmFuc2FjdGlvblxuICAgKiBAYWJzdHJhY3RcbiAgICogQGZpbmFsXG4gICAqIEByZXR1cm4ge2FycmF5PG9iamVjdD59IExpc3Qgb2Ygb3BlcmF0aW9uIHdyYXAgcHJvY2VlZHVyZXMuXG4gICAqICAgVE9ETzogY29udmVydCB0byBhcnJheTxUcmFuc2FjdGlvbldyYXBwZXI+XG4gICAqL1xuICBnZXRUcmFuc2FjdGlvbldyYXBwZXJzOiBmdW5jdGlvbigpIHtcbiAgICByZXR1cm4gVFJBTlNBQ1RJT05fV1JBUFBFUlM7XG4gIH0sXG5cbiAgLyoqXG4gICAqIEByZXR1cm4ge29iamVjdH0gVGhlIHF1ZXVlIHRvIGNvbGxlY3QgYG9uRE9NUmVhZHlgIGNhbGxiYWNrcyB3aXRoLlxuICAgKi9cbiAgZ2V0UmVhY3RNb3VudFJlYWR5OiBmdW5jdGlvbigpIHtcbiAgICByZXR1cm4gdGhpcy5yZWFjdE1vdW50UmVhZHk7XG4gIH0sXG5cbiAgZ2V0UHV0TGlzdGVuZXJRdWV1ZTogZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIHRoaXMucHV0TGlzdGVuZXJRdWV1ZTtcbiAgfSxcblxuICAvKipcbiAgICogYFBvb2xlZENsYXNzYCBsb29rcyBmb3IgdGhpcywgYW5kIHdpbGwgaW52b2tlIHRoaXMgYmVmb3JlIGFsbG93aW5nIHRoaXNcbiAgICogaW5zdGFuY2UgdG8gYmUgcmVzdXNlZC5cbiAgICovXG4gIGRlc3RydWN0b3I6IGZ1bmN0aW9uKCkge1xuICAgIENhbGxiYWNrUXVldWUucmVsZWFzZSh0aGlzLnJlYWN0TW91bnRSZWFkeSk7XG4gICAgdGhpcy5yZWFjdE1vdW50UmVhZHkgPSBudWxsO1xuXG4gICAgUmVhY3RQdXRMaXN0ZW5lclF1ZXVlLnJlbGVhc2UodGhpcy5wdXRMaXN0ZW5lclF1ZXVlKTtcbiAgICB0aGlzLnB1dExpc3RlbmVyUXVldWUgPSBudWxsO1xuICB9XG59O1xuXG5cbmFzc2lnbihSZWFjdFJlY29uY2lsZVRyYW5zYWN0aW9uLnByb3RvdHlwZSwgVHJhbnNhY3Rpb24uTWl4aW4sIE1peGluKTtcblxuUG9vbGVkQ2xhc3MuYWRkUG9vbGluZ1RvKFJlYWN0UmVjb25jaWxlVHJhbnNhY3Rpb24pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJlYWN0UmVjb25jaWxlVHJhbnNhY3Rpb247XG4iLCIvKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgUmVhY3RSb290SW5kZXhcbiAqIEB0eXBlY2hlY2tzXG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBSZWFjdFJvb3RJbmRleEluamVjdGlvbiA9IHtcbiAgLyoqXG4gICAqIEBwYXJhbSB7ZnVuY3Rpb259IF9jcmVhdGVSZWFjdFJvb3RJbmRleFxuICAgKi9cbiAgaW5qZWN0Q3JlYXRlUmVhY3RSb290SW5kZXg6IGZ1bmN0aW9uKF9jcmVhdGVSZWFjdFJvb3RJbmRleCkge1xuICAgIFJlYWN0Um9vdEluZGV4LmNyZWF0ZVJlYWN0Um9vdEluZGV4ID0gX2NyZWF0ZVJlYWN0Um9vdEluZGV4O1xuICB9XG59O1xuXG52YXIgUmVhY3RSb290SW5kZXggPSB7XG4gIGNyZWF0ZVJlYWN0Um9vdEluZGV4OiBudWxsLFxuICBpbmplY3Rpb246IFJlYWN0Um9vdEluZGV4SW5qZWN0aW9uXG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJlYWN0Um9vdEluZGV4O1xuIiwiKGZ1bmN0aW9uIChwcm9jZXNzKXtcbi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEB0eXBlY2hlY2tzIHN0YXRpYy1vbmx5XG4gKiBAcHJvdmlkZXNNb2R1bGUgUmVhY3RTZXJ2ZXJSZW5kZXJpbmdcbiAqL1xuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBSZWFjdEVsZW1lbnQgPSByZXF1aXJlKFwiLi9SZWFjdEVsZW1lbnRcIik7XG52YXIgUmVhY3RJbnN0YW5jZUhhbmRsZXMgPSByZXF1aXJlKFwiLi9SZWFjdEluc3RhbmNlSGFuZGxlc1wiKTtcbnZhciBSZWFjdE1hcmt1cENoZWNrc3VtID0gcmVxdWlyZShcIi4vUmVhY3RNYXJrdXBDaGVja3N1bVwiKTtcbnZhciBSZWFjdFNlcnZlclJlbmRlcmluZ1RyYW5zYWN0aW9uID1cbiAgcmVxdWlyZShcIi4vUmVhY3RTZXJ2ZXJSZW5kZXJpbmdUcmFuc2FjdGlvblwiKTtcblxudmFyIGluc3RhbnRpYXRlUmVhY3RDb21wb25lbnQgPSByZXF1aXJlKFwiLi9pbnN0YW50aWF0ZVJlYWN0Q29tcG9uZW50XCIpO1xudmFyIGludmFyaWFudCA9IHJlcXVpcmUoXCIuL2ludmFyaWFudFwiKTtcblxuLyoqXG4gKiBAcGFyYW0ge1JlYWN0RWxlbWVudH0gZWxlbWVudFxuICogQHJldHVybiB7c3RyaW5nfSB0aGUgSFRNTCBtYXJrdXBcbiAqL1xuZnVuY3Rpb24gcmVuZGVyVG9TdHJpbmcoZWxlbWVudCkge1xuICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgIFJlYWN0RWxlbWVudC5pc1ZhbGlkRWxlbWVudChlbGVtZW50KSxcbiAgICAncmVuZGVyVG9TdHJpbmcoKTogWW91IG11c3QgcGFzcyBhIHZhbGlkIFJlYWN0RWxlbWVudC4nXG4gICkgOiBpbnZhcmlhbnQoUmVhY3RFbGVtZW50LmlzVmFsaWRFbGVtZW50KGVsZW1lbnQpKSk7XG5cbiAgdmFyIHRyYW5zYWN0aW9uO1xuICB0cnkge1xuICAgIHZhciBpZCA9IFJlYWN0SW5zdGFuY2VIYW5kbGVzLmNyZWF0ZVJlYWN0Um9vdElEKCk7XG4gICAgdHJhbnNhY3Rpb24gPSBSZWFjdFNlcnZlclJlbmRlcmluZ1RyYW5zYWN0aW9uLmdldFBvb2xlZChmYWxzZSk7XG5cbiAgICByZXR1cm4gdHJhbnNhY3Rpb24ucGVyZm9ybShmdW5jdGlvbigpIHtcbiAgICAgIHZhciBjb21wb25lbnRJbnN0YW5jZSA9IGluc3RhbnRpYXRlUmVhY3RDb21wb25lbnQoZWxlbWVudCwgbnVsbCk7XG4gICAgICB2YXIgbWFya3VwID0gY29tcG9uZW50SW5zdGFuY2UubW91bnRDb21wb25lbnQoaWQsIHRyYW5zYWN0aW9uLCAwKTtcbiAgICAgIHJldHVybiBSZWFjdE1hcmt1cENoZWNrc3VtLmFkZENoZWNrc3VtVG9NYXJrdXAobWFya3VwKTtcbiAgICB9LCBudWxsKTtcbiAgfSBmaW5hbGx5IHtcbiAgICBSZWFjdFNlcnZlclJlbmRlcmluZ1RyYW5zYWN0aW9uLnJlbGVhc2UodHJhbnNhY3Rpb24pO1xuICB9XG59XG5cbi8qKlxuICogQHBhcmFtIHtSZWFjdEVsZW1lbnR9IGVsZW1lbnRcbiAqIEByZXR1cm4ge3N0cmluZ30gdGhlIEhUTUwgbWFya3VwLCB3aXRob3V0IHRoZSBleHRyYSBSZWFjdCBJRCBhbmQgY2hlY2tzdW1cbiAqIChmb3IgZ2VuZXJhdGluZyBzdGF0aWMgcGFnZXMpXG4gKi9cbmZ1bmN0aW9uIHJlbmRlclRvU3RhdGljTWFya3VwKGVsZW1lbnQpIHtcbiAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICBSZWFjdEVsZW1lbnQuaXNWYWxpZEVsZW1lbnQoZWxlbWVudCksXG4gICAgJ3JlbmRlclRvU3RhdGljTWFya3VwKCk6IFlvdSBtdXN0IHBhc3MgYSB2YWxpZCBSZWFjdEVsZW1lbnQuJ1xuICApIDogaW52YXJpYW50KFJlYWN0RWxlbWVudC5pc1ZhbGlkRWxlbWVudChlbGVtZW50KSkpO1xuXG4gIHZhciB0cmFuc2FjdGlvbjtcbiAgdHJ5IHtcbiAgICB2YXIgaWQgPSBSZWFjdEluc3RhbmNlSGFuZGxlcy5jcmVhdGVSZWFjdFJvb3RJRCgpO1xuICAgIHRyYW5zYWN0aW9uID0gUmVhY3RTZXJ2ZXJSZW5kZXJpbmdUcmFuc2FjdGlvbi5nZXRQb29sZWQodHJ1ZSk7XG5cbiAgICByZXR1cm4gdHJhbnNhY3Rpb24ucGVyZm9ybShmdW5jdGlvbigpIHtcbiAgICAgIHZhciBjb21wb25lbnRJbnN0YW5jZSA9IGluc3RhbnRpYXRlUmVhY3RDb21wb25lbnQoZWxlbWVudCwgbnVsbCk7XG4gICAgICByZXR1cm4gY29tcG9uZW50SW5zdGFuY2UubW91bnRDb21wb25lbnQoaWQsIHRyYW5zYWN0aW9uLCAwKTtcbiAgICB9LCBudWxsKTtcbiAgfSBmaW5hbGx5IHtcbiAgICBSZWFjdFNlcnZlclJlbmRlcmluZ1RyYW5zYWN0aW9uLnJlbGVhc2UodHJhbnNhY3Rpb24pO1xuICB9XG59XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICByZW5kZXJUb1N0cmluZzogcmVuZGVyVG9TdHJpbmcsXG4gIHJlbmRlclRvU3RhdGljTWFya3VwOiByZW5kZXJUb1N0YXRpY01hcmt1cFxufTtcblxufSkuY2FsbCh0aGlzLHJlcXVpcmUoJ19wcm9jZXNzJykpIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBSZWFjdFNlcnZlclJlbmRlcmluZ1RyYW5zYWN0aW9uXG4gKiBAdHlwZWNoZWNrc1xuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgUG9vbGVkQ2xhc3MgPSByZXF1aXJlKFwiLi9Qb29sZWRDbGFzc1wiKTtcbnZhciBDYWxsYmFja1F1ZXVlID0gcmVxdWlyZShcIi4vQ2FsbGJhY2tRdWV1ZVwiKTtcbnZhciBSZWFjdFB1dExpc3RlbmVyUXVldWUgPSByZXF1aXJlKFwiLi9SZWFjdFB1dExpc3RlbmVyUXVldWVcIik7XG52YXIgVHJhbnNhY3Rpb24gPSByZXF1aXJlKFwiLi9UcmFuc2FjdGlvblwiKTtcblxudmFyIGFzc2lnbiA9IHJlcXVpcmUoXCIuL09iamVjdC5hc3NpZ25cIik7XG52YXIgZW1wdHlGdW5jdGlvbiA9IHJlcXVpcmUoXCIuL2VtcHR5RnVuY3Rpb25cIik7XG5cbi8qKlxuICogUHJvdmlkZXMgYSBgQ2FsbGJhY2tRdWV1ZWAgcXVldWUgZm9yIGNvbGxlY3RpbmcgYG9uRE9NUmVhZHlgIGNhbGxiYWNrc1xuICogZHVyaW5nIHRoZSBwZXJmb3JtaW5nIG9mIHRoZSB0cmFuc2FjdGlvbi5cbiAqL1xudmFyIE9OX0RPTV9SRUFEWV9RVUVVRUlORyA9IHtcbiAgLyoqXG4gICAqIEluaXRpYWxpemVzIHRoZSBpbnRlcm5hbCBgb25ET01SZWFkeWAgcXVldWUuXG4gICAqL1xuICBpbml0aWFsaXplOiBmdW5jdGlvbigpIHtcbiAgICB0aGlzLnJlYWN0TW91bnRSZWFkeS5yZXNldCgpO1xuICB9LFxuXG4gIGNsb3NlOiBlbXB0eUZ1bmN0aW9uXG59O1xuXG52YXIgUFVUX0xJU1RFTkVSX1FVRVVFSU5HID0ge1xuICBpbml0aWFsaXplOiBmdW5jdGlvbigpIHtcbiAgICB0aGlzLnB1dExpc3RlbmVyUXVldWUucmVzZXQoKTtcbiAgfSxcblxuICBjbG9zZTogZW1wdHlGdW5jdGlvblxufTtcblxuLyoqXG4gKiBFeGVjdXRlZCB3aXRoaW4gdGhlIHNjb3BlIG9mIHRoZSBgVHJhbnNhY3Rpb25gIGluc3RhbmNlLiBDb25zaWRlciB0aGVzZSBhc1xuICogYmVpbmcgbWVtYmVyIG1ldGhvZHMsIGJ1dCB3aXRoIGFuIGltcGxpZWQgb3JkZXJpbmcgd2hpbGUgYmVpbmcgaXNvbGF0ZWQgZnJvbVxuICogZWFjaCBvdGhlci5cbiAqL1xudmFyIFRSQU5TQUNUSU9OX1dSQVBQRVJTID0gW1xuICBQVVRfTElTVEVORVJfUVVFVUVJTkcsXG4gIE9OX0RPTV9SRUFEWV9RVUVVRUlOR1xuXTtcblxuLyoqXG4gKiBAY2xhc3MgUmVhY3RTZXJ2ZXJSZW5kZXJpbmdUcmFuc2FjdGlvblxuICogQHBhcmFtIHtib29sZWFufSByZW5kZXJUb1N0YXRpY01hcmt1cFxuICovXG5mdW5jdGlvbiBSZWFjdFNlcnZlclJlbmRlcmluZ1RyYW5zYWN0aW9uKHJlbmRlclRvU3RhdGljTWFya3VwKSB7XG4gIHRoaXMucmVpbml0aWFsaXplVHJhbnNhY3Rpb24oKTtcbiAgdGhpcy5yZW5kZXJUb1N0YXRpY01hcmt1cCA9IHJlbmRlclRvU3RhdGljTWFya3VwO1xuICB0aGlzLnJlYWN0TW91bnRSZWFkeSA9IENhbGxiYWNrUXVldWUuZ2V0UG9vbGVkKG51bGwpO1xuICB0aGlzLnB1dExpc3RlbmVyUXVldWUgPSBSZWFjdFB1dExpc3RlbmVyUXVldWUuZ2V0UG9vbGVkKCk7XG59XG5cbnZhciBNaXhpbiA9IHtcbiAgLyoqXG4gICAqIEBzZWUgVHJhbnNhY3Rpb25cbiAgICogQGFic3RyYWN0XG4gICAqIEBmaW5hbFxuICAgKiBAcmV0dXJuIHthcnJheX0gRW1wdHkgbGlzdCBvZiBvcGVyYXRpb24gd3JhcCBwcm9jZWVkdXJlcy5cbiAgICovXG4gIGdldFRyYW5zYWN0aW9uV3JhcHBlcnM6IGZ1bmN0aW9uKCkge1xuICAgIHJldHVybiBUUkFOU0FDVElPTl9XUkFQUEVSUztcbiAgfSxcblxuICAvKipcbiAgICogQHJldHVybiB7b2JqZWN0fSBUaGUgcXVldWUgdG8gY29sbGVjdCBgb25ET01SZWFkeWAgY2FsbGJhY2tzIHdpdGguXG4gICAqL1xuICBnZXRSZWFjdE1vdW50UmVhZHk6IGZ1bmN0aW9uKCkge1xuICAgIHJldHVybiB0aGlzLnJlYWN0TW91bnRSZWFkeTtcbiAgfSxcblxuICBnZXRQdXRMaXN0ZW5lclF1ZXVlOiBmdW5jdGlvbigpIHtcbiAgICByZXR1cm4gdGhpcy5wdXRMaXN0ZW5lclF1ZXVlO1xuICB9LFxuXG4gIC8qKlxuICAgKiBgUG9vbGVkQ2xhc3NgIGxvb2tzIGZvciB0aGlzLCBhbmQgd2lsbCBpbnZva2UgdGhpcyBiZWZvcmUgYWxsb3dpbmcgdGhpc1xuICAgKiBpbnN0YW5jZSB0byBiZSByZXN1c2VkLlxuICAgKi9cbiAgZGVzdHJ1Y3RvcjogZnVuY3Rpb24oKSB7XG4gICAgQ2FsbGJhY2tRdWV1ZS5yZWxlYXNlKHRoaXMucmVhY3RNb3VudFJlYWR5KTtcbiAgICB0aGlzLnJlYWN0TW91bnRSZWFkeSA9IG51bGw7XG5cbiAgICBSZWFjdFB1dExpc3RlbmVyUXVldWUucmVsZWFzZSh0aGlzLnB1dExpc3RlbmVyUXVldWUpO1xuICAgIHRoaXMucHV0TGlzdGVuZXJRdWV1ZSA9IG51bGw7XG4gIH1cbn07XG5cblxuYXNzaWduKFxuICBSZWFjdFNlcnZlclJlbmRlcmluZ1RyYW5zYWN0aW9uLnByb3RvdHlwZSxcbiAgVHJhbnNhY3Rpb24uTWl4aW4sXG4gIE1peGluXG4pO1xuXG5Qb29sZWRDbGFzcy5hZGRQb29saW5nVG8oUmVhY3RTZXJ2ZXJSZW5kZXJpbmdUcmFuc2FjdGlvbik7XG5cbm1vZHVsZS5leHBvcnRzID0gUmVhY3RTZXJ2ZXJSZW5kZXJpbmdUcmFuc2FjdGlvbjtcbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBSZWFjdFRleHRDb21wb25lbnRcbiAqIEB0eXBlY2hlY2tzIHN0YXRpYy1vbmx5XG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBET01Qcm9wZXJ0eU9wZXJhdGlvbnMgPSByZXF1aXJlKFwiLi9ET01Qcm9wZXJ0eU9wZXJhdGlvbnNcIik7XG52YXIgUmVhY3RDb21wb25lbnQgPSByZXF1aXJlKFwiLi9SZWFjdENvbXBvbmVudFwiKTtcbnZhciBSZWFjdEVsZW1lbnQgPSByZXF1aXJlKFwiLi9SZWFjdEVsZW1lbnRcIik7XG5cbnZhciBhc3NpZ24gPSByZXF1aXJlKFwiLi9PYmplY3QuYXNzaWduXCIpO1xudmFyIGVzY2FwZVRleHRGb3JCcm93c2VyID0gcmVxdWlyZShcIi4vZXNjYXBlVGV4dEZvckJyb3dzZXJcIik7XG5cbi8qKlxuICogVGV4dCBub2RlcyB2aW9sYXRlIGEgY291cGxlIGFzc3VtcHRpb25zIHRoYXQgUmVhY3QgbWFrZXMgYWJvdXQgY29tcG9uZW50czpcbiAqXG4gKiAgLSBXaGVuIG1vdW50aW5nIHRleHQgaW50byB0aGUgRE9NLCBhZGphY2VudCB0ZXh0IG5vZGVzIGFyZSBtZXJnZWQuXG4gKiAgLSBUZXh0IG5vZGVzIGNhbm5vdCBiZSBhc3NpZ25lZCBhIFJlYWN0IHJvb3QgSUQuXG4gKlxuICogVGhpcyBjb21wb25lbnQgaXMgdXNlZCB0byB3cmFwIHN0cmluZ3MgaW4gZWxlbWVudHMgc28gdGhhdCB0aGV5IGNhbiB1bmRlcmdvXG4gKiB0aGUgc2FtZSByZWNvbmNpbGlhdGlvbiB0aGF0IGlzIGFwcGxpZWQgdG8gZWxlbWVudHMuXG4gKlxuICogVE9ETzogSW52ZXN0aWdhdGUgcmVwcmVzZW50aW5nIFJlYWN0IGNvbXBvbmVudHMgaW4gdGhlIERPTSB3aXRoIHRleHQgbm9kZXMuXG4gKlxuICogQGNsYXNzIFJlYWN0VGV4dENvbXBvbmVudFxuICogQGV4dGVuZHMgUmVhY3RDb21wb25lbnRcbiAqIEBpbnRlcm5hbFxuICovXG52YXIgUmVhY3RUZXh0Q29tcG9uZW50ID0gZnVuY3Rpb24ocHJvcHMpIHtcbiAgLy8gVGhpcyBjb25zdHJ1Y3RvciBhbmQgaXQncyBhcmd1bWVudCBpcyBjdXJyZW50bHkgdXNlZCBieSBtb2Nrcy5cbn07XG5cbmFzc2lnbihSZWFjdFRleHRDb21wb25lbnQucHJvdG90eXBlLCBSZWFjdENvbXBvbmVudC5NaXhpbiwge1xuXG4gIC8qKlxuICAgKiBDcmVhdGVzIHRoZSBtYXJrdXAgZm9yIHRoaXMgdGV4dCBub2RlLiBUaGlzIG5vZGUgaXMgbm90IGludGVuZGVkIHRvIGhhdmVcbiAgICogYW55IGZlYXR1cmVzIGJlc2lkZXMgY29udGFpbmluZyB0ZXh0IGNvbnRlbnQuXG4gICAqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSByb290SUQgRE9NIElEIG9mIHRoZSByb290IG5vZGUuXG4gICAqIEBwYXJhbSB7UmVhY3RSZWNvbmNpbGVUcmFuc2FjdGlvbnxSZWFjdFNlcnZlclJlbmRlcmluZ1RyYW5zYWN0aW9ufSB0cmFuc2FjdGlvblxuICAgKiBAcGFyYW0ge251bWJlcn0gbW91bnREZXB0aCBudW1iZXIgb2YgY29tcG9uZW50cyBpbiB0aGUgb3duZXIgaGllcmFyY2h5XG4gICAqIEByZXR1cm4ge3N0cmluZ30gTWFya3VwIGZvciB0aGlzIHRleHQgbm9kZS5cbiAgICogQGludGVybmFsXG4gICAqL1xuICBtb3VudENvbXBvbmVudDogZnVuY3Rpb24ocm9vdElELCB0cmFuc2FjdGlvbiwgbW91bnREZXB0aCkge1xuICAgIFJlYWN0Q29tcG9uZW50Lk1peGluLm1vdW50Q29tcG9uZW50LmNhbGwoXG4gICAgICB0aGlzLFxuICAgICAgcm9vdElELFxuICAgICAgdHJhbnNhY3Rpb24sXG4gICAgICBtb3VudERlcHRoXG4gICAgKTtcblxuICAgIHZhciBlc2NhcGVkVGV4dCA9IGVzY2FwZVRleHRGb3JCcm93c2VyKHRoaXMucHJvcHMpO1xuXG4gICAgaWYgKHRyYW5zYWN0aW9uLnJlbmRlclRvU3RhdGljTWFya3VwKSB7XG4gICAgICAvLyBOb3JtYWxseSB3ZSdkIHdyYXAgdGhpcyBpbiBhIGBzcGFuYCBmb3IgdGhlIHJlYXNvbnMgc3RhdGVkIGFib3ZlLCBidXRcbiAgICAgIC8vIHNpbmNlIHRoaXMgaXMgYSBzaXR1YXRpb24gd2hlcmUgUmVhY3Qgd29uJ3QgdGFrZSBvdmVyIChzdGF0aWMgcGFnZXMpLFxuICAgICAgLy8gd2UgY2FuIHNpbXBseSByZXR1cm4gdGhlIHRleHQgYXMgaXQgaXMuXG4gICAgICByZXR1cm4gZXNjYXBlZFRleHQ7XG4gICAgfVxuXG4gICAgcmV0dXJuIChcbiAgICAgICc8c3BhbiAnICsgRE9NUHJvcGVydHlPcGVyYXRpb25zLmNyZWF0ZU1hcmt1cEZvcklEKHJvb3RJRCkgKyAnPicgK1xuICAgICAgICBlc2NhcGVkVGV4dCArXG4gICAgICAnPC9zcGFuPidcbiAgICApO1xuICB9LFxuXG4gIC8qKlxuICAgKiBVcGRhdGVzIHRoaXMgY29tcG9uZW50IGJ5IHVwZGF0aW5nIHRoZSB0ZXh0IGNvbnRlbnQuXG4gICAqXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBuZXh0Q29tcG9uZW50IENvbnRhaW5zIHRoZSBuZXh0IHRleHQgY29udGVudC5cbiAgICogQHBhcmFtIHtSZWFjdFJlY29uY2lsZVRyYW5zYWN0aW9ufSB0cmFuc2FjdGlvblxuICAgKiBAaW50ZXJuYWxcbiAgICovXG4gIHJlY2VpdmVDb21wb25lbnQ6IGZ1bmN0aW9uKG5leHRDb21wb25lbnQsIHRyYW5zYWN0aW9uKSB7XG4gICAgdmFyIG5leHRQcm9wcyA9IG5leHRDb21wb25lbnQucHJvcHM7XG4gICAgaWYgKG5leHRQcm9wcyAhPT0gdGhpcy5wcm9wcykge1xuICAgICAgdGhpcy5wcm9wcyA9IG5leHRQcm9wcztcbiAgICAgIFJlYWN0Q29tcG9uZW50LkJhY2tlbmRJRE9wZXJhdGlvbnMudXBkYXRlVGV4dENvbnRlbnRCeUlEKFxuICAgICAgICB0aGlzLl9yb290Tm9kZUlELFxuICAgICAgICBuZXh0UHJvcHNcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbn0pO1xuXG52YXIgUmVhY3RUZXh0Q29tcG9uZW50RmFjdG9yeSA9IGZ1bmN0aW9uKHRleHQpIHtcbiAgLy8gQnlwYXNzIHZhbGlkYXRpb24gYW5kIGNvbmZpZ3VyYXRpb25cbiAgcmV0dXJuIG5ldyBSZWFjdEVsZW1lbnQoUmVhY3RUZXh0Q29tcG9uZW50LCBudWxsLCBudWxsLCBudWxsLCBudWxsLCB0ZXh0KTtcbn07XG5cblJlYWN0VGV4dENvbXBvbmVudEZhY3RvcnkudHlwZSA9IFJlYWN0VGV4dENvbXBvbmVudDtcblxubW9kdWxlLmV4cG9ydHMgPSBSZWFjdFRleHRDb21wb25lbnRGYWN0b3J5O1xuIiwiKGZ1bmN0aW9uIChwcm9jZXNzKXtcbi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBSZWFjdFVwZGF0ZXNcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIENhbGxiYWNrUXVldWUgPSByZXF1aXJlKFwiLi9DYWxsYmFja1F1ZXVlXCIpO1xudmFyIFBvb2xlZENsYXNzID0gcmVxdWlyZShcIi4vUG9vbGVkQ2xhc3NcIik7XG52YXIgUmVhY3RDdXJyZW50T3duZXIgPSByZXF1aXJlKFwiLi9SZWFjdEN1cnJlbnRPd25lclwiKTtcbnZhciBSZWFjdFBlcmYgPSByZXF1aXJlKFwiLi9SZWFjdFBlcmZcIik7XG52YXIgVHJhbnNhY3Rpb24gPSByZXF1aXJlKFwiLi9UcmFuc2FjdGlvblwiKTtcblxudmFyIGFzc2lnbiA9IHJlcXVpcmUoXCIuL09iamVjdC5hc3NpZ25cIik7XG52YXIgaW52YXJpYW50ID0gcmVxdWlyZShcIi4vaW52YXJpYW50XCIpO1xudmFyIHdhcm5pbmcgPSByZXF1aXJlKFwiLi93YXJuaW5nXCIpO1xuXG52YXIgZGlydHlDb21wb25lbnRzID0gW107XG52YXIgYXNhcENhbGxiYWNrUXVldWUgPSBDYWxsYmFja1F1ZXVlLmdldFBvb2xlZCgpO1xudmFyIGFzYXBFbnF1ZXVlZCA9IGZhbHNlO1xuXG52YXIgYmF0Y2hpbmdTdHJhdGVneSA9IG51bGw7XG5cbmZ1bmN0aW9uIGVuc3VyZUluamVjdGVkKCkge1xuICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgIFJlYWN0VXBkYXRlcy5SZWFjdFJlY29uY2lsZVRyYW5zYWN0aW9uICYmIGJhdGNoaW5nU3RyYXRlZ3ksXG4gICAgJ1JlYWN0VXBkYXRlczogbXVzdCBpbmplY3QgYSByZWNvbmNpbGUgdHJhbnNhY3Rpb24gY2xhc3MgYW5kIGJhdGNoaW5nICcgK1xuICAgICdzdHJhdGVneSdcbiAgKSA6IGludmFyaWFudChSZWFjdFVwZGF0ZXMuUmVhY3RSZWNvbmNpbGVUcmFuc2FjdGlvbiAmJiBiYXRjaGluZ1N0cmF0ZWd5KSk7XG59XG5cbnZhciBORVNURURfVVBEQVRFUyA9IHtcbiAgaW5pdGlhbGl6ZTogZnVuY3Rpb24oKSB7XG4gICAgdGhpcy5kaXJ0eUNvbXBvbmVudHNMZW5ndGggPSBkaXJ0eUNvbXBvbmVudHMubGVuZ3RoO1xuICB9LFxuICBjbG9zZTogZnVuY3Rpb24oKSB7XG4gICAgaWYgKHRoaXMuZGlydHlDb21wb25lbnRzTGVuZ3RoICE9PSBkaXJ0eUNvbXBvbmVudHMubGVuZ3RoKSB7XG4gICAgICAvLyBBZGRpdGlvbmFsIHVwZGF0ZXMgd2VyZSBlbnF1ZXVlZCBieSBjb21wb25lbnREaWRVcGRhdGUgaGFuZGxlcnMgb3JcbiAgICAgIC8vIHNpbWlsYXI7IGJlZm9yZSBvdXIgb3duIFVQREFURV9RVUVVRUlORyB3cmFwcGVyIGNsb3Nlcywgd2Ugd2FudCB0byBydW5cbiAgICAgIC8vIHRoZXNlIG5ldyB1cGRhdGVzIHNvIHRoYXQgaWYgQSdzIGNvbXBvbmVudERpZFVwZGF0ZSBjYWxscyBzZXRTdGF0ZSBvblxuICAgICAgLy8gQiwgQiB3aWxsIHVwZGF0ZSBiZWZvcmUgdGhlIGNhbGxiYWNrIEEncyB1cGRhdGVyIHByb3ZpZGVkIHdoZW4gY2FsbGluZ1xuICAgICAgLy8gc2V0U3RhdGUuXG4gICAgICBkaXJ0eUNvbXBvbmVudHMuc3BsaWNlKDAsIHRoaXMuZGlydHlDb21wb25lbnRzTGVuZ3RoKTtcbiAgICAgIGZsdXNoQmF0Y2hlZFVwZGF0ZXMoKTtcbiAgICB9IGVsc2Uge1xuICAgICAgZGlydHlDb21wb25lbnRzLmxlbmd0aCA9IDA7XG4gICAgfVxuICB9XG59O1xuXG52YXIgVVBEQVRFX1FVRVVFSU5HID0ge1xuICBpbml0aWFsaXplOiBmdW5jdGlvbigpIHtcbiAgICB0aGlzLmNhbGxiYWNrUXVldWUucmVzZXQoKTtcbiAgfSxcbiAgY2xvc2U6IGZ1bmN0aW9uKCkge1xuICAgIHRoaXMuY2FsbGJhY2tRdWV1ZS5ub3RpZnlBbGwoKTtcbiAgfVxufTtcblxudmFyIFRSQU5TQUNUSU9OX1dSQVBQRVJTID0gW05FU1RFRF9VUERBVEVTLCBVUERBVEVfUVVFVUVJTkddO1xuXG5mdW5jdGlvbiBSZWFjdFVwZGF0ZXNGbHVzaFRyYW5zYWN0aW9uKCkge1xuICB0aGlzLnJlaW5pdGlhbGl6ZVRyYW5zYWN0aW9uKCk7XG4gIHRoaXMuZGlydHlDb21wb25lbnRzTGVuZ3RoID0gbnVsbDtcbiAgdGhpcy5jYWxsYmFja1F1ZXVlID0gQ2FsbGJhY2tRdWV1ZS5nZXRQb29sZWQoKTtcbiAgdGhpcy5yZWNvbmNpbGVUcmFuc2FjdGlvbiA9XG4gICAgUmVhY3RVcGRhdGVzLlJlYWN0UmVjb25jaWxlVHJhbnNhY3Rpb24uZ2V0UG9vbGVkKCk7XG59XG5cbmFzc2lnbihcbiAgUmVhY3RVcGRhdGVzRmx1c2hUcmFuc2FjdGlvbi5wcm90b3R5cGUsXG4gIFRyYW5zYWN0aW9uLk1peGluLCB7XG4gIGdldFRyYW5zYWN0aW9uV3JhcHBlcnM6IGZ1bmN0aW9uKCkge1xuICAgIHJldHVybiBUUkFOU0FDVElPTl9XUkFQUEVSUztcbiAgfSxcblxuICBkZXN0cnVjdG9yOiBmdW5jdGlvbigpIHtcbiAgICB0aGlzLmRpcnR5Q29tcG9uZW50c0xlbmd0aCA9IG51bGw7XG4gICAgQ2FsbGJhY2tRdWV1ZS5yZWxlYXNlKHRoaXMuY2FsbGJhY2tRdWV1ZSk7XG4gICAgdGhpcy5jYWxsYmFja1F1ZXVlID0gbnVsbDtcbiAgICBSZWFjdFVwZGF0ZXMuUmVhY3RSZWNvbmNpbGVUcmFuc2FjdGlvbi5yZWxlYXNlKHRoaXMucmVjb25jaWxlVHJhbnNhY3Rpb24pO1xuICAgIHRoaXMucmVjb25jaWxlVHJhbnNhY3Rpb24gPSBudWxsO1xuICB9LFxuXG4gIHBlcmZvcm06IGZ1bmN0aW9uKG1ldGhvZCwgc2NvcGUsIGEpIHtcbiAgICAvLyBFc3NlbnRpYWxseSBjYWxscyBgdGhpcy5yZWNvbmNpbGVUcmFuc2FjdGlvbi5wZXJmb3JtKG1ldGhvZCwgc2NvcGUsIGEpYFxuICAgIC8vIHdpdGggdGhpcyB0cmFuc2FjdGlvbidzIHdyYXBwZXJzIGFyb3VuZCBpdC5cbiAgICByZXR1cm4gVHJhbnNhY3Rpb24uTWl4aW4ucGVyZm9ybS5jYWxsKFxuICAgICAgdGhpcyxcbiAgICAgIHRoaXMucmVjb25jaWxlVHJhbnNhY3Rpb24ucGVyZm9ybSxcbiAgICAgIHRoaXMucmVjb25jaWxlVHJhbnNhY3Rpb24sXG4gICAgICBtZXRob2QsXG4gICAgICBzY29wZSxcbiAgICAgIGFcbiAgICApO1xuICB9XG59KTtcblxuUG9vbGVkQ2xhc3MuYWRkUG9vbGluZ1RvKFJlYWN0VXBkYXRlc0ZsdXNoVHJhbnNhY3Rpb24pO1xuXG5mdW5jdGlvbiBiYXRjaGVkVXBkYXRlcyhjYWxsYmFjaywgYSwgYikge1xuICBlbnN1cmVJbmplY3RlZCgpO1xuICBiYXRjaGluZ1N0cmF0ZWd5LmJhdGNoZWRVcGRhdGVzKGNhbGxiYWNrLCBhLCBiKTtcbn1cblxuLyoqXG4gKiBBcnJheSBjb21wYXJhdG9yIGZvciBSZWFjdENvbXBvbmVudHMgYnkgb3duZXIgZGVwdGhcbiAqXG4gKiBAcGFyYW0ge1JlYWN0Q29tcG9uZW50fSBjMSBmaXJzdCBjb21wb25lbnQgeW91J3JlIGNvbXBhcmluZ1xuICogQHBhcmFtIHtSZWFjdENvbXBvbmVudH0gYzIgc2Vjb25kIGNvbXBvbmVudCB5b3UncmUgY29tcGFyaW5nXG4gKiBAcmV0dXJuIHtudW1iZXJ9IFJldHVybiB2YWx1ZSB1c2FibGUgYnkgQXJyYXkucHJvdG90eXBlLnNvcnQoKS5cbiAqL1xuZnVuY3Rpb24gbW91bnREZXB0aENvbXBhcmF0b3IoYzEsIGMyKSB7XG4gIHJldHVybiBjMS5fbW91bnREZXB0aCAtIGMyLl9tb3VudERlcHRoO1xufVxuXG5mdW5jdGlvbiBydW5CYXRjaGVkVXBkYXRlcyh0cmFuc2FjdGlvbikge1xuICB2YXIgbGVuID0gdHJhbnNhY3Rpb24uZGlydHlDb21wb25lbnRzTGVuZ3RoO1xuICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgIGxlbiA9PT0gZGlydHlDb21wb25lbnRzLmxlbmd0aCxcbiAgICAnRXhwZWN0ZWQgZmx1c2ggdHJhbnNhY3Rpb25cXCdzIHN0b3JlZCBkaXJ0eS1jb21wb25lbnRzIGxlbmd0aCAoJXMpIHRvICcgK1xuICAgICdtYXRjaCBkaXJ0eS1jb21wb25lbnRzIGFycmF5IGxlbmd0aCAoJXMpLicsXG4gICAgbGVuLFxuICAgIGRpcnR5Q29tcG9uZW50cy5sZW5ndGhcbiAgKSA6IGludmFyaWFudChsZW4gPT09IGRpcnR5Q29tcG9uZW50cy5sZW5ndGgpKTtcblxuICAvLyBTaW5jZSByZWNvbmNpbGluZyBhIGNvbXBvbmVudCBoaWdoZXIgaW4gdGhlIG93bmVyIGhpZXJhcmNoeSB1c3VhbGx5IChub3RcbiAgLy8gYWx3YXlzIC0tIHNlZSBzaG91bGRDb21wb25lbnRVcGRhdGUoKSkgd2lsbCByZWNvbmNpbGUgY2hpbGRyZW4sIHJlY29uY2lsZVxuICAvLyB0aGVtIGJlZm9yZSB0aGVpciBjaGlsZHJlbiBieSBzb3J0aW5nIHRoZSBhcnJheS5cbiAgZGlydHlDb21wb25lbnRzLnNvcnQobW91bnREZXB0aENvbXBhcmF0b3IpO1xuXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuOyBpKyspIHtcbiAgICAvLyBJZiBhIGNvbXBvbmVudCBpcyB1bm1vdW50ZWQgYmVmb3JlIHBlbmRpbmcgY2hhbmdlcyBhcHBseSwgaWdub3JlIHRoZW1cbiAgICAvLyBUT0RPOiBRdWV1ZSB1bm1vdW50cyBpbiB0aGUgc2FtZSBsaXN0IHRvIGF2b2lkIHRoaXMgaGFwcGVuaW5nIGF0IGFsbFxuICAgIHZhciBjb21wb25lbnQgPSBkaXJ0eUNvbXBvbmVudHNbaV07XG4gICAgaWYgKGNvbXBvbmVudC5pc01vdW50ZWQoKSkge1xuICAgICAgLy8gSWYgcGVyZm9ybVVwZGF0ZUlmTmVjZXNzYXJ5IGhhcHBlbnMgdG8gZW5xdWV1ZSBhbnkgbmV3IHVwZGF0ZXMsIHdlXG4gICAgICAvLyBzaG91bGRuJ3QgZXhlY3V0ZSB0aGUgY2FsbGJhY2tzIHVudGlsIHRoZSBuZXh0IHJlbmRlciBoYXBwZW5zLCBzb1xuICAgICAgLy8gc3Rhc2ggdGhlIGNhbGxiYWNrcyBmaXJzdFxuICAgICAgdmFyIGNhbGxiYWNrcyA9IGNvbXBvbmVudC5fcGVuZGluZ0NhbGxiYWNrcztcbiAgICAgIGNvbXBvbmVudC5fcGVuZGluZ0NhbGxiYWNrcyA9IG51bGw7XG4gICAgICBjb21wb25lbnQucGVyZm9ybVVwZGF0ZUlmTmVjZXNzYXJ5KHRyYW5zYWN0aW9uLnJlY29uY2lsZVRyYW5zYWN0aW9uKTtcblxuICAgICAgaWYgKGNhbGxiYWNrcykge1xuICAgICAgICBmb3IgKHZhciBqID0gMDsgaiA8IGNhbGxiYWNrcy5sZW5ndGg7IGorKykge1xuICAgICAgICAgIHRyYW5zYWN0aW9uLmNhbGxiYWNrUXVldWUuZW5xdWV1ZShcbiAgICAgICAgICAgIGNhbGxiYWNrc1tqXSxcbiAgICAgICAgICAgIGNvbXBvbmVudFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cbn1cblxudmFyIGZsdXNoQmF0Y2hlZFVwZGF0ZXMgPSBSZWFjdFBlcmYubWVhc3VyZShcbiAgJ1JlYWN0VXBkYXRlcycsXG4gICdmbHVzaEJhdGNoZWRVcGRhdGVzJyxcbiAgZnVuY3Rpb24oKSB7XG4gICAgLy8gUmVhY3RVcGRhdGVzRmx1c2hUcmFuc2FjdGlvbidzIHdyYXBwZXJzIHdpbGwgY2xlYXIgdGhlIGRpcnR5Q29tcG9uZW50c1xuICAgIC8vIGFycmF5IGFuZCBwZXJmb3JtIGFueSB1cGRhdGVzIGVucXVldWVkIGJ5IG1vdW50LXJlYWR5IGhhbmRsZXJzIChpLmUuLFxuICAgIC8vIGNvbXBvbmVudERpZFVwZGF0ZSkgYnV0IHdlIG5lZWQgdG8gY2hlY2sgaGVyZSB0b28gaW4gb3JkZXIgdG8gY2F0Y2hcbiAgICAvLyB1cGRhdGVzIGVucXVldWVkIGJ5IHNldFN0YXRlIGNhbGxiYWNrcyBhbmQgYXNhcCBjYWxscy5cbiAgICB3aGlsZSAoZGlydHlDb21wb25lbnRzLmxlbmd0aCB8fCBhc2FwRW5xdWV1ZWQpIHtcbiAgICAgIGlmIChkaXJ0eUNvbXBvbmVudHMubGVuZ3RoKSB7XG4gICAgICAgIHZhciB0cmFuc2FjdGlvbiA9IFJlYWN0VXBkYXRlc0ZsdXNoVHJhbnNhY3Rpb24uZ2V0UG9vbGVkKCk7XG4gICAgICAgIHRyYW5zYWN0aW9uLnBlcmZvcm0ocnVuQmF0Y2hlZFVwZGF0ZXMsIG51bGwsIHRyYW5zYWN0aW9uKTtcbiAgICAgICAgUmVhY3RVcGRhdGVzRmx1c2hUcmFuc2FjdGlvbi5yZWxlYXNlKHRyYW5zYWN0aW9uKTtcbiAgICAgIH1cblxuICAgICAgaWYgKGFzYXBFbnF1ZXVlZCkge1xuICAgICAgICBhc2FwRW5xdWV1ZWQgPSBmYWxzZTtcbiAgICAgICAgdmFyIHF1ZXVlID0gYXNhcENhbGxiYWNrUXVldWU7XG4gICAgICAgIGFzYXBDYWxsYmFja1F1ZXVlID0gQ2FsbGJhY2tRdWV1ZS5nZXRQb29sZWQoKTtcbiAgICAgICAgcXVldWUubm90aWZ5QWxsKCk7XG4gICAgICAgIENhbGxiYWNrUXVldWUucmVsZWFzZShxdWV1ZSk7XG4gICAgICB9XG4gICAgfVxuICB9XG4pO1xuXG4vKipcbiAqIE1hcmsgYSBjb21wb25lbnQgYXMgbmVlZGluZyBhIHJlcmVuZGVyLCBhZGRpbmcgYW4gb3B0aW9uYWwgY2FsbGJhY2sgdG8gYVxuICogbGlzdCBvZiBmdW5jdGlvbnMgd2hpY2ggd2lsbCBiZSBleGVjdXRlZCBvbmNlIHRoZSByZXJlbmRlciBvY2N1cnMuXG4gKi9cbmZ1bmN0aW9uIGVucXVldWVVcGRhdGUoY29tcG9uZW50LCBjYWxsYmFjaykge1xuICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICFjYWxsYmFjayB8fCB0eXBlb2YgY2FsbGJhY2sgPT09IFwiZnVuY3Rpb25cIixcbiAgICAnZW5xdWV1ZVVwZGF0ZSguLi4pOiBZb3UgY2FsbGVkIGBzZXRQcm9wc2AsIGByZXBsYWNlUHJvcHNgLCAnICtcbiAgICAnYHNldFN0YXRlYCwgYHJlcGxhY2VTdGF0ZWAsIG9yIGBmb3JjZVVwZGF0ZWAgd2l0aCBhIGNhbGxiYWNrIHRoYXQgJyArXG4gICAgJ2lzblxcJ3QgY2FsbGFibGUuJ1xuICApIDogaW52YXJpYW50KCFjYWxsYmFjayB8fCB0eXBlb2YgY2FsbGJhY2sgPT09IFwiZnVuY3Rpb25cIikpO1xuICBlbnN1cmVJbmplY3RlZCgpO1xuXG4gIC8vIFZhcmlvdXMgcGFydHMgb2Ygb3VyIGNvZGUgKHN1Y2ggYXMgUmVhY3RDb21wb3NpdGVDb21wb25lbnQnc1xuICAvLyBfcmVuZGVyVmFsaWRhdGVkQ29tcG9uZW50KSBhc3N1bWUgdGhhdCBjYWxscyB0byByZW5kZXIgYXJlbid0IG5lc3RlZDtcbiAgLy8gdmVyaWZ5IHRoYXQgdGhhdCdzIHRoZSBjYXNlLiAoVGhpcyBpcyBjYWxsZWQgYnkgZWFjaCB0b3AtbGV2ZWwgdXBkYXRlXG4gIC8vIGZ1bmN0aW9uLCBsaWtlIHNldFByb3BzLCBzZXRTdGF0ZSwgZm9yY2VVcGRhdGUsIGV0Yy47IGNyZWF0aW9uIGFuZFxuICAvLyBkZXN0cnVjdGlvbiBvZiB0b3AtbGV2ZWwgY29tcG9uZW50cyBpcyBndWFyZGVkIGluIFJlYWN0TW91bnQuKVxuICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gd2FybmluZyhcbiAgICBSZWFjdEN1cnJlbnRPd25lci5jdXJyZW50ID09IG51bGwsXG4gICAgJ2VucXVldWVVcGRhdGUoKTogUmVuZGVyIG1ldGhvZHMgc2hvdWxkIGJlIGEgcHVyZSBmdW5jdGlvbiBvZiBwcm9wcyAnICtcbiAgICAnYW5kIHN0YXRlOyB0cmlnZ2VyaW5nIG5lc3RlZCBjb21wb25lbnQgdXBkYXRlcyBmcm9tIHJlbmRlciBpcyBub3QgJyArXG4gICAgJ2FsbG93ZWQuIElmIG5lY2Vzc2FyeSwgdHJpZ2dlciBuZXN0ZWQgdXBkYXRlcyBpbiAnICtcbiAgICAnY29tcG9uZW50RGlkVXBkYXRlLidcbiAgKSA6IG51bGwpO1xuXG4gIGlmICghYmF0Y2hpbmdTdHJhdGVneS5pc0JhdGNoaW5nVXBkYXRlcykge1xuICAgIGJhdGNoaW5nU3RyYXRlZ3kuYmF0Y2hlZFVwZGF0ZXMoZW5xdWV1ZVVwZGF0ZSwgY29tcG9uZW50LCBjYWxsYmFjayk7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgZGlydHlDb21wb25lbnRzLnB1c2goY29tcG9uZW50KTtcblxuICBpZiAoY2FsbGJhY2spIHtcbiAgICBpZiAoY29tcG9uZW50Ll9wZW5kaW5nQ2FsbGJhY2tzKSB7XG4gICAgICBjb21wb25lbnQuX3BlbmRpbmdDYWxsYmFja3MucHVzaChjYWxsYmFjayk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbXBvbmVudC5fcGVuZGluZ0NhbGxiYWNrcyA9IFtjYWxsYmFja107XG4gICAgfVxuICB9XG59XG5cbi8qKlxuICogRW5xdWV1ZSBhIGNhbGxiYWNrIHRvIGJlIHJ1biBhdCB0aGUgZW5kIG9mIHRoZSBjdXJyZW50IGJhdGNoaW5nIGN5Y2xlLiBUaHJvd3NcbiAqIGlmIG5vIHVwZGF0ZXMgYXJlIGN1cnJlbnRseSBiZWluZyBwZXJmb3JtZWQuXG4gKi9cbmZ1bmN0aW9uIGFzYXAoY2FsbGJhY2ssIGNvbnRleHQpIHtcbiAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICBiYXRjaGluZ1N0cmF0ZWd5LmlzQmF0Y2hpbmdVcGRhdGVzLFxuICAgICdSZWFjdFVwZGF0ZXMuYXNhcDogQ2FuXFwndCBlbnF1ZXVlIGFuIGFzYXAgY2FsbGJhY2sgaW4gYSBjb250ZXh0IHdoZXJlJyArXG4gICAgJ3VwZGF0ZXMgYXJlIG5vdCBiZWluZyBiYXRjaGVkLidcbiAgKSA6IGludmFyaWFudChiYXRjaGluZ1N0cmF0ZWd5LmlzQmF0Y2hpbmdVcGRhdGVzKSk7XG4gIGFzYXBDYWxsYmFja1F1ZXVlLmVucXVldWUoY2FsbGJhY2ssIGNvbnRleHQpO1xuICBhc2FwRW5xdWV1ZWQgPSB0cnVlO1xufVxuXG52YXIgUmVhY3RVcGRhdGVzSW5qZWN0aW9uID0ge1xuICBpbmplY3RSZWNvbmNpbGVUcmFuc2FjdGlvbjogZnVuY3Rpb24oUmVjb25jaWxlVHJhbnNhY3Rpb24pIHtcbiAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgUmVjb25jaWxlVHJhbnNhY3Rpb24sXG4gICAgICAnUmVhY3RVcGRhdGVzOiBtdXN0IHByb3ZpZGUgYSByZWNvbmNpbGUgdHJhbnNhY3Rpb24gY2xhc3MnXG4gICAgKSA6IGludmFyaWFudChSZWNvbmNpbGVUcmFuc2FjdGlvbikpO1xuICAgIFJlYWN0VXBkYXRlcy5SZWFjdFJlY29uY2lsZVRyYW5zYWN0aW9uID0gUmVjb25jaWxlVHJhbnNhY3Rpb247XG4gIH0sXG5cbiAgaW5qZWN0QmF0Y2hpbmdTdHJhdGVneTogZnVuY3Rpb24oX2JhdGNoaW5nU3RyYXRlZ3kpIHtcbiAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgX2JhdGNoaW5nU3RyYXRlZ3ksXG4gICAgICAnUmVhY3RVcGRhdGVzOiBtdXN0IHByb3ZpZGUgYSBiYXRjaGluZyBzdHJhdGVneSdcbiAgICApIDogaW52YXJpYW50KF9iYXRjaGluZ1N0cmF0ZWd5KSk7XG4gICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgIHR5cGVvZiBfYmF0Y2hpbmdTdHJhdGVneS5iYXRjaGVkVXBkYXRlcyA9PT0gJ2Z1bmN0aW9uJyxcbiAgICAgICdSZWFjdFVwZGF0ZXM6IG11c3QgcHJvdmlkZSBhIGJhdGNoZWRVcGRhdGVzKCkgZnVuY3Rpb24nXG4gICAgKSA6IGludmFyaWFudCh0eXBlb2YgX2JhdGNoaW5nU3RyYXRlZ3kuYmF0Y2hlZFVwZGF0ZXMgPT09ICdmdW5jdGlvbicpKTtcbiAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgdHlwZW9mIF9iYXRjaGluZ1N0cmF0ZWd5LmlzQmF0Y2hpbmdVcGRhdGVzID09PSAnYm9vbGVhbicsXG4gICAgICAnUmVhY3RVcGRhdGVzOiBtdXN0IHByb3ZpZGUgYW4gaXNCYXRjaGluZ1VwZGF0ZXMgYm9vbGVhbiBhdHRyaWJ1dGUnXG4gICAgKSA6IGludmFyaWFudCh0eXBlb2YgX2JhdGNoaW5nU3RyYXRlZ3kuaXNCYXRjaGluZ1VwZGF0ZXMgPT09ICdib29sZWFuJykpO1xuICAgIGJhdGNoaW5nU3RyYXRlZ3kgPSBfYmF0Y2hpbmdTdHJhdGVneTtcbiAgfVxufTtcblxudmFyIFJlYWN0VXBkYXRlcyA9IHtcbiAgLyoqXG4gICAqIFJlYWN0IHJlZmVyZW5jZXMgYFJlYWN0UmVjb25jaWxlVHJhbnNhY3Rpb25gIHVzaW5nIHRoaXMgcHJvcGVydHkgaW4gb3JkZXJcbiAgICogdG8gYWxsb3cgZGVwZW5kZW5jeSBpbmplY3Rpb24uXG4gICAqXG4gICAqIEBpbnRlcm5hbFxuICAgKi9cbiAgUmVhY3RSZWNvbmNpbGVUcmFuc2FjdGlvbjogbnVsbCxcblxuICBiYXRjaGVkVXBkYXRlczogYmF0Y2hlZFVwZGF0ZXMsXG4gIGVucXVldWVVcGRhdGU6IGVucXVldWVVcGRhdGUsXG4gIGZsdXNoQmF0Y2hlZFVwZGF0ZXM6IGZsdXNoQmF0Y2hlZFVwZGF0ZXMsXG4gIGluamVjdGlvbjogUmVhY3RVcGRhdGVzSW5qZWN0aW9uLFxuICBhc2FwOiBhc2FwXG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJlYWN0VXBkYXRlcztcblxufSkuY2FsbCh0aGlzLHJlcXVpcmUoJ19wcm9jZXNzJykpIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIFNWR0RPTVByb3BlcnR5Q29uZmlnXG4gKi9cblxuLypqc2xpbnQgYml0d2lzZTogdHJ1ZSovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgRE9NUHJvcGVydHkgPSByZXF1aXJlKFwiLi9ET01Qcm9wZXJ0eVwiKTtcblxudmFyIE1VU1RfVVNFX0FUVFJJQlVURSA9IERPTVByb3BlcnR5LmluamVjdGlvbi5NVVNUX1VTRV9BVFRSSUJVVEU7XG5cbnZhciBTVkdET01Qcm9wZXJ0eUNvbmZpZyA9IHtcbiAgUHJvcGVydGllczoge1xuICAgIGN4OiBNVVNUX1VTRV9BVFRSSUJVVEUsXG4gICAgY3k6IE1VU1RfVVNFX0FUVFJJQlVURSxcbiAgICBkOiBNVVNUX1VTRV9BVFRSSUJVVEUsXG4gICAgZHg6IE1VU1RfVVNFX0FUVFJJQlVURSxcbiAgICBkeTogTVVTVF9VU0VfQVRUUklCVVRFLFxuICAgIGZpbGw6IE1VU1RfVVNFX0FUVFJJQlVURSxcbiAgICBmaWxsT3BhY2l0eTogTVVTVF9VU0VfQVRUUklCVVRFLFxuICAgIGZvbnRGYW1pbHk6IE1VU1RfVVNFX0FUVFJJQlVURSxcbiAgICBmb250U2l6ZTogTVVTVF9VU0VfQVRUUklCVVRFLFxuICAgIGZ4OiBNVVNUX1VTRV9BVFRSSUJVVEUsXG4gICAgZnk6IE1VU1RfVVNFX0FUVFJJQlVURSxcbiAgICBncmFkaWVudFRyYW5zZm9ybTogTVVTVF9VU0VfQVRUUklCVVRFLFxuICAgIGdyYWRpZW50VW5pdHM6IE1VU1RfVVNFX0FUVFJJQlVURSxcbiAgICBtYXJrZXJFbmQ6IE1VU1RfVVNFX0FUVFJJQlVURSxcbiAgICBtYXJrZXJNaWQ6IE1VU1RfVVNFX0FUVFJJQlVURSxcbiAgICBtYXJrZXJTdGFydDogTVVTVF9VU0VfQVRUUklCVVRFLFxuICAgIG9mZnNldDogTVVTVF9VU0VfQVRUUklCVVRFLFxuICAgIG9wYWNpdHk6IE1VU1RfVVNFX0FUVFJJQlVURSxcbiAgICBwYXR0ZXJuQ29udGVudFVuaXRzOiBNVVNUX1VTRV9BVFRSSUJVVEUsXG4gICAgcGF0dGVyblVuaXRzOiBNVVNUX1VTRV9BVFRSSUJVVEUsXG4gICAgcG9pbnRzOiBNVVNUX1VTRV9BVFRSSUJVVEUsXG4gICAgcHJlc2VydmVBc3BlY3RSYXRpbzogTVVTVF9VU0VfQVRUUklCVVRFLFxuICAgIHI6IE1VU1RfVVNFX0FUVFJJQlVURSxcbiAgICByeDogTVVTVF9VU0VfQVRUUklCVVRFLFxuICAgIHJ5OiBNVVNUX1VTRV9BVFRSSUJVVEUsXG4gICAgc3ByZWFkTWV0aG9kOiBNVVNUX1VTRV9BVFRSSUJVVEUsXG4gICAgc3RvcENvbG9yOiBNVVNUX1VTRV9BVFRSSUJVVEUsXG4gICAgc3RvcE9wYWNpdHk6IE1VU1RfVVNFX0FUVFJJQlVURSxcbiAgICBzdHJva2U6IE1VU1RfVVNFX0FUVFJJQlVURSxcbiAgICBzdHJva2VEYXNoYXJyYXk6IE1VU1RfVVNFX0FUVFJJQlVURSxcbiAgICBzdHJva2VMaW5lY2FwOiBNVVNUX1VTRV9BVFRSSUJVVEUsXG4gICAgc3Ryb2tlT3BhY2l0eTogTVVTVF9VU0VfQVRUUklCVVRFLFxuICAgIHN0cm9rZVdpZHRoOiBNVVNUX1VTRV9BVFRSSUJVVEUsXG4gICAgdGV4dEFuY2hvcjogTVVTVF9VU0VfQVRUUklCVVRFLFxuICAgIHRyYW5zZm9ybTogTVVTVF9VU0VfQVRUUklCVVRFLFxuICAgIHZlcnNpb246IE1VU1RfVVNFX0FUVFJJQlVURSxcbiAgICB2aWV3Qm94OiBNVVNUX1VTRV9BVFRSSUJVVEUsXG4gICAgeDE6IE1VU1RfVVNFX0FUVFJJQlVURSxcbiAgICB4MjogTVVTVF9VU0VfQVRUUklCVVRFLFxuICAgIHg6IE1VU1RfVVNFX0FUVFJJQlVURSxcbiAgICB5MTogTVVTVF9VU0VfQVRUUklCVVRFLFxuICAgIHkyOiBNVVNUX1VTRV9BVFRSSUJVVEUsXG4gICAgeTogTVVTVF9VU0VfQVRUUklCVVRFXG4gIH0sXG4gIERPTUF0dHJpYnV0ZU5hbWVzOiB7XG4gICAgZmlsbE9wYWNpdHk6ICdmaWxsLW9wYWNpdHknLFxuICAgIGZvbnRGYW1pbHk6ICdmb250LWZhbWlseScsXG4gICAgZm9udFNpemU6ICdmb250LXNpemUnLFxuICAgIGdyYWRpZW50VHJhbnNmb3JtOiAnZ3JhZGllbnRUcmFuc2Zvcm0nLFxuICAgIGdyYWRpZW50VW5pdHM6ICdncmFkaWVudFVuaXRzJyxcbiAgICBtYXJrZXJFbmQ6ICdtYXJrZXItZW5kJyxcbiAgICBtYXJrZXJNaWQ6ICdtYXJrZXItbWlkJyxcbiAgICBtYXJrZXJTdGFydDogJ21hcmtlci1zdGFydCcsXG4gICAgcGF0dGVybkNvbnRlbnRVbml0czogJ3BhdHRlcm5Db250ZW50VW5pdHMnLFxuICAgIHBhdHRlcm5Vbml0czogJ3BhdHRlcm5Vbml0cycsXG4gICAgcHJlc2VydmVBc3BlY3RSYXRpbzogJ3ByZXNlcnZlQXNwZWN0UmF0aW8nLFxuICAgIHNwcmVhZE1ldGhvZDogJ3NwcmVhZE1ldGhvZCcsXG4gICAgc3RvcENvbG9yOiAnc3RvcC1jb2xvcicsXG4gICAgc3RvcE9wYWNpdHk6ICdzdG9wLW9wYWNpdHknLFxuICAgIHN0cm9rZURhc2hhcnJheTogJ3N0cm9rZS1kYXNoYXJyYXknLFxuICAgIHN0cm9rZUxpbmVjYXA6ICdzdHJva2UtbGluZWNhcCcsXG4gICAgc3Ryb2tlT3BhY2l0eTogJ3N0cm9rZS1vcGFjaXR5JyxcbiAgICBzdHJva2VXaWR0aDogJ3N0cm9rZS13aWR0aCcsXG4gICAgdGV4dEFuY2hvcjogJ3RleHQtYW5jaG9yJyxcbiAgICB2aWV3Qm94OiAndmlld0JveCdcbiAgfVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBTVkdET01Qcm9wZXJ0eUNvbmZpZztcbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBTZWxlY3RFdmVudFBsdWdpblxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgRXZlbnRDb25zdGFudHMgPSByZXF1aXJlKFwiLi9FdmVudENvbnN0YW50c1wiKTtcbnZhciBFdmVudFByb3BhZ2F0b3JzID0gcmVxdWlyZShcIi4vRXZlbnRQcm9wYWdhdG9yc1wiKTtcbnZhciBSZWFjdElucHV0U2VsZWN0aW9uID0gcmVxdWlyZShcIi4vUmVhY3RJbnB1dFNlbGVjdGlvblwiKTtcbnZhciBTeW50aGV0aWNFdmVudCA9IHJlcXVpcmUoXCIuL1N5bnRoZXRpY0V2ZW50XCIpO1xuXG52YXIgZ2V0QWN0aXZlRWxlbWVudCA9IHJlcXVpcmUoXCIuL2dldEFjdGl2ZUVsZW1lbnRcIik7XG52YXIgaXNUZXh0SW5wdXRFbGVtZW50ID0gcmVxdWlyZShcIi4vaXNUZXh0SW5wdXRFbGVtZW50XCIpO1xudmFyIGtleU9mID0gcmVxdWlyZShcIi4va2V5T2ZcIik7XG52YXIgc2hhbGxvd0VxdWFsID0gcmVxdWlyZShcIi4vc2hhbGxvd0VxdWFsXCIpO1xuXG52YXIgdG9wTGV2ZWxUeXBlcyA9IEV2ZW50Q29uc3RhbnRzLnRvcExldmVsVHlwZXM7XG5cbnZhciBldmVudFR5cGVzID0ge1xuICBzZWxlY3Q6IHtcbiAgICBwaGFzZWRSZWdpc3RyYXRpb25OYW1lczoge1xuICAgICAgYnViYmxlZDoga2V5T2Yoe29uU2VsZWN0OiBudWxsfSksXG4gICAgICBjYXB0dXJlZDoga2V5T2Yoe29uU2VsZWN0Q2FwdHVyZTogbnVsbH0pXG4gICAgfSxcbiAgICBkZXBlbmRlbmNpZXM6IFtcbiAgICAgIHRvcExldmVsVHlwZXMudG9wQmx1cixcbiAgICAgIHRvcExldmVsVHlwZXMudG9wQ29udGV4dE1lbnUsXG4gICAgICB0b3BMZXZlbFR5cGVzLnRvcEZvY3VzLFxuICAgICAgdG9wTGV2ZWxUeXBlcy50b3BLZXlEb3duLFxuICAgICAgdG9wTGV2ZWxUeXBlcy50b3BNb3VzZURvd24sXG4gICAgICB0b3BMZXZlbFR5cGVzLnRvcE1vdXNlVXAsXG4gICAgICB0b3BMZXZlbFR5cGVzLnRvcFNlbGVjdGlvbkNoYW5nZVxuICAgIF1cbiAgfVxufTtcblxudmFyIGFjdGl2ZUVsZW1lbnQgPSBudWxsO1xudmFyIGFjdGl2ZUVsZW1lbnRJRCA9IG51bGw7XG52YXIgbGFzdFNlbGVjdGlvbiA9IG51bGw7XG52YXIgbW91c2VEb3duID0gZmFsc2U7XG5cbi8qKlxuICogR2V0IGFuIG9iamVjdCB3aGljaCBpcyBhIHVuaXF1ZSByZXByZXNlbnRhdGlvbiBvZiB0aGUgY3VycmVudCBzZWxlY3Rpb24uXG4gKlxuICogVGhlIHJldHVybiB2YWx1ZSB3aWxsIG5vdCBiZSBjb25zaXN0ZW50IGFjcm9zcyBub2RlcyBvciBicm93c2VycywgYnV0XG4gKiB0d28gaWRlbnRpY2FsIHNlbGVjdGlvbnMgb24gdGhlIHNhbWUgbm9kZSB3aWxsIHJldHVybiBpZGVudGljYWwgb2JqZWN0cy5cbiAqXG4gKiBAcGFyYW0ge0RPTUVsZW1lbnR9IG5vZGVcbiAqIEBwYXJhbSB7b2JqZWN0fVxuICovXG5mdW5jdGlvbiBnZXRTZWxlY3Rpb24obm9kZSkge1xuICBpZiAoJ3NlbGVjdGlvblN0YXJ0JyBpbiBub2RlICYmXG4gICAgICBSZWFjdElucHV0U2VsZWN0aW9uLmhhc1NlbGVjdGlvbkNhcGFiaWxpdGllcyhub2RlKSkge1xuICAgIHJldHVybiB7XG4gICAgICBzdGFydDogbm9kZS5zZWxlY3Rpb25TdGFydCxcbiAgICAgIGVuZDogbm9kZS5zZWxlY3Rpb25FbmRcbiAgICB9O1xuICB9IGVsc2UgaWYgKHdpbmRvdy5nZXRTZWxlY3Rpb24pIHtcbiAgICB2YXIgc2VsZWN0aW9uID0gd2luZG93LmdldFNlbGVjdGlvbigpO1xuICAgIHJldHVybiB7XG4gICAgICBhbmNob3JOb2RlOiBzZWxlY3Rpb24uYW5jaG9yTm9kZSxcbiAgICAgIGFuY2hvck9mZnNldDogc2VsZWN0aW9uLmFuY2hvck9mZnNldCxcbiAgICAgIGZvY3VzTm9kZTogc2VsZWN0aW9uLmZvY3VzTm9kZSxcbiAgICAgIGZvY3VzT2Zmc2V0OiBzZWxlY3Rpb24uZm9jdXNPZmZzZXRcbiAgICB9O1xuICB9IGVsc2UgaWYgKGRvY3VtZW50LnNlbGVjdGlvbikge1xuICAgIHZhciByYW5nZSA9IGRvY3VtZW50LnNlbGVjdGlvbi5jcmVhdGVSYW5nZSgpO1xuICAgIHJldHVybiB7XG4gICAgICBwYXJlbnRFbGVtZW50OiByYW5nZS5wYXJlbnRFbGVtZW50KCksXG4gICAgICB0ZXh0OiByYW5nZS50ZXh0LFxuICAgICAgdG9wOiByYW5nZS5ib3VuZGluZ1RvcCxcbiAgICAgIGxlZnQ6IHJhbmdlLmJvdW5kaW5nTGVmdFxuICAgIH07XG4gIH1cbn1cblxuLyoqXG4gKiBQb2xsIHNlbGVjdGlvbiB0byBzZWUgd2hldGhlciBpdCdzIGNoYW5nZWQuXG4gKlxuICogQHBhcmFtIHtvYmplY3R9IG5hdGl2ZUV2ZW50XG4gKiBAcmV0dXJuIHs/U3ludGhldGljRXZlbnR9XG4gKi9cbmZ1bmN0aW9uIGNvbnN0cnVjdFNlbGVjdEV2ZW50KG5hdGl2ZUV2ZW50KSB7XG4gIC8vIEVuc3VyZSB3ZSBoYXZlIHRoZSByaWdodCBlbGVtZW50LCBhbmQgdGhhdCB0aGUgdXNlciBpcyBub3QgZHJhZ2dpbmcgYVxuICAvLyBzZWxlY3Rpb24gKHRoaXMgbWF0Y2hlcyBuYXRpdmUgYHNlbGVjdGAgZXZlbnQgYmVoYXZpb3IpLiBJbiBIVE1MNSwgc2VsZWN0XG4gIC8vIGZpcmVzIG9ubHkgb24gaW5wdXQgYW5kIHRleHRhcmVhIHRodXMgaWYgdGhlcmUncyBubyBmb2N1c2VkIGVsZW1lbnQgd2VcbiAgLy8gd29uJ3QgZGlzcGF0Y2guXG4gIGlmIChtb3VzZURvd24gfHxcbiAgICAgIGFjdGl2ZUVsZW1lbnQgPT0gbnVsbCB8fFxuICAgICAgYWN0aXZlRWxlbWVudCAhPSBnZXRBY3RpdmVFbGVtZW50KCkpIHtcbiAgICByZXR1cm47XG4gIH1cblxuICAvLyBPbmx5IGZpcmUgd2hlbiBzZWxlY3Rpb24gaGFzIGFjdHVhbGx5IGNoYW5nZWQuXG4gIHZhciBjdXJyZW50U2VsZWN0aW9uID0gZ2V0U2VsZWN0aW9uKGFjdGl2ZUVsZW1lbnQpO1xuICBpZiAoIWxhc3RTZWxlY3Rpb24gfHwgIXNoYWxsb3dFcXVhbChsYXN0U2VsZWN0aW9uLCBjdXJyZW50U2VsZWN0aW9uKSkge1xuICAgIGxhc3RTZWxlY3Rpb24gPSBjdXJyZW50U2VsZWN0aW9uO1xuXG4gICAgdmFyIHN5bnRoZXRpY0V2ZW50ID0gU3ludGhldGljRXZlbnQuZ2V0UG9vbGVkKFxuICAgICAgZXZlbnRUeXBlcy5zZWxlY3QsXG4gICAgICBhY3RpdmVFbGVtZW50SUQsXG4gICAgICBuYXRpdmVFdmVudFxuICAgICk7XG5cbiAgICBzeW50aGV0aWNFdmVudC50eXBlID0gJ3NlbGVjdCc7XG4gICAgc3ludGhldGljRXZlbnQudGFyZ2V0ID0gYWN0aXZlRWxlbWVudDtcblxuICAgIEV2ZW50UHJvcGFnYXRvcnMuYWNjdW11bGF0ZVR3b1BoYXNlRGlzcGF0Y2hlcyhzeW50aGV0aWNFdmVudCk7XG5cbiAgICByZXR1cm4gc3ludGhldGljRXZlbnQ7XG4gIH1cbn1cblxuLyoqXG4gKiBUaGlzIHBsdWdpbiBjcmVhdGVzIGFuIGBvblNlbGVjdGAgZXZlbnQgdGhhdCBub3JtYWxpemVzIHNlbGVjdCBldmVudHNcbiAqIGFjcm9zcyBmb3JtIGVsZW1lbnRzLlxuICpcbiAqIFN1cHBvcnRlZCBlbGVtZW50cyBhcmU6XG4gKiAtIGlucHV0IChzZWUgYGlzVGV4dElucHV0RWxlbWVudGApXG4gKiAtIHRleHRhcmVhXG4gKiAtIGNvbnRlbnRFZGl0YWJsZVxuICpcbiAqIFRoaXMgZGlmZmVycyBmcm9tIG5hdGl2ZSBicm93c2VyIGltcGxlbWVudGF0aW9ucyBpbiB0aGUgZm9sbG93aW5nIHdheXM6XG4gKiAtIEZpcmVzIG9uIGNvbnRlbnRFZGl0YWJsZSBmaWVsZHMgYXMgd2VsbCBhcyBpbnB1dHMuXG4gKiAtIEZpcmVzIGZvciBjb2xsYXBzZWQgc2VsZWN0aW9uLlxuICogLSBGaXJlcyBhZnRlciB1c2VyIGlucHV0LlxuICovXG52YXIgU2VsZWN0RXZlbnRQbHVnaW4gPSB7XG5cbiAgZXZlbnRUeXBlczogZXZlbnRUeXBlcyxcblxuICAvKipcbiAgICogQHBhcmFtIHtzdHJpbmd9IHRvcExldmVsVHlwZSBSZWNvcmQgZnJvbSBgRXZlbnRDb25zdGFudHNgLlxuICAgKiBAcGFyYW0ge0RPTUV2ZW50VGFyZ2V0fSB0b3BMZXZlbFRhcmdldCBUaGUgbGlzdGVuaW5nIGNvbXBvbmVudCByb290IG5vZGUuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB0b3BMZXZlbFRhcmdldElEIElEIG9mIGB0b3BMZXZlbFRhcmdldGAuXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBuYXRpdmVFdmVudCBOYXRpdmUgYnJvd3NlciBldmVudC5cbiAgICogQHJldHVybiB7Kn0gQW4gYWNjdW11bGF0aW9uIG9mIHN5bnRoZXRpYyBldmVudHMuXG4gICAqIEBzZWUge0V2ZW50UGx1Z2luSHViLmV4dHJhY3RFdmVudHN9XG4gICAqL1xuICBleHRyYWN0RXZlbnRzOiBmdW5jdGlvbihcbiAgICAgIHRvcExldmVsVHlwZSxcbiAgICAgIHRvcExldmVsVGFyZ2V0LFxuICAgICAgdG9wTGV2ZWxUYXJnZXRJRCxcbiAgICAgIG5hdGl2ZUV2ZW50KSB7XG5cbiAgICBzd2l0Y2ggKHRvcExldmVsVHlwZSkge1xuICAgICAgLy8gVHJhY2sgdGhlIGlucHV0IG5vZGUgdGhhdCBoYXMgZm9jdXMuXG4gICAgICBjYXNlIHRvcExldmVsVHlwZXMudG9wRm9jdXM6XG4gICAgICAgIGlmIChpc1RleHRJbnB1dEVsZW1lbnQodG9wTGV2ZWxUYXJnZXQpIHx8XG4gICAgICAgICAgICB0b3BMZXZlbFRhcmdldC5jb250ZW50RWRpdGFibGUgPT09ICd0cnVlJykge1xuICAgICAgICAgIGFjdGl2ZUVsZW1lbnQgPSB0b3BMZXZlbFRhcmdldDtcbiAgICAgICAgICBhY3RpdmVFbGVtZW50SUQgPSB0b3BMZXZlbFRhcmdldElEO1xuICAgICAgICAgIGxhc3RTZWxlY3Rpb24gPSBudWxsO1xuICAgICAgICB9XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSB0b3BMZXZlbFR5cGVzLnRvcEJsdXI6XG4gICAgICAgIGFjdGl2ZUVsZW1lbnQgPSBudWxsO1xuICAgICAgICBhY3RpdmVFbGVtZW50SUQgPSBudWxsO1xuICAgICAgICBsYXN0U2VsZWN0aW9uID0gbnVsbDtcbiAgICAgICAgYnJlYWs7XG5cbiAgICAgIC8vIERvbid0IGZpcmUgdGhlIGV2ZW50IHdoaWxlIHRoZSB1c2VyIGlzIGRyYWdnaW5nLiBUaGlzIG1hdGNoZXMgdGhlXG4gICAgICAvLyBzZW1hbnRpY3Mgb2YgdGhlIG5hdGl2ZSBzZWxlY3QgZXZlbnQuXG4gICAgICBjYXNlIHRvcExldmVsVHlwZXMudG9wTW91c2VEb3duOlxuICAgICAgICBtb3VzZURvd24gPSB0cnVlO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgdG9wTGV2ZWxUeXBlcy50b3BDb250ZXh0TWVudTpcbiAgICAgIGNhc2UgdG9wTGV2ZWxUeXBlcy50b3BNb3VzZVVwOlxuICAgICAgICBtb3VzZURvd24gPSBmYWxzZTtcbiAgICAgICAgcmV0dXJuIGNvbnN0cnVjdFNlbGVjdEV2ZW50KG5hdGl2ZUV2ZW50KTtcblxuICAgICAgLy8gQ2hyb21lIGFuZCBJRSBmaXJlIG5vbi1zdGFuZGFyZCBldmVudCB3aGVuIHNlbGVjdGlvbiBpcyBjaGFuZ2VkIChhbmRcbiAgICAgIC8vIHNvbWV0aW1lcyB3aGVuIGl0IGhhc24ndCkuXG4gICAgICAvLyBGaXJlZm94IGRvZXNuJ3Qgc3VwcG9ydCBzZWxlY3Rpb25jaGFuZ2UsIHNvIGNoZWNrIHNlbGVjdGlvbiBzdGF0dXNcbiAgICAgIC8vIGFmdGVyIGVhY2gga2V5IGVudHJ5LiBUaGUgc2VsZWN0aW9uIGNoYW5nZXMgYWZ0ZXIga2V5ZG93biBhbmQgYmVmb3JlXG4gICAgICAvLyBrZXl1cCwgYnV0IHdlIGNoZWNrIG9uIGtleWRvd24gYXMgd2VsbCBpbiB0aGUgY2FzZSBvZiBob2xkaW5nIGRvd24gYVxuICAgICAgLy8ga2V5LCB3aGVuIG11bHRpcGxlIGtleWRvd24gZXZlbnRzIGFyZSBmaXJlZCBidXQgb25seSBvbmUga2V5dXAgaXMuXG4gICAgICBjYXNlIHRvcExldmVsVHlwZXMudG9wU2VsZWN0aW9uQ2hhbmdlOlxuICAgICAgY2FzZSB0b3BMZXZlbFR5cGVzLnRvcEtleURvd246XG4gICAgICBjYXNlIHRvcExldmVsVHlwZXMudG9wS2V5VXA6XG4gICAgICAgIHJldHVybiBjb25zdHJ1Y3RTZWxlY3RFdmVudChuYXRpdmVFdmVudCk7XG4gICAgfVxuICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFNlbGVjdEV2ZW50UGx1Z2luO1xuIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIFNlcnZlclJlYWN0Um9vdEluZGV4XG4gKiBAdHlwZWNoZWNrc1xuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG4vKipcbiAqIFNpemUgb2YgdGhlIHJlYWN0Um9vdCBJRCBzcGFjZS4gV2UgZ2VuZXJhdGUgcmFuZG9tIG51bWJlcnMgZm9yIFJlYWN0IHJvb3RcbiAqIElEcyBhbmQgaWYgdGhlcmUncyBhIGNvbGxpc2lvbiB0aGUgZXZlbnRzIGFuZCBET00gdXBkYXRlIHN5c3RlbSB3aWxsXG4gKiBnZXQgY29uZnVzZWQuIEluIHRoZSBmdXR1cmUgd2UgbmVlZCBhIHdheSB0byBnZW5lcmF0ZSBHVUlEcyBidXQgZm9yXG4gKiBub3cgdGhpcyB3aWxsIHdvcmsgb24gYSBzbWFsbGVyIHNjYWxlLlxuICovXG52YXIgR0xPQkFMX01PVU5UX1BPSU5UX01BWCA9IE1hdGgucG93KDIsIDUzKTtcblxudmFyIFNlcnZlclJlYWN0Um9vdEluZGV4ID0ge1xuICBjcmVhdGVSZWFjdFJvb3RJbmRleDogZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIE1hdGguY2VpbChNYXRoLnJhbmRvbSgpICogR0xPQkFMX01PVU5UX1BPSU5UX01BWCk7XG4gIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gU2VydmVyUmVhY3RSb290SW5kZXg7XG4iLCIoZnVuY3Rpb24gKHByb2Nlc3Mpe1xuLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIFNpbXBsZUV2ZW50UGx1Z2luXG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBFdmVudENvbnN0YW50cyA9IHJlcXVpcmUoXCIuL0V2ZW50Q29uc3RhbnRzXCIpO1xudmFyIEV2ZW50UGx1Z2luVXRpbHMgPSByZXF1aXJlKFwiLi9FdmVudFBsdWdpblV0aWxzXCIpO1xudmFyIEV2ZW50UHJvcGFnYXRvcnMgPSByZXF1aXJlKFwiLi9FdmVudFByb3BhZ2F0b3JzXCIpO1xudmFyIFN5bnRoZXRpY0NsaXBib2FyZEV2ZW50ID0gcmVxdWlyZShcIi4vU3ludGhldGljQ2xpcGJvYXJkRXZlbnRcIik7XG52YXIgU3ludGhldGljRXZlbnQgPSByZXF1aXJlKFwiLi9TeW50aGV0aWNFdmVudFwiKTtcbnZhciBTeW50aGV0aWNGb2N1c0V2ZW50ID0gcmVxdWlyZShcIi4vU3ludGhldGljRm9jdXNFdmVudFwiKTtcbnZhciBTeW50aGV0aWNLZXlib2FyZEV2ZW50ID0gcmVxdWlyZShcIi4vU3ludGhldGljS2V5Ym9hcmRFdmVudFwiKTtcbnZhciBTeW50aGV0aWNNb3VzZUV2ZW50ID0gcmVxdWlyZShcIi4vU3ludGhldGljTW91c2VFdmVudFwiKTtcbnZhciBTeW50aGV0aWNEcmFnRXZlbnQgPSByZXF1aXJlKFwiLi9TeW50aGV0aWNEcmFnRXZlbnRcIik7XG52YXIgU3ludGhldGljVG91Y2hFdmVudCA9IHJlcXVpcmUoXCIuL1N5bnRoZXRpY1RvdWNoRXZlbnRcIik7XG52YXIgU3ludGhldGljVUlFdmVudCA9IHJlcXVpcmUoXCIuL1N5bnRoZXRpY1VJRXZlbnRcIik7XG52YXIgU3ludGhldGljV2hlZWxFdmVudCA9IHJlcXVpcmUoXCIuL1N5bnRoZXRpY1doZWVsRXZlbnRcIik7XG5cbnZhciBnZXRFdmVudENoYXJDb2RlID0gcmVxdWlyZShcIi4vZ2V0RXZlbnRDaGFyQ29kZVwiKTtcblxudmFyIGludmFyaWFudCA9IHJlcXVpcmUoXCIuL2ludmFyaWFudFwiKTtcbnZhciBrZXlPZiA9IHJlcXVpcmUoXCIuL2tleU9mXCIpO1xudmFyIHdhcm5pbmcgPSByZXF1aXJlKFwiLi93YXJuaW5nXCIpO1xuXG52YXIgdG9wTGV2ZWxUeXBlcyA9IEV2ZW50Q29uc3RhbnRzLnRvcExldmVsVHlwZXM7XG5cbnZhciBldmVudFR5cGVzID0ge1xuICBibHVyOiB7XG4gICAgcGhhc2VkUmVnaXN0cmF0aW9uTmFtZXM6IHtcbiAgICAgIGJ1YmJsZWQ6IGtleU9mKHtvbkJsdXI6IHRydWV9KSxcbiAgICAgIGNhcHR1cmVkOiBrZXlPZih7b25CbHVyQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBjbGljazoge1xuICAgIHBoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzOiB7XG4gICAgICBidWJibGVkOiBrZXlPZih7b25DbGljazogdHJ1ZX0pLFxuICAgICAgY2FwdHVyZWQ6IGtleU9mKHtvbkNsaWNrQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBjb250ZXh0TWVudToge1xuICAgIHBoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzOiB7XG4gICAgICBidWJibGVkOiBrZXlPZih7b25Db250ZXh0TWVudTogdHJ1ZX0pLFxuICAgICAgY2FwdHVyZWQ6IGtleU9mKHtvbkNvbnRleHRNZW51Q2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBjb3B5OiB7XG4gICAgcGhhc2VkUmVnaXN0cmF0aW9uTmFtZXM6IHtcbiAgICAgIGJ1YmJsZWQ6IGtleU9mKHtvbkNvcHk6IHRydWV9KSxcbiAgICAgIGNhcHR1cmVkOiBrZXlPZih7b25Db3B5Q2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBjdXQ6IHtcbiAgICBwaGFzZWRSZWdpc3RyYXRpb25OYW1lczoge1xuICAgICAgYnViYmxlZDoga2V5T2Yoe29uQ3V0OiB0cnVlfSksXG4gICAgICBjYXB0dXJlZDoga2V5T2Yoe29uQ3V0Q2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBkb3VibGVDbGljazoge1xuICAgIHBoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzOiB7XG4gICAgICBidWJibGVkOiBrZXlPZih7b25Eb3VibGVDbGljazogdHJ1ZX0pLFxuICAgICAgY2FwdHVyZWQ6IGtleU9mKHtvbkRvdWJsZUNsaWNrQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBkcmFnOiB7XG4gICAgcGhhc2VkUmVnaXN0cmF0aW9uTmFtZXM6IHtcbiAgICAgIGJ1YmJsZWQ6IGtleU9mKHtvbkRyYWc6IHRydWV9KSxcbiAgICAgIGNhcHR1cmVkOiBrZXlPZih7b25EcmFnQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBkcmFnRW5kOiB7XG4gICAgcGhhc2VkUmVnaXN0cmF0aW9uTmFtZXM6IHtcbiAgICAgIGJ1YmJsZWQ6IGtleU9mKHtvbkRyYWdFbmQ6IHRydWV9KSxcbiAgICAgIGNhcHR1cmVkOiBrZXlPZih7b25EcmFnRW5kQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBkcmFnRW50ZXI6IHtcbiAgICBwaGFzZWRSZWdpc3RyYXRpb25OYW1lczoge1xuICAgICAgYnViYmxlZDoga2V5T2Yoe29uRHJhZ0VudGVyOiB0cnVlfSksXG4gICAgICBjYXB0dXJlZDoga2V5T2Yoe29uRHJhZ0VudGVyQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBkcmFnRXhpdDoge1xuICAgIHBoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzOiB7XG4gICAgICBidWJibGVkOiBrZXlPZih7b25EcmFnRXhpdDogdHJ1ZX0pLFxuICAgICAgY2FwdHVyZWQ6IGtleU9mKHtvbkRyYWdFeGl0Q2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBkcmFnTGVhdmU6IHtcbiAgICBwaGFzZWRSZWdpc3RyYXRpb25OYW1lczoge1xuICAgICAgYnViYmxlZDoga2V5T2Yoe29uRHJhZ0xlYXZlOiB0cnVlfSksXG4gICAgICBjYXB0dXJlZDoga2V5T2Yoe29uRHJhZ0xlYXZlQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBkcmFnT3Zlcjoge1xuICAgIHBoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzOiB7XG4gICAgICBidWJibGVkOiBrZXlPZih7b25EcmFnT3ZlcjogdHJ1ZX0pLFxuICAgICAgY2FwdHVyZWQ6IGtleU9mKHtvbkRyYWdPdmVyQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBkcmFnU3RhcnQ6IHtcbiAgICBwaGFzZWRSZWdpc3RyYXRpb25OYW1lczoge1xuICAgICAgYnViYmxlZDoga2V5T2Yoe29uRHJhZ1N0YXJ0OiB0cnVlfSksXG4gICAgICBjYXB0dXJlZDoga2V5T2Yoe29uRHJhZ1N0YXJ0Q2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBkcm9wOiB7XG4gICAgcGhhc2VkUmVnaXN0cmF0aW9uTmFtZXM6IHtcbiAgICAgIGJ1YmJsZWQ6IGtleU9mKHtvbkRyb3A6IHRydWV9KSxcbiAgICAgIGNhcHR1cmVkOiBrZXlPZih7b25Ecm9wQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBmb2N1czoge1xuICAgIHBoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzOiB7XG4gICAgICBidWJibGVkOiBrZXlPZih7b25Gb2N1czogdHJ1ZX0pLFxuICAgICAgY2FwdHVyZWQ6IGtleU9mKHtvbkZvY3VzQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBpbnB1dDoge1xuICAgIHBoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzOiB7XG4gICAgICBidWJibGVkOiBrZXlPZih7b25JbnB1dDogdHJ1ZX0pLFxuICAgICAgY2FwdHVyZWQ6IGtleU9mKHtvbklucHV0Q2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBrZXlEb3duOiB7XG4gICAgcGhhc2VkUmVnaXN0cmF0aW9uTmFtZXM6IHtcbiAgICAgIGJ1YmJsZWQ6IGtleU9mKHtvbktleURvd246IHRydWV9KSxcbiAgICAgIGNhcHR1cmVkOiBrZXlPZih7b25LZXlEb3duQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBrZXlQcmVzczoge1xuICAgIHBoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzOiB7XG4gICAgICBidWJibGVkOiBrZXlPZih7b25LZXlQcmVzczogdHJ1ZX0pLFxuICAgICAgY2FwdHVyZWQ6IGtleU9mKHtvbktleVByZXNzQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBrZXlVcDoge1xuICAgIHBoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzOiB7XG4gICAgICBidWJibGVkOiBrZXlPZih7b25LZXlVcDogdHJ1ZX0pLFxuICAgICAgY2FwdHVyZWQ6IGtleU9mKHtvbktleVVwQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBsb2FkOiB7XG4gICAgcGhhc2VkUmVnaXN0cmF0aW9uTmFtZXM6IHtcbiAgICAgIGJ1YmJsZWQ6IGtleU9mKHtvbkxvYWQ6IHRydWV9KSxcbiAgICAgIGNhcHR1cmVkOiBrZXlPZih7b25Mb2FkQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBlcnJvcjoge1xuICAgIHBoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzOiB7XG4gICAgICBidWJibGVkOiBrZXlPZih7b25FcnJvcjogdHJ1ZX0pLFxuICAgICAgY2FwdHVyZWQ6IGtleU9mKHtvbkVycm9yQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICAvLyBOb3RlOiBXZSBkbyBub3QgYWxsb3cgbGlzdGVuaW5nIHRvIG1vdXNlT3ZlciBldmVudHMuIEluc3RlYWQsIHVzZSB0aGVcbiAgLy8gb25Nb3VzZUVudGVyL29uTW91c2VMZWF2ZSBjcmVhdGVkIGJ5IGBFbnRlckxlYXZlRXZlbnRQbHVnaW5gLlxuICBtb3VzZURvd246IHtcbiAgICBwaGFzZWRSZWdpc3RyYXRpb25OYW1lczoge1xuICAgICAgYnViYmxlZDoga2V5T2Yoe29uTW91c2VEb3duOiB0cnVlfSksXG4gICAgICBjYXB0dXJlZDoga2V5T2Yoe29uTW91c2VEb3duQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBtb3VzZU1vdmU6IHtcbiAgICBwaGFzZWRSZWdpc3RyYXRpb25OYW1lczoge1xuICAgICAgYnViYmxlZDoga2V5T2Yoe29uTW91c2VNb3ZlOiB0cnVlfSksXG4gICAgICBjYXB0dXJlZDoga2V5T2Yoe29uTW91c2VNb3ZlQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBtb3VzZU91dDoge1xuICAgIHBoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzOiB7XG4gICAgICBidWJibGVkOiBrZXlPZih7b25Nb3VzZU91dDogdHJ1ZX0pLFxuICAgICAgY2FwdHVyZWQ6IGtleU9mKHtvbk1vdXNlT3V0Q2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBtb3VzZU92ZXI6IHtcbiAgICBwaGFzZWRSZWdpc3RyYXRpb25OYW1lczoge1xuICAgICAgYnViYmxlZDoga2V5T2Yoe29uTW91c2VPdmVyOiB0cnVlfSksXG4gICAgICBjYXB0dXJlZDoga2V5T2Yoe29uTW91c2VPdmVyQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBtb3VzZVVwOiB7XG4gICAgcGhhc2VkUmVnaXN0cmF0aW9uTmFtZXM6IHtcbiAgICAgIGJ1YmJsZWQ6IGtleU9mKHtvbk1vdXNlVXA6IHRydWV9KSxcbiAgICAgIGNhcHR1cmVkOiBrZXlPZih7b25Nb3VzZVVwQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBwYXN0ZToge1xuICAgIHBoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzOiB7XG4gICAgICBidWJibGVkOiBrZXlPZih7b25QYXN0ZTogdHJ1ZX0pLFxuICAgICAgY2FwdHVyZWQ6IGtleU9mKHtvblBhc3RlQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICByZXNldDoge1xuICAgIHBoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzOiB7XG4gICAgICBidWJibGVkOiBrZXlPZih7b25SZXNldDogdHJ1ZX0pLFxuICAgICAgY2FwdHVyZWQ6IGtleU9mKHtvblJlc2V0Q2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBzY3JvbGw6IHtcbiAgICBwaGFzZWRSZWdpc3RyYXRpb25OYW1lczoge1xuICAgICAgYnViYmxlZDoga2V5T2Yoe29uU2Nyb2xsOiB0cnVlfSksXG4gICAgICBjYXB0dXJlZDoga2V5T2Yoe29uU2Nyb2xsQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICBzdWJtaXQ6IHtcbiAgICBwaGFzZWRSZWdpc3RyYXRpb25OYW1lczoge1xuICAgICAgYnViYmxlZDoga2V5T2Yoe29uU3VibWl0OiB0cnVlfSksXG4gICAgICBjYXB0dXJlZDoga2V5T2Yoe29uU3VibWl0Q2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICB0b3VjaENhbmNlbDoge1xuICAgIHBoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzOiB7XG4gICAgICBidWJibGVkOiBrZXlPZih7b25Ub3VjaENhbmNlbDogdHJ1ZX0pLFxuICAgICAgY2FwdHVyZWQ6IGtleU9mKHtvblRvdWNoQ2FuY2VsQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICB0b3VjaEVuZDoge1xuICAgIHBoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzOiB7XG4gICAgICBidWJibGVkOiBrZXlPZih7b25Ub3VjaEVuZDogdHJ1ZX0pLFxuICAgICAgY2FwdHVyZWQ6IGtleU9mKHtvblRvdWNoRW5kQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICB0b3VjaE1vdmU6IHtcbiAgICBwaGFzZWRSZWdpc3RyYXRpb25OYW1lczoge1xuICAgICAgYnViYmxlZDoga2V5T2Yoe29uVG91Y2hNb3ZlOiB0cnVlfSksXG4gICAgICBjYXB0dXJlZDoga2V5T2Yoe29uVG91Y2hNb3ZlQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICB0b3VjaFN0YXJ0OiB7XG4gICAgcGhhc2VkUmVnaXN0cmF0aW9uTmFtZXM6IHtcbiAgICAgIGJ1YmJsZWQ6IGtleU9mKHtvblRvdWNoU3RhcnQ6IHRydWV9KSxcbiAgICAgIGNhcHR1cmVkOiBrZXlPZih7b25Ub3VjaFN0YXJ0Q2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9LFxuICB3aGVlbDoge1xuICAgIHBoYXNlZFJlZ2lzdHJhdGlvbk5hbWVzOiB7XG4gICAgICBidWJibGVkOiBrZXlPZih7b25XaGVlbDogdHJ1ZX0pLFxuICAgICAgY2FwdHVyZWQ6IGtleU9mKHtvbldoZWVsQ2FwdHVyZTogdHJ1ZX0pXG4gICAgfVxuICB9XG59O1xuXG52YXIgdG9wTGV2ZWxFdmVudHNUb0Rpc3BhdGNoQ29uZmlnID0ge1xuICB0b3BCbHVyOiAgICAgICAgZXZlbnRUeXBlcy5ibHVyLFxuICB0b3BDbGljazogICAgICAgZXZlbnRUeXBlcy5jbGljayxcbiAgdG9wQ29udGV4dE1lbnU6IGV2ZW50VHlwZXMuY29udGV4dE1lbnUsXG4gIHRvcENvcHk6ICAgICAgICBldmVudFR5cGVzLmNvcHksXG4gIHRvcEN1dDogICAgICAgICBldmVudFR5cGVzLmN1dCxcbiAgdG9wRG91YmxlQ2xpY2s6IGV2ZW50VHlwZXMuZG91YmxlQ2xpY2ssXG4gIHRvcERyYWc6ICAgICAgICBldmVudFR5cGVzLmRyYWcsXG4gIHRvcERyYWdFbmQ6ICAgICBldmVudFR5cGVzLmRyYWdFbmQsXG4gIHRvcERyYWdFbnRlcjogICBldmVudFR5cGVzLmRyYWdFbnRlcixcbiAgdG9wRHJhZ0V4aXQ6ICAgIGV2ZW50VHlwZXMuZHJhZ0V4aXQsXG4gIHRvcERyYWdMZWF2ZTogICBldmVudFR5cGVzLmRyYWdMZWF2ZSxcbiAgdG9wRHJhZ092ZXI6ICAgIGV2ZW50VHlwZXMuZHJhZ092ZXIsXG4gIHRvcERyYWdTdGFydDogICBldmVudFR5cGVzLmRyYWdTdGFydCxcbiAgdG9wRHJvcDogICAgICAgIGV2ZW50VHlwZXMuZHJvcCxcbiAgdG9wRXJyb3I6ICAgICAgIGV2ZW50VHlwZXMuZXJyb3IsXG4gIHRvcEZvY3VzOiAgICAgICBldmVudFR5cGVzLmZvY3VzLFxuICB0b3BJbnB1dDogICAgICAgZXZlbnRUeXBlcy5pbnB1dCxcbiAgdG9wS2V5RG93bjogICAgIGV2ZW50VHlwZXMua2V5RG93bixcbiAgdG9wS2V5UHJlc3M6ICAgIGV2ZW50VHlwZXMua2V5UHJlc3MsXG4gIHRvcEtleVVwOiAgICAgICBldmVudFR5cGVzLmtleVVwLFxuICB0b3BMb2FkOiAgICAgICAgZXZlbnRUeXBlcy5sb2FkLFxuICB0b3BNb3VzZURvd246ICAgZXZlbnRUeXBlcy5tb3VzZURvd24sXG4gIHRvcE1vdXNlTW92ZTogICBldmVudFR5cGVzLm1vdXNlTW92ZSxcbiAgdG9wTW91c2VPdXQ6ICAgIGV2ZW50VHlwZXMubW91c2VPdXQsXG4gIHRvcE1vdXNlT3ZlcjogICBldmVudFR5cGVzLm1vdXNlT3ZlcixcbiAgdG9wTW91c2VVcDogICAgIGV2ZW50VHlwZXMubW91c2VVcCxcbiAgdG9wUGFzdGU6ICAgICAgIGV2ZW50VHlwZXMucGFzdGUsXG4gIHRvcFJlc2V0OiAgICAgICBldmVudFR5cGVzLnJlc2V0LFxuICB0b3BTY3JvbGw6ICAgICAgZXZlbnRUeXBlcy5zY3JvbGwsXG4gIHRvcFN1Ym1pdDogICAgICBldmVudFR5cGVzLnN1Ym1pdCxcbiAgdG9wVG91Y2hDYW5jZWw6IGV2ZW50VHlwZXMudG91Y2hDYW5jZWwsXG4gIHRvcFRvdWNoRW5kOiAgICBldmVudFR5cGVzLnRvdWNoRW5kLFxuICB0b3BUb3VjaE1vdmU6ICAgZXZlbnRUeXBlcy50b3VjaE1vdmUsXG4gIHRvcFRvdWNoU3RhcnQ6ICBldmVudFR5cGVzLnRvdWNoU3RhcnQsXG4gIHRvcFdoZWVsOiAgICAgICBldmVudFR5cGVzLndoZWVsXG59O1xuXG5mb3IgKHZhciB0b3BMZXZlbFR5cGUgaW4gdG9wTGV2ZWxFdmVudHNUb0Rpc3BhdGNoQ29uZmlnKSB7XG4gIHRvcExldmVsRXZlbnRzVG9EaXNwYXRjaENvbmZpZ1t0b3BMZXZlbFR5cGVdLmRlcGVuZGVuY2llcyA9IFt0b3BMZXZlbFR5cGVdO1xufVxuXG52YXIgU2ltcGxlRXZlbnRQbHVnaW4gPSB7XG5cbiAgZXZlbnRUeXBlczogZXZlbnRUeXBlcyxcblxuICAvKipcbiAgICogU2FtZSBhcyB0aGUgZGVmYXVsdCBpbXBsZW1lbnRhdGlvbiwgZXhjZXB0IGNhbmNlbHMgdGhlIGV2ZW50IHdoZW4gcmV0dXJuXG4gICAqIHZhbHVlIGlzIGZhbHNlLiBUaGlzIGJlaGF2aW9yIHdpbGwgYmUgZGlzYWJsZWQgaW4gYSBmdXR1cmUgcmVsZWFzZS5cbiAgICpcbiAgICogQHBhcmFtIHtvYmplY3R9IEV2ZW50IHRvIGJlIGRpc3BhdGNoZWQuXG4gICAqIEBwYXJhbSB7ZnVuY3Rpb259IEFwcGxpY2F0aW9uLWxldmVsIGNhbGxiYWNrLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gZG9tSUQgRE9NIElEIHRvIHBhc3MgdG8gdGhlIGNhbGxiYWNrLlxuICAgKi9cbiAgZXhlY3V0ZURpc3BhdGNoOiBmdW5jdGlvbihldmVudCwgbGlzdGVuZXIsIGRvbUlEKSB7XG4gICAgdmFyIHJldHVyblZhbHVlID0gRXZlbnRQbHVnaW5VdGlscy5leGVjdXRlRGlzcGF0Y2goZXZlbnQsIGxpc3RlbmVyLCBkb21JRCk7XG5cbiAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gd2FybmluZyhcbiAgICAgIHR5cGVvZiByZXR1cm5WYWx1ZSAhPT0gJ2Jvb2xlYW4nLFxuICAgICAgJ1JldHVybmluZyBgZmFsc2VgIGZyb20gYW4gZXZlbnQgaGFuZGxlciBpcyBkZXByZWNhdGVkIGFuZCB3aWxsIGJlICcgK1xuICAgICAgJ2lnbm9yZWQgaW4gYSBmdXR1cmUgcmVsZWFzZS4gSW5zdGVhZCwgbWFudWFsbHkgY2FsbCAnICtcbiAgICAgICdlLnN0b3BQcm9wYWdhdGlvbigpIG9yIGUucHJldmVudERlZmF1bHQoKSwgYXMgYXBwcm9wcmlhdGUuJ1xuICAgICkgOiBudWxsKTtcblxuICAgIGlmIChyZXR1cm5WYWx1ZSA9PT0gZmFsc2UpIHtcbiAgICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICB9XG4gIH0sXG5cbiAgLyoqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB0b3BMZXZlbFR5cGUgUmVjb3JkIGZyb20gYEV2ZW50Q29uc3RhbnRzYC5cbiAgICogQHBhcmFtIHtET01FdmVudFRhcmdldH0gdG9wTGV2ZWxUYXJnZXQgVGhlIGxpc3RlbmluZyBjb21wb25lbnQgcm9vdCBub2RlLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gdG9wTGV2ZWxUYXJnZXRJRCBJRCBvZiBgdG9wTGV2ZWxUYXJnZXRgLlxuICAgKiBAcGFyYW0ge29iamVjdH0gbmF0aXZlRXZlbnQgTmF0aXZlIGJyb3dzZXIgZXZlbnQuXG4gICAqIEByZXR1cm4geyp9IEFuIGFjY3VtdWxhdGlvbiBvZiBzeW50aGV0aWMgZXZlbnRzLlxuICAgKiBAc2VlIHtFdmVudFBsdWdpbkh1Yi5leHRyYWN0RXZlbnRzfVxuICAgKi9cbiAgZXh0cmFjdEV2ZW50czogZnVuY3Rpb24oXG4gICAgICB0b3BMZXZlbFR5cGUsXG4gICAgICB0b3BMZXZlbFRhcmdldCxcbiAgICAgIHRvcExldmVsVGFyZ2V0SUQsXG4gICAgICBuYXRpdmVFdmVudCkge1xuICAgIHZhciBkaXNwYXRjaENvbmZpZyA9IHRvcExldmVsRXZlbnRzVG9EaXNwYXRjaENvbmZpZ1t0b3BMZXZlbFR5cGVdO1xuICAgIGlmICghZGlzcGF0Y2hDb25maWcpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgICB2YXIgRXZlbnRDb25zdHJ1Y3RvcjtcbiAgICBzd2l0Y2ggKHRvcExldmVsVHlwZSkge1xuICAgICAgY2FzZSB0b3BMZXZlbFR5cGVzLnRvcElucHV0OlxuICAgICAgY2FzZSB0b3BMZXZlbFR5cGVzLnRvcExvYWQ6XG4gICAgICBjYXNlIHRvcExldmVsVHlwZXMudG9wRXJyb3I6XG4gICAgICBjYXNlIHRvcExldmVsVHlwZXMudG9wUmVzZXQ6XG4gICAgICBjYXNlIHRvcExldmVsVHlwZXMudG9wU3VibWl0OlxuICAgICAgICAvLyBIVE1MIEV2ZW50c1xuICAgICAgICAvLyBAc2VlIGh0dHA6Ly93d3cudzMub3JnL1RSL2h0bWw1L2luZGV4Lmh0bWwjZXZlbnRzLTBcbiAgICAgICAgRXZlbnRDb25zdHJ1Y3RvciA9IFN5bnRoZXRpY0V2ZW50O1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgdG9wTGV2ZWxUeXBlcy50b3BLZXlQcmVzczpcbiAgICAgICAgLy8gRmlyZUZveCBjcmVhdGVzIGEga2V5cHJlc3MgZXZlbnQgZm9yIGZ1bmN0aW9uIGtleXMgdG9vLiBUaGlzIHJlbW92ZXNcbiAgICAgICAgLy8gdGhlIHVud2FudGVkIGtleXByZXNzIGV2ZW50cy4gRW50ZXIgaXMgaG93ZXZlciBib3RoIHByaW50YWJsZSBhbmRcbiAgICAgICAgLy8gbm9uLXByaW50YWJsZS4gT25lIHdvdWxkIGV4cGVjdCBUYWIgdG8gYmUgYXMgd2VsbCAoYnV0IGl0IGlzbid0KS5cbiAgICAgICAgaWYgKGdldEV2ZW50Q2hhckNvZGUobmF0aXZlRXZlbnQpID09PSAwKSB7XG4gICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cbiAgICAgICAgLyogZmFsbHMgdGhyb3VnaCAqL1xuICAgICAgY2FzZSB0b3BMZXZlbFR5cGVzLnRvcEtleURvd246XG4gICAgICBjYXNlIHRvcExldmVsVHlwZXMudG9wS2V5VXA6XG4gICAgICAgIEV2ZW50Q29uc3RydWN0b3IgPSBTeW50aGV0aWNLZXlib2FyZEV2ZW50O1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgdG9wTGV2ZWxUeXBlcy50b3BCbHVyOlxuICAgICAgY2FzZSB0b3BMZXZlbFR5cGVzLnRvcEZvY3VzOlxuICAgICAgICBFdmVudENvbnN0cnVjdG9yID0gU3ludGhldGljRm9jdXNFdmVudDtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIHRvcExldmVsVHlwZXMudG9wQ2xpY2s6XG4gICAgICAgIC8vIEZpcmVmb3ggY3JlYXRlcyBhIGNsaWNrIGV2ZW50IG9uIHJpZ2h0IG1vdXNlIGNsaWNrcy4gVGhpcyByZW1vdmVzIHRoZVxuICAgICAgICAvLyB1bndhbnRlZCBjbGljayBldmVudHMuXG4gICAgICAgIGlmIChuYXRpdmVFdmVudC5idXR0b24gPT09IDIpIHtcbiAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfVxuICAgICAgICAvKiBmYWxscyB0aHJvdWdoICovXG4gICAgICBjYXNlIHRvcExldmVsVHlwZXMudG9wQ29udGV4dE1lbnU6XG4gICAgICBjYXNlIHRvcExldmVsVHlwZXMudG9wRG91YmxlQ2xpY2s6XG4gICAgICBjYXNlIHRvcExldmVsVHlwZXMudG9wTW91c2VEb3duOlxuICAgICAgY2FzZSB0b3BMZXZlbFR5cGVzLnRvcE1vdXNlTW92ZTpcbiAgICAgIGNhc2UgdG9wTGV2ZWxUeXBlcy50b3BNb3VzZU91dDpcbiAgICAgIGNhc2UgdG9wTGV2ZWxUeXBlcy50b3BNb3VzZU92ZXI6XG4gICAgICBjYXNlIHRvcExldmVsVHlwZXMudG9wTW91c2VVcDpcbiAgICAgICAgRXZlbnRDb25zdHJ1Y3RvciA9IFN5bnRoZXRpY01vdXNlRXZlbnQ7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSB0b3BMZXZlbFR5cGVzLnRvcERyYWc6XG4gICAgICBjYXNlIHRvcExldmVsVHlwZXMudG9wRHJhZ0VuZDpcbiAgICAgIGNhc2UgdG9wTGV2ZWxUeXBlcy50b3BEcmFnRW50ZXI6XG4gICAgICBjYXNlIHRvcExldmVsVHlwZXMudG9wRHJhZ0V4aXQ6XG4gICAgICBjYXNlIHRvcExldmVsVHlwZXMudG9wRHJhZ0xlYXZlOlxuICAgICAgY2FzZSB0b3BMZXZlbFR5cGVzLnRvcERyYWdPdmVyOlxuICAgICAgY2FzZSB0b3BMZXZlbFR5cGVzLnRvcERyYWdTdGFydDpcbiAgICAgIGNhc2UgdG9wTGV2ZWxUeXBlcy50b3BEcm9wOlxuICAgICAgICBFdmVudENvbnN0cnVjdG9yID0gU3ludGhldGljRHJhZ0V2ZW50O1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgdG9wTGV2ZWxUeXBlcy50b3BUb3VjaENhbmNlbDpcbiAgICAgIGNhc2UgdG9wTGV2ZWxUeXBlcy50b3BUb3VjaEVuZDpcbiAgICAgIGNhc2UgdG9wTGV2ZWxUeXBlcy50b3BUb3VjaE1vdmU6XG4gICAgICBjYXNlIHRvcExldmVsVHlwZXMudG9wVG91Y2hTdGFydDpcbiAgICAgICAgRXZlbnRDb25zdHJ1Y3RvciA9IFN5bnRoZXRpY1RvdWNoRXZlbnQ7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSB0b3BMZXZlbFR5cGVzLnRvcFNjcm9sbDpcbiAgICAgICAgRXZlbnRDb25zdHJ1Y3RvciA9IFN5bnRoZXRpY1VJRXZlbnQ7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSB0b3BMZXZlbFR5cGVzLnRvcFdoZWVsOlxuICAgICAgICBFdmVudENvbnN0cnVjdG9yID0gU3ludGhldGljV2hlZWxFdmVudDtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIHRvcExldmVsVHlwZXMudG9wQ29weTpcbiAgICAgIGNhc2UgdG9wTGV2ZWxUeXBlcy50b3BDdXQ6XG4gICAgICBjYXNlIHRvcExldmVsVHlwZXMudG9wUGFzdGU6XG4gICAgICAgIEV2ZW50Q29uc3RydWN0b3IgPSBTeW50aGV0aWNDbGlwYm9hcmRFdmVudDtcbiAgICAgICAgYnJlYWs7XG4gICAgfVxuICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICBFdmVudENvbnN0cnVjdG9yLFxuICAgICAgJ1NpbXBsZUV2ZW50UGx1Z2luOiBVbmhhbmRsZWQgZXZlbnQgdHlwZSwgYCVzYC4nLFxuICAgICAgdG9wTGV2ZWxUeXBlXG4gICAgKSA6IGludmFyaWFudChFdmVudENvbnN0cnVjdG9yKSk7XG4gICAgdmFyIGV2ZW50ID0gRXZlbnRDb25zdHJ1Y3Rvci5nZXRQb29sZWQoXG4gICAgICBkaXNwYXRjaENvbmZpZyxcbiAgICAgIHRvcExldmVsVGFyZ2V0SUQsXG4gICAgICBuYXRpdmVFdmVudFxuICAgICk7XG4gICAgRXZlbnRQcm9wYWdhdG9ycy5hY2N1bXVsYXRlVHdvUGhhc2VEaXNwYXRjaGVzKGV2ZW50KTtcbiAgICByZXR1cm4gZXZlbnQ7XG4gIH1cblxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBTaW1wbGVFdmVudFBsdWdpbjtcblxufSkuY2FsbCh0aGlzLHJlcXVpcmUoJ19wcm9jZXNzJykpIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIFN5bnRoZXRpY0NsaXBib2FyZEV2ZW50XG4gKiBAdHlwZWNoZWNrcyBzdGF0aWMtb25seVxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgU3ludGhldGljRXZlbnQgPSByZXF1aXJlKFwiLi9TeW50aGV0aWNFdmVudFwiKTtcblxuLyoqXG4gKiBAaW50ZXJmYWNlIEV2ZW50XG4gKiBAc2VlIGh0dHA6Ly93d3cudzMub3JnL1RSL2NsaXBib2FyZC1hcGlzL1xuICovXG52YXIgQ2xpcGJvYXJkRXZlbnRJbnRlcmZhY2UgPSB7XG4gIGNsaXBib2FyZERhdGE6IGZ1bmN0aW9uKGV2ZW50KSB7XG4gICAgcmV0dXJuIChcbiAgICAgICdjbGlwYm9hcmREYXRhJyBpbiBldmVudCA/XG4gICAgICAgIGV2ZW50LmNsaXBib2FyZERhdGEgOlxuICAgICAgICB3aW5kb3cuY2xpcGJvYXJkRGF0YVxuICAgICk7XG4gIH1cbn07XG5cbi8qKlxuICogQHBhcmFtIHtvYmplY3R9IGRpc3BhdGNoQ29uZmlnIENvbmZpZ3VyYXRpb24gdXNlZCB0byBkaXNwYXRjaCB0aGlzIGV2ZW50LlxuICogQHBhcmFtIHtzdHJpbmd9IGRpc3BhdGNoTWFya2VyIE1hcmtlciBpZGVudGlmeWluZyB0aGUgZXZlbnQgdGFyZ2V0LlxuICogQHBhcmFtIHtvYmplY3R9IG5hdGl2ZUV2ZW50IE5hdGl2ZSBicm93c2VyIGV2ZW50LlxuICogQGV4dGVuZHMge1N5bnRoZXRpY1VJRXZlbnR9XG4gKi9cbmZ1bmN0aW9uIFN5bnRoZXRpY0NsaXBib2FyZEV2ZW50KGRpc3BhdGNoQ29uZmlnLCBkaXNwYXRjaE1hcmtlciwgbmF0aXZlRXZlbnQpIHtcbiAgU3ludGhldGljRXZlbnQuY2FsbCh0aGlzLCBkaXNwYXRjaENvbmZpZywgZGlzcGF0Y2hNYXJrZXIsIG5hdGl2ZUV2ZW50KTtcbn1cblxuU3ludGhldGljRXZlbnQuYXVnbWVudENsYXNzKFN5bnRoZXRpY0NsaXBib2FyZEV2ZW50LCBDbGlwYm9hcmRFdmVudEludGVyZmFjZSk7XG5cbm1vZHVsZS5leHBvcnRzID0gU3ludGhldGljQ2xpcGJvYXJkRXZlbnQ7XG5cbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBTeW50aGV0aWNDb21wb3NpdGlvbkV2ZW50XG4gKiBAdHlwZWNoZWNrcyBzdGF0aWMtb25seVxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgU3ludGhldGljRXZlbnQgPSByZXF1aXJlKFwiLi9TeW50aGV0aWNFdmVudFwiKTtcblxuLyoqXG4gKiBAaW50ZXJmYWNlIEV2ZW50XG4gKiBAc2VlIGh0dHA6Ly93d3cudzMub3JnL1RSL0RPTS1MZXZlbC0zLUV2ZW50cy8jZXZlbnRzLWNvbXBvc2l0aW9uZXZlbnRzXG4gKi9cbnZhciBDb21wb3NpdGlvbkV2ZW50SW50ZXJmYWNlID0ge1xuICBkYXRhOiBudWxsXG59O1xuXG4vKipcbiAqIEBwYXJhbSB7b2JqZWN0fSBkaXNwYXRjaENvbmZpZyBDb25maWd1cmF0aW9uIHVzZWQgdG8gZGlzcGF0Y2ggdGhpcyBldmVudC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBkaXNwYXRjaE1hcmtlciBNYXJrZXIgaWRlbnRpZnlpbmcgdGhlIGV2ZW50IHRhcmdldC5cbiAqIEBwYXJhbSB7b2JqZWN0fSBuYXRpdmVFdmVudCBOYXRpdmUgYnJvd3NlciBldmVudC5cbiAqIEBleHRlbmRzIHtTeW50aGV0aWNVSUV2ZW50fVxuICovXG5mdW5jdGlvbiBTeW50aGV0aWNDb21wb3NpdGlvbkV2ZW50KFxuICBkaXNwYXRjaENvbmZpZyxcbiAgZGlzcGF0Y2hNYXJrZXIsXG4gIG5hdGl2ZUV2ZW50KSB7XG4gIFN5bnRoZXRpY0V2ZW50LmNhbGwodGhpcywgZGlzcGF0Y2hDb25maWcsIGRpc3BhdGNoTWFya2VyLCBuYXRpdmVFdmVudCk7XG59XG5cblN5bnRoZXRpY0V2ZW50LmF1Z21lbnRDbGFzcyhcbiAgU3ludGhldGljQ29tcG9zaXRpb25FdmVudCxcbiAgQ29tcG9zaXRpb25FdmVudEludGVyZmFjZVxuKTtcblxubW9kdWxlLmV4cG9ydHMgPSBTeW50aGV0aWNDb21wb3NpdGlvbkV2ZW50O1xuXG4iLCIvKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgU3ludGhldGljRHJhZ0V2ZW50XG4gKiBAdHlwZWNoZWNrcyBzdGF0aWMtb25seVxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgU3ludGhldGljTW91c2VFdmVudCA9IHJlcXVpcmUoXCIuL1N5bnRoZXRpY01vdXNlRXZlbnRcIik7XG5cbi8qKlxuICogQGludGVyZmFjZSBEcmFnRXZlbnRcbiAqIEBzZWUgaHR0cDovL3d3dy53My5vcmcvVFIvRE9NLUxldmVsLTMtRXZlbnRzL1xuICovXG52YXIgRHJhZ0V2ZW50SW50ZXJmYWNlID0ge1xuICBkYXRhVHJhbnNmZXI6IG51bGxcbn07XG5cbi8qKlxuICogQHBhcmFtIHtvYmplY3R9IGRpc3BhdGNoQ29uZmlnIENvbmZpZ3VyYXRpb24gdXNlZCB0byBkaXNwYXRjaCB0aGlzIGV2ZW50LlxuICogQHBhcmFtIHtzdHJpbmd9IGRpc3BhdGNoTWFya2VyIE1hcmtlciBpZGVudGlmeWluZyB0aGUgZXZlbnQgdGFyZ2V0LlxuICogQHBhcmFtIHtvYmplY3R9IG5hdGl2ZUV2ZW50IE5hdGl2ZSBicm93c2VyIGV2ZW50LlxuICogQGV4dGVuZHMge1N5bnRoZXRpY1VJRXZlbnR9XG4gKi9cbmZ1bmN0aW9uIFN5bnRoZXRpY0RyYWdFdmVudChkaXNwYXRjaENvbmZpZywgZGlzcGF0Y2hNYXJrZXIsIG5hdGl2ZUV2ZW50KSB7XG4gIFN5bnRoZXRpY01vdXNlRXZlbnQuY2FsbCh0aGlzLCBkaXNwYXRjaENvbmZpZywgZGlzcGF0Y2hNYXJrZXIsIG5hdGl2ZUV2ZW50KTtcbn1cblxuU3ludGhldGljTW91c2VFdmVudC5hdWdtZW50Q2xhc3MoU3ludGhldGljRHJhZ0V2ZW50LCBEcmFnRXZlbnRJbnRlcmZhY2UpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFN5bnRoZXRpY0RyYWdFdmVudDtcbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBTeW50aGV0aWNFdmVudFxuICogQHR5cGVjaGVja3Mgc3RhdGljLW9ubHlcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIFBvb2xlZENsYXNzID0gcmVxdWlyZShcIi4vUG9vbGVkQ2xhc3NcIik7XG5cbnZhciBhc3NpZ24gPSByZXF1aXJlKFwiLi9PYmplY3QuYXNzaWduXCIpO1xudmFyIGVtcHR5RnVuY3Rpb24gPSByZXF1aXJlKFwiLi9lbXB0eUZ1bmN0aW9uXCIpO1xudmFyIGdldEV2ZW50VGFyZ2V0ID0gcmVxdWlyZShcIi4vZ2V0RXZlbnRUYXJnZXRcIik7XG5cbi8qKlxuICogQGludGVyZmFjZSBFdmVudFxuICogQHNlZSBodHRwOi8vd3d3LnczLm9yZy9UUi9ET00tTGV2ZWwtMy1FdmVudHMvXG4gKi9cbnZhciBFdmVudEludGVyZmFjZSA9IHtcbiAgdHlwZTogbnVsbCxcbiAgdGFyZ2V0OiBnZXRFdmVudFRhcmdldCxcbiAgLy8gY3VycmVudFRhcmdldCBpcyBzZXQgd2hlbiBkaXNwYXRjaGluZzsgbm8gdXNlIGluIGNvcHlpbmcgaXQgaGVyZVxuICBjdXJyZW50VGFyZ2V0OiBlbXB0eUZ1bmN0aW9uLnRoYXRSZXR1cm5zTnVsbCxcbiAgZXZlbnRQaGFzZTogbnVsbCxcbiAgYnViYmxlczogbnVsbCxcbiAgY2FuY2VsYWJsZTogbnVsbCxcbiAgdGltZVN0YW1wOiBmdW5jdGlvbihldmVudCkge1xuICAgIHJldHVybiBldmVudC50aW1lU3RhbXAgfHwgRGF0ZS5ub3coKTtcbiAgfSxcbiAgZGVmYXVsdFByZXZlbnRlZDogbnVsbCxcbiAgaXNUcnVzdGVkOiBudWxsXG59O1xuXG4vKipcbiAqIFN5bnRoZXRpYyBldmVudHMgYXJlIGRpc3BhdGNoZWQgYnkgZXZlbnQgcGx1Z2lucywgdHlwaWNhbGx5IGluIHJlc3BvbnNlIHRvIGFcbiAqIHRvcC1sZXZlbCBldmVudCBkZWxlZ2F0aW9uIGhhbmRsZXIuXG4gKlxuICogVGhlc2Ugc3lzdGVtcyBzaG91bGQgZ2VuZXJhbGx5IHVzZSBwb29saW5nIHRvIHJlZHVjZSB0aGUgZnJlcXVlbmN5IG9mIGdhcmJhZ2VcbiAqIGNvbGxlY3Rpb24uIFRoZSBzeXN0ZW0gc2hvdWxkIGNoZWNrIGBpc1BlcnNpc3RlbnRgIHRvIGRldGVybWluZSB3aGV0aGVyIHRoZVxuICogZXZlbnQgc2hvdWxkIGJlIHJlbGVhc2VkIGludG8gdGhlIHBvb2wgYWZ0ZXIgYmVpbmcgZGlzcGF0Y2hlZC4gVXNlcnMgdGhhdFxuICogbmVlZCBhIHBlcnNpc3RlZCBldmVudCBzaG91bGQgaW52b2tlIGBwZXJzaXN0YC5cbiAqXG4gKiBTeW50aGV0aWMgZXZlbnRzIChhbmQgc3ViY2xhc3NlcykgaW1wbGVtZW50IHRoZSBET00gTGV2ZWwgMyBFdmVudHMgQVBJIGJ5XG4gKiBub3JtYWxpemluZyBicm93c2VyIHF1aXJrcy4gU3ViY2xhc3NlcyBkbyBub3QgbmVjZXNzYXJpbHkgaGF2ZSB0byBpbXBsZW1lbnQgYVxuICogRE9NIGludGVyZmFjZTsgY3VzdG9tIGFwcGxpY2F0aW9uLXNwZWNpZmljIGV2ZW50cyBjYW4gYWxzbyBzdWJjbGFzcyB0aGlzLlxuICpcbiAqIEBwYXJhbSB7b2JqZWN0fSBkaXNwYXRjaENvbmZpZyBDb25maWd1cmF0aW9uIHVzZWQgdG8gZGlzcGF0Y2ggdGhpcyBldmVudC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBkaXNwYXRjaE1hcmtlciBNYXJrZXIgaWRlbnRpZnlpbmcgdGhlIGV2ZW50IHRhcmdldC5cbiAqIEBwYXJhbSB7b2JqZWN0fSBuYXRpdmVFdmVudCBOYXRpdmUgYnJvd3NlciBldmVudC5cbiAqL1xuZnVuY3Rpb24gU3ludGhldGljRXZlbnQoZGlzcGF0Y2hDb25maWcsIGRpc3BhdGNoTWFya2VyLCBuYXRpdmVFdmVudCkge1xuICB0aGlzLmRpc3BhdGNoQ29uZmlnID0gZGlzcGF0Y2hDb25maWc7XG4gIHRoaXMuZGlzcGF0Y2hNYXJrZXIgPSBkaXNwYXRjaE1hcmtlcjtcbiAgdGhpcy5uYXRpdmVFdmVudCA9IG5hdGl2ZUV2ZW50O1xuXG4gIHZhciBJbnRlcmZhY2UgPSB0aGlzLmNvbnN0cnVjdG9yLkludGVyZmFjZTtcbiAgZm9yICh2YXIgcHJvcE5hbWUgaW4gSW50ZXJmYWNlKSB7XG4gICAgaWYgKCFJbnRlcmZhY2UuaGFzT3duUHJvcGVydHkocHJvcE5hbWUpKSB7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG4gICAgdmFyIG5vcm1hbGl6ZSA9IEludGVyZmFjZVtwcm9wTmFtZV07XG4gICAgaWYgKG5vcm1hbGl6ZSkge1xuICAgICAgdGhpc1twcm9wTmFtZV0gPSBub3JtYWxpemUobmF0aXZlRXZlbnQpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzW3Byb3BOYW1lXSA9IG5hdGl2ZUV2ZW50W3Byb3BOYW1lXTtcbiAgICB9XG4gIH1cblxuICB2YXIgZGVmYXVsdFByZXZlbnRlZCA9IG5hdGl2ZUV2ZW50LmRlZmF1bHRQcmV2ZW50ZWQgIT0gbnVsbCA/XG4gICAgbmF0aXZlRXZlbnQuZGVmYXVsdFByZXZlbnRlZCA6XG4gICAgbmF0aXZlRXZlbnQucmV0dXJuVmFsdWUgPT09IGZhbHNlO1xuICBpZiAoZGVmYXVsdFByZXZlbnRlZCkge1xuICAgIHRoaXMuaXNEZWZhdWx0UHJldmVudGVkID0gZW1wdHlGdW5jdGlvbi50aGF0UmV0dXJuc1RydWU7XG4gIH0gZWxzZSB7XG4gICAgdGhpcy5pc0RlZmF1bHRQcmV2ZW50ZWQgPSBlbXB0eUZ1bmN0aW9uLnRoYXRSZXR1cm5zRmFsc2U7XG4gIH1cbiAgdGhpcy5pc1Byb3BhZ2F0aW9uU3RvcHBlZCA9IGVtcHR5RnVuY3Rpb24udGhhdFJldHVybnNGYWxzZTtcbn1cblxuYXNzaWduKFN5bnRoZXRpY0V2ZW50LnByb3RvdHlwZSwge1xuXG4gIHByZXZlbnREZWZhdWx0OiBmdW5jdGlvbigpIHtcbiAgICB0aGlzLmRlZmF1bHRQcmV2ZW50ZWQgPSB0cnVlO1xuICAgIHZhciBldmVudCA9IHRoaXMubmF0aXZlRXZlbnQ7XG4gICAgZXZlbnQucHJldmVudERlZmF1bHQgPyBldmVudC5wcmV2ZW50RGVmYXVsdCgpIDogZXZlbnQucmV0dXJuVmFsdWUgPSBmYWxzZTtcbiAgICB0aGlzLmlzRGVmYXVsdFByZXZlbnRlZCA9IGVtcHR5RnVuY3Rpb24udGhhdFJldHVybnNUcnVlO1xuICB9LFxuXG4gIHN0b3BQcm9wYWdhdGlvbjogZnVuY3Rpb24oKSB7XG4gICAgdmFyIGV2ZW50ID0gdGhpcy5uYXRpdmVFdmVudDtcbiAgICBldmVudC5zdG9wUHJvcGFnYXRpb24gPyBldmVudC5zdG9wUHJvcGFnYXRpb24oKSA6IGV2ZW50LmNhbmNlbEJ1YmJsZSA9IHRydWU7XG4gICAgdGhpcy5pc1Byb3BhZ2F0aW9uU3RvcHBlZCA9IGVtcHR5RnVuY3Rpb24udGhhdFJldHVybnNUcnVlO1xuICB9LFxuXG4gIC8qKlxuICAgKiBXZSByZWxlYXNlIGFsbCBkaXNwYXRjaGVkIGBTeW50aGV0aWNFdmVudGBzIGFmdGVyIGVhY2ggZXZlbnQgbG9vcCwgYWRkaW5nXG4gICAqIHRoZW0gYmFjayBpbnRvIHRoZSBwb29sLiBUaGlzIGFsbG93cyBhIHdheSB0byBob2xkIG9udG8gYSByZWZlcmVuY2UgdGhhdFxuICAgKiB3b24ndCBiZSBhZGRlZCBiYWNrIGludG8gdGhlIHBvb2wuXG4gICAqL1xuICBwZXJzaXN0OiBmdW5jdGlvbigpIHtcbiAgICB0aGlzLmlzUGVyc2lzdGVudCA9IGVtcHR5RnVuY3Rpb24udGhhdFJldHVybnNUcnVlO1xuICB9LFxuXG4gIC8qKlxuICAgKiBDaGVja3MgaWYgdGhpcyBldmVudCBzaG91bGQgYmUgcmVsZWFzZWQgYmFjayBpbnRvIHRoZSBwb29sLlxuICAgKlxuICAgKiBAcmV0dXJuIHtib29sZWFufSBUcnVlIGlmIHRoaXMgc2hvdWxkIG5vdCBiZSByZWxlYXNlZCwgZmFsc2Ugb3RoZXJ3aXNlLlxuICAgKi9cbiAgaXNQZXJzaXN0ZW50OiBlbXB0eUZ1bmN0aW9uLnRoYXRSZXR1cm5zRmFsc2UsXG5cbiAgLyoqXG4gICAqIGBQb29sZWRDbGFzc2AgbG9va3MgZm9yIGBkZXN0cnVjdG9yYCBvbiBlYWNoIGluc3RhbmNlIGl0IHJlbGVhc2VzLlxuICAgKi9cbiAgZGVzdHJ1Y3RvcjogZnVuY3Rpb24oKSB7XG4gICAgdmFyIEludGVyZmFjZSA9IHRoaXMuY29uc3RydWN0b3IuSW50ZXJmYWNlO1xuICAgIGZvciAodmFyIHByb3BOYW1lIGluIEludGVyZmFjZSkge1xuICAgICAgdGhpc1twcm9wTmFtZV0gPSBudWxsO1xuICAgIH1cbiAgICB0aGlzLmRpc3BhdGNoQ29uZmlnID0gbnVsbDtcbiAgICB0aGlzLmRpc3BhdGNoTWFya2VyID0gbnVsbDtcbiAgICB0aGlzLm5hdGl2ZUV2ZW50ID0gbnVsbDtcbiAgfVxuXG59KTtcblxuU3ludGhldGljRXZlbnQuSW50ZXJmYWNlID0gRXZlbnRJbnRlcmZhY2U7XG5cbi8qKlxuICogSGVscGVyIHRvIHJlZHVjZSBib2lsZXJwbGF0ZSB3aGVuIGNyZWF0aW5nIHN1YmNsYXNzZXMuXG4gKlxuICogQHBhcmFtIHtmdW5jdGlvbn0gQ2xhc3NcbiAqIEBwYXJhbSB7P29iamVjdH0gSW50ZXJmYWNlXG4gKi9cblN5bnRoZXRpY0V2ZW50LmF1Z21lbnRDbGFzcyA9IGZ1bmN0aW9uKENsYXNzLCBJbnRlcmZhY2UpIHtcbiAgdmFyIFN1cGVyID0gdGhpcztcblxuICB2YXIgcHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShTdXBlci5wcm90b3R5cGUpO1xuICBhc3NpZ24ocHJvdG90eXBlLCBDbGFzcy5wcm90b3R5cGUpO1xuICBDbGFzcy5wcm90b3R5cGUgPSBwcm90b3R5cGU7XG4gIENsYXNzLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IENsYXNzO1xuXG4gIENsYXNzLkludGVyZmFjZSA9IGFzc2lnbih7fSwgU3VwZXIuSW50ZXJmYWNlLCBJbnRlcmZhY2UpO1xuICBDbGFzcy5hdWdtZW50Q2xhc3MgPSBTdXBlci5hdWdtZW50Q2xhc3M7XG5cbiAgUG9vbGVkQ2xhc3MuYWRkUG9vbGluZ1RvKENsYXNzLCBQb29sZWRDbGFzcy50aHJlZUFyZ3VtZW50UG9vbGVyKTtcbn07XG5cblBvb2xlZENsYXNzLmFkZFBvb2xpbmdUbyhTeW50aGV0aWNFdmVudCwgUG9vbGVkQ2xhc3MudGhyZWVBcmd1bWVudFBvb2xlcik7XG5cbm1vZHVsZS5leHBvcnRzID0gU3ludGhldGljRXZlbnQ7XG4iLCIvKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgU3ludGhldGljRm9jdXNFdmVudFxuICogQHR5cGVjaGVja3Mgc3RhdGljLW9ubHlcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIFN5bnRoZXRpY1VJRXZlbnQgPSByZXF1aXJlKFwiLi9TeW50aGV0aWNVSUV2ZW50XCIpO1xuXG4vKipcbiAqIEBpbnRlcmZhY2UgRm9jdXNFdmVudFxuICogQHNlZSBodHRwOi8vd3d3LnczLm9yZy9UUi9ET00tTGV2ZWwtMy1FdmVudHMvXG4gKi9cbnZhciBGb2N1c0V2ZW50SW50ZXJmYWNlID0ge1xuICByZWxhdGVkVGFyZ2V0OiBudWxsXG59O1xuXG4vKipcbiAqIEBwYXJhbSB7b2JqZWN0fSBkaXNwYXRjaENvbmZpZyBDb25maWd1cmF0aW9uIHVzZWQgdG8gZGlzcGF0Y2ggdGhpcyBldmVudC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBkaXNwYXRjaE1hcmtlciBNYXJrZXIgaWRlbnRpZnlpbmcgdGhlIGV2ZW50IHRhcmdldC5cbiAqIEBwYXJhbSB7b2JqZWN0fSBuYXRpdmVFdmVudCBOYXRpdmUgYnJvd3NlciBldmVudC5cbiAqIEBleHRlbmRzIHtTeW50aGV0aWNVSUV2ZW50fVxuICovXG5mdW5jdGlvbiBTeW50aGV0aWNGb2N1c0V2ZW50KGRpc3BhdGNoQ29uZmlnLCBkaXNwYXRjaE1hcmtlciwgbmF0aXZlRXZlbnQpIHtcbiAgU3ludGhldGljVUlFdmVudC5jYWxsKHRoaXMsIGRpc3BhdGNoQ29uZmlnLCBkaXNwYXRjaE1hcmtlciwgbmF0aXZlRXZlbnQpO1xufVxuXG5TeW50aGV0aWNVSUV2ZW50LmF1Z21lbnRDbGFzcyhTeW50aGV0aWNGb2N1c0V2ZW50LCBGb2N1c0V2ZW50SW50ZXJmYWNlKTtcblxubW9kdWxlLmV4cG9ydHMgPSBTeW50aGV0aWNGb2N1c0V2ZW50O1xuIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMyBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIFN5bnRoZXRpY0lucHV0RXZlbnRcbiAqIEB0eXBlY2hlY2tzIHN0YXRpYy1vbmx5XG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBTeW50aGV0aWNFdmVudCA9IHJlcXVpcmUoXCIuL1N5bnRoZXRpY0V2ZW50XCIpO1xuXG4vKipcbiAqIEBpbnRlcmZhY2UgRXZlbnRcbiAqIEBzZWUgaHR0cDovL3d3dy53My5vcmcvVFIvMjAxMy9XRC1ET00tTGV2ZWwtMy1FdmVudHMtMjAxMzExMDVcbiAqICAgICAgLyNldmVudHMtaW5wdXRldmVudHNcbiAqL1xudmFyIElucHV0RXZlbnRJbnRlcmZhY2UgPSB7XG4gIGRhdGE6IG51bGxcbn07XG5cbi8qKlxuICogQHBhcmFtIHtvYmplY3R9IGRpc3BhdGNoQ29uZmlnIENvbmZpZ3VyYXRpb24gdXNlZCB0byBkaXNwYXRjaCB0aGlzIGV2ZW50LlxuICogQHBhcmFtIHtzdHJpbmd9IGRpc3BhdGNoTWFya2VyIE1hcmtlciBpZGVudGlmeWluZyB0aGUgZXZlbnQgdGFyZ2V0LlxuICogQHBhcmFtIHtvYmplY3R9IG5hdGl2ZUV2ZW50IE5hdGl2ZSBicm93c2VyIGV2ZW50LlxuICogQGV4dGVuZHMge1N5bnRoZXRpY1VJRXZlbnR9XG4gKi9cbmZ1bmN0aW9uIFN5bnRoZXRpY0lucHV0RXZlbnQoXG4gIGRpc3BhdGNoQ29uZmlnLFxuICBkaXNwYXRjaE1hcmtlcixcbiAgbmF0aXZlRXZlbnQpIHtcbiAgU3ludGhldGljRXZlbnQuY2FsbCh0aGlzLCBkaXNwYXRjaENvbmZpZywgZGlzcGF0Y2hNYXJrZXIsIG5hdGl2ZUV2ZW50KTtcbn1cblxuU3ludGhldGljRXZlbnQuYXVnbWVudENsYXNzKFxuICBTeW50aGV0aWNJbnB1dEV2ZW50LFxuICBJbnB1dEV2ZW50SW50ZXJmYWNlXG4pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFN5bnRoZXRpY0lucHV0RXZlbnQ7XG5cbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBTeW50aGV0aWNLZXlib2FyZEV2ZW50XG4gKiBAdHlwZWNoZWNrcyBzdGF0aWMtb25seVxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgU3ludGhldGljVUlFdmVudCA9IHJlcXVpcmUoXCIuL1N5bnRoZXRpY1VJRXZlbnRcIik7XG5cbnZhciBnZXRFdmVudENoYXJDb2RlID0gcmVxdWlyZShcIi4vZ2V0RXZlbnRDaGFyQ29kZVwiKTtcbnZhciBnZXRFdmVudEtleSA9IHJlcXVpcmUoXCIuL2dldEV2ZW50S2V5XCIpO1xudmFyIGdldEV2ZW50TW9kaWZpZXJTdGF0ZSA9IHJlcXVpcmUoXCIuL2dldEV2ZW50TW9kaWZpZXJTdGF0ZVwiKTtcblxuLyoqXG4gKiBAaW50ZXJmYWNlIEtleWJvYXJkRXZlbnRcbiAqIEBzZWUgaHR0cDovL3d3dy53My5vcmcvVFIvRE9NLUxldmVsLTMtRXZlbnRzL1xuICovXG52YXIgS2V5Ym9hcmRFdmVudEludGVyZmFjZSA9IHtcbiAga2V5OiBnZXRFdmVudEtleSxcbiAgbG9jYXRpb246IG51bGwsXG4gIGN0cmxLZXk6IG51bGwsXG4gIHNoaWZ0S2V5OiBudWxsLFxuICBhbHRLZXk6IG51bGwsXG4gIG1ldGFLZXk6IG51bGwsXG4gIHJlcGVhdDogbnVsbCxcbiAgbG9jYWxlOiBudWxsLFxuICBnZXRNb2RpZmllclN0YXRlOiBnZXRFdmVudE1vZGlmaWVyU3RhdGUsXG4gIC8vIExlZ2FjeSBJbnRlcmZhY2VcbiAgY2hhckNvZGU6IGZ1bmN0aW9uKGV2ZW50KSB7XG4gICAgLy8gYGNoYXJDb2RlYCBpcyB0aGUgcmVzdWx0IG9mIGEgS2V5UHJlc3MgZXZlbnQgYW5kIHJlcHJlc2VudHMgdGhlIHZhbHVlIG9mXG4gICAgLy8gdGhlIGFjdHVhbCBwcmludGFibGUgY2hhcmFjdGVyLlxuXG4gICAgLy8gS2V5UHJlc3MgaXMgZGVwcmVjYXRlZCwgYnV0IGl0cyByZXBsYWNlbWVudCBpcyBub3QgeWV0IGZpbmFsIGFuZCBub3RcbiAgICAvLyBpbXBsZW1lbnRlZCBpbiBhbnkgbWFqb3IgYnJvd3Nlci4gT25seSBLZXlQcmVzcyBoYXMgY2hhckNvZGUuXG4gICAgaWYgKGV2ZW50LnR5cGUgPT09ICdrZXlwcmVzcycpIHtcbiAgICAgIHJldHVybiBnZXRFdmVudENoYXJDb2RlKGV2ZW50KTtcbiAgICB9XG4gICAgcmV0dXJuIDA7XG4gIH0sXG4gIGtleUNvZGU6IGZ1bmN0aW9uKGV2ZW50KSB7XG4gICAgLy8gYGtleUNvZGVgIGlzIHRoZSByZXN1bHQgb2YgYSBLZXlEb3duL1VwIGV2ZW50IGFuZCByZXByZXNlbnRzIHRoZSB2YWx1ZSBvZlxuICAgIC8vIHBoeXNpY2FsIGtleWJvYXJkIGtleS5cblxuICAgIC8vIFRoZSBhY3R1YWwgbWVhbmluZyBvZiB0aGUgdmFsdWUgZGVwZW5kcyBvbiB0aGUgdXNlcnMnIGtleWJvYXJkIGxheW91dFxuICAgIC8vIHdoaWNoIGNhbm5vdCBiZSBkZXRlY3RlZC4gQXNzdW1pbmcgdGhhdCBpdCBpcyBhIFVTIGtleWJvYXJkIGxheW91dFxuICAgIC8vIHByb3ZpZGVzIGEgc3VycHJpc2luZ2x5IGFjY3VyYXRlIG1hcHBpbmcgZm9yIFVTIGFuZCBFdXJvcGVhbiB1c2Vycy5cbiAgICAvLyBEdWUgdG8gdGhpcywgaXQgaXMgbGVmdCB0byB0aGUgdXNlciB0byBpbXBsZW1lbnQgYXQgdGhpcyB0aW1lLlxuICAgIGlmIChldmVudC50eXBlID09PSAna2V5ZG93bicgfHwgZXZlbnQudHlwZSA9PT0gJ2tleXVwJykge1xuICAgICAgcmV0dXJuIGV2ZW50LmtleUNvZGU7XG4gICAgfVxuICAgIHJldHVybiAwO1xuICB9LFxuICB3aGljaDogZnVuY3Rpb24oZXZlbnQpIHtcbiAgICAvLyBgd2hpY2hgIGlzIGFuIGFsaWFzIGZvciBlaXRoZXIgYGtleUNvZGVgIG9yIGBjaGFyQ29kZWAgZGVwZW5kaW5nIG9uIHRoZVxuICAgIC8vIHR5cGUgb2YgdGhlIGV2ZW50LlxuICAgIGlmIChldmVudC50eXBlID09PSAna2V5cHJlc3MnKSB7XG4gICAgICByZXR1cm4gZ2V0RXZlbnRDaGFyQ29kZShldmVudCk7XG4gICAgfVxuICAgIGlmIChldmVudC50eXBlID09PSAna2V5ZG93bicgfHwgZXZlbnQudHlwZSA9PT0gJ2tleXVwJykge1xuICAgICAgcmV0dXJuIGV2ZW50LmtleUNvZGU7XG4gICAgfVxuICAgIHJldHVybiAwO1xuICB9XG59O1xuXG4vKipcbiAqIEBwYXJhbSB7b2JqZWN0fSBkaXNwYXRjaENvbmZpZyBDb25maWd1cmF0aW9uIHVzZWQgdG8gZGlzcGF0Y2ggdGhpcyBldmVudC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBkaXNwYXRjaE1hcmtlciBNYXJrZXIgaWRlbnRpZnlpbmcgdGhlIGV2ZW50IHRhcmdldC5cbiAqIEBwYXJhbSB7b2JqZWN0fSBuYXRpdmVFdmVudCBOYXRpdmUgYnJvd3NlciBldmVudC5cbiAqIEBleHRlbmRzIHtTeW50aGV0aWNVSUV2ZW50fVxuICovXG5mdW5jdGlvbiBTeW50aGV0aWNLZXlib2FyZEV2ZW50KGRpc3BhdGNoQ29uZmlnLCBkaXNwYXRjaE1hcmtlciwgbmF0aXZlRXZlbnQpIHtcbiAgU3ludGhldGljVUlFdmVudC5jYWxsKHRoaXMsIGRpc3BhdGNoQ29uZmlnLCBkaXNwYXRjaE1hcmtlciwgbmF0aXZlRXZlbnQpO1xufVxuXG5TeW50aGV0aWNVSUV2ZW50LmF1Z21lbnRDbGFzcyhTeW50aGV0aWNLZXlib2FyZEV2ZW50LCBLZXlib2FyZEV2ZW50SW50ZXJmYWNlKTtcblxubW9kdWxlLmV4cG9ydHMgPSBTeW50aGV0aWNLZXlib2FyZEV2ZW50O1xuIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIFN5bnRoZXRpY01vdXNlRXZlbnRcbiAqIEB0eXBlY2hlY2tzIHN0YXRpYy1vbmx5XG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBTeW50aGV0aWNVSUV2ZW50ID0gcmVxdWlyZShcIi4vU3ludGhldGljVUlFdmVudFwiKTtcbnZhciBWaWV3cG9ydE1ldHJpY3MgPSByZXF1aXJlKFwiLi9WaWV3cG9ydE1ldHJpY3NcIik7XG5cbnZhciBnZXRFdmVudE1vZGlmaWVyU3RhdGUgPSByZXF1aXJlKFwiLi9nZXRFdmVudE1vZGlmaWVyU3RhdGVcIik7XG5cbi8qKlxuICogQGludGVyZmFjZSBNb3VzZUV2ZW50XG4gKiBAc2VlIGh0dHA6Ly93d3cudzMub3JnL1RSL0RPTS1MZXZlbC0zLUV2ZW50cy9cbiAqL1xudmFyIE1vdXNlRXZlbnRJbnRlcmZhY2UgPSB7XG4gIHNjcmVlblg6IG51bGwsXG4gIHNjcmVlblk6IG51bGwsXG4gIGNsaWVudFg6IG51bGwsXG4gIGNsaWVudFk6IG51bGwsXG4gIGN0cmxLZXk6IG51bGwsXG4gIHNoaWZ0S2V5OiBudWxsLFxuICBhbHRLZXk6IG51bGwsXG4gIG1ldGFLZXk6IG51bGwsXG4gIGdldE1vZGlmaWVyU3RhdGU6IGdldEV2ZW50TW9kaWZpZXJTdGF0ZSxcbiAgYnV0dG9uOiBmdW5jdGlvbihldmVudCkge1xuICAgIC8vIFdlYmtpdCwgRmlyZWZveCwgSUU5K1xuICAgIC8vIHdoaWNoOiAgMSAyIDNcbiAgICAvLyBidXR0b246IDAgMSAyIChzdGFuZGFyZClcbiAgICB2YXIgYnV0dG9uID0gZXZlbnQuYnV0dG9uO1xuICAgIGlmICgnd2hpY2gnIGluIGV2ZW50KSB7XG4gICAgICByZXR1cm4gYnV0dG9uO1xuICAgIH1cbiAgICAvLyBJRTw5XG4gICAgLy8gd2hpY2g6ICB1bmRlZmluZWRcbiAgICAvLyBidXR0b246IDAgMCAwXG4gICAgLy8gYnV0dG9uOiAxIDQgMiAob25tb3VzZXVwKVxuICAgIHJldHVybiBidXR0b24gPT09IDIgPyAyIDogYnV0dG9uID09PSA0ID8gMSA6IDA7XG4gIH0sXG4gIGJ1dHRvbnM6IG51bGwsXG4gIHJlbGF0ZWRUYXJnZXQ6IGZ1bmN0aW9uKGV2ZW50KSB7XG4gICAgcmV0dXJuIGV2ZW50LnJlbGF0ZWRUYXJnZXQgfHwgKFxuICAgICAgZXZlbnQuZnJvbUVsZW1lbnQgPT09IGV2ZW50LnNyY0VsZW1lbnQgP1xuICAgICAgICBldmVudC50b0VsZW1lbnQgOlxuICAgICAgICBldmVudC5mcm9tRWxlbWVudFxuICAgICk7XG4gIH0sXG4gIC8vIFwiUHJvcHJpZXRhcnlcIiBJbnRlcmZhY2UuXG4gIHBhZ2VYOiBmdW5jdGlvbihldmVudCkge1xuICAgIHJldHVybiAncGFnZVgnIGluIGV2ZW50ID9cbiAgICAgIGV2ZW50LnBhZ2VYIDpcbiAgICAgIGV2ZW50LmNsaWVudFggKyBWaWV3cG9ydE1ldHJpY3MuY3VycmVudFNjcm9sbExlZnQ7XG4gIH0sXG4gIHBhZ2VZOiBmdW5jdGlvbihldmVudCkge1xuICAgIHJldHVybiAncGFnZVknIGluIGV2ZW50ID9cbiAgICAgIGV2ZW50LnBhZ2VZIDpcbiAgICAgIGV2ZW50LmNsaWVudFkgKyBWaWV3cG9ydE1ldHJpY3MuY3VycmVudFNjcm9sbFRvcDtcbiAgfVxufTtcblxuLyoqXG4gKiBAcGFyYW0ge29iamVjdH0gZGlzcGF0Y2hDb25maWcgQ29uZmlndXJhdGlvbiB1c2VkIHRvIGRpc3BhdGNoIHRoaXMgZXZlbnQuXG4gKiBAcGFyYW0ge3N0cmluZ30gZGlzcGF0Y2hNYXJrZXIgTWFya2VyIGlkZW50aWZ5aW5nIHRoZSBldmVudCB0YXJnZXQuXG4gKiBAcGFyYW0ge29iamVjdH0gbmF0aXZlRXZlbnQgTmF0aXZlIGJyb3dzZXIgZXZlbnQuXG4gKiBAZXh0ZW5kcyB7U3ludGhldGljVUlFdmVudH1cbiAqL1xuZnVuY3Rpb24gU3ludGhldGljTW91c2VFdmVudChkaXNwYXRjaENvbmZpZywgZGlzcGF0Y2hNYXJrZXIsIG5hdGl2ZUV2ZW50KSB7XG4gIFN5bnRoZXRpY1VJRXZlbnQuY2FsbCh0aGlzLCBkaXNwYXRjaENvbmZpZywgZGlzcGF0Y2hNYXJrZXIsIG5hdGl2ZUV2ZW50KTtcbn1cblxuU3ludGhldGljVUlFdmVudC5hdWdtZW50Q2xhc3MoU3ludGhldGljTW91c2VFdmVudCwgTW91c2VFdmVudEludGVyZmFjZSk7XG5cbm1vZHVsZS5leHBvcnRzID0gU3ludGhldGljTW91c2VFdmVudDtcbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBTeW50aGV0aWNUb3VjaEV2ZW50XG4gKiBAdHlwZWNoZWNrcyBzdGF0aWMtb25seVxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgU3ludGhldGljVUlFdmVudCA9IHJlcXVpcmUoXCIuL1N5bnRoZXRpY1VJRXZlbnRcIik7XG5cbnZhciBnZXRFdmVudE1vZGlmaWVyU3RhdGUgPSByZXF1aXJlKFwiLi9nZXRFdmVudE1vZGlmaWVyU3RhdGVcIik7XG5cbi8qKlxuICogQGludGVyZmFjZSBUb3VjaEV2ZW50XG4gKiBAc2VlIGh0dHA6Ly93d3cudzMub3JnL1RSL3RvdWNoLWV2ZW50cy9cbiAqL1xudmFyIFRvdWNoRXZlbnRJbnRlcmZhY2UgPSB7XG4gIHRvdWNoZXM6IG51bGwsXG4gIHRhcmdldFRvdWNoZXM6IG51bGwsXG4gIGNoYW5nZWRUb3VjaGVzOiBudWxsLFxuICBhbHRLZXk6IG51bGwsXG4gIG1ldGFLZXk6IG51bGwsXG4gIGN0cmxLZXk6IG51bGwsXG4gIHNoaWZ0S2V5OiBudWxsLFxuICBnZXRNb2RpZmllclN0YXRlOiBnZXRFdmVudE1vZGlmaWVyU3RhdGVcbn07XG5cbi8qKlxuICogQHBhcmFtIHtvYmplY3R9IGRpc3BhdGNoQ29uZmlnIENvbmZpZ3VyYXRpb24gdXNlZCB0byBkaXNwYXRjaCB0aGlzIGV2ZW50LlxuICogQHBhcmFtIHtzdHJpbmd9IGRpc3BhdGNoTWFya2VyIE1hcmtlciBpZGVudGlmeWluZyB0aGUgZXZlbnQgdGFyZ2V0LlxuICogQHBhcmFtIHtvYmplY3R9IG5hdGl2ZUV2ZW50IE5hdGl2ZSBicm93c2VyIGV2ZW50LlxuICogQGV4dGVuZHMge1N5bnRoZXRpY1VJRXZlbnR9XG4gKi9cbmZ1bmN0aW9uIFN5bnRoZXRpY1RvdWNoRXZlbnQoZGlzcGF0Y2hDb25maWcsIGRpc3BhdGNoTWFya2VyLCBuYXRpdmVFdmVudCkge1xuICBTeW50aGV0aWNVSUV2ZW50LmNhbGwodGhpcywgZGlzcGF0Y2hDb25maWcsIGRpc3BhdGNoTWFya2VyLCBuYXRpdmVFdmVudCk7XG59XG5cblN5bnRoZXRpY1VJRXZlbnQuYXVnbWVudENsYXNzKFN5bnRoZXRpY1RvdWNoRXZlbnQsIFRvdWNoRXZlbnRJbnRlcmZhY2UpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFN5bnRoZXRpY1RvdWNoRXZlbnQ7XG4iLCIvKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgU3ludGhldGljVUlFdmVudFxuICogQHR5cGVjaGVja3Mgc3RhdGljLW9ubHlcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIFN5bnRoZXRpY0V2ZW50ID0gcmVxdWlyZShcIi4vU3ludGhldGljRXZlbnRcIik7XG5cbnZhciBnZXRFdmVudFRhcmdldCA9IHJlcXVpcmUoXCIuL2dldEV2ZW50VGFyZ2V0XCIpO1xuXG4vKipcbiAqIEBpbnRlcmZhY2UgVUlFdmVudFxuICogQHNlZSBodHRwOi8vd3d3LnczLm9yZy9UUi9ET00tTGV2ZWwtMy1FdmVudHMvXG4gKi9cbnZhciBVSUV2ZW50SW50ZXJmYWNlID0ge1xuICB2aWV3OiBmdW5jdGlvbihldmVudCkge1xuICAgIGlmIChldmVudC52aWV3KSB7XG4gICAgICByZXR1cm4gZXZlbnQudmlldztcbiAgICB9XG5cbiAgICB2YXIgdGFyZ2V0ID0gZ2V0RXZlbnRUYXJnZXQoZXZlbnQpO1xuICAgIGlmICh0YXJnZXQgIT0gbnVsbCAmJiB0YXJnZXQud2luZG93ID09PSB0YXJnZXQpIHtcbiAgICAgIC8vIHRhcmdldCBpcyBhIHdpbmRvdyBvYmplY3RcbiAgICAgIHJldHVybiB0YXJnZXQ7XG4gICAgfVxuXG4gICAgdmFyIGRvYyA9IHRhcmdldC5vd25lckRvY3VtZW50O1xuICAgIC8vIFRPRE86IEZpZ3VyZSBvdXQgd2h5IGBvd25lckRvY3VtZW50YCBpcyBzb21ldGltZXMgdW5kZWZpbmVkIGluIElFOC5cbiAgICBpZiAoZG9jKSB7XG4gICAgICByZXR1cm4gZG9jLmRlZmF1bHRWaWV3IHx8IGRvYy5wYXJlbnRXaW5kb3c7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiB3aW5kb3c7XG4gICAgfVxuICB9LFxuICBkZXRhaWw6IGZ1bmN0aW9uKGV2ZW50KSB7XG4gICAgcmV0dXJuIGV2ZW50LmRldGFpbCB8fCAwO1xuICB9XG59O1xuXG4vKipcbiAqIEBwYXJhbSB7b2JqZWN0fSBkaXNwYXRjaENvbmZpZyBDb25maWd1cmF0aW9uIHVzZWQgdG8gZGlzcGF0Y2ggdGhpcyBldmVudC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBkaXNwYXRjaE1hcmtlciBNYXJrZXIgaWRlbnRpZnlpbmcgdGhlIGV2ZW50IHRhcmdldC5cbiAqIEBwYXJhbSB7b2JqZWN0fSBuYXRpdmVFdmVudCBOYXRpdmUgYnJvd3NlciBldmVudC5cbiAqIEBleHRlbmRzIHtTeW50aGV0aWNFdmVudH1cbiAqL1xuZnVuY3Rpb24gU3ludGhldGljVUlFdmVudChkaXNwYXRjaENvbmZpZywgZGlzcGF0Y2hNYXJrZXIsIG5hdGl2ZUV2ZW50KSB7XG4gIFN5bnRoZXRpY0V2ZW50LmNhbGwodGhpcywgZGlzcGF0Y2hDb25maWcsIGRpc3BhdGNoTWFya2VyLCBuYXRpdmVFdmVudCk7XG59XG5cblN5bnRoZXRpY0V2ZW50LmF1Z21lbnRDbGFzcyhTeW50aGV0aWNVSUV2ZW50LCBVSUV2ZW50SW50ZXJmYWNlKTtcblxubW9kdWxlLmV4cG9ydHMgPSBTeW50aGV0aWNVSUV2ZW50O1xuIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIFN5bnRoZXRpY1doZWVsRXZlbnRcbiAqIEB0eXBlY2hlY2tzIHN0YXRpYy1vbmx5XG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBTeW50aGV0aWNNb3VzZUV2ZW50ID0gcmVxdWlyZShcIi4vU3ludGhldGljTW91c2VFdmVudFwiKTtcblxuLyoqXG4gKiBAaW50ZXJmYWNlIFdoZWVsRXZlbnRcbiAqIEBzZWUgaHR0cDovL3d3dy53My5vcmcvVFIvRE9NLUxldmVsLTMtRXZlbnRzL1xuICovXG52YXIgV2hlZWxFdmVudEludGVyZmFjZSA9IHtcbiAgZGVsdGFYOiBmdW5jdGlvbihldmVudCkge1xuICAgIHJldHVybiAoXG4gICAgICAnZGVsdGFYJyBpbiBldmVudCA/IGV2ZW50LmRlbHRhWCA6XG4gICAgICAvLyBGYWxsYmFjayB0byBgd2hlZWxEZWx0YVhgIGZvciBXZWJraXQgYW5kIG5vcm1hbGl6ZSAocmlnaHQgaXMgcG9zaXRpdmUpLlxuICAgICAgJ3doZWVsRGVsdGFYJyBpbiBldmVudCA/IC1ldmVudC53aGVlbERlbHRhWCA6IDBcbiAgICApO1xuICB9LFxuICBkZWx0YVk6IGZ1bmN0aW9uKGV2ZW50KSB7XG4gICAgcmV0dXJuIChcbiAgICAgICdkZWx0YVknIGluIGV2ZW50ID8gZXZlbnQuZGVsdGFZIDpcbiAgICAgIC8vIEZhbGxiYWNrIHRvIGB3aGVlbERlbHRhWWAgZm9yIFdlYmtpdCBhbmQgbm9ybWFsaXplIChkb3duIGlzIHBvc2l0aXZlKS5cbiAgICAgICd3aGVlbERlbHRhWScgaW4gZXZlbnQgPyAtZXZlbnQud2hlZWxEZWx0YVkgOlxuICAgICAgLy8gRmFsbGJhY2sgdG8gYHdoZWVsRGVsdGFgIGZvciBJRTw5IGFuZCBub3JtYWxpemUgKGRvd24gaXMgcG9zaXRpdmUpLlxuICAgICAgJ3doZWVsRGVsdGEnIGluIGV2ZW50ID8gLWV2ZW50LndoZWVsRGVsdGEgOiAwXG4gICAgKTtcbiAgfSxcbiAgZGVsdGFaOiBudWxsLFxuXG4gIC8vIEJyb3dzZXJzIHdpdGhvdXQgXCJkZWx0YU1vZGVcIiBpcyByZXBvcnRpbmcgaW4gcmF3IHdoZWVsIGRlbHRhIHdoZXJlIG9uZVxuICAvLyBub3RjaCBvbiB0aGUgc2Nyb2xsIGlzIGFsd2F5cyArLy0gMTIwLCByb3VnaGx5IGVxdWl2YWxlbnQgdG8gcGl4ZWxzLlxuICAvLyBBIGdvb2QgYXBwcm94aW1hdGlvbiBvZiBET01fREVMVEFfTElORSAoMSkgaXMgNSUgb2Ygdmlld3BvcnQgc2l6ZSBvclxuICAvLyB+NDAgcGl4ZWxzLCBmb3IgRE9NX0RFTFRBX1NDUkVFTiAoMikgaXQgaXMgODcuNSUgb2Ygdmlld3BvcnQgc2l6ZS5cbiAgZGVsdGFNb2RlOiBudWxsXG59O1xuXG4vKipcbiAqIEBwYXJhbSB7b2JqZWN0fSBkaXNwYXRjaENvbmZpZyBDb25maWd1cmF0aW9uIHVzZWQgdG8gZGlzcGF0Y2ggdGhpcyBldmVudC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBkaXNwYXRjaE1hcmtlciBNYXJrZXIgaWRlbnRpZnlpbmcgdGhlIGV2ZW50IHRhcmdldC5cbiAqIEBwYXJhbSB7b2JqZWN0fSBuYXRpdmVFdmVudCBOYXRpdmUgYnJvd3NlciBldmVudC5cbiAqIEBleHRlbmRzIHtTeW50aGV0aWNNb3VzZUV2ZW50fVxuICovXG5mdW5jdGlvbiBTeW50aGV0aWNXaGVlbEV2ZW50KGRpc3BhdGNoQ29uZmlnLCBkaXNwYXRjaE1hcmtlciwgbmF0aXZlRXZlbnQpIHtcbiAgU3ludGhldGljTW91c2VFdmVudC5jYWxsKHRoaXMsIGRpc3BhdGNoQ29uZmlnLCBkaXNwYXRjaE1hcmtlciwgbmF0aXZlRXZlbnQpO1xufVxuXG5TeW50aGV0aWNNb3VzZUV2ZW50LmF1Z21lbnRDbGFzcyhTeW50aGV0aWNXaGVlbEV2ZW50LCBXaGVlbEV2ZW50SW50ZXJmYWNlKTtcblxubW9kdWxlLmV4cG9ydHMgPSBTeW50aGV0aWNXaGVlbEV2ZW50O1xuIiwiKGZ1bmN0aW9uIChwcm9jZXNzKXtcbi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBUcmFuc2FjdGlvblxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgaW52YXJpYW50ID0gcmVxdWlyZShcIi4vaW52YXJpYW50XCIpO1xuXG4vKipcbiAqIGBUcmFuc2FjdGlvbmAgY3JlYXRlcyBhIGJsYWNrIGJveCB0aGF0IGlzIGFibGUgdG8gd3JhcCBhbnkgbWV0aG9kIHN1Y2ggdGhhdFxuICogY2VydGFpbiBpbnZhcmlhbnRzIGFyZSBtYWludGFpbmVkIGJlZm9yZSBhbmQgYWZ0ZXIgdGhlIG1ldGhvZCBpcyBpbnZva2VkXG4gKiAoRXZlbiBpZiBhbiBleGNlcHRpb24gaXMgdGhyb3duIHdoaWxlIGludm9raW5nIHRoZSB3cmFwcGVkIG1ldGhvZCkuIFdob2V2ZXJcbiAqIGluc3RhbnRpYXRlcyBhIHRyYW5zYWN0aW9uIGNhbiBwcm92aWRlIGVuZm9yY2VycyBvZiB0aGUgaW52YXJpYW50cyBhdFxuICogY3JlYXRpb24gdGltZS4gVGhlIGBUcmFuc2FjdGlvbmAgY2xhc3MgaXRzZWxmIHdpbGwgc3VwcGx5IG9uZSBhZGRpdGlvbmFsXG4gKiBhdXRvbWF0aWMgaW52YXJpYW50IGZvciB5b3UgLSB0aGUgaW52YXJpYW50IHRoYXQgYW55IHRyYW5zYWN0aW9uIGluc3RhbmNlXG4gKiBzaG91bGQgbm90IGJlIHJ1biB3aGlsZSBpdCBpcyBhbHJlYWR5IGJlaW5nIHJ1bi4gWW91IHdvdWxkIHR5cGljYWxseSBjcmVhdGUgYVxuICogc2luZ2xlIGluc3RhbmNlIG9mIGEgYFRyYW5zYWN0aW9uYCBmb3IgcmV1c2UgbXVsdGlwbGUgdGltZXMsIHRoYXQgcG90ZW50aWFsbHlcbiAqIGlzIHVzZWQgdG8gd3JhcCBzZXZlcmFsIGRpZmZlcmVudCBtZXRob2RzLiBXcmFwcGVycyBhcmUgZXh0cmVtZWx5IHNpbXBsZSAtXG4gKiB0aGV5IG9ubHkgcmVxdWlyZSBpbXBsZW1lbnRpbmcgdHdvIG1ldGhvZHMuXG4gKlxuICogPHByZT5cbiAqICAgICAgICAgICAgICAgICAgICAgICB3cmFwcGVycyAoaW5qZWN0ZWQgYXQgY3JlYXRpb24gdGltZSlcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICArICAgICAgICArXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgfFxuICogICAgICAgICAgICAgICAgICAgICstLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLXwtLS0tLS0tLS0tLS0tLStcbiAqICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICB2ICAgICAgICB8ICAgICAgICAgICAgICB8XG4gKiAgICAgICAgICAgICAgICAgICAgfCAgICAgICstLS0tLS0tLS0tLS0tLS0rICAgfCAgICAgICAgICAgICAgfFxuICogICAgICAgICAgICAgICAgICAgIHwgICArLS18ICAgIHdyYXBwZXIxICAgfC0tLXwtLS0tKyAgICAgICAgIHxcbiAqICAgICAgICAgICAgICAgICAgICB8ICAgfCAgKy0tLS0tLS0tLS0tLS0tLSsgICB2ICAgIHwgICAgICAgICB8XG4gKiAgICAgICAgICAgICAgICAgICAgfCAgIHwgICAgICAgICAgKy0tLS0tLS0tLS0tLS0rICB8ICAgICAgICAgfFxuICogICAgICAgICAgICAgICAgICAgIHwgICB8ICAgICArLS0tLXwgICB3cmFwcGVyMiAgfC0tLS0tLS0tKyAgIHxcbiAqICAgICAgICAgICAgICAgICAgICB8ICAgfCAgICAgfCAgICArLS0tLS0tLS0tLS0tLSsgIHwgICAgIHwgICB8XG4gKiAgICAgICAgICAgICAgICAgICAgfCAgIHwgICAgIHwgICAgICAgICAgICAgICAgICAgICB8ICAgICB8ICAgfFxuICogICAgICAgICAgICAgICAgICAgIHwgICB2ICAgICB2ICAgICAgICAgICAgICAgICAgICAgdiAgICAgdiAgIHwgd3JhcHBlclxuICogICAgICAgICAgICAgICAgICAgIHwgKy0tLSsgKy0tLSsgICArLS0tLS0tLS0tKyAgICstLS0rICstLS0rIHwgaW52YXJpYW50c1xuICogcGVyZm9ybShhbnlNZXRob2QpIHwgfCAgIHwgfCAgIHwgICB8ICAgICAgICAgfCAgIHwgICB8IHwgICB8IHwgbWFpbnRhaW5lZFxuICogKy0tLS0tLS0tLS0tLS0tLS0tPnwtfC0tLXwtfC0tLXwtLT58YW55TWV0aG9kfC0tLXwtLS18LXwtLS18LXwtLS0tLS0tLT5cbiAqICAgICAgICAgICAgICAgICAgICB8IHwgICB8IHwgICB8ICAgfCAgICAgICAgIHwgICB8ICAgfCB8ICAgfCB8XG4gKiAgICAgICAgICAgICAgICAgICAgfCB8ICAgfCB8ICAgfCAgIHwgICAgICAgICB8ICAgfCAgIHwgfCAgIHwgfFxuICogICAgICAgICAgICAgICAgICAgIHwgfCAgIHwgfCAgIHwgICB8ICAgICAgICAgfCAgIHwgICB8IHwgICB8IHxcbiAqICAgICAgICAgICAgICAgICAgICB8ICstLS0rICstLS0rICAgKy0tLS0tLS0tLSsgICArLS0tKyArLS0tKyB8XG4gKiAgICAgICAgICAgICAgICAgICAgfCAgaW5pdGlhbGl6ZSAgICAgICAgICAgICAgICAgICAgY2xvc2UgICAgfFxuICogICAgICAgICAgICAgICAgICAgICstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLStcbiAqIDwvcHJlPlxuICpcbiAqIFVzZSBjYXNlczpcbiAqIC0gUHJlc2VydmluZyB0aGUgaW5wdXQgc2VsZWN0aW9uIHJhbmdlcyBiZWZvcmUvYWZ0ZXIgcmVjb25jaWxpYXRpb24uXG4gKiAgIFJlc3RvcmluZyBzZWxlY3Rpb24gZXZlbiBpbiB0aGUgZXZlbnQgb2YgYW4gdW5leHBlY3RlZCBlcnJvci5cbiAqIC0gRGVhY3RpdmF0aW5nIGV2ZW50cyB3aGlsZSByZWFycmFuZ2luZyB0aGUgRE9NLCBwcmV2ZW50aW5nIGJsdXJzL2ZvY3VzZXMsXG4gKiAgIHdoaWxlIGd1YXJhbnRlZWluZyB0aGF0IGFmdGVyd2FyZHMsIHRoZSBldmVudCBzeXN0ZW0gaXMgcmVhY3RpdmF0ZWQuXG4gKiAtIEZsdXNoaW5nIGEgcXVldWUgb2YgY29sbGVjdGVkIERPTSBtdXRhdGlvbnMgdG8gdGhlIG1haW4gVUkgdGhyZWFkIGFmdGVyIGFcbiAqICAgcmVjb25jaWxpYXRpb24gdGFrZXMgcGxhY2UgaW4gYSB3b3JrZXIgdGhyZWFkLlxuICogLSBJbnZva2luZyBhbnkgY29sbGVjdGVkIGBjb21wb25lbnREaWRVcGRhdGVgIGNhbGxiYWNrcyBhZnRlciByZW5kZXJpbmcgbmV3XG4gKiAgIGNvbnRlbnQuXG4gKiAtIChGdXR1cmUgdXNlIGNhc2UpOiBXcmFwcGluZyBwYXJ0aWN1bGFyIGZsdXNoZXMgb2YgdGhlIGBSZWFjdFdvcmtlcmAgcXVldWVcbiAqICAgdG8gcHJlc2VydmUgdGhlIGBzY3JvbGxUb3BgIChhbiBhdXRvbWF0aWMgc2Nyb2xsIGF3YXJlIERPTSkuXG4gKiAtIChGdXR1cmUgdXNlIGNhc2UpOiBMYXlvdXQgY2FsY3VsYXRpb25zIGJlZm9yZSBhbmQgYWZ0ZXIgRE9NIHVwYXRlcy5cbiAqXG4gKiBUcmFuc2FjdGlvbmFsIHBsdWdpbiBBUEk6XG4gKiAtIEEgbW9kdWxlIHRoYXQgaGFzIGFuIGBpbml0aWFsaXplYCBtZXRob2QgdGhhdCByZXR1cm5zIGFueSBwcmVjb21wdXRhdGlvbi5cbiAqIC0gYW5kIGEgYGNsb3NlYCBtZXRob2QgdGhhdCBhY2NlcHRzIHRoZSBwcmVjb21wdXRhdGlvbi4gYGNsb3NlYCBpcyBpbnZva2VkXG4gKiAgIHdoZW4gdGhlIHdyYXBwZWQgcHJvY2VzcyBpcyBjb21wbGV0ZWQsIG9yIGhhcyBmYWlsZWQuXG4gKlxuICogQHBhcmFtIHtBcnJheTxUcmFuc2FjdGlvbmFsV3JhcHBlcj59IHRyYW5zYWN0aW9uV3JhcHBlciBXcmFwcGVyIG1vZHVsZXNcbiAqIHRoYXQgaW1wbGVtZW50IGBpbml0aWFsaXplYCBhbmQgYGNsb3NlYC5cbiAqIEByZXR1cm4ge1RyYW5zYWN0aW9ufSBTaW5nbGUgdHJhbnNhY3Rpb24gZm9yIHJldXNlIGluIHRocmVhZC5cbiAqXG4gKiBAY2xhc3MgVHJhbnNhY3Rpb25cbiAqL1xudmFyIE1peGluID0ge1xuICAvKipcbiAgICogU2V0cyB1cCB0aGlzIGluc3RhbmNlIHNvIHRoYXQgaXQgaXMgcHJlcGFyZWQgZm9yIGNvbGxlY3RpbmcgbWV0cmljcy4gRG9lc1xuICAgKiBzbyBzdWNoIHRoYXQgdGhpcyBzZXR1cCBtZXRob2QgbWF5IGJlIHVzZWQgb24gYW4gaW5zdGFuY2UgdGhhdCBpcyBhbHJlYWR5XG4gICAqIGluaXRpYWxpemVkLCBpbiBhIHdheSB0aGF0IGRvZXMgbm90IGNvbnN1bWUgYWRkaXRpb25hbCBtZW1vcnkgdXBvbiByZXVzZS5cbiAgICogVGhhdCBjYW4gYmUgdXNlZnVsIGlmIHlvdSBkZWNpZGUgdG8gbWFrZSB5b3VyIHN1YmNsYXNzIG9mIHRoaXMgbWl4aW4gYVxuICAgKiBcIlBvb2xlZENsYXNzXCIuXG4gICAqL1xuICByZWluaXRpYWxpemVUcmFuc2FjdGlvbjogZnVuY3Rpb24oKSB7XG4gICAgdGhpcy50cmFuc2FjdGlvbldyYXBwZXJzID0gdGhpcy5nZXRUcmFuc2FjdGlvbldyYXBwZXJzKCk7XG4gICAgaWYgKCF0aGlzLndyYXBwZXJJbml0RGF0YSkge1xuICAgICAgdGhpcy53cmFwcGVySW5pdERhdGEgPSBbXTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy53cmFwcGVySW5pdERhdGEubGVuZ3RoID0gMDtcbiAgICB9XG4gICAgdGhpcy5faXNJblRyYW5zYWN0aW9uID0gZmFsc2U7XG4gIH0sXG5cbiAgX2lzSW5UcmFuc2FjdGlvbjogZmFsc2UsXG5cbiAgLyoqXG4gICAqIEBhYnN0cmFjdFxuICAgKiBAcmV0dXJuIHtBcnJheTxUcmFuc2FjdGlvbldyYXBwZXI+fSBBcnJheSBvZiB0cmFuc2FjdGlvbiB3cmFwcGVycy5cbiAgICovXG4gIGdldFRyYW5zYWN0aW9uV3JhcHBlcnM6IG51bGwsXG5cbiAgaXNJblRyYW5zYWN0aW9uOiBmdW5jdGlvbigpIHtcbiAgICByZXR1cm4gISF0aGlzLl9pc0luVHJhbnNhY3Rpb247XG4gIH0sXG5cbiAgLyoqXG4gICAqIEV4ZWN1dGVzIHRoZSBmdW5jdGlvbiB3aXRoaW4gYSBzYWZldHkgd2luZG93LiBVc2UgdGhpcyBmb3IgdGhlIHRvcCBsZXZlbFxuICAgKiBtZXRob2RzIHRoYXQgcmVzdWx0IGluIGxhcmdlIGFtb3VudHMgb2YgY29tcHV0YXRpb24vbXV0YXRpb25zIHRoYXQgd291bGRcbiAgICogbmVlZCB0byBiZSBzYWZldHkgY2hlY2tlZC5cbiAgICpcbiAgICogQHBhcmFtIHtmdW5jdGlvbn0gbWV0aG9kIE1lbWJlciBvZiBzY29wZSB0byBjYWxsLlxuICAgKiBAcGFyYW0ge09iamVjdH0gc2NvcGUgU2NvcGUgdG8gaW52b2tlIGZyb20uXG4gICAqIEBwYXJhbSB7T2JqZWN0Pz19IGFyZ3MuLi4gQXJndW1lbnRzIHRvIHBhc3MgdG8gdGhlIG1ldGhvZCAob3B0aW9uYWwpLlxuICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgIEhlbHBzIHByZXZlbnQgbmVlZCB0byBiaW5kIGluIG1hbnkgY2FzZXMuXG4gICAqIEByZXR1cm4gUmV0dXJuIHZhbHVlIGZyb20gYG1ldGhvZGAuXG4gICAqL1xuICBwZXJmb3JtOiBmdW5jdGlvbihtZXRob2QsIHNjb3BlLCBhLCBiLCBjLCBkLCBlLCBmKSB7XG4gICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgICF0aGlzLmlzSW5UcmFuc2FjdGlvbigpLFxuICAgICAgJ1RyYW5zYWN0aW9uLnBlcmZvcm0oLi4uKTogQ2Fubm90IGluaXRpYWxpemUgYSB0cmFuc2FjdGlvbiB3aGVuIHRoZXJlICcgK1xuICAgICAgJ2lzIGFscmVhZHkgYW4gb3V0c3RhbmRpbmcgdHJhbnNhY3Rpb24uJ1xuICAgICkgOiBpbnZhcmlhbnQoIXRoaXMuaXNJblRyYW5zYWN0aW9uKCkpKTtcbiAgICB2YXIgZXJyb3JUaHJvd247XG4gICAgdmFyIHJldDtcbiAgICB0cnkge1xuICAgICAgdGhpcy5faXNJblRyYW5zYWN0aW9uID0gdHJ1ZTtcbiAgICAgIC8vIENhdGNoaW5nIGVycm9ycyBtYWtlcyBkZWJ1Z2dpbmcgbW9yZSBkaWZmaWN1bHQsIHNvIHdlIHN0YXJ0IHdpdGhcbiAgICAgIC8vIGVycm9yVGhyb3duIHNldCB0byB0cnVlIGJlZm9yZSBzZXR0aW5nIGl0IHRvIGZhbHNlIGFmdGVyIGNhbGxpbmdcbiAgICAgIC8vIGNsb3NlIC0tIGlmIGl0J3Mgc3RpbGwgc2V0IHRvIHRydWUgaW4gdGhlIGZpbmFsbHkgYmxvY2ssIGl0IG1lYW5zXG4gICAgICAvLyBvbmUgb2YgdGhlc2UgY2FsbHMgdGhyZXcuXG4gICAgICBlcnJvclRocm93biA9IHRydWU7XG4gICAgICB0aGlzLmluaXRpYWxpemVBbGwoMCk7XG4gICAgICByZXQgPSBtZXRob2QuY2FsbChzY29wZSwgYSwgYiwgYywgZCwgZSwgZik7XG4gICAgICBlcnJvclRocm93biA9IGZhbHNlO1xuICAgIH0gZmluYWxseSB7XG4gICAgICB0cnkge1xuICAgICAgICBpZiAoZXJyb3JUaHJvd24pIHtcbiAgICAgICAgICAvLyBJZiBgbWV0aG9kYCB0aHJvd3MsIHByZWZlciB0byBzaG93IHRoYXQgc3RhY2sgdHJhY2Ugb3ZlciBhbnkgdGhyb3duXG4gICAgICAgICAgLy8gYnkgaW52b2tpbmcgYGNsb3NlQWxsYC5cbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgdGhpcy5jbG9zZUFsbCgwKTtcbiAgICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy8gU2luY2UgYG1ldGhvZGAgZGlkbid0IHRocm93LCB3ZSBkb24ndCB3YW50IHRvIHNpbGVuY2UgdGhlIGV4Y2VwdGlvblxuICAgICAgICAgIC8vIGhlcmUuXG4gICAgICAgICAgdGhpcy5jbG9zZUFsbCgwKTtcbiAgICAgICAgfVxuICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgdGhpcy5faXNJblRyYW5zYWN0aW9uID0gZmFsc2U7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiByZXQ7XG4gIH0sXG5cbiAgaW5pdGlhbGl6ZUFsbDogZnVuY3Rpb24oc3RhcnRJbmRleCkge1xuICAgIHZhciB0cmFuc2FjdGlvbldyYXBwZXJzID0gdGhpcy50cmFuc2FjdGlvbldyYXBwZXJzO1xuICAgIGZvciAodmFyIGkgPSBzdGFydEluZGV4OyBpIDwgdHJhbnNhY3Rpb25XcmFwcGVycy5sZW5ndGg7IGkrKykge1xuICAgICAgdmFyIHdyYXBwZXIgPSB0cmFuc2FjdGlvbldyYXBwZXJzW2ldO1xuICAgICAgdHJ5IHtcbiAgICAgICAgLy8gQ2F0Y2hpbmcgZXJyb3JzIG1ha2VzIGRlYnVnZ2luZyBtb3JlIGRpZmZpY3VsdCwgc28gd2Ugc3RhcnQgd2l0aCB0aGVcbiAgICAgICAgLy8gT0JTRVJWRURfRVJST1Igc3RhdGUgYmVmb3JlIG92ZXJ3cml0aW5nIGl0IHdpdGggdGhlIHJlYWwgcmV0dXJuIHZhbHVlXG4gICAgICAgIC8vIG9mIGluaXRpYWxpemUgLS0gaWYgaXQncyBzdGlsbCBzZXQgdG8gT0JTRVJWRURfRVJST1IgaW4gdGhlIGZpbmFsbHlcbiAgICAgICAgLy8gYmxvY2ssIGl0IG1lYW5zIHdyYXBwZXIuaW5pdGlhbGl6ZSB0aHJldy5cbiAgICAgICAgdGhpcy53cmFwcGVySW5pdERhdGFbaV0gPSBUcmFuc2FjdGlvbi5PQlNFUlZFRF9FUlJPUjtcbiAgICAgICAgdGhpcy53cmFwcGVySW5pdERhdGFbaV0gPSB3cmFwcGVyLmluaXRpYWxpemUgP1xuICAgICAgICAgIHdyYXBwZXIuaW5pdGlhbGl6ZS5jYWxsKHRoaXMpIDpcbiAgICAgICAgICBudWxsO1xuICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgaWYgKHRoaXMud3JhcHBlckluaXREYXRhW2ldID09PSBUcmFuc2FjdGlvbi5PQlNFUlZFRF9FUlJPUikge1xuICAgICAgICAgIC8vIFRoZSBpbml0aWFsaXplciBmb3Igd3JhcHBlciBpIHRocmV3IGFuIGVycm9yOyBpbml0aWFsaXplIHRoZVxuICAgICAgICAgIC8vIHJlbWFpbmluZyB3cmFwcGVycyBidXQgc2lsZW5jZSBhbnkgZXhjZXB0aW9ucyBmcm9tIHRoZW0gdG8gZW5zdXJlXG4gICAgICAgICAgLy8gdGhhdCB0aGUgZmlyc3QgZXJyb3IgaXMgdGhlIG9uZSB0byBidWJibGUgdXAuXG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIHRoaXMuaW5pdGlhbGl6ZUFsbChpICsgMSk7XG4gICAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9LFxuXG4gIC8qKlxuICAgKiBJbnZva2VzIGVhY2ggb2YgYHRoaXMudHJhbnNhY3Rpb25XcmFwcGVycy5jbG9zZVtpXWAgZnVuY3Rpb25zLCBwYXNzaW5nIGludG9cbiAgICogdGhlbSB0aGUgcmVzcGVjdGl2ZSByZXR1cm4gdmFsdWVzIG9mIGB0aGlzLnRyYW5zYWN0aW9uV3JhcHBlcnMuaW5pdFtpXWBcbiAgICogKGBjbG9zZWBycyB0aGF0IGNvcnJlc3BvbmQgdG8gaW5pdGlhbGl6ZXJzIHRoYXQgZmFpbGVkIHdpbGwgbm90IGJlXG4gICAqIGludm9rZWQpLlxuICAgKi9cbiAgY2xvc2VBbGw6IGZ1bmN0aW9uKHN0YXJ0SW5kZXgpIHtcbiAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgICAgdGhpcy5pc0luVHJhbnNhY3Rpb24oKSxcbiAgICAgICdUcmFuc2FjdGlvbi5jbG9zZUFsbCgpOiBDYW5ub3QgY2xvc2UgdHJhbnNhY3Rpb24gd2hlbiBub25lIGFyZSBvcGVuLidcbiAgICApIDogaW52YXJpYW50KHRoaXMuaXNJblRyYW5zYWN0aW9uKCkpKTtcbiAgICB2YXIgdHJhbnNhY3Rpb25XcmFwcGVycyA9IHRoaXMudHJhbnNhY3Rpb25XcmFwcGVycztcbiAgICBmb3IgKHZhciBpID0gc3RhcnRJbmRleDsgaSA8IHRyYW5zYWN0aW9uV3JhcHBlcnMubGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciB3cmFwcGVyID0gdHJhbnNhY3Rpb25XcmFwcGVyc1tpXTtcbiAgICAgIHZhciBpbml0RGF0YSA9IHRoaXMud3JhcHBlckluaXREYXRhW2ldO1xuICAgICAgdmFyIGVycm9yVGhyb3duO1xuICAgICAgdHJ5IHtcbiAgICAgICAgLy8gQ2F0Y2hpbmcgZXJyb3JzIG1ha2VzIGRlYnVnZ2luZyBtb3JlIGRpZmZpY3VsdCwgc28gd2Ugc3RhcnQgd2l0aFxuICAgICAgICAvLyBlcnJvclRocm93biBzZXQgdG8gdHJ1ZSBiZWZvcmUgc2V0dGluZyBpdCB0byBmYWxzZSBhZnRlciBjYWxsaW5nXG4gICAgICAgIC8vIGNsb3NlIC0tIGlmIGl0J3Mgc3RpbGwgc2V0IHRvIHRydWUgaW4gdGhlIGZpbmFsbHkgYmxvY2ssIGl0IG1lYW5zXG4gICAgICAgIC8vIHdyYXBwZXIuY2xvc2UgdGhyZXcuXG4gICAgICAgIGVycm9yVGhyb3duID0gdHJ1ZTtcbiAgICAgICAgaWYgKGluaXREYXRhICE9PSBUcmFuc2FjdGlvbi5PQlNFUlZFRF9FUlJPUikge1xuICAgICAgICAgIHdyYXBwZXIuY2xvc2UgJiYgd3JhcHBlci5jbG9zZS5jYWxsKHRoaXMsIGluaXREYXRhKTtcbiAgICAgICAgfVxuICAgICAgICBlcnJvclRocm93biA9IGZhbHNlO1xuICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgaWYgKGVycm9yVGhyb3duKSB7XG4gICAgICAgICAgLy8gVGhlIGNsb3NlciBmb3Igd3JhcHBlciBpIHRocmV3IGFuIGVycm9yOyBjbG9zZSB0aGUgcmVtYWluaW5nXG4gICAgICAgICAgLy8gd3JhcHBlcnMgYnV0IHNpbGVuY2UgYW55IGV4Y2VwdGlvbnMgZnJvbSB0aGVtIHRvIGVuc3VyZSB0aGF0IHRoZVxuICAgICAgICAgIC8vIGZpcnN0IGVycm9yIGlzIHRoZSBvbmUgdG8gYnViYmxlIHVwLlxuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICB0aGlzLmNsb3NlQWxsKGkgKyAxKTtcbiAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIHRoaXMud3JhcHBlckluaXREYXRhLmxlbmd0aCA9IDA7XG4gIH1cbn07XG5cbnZhciBUcmFuc2FjdGlvbiA9IHtcblxuICBNaXhpbjogTWl4aW4sXG5cbiAgLyoqXG4gICAqIFRva2VuIHRvIGxvb2sgZm9yIHRvIGRldGVybWluZSBpZiBhbiBlcnJvciBvY2N1cmVkLlxuICAgKi9cbiAgT0JTRVJWRURfRVJST1I6IHt9XG5cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gVHJhbnNhY3Rpb247XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKCdfcHJvY2VzcycpKSIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBWaWV3cG9ydE1ldHJpY3NcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIGdldFVuYm91bmRlZFNjcm9sbFBvc2l0aW9uID0gcmVxdWlyZShcIi4vZ2V0VW5ib3VuZGVkU2Nyb2xsUG9zaXRpb25cIik7XG5cbnZhciBWaWV3cG9ydE1ldHJpY3MgPSB7XG5cbiAgY3VycmVudFNjcm9sbExlZnQ6IDAsXG5cbiAgY3VycmVudFNjcm9sbFRvcDogMCxcblxuICByZWZyZXNoU2Nyb2xsVmFsdWVzOiBmdW5jdGlvbigpIHtcbiAgICB2YXIgc2Nyb2xsUG9zaXRpb24gPSBnZXRVbmJvdW5kZWRTY3JvbGxQb3NpdGlvbih3aW5kb3cpO1xuICAgIFZpZXdwb3J0TWV0cmljcy5jdXJyZW50U2Nyb2xsTGVmdCA9IHNjcm9sbFBvc2l0aW9uLng7XG4gICAgVmlld3BvcnRNZXRyaWNzLmN1cnJlbnRTY3JvbGxUb3AgPSBzY3JvbGxQb3NpdGlvbi55O1xuICB9XG5cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gVmlld3BvcnRNZXRyaWNzO1xuIiwiKGZ1bmN0aW9uIChwcm9jZXNzKXtcbi8qKlxuICogQ29weXJpZ2h0IDIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgYWNjdW11bGF0ZUludG9cbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIGludmFyaWFudCA9IHJlcXVpcmUoXCIuL2ludmFyaWFudFwiKTtcblxuLyoqXG4gKlxuICogQWNjdW11bGF0ZXMgaXRlbXMgdGhhdCBtdXN0IG5vdCBiZSBudWxsIG9yIHVuZGVmaW5lZCBpbnRvIHRoZSBmaXJzdCBvbmUuIFRoaXNcbiAqIGlzIHVzZWQgdG8gY29uc2VydmUgbWVtb3J5IGJ5IGF2b2lkaW5nIGFycmF5IGFsbG9jYXRpb25zLCBhbmQgdGh1cyBzYWNyaWZpY2VzXG4gKiBBUEkgY2xlYW5uZXNzLiBTaW5jZSBgY3VycmVudGAgY2FuIGJlIG51bGwgYmVmb3JlIGJlaW5nIHBhc3NlZCBpbiBhbmQgbm90XG4gKiBudWxsIGFmdGVyIHRoaXMgZnVuY3Rpb24sIG1ha2Ugc3VyZSB0byBhc3NpZ24gaXQgYmFjayB0byBgY3VycmVudGA6XG4gKlxuICogYGEgPSBhY2N1bXVsYXRlSW50byhhLCBiKTtgXG4gKlxuICogVGhpcyBBUEkgc2hvdWxkIGJlIHNwYXJpbmdseSB1c2VkLiBUcnkgYGFjY3VtdWxhdGVgIGZvciBzb21ldGhpbmcgY2xlYW5lci5cbiAqXG4gKiBAcmV0dXJuIHsqfGFycmF5PCo+fSBBbiBhY2N1bXVsYXRpb24gb2YgaXRlbXMuXG4gKi9cblxuZnVuY3Rpb24gYWNjdW11bGF0ZUludG8oY3VycmVudCwgbmV4dCkge1xuICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgIG5leHQgIT0gbnVsbCxcbiAgICAnYWNjdW11bGF0ZUludG8oLi4uKTogQWNjdW11bGF0ZWQgaXRlbXMgbXVzdCBub3QgYmUgbnVsbCBvciB1bmRlZmluZWQuJ1xuICApIDogaW52YXJpYW50KG5leHQgIT0gbnVsbCkpO1xuICBpZiAoY3VycmVudCA9PSBudWxsKSB7XG4gICAgcmV0dXJuIG5leHQ7XG4gIH1cblxuICAvLyBCb3RoIGFyZSBub3QgZW1wdHkuIFdhcm5pbmc6IE5ldmVyIGNhbGwgeC5jb25jYXQoeSkgd2hlbiB5b3UgYXJlIG5vdFxuICAvLyBjZXJ0YWluIHRoYXQgeCBpcyBhbiBBcnJheSAoeCBjb3VsZCBiZSBhIHN0cmluZyB3aXRoIGNvbmNhdCBtZXRob2QpLlxuICB2YXIgY3VycmVudElzQXJyYXkgPSBBcnJheS5pc0FycmF5KGN1cnJlbnQpO1xuICB2YXIgbmV4dElzQXJyYXkgPSBBcnJheS5pc0FycmF5KG5leHQpO1xuXG4gIGlmIChjdXJyZW50SXNBcnJheSAmJiBuZXh0SXNBcnJheSkge1xuICAgIGN1cnJlbnQucHVzaC5hcHBseShjdXJyZW50LCBuZXh0KTtcbiAgICByZXR1cm4gY3VycmVudDtcbiAgfVxuXG4gIGlmIChjdXJyZW50SXNBcnJheSkge1xuICAgIGN1cnJlbnQucHVzaChuZXh0KTtcbiAgICByZXR1cm4gY3VycmVudDtcbiAgfVxuXG4gIGlmIChuZXh0SXNBcnJheSkge1xuICAgIC8vIEEgYml0IHRvbyBkYW5nZXJvdXMgdG8gbXV0YXRlIGBuZXh0YC5cbiAgICByZXR1cm4gW2N1cnJlbnRdLmNvbmNhdChuZXh0KTtcbiAgfVxuXG4gIHJldHVybiBbY3VycmVudCwgbmV4dF07XG59XG5cbm1vZHVsZS5leHBvcnRzID0gYWNjdW11bGF0ZUludG87XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKCdfcHJvY2VzcycpKSIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBhZGxlcjMyXG4gKi9cblxuLyoganNsaW50IGJpdHdpc2U6dHJ1ZSAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIE1PRCA9IDY1NTIxO1xuXG4vLyBUaGlzIGlzIGEgY2xlYW4tcm9vbSBpbXBsZW1lbnRhdGlvbiBvZiBhZGxlcjMyIGRlc2lnbmVkIGZvciBkZXRlY3Rpbmdcbi8vIGlmIG1hcmt1cCBpcyBub3Qgd2hhdCB3ZSBleHBlY3QgaXQgdG8gYmUuIEl0IGRvZXMgbm90IG5lZWQgdG8gYmVcbi8vIGNyeXB0b2dyYXBoaWNhbGx5IHN0cm9uZywgb25seSByZWFzb25hYmx5IGdvb2QgYXQgZGV0ZWN0aW5nIGlmIG1hcmt1cFxuLy8gZ2VuZXJhdGVkIG9uIHRoZSBzZXJ2ZXIgaXMgZGlmZmVyZW50IHRoYW4gdGhhdCBvbiB0aGUgY2xpZW50LlxuZnVuY3Rpb24gYWRsZXIzMihkYXRhKSB7XG4gIHZhciBhID0gMTtcbiAgdmFyIGIgPSAwO1xuICBmb3IgKHZhciBpID0gMDsgaSA8IGRhdGEubGVuZ3RoOyBpKyspIHtcbiAgICBhID0gKGEgKyBkYXRhLmNoYXJDb2RlQXQoaSkpICUgTU9EO1xuICAgIGIgPSAoYiArIGEpICUgTU9EO1xuICB9XG4gIHJldHVybiBhIHwgKGIgPDwgMTYpO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGFkbGVyMzI7XG4iLCIvKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgY2FtZWxpemVcbiAqIEB0eXBlY2hlY2tzXG4gKi9cblxudmFyIF9oeXBoZW5QYXR0ZXJuID0gLy0oLikvZztcblxuLyoqXG4gKiBDYW1lbGNhc2VzIGEgaHlwaGVuYXRlZCBzdHJpbmcsIGZvciBleGFtcGxlOlxuICpcbiAqICAgPiBjYW1lbGl6ZSgnYmFja2dyb3VuZC1jb2xvcicpXG4gKiAgIDwgXCJiYWNrZ3JvdW5kQ29sb3JcIlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBzdHJpbmdcbiAqIEByZXR1cm4ge3N0cmluZ31cbiAqL1xuZnVuY3Rpb24gY2FtZWxpemUoc3RyaW5nKSB7XG4gIHJldHVybiBzdHJpbmcucmVwbGFjZShfaHlwaGVuUGF0dGVybiwgZnVuY3Rpb24oXywgY2hhcmFjdGVyKSB7XG4gICAgcmV0dXJuIGNoYXJhY3Rlci50b1VwcGVyQ2FzZSgpO1xuICB9KTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBjYW1lbGl6ZTtcbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgY2FtZWxpemVTdHlsZU5hbWVcbiAqIEB0eXBlY2hlY2tzXG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBjYW1lbGl6ZSA9IHJlcXVpcmUoXCIuL2NhbWVsaXplXCIpO1xuXG52YXIgbXNQYXR0ZXJuID0gL14tbXMtLztcblxuLyoqXG4gKiBDYW1lbGNhc2VzIGEgaHlwaGVuYXRlZCBDU1MgcHJvcGVydHkgbmFtZSwgZm9yIGV4YW1wbGU6XG4gKlxuICogICA+IGNhbWVsaXplU3R5bGVOYW1lKCdiYWNrZ3JvdW5kLWNvbG9yJylcbiAqICAgPCBcImJhY2tncm91bmRDb2xvclwiXG4gKiAgID4gY2FtZWxpemVTdHlsZU5hbWUoJy1tb3otdHJhbnNpdGlvbicpXG4gKiAgIDwgXCJNb3pUcmFuc2l0aW9uXCJcbiAqICAgPiBjYW1lbGl6ZVN0eWxlTmFtZSgnLW1zLXRyYW5zaXRpb24nKVxuICogICA8IFwibXNUcmFuc2l0aW9uXCJcbiAqXG4gKiBBcyBBbmRpIFNtaXRoIHN1Z2dlc3RzXG4gKiAoaHR0cDovL3d3dy5hbmRpc21pdGguY29tL2Jsb2cvMjAxMi8wMi9tb2Rlcm5penItcHJlZml4ZWQvKSwgYW4gYC1tc2AgcHJlZml4XG4gKiBpcyBjb252ZXJ0ZWQgdG8gbG93ZXJjYXNlIGBtc2AuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IHN0cmluZ1xuICogQHJldHVybiB7c3RyaW5nfVxuICovXG5mdW5jdGlvbiBjYW1lbGl6ZVN0eWxlTmFtZShzdHJpbmcpIHtcbiAgcmV0dXJuIGNhbWVsaXplKHN0cmluZy5yZXBsYWNlKG1zUGF0dGVybiwgJ21zLScpKTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBjYW1lbGl6ZVN0eWxlTmFtZTtcbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBjb250YWluc05vZGVcbiAqIEB0eXBlY2hlY2tzXG4gKi9cblxudmFyIGlzVGV4dE5vZGUgPSByZXF1aXJlKFwiLi9pc1RleHROb2RlXCIpO1xuXG4vKmpzbGludCBiaXR3aXNlOnRydWUgKi9cblxuLyoqXG4gKiBDaGVja3MgaWYgYSBnaXZlbiBET00gbm9kZSBjb250YWlucyBvciBpcyBhbm90aGVyIERPTSBub2RlLlxuICpcbiAqIEBwYXJhbSB7P0RPTU5vZGV9IG91dGVyTm9kZSBPdXRlciBET00gbm9kZS5cbiAqIEBwYXJhbSB7P0RPTU5vZGV9IGlubmVyTm9kZSBJbm5lciBET00gbm9kZS5cbiAqIEByZXR1cm4ge2Jvb2xlYW59IFRydWUgaWYgYG91dGVyTm9kZWAgY29udGFpbnMgb3IgaXMgYGlubmVyTm9kZWAuXG4gKi9cbmZ1bmN0aW9uIGNvbnRhaW5zTm9kZShvdXRlck5vZGUsIGlubmVyTm9kZSkge1xuICBpZiAoIW91dGVyTm9kZSB8fCAhaW5uZXJOb2RlKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9IGVsc2UgaWYgKG91dGVyTm9kZSA9PT0gaW5uZXJOb2RlKSB7XG4gICAgcmV0dXJuIHRydWU7XG4gIH0gZWxzZSBpZiAoaXNUZXh0Tm9kZShvdXRlck5vZGUpKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9IGVsc2UgaWYgKGlzVGV4dE5vZGUoaW5uZXJOb2RlKSkge1xuICAgIHJldHVybiBjb250YWluc05vZGUob3V0ZXJOb2RlLCBpbm5lck5vZGUucGFyZW50Tm9kZSk7XG4gIH0gZWxzZSBpZiAob3V0ZXJOb2RlLmNvbnRhaW5zKSB7XG4gICAgcmV0dXJuIG91dGVyTm9kZS5jb250YWlucyhpbm5lck5vZGUpO1xuICB9IGVsc2UgaWYgKG91dGVyTm9kZS5jb21wYXJlRG9jdW1lbnRQb3NpdGlvbikge1xuICAgIHJldHVybiAhIShvdXRlck5vZGUuY29tcGFyZURvY3VtZW50UG9zaXRpb24oaW5uZXJOb2RlKSAmIDE2KTtcbiAgfSBlbHNlIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbn1cblxubW9kdWxlLmV4cG9ydHMgPSBjb250YWluc05vZGU7XG4iLCIvKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgY3JlYXRlQXJyYXlGcm9tXG4gKiBAdHlwZWNoZWNrc1xuICovXG5cbnZhciB0b0FycmF5ID0gcmVxdWlyZShcIi4vdG9BcnJheVwiKTtcblxuLyoqXG4gKiBQZXJmb3JtIGEgaGV1cmlzdGljIHRlc3QgdG8gZGV0ZXJtaW5lIGlmIGFuIG9iamVjdCBpcyBcImFycmF5LWxpa2VcIi5cbiAqXG4gKiAgIEEgbW9uayBhc2tlZCBKb3NodSwgYSBaZW4gbWFzdGVyLCBcIkhhcyBhIGRvZyBCdWRkaGEgbmF0dXJlP1wiXG4gKiAgIEpvc2h1IHJlcGxpZWQ6IFwiTXUuXCJcbiAqXG4gKiBUaGlzIGZ1bmN0aW9uIGRldGVybWluZXMgaWYgaXRzIGFyZ3VtZW50IGhhcyBcImFycmF5IG5hdHVyZVwiOiBpdCByZXR1cm5zXG4gKiB0cnVlIGlmIHRoZSBhcmd1bWVudCBpcyBhbiBhY3R1YWwgYXJyYXksIGFuIGBhcmd1bWVudHMnIG9iamVjdCwgb3IgYW5cbiAqIEhUTUxDb2xsZWN0aW9uIChlLmcuIG5vZGUuY2hpbGROb2RlcyBvciBub2RlLmdldEVsZW1lbnRzQnlUYWdOYW1lKCkpLlxuICpcbiAqIEl0IHdpbGwgcmV0dXJuIGZhbHNlIGZvciBvdGhlciBhcnJheS1saWtlIG9iamVjdHMgbGlrZSBGaWxlbGlzdC5cbiAqXG4gKiBAcGFyYW0geyp9IG9ialxuICogQHJldHVybiB7Ym9vbGVhbn1cbiAqL1xuZnVuY3Rpb24gaGFzQXJyYXlOYXR1cmUob2JqKSB7XG4gIHJldHVybiAoXG4gICAgLy8gbm90IG51bGwvZmFsc2VcbiAgICAhIW9iaiAmJlxuICAgIC8vIGFycmF5cyBhcmUgb2JqZWN0cywgTm9kZUxpc3RzIGFyZSBmdW5jdGlvbnMgaW4gU2FmYXJpXG4gICAgKHR5cGVvZiBvYmogPT0gJ29iamVjdCcgfHwgdHlwZW9mIG9iaiA9PSAnZnVuY3Rpb24nKSAmJlxuICAgIC8vIHF1YWNrcyBsaWtlIGFuIGFycmF5XG4gICAgKCdsZW5ndGgnIGluIG9iaikgJiZcbiAgICAvLyBub3Qgd2luZG93XG4gICAgISgnc2V0SW50ZXJ2YWwnIGluIG9iaikgJiZcbiAgICAvLyBubyBET00gbm9kZSBzaG91bGQgYmUgY29uc2lkZXJlZCBhbiBhcnJheS1saWtlXG4gICAgLy8gYSAnc2VsZWN0JyBlbGVtZW50IGhhcyAnbGVuZ3RoJyBhbmQgJ2l0ZW0nIHByb3BlcnRpZXMgb24gSUU4XG4gICAgKHR5cGVvZiBvYmoubm9kZVR5cGUgIT0gJ251bWJlcicpICYmXG4gICAgKFxuICAgICAgLy8gYSByZWFsIGFycmF5XG4gICAgICAoLy8gSFRNTENvbGxlY3Rpb24vTm9kZUxpc3RcbiAgICAgIChBcnJheS5pc0FycmF5KG9iaikgfHxcbiAgICAgIC8vIGFyZ3VtZW50c1xuICAgICAgKCdjYWxsZWUnIGluIG9iaikgfHwgJ2l0ZW0nIGluIG9iaikpXG4gICAgKVxuICApO1xufVxuXG4vKipcbiAqIEVuc3VyZSB0aGF0IHRoZSBhcmd1bWVudCBpcyBhbiBhcnJheSBieSB3cmFwcGluZyBpdCBpbiBhbiBhcnJheSBpZiBpdCBpcyBub3QuXG4gKiBDcmVhdGVzIGEgY29weSBvZiB0aGUgYXJndW1lbnQgaWYgaXQgaXMgYWxyZWFkeSBhbiBhcnJheS5cbiAqXG4gKiBUaGlzIGlzIG1vc3RseSB1c2VmdWwgaWRpb21hdGljYWxseTpcbiAqXG4gKiAgIHZhciBjcmVhdGVBcnJheUZyb20gPSByZXF1aXJlKCdjcmVhdGVBcnJheUZyb20nKTtcbiAqXG4gKiAgIGZ1bmN0aW9uIHRha2VzT25lT3JNb3JlVGhpbmdzKHRoaW5ncykge1xuICogICAgIHRoaW5ncyA9IGNyZWF0ZUFycmF5RnJvbSh0aGluZ3MpO1xuICogICAgIC4uLlxuICogICB9XG4gKlxuICogVGhpcyBhbGxvd3MgeW91IHRvIHRyZWF0IGB0aGluZ3MnIGFzIGFuIGFycmF5LCBidXQgYWNjZXB0IHNjYWxhcnMgaW4gdGhlIEFQSS5cbiAqXG4gKiBJZiB5b3UgbmVlZCB0byBjb252ZXJ0IGFuIGFycmF5LWxpa2Ugb2JqZWN0LCBsaWtlIGBhcmd1bWVudHNgLCBpbnRvIGFuIGFycmF5XG4gKiB1c2UgdG9BcnJheSBpbnN0ZWFkLlxuICpcbiAqIEBwYXJhbSB7Kn0gb2JqXG4gKiBAcmV0dXJuIHthcnJheX1cbiAqL1xuZnVuY3Rpb24gY3JlYXRlQXJyYXlGcm9tKG9iaikge1xuICBpZiAoIWhhc0FycmF5TmF0dXJlKG9iaikpIHtcbiAgICByZXR1cm4gW29ial07XG4gIH0gZWxzZSBpZiAoQXJyYXkuaXNBcnJheShvYmopKSB7XG4gICAgcmV0dXJuIG9iai5zbGljZSgpO1xuICB9IGVsc2Uge1xuICAgIHJldHVybiB0b0FycmF5KG9iaik7XG4gIH1cbn1cblxubW9kdWxlLmV4cG9ydHMgPSBjcmVhdGVBcnJheUZyb207XG4iLCIoZnVuY3Rpb24gKHByb2Nlc3Mpe1xuLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIGNyZWF0ZUZ1bGxQYWdlQ29tcG9uZW50XG4gKiBAdHlwZWNoZWNrc1xuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG4vLyBEZWZlYXQgY2lyY3VsYXIgcmVmZXJlbmNlcyBieSByZXF1aXJpbmcgdGhpcyBkaXJlY3RseS5cbnZhciBSZWFjdENvbXBvc2l0ZUNvbXBvbmVudCA9IHJlcXVpcmUoXCIuL1JlYWN0Q29tcG9zaXRlQ29tcG9uZW50XCIpO1xudmFyIFJlYWN0RWxlbWVudCA9IHJlcXVpcmUoXCIuL1JlYWN0RWxlbWVudFwiKTtcblxudmFyIGludmFyaWFudCA9IHJlcXVpcmUoXCIuL2ludmFyaWFudFwiKTtcblxuLyoqXG4gKiBDcmVhdGUgYSBjb21wb25lbnQgdGhhdCB3aWxsIHRocm93IGFuIGV4Y2VwdGlvbiB3aGVuIHVubW91bnRlZC5cbiAqXG4gKiBDb21wb25lbnRzIGxpa2UgPGh0bWw+IDxoZWFkPiBhbmQgPGJvZHk+IGNhbid0IGJlIHJlbW92ZWQgb3IgYWRkZWRcbiAqIGVhc2lseSBpbiBhIGNyb3NzLWJyb3dzZXIgd2F5LCBob3dldmVyIGl0J3MgdmFsdWFibGUgdG8gYmUgYWJsZSB0b1xuICogdGFrZSBhZHZhbnRhZ2Ugb2YgUmVhY3QncyByZWNvbmNpbGlhdGlvbiBmb3Igc3R5bGluZyBhbmQgPHRpdGxlPlxuICogbWFuYWdlbWVudC4gU28gd2UganVzdCBkb2N1bWVudCBpdCBhbmQgdGhyb3cgaW4gZGFuZ2Vyb3VzIGNhc2VzLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSB0YWcgVGhlIHRhZyB0byB3cmFwXG4gKiBAcmV0dXJuIHtmdW5jdGlvbn0gY29udmVuaWVuY2UgY29uc3RydWN0b3Igb2YgbmV3IGNvbXBvbmVudFxuICovXG5mdW5jdGlvbiBjcmVhdGVGdWxsUGFnZUNvbXBvbmVudCh0YWcpIHtcbiAgdmFyIGVsZW1lbnRGYWN0b3J5ID0gUmVhY3RFbGVtZW50LmNyZWF0ZUZhY3RvcnkodGFnKTtcblxuICB2YXIgRnVsbFBhZ2VDb21wb25lbnQgPSBSZWFjdENvbXBvc2l0ZUNvbXBvbmVudC5jcmVhdGVDbGFzcyh7XG4gICAgZGlzcGxheU5hbWU6ICdSZWFjdEZ1bGxQYWdlQ29tcG9uZW50JyArIHRhZyxcblxuICAgIGNvbXBvbmVudFdpbGxVbm1vdW50OiBmdW5jdGlvbigpIHtcbiAgICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICAgIGZhbHNlLFxuICAgICAgICAnJXMgdHJpZWQgdG8gdW5tb3VudC4gQmVjYXVzZSBvZiBjcm9zcy1icm93c2VyIHF1aXJrcyBpdCBpcyAnICtcbiAgICAgICAgJ2ltcG9zc2libGUgdG8gdW5tb3VudCBzb21lIHRvcC1sZXZlbCBjb21wb25lbnRzIChlZyA8aHRtbD4sIDxoZWFkPiwgJyArXG4gICAgICAgICdhbmQgPGJvZHk+KSByZWxpYWJseSBhbmQgZWZmaWNpZW50bHkuIFRvIGZpeCB0aGlzLCBoYXZlIGEgc2luZ2xlICcgK1xuICAgICAgICAndG9wLWxldmVsIGNvbXBvbmVudCB0aGF0IG5ldmVyIHVubW91bnRzIHJlbmRlciB0aGVzZSBlbGVtZW50cy4nLFxuICAgICAgICB0aGlzLmNvbnN0cnVjdG9yLmRpc3BsYXlOYW1lXG4gICAgICApIDogaW52YXJpYW50KGZhbHNlKSk7XG4gICAgfSxcblxuICAgIHJlbmRlcjogZnVuY3Rpb24oKSB7XG4gICAgICByZXR1cm4gZWxlbWVudEZhY3RvcnkodGhpcy5wcm9wcyk7XG4gICAgfVxuICB9KTtcblxuICByZXR1cm4gRnVsbFBhZ2VDb21wb25lbnQ7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gY3JlYXRlRnVsbFBhZ2VDb21wb25lbnQ7XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKCdfcHJvY2VzcycpKSIsIihmdW5jdGlvbiAocHJvY2Vzcyl7XG4vKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgY3JlYXRlTm9kZXNGcm9tTWFya3VwXG4gKiBAdHlwZWNoZWNrc1xuICovXG5cbi8qanNsaW50IGV2aWw6IHRydWUsIHN1YjogdHJ1ZSAqL1xuXG52YXIgRXhlY3V0aW9uRW52aXJvbm1lbnQgPSByZXF1aXJlKFwiLi9FeGVjdXRpb25FbnZpcm9ubWVudFwiKTtcblxudmFyIGNyZWF0ZUFycmF5RnJvbSA9IHJlcXVpcmUoXCIuL2NyZWF0ZUFycmF5RnJvbVwiKTtcbnZhciBnZXRNYXJrdXBXcmFwID0gcmVxdWlyZShcIi4vZ2V0TWFya3VwV3JhcFwiKTtcbnZhciBpbnZhcmlhbnQgPSByZXF1aXJlKFwiLi9pbnZhcmlhbnRcIik7XG5cbi8qKlxuICogRHVtbXkgY29udGFpbmVyIHVzZWQgdG8gcmVuZGVyIGFsbCBtYXJrdXAuXG4gKi9cbnZhciBkdW1teU5vZGUgPVxuICBFeGVjdXRpb25FbnZpcm9ubWVudC5jYW5Vc2VET00gPyBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKSA6IG51bGw7XG5cbi8qKlxuICogUGF0dGVybiB1c2VkIGJ5IGBnZXROb2RlTmFtZWAuXG4gKi9cbnZhciBub2RlTmFtZVBhdHRlcm4gPSAvXlxccyo8KFxcdyspLztcblxuLyoqXG4gKiBFeHRyYWN0cyB0aGUgYG5vZGVOYW1lYCBvZiB0aGUgZmlyc3QgZWxlbWVudCBpbiBhIHN0cmluZyBvZiBtYXJrdXAuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IG1hcmt1cCBTdHJpbmcgb2YgbWFya3VwLlxuICogQHJldHVybiB7P3N0cmluZ30gTm9kZSBuYW1lIG9mIHRoZSBzdXBwbGllZCBtYXJrdXAuXG4gKi9cbmZ1bmN0aW9uIGdldE5vZGVOYW1lKG1hcmt1cCkge1xuICB2YXIgbm9kZU5hbWVNYXRjaCA9IG1hcmt1cC5tYXRjaChub2RlTmFtZVBhdHRlcm4pO1xuICByZXR1cm4gbm9kZU5hbWVNYXRjaCAmJiBub2RlTmFtZU1hdGNoWzFdLnRvTG93ZXJDYXNlKCk7XG59XG5cbi8qKlxuICogQ3JlYXRlcyBhbiBhcnJheSBjb250YWluaW5nIHRoZSBub2RlcyByZW5kZXJlZCBmcm9tIHRoZSBzdXBwbGllZCBtYXJrdXAuIFRoZVxuICogb3B0aW9uYWxseSBzdXBwbGllZCBgaGFuZGxlU2NyaXB0YCBmdW5jdGlvbiB3aWxsIGJlIGludm9rZWQgb25jZSBmb3IgZWFjaFxuICogPHNjcmlwdD4gZWxlbWVudCB0aGF0IGlzIHJlbmRlcmVkLiBJZiBubyBgaGFuZGxlU2NyaXB0YCBmdW5jdGlvbiBpcyBzdXBwbGllZCxcbiAqIGFuIGV4Y2VwdGlvbiBpcyB0aHJvd24gaWYgYW55IDxzY3JpcHQ+IGVsZW1lbnRzIGFyZSByZW5kZXJlZC5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gbWFya3VwIEEgc3RyaW5nIG9mIHZhbGlkIEhUTUwgbWFya3VwLlxuICogQHBhcmFtIHs/ZnVuY3Rpb259IGhhbmRsZVNjcmlwdCBJbnZva2VkIG9uY2UgZm9yIGVhY2ggcmVuZGVyZWQgPHNjcmlwdD4uXG4gKiBAcmV0dXJuIHthcnJheTxET01FbGVtZW50fERPTVRleHROb2RlPn0gQW4gYXJyYXkgb2YgcmVuZGVyZWQgbm9kZXMuXG4gKi9cbmZ1bmN0aW9uIGNyZWF0ZU5vZGVzRnJvbU1hcmt1cChtYXJrdXAsIGhhbmRsZVNjcmlwdCkge1xuICB2YXIgbm9kZSA9IGR1bW15Tm9kZTtcbiAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudCghIWR1bW15Tm9kZSwgJ2NyZWF0ZU5vZGVzRnJvbU1hcmt1cCBkdW1teSBub3QgaW5pdGlhbGl6ZWQnKSA6IGludmFyaWFudCghIWR1bW15Tm9kZSkpO1xuICB2YXIgbm9kZU5hbWUgPSBnZXROb2RlTmFtZShtYXJrdXApO1xuXG4gIHZhciB3cmFwID0gbm9kZU5hbWUgJiYgZ2V0TWFya3VwV3JhcChub2RlTmFtZSk7XG4gIGlmICh3cmFwKSB7XG4gICAgbm9kZS5pbm5lckhUTUwgPSB3cmFwWzFdICsgbWFya3VwICsgd3JhcFsyXTtcblxuICAgIHZhciB3cmFwRGVwdGggPSB3cmFwWzBdO1xuICAgIHdoaWxlICh3cmFwRGVwdGgtLSkge1xuICAgICAgbm9kZSA9IG5vZGUubGFzdENoaWxkO1xuICAgIH1cbiAgfSBlbHNlIHtcbiAgICBub2RlLmlubmVySFRNTCA9IG1hcmt1cDtcbiAgfVxuXG4gIHZhciBzY3JpcHRzID0gbm9kZS5nZXRFbGVtZW50c0J5VGFnTmFtZSgnc2NyaXB0Jyk7XG4gIGlmIChzY3JpcHRzLmxlbmd0aCkge1xuICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgICBoYW5kbGVTY3JpcHQsXG4gICAgICAnY3JlYXRlTm9kZXNGcm9tTWFya3VwKC4uLik6IFVuZXhwZWN0ZWQgPHNjcmlwdD4gZWxlbWVudCByZW5kZXJlZC4nXG4gICAgKSA6IGludmFyaWFudChoYW5kbGVTY3JpcHQpKTtcbiAgICBjcmVhdGVBcnJheUZyb20oc2NyaXB0cykuZm9yRWFjaChoYW5kbGVTY3JpcHQpO1xuICB9XG5cbiAgdmFyIG5vZGVzID0gY3JlYXRlQXJyYXlGcm9tKG5vZGUuY2hpbGROb2Rlcyk7XG4gIHdoaWxlIChub2RlLmxhc3RDaGlsZCkge1xuICAgIG5vZGUucmVtb3ZlQ2hpbGQobm9kZS5sYXN0Q2hpbGQpO1xuICB9XG4gIHJldHVybiBub2Rlcztcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBjcmVhdGVOb2Rlc0Zyb21NYXJrdXA7XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKCdfcHJvY2VzcycpKSIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBkYW5nZXJvdXNTdHlsZVZhbHVlXG4gKiBAdHlwZWNoZWNrcyBzdGF0aWMtb25seVxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgQ1NTUHJvcGVydHkgPSByZXF1aXJlKFwiLi9DU1NQcm9wZXJ0eVwiKTtcblxudmFyIGlzVW5pdGxlc3NOdW1iZXIgPSBDU1NQcm9wZXJ0eS5pc1VuaXRsZXNzTnVtYmVyO1xuXG4vKipcbiAqIENvbnZlcnQgYSB2YWx1ZSBpbnRvIHRoZSBwcm9wZXIgY3NzIHdyaXRhYmxlIHZhbHVlLiBUaGUgc3R5bGUgbmFtZSBgbmFtZWBcbiAqIHNob3VsZCBiZSBsb2dpY2FsIChubyBoeXBoZW5zKSwgYXMgc3BlY2lmaWVkXG4gKiBpbiBgQ1NTUHJvcGVydHkuaXNVbml0bGVzc051bWJlcmAuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IG5hbWUgQ1NTIHByb3BlcnR5IG5hbWUgc3VjaCBhcyBgdG9wTWFyZ2luYC5cbiAqIEBwYXJhbSB7Kn0gdmFsdWUgQ1NTIHByb3BlcnR5IHZhbHVlIHN1Y2ggYXMgYDEwcHhgLlxuICogQHJldHVybiB7c3RyaW5nfSBOb3JtYWxpemVkIHN0eWxlIHZhbHVlIHdpdGggZGltZW5zaW9ucyBhcHBsaWVkLlxuICovXG5mdW5jdGlvbiBkYW5nZXJvdXNTdHlsZVZhbHVlKG5hbWUsIHZhbHVlKSB7XG4gIC8vIE5vdGUgdGhhdCB3ZSd2ZSByZW1vdmVkIGVzY2FwZVRleHRGb3JCcm93c2VyKCkgY2FsbHMgaGVyZSBzaW5jZSB0aGVcbiAgLy8gd2hvbGUgc3RyaW5nIHdpbGwgYmUgZXNjYXBlZCB3aGVuIHRoZSBhdHRyaWJ1dGUgaXMgaW5qZWN0ZWQgaW50b1xuICAvLyB0aGUgbWFya3VwLiBJZiB5b3UgcHJvdmlkZSB1bnNhZmUgdXNlciBkYXRhIGhlcmUgdGhleSBjYW4gaW5qZWN0XG4gIC8vIGFyYml0cmFyeSBDU1Mgd2hpY2ggbWF5IGJlIHByb2JsZW1hdGljIChJIGNvdWxkbid0IHJlcHJvIHRoaXMpOlxuICAvLyBodHRwczovL3d3dy5vd2FzcC5vcmcvaW5kZXgucGhwL1hTU19GaWx0ZXJfRXZhc2lvbl9DaGVhdF9TaGVldFxuICAvLyBodHRwOi8vd3d3LnRoZXNwYW5uZXIuY28udWsvMjAwNy8xMS8yNi91bHRpbWF0ZS14c3MtY3NzLWluamVjdGlvbi9cbiAgLy8gVGhpcyBpcyBub3QgYW4gWFNTIGhvbGUgYnV0IGluc3RlYWQgYSBwb3RlbnRpYWwgQ1NTIGluamVjdGlvbiBpc3N1ZVxuICAvLyB3aGljaCBoYXMgbGVhZCB0byBhIGdyZWF0ZXIgZGlzY3Vzc2lvbiBhYm91dCBob3cgd2UncmUgZ29pbmcgdG9cbiAgLy8gdHJ1c3QgVVJMcyBtb3ZpbmcgZm9yd2FyZC4gU2VlICMyMTE1OTAxXG5cbiAgdmFyIGlzRW1wdHkgPSB2YWx1ZSA9PSBudWxsIHx8IHR5cGVvZiB2YWx1ZSA9PT0gJ2Jvb2xlYW4nIHx8IHZhbHVlID09PSAnJztcbiAgaWYgKGlzRW1wdHkpIHtcbiAgICByZXR1cm4gJyc7XG4gIH1cblxuICB2YXIgaXNOb25OdW1lcmljID0gaXNOYU4odmFsdWUpO1xuICBpZiAoaXNOb25OdW1lcmljIHx8IHZhbHVlID09PSAwIHx8XG4gICAgICBpc1VuaXRsZXNzTnVtYmVyLmhhc093blByb3BlcnR5KG5hbWUpICYmIGlzVW5pdGxlc3NOdW1iZXJbbmFtZV0pIHtcbiAgICByZXR1cm4gJycgKyB2YWx1ZTsgLy8gY2FzdCB0byBzdHJpbmdcbiAgfVxuXG4gIGlmICh0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnKSB7XG4gICAgdmFsdWUgPSB2YWx1ZS50cmltKCk7XG4gIH1cbiAgcmV0dXJuIHZhbHVlICsgJ3B4Jztcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBkYW5nZXJvdXNTdHlsZVZhbHVlO1xuIiwiKGZ1bmN0aW9uIChwcm9jZXNzKXtcbi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBkZXByZWNhdGVkXG4gKi9cblxudmFyIGFzc2lnbiA9IHJlcXVpcmUoXCIuL09iamVjdC5hc3NpZ25cIik7XG52YXIgd2FybmluZyA9IHJlcXVpcmUoXCIuL3dhcm5pbmdcIik7XG5cbi8qKlxuICogVGhpcyB3aWxsIGxvZyBhIHNpbmdsZSBkZXByZWNhdGlvbiBub3RpY2UgcGVyIGZ1bmN0aW9uIGFuZCBmb3J3YXJkIHRoZSBjYWxsXG4gKiBvbiB0byB0aGUgbmV3IEFQSS5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gbmFtZXNwYWNlIFRoZSBuYW1lc3BhY2Ugb2YgdGhlIGNhbGwsIGVnICdSZWFjdCdcbiAqIEBwYXJhbSB7c3RyaW5nfSBvbGROYW1lIFRoZSBvbGQgZnVuY3Rpb24gbmFtZSwgZWcgJ3JlbmRlckNvbXBvbmVudCdcbiAqIEBwYXJhbSB7c3RyaW5nfSBuZXdOYW1lIFRoZSBuZXcgZnVuY3Rpb24gbmFtZSwgZWcgJ3JlbmRlcidcbiAqIEBwYXJhbSB7Kn0gY3R4IFRoZSBjb250ZXh0IHRoaXMgZm9yd2FyZGVkIGNhbGwgc2hvdWxkIHJ1biBpblxuICogQHBhcmFtIHtmdW5jdGlvbn0gZm4gVGhlIGZ1bmN0aW9uIHRvIGZvcndhcmQgb24gdG9cbiAqIEByZXR1cm4geyp9IFdpbGwgYmUgdGhlIHZhbHVlIGFzIHJldHVybmVkIGZyb20gYGZuYFxuICovXG5mdW5jdGlvbiBkZXByZWNhdGVkKG5hbWVzcGFjZSwgb2xkTmFtZSwgbmV3TmFtZSwgY3R4LCBmbikge1xuICB2YXIgd2FybmVkID0gZmFsc2U7XG4gIGlmIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYpIHtcbiAgICB2YXIgbmV3Rm4gPSBmdW5jdGlvbigpIHtcbiAgICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyB3YXJuaW5nKFxuICAgICAgICB3YXJuZWQsXG4gICAgICAgIChuYW1lc3BhY2UgKyBcIi5cIiArIG9sZE5hbWUgKyBcIiB3aWxsIGJlIGRlcHJlY2F0ZWQgaW4gYSBmdXR1cmUgdmVyc2lvbi4gXCIpICtcbiAgICAgICAgKFwiVXNlIFwiICsgbmFtZXNwYWNlICsgXCIuXCIgKyBuZXdOYW1lICsgXCIgaW5zdGVhZC5cIilcbiAgICAgICkgOiBudWxsKTtcbiAgICAgIHdhcm5lZCA9IHRydWU7XG4gICAgICByZXR1cm4gZm4uYXBwbHkoY3R4LCBhcmd1bWVudHMpO1xuICAgIH07XG4gICAgbmV3Rm4uZGlzcGxheU5hbWUgPSAobmFtZXNwYWNlICsgXCJfXCIgKyBvbGROYW1lKTtcbiAgICAvLyBXZSBuZWVkIHRvIG1ha2Ugc3VyZSBhbGwgcHJvcGVydGllcyBvZiB0aGUgb3JpZ2luYWwgZm4gYXJlIGNvcGllZCBvdmVyLlxuICAgIC8vIEluIHBhcnRpY3VsYXIsIHRoaXMgaXMgbmVlZGVkIHRvIHN1cHBvcnQgUHJvcFR5cGVzXG4gICAgcmV0dXJuIGFzc2lnbihuZXdGbiwgZm4pO1xuICB9XG5cbiAgcmV0dXJuIGZuO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGRlcHJlY2F0ZWQ7XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKCdfcHJvY2VzcycpKSIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBlbXB0eUZ1bmN0aW9uXG4gKi9cblxuZnVuY3Rpb24gbWFrZUVtcHR5RnVuY3Rpb24oYXJnKSB7XG4gIHJldHVybiBmdW5jdGlvbigpIHtcbiAgICByZXR1cm4gYXJnO1xuICB9O1xufVxuXG4vKipcbiAqIFRoaXMgZnVuY3Rpb24gYWNjZXB0cyBhbmQgZGlzY2FyZHMgaW5wdXRzOyBpdCBoYXMgbm8gc2lkZSBlZmZlY3RzLiBUaGlzIGlzXG4gKiBwcmltYXJpbHkgdXNlZnVsIGlkaW9tYXRpY2FsbHkgZm9yIG92ZXJyaWRhYmxlIGZ1bmN0aW9uIGVuZHBvaW50cyB3aGljaFxuICogYWx3YXlzIG5lZWQgdG8gYmUgY2FsbGFibGUsIHNpbmNlIEpTIGxhY2tzIGEgbnVsbC1jYWxsIGlkaW9tIGFsYSBDb2NvYS5cbiAqL1xuZnVuY3Rpb24gZW1wdHlGdW5jdGlvbigpIHt9XG5cbmVtcHR5RnVuY3Rpb24udGhhdFJldHVybnMgPSBtYWtlRW1wdHlGdW5jdGlvbjtcbmVtcHR5RnVuY3Rpb24udGhhdFJldHVybnNGYWxzZSA9IG1ha2VFbXB0eUZ1bmN0aW9uKGZhbHNlKTtcbmVtcHR5RnVuY3Rpb24udGhhdFJldHVybnNUcnVlID0gbWFrZUVtcHR5RnVuY3Rpb24odHJ1ZSk7XG5lbXB0eUZ1bmN0aW9uLnRoYXRSZXR1cm5zTnVsbCA9IG1ha2VFbXB0eUZ1bmN0aW9uKG51bGwpO1xuZW1wdHlGdW5jdGlvbi50aGF0UmV0dXJuc1RoaXMgPSBmdW5jdGlvbigpIHsgcmV0dXJuIHRoaXM7IH07XG5lbXB0eUZ1bmN0aW9uLnRoYXRSZXR1cm5zQXJndW1lbnQgPSBmdW5jdGlvbihhcmcpIHsgcmV0dXJuIGFyZzsgfTtcblxubW9kdWxlLmV4cG9ydHMgPSBlbXB0eUZ1bmN0aW9uO1xuIiwiKGZ1bmN0aW9uIChwcm9jZXNzKXtcbi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBlbXB0eU9iamVjdFxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgZW1wdHlPYmplY3QgPSB7fTtcblxuaWYgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOVikge1xuICBPYmplY3QuZnJlZXplKGVtcHR5T2JqZWN0KTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBlbXB0eU9iamVjdDtcblxufSkuY2FsbCh0aGlzLHJlcXVpcmUoJ19wcm9jZXNzJykpIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIGVzY2FwZVRleHRGb3JCcm93c2VyXG4gKiBAdHlwZWNoZWNrcyBzdGF0aWMtb25seVxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgRVNDQVBFX0xPT0tVUCA9IHtcbiAgXCImXCI6IFwiJmFtcDtcIixcbiAgXCI+XCI6IFwiJmd0O1wiLFxuICBcIjxcIjogXCImbHQ7XCIsXG4gIFwiXFxcIlwiOiBcIiZxdW90O1wiLFxuICBcIidcIjogXCImI3gyNztcIlxufTtcblxudmFyIEVTQ0FQRV9SRUdFWCA9IC9bJj48XCInXS9nO1xuXG5mdW5jdGlvbiBlc2NhcGVyKG1hdGNoKSB7XG4gIHJldHVybiBFU0NBUEVfTE9PS1VQW21hdGNoXTtcbn1cblxuLyoqXG4gKiBFc2NhcGVzIHRleHQgdG8gcHJldmVudCBzY3JpcHRpbmcgYXR0YWNrcy5cbiAqXG4gKiBAcGFyYW0geyp9IHRleHQgVGV4dCB2YWx1ZSB0byBlc2NhcGUuXG4gKiBAcmV0dXJuIHtzdHJpbmd9IEFuIGVzY2FwZWQgc3RyaW5nLlxuICovXG5mdW5jdGlvbiBlc2NhcGVUZXh0Rm9yQnJvd3Nlcih0ZXh0KSB7XG4gIHJldHVybiAoJycgKyB0ZXh0KS5yZXBsYWNlKEVTQ0FQRV9SRUdFWCwgZXNjYXBlcik7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gZXNjYXBlVGV4dEZvckJyb3dzZXI7XG4iLCIoZnVuY3Rpb24gKHByb2Nlc3Mpe1xuLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIGZsYXR0ZW5DaGlsZHJlblxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgUmVhY3RUZXh0Q29tcG9uZW50ID0gcmVxdWlyZShcIi4vUmVhY3RUZXh0Q29tcG9uZW50XCIpO1xuXG52YXIgdHJhdmVyc2VBbGxDaGlsZHJlbiA9IHJlcXVpcmUoXCIuL3RyYXZlcnNlQWxsQ2hpbGRyZW5cIik7XG52YXIgd2FybmluZyA9IHJlcXVpcmUoXCIuL3dhcm5pbmdcIik7XG5cbi8qKlxuICogQHBhcmFtIHtmdW5jdGlvbn0gdHJhdmVyc2VDb250ZXh0IENvbnRleHQgcGFzc2VkIHRocm91Z2ggdHJhdmVyc2FsLlxuICogQHBhcmFtIHs/UmVhY3RDb21wb25lbnR9IGNoaWxkIFJlYWN0IGNoaWxkIGNvbXBvbmVudC5cbiAqIEBwYXJhbSB7IXN0cmluZ30gbmFtZSBTdHJpbmcgbmFtZSBvZiBrZXkgcGF0aCB0byBjaGlsZC5cbiAqL1xuZnVuY3Rpb24gZmxhdHRlblNpbmdsZUNoaWxkSW50b0NvbnRleHQodHJhdmVyc2VDb250ZXh0LCBjaGlsZCwgbmFtZSkge1xuICAvLyBXZSBmb3VuZCBhIGNvbXBvbmVudCBpbnN0YW5jZS5cbiAgdmFyIHJlc3VsdCA9IHRyYXZlcnNlQ29udGV4dDtcbiAgdmFyIGtleVVuaXF1ZSA9ICFyZXN1bHQuaGFzT3duUHJvcGVydHkobmFtZSk7XG4gIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyB3YXJuaW5nKFxuICAgIGtleVVuaXF1ZSxcbiAgICAnZmxhdHRlbkNoaWxkcmVuKC4uLik6IEVuY291bnRlcmVkIHR3byBjaGlsZHJlbiB3aXRoIHRoZSBzYW1lIGtleSwgJyArXG4gICAgJ2Alc2AuIENoaWxkIGtleXMgbXVzdCBiZSB1bmlxdWU7IHdoZW4gdHdvIGNoaWxkcmVuIHNoYXJlIGEga2V5LCBvbmx5ICcgK1xuICAgICd0aGUgZmlyc3QgY2hpbGQgd2lsbCBiZSB1c2VkLicsXG4gICAgbmFtZVxuICApIDogbnVsbCk7XG4gIGlmIChrZXlVbmlxdWUgJiYgY2hpbGQgIT0gbnVsbCkge1xuICAgIHZhciB0eXBlID0gdHlwZW9mIGNoaWxkO1xuICAgIHZhciBub3JtYWxpemVkVmFsdWU7XG5cbiAgICBpZiAodHlwZSA9PT0gJ3N0cmluZycpIHtcbiAgICAgIG5vcm1hbGl6ZWRWYWx1ZSA9IFJlYWN0VGV4dENvbXBvbmVudChjaGlsZCk7XG4gICAgfSBlbHNlIGlmICh0eXBlID09PSAnbnVtYmVyJykge1xuICAgICAgbm9ybWFsaXplZFZhbHVlID0gUmVhY3RUZXh0Q29tcG9uZW50KCcnICsgY2hpbGQpO1xuICAgIH0gZWxzZSB7XG4gICAgICBub3JtYWxpemVkVmFsdWUgPSBjaGlsZDtcbiAgICB9XG5cbiAgICByZXN1bHRbbmFtZV0gPSBub3JtYWxpemVkVmFsdWU7XG4gIH1cbn1cblxuLyoqXG4gKiBGbGF0dGVucyBjaGlsZHJlbiB0aGF0IGFyZSB0eXBpY2FsbHkgc3BlY2lmaWVkIGFzIGBwcm9wcy5jaGlsZHJlbmAuIEFueSBudWxsXG4gKiBjaGlsZHJlbiB3aWxsIG5vdCBiZSBpbmNsdWRlZCBpbiB0aGUgcmVzdWx0aW5nIG9iamVjdC5cbiAqIEByZXR1cm4geyFvYmplY3R9IGZsYXR0ZW5lZCBjaGlsZHJlbiBrZXllZCBieSBuYW1lLlxuICovXG5mdW5jdGlvbiBmbGF0dGVuQ2hpbGRyZW4oY2hpbGRyZW4pIHtcbiAgaWYgKGNoaWxkcmVuID09IG51bGwpIHtcbiAgICByZXR1cm4gY2hpbGRyZW47XG4gIH1cbiAgdmFyIHJlc3VsdCA9IHt9O1xuICB0cmF2ZXJzZUFsbENoaWxkcmVuKGNoaWxkcmVuLCBmbGF0dGVuU2luZ2xlQ2hpbGRJbnRvQ29udGV4dCwgcmVzdWx0KTtcbiAgcmV0dXJuIHJlc3VsdDtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBmbGF0dGVuQ2hpbGRyZW47XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKCdfcHJvY2VzcycpKSIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgZm9jdXNOb2RlXG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbi8qKlxuICogQHBhcmFtIHtET01FbGVtZW50fSBub2RlIGlucHV0L3RleHRhcmVhIHRvIGZvY3VzXG4gKi9cbmZ1bmN0aW9uIGZvY3VzTm9kZShub2RlKSB7XG4gIC8vIElFOCBjYW4gdGhyb3cgXCJDYW4ndCBtb3ZlIGZvY3VzIHRvIHRoZSBjb250cm9sIGJlY2F1c2UgaXQgaXMgaW52aXNpYmxlLFxuICAvLyBub3QgZW5hYmxlZCwgb3Igb2YgYSB0eXBlIHRoYXQgZG9lcyBub3QgYWNjZXB0IHRoZSBmb2N1cy5cIiBmb3IgYWxsIGtpbmRzIG9mXG4gIC8vIHJlYXNvbnMgdGhhdCBhcmUgdG9vIGV4cGVuc2l2ZSBhbmQgZnJhZ2lsZSB0byB0ZXN0LlxuICB0cnkge1xuICAgIG5vZGUuZm9jdXMoKTtcbiAgfSBjYXRjaChlKSB7XG4gIH1cbn1cblxubW9kdWxlLmV4cG9ydHMgPSBmb2N1c05vZGU7XG4iLCIvKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgZm9yRWFjaEFjY3VtdWxhdGVkXG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbi8qKlxuICogQHBhcmFtIHthcnJheX0gYW4gXCJhY2N1bXVsYXRpb25cIiBvZiBpdGVtcyB3aGljaCBpcyBlaXRoZXIgYW4gQXJyYXkgb3JcbiAqIGEgc2luZ2xlIGl0ZW0uIFVzZWZ1bCB3aGVuIHBhaXJlZCB3aXRoIHRoZSBgYWNjdW11bGF0ZWAgbW9kdWxlLiBUaGlzIGlzIGFcbiAqIHNpbXBsZSB1dGlsaXR5IHRoYXQgYWxsb3dzIHVzIHRvIHJlYXNvbiBhYm91dCBhIGNvbGxlY3Rpb24gb2YgaXRlbXMsIGJ1dFxuICogaGFuZGxpbmcgdGhlIGNhc2Ugd2hlbiB0aGVyZSBpcyBleGFjdGx5IG9uZSBpdGVtIChhbmQgd2UgZG8gbm90IG5lZWQgdG9cbiAqIGFsbG9jYXRlIGFuIGFycmF5KS5cbiAqL1xudmFyIGZvckVhY2hBY2N1bXVsYXRlZCA9IGZ1bmN0aW9uKGFyciwgY2IsIHNjb3BlKSB7XG4gIGlmIChBcnJheS5pc0FycmF5KGFycikpIHtcbiAgICBhcnIuZm9yRWFjaChjYiwgc2NvcGUpO1xuICB9IGVsc2UgaWYgKGFycikge1xuICAgIGNiLmNhbGwoc2NvcGUsIGFycik7XG4gIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gZm9yRWFjaEFjY3VtdWxhdGVkO1xuIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIGdldEFjdGl2ZUVsZW1lbnRcbiAqIEB0eXBlY2hlY2tzXG4gKi9cblxuLyoqXG4gKiBTYW1lIGFzIGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQgYnV0IHdyYXBzIGluIGEgdHJ5LWNhdGNoIGJsb2NrLiBJbiBJRSBpdCBpc1xuICogbm90IHNhZmUgdG8gY2FsbCBkb2N1bWVudC5hY3RpdmVFbGVtZW50IGlmIHRoZXJlIGlzIG5vdGhpbmcgZm9jdXNlZC5cbiAqXG4gKiBUaGUgYWN0aXZlRWxlbWVudCB3aWxsIGJlIG51bGwgb25seSBpZiB0aGUgZG9jdW1lbnQgYm9keSBpcyBub3QgeWV0IGRlZmluZWQuXG4gKi9cbmZ1bmN0aW9uIGdldEFjdGl2ZUVsZW1lbnQoKSAvKj9ET01FbGVtZW50Ki8ge1xuICB0cnkge1xuICAgIHJldHVybiBkb2N1bWVudC5hY3RpdmVFbGVtZW50IHx8IGRvY3VtZW50LmJvZHk7XG4gIH0gY2F0Y2ggKGUpIHtcbiAgICByZXR1cm4gZG9jdW1lbnQuYm9keTtcbiAgfVxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGdldEFjdGl2ZUVsZW1lbnQ7XG4iLCIvKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgZ2V0RXZlbnRDaGFyQ29kZVxuICogQHR5cGVjaGVja3Mgc3RhdGljLW9ubHlcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxuLyoqXG4gKiBgY2hhckNvZGVgIHJlcHJlc2VudHMgdGhlIGFjdHVhbCBcImNoYXJhY3RlciBjb2RlXCIgYW5kIGlzIHNhZmUgdG8gdXNlIHdpdGhcbiAqIGBTdHJpbmcuZnJvbUNoYXJDb2RlYC4gQXMgc3VjaCwgb25seSBrZXlzIHRoYXQgY29ycmVzcG9uZCB0byBwcmludGFibGVcbiAqIGNoYXJhY3RlcnMgcHJvZHVjZSBhIHZhbGlkIGBjaGFyQ29kZWAsIHRoZSBvbmx5IGV4Y2VwdGlvbiB0byB0aGlzIGlzIEVudGVyLlxuICogVGhlIFRhYi1rZXkgaXMgY29uc2lkZXJlZCBub24tcHJpbnRhYmxlIGFuZCBkb2VzIG5vdCBoYXZlIGEgYGNoYXJDb2RlYCxcbiAqIHByZXN1bWFibHkgYmVjYXVzZSBpdCBkb2VzIG5vdCBwcm9kdWNlIGEgdGFiLWNoYXJhY3RlciBpbiBicm93c2Vycy5cbiAqXG4gKiBAcGFyYW0ge29iamVjdH0gbmF0aXZlRXZlbnQgTmF0aXZlIGJyb3dzZXIgZXZlbnQuXG4gKiBAcmV0dXJuIHtzdHJpbmd9IE5vcm1hbGl6ZWQgYGNoYXJDb2RlYCBwcm9wZXJ0eS5cbiAqL1xuZnVuY3Rpb24gZ2V0RXZlbnRDaGFyQ29kZShuYXRpdmVFdmVudCkge1xuICB2YXIgY2hhckNvZGU7XG4gIHZhciBrZXlDb2RlID0gbmF0aXZlRXZlbnQua2V5Q29kZTtcblxuICBpZiAoJ2NoYXJDb2RlJyBpbiBuYXRpdmVFdmVudCkge1xuICAgIGNoYXJDb2RlID0gbmF0aXZlRXZlbnQuY2hhckNvZGU7XG5cbiAgICAvLyBGRiBkb2VzIG5vdCBzZXQgYGNoYXJDb2RlYCBmb3IgdGhlIEVudGVyLWtleSwgY2hlY2sgYWdhaW5zdCBga2V5Q29kZWAuXG4gICAgaWYgKGNoYXJDb2RlID09PSAwICYmIGtleUNvZGUgPT09IDEzKSB7XG4gICAgICBjaGFyQ29kZSA9IDEzO1xuICAgIH1cbiAgfSBlbHNlIHtcbiAgICAvLyBJRTggZG9lcyBub3QgaW1wbGVtZW50IGBjaGFyQ29kZWAsIGJ1dCBga2V5Q29kZWAgaGFzIHRoZSBjb3JyZWN0IHZhbHVlLlxuICAgIGNoYXJDb2RlID0ga2V5Q29kZTtcbiAgfVxuXG4gIC8vIFNvbWUgbm9uLXByaW50YWJsZSBrZXlzIGFyZSByZXBvcnRlZCBpbiBgY2hhckNvZGVgL2BrZXlDb2RlYCwgZGlzY2FyZCB0aGVtLlxuICAvLyBNdXN0IG5vdCBkaXNjYXJkIHRoZSAobm9uLSlwcmludGFibGUgRW50ZXIta2V5LlxuICBpZiAoY2hhckNvZGUgPj0gMzIgfHwgY2hhckNvZGUgPT09IDEzKSB7XG4gICAgcmV0dXJuIGNoYXJDb2RlO1xuICB9XG5cbiAgcmV0dXJuIDA7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gZ2V0RXZlbnRDaGFyQ29kZTtcbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBnZXRFdmVudEtleVxuICogQHR5cGVjaGVja3Mgc3RhdGljLW9ubHlcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIGdldEV2ZW50Q2hhckNvZGUgPSByZXF1aXJlKFwiLi9nZXRFdmVudENoYXJDb2RlXCIpO1xuXG4vKipcbiAqIE5vcm1hbGl6YXRpb24gb2YgZGVwcmVjYXRlZCBIVE1MNSBga2V5YCB2YWx1ZXNcbiAqIEBzZWUgaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvQVBJL0tleWJvYXJkRXZlbnQjS2V5X25hbWVzXG4gKi9cbnZhciBub3JtYWxpemVLZXkgPSB7XG4gICdFc2MnOiAnRXNjYXBlJyxcbiAgJ1NwYWNlYmFyJzogJyAnLFxuICAnTGVmdCc6ICdBcnJvd0xlZnQnLFxuICAnVXAnOiAnQXJyb3dVcCcsXG4gICdSaWdodCc6ICdBcnJvd1JpZ2h0JyxcbiAgJ0Rvd24nOiAnQXJyb3dEb3duJyxcbiAgJ0RlbCc6ICdEZWxldGUnLFxuICAnV2luJzogJ09TJyxcbiAgJ01lbnUnOiAnQ29udGV4dE1lbnUnLFxuICAnQXBwcyc6ICdDb250ZXh0TWVudScsXG4gICdTY3JvbGwnOiAnU2Nyb2xsTG9jaycsXG4gICdNb3pQcmludGFibGVLZXknOiAnVW5pZGVudGlmaWVkJ1xufTtcblxuLyoqXG4gKiBUcmFuc2xhdGlvbiBmcm9tIGxlZ2FjeSBga2V5Q29kZWAgdG8gSFRNTDUgYGtleWBcbiAqIE9ubHkgc3BlY2lhbCBrZXlzIHN1cHBvcnRlZCwgYWxsIG90aGVycyBkZXBlbmQgb24ga2V5Ym9hcmQgbGF5b3V0IG9yIGJyb3dzZXJcbiAqIEBzZWUgaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvQVBJL0tleWJvYXJkRXZlbnQjS2V5X25hbWVzXG4gKi9cbnZhciB0cmFuc2xhdGVUb0tleSA9IHtcbiAgODogJ0JhY2tzcGFjZScsXG4gIDk6ICdUYWInLFxuICAxMjogJ0NsZWFyJyxcbiAgMTM6ICdFbnRlcicsXG4gIDE2OiAnU2hpZnQnLFxuICAxNzogJ0NvbnRyb2wnLFxuICAxODogJ0FsdCcsXG4gIDE5OiAnUGF1c2UnLFxuICAyMDogJ0NhcHNMb2NrJyxcbiAgMjc6ICdFc2NhcGUnLFxuICAzMjogJyAnLFxuICAzMzogJ1BhZ2VVcCcsXG4gIDM0OiAnUGFnZURvd24nLFxuICAzNTogJ0VuZCcsXG4gIDM2OiAnSG9tZScsXG4gIDM3OiAnQXJyb3dMZWZ0JyxcbiAgMzg6ICdBcnJvd1VwJyxcbiAgMzk6ICdBcnJvd1JpZ2h0JyxcbiAgNDA6ICdBcnJvd0Rvd24nLFxuICA0NTogJ0luc2VydCcsXG4gIDQ2OiAnRGVsZXRlJyxcbiAgMTEyOiAnRjEnLCAxMTM6ICdGMicsIDExNDogJ0YzJywgMTE1OiAnRjQnLCAxMTY6ICdGNScsIDExNzogJ0Y2JyxcbiAgMTE4OiAnRjcnLCAxMTk6ICdGOCcsIDEyMDogJ0Y5JywgMTIxOiAnRjEwJywgMTIyOiAnRjExJywgMTIzOiAnRjEyJyxcbiAgMTQ0OiAnTnVtTG9jaycsXG4gIDE0NTogJ1Njcm9sbExvY2snLFxuICAyMjQ6ICdNZXRhJ1xufTtcblxuLyoqXG4gKiBAcGFyYW0ge29iamVjdH0gbmF0aXZlRXZlbnQgTmF0aXZlIGJyb3dzZXIgZXZlbnQuXG4gKiBAcmV0dXJuIHtzdHJpbmd9IE5vcm1hbGl6ZWQgYGtleWAgcHJvcGVydHkuXG4gKi9cbmZ1bmN0aW9uIGdldEV2ZW50S2V5KG5hdGl2ZUV2ZW50KSB7XG4gIGlmIChuYXRpdmVFdmVudC5rZXkpIHtcbiAgICAvLyBOb3JtYWxpemUgaW5jb25zaXN0ZW50IHZhbHVlcyByZXBvcnRlZCBieSBicm93c2VycyBkdWUgdG9cbiAgICAvLyBpbXBsZW1lbnRhdGlvbnMgb2YgYSB3b3JraW5nIGRyYWZ0IHNwZWNpZmljYXRpb24uXG5cbiAgICAvLyBGaXJlRm94IGltcGxlbWVudHMgYGtleWAgYnV0IHJldHVybnMgYE1velByaW50YWJsZUtleWAgZm9yIGFsbFxuICAgIC8vIHByaW50YWJsZSBjaGFyYWN0ZXJzIChub3JtYWxpemVkIHRvIGBVbmlkZW50aWZpZWRgKSwgaWdub3JlIGl0LlxuICAgIHZhciBrZXkgPSBub3JtYWxpemVLZXlbbmF0aXZlRXZlbnQua2V5XSB8fCBuYXRpdmVFdmVudC5rZXk7XG4gICAgaWYgKGtleSAhPT0gJ1VuaWRlbnRpZmllZCcpIHtcbiAgICAgIHJldHVybiBrZXk7XG4gICAgfVxuICB9XG5cbiAgLy8gQnJvd3NlciBkb2VzIG5vdCBpbXBsZW1lbnQgYGtleWAsIHBvbHlmaWxsIGFzIG11Y2ggb2YgaXQgYXMgd2UgY2FuLlxuICBpZiAobmF0aXZlRXZlbnQudHlwZSA9PT0gJ2tleXByZXNzJykge1xuICAgIHZhciBjaGFyQ29kZSA9IGdldEV2ZW50Q2hhckNvZGUobmF0aXZlRXZlbnQpO1xuXG4gICAgLy8gVGhlIGVudGVyLWtleSBpcyB0ZWNobmljYWxseSBib3RoIHByaW50YWJsZSBhbmQgbm9uLXByaW50YWJsZSBhbmQgY2FuXG4gICAgLy8gdGh1cyBiZSBjYXB0dXJlZCBieSBga2V5cHJlc3NgLCBubyBvdGhlciBub24tcHJpbnRhYmxlIGtleSBzaG91bGQuXG4gICAgcmV0dXJuIGNoYXJDb2RlID09PSAxMyA/ICdFbnRlcicgOiBTdHJpbmcuZnJvbUNoYXJDb2RlKGNoYXJDb2RlKTtcbiAgfVxuICBpZiAobmF0aXZlRXZlbnQudHlwZSA9PT0gJ2tleWRvd24nIHx8IG5hdGl2ZUV2ZW50LnR5cGUgPT09ICdrZXl1cCcpIHtcbiAgICAvLyBXaGlsZSB1c2VyIGtleWJvYXJkIGxheW91dCBkZXRlcm1pbmVzIHRoZSBhY3R1YWwgbWVhbmluZyBvZiBlYWNoXG4gICAgLy8gYGtleUNvZGVgIHZhbHVlLCBhbG1vc3QgYWxsIGZ1bmN0aW9uIGtleXMgaGF2ZSBhIHVuaXZlcnNhbCB2YWx1ZS5cbiAgICByZXR1cm4gdHJhbnNsYXRlVG9LZXlbbmF0aXZlRXZlbnQua2V5Q29kZV0gfHwgJ1VuaWRlbnRpZmllZCc7XG4gIH1cbiAgcmV0dXJuICcnO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGdldEV2ZW50S2V5O1xuIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMyBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIGdldEV2ZW50TW9kaWZpZXJTdGF0ZVxuICogQHR5cGVjaGVja3Mgc3RhdGljLW9ubHlcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxuLyoqXG4gKiBUcmFuc2xhdGlvbiBmcm9tIG1vZGlmaWVyIGtleSB0byB0aGUgYXNzb2NpYXRlZCBwcm9wZXJ0eSBpbiB0aGUgZXZlbnQuXG4gKiBAc2VlIGh0dHA6Ly93d3cudzMub3JnL1RSL0RPTS1MZXZlbC0zLUV2ZW50cy8ja2V5cy1Nb2RpZmllcnNcbiAqL1xuXG52YXIgbW9kaWZpZXJLZXlUb1Byb3AgPSB7XG4gICdBbHQnOiAnYWx0S2V5JyxcbiAgJ0NvbnRyb2wnOiAnY3RybEtleScsXG4gICdNZXRhJzogJ21ldGFLZXknLFxuICAnU2hpZnQnOiAnc2hpZnRLZXknXG59O1xuXG4vLyBJRTggZG9lcyBub3QgaW1wbGVtZW50IGdldE1vZGlmaWVyU3RhdGUgc28gd2Ugc2ltcGx5IG1hcCBpdCB0byB0aGUgb25seVxuLy8gbW9kaWZpZXIga2V5cyBleHBvc2VkIGJ5IHRoZSBldmVudCBpdHNlbGYsIGRvZXMgbm90IHN1cHBvcnQgTG9jay1rZXlzLlxuLy8gQ3VycmVudGx5LCBhbGwgbWFqb3IgYnJvd3NlcnMgZXhjZXB0IENocm9tZSBzZWVtcyB0byBzdXBwb3J0IExvY2sta2V5cy5cbmZ1bmN0aW9uIG1vZGlmaWVyU3RhdGVHZXR0ZXIoa2V5QXJnKSB7XG4gIC8qanNoaW50IHZhbGlkdGhpczp0cnVlICovXG4gIHZhciBzeW50aGV0aWNFdmVudCA9IHRoaXM7XG4gIHZhciBuYXRpdmVFdmVudCA9IHN5bnRoZXRpY0V2ZW50Lm5hdGl2ZUV2ZW50O1xuICBpZiAobmF0aXZlRXZlbnQuZ2V0TW9kaWZpZXJTdGF0ZSkge1xuICAgIHJldHVybiBuYXRpdmVFdmVudC5nZXRNb2RpZmllclN0YXRlKGtleUFyZyk7XG4gIH1cbiAgdmFyIGtleVByb3AgPSBtb2RpZmllcktleVRvUHJvcFtrZXlBcmddO1xuICByZXR1cm4ga2V5UHJvcCA/ICEhbmF0aXZlRXZlbnRba2V5UHJvcF0gOiBmYWxzZTtcbn1cblxuZnVuY3Rpb24gZ2V0RXZlbnRNb2RpZmllclN0YXRlKG5hdGl2ZUV2ZW50KSB7XG4gIHJldHVybiBtb2RpZmllclN0YXRlR2V0dGVyO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGdldEV2ZW50TW9kaWZpZXJTdGF0ZTtcbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBnZXRFdmVudFRhcmdldFxuICogQHR5cGVjaGVja3Mgc3RhdGljLW9ubHlcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxuLyoqXG4gKiBHZXRzIHRoZSB0YXJnZXQgbm9kZSBmcm9tIGEgbmF0aXZlIGJyb3dzZXIgZXZlbnQgYnkgYWNjb3VudGluZyBmb3JcbiAqIGluY29uc2lzdGVuY2llcyBpbiBicm93c2VyIERPTSBBUElzLlxuICpcbiAqIEBwYXJhbSB7b2JqZWN0fSBuYXRpdmVFdmVudCBOYXRpdmUgYnJvd3NlciBldmVudC5cbiAqIEByZXR1cm4ge0RPTUV2ZW50VGFyZ2V0fSBUYXJnZXQgbm9kZS5cbiAqL1xuZnVuY3Rpb24gZ2V0RXZlbnRUYXJnZXQobmF0aXZlRXZlbnQpIHtcbiAgdmFyIHRhcmdldCA9IG5hdGl2ZUV2ZW50LnRhcmdldCB8fCBuYXRpdmVFdmVudC5zcmNFbGVtZW50IHx8IHdpbmRvdztcbiAgLy8gU2FmYXJpIG1heSBmaXJlIGV2ZW50cyBvbiB0ZXh0IG5vZGVzIChOb2RlLlRFWFRfTk9ERSBpcyAzKS5cbiAgLy8gQHNlZSBodHRwOi8vd3d3LnF1aXJrc21vZGUub3JnL2pzL2V2ZW50c19wcm9wZXJ0aWVzLmh0bWxcbiAgcmV0dXJuIHRhcmdldC5ub2RlVHlwZSA9PT0gMyA/IHRhcmdldC5wYXJlbnROb2RlIDogdGFyZ2V0O1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGdldEV2ZW50VGFyZ2V0O1xuIiwiKGZ1bmN0aW9uIChwcm9jZXNzKXtcbi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBnZXRNYXJrdXBXcmFwXG4gKi9cblxudmFyIEV4ZWN1dGlvbkVudmlyb25tZW50ID0gcmVxdWlyZShcIi4vRXhlY3V0aW9uRW52aXJvbm1lbnRcIik7XG5cbnZhciBpbnZhcmlhbnQgPSByZXF1aXJlKFwiLi9pbnZhcmlhbnRcIik7XG5cbi8qKlxuICogRHVtbXkgY29udGFpbmVyIHVzZWQgdG8gZGV0ZWN0IHdoaWNoIHdyYXBzIGFyZSBuZWNlc3NhcnkuXG4gKi9cbnZhciBkdW1teU5vZGUgPVxuICBFeGVjdXRpb25FbnZpcm9ubWVudC5jYW5Vc2VET00gPyBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKSA6IG51bGw7XG5cbi8qKlxuICogU29tZSBicm93c2VycyBjYW5ub3QgdXNlIGBpbm5lckhUTUxgIHRvIHJlbmRlciBjZXJ0YWluIGVsZW1lbnRzIHN0YW5kYWxvbmUsXG4gKiBzbyB3ZSB3cmFwIHRoZW0sIHJlbmRlciB0aGUgd3JhcHBlZCBub2RlcywgdGhlbiBleHRyYWN0IHRoZSBkZXNpcmVkIG5vZGUuXG4gKlxuICogSW4gSUU4LCBjZXJ0YWluIGVsZW1lbnRzIGNhbm5vdCByZW5kZXIgYWxvbmUsIHNvIHdyYXAgYWxsIGVsZW1lbnRzICgnKicpLlxuICovXG52YXIgc2hvdWxkV3JhcCA9IHtcbiAgLy8gRm9yY2Ugd3JhcHBpbmcgZm9yIFNWRyBlbGVtZW50cyBiZWNhdXNlIGlmIHRoZXkgZ2V0IGNyZWF0ZWQgaW5zaWRlIGEgPGRpdj4sXG4gIC8vIHRoZXkgd2lsbCBiZSBpbml0aWFsaXplZCBpbiB0aGUgd3JvbmcgbmFtZXNwYWNlIChhbmQgd2lsbCBub3QgZGlzcGxheSkuXG4gICdjaXJjbGUnOiB0cnVlLFxuICAnZGVmcyc6IHRydWUsXG4gICdlbGxpcHNlJzogdHJ1ZSxcbiAgJ2cnOiB0cnVlLFxuICAnbGluZSc6IHRydWUsXG4gICdsaW5lYXJHcmFkaWVudCc6IHRydWUsXG4gICdwYXRoJzogdHJ1ZSxcbiAgJ3BvbHlnb24nOiB0cnVlLFxuICAncG9seWxpbmUnOiB0cnVlLFxuICAncmFkaWFsR3JhZGllbnQnOiB0cnVlLFxuICAncmVjdCc6IHRydWUsXG4gICdzdG9wJzogdHJ1ZSxcbiAgJ3RleHQnOiB0cnVlXG59O1xuXG52YXIgc2VsZWN0V3JhcCA9IFsxLCAnPHNlbGVjdCBtdWx0aXBsZT1cInRydWVcIj4nLCAnPC9zZWxlY3Q+J107XG52YXIgdGFibGVXcmFwID0gWzEsICc8dGFibGU+JywgJzwvdGFibGU+J107XG52YXIgdHJXcmFwID0gWzMsICc8dGFibGU+PHRib2R5Pjx0cj4nLCAnPC90cj48L3Rib2R5PjwvdGFibGU+J107XG5cbnZhciBzdmdXcmFwID0gWzEsICc8c3ZnPicsICc8L3N2Zz4nXTtcblxudmFyIG1hcmt1cFdyYXAgPSB7XG4gICcqJzogWzEsICc/PGRpdj4nLCAnPC9kaXY+J10sXG5cbiAgJ2FyZWEnOiBbMSwgJzxtYXA+JywgJzwvbWFwPiddLFxuICAnY29sJzogWzIsICc8dGFibGU+PHRib2R5PjwvdGJvZHk+PGNvbGdyb3VwPicsICc8L2NvbGdyb3VwPjwvdGFibGU+J10sXG4gICdsZWdlbmQnOiBbMSwgJzxmaWVsZHNldD4nLCAnPC9maWVsZHNldD4nXSxcbiAgJ3BhcmFtJzogWzEsICc8b2JqZWN0PicsICc8L29iamVjdD4nXSxcbiAgJ3RyJzogWzIsICc8dGFibGU+PHRib2R5PicsICc8L3Rib2R5PjwvdGFibGU+J10sXG5cbiAgJ29wdGdyb3VwJzogc2VsZWN0V3JhcCxcbiAgJ29wdGlvbic6IHNlbGVjdFdyYXAsXG5cbiAgJ2NhcHRpb24nOiB0YWJsZVdyYXAsXG4gICdjb2xncm91cCc6IHRhYmxlV3JhcCxcbiAgJ3Rib2R5JzogdGFibGVXcmFwLFxuICAndGZvb3QnOiB0YWJsZVdyYXAsXG4gICd0aGVhZCc6IHRhYmxlV3JhcCxcblxuICAndGQnOiB0cldyYXAsXG4gICd0aCc6IHRyV3JhcCxcblxuICAnY2lyY2xlJzogc3ZnV3JhcCxcbiAgJ2RlZnMnOiBzdmdXcmFwLFxuICAnZWxsaXBzZSc6IHN2Z1dyYXAsXG4gICdnJzogc3ZnV3JhcCxcbiAgJ2xpbmUnOiBzdmdXcmFwLFxuICAnbGluZWFyR3JhZGllbnQnOiBzdmdXcmFwLFxuICAncGF0aCc6IHN2Z1dyYXAsXG4gICdwb2x5Z29uJzogc3ZnV3JhcCxcbiAgJ3BvbHlsaW5lJzogc3ZnV3JhcCxcbiAgJ3JhZGlhbEdyYWRpZW50Jzogc3ZnV3JhcCxcbiAgJ3JlY3QnOiBzdmdXcmFwLFxuICAnc3RvcCc6IHN2Z1dyYXAsXG4gICd0ZXh0Jzogc3ZnV3JhcFxufTtcblxuLyoqXG4gKiBHZXRzIHRoZSBtYXJrdXAgd3JhcCBjb25maWd1cmF0aW9uIGZvciB0aGUgc3VwcGxpZWQgYG5vZGVOYW1lYC5cbiAqXG4gKiBOT1RFOiBUaGlzIGxhemlseSBkZXRlY3RzIHdoaWNoIHdyYXBzIGFyZSBuZWNlc3NhcnkgZm9yIHRoZSBjdXJyZW50IGJyb3dzZXIuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IG5vZGVOYW1lIExvd2VyY2FzZSBgbm9kZU5hbWVgLlxuICogQHJldHVybiB7P2FycmF5fSBNYXJrdXAgd3JhcCBjb25maWd1cmF0aW9uLCBpZiBhcHBsaWNhYmxlLlxuICovXG5mdW5jdGlvbiBnZXRNYXJrdXBXcmFwKG5vZGVOYW1lKSB7XG4gIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoISFkdW1teU5vZGUsICdNYXJrdXAgd3JhcHBpbmcgbm9kZSBub3QgaW5pdGlhbGl6ZWQnKSA6IGludmFyaWFudCghIWR1bW15Tm9kZSkpO1xuICBpZiAoIW1hcmt1cFdyYXAuaGFzT3duUHJvcGVydHkobm9kZU5hbWUpKSB7XG4gICAgbm9kZU5hbWUgPSAnKic7XG4gIH1cbiAgaWYgKCFzaG91bGRXcmFwLmhhc093blByb3BlcnR5KG5vZGVOYW1lKSkge1xuICAgIGlmIChub2RlTmFtZSA9PT0gJyonKSB7XG4gICAgICBkdW1teU5vZGUuaW5uZXJIVE1MID0gJzxsaW5rIC8+JztcbiAgICB9IGVsc2Uge1xuICAgICAgZHVtbXlOb2RlLmlubmVySFRNTCA9ICc8JyArIG5vZGVOYW1lICsgJz48LycgKyBub2RlTmFtZSArICc+JztcbiAgICB9XG4gICAgc2hvdWxkV3JhcFtub2RlTmFtZV0gPSAhZHVtbXlOb2RlLmZpcnN0Q2hpbGQ7XG4gIH1cbiAgcmV0dXJuIHNob3VsZFdyYXBbbm9kZU5hbWVdID8gbWFya3VwV3JhcFtub2RlTmFtZV0gOiBudWxsO1xufVxuXG5cbm1vZHVsZS5leHBvcnRzID0gZ2V0TWFya3VwV3JhcDtcblxufSkuY2FsbCh0aGlzLHJlcXVpcmUoJ19wcm9jZXNzJykpIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIGdldE5vZGVGb3JDaGFyYWN0ZXJPZmZzZXRcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxuLyoqXG4gKiBHaXZlbiBhbnkgbm9kZSByZXR1cm4gdGhlIGZpcnN0IGxlYWYgbm9kZSB3aXRob3V0IGNoaWxkcmVuLlxuICpcbiAqIEBwYXJhbSB7RE9NRWxlbWVudHxET01UZXh0Tm9kZX0gbm9kZVxuICogQHJldHVybiB7RE9NRWxlbWVudHxET01UZXh0Tm9kZX1cbiAqL1xuZnVuY3Rpb24gZ2V0TGVhZk5vZGUobm9kZSkge1xuICB3aGlsZSAobm9kZSAmJiBub2RlLmZpcnN0Q2hpbGQpIHtcbiAgICBub2RlID0gbm9kZS5maXJzdENoaWxkO1xuICB9XG4gIHJldHVybiBub2RlO1xufVxuXG4vKipcbiAqIEdldCB0aGUgbmV4dCBzaWJsaW5nIHdpdGhpbiBhIGNvbnRhaW5lci4gVGhpcyB3aWxsIHdhbGsgdXAgdGhlXG4gKiBET00gaWYgYSBub2RlJ3Mgc2libGluZ3MgaGF2ZSBiZWVuIGV4aGF1c3RlZC5cbiAqXG4gKiBAcGFyYW0ge0RPTUVsZW1lbnR8RE9NVGV4dE5vZGV9IG5vZGVcbiAqIEByZXR1cm4gez9ET01FbGVtZW50fERPTVRleHROb2RlfVxuICovXG5mdW5jdGlvbiBnZXRTaWJsaW5nTm9kZShub2RlKSB7XG4gIHdoaWxlIChub2RlKSB7XG4gICAgaWYgKG5vZGUubmV4dFNpYmxpbmcpIHtcbiAgICAgIHJldHVybiBub2RlLm5leHRTaWJsaW5nO1xuICAgIH1cbiAgICBub2RlID0gbm9kZS5wYXJlbnROb2RlO1xuICB9XG59XG5cbi8qKlxuICogR2V0IG9iamVjdCBkZXNjcmliaW5nIHRoZSBub2RlcyB3aGljaCBjb250YWluIGNoYXJhY3RlcnMgYXQgb2Zmc2V0LlxuICpcbiAqIEBwYXJhbSB7RE9NRWxlbWVudHxET01UZXh0Tm9kZX0gcm9vdFxuICogQHBhcmFtIHtudW1iZXJ9IG9mZnNldFxuICogQHJldHVybiB7P29iamVjdH1cbiAqL1xuZnVuY3Rpb24gZ2V0Tm9kZUZvckNoYXJhY3Rlck9mZnNldChyb290LCBvZmZzZXQpIHtcbiAgdmFyIG5vZGUgPSBnZXRMZWFmTm9kZShyb290KTtcbiAgdmFyIG5vZGVTdGFydCA9IDA7XG4gIHZhciBub2RlRW5kID0gMDtcblxuICB3aGlsZSAobm9kZSkge1xuICAgIGlmIChub2RlLm5vZGVUeXBlID09IDMpIHtcbiAgICAgIG5vZGVFbmQgPSBub2RlU3RhcnQgKyBub2RlLnRleHRDb250ZW50Lmxlbmd0aDtcblxuICAgICAgaWYgKG5vZGVTdGFydCA8PSBvZmZzZXQgJiYgbm9kZUVuZCA+PSBvZmZzZXQpIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBub2RlOiBub2RlLFxuICAgICAgICAgIG9mZnNldDogb2Zmc2V0IC0gbm9kZVN0YXJ0XG4gICAgICAgIH07XG4gICAgICB9XG5cbiAgICAgIG5vZGVTdGFydCA9IG5vZGVFbmQ7XG4gICAgfVxuXG4gICAgbm9kZSA9IGdldExlYWZOb2RlKGdldFNpYmxpbmdOb2RlKG5vZGUpKTtcbiAgfVxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGdldE5vZGVGb3JDaGFyYWN0ZXJPZmZzZXQ7XG4iLCIvKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgZ2V0UmVhY3RSb290RWxlbWVudEluQ29udGFpbmVyXG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBET0NfTk9ERV9UWVBFID0gOTtcblxuLyoqXG4gKiBAcGFyYW0ge0RPTUVsZW1lbnR8RE9NRG9jdW1lbnR9IGNvbnRhaW5lciBET00gZWxlbWVudCB0aGF0IG1heSBjb250YWluXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhIFJlYWN0IGNvbXBvbmVudFxuICogQHJldHVybiB7Pyp9IERPTSBlbGVtZW50IHRoYXQgbWF5IGhhdmUgdGhlIHJlYWN0Um9vdCBJRCwgb3IgbnVsbC5cbiAqL1xuZnVuY3Rpb24gZ2V0UmVhY3RSb290RWxlbWVudEluQ29udGFpbmVyKGNvbnRhaW5lcikge1xuICBpZiAoIWNvbnRhaW5lcikge1xuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgaWYgKGNvbnRhaW5lci5ub2RlVHlwZSA9PT0gRE9DX05PREVfVFlQRSkge1xuICAgIHJldHVybiBjb250YWluZXIuZG9jdW1lbnRFbGVtZW50O1xuICB9IGVsc2Uge1xuICAgIHJldHVybiBjb250YWluZXIuZmlyc3RDaGlsZDtcbiAgfVxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGdldFJlYWN0Um9vdEVsZW1lbnRJbkNvbnRhaW5lcjtcbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBnZXRUZXh0Q29udGVudEFjY2Vzc29yXG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBFeGVjdXRpb25FbnZpcm9ubWVudCA9IHJlcXVpcmUoXCIuL0V4ZWN1dGlvbkVudmlyb25tZW50XCIpO1xuXG52YXIgY29udGVudEtleSA9IG51bGw7XG5cbi8qKlxuICogR2V0cyB0aGUga2V5IHVzZWQgdG8gYWNjZXNzIHRleHQgY29udGVudCBvbiBhIERPTSBub2RlLlxuICpcbiAqIEByZXR1cm4gez9zdHJpbmd9IEtleSB1c2VkIHRvIGFjY2VzcyB0ZXh0IGNvbnRlbnQuXG4gKiBAaW50ZXJuYWxcbiAqL1xuZnVuY3Rpb24gZ2V0VGV4dENvbnRlbnRBY2Nlc3NvcigpIHtcbiAgaWYgKCFjb250ZW50S2V5ICYmIEV4ZWN1dGlvbkVudmlyb25tZW50LmNhblVzZURPTSkge1xuICAgIC8vIFByZWZlciB0ZXh0Q29udGVudCB0byBpbm5lclRleHQgYmVjYXVzZSBtYW55IGJyb3dzZXJzIHN1cHBvcnQgYm90aCBidXRcbiAgICAvLyBTVkcgPHRleHQ+IGVsZW1lbnRzIGRvbid0IHN1cHBvcnQgaW5uZXJUZXh0IGV2ZW4gd2hlbiA8ZGl2PiBkb2VzLlxuICAgIGNvbnRlbnRLZXkgPSAndGV4dENvbnRlbnQnIGluIGRvY3VtZW50LmRvY3VtZW50RWxlbWVudCA/XG4gICAgICAndGV4dENvbnRlbnQnIDpcbiAgICAgICdpbm5lclRleHQnO1xuICB9XG4gIHJldHVybiBjb250ZW50S2V5O1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGdldFRleHRDb250ZW50QWNjZXNzb3I7XG4iLCIvKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgZ2V0VW5ib3VuZGVkU2Nyb2xsUG9zaXRpb25cbiAqIEB0eXBlY2hlY2tzXG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbi8qKlxuICogR2V0cyB0aGUgc2Nyb2xsIHBvc2l0aW9uIG9mIHRoZSBzdXBwbGllZCBlbGVtZW50IG9yIHdpbmRvdy5cbiAqXG4gKiBUaGUgcmV0dXJuIHZhbHVlcyBhcmUgdW5ib3VuZGVkLCB1bmxpa2UgYGdldFNjcm9sbFBvc2l0aW9uYC4gVGhpcyBtZWFucyB0aGV5XG4gKiBtYXkgYmUgbmVnYXRpdmUgb3IgZXhjZWVkIHRoZSBlbGVtZW50IGJvdW5kYXJpZXMgKHdoaWNoIGlzIHBvc3NpYmxlIHVzaW5nXG4gKiBpbmVydGlhbCBzY3JvbGxpbmcpLlxuICpcbiAqIEBwYXJhbSB7RE9NV2luZG93fERPTUVsZW1lbnR9IHNjcm9sbGFibGVcbiAqIEByZXR1cm4ge29iamVjdH0gTWFwIHdpdGggYHhgIGFuZCBgeWAga2V5cy5cbiAqL1xuZnVuY3Rpb24gZ2V0VW5ib3VuZGVkU2Nyb2xsUG9zaXRpb24oc2Nyb2xsYWJsZSkge1xuICBpZiAoc2Nyb2xsYWJsZSA9PT0gd2luZG93KSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHg6IHdpbmRvdy5wYWdlWE9mZnNldCB8fCBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuc2Nyb2xsTGVmdCxcbiAgICAgIHk6IHdpbmRvdy5wYWdlWU9mZnNldCB8fCBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuc2Nyb2xsVG9wXG4gICAgfTtcbiAgfVxuICByZXR1cm4ge1xuICAgIHg6IHNjcm9sbGFibGUuc2Nyb2xsTGVmdCxcbiAgICB5OiBzY3JvbGxhYmxlLnNjcm9sbFRvcFxuICB9O1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGdldFVuYm91bmRlZFNjcm9sbFBvc2l0aW9uO1xuIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIGh5cGhlbmF0ZVxuICogQHR5cGVjaGVja3NcbiAqL1xuXG52YXIgX3VwcGVyY2FzZVBhdHRlcm4gPSAvKFtBLVpdKS9nO1xuXG4vKipcbiAqIEh5cGhlbmF0ZXMgYSBjYW1lbGNhc2VkIHN0cmluZywgZm9yIGV4YW1wbGU6XG4gKlxuICogICA+IGh5cGhlbmF0ZSgnYmFja2dyb3VuZENvbG9yJylcbiAqICAgPCBcImJhY2tncm91bmQtY29sb3JcIlxuICpcbiAqIEZvciBDU1Mgc3R5bGUgbmFtZXMsIHVzZSBgaHlwaGVuYXRlU3R5bGVOYW1lYCBpbnN0ZWFkIHdoaWNoIHdvcmtzIHByb3Blcmx5XG4gKiB3aXRoIGFsbCB2ZW5kb3IgcHJlZml4ZXMsIGluY2x1ZGluZyBgbXNgLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBzdHJpbmdcbiAqIEByZXR1cm4ge3N0cmluZ31cbiAqL1xuZnVuY3Rpb24gaHlwaGVuYXRlKHN0cmluZykge1xuICByZXR1cm4gc3RyaW5nLnJlcGxhY2UoX3VwcGVyY2FzZVBhdHRlcm4sICctJDEnKS50b0xvd2VyQ2FzZSgpO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGh5cGhlbmF0ZTtcbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBoeXBoZW5hdGVTdHlsZU5hbWVcbiAqIEB0eXBlY2hlY2tzXG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBoeXBoZW5hdGUgPSByZXF1aXJlKFwiLi9oeXBoZW5hdGVcIik7XG5cbnZhciBtc1BhdHRlcm4gPSAvXm1zLS87XG5cbi8qKlxuICogSHlwaGVuYXRlcyBhIGNhbWVsY2FzZWQgQ1NTIHByb3BlcnR5IG5hbWUsIGZvciBleGFtcGxlOlxuICpcbiAqICAgPiBoeXBoZW5hdGVTdHlsZU5hbWUoJ2JhY2tncm91bmRDb2xvcicpXG4gKiAgIDwgXCJiYWNrZ3JvdW5kLWNvbG9yXCJcbiAqICAgPiBoeXBoZW5hdGVTdHlsZU5hbWUoJ01velRyYW5zaXRpb24nKVxuICogICA8IFwiLW1vei10cmFuc2l0aW9uXCJcbiAqICAgPiBoeXBoZW5hdGVTdHlsZU5hbWUoJ21zVHJhbnNpdGlvbicpXG4gKiAgIDwgXCItbXMtdHJhbnNpdGlvblwiXG4gKlxuICogQXMgTW9kZXJuaXpyIHN1Z2dlc3RzIChodHRwOi8vbW9kZXJuaXpyLmNvbS9kb2NzLyNwcmVmaXhlZCksIGFuIGBtc2AgcHJlZml4XG4gKiBpcyBjb252ZXJ0ZWQgdG8gYC1tcy1gLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBzdHJpbmdcbiAqIEByZXR1cm4ge3N0cmluZ31cbiAqL1xuZnVuY3Rpb24gaHlwaGVuYXRlU3R5bGVOYW1lKHN0cmluZykge1xuICByZXR1cm4gaHlwaGVuYXRlKHN0cmluZykucmVwbGFjZShtc1BhdHRlcm4sICctbXMtJyk7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gaHlwaGVuYXRlU3R5bGVOYW1lO1xuIiwiKGZ1bmN0aW9uIChwcm9jZXNzKXtcbi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBpbnN0YW50aWF0ZVJlYWN0Q29tcG9uZW50XG4gKiBAdHlwZWNoZWNrcyBzdGF0aWMtb25seVxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgd2FybmluZyA9IHJlcXVpcmUoXCIuL3dhcm5pbmdcIik7XG5cbnZhciBSZWFjdEVsZW1lbnQgPSByZXF1aXJlKFwiLi9SZWFjdEVsZW1lbnRcIik7XG52YXIgUmVhY3RMZWdhY3lFbGVtZW50ID0gcmVxdWlyZShcIi4vUmVhY3RMZWdhY3lFbGVtZW50XCIpO1xudmFyIFJlYWN0TmF0aXZlQ29tcG9uZW50ID0gcmVxdWlyZShcIi4vUmVhY3ROYXRpdmVDb21wb25lbnRcIik7XG52YXIgUmVhY3RFbXB0eUNvbXBvbmVudCA9IHJlcXVpcmUoXCIuL1JlYWN0RW1wdHlDb21wb25lbnRcIik7XG5cbi8qKlxuICogR2l2ZW4gYW4gYGVsZW1lbnRgIGNyZWF0ZSBhbiBpbnN0YW5jZSB0aGF0IHdpbGwgYWN0dWFsbHkgYmUgbW91bnRlZC5cbiAqXG4gKiBAcGFyYW0ge29iamVjdH0gZWxlbWVudFxuICogQHBhcmFtIHsqfSBwYXJlbnRDb21wb3NpdGVUeXBlIFRoZSBjb21wb3NpdGUgdHlwZSB0aGF0IHJlc29sdmVkIHRoaXMuXG4gKiBAcmV0dXJuIHtvYmplY3R9IEEgbmV3IGluc3RhbmNlIG9mIHRoZSBlbGVtZW50J3MgY29uc3RydWN0b3IuXG4gKiBAcHJvdGVjdGVkXG4gKi9cbmZ1bmN0aW9uIGluc3RhbnRpYXRlUmVhY3RDb21wb25lbnQoZWxlbWVudCwgcGFyZW50Q29tcG9zaXRlVHlwZSkge1xuICB2YXIgaW5zdGFuY2U7XG5cbiAgaWYgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOVikge1xuICAgIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyB3YXJuaW5nKFxuICAgICAgZWxlbWVudCAmJiAodHlwZW9mIGVsZW1lbnQudHlwZSA9PT0gJ2Z1bmN0aW9uJyB8fFxuICAgICAgICAgICAgICAgICAgICAgdHlwZW9mIGVsZW1lbnQudHlwZSA9PT0gJ3N0cmluZycpLFxuICAgICAgJ09ubHkgZnVuY3Rpb25zIG9yIHN0cmluZ3MgY2FuIGJlIG1vdW50ZWQgYXMgUmVhY3QgY29tcG9uZW50cy4nXG4gICAgKSA6IG51bGwpO1xuXG4gICAgLy8gUmVzb2x2ZSBtb2NrIGluc3RhbmNlc1xuICAgIGlmIChlbGVtZW50LnR5cGUuX21vY2tlZFJlYWN0Q2xhc3NDb25zdHJ1Y3Rvcikge1xuICAgICAgLy8gSWYgdGhpcyBpcyBhIG1vY2tlZCBjbGFzcywgd2UgdHJlYXQgdGhlIGxlZ2FjeSBmYWN0b3J5IGFzIGlmIGl0IHdhcyB0aGVcbiAgICAgIC8vIGNsYXNzIGNvbnN0cnVjdG9yIGZvciBmdXR1cmUgcHJvb2ZpbmcgdW5pdCB0ZXN0cy4gQmVjYXVzZSB0aGlzIG1pZ2h0XG4gICAgICAvLyBiZSBtb2NrZWQgYXMgYSBsZWdhY3kgZmFjdG9yeSwgd2UgaWdub3JlIGFueSB3YXJuaW5ncyB0cmlnZ2VyZCBieVxuICAgICAgLy8gdGhpcyB0ZW1wb3JhcnkgaGFjay5cbiAgICAgIFJlYWN0TGVnYWN5RWxlbWVudC5faXNMZWdhY3lDYWxsV2FybmluZ0VuYWJsZWQgPSBmYWxzZTtcbiAgICAgIHRyeSB7XG4gICAgICAgIGluc3RhbmNlID0gbmV3IGVsZW1lbnQudHlwZS5fbW9ja2VkUmVhY3RDbGFzc0NvbnN0cnVjdG9yKFxuICAgICAgICAgIGVsZW1lbnQucHJvcHNcbiAgICAgICAgKTtcbiAgICAgIH0gZmluYWxseSB7XG4gICAgICAgIFJlYWN0TGVnYWN5RWxlbWVudC5faXNMZWdhY3lDYWxsV2FybmluZ0VuYWJsZWQgPSB0cnVlO1xuICAgICAgfVxuXG4gICAgICAvLyBJZiB0aGUgbW9jayBpbXBsZW1lbnRhdGlvbiB3YXMgYSBsZWdhY3kgZmFjdG9yeSwgdGhlbiBpdCByZXR1cm5zIGFcbiAgICAgIC8vIGVsZW1lbnQuIFdlIG5lZWQgdG8gdHVybiB0aGlzIGludG8gYSByZWFsIGNvbXBvbmVudCBpbnN0YW5jZS5cbiAgICAgIGlmIChSZWFjdEVsZW1lbnQuaXNWYWxpZEVsZW1lbnQoaW5zdGFuY2UpKSB7XG4gICAgICAgIGluc3RhbmNlID0gbmV3IGluc3RhbmNlLnR5cGUoaW5zdGFuY2UucHJvcHMpO1xuICAgICAgfVxuXG4gICAgICB2YXIgcmVuZGVyID0gaW5zdGFuY2UucmVuZGVyO1xuICAgICAgaWYgKCFyZW5kZXIpIHtcbiAgICAgICAgLy8gRm9yIGF1dG8tbW9ja2VkIGZhY3RvcmllcywgdGhlIHByb3RvdHlwZSBpc24ndCBzaGltbWVkIGFuZCB0aGVyZWZvcmVcbiAgICAgICAgLy8gdGhlcmUgaXMgbm8gcmVuZGVyIGZ1bmN0aW9uIG9uIHRoZSBpbnN0YW5jZS4gV2UgcmVwbGFjZSB0aGUgd2hvbGVcbiAgICAgICAgLy8gY29tcG9uZW50IHdpdGggYW4gZW1wdHkgY29tcG9uZW50IGluc3RhbmNlIGluc3RlYWQuXG4gICAgICAgIGVsZW1lbnQgPSBSZWFjdEVtcHR5Q29tcG9uZW50LmdldEVtcHR5Q29tcG9uZW50KCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBpZiAocmVuZGVyLl9pc01vY2tGdW5jdGlvbiAmJiAhcmVuZGVyLl9nZXRNb2NrSW1wbGVtZW50YXRpb24oKSkge1xuICAgICAgICAgIC8vIEF1dG8tbW9ja2VkIGNvbXBvbmVudHMgbWF5IGhhdmUgYSBwcm90b3R5cGUgd2l0aCBhIG1vY2tlZCByZW5kZXJcbiAgICAgICAgICAvLyBmdW5jdGlvbi4gRm9yIHRob3NlLCB3ZSdsbCBuZWVkIHRvIG1vY2sgdGhlIHJlc3VsdCBvZiB0aGUgcmVuZGVyXG4gICAgICAgICAgLy8gc2luY2Ugd2UgY29uc2lkZXIgdW5kZWZpbmVkIHRvIGJlIGludmFsaWQgcmVzdWx0cyBmcm9tIHJlbmRlci5cbiAgICAgICAgICByZW5kZXIubW9ja0ltcGxlbWVudGF0aW9uKFxuICAgICAgICAgICAgUmVhY3RFbXB0eUNvbXBvbmVudC5nZXRFbXB0eUNvbXBvbmVudFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgICAgaW5zdGFuY2UuY29uc3RydWN0KGVsZW1lbnQpO1xuICAgICAgICByZXR1cm4gaW5zdGFuY2U7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLy8gU3BlY2lhbCBjYXNlIHN0cmluZyB2YWx1ZXNcbiAgaWYgKHR5cGVvZiBlbGVtZW50LnR5cGUgPT09ICdzdHJpbmcnKSB7XG4gICAgaW5zdGFuY2UgPSBSZWFjdE5hdGl2ZUNvbXBvbmVudC5jcmVhdGVJbnN0YW5jZUZvclRhZyhcbiAgICAgIGVsZW1lbnQudHlwZSxcbiAgICAgIGVsZW1lbnQucHJvcHMsXG4gICAgICBwYXJlbnRDb21wb3NpdGVUeXBlXG4gICAgKTtcbiAgfSBlbHNlIHtcbiAgICAvLyBOb3JtYWwgY2FzZSBmb3Igbm9uLW1vY2tzIGFuZCBub24tc3RyaW5nc1xuICAgIGluc3RhbmNlID0gbmV3IGVsZW1lbnQudHlwZShlbGVtZW50LnByb3BzKTtcbiAgfVxuXG4gIGlmIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYpIHtcbiAgICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gd2FybmluZyhcbiAgICAgIHR5cGVvZiBpbnN0YW5jZS5jb25zdHJ1Y3QgPT09ICdmdW5jdGlvbicgJiZcbiAgICAgIHR5cGVvZiBpbnN0YW5jZS5tb3VudENvbXBvbmVudCA9PT0gJ2Z1bmN0aW9uJyAmJlxuICAgICAgdHlwZW9mIGluc3RhbmNlLnJlY2VpdmVDb21wb25lbnQgPT09ICdmdW5jdGlvbicsXG4gICAgICAnT25seSBSZWFjdCBDb21wb25lbnRzIGNhbiBiZSBtb3VudGVkLidcbiAgICApIDogbnVsbCk7XG4gIH1cblxuICAvLyBUaGlzIGFjdHVhbGx5IHNldHMgdXAgdGhlIGludGVybmFsIGluc3RhbmNlLiBUaGlzIHdpbGwgYmVjb21lIGRlY291cGxlZFxuICAvLyBmcm9tIHRoZSBwdWJsaWMgaW5zdGFuY2UgaW4gYSBmdXR1cmUgZGlmZi5cbiAgaW5zdGFuY2UuY29uc3RydWN0KGVsZW1lbnQpO1xuXG4gIHJldHVybiBpbnN0YW5jZTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBpbnN0YW50aWF0ZVJlYWN0Q29tcG9uZW50O1xuXG59KS5jYWxsKHRoaXMscmVxdWlyZSgnX3Byb2Nlc3MnKSkiLCIoZnVuY3Rpb24gKHByb2Nlc3Mpe1xuLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIGludmFyaWFudFxuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG4vKipcbiAqIFVzZSBpbnZhcmlhbnQoKSB0byBhc3NlcnQgc3RhdGUgd2hpY2ggeW91ciBwcm9ncmFtIGFzc3VtZXMgdG8gYmUgdHJ1ZS5cbiAqXG4gKiBQcm92aWRlIHNwcmludGYtc3R5bGUgZm9ybWF0IChvbmx5ICVzIGlzIHN1cHBvcnRlZCkgYW5kIGFyZ3VtZW50c1xuICogdG8gcHJvdmlkZSBpbmZvcm1hdGlvbiBhYm91dCB3aGF0IGJyb2tlIGFuZCB3aGF0IHlvdSB3ZXJlXG4gKiBleHBlY3RpbmcuXG4gKlxuICogVGhlIGludmFyaWFudCBtZXNzYWdlIHdpbGwgYmUgc3RyaXBwZWQgaW4gcHJvZHVjdGlvbiwgYnV0IHRoZSBpbnZhcmlhbnRcbiAqIHdpbGwgcmVtYWluIHRvIGVuc3VyZSBsb2dpYyBkb2VzIG5vdCBkaWZmZXIgaW4gcHJvZHVjdGlvbi5cbiAqL1xuXG52YXIgaW52YXJpYW50ID0gZnVuY3Rpb24oY29uZGl0aW9uLCBmb3JtYXQsIGEsIGIsIGMsIGQsIGUsIGYpIHtcbiAgaWYgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOVikge1xuICAgIGlmIChmb3JtYXQgPT09IHVuZGVmaW5lZCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdpbnZhcmlhbnQgcmVxdWlyZXMgYW4gZXJyb3IgbWVzc2FnZSBhcmd1bWVudCcpO1xuICAgIH1cbiAgfVxuXG4gIGlmICghY29uZGl0aW9uKSB7XG4gICAgdmFyIGVycm9yO1xuICAgIGlmIChmb3JtYXQgPT09IHVuZGVmaW5lZCkge1xuICAgICAgZXJyb3IgPSBuZXcgRXJyb3IoXG4gICAgICAgICdNaW5pZmllZCBleGNlcHRpb24gb2NjdXJyZWQ7IHVzZSB0aGUgbm9uLW1pbmlmaWVkIGRldiBlbnZpcm9ubWVudCAnICtcbiAgICAgICAgJ2ZvciB0aGUgZnVsbCBlcnJvciBtZXNzYWdlIGFuZCBhZGRpdGlvbmFsIGhlbHBmdWwgd2FybmluZ3MuJ1xuICAgICAgKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdmFyIGFyZ3MgPSBbYSwgYiwgYywgZCwgZSwgZl07XG4gICAgICB2YXIgYXJnSW5kZXggPSAwO1xuICAgICAgZXJyb3IgPSBuZXcgRXJyb3IoXG4gICAgICAgICdJbnZhcmlhbnQgVmlvbGF0aW9uOiAnICtcbiAgICAgICAgZm9ybWF0LnJlcGxhY2UoLyVzL2csIGZ1bmN0aW9uKCkgeyByZXR1cm4gYXJnc1thcmdJbmRleCsrXTsgfSlcbiAgICAgICk7XG4gICAgfVxuXG4gICAgZXJyb3IuZnJhbWVzVG9Qb3AgPSAxOyAvLyB3ZSBkb24ndCBjYXJlIGFib3V0IGludmFyaWFudCdzIG93biBmcmFtZVxuICAgIHRocm93IGVycm9yO1xuICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IGludmFyaWFudDtcblxufSkuY2FsbCh0aGlzLHJlcXVpcmUoJ19wcm9jZXNzJykpIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIGlzRXZlbnRTdXBwb3J0ZWRcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIEV4ZWN1dGlvbkVudmlyb25tZW50ID0gcmVxdWlyZShcIi4vRXhlY3V0aW9uRW52aXJvbm1lbnRcIik7XG5cbnZhciB1c2VIYXNGZWF0dXJlO1xuaWYgKEV4ZWN1dGlvbkVudmlyb25tZW50LmNhblVzZURPTSkge1xuICB1c2VIYXNGZWF0dXJlID1cbiAgICBkb2N1bWVudC5pbXBsZW1lbnRhdGlvbiAmJlxuICAgIGRvY3VtZW50LmltcGxlbWVudGF0aW9uLmhhc0ZlYXR1cmUgJiZcbiAgICAvLyBhbHdheXMgcmV0dXJucyB0cnVlIGluIG5ld2VyIGJyb3dzZXJzIGFzIHBlciB0aGUgc3RhbmRhcmQuXG4gICAgLy8gQHNlZSBodHRwOi8vZG9tLnNwZWMud2hhdHdnLm9yZy8jZG9tLWRvbWltcGxlbWVudGF0aW9uLWhhc2ZlYXR1cmVcbiAgICBkb2N1bWVudC5pbXBsZW1lbnRhdGlvbi5oYXNGZWF0dXJlKCcnLCAnJykgIT09IHRydWU7XG59XG5cbi8qKlxuICogQ2hlY2tzIGlmIGFuIGV2ZW50IGlzIHN1cHBvcnRlZCBpbiB0aGUgY3VycmVudCBleGVjdXRpb24gZW52aXJvbm1lbnQuXG4gKlxuICogTk9URTogVGhpcyB3aWxsIG5vdCB3b3JrIGNvcnJlY3RseSBmb3Igbm9uLWdlbmVyaWMgZXZlbnRzIHN1Y2ggYXMgYGNoYW5nZWAsXG4gKiBgcmVzZXRgLCBgbG9hZGAsIGBlcnJvcmAsIGFuZCBgc2VsZWN0YC5cbiAqXG4gKiBCb3Jyb3dzIGZyb20gTW9kZXJuaXpyLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBldmVudE5hbWVTdWZmaXggRXZlbnQgbmFtZSwgZS5nLiBcImNsaWNrXCIuXG4gKiBAcGFyYW0gez9ib29sZWFufSBjYXB0dXJlIENoZWNrIGlmIHRoZSBjYXB0dXJlIHBoYXNlIGlzIHN1cHBvcnRlZC5cbiAqIEByZXR1cm4ge2Jvb2xlYW59IFRydWUgaWYgdGhlIGV2ZW50IGlzIHN1cHBvcnRlZC5cbiAqIEBpbnRlcm5hbFxuICogQGxpY2Vuc2UgTW9kZXJuaXpyIDMuMC4wcHJlIChDdXN0b20gQnVpbGQpIHwgTUlUXG4gKi9cbmZ1bmN0aW9uIGlzRXZlbnRTdXBwb3J0ZWQoZXZlbnROYW1lU3VmZml4LCBjYXB0dXJlKSB7XG4gIGlmICghRXhlY3V0aW9uRW52aXJvbm1lbnQuY2FuVXNlRE9NIHx8XG4gICAgICBjYXB0dXJlICYmICEoJ2FkZEV2ZW50TGlzdGVuZXInIGluIGRvY3VtZW50KSkge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIHZhciBldmVudE5hbWUgPSAnb24nICsgZXZlbnROYW1lU3VmZml4O1xuICB2YXIgaXNTdXBwb3J0ZWQgPSBldmVudE5hbWUgaW4gZG9jdW1lbnQ7XG5cbiAgaWYgKCFpc1N1cHBvcnRlZCkge1xuICAgIHZhciBlbGVtZW50ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnZGl2Jyk7XG4gICAgZWxlbWVudC5zZXRBdHRyaWJ1dGUoZXZlbnROYW1lLCAncmV0dXJuOycpO1xuICAgIGlzU3VwcG9ydGVkID0gdHlwZW9mIGVsZW1lbnRbZXZlbnROYW1lXSA9PT0gJ2Z1bmN0aW9uJztcbiAgfVxuXG4gIGlmICghaXNTdXBwb3J0ZWQgJiYgdXNlSGFzRmVhdHVyZSAmJiBldmVudE5hbWVTdWZmaXggPT09ICd3aGVlbCcpIHtcbiAgICAvLyBUaGlzIGlzIHRoZSBvbmx5IHdheSB0byB0ZXN0IHN1cHBvcnQgZm9yIHRoZSBgd2hlZWxgIGV2ZW50IGluIElFOSsuXG4gICAgaXNTdXBwb3J0ZWQgPSBkb2N1bWVudC5pbXBsZW1lbnRhdGlvbi5oYXNGZWF0dXJlKCdFdmVudHMud2hlZWwnLCAnMy4wJyk7XG4gIH1cblxuICByZXR1cm4gaXNTdXBwb3J0ZWQ7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gaXNFdmVudFN1cHBvcnRlZDtcbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBpc05vZGVcbiAqIEB0eXBlY2hlY2tzXG4gKi9cblxuLyoqXG4gKiBAcGFyYW0geyp9IG9iamVjdCBUaGUgb2JqZWN0IHRvIGNoZWNrLlxuICogQHJldHVybiB7Ym9vbGVhbn0gV2hldGhlciBvciBub3QgdGhlIG9iamVjdCBpcyBhIERPTSBub2RlLlxuICovXG5mdW5jdGlvbiBpc05vZGUob2JqZWN0KSB7XG4gIHJldHVybiAhIShvYmplY3QgJiYgKFxuICAgIHR5cGVvZiBOb2RlID09PSAnZnVuY3Rpb24nID8gb2JqZWN0IGluc3RhbmNlb2YgTm9kZSA6XG4gICAgICB0eXBlb2Ygb2JqZWN0ID09PSAnb2JqZWN0JyAmJlxuICAgICAgdHlwZW9mIG9iamVjdC5ub2RlVHlwZSA9PT0gJ251bWJlcicgJiZcbiAgICAgIHR5cGVvZiBvYmplY3Qubm9kZU5hbWUgPT09ICdzdHJpbmcnXG4gICkpO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGlzTm9kZTtcbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBpc1RleHRJbnB1dEVsZW1lbnRcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxuLyoqXG4gKiBAc2VlIGh0dHA6Ly93d3cud2hhdHdnLm9yZy9zcGVjcy93ZWItYXBwcy9jdXJyZW50LXdvcmsvbXVsdGlwYWdlL3RoZS1pbnB1dC1lbGVtZW50Lmh0bWwjaW5wdXQtdHlwZS1hdHRyLXN1bW1hcnlcbiAqL1xudmFyIHN1cHBvcnRlZElucHV0VHlwZXMgPSB7XG4gICdjb2xvcic6IHRydWUsXG4gICdkYXRlJzogdHJ1ZSxcbiAgJ2RhdGV0aW1lJzogdHJ1ZSxcbiAgJ2RhdGV0aW1lLWxvY2FsJzogdHJ1ZSxcbiAgJ2VtYWlsJzogdHJ1ZSxcbiAgJ21vbnRoJzogdHJ1ZSxcbiAgJ251bWJlcic6IHRydWUsXG4gICdwYXNzd29yZCc6IHRydWUsXG4gICdyYW5nZSc6IHRydWUsXG4gICdzZWFyY2gnOiB0cnVlLFxuICAndGVsJzogdHJ1ZSxcbiAgJ3RleHQnOiB0cnVlLFxuICAndGltZSc6IHRydWUsXG4gICd1cmwnOiB0cnVlLFxuICAnd2Vlayc6IHRydWVcbn07XG5cbmZ1bmN0aW9uIGlzVGV4dElucHV0RWxlbWVudChlbGVtKSB7XG4gIHJldHVybiBlbGVtICYmIChcbiAgICAoZWxlbS5ub2RlTmFtZSA9PT0gJ0lOUFVUJyAmJiBzdXBwb3J0ZWRJbnB1dFR5cGVzW2VsZW0udHlwZV0pIHx8XG4gICAgZWxlbS5ub2RlTmFtZSA9PT0gJ1RFWFRBUkVBJ1xuICApO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGlzVGV4dElucHV0RWxlbWVudDtcbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBpc1RleHROb2RlXG4gKiBAdHlwZWNoZWNrc1xuICovXG5cbnZhciBpc05vZGUgPSByZXF1aXJlKFwiLi9pc05vZGVcIik7XG5cbi8qKlxuICogQHBhcmFtIHsqfSBvYmplY3QgVGhlIG9iamVjdCB0byBjaGVjay5cbiAqIEByZXR1cm4ge2Jvb2xlYW59IFdoZXRoZXIgb3Igbm90IHRoZSBvYmplY3QgaXMgYSBET00gdGV4dCBub2RlLlxuICovXG5mdW5jdGlvbiBpc1RleHROb2RlKG9iamVjdCkge1xuICByZXR1cm4gaXNOb2RlKG9iamVjdCkgJiYgb2JqZWN0Lm5vZGVUeXBlID09IDM7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gaXNUZXh0Tm9kZTtcbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBqb2luQ2xhc3Nlc1xuICogQHR5cGVjaGVja3Mgc3RhdGljLW9ubHlcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxuLyoqXG4gKiBDb21iaW5lcyBtdWx0aXBsZSBjbGFzc05hbWUgc3RyaW5ncyBpbnRvIG9uZS5cbiAqIGh0dHA6Ly9qc3BlcmYuY29tL2pvaW5jbGFzc2VzLWFyZ3MtdnMtYXJyYXlcbiAqXG4gKiBAcGFyYW0gey4uLj9zdHJpbmd9IGNsYXNzZXNcbiAqIEByZXR1cm4ge3N0cmluZ31cbiAqL1xuZnVuY3Rpb24gam9pbkNsYXNzZXMoY2xhc3NOYW1lLyosIC4uLiAqLykge1xuICBpZiAoIWNsYXNzTmFtZSkge1xuICAgIGNsYXNzTmFtZSA9ICcnO1xuICB9XG4gIHZhciBuZXh0Q2xhc3M7XG4gIHZhciBhcmdMZW5ndGggPSBhcmd1bWVudHMubGVuZ3RoO1xuICBpZiAoYXJnTGVuZ3RoID4gMSkge1xuICAgIGZvciAodmFyIGlpID0gMTsgaWkgPCBhcmdMZW5ndGg7IGlpKyspIHtcbiAgICAgIG5leHRDbGFzcyA9IGFyZ3VtZW50c1tpaV07XG4gICAgICBpZiAobmV4dENsYXNzKSB7XG4gICAgICAgIGNsYXNzTmFtZSA9IChjbGFzc05hbWUgPyBjbGFzc05hbWUgKyAnICcgOiAnJykgKyBuZXh0Q2xhc3M7XG4gICAgICB9XG4gICAgfVxuICB9XG4gIHJldHVybiBjbGFzc05hbWU7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gam9pbkNsYXNzZXM7XG4iLCIoZnVuY3Rpb24gKHByb2Nlc3Mpe1xuLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIGtleU1pcnJvclxuICogQHR5cGVjaGVja3Mgc3RhdGljLW9ubHlcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIGludmFyaWFudCA9IHJlcXVpcmUoXCIuL2ludmFyaWFudFwiKTtcblxuLyoqXG4gKiBDb25zdHJ1Y3RzIGFuIGVudW1lcmF0aW9uIHdpdGgga2V5cyBlcXVhbCB0byB0aGVpciB2YWx1ZS5cbiAqXG4gKiBGb3IgZXhhbXBsZTpcbiAqXG4gKiAgIHZhciBDT0xPUlMgPSBrZXlNaXJyb3Ioe2JsdWU6IG51bGwsIHJlZDogbnVsbH0pO1xuICogICB2YXIgbXlDb2xvciA9IENPTE9SUy5ibHVlO1xuICogICB2YXIgaXNDb2xvclZhbGlkID0gISFDT0xPUlNbbXlDb2xvcl07XG4gKlxuICogVGhlIGxhc3QgbGluZSBjb3VsZCBub3QgYmUgcGVyZm9ybWVkIGlmIHRoZSB2YWx1ZXMgb2YgdGhlIGdlbmVyYXRlZCBlbnVtIHdlcmVcbiAqIG5vdCBlcXVhbCB0byB0aGVpciBrZXlzLlxuICpcbiAqICAgSW5wdXQ6ICB7a2V5MTogdmFsMSwga2V5MjogdmFsMn1cbiAqICAgT3V0cHV0OiB7a2V5MToga2V5MSwga2V5Mjoga2V5Mn1cbiAqXG4gKiBAcGFyYW0ge29iamVjdH0gb2JqXG4gKiBAcmV0dXJuIHtvYmplY3R9XG4gKi9cbnZhciBrZXlNaXJyb3IgPSBmdW5jdGlvbihvYmopIHtcbiAgdmFyIHJldCA9IHt9O1xuICB2YXIga2V5O1xuICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgIG9iaiBpbnN0YW5jZW9mIE9iamVjdCAmJiAhQXJyYXkuaXNBcnJheShvYmopLFxuICAgICdrZXlNaXJyb3IoLi4uKTogQXJndW1lbnQgbXVzdCBiZSBhbiBvYmplY3QuJ1xuICApIDogaW52YXJpYW50KG9iaiBpbnN0YW5jZW9mIE9iamVjdCAmJiAhQXJyYXkuaXNBcnJheShvYmopKSk7XG4gIGZvciAoa2V5IGluIG9iaikge1xuICAgIGlmICghb2JqLmhhc093blByb3BlcnR5KGtleSkpIHtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cbiAgICByZXRba2V5XSA9IGtleTtcbiAgfVxuICByZXR1cm4gcmV0O1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSBrZXlNaXJyb3I7XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKCdfcHJvY2VzcycpKSIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBrZXlPZlxuICovXG5cbi8qKlxuICogQWxsb3dzIGV4dHJhY3Rpb24gb2YgYSBtaW5pZmllZCBrZXkuIExldCdzIHRoZSBidWlsZCBzeXN0ZW0gbWluaWZ5IGtleXNcbiAqIHdpdGhvdXQgbG9vc2luZyB0aGUgYWJpbGl0eSB0byBkeW5hbWljYWxseSB1c2Uga2V5IHN0cmluZ3MgYXMgdmFsdWVzXG4gKiB0aGVtc2VsdmVzLiBQYXNzIGluIGFuIG9iamVjdCB3aXRoIGEgc2luZ2xlIGtleS92YWwgcGFpciBhbmQgaXQgd2lsbCByZXR1cm5cbiAqIHlvdSB0aGUgc3RyaW5nIGtleSBvZiB0aGF0IHNpbmdsZSByZWNvcmQuIFN1cHBvc2UgeW91IHdhbnQgdG8gZ3JhYiB0aGVcbiAqIHZhbHVlIGZvciBhIGtleSAnY2xhc3NOYW1lJyBpbnNpZGUgb2YgYW4gb2JqZWN0LiBLZXkvdmFsIG1pbmlmaWNhdGlvbiBtYXlcbiAqIGhhdmUgYWxpYXNlZCB0aGF0IGtleSB0byBiZSAneGExMicuIGtleU9mKHtjbGFzc05hbWU6IG51bGx9KSB3aWxsIHJldHVyblxuICogJ3hhMTInIGluIHRoYXQgY2FzZS4gUmVzb2x2ZSBrZXlzIHlvdSB3YW50IHRvIHVzZSBvbmNlIGF0IHN0YXJ0dXAgdGltZSwgdGhlblxuICogcmV1c2UgdGhvc2UgcmVzb2x1dGlvbnMuXG4gKi9cbnZhciBrZXlPZiA9IGZ1bmN0aW9uKG9uZUtleU9iaikge1xuICB2YXIga2V5O1xuICBmb3IgKGtleSBpbiBvbmVLZXlPYmopIHtcbiAgICBpZiAoIW9uZUtleU9iai5oYXNPd25Qcm9wZXJ0eShrZXkpKSB7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG4gICAgcmV0dXJuIGtleTtcbiAgfVxuICByZXR1cm4gbnVsbDtcbn07XG5cblxubW9kdWxlLmV4cG9ydHMgPSBrZXlPZjtcbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBtYXBPYmplY3RcbiAqL1xuXG4ndXNlIHN0cmljdCc7XG5cbnZhciBoYXNPd25Qcm9wZXJ0eSA9IE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHk7XG5cbi8qKlxuICogRXhlY3V0ZXMgdGhlIHByb3ZpZGVkIGBjYWxsYmFja2Agb25jZSBmb3IgZWFjaCBlbnVtZXJhYmxlIG93biBwcm9wZXJ0eSBpbiB0aGVcbiAqIG9iamVjdCBhbmQgY29uc3RydWN0cyBhIG5ldyBvYmplY3QgZnJvbSB0aGUgcmVzdWx0cy4gVGhlIGBjYWxsYmFja2AgaXNcbiAqIGludm9rZWQgd2l0aCB0aHJlZSBhcmd1bWVudHM6XG4gKlxuICogIC0gdGhlIHByb3BlcnR5IHZhbHVlXG4gKiAgLSB0aGUgcHJvcGVydHkgbmFtZVxuICogIC0gdGhlIG9iamVjdCBiZWluZyB0cmF2ZXJzZWRcbiAqXG4gKiBQcm9wZXJ0aWVzIHRoYXQgYXJlIGFkZGVkIGFmdGVyIHRoZSBjYWxsIHRvIGBtYXBPYmplY3RgIHdpbGwgbm90IGJlIHZpc2l0ZWRcbiAqIGJ5IGBjYWxsYmFja2AuIElmIHRoZSB2YWx1ZXMgb2YgZXhpc3RpbmcgcHJvcGVydGllcyBhcmUgY2hhbmdlZCwgdGhlIHZhbHVlXG4gKiBwYXNzZWQgdG8gYGNhbGxiYWNrYCB3aWxsIGJlIHRoZSB2YWx1ZSBhdCB0aGUgdGltZSBgbWFwT2JqZWN0YCB2aXNpdHMgdGhlbS5cbiAqIFByb3BlcnRpZXMgdGhhdCBhcmUgZGVsZXRlZCBiZWZvcmUgYmVpbmcgdmlzaXRlZCBhcmUgbm90IHZpc2l0ZWQuXG4gKlxuICogQGdyZXAgZnVuY3Rpb24gb2JqZWN0TWFwKClcbiAqIEBncmVwIGZ1bmN0aW9uIG9iak1hcCgpXG4gKlxuICogQHBhcmFtIHs/b2JqZWN0fSBvYmplY3RcbiAqIEBwYXJhbSB7ZnVuY3Rpb259IGNhbGxiYWNrXG4gKiBAcGFyYW0geyp9IGNvbnRleHRcbiAqIEByZXR1cm4gez9vYmplY3R9XG4gKi9cbmZ1bmN0aW9uIG1hcE9iamVjdChvYmplY3QsIGNhbGxiYWNrLCBjb250ZXh0KSB7XG4gIGlmICghb2JqZWN0KSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cbiAgdmFyIHJlc3VsdCA9IHt9O1xuICBmb3IgKHZhciBuYW1lIGluIG9iamVjdCkge1xuICAgIGlmIChoYXNPd25Qcm9wZXJ0eS5jYWxsKG9iamVjdCwgbmFtZSkpIHtcbiAgICAgIHJlc3VsdFtuYW1lXSA9IGNhbGxiYWNrLmNhbGwoY29udGV4dCwgb2JqZWN0W25hbWVdLCBuYW1lLCBvYmplY3QpO1xuICAgIH1cbiAgfVxuICByZXR1cm4gcmVzdWx0O1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IG1hcE9iamVjdDtcbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBtZW1vaXplU3RyaW5nT25seVxuICogQHR5cGVjaGVja3Mgc3RhdGljLW9ubHlcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxuLyoqXG4gKiBNZW1vaXplcyB0aGUgcmV0dXJuIHZhbHVlIG9mIGEgZnVuY3Rpb24gdGhhdCBhY2NlcHRzIG9uZSBzdHJpbmcgYXJndW1lbnQuXG4gKlxuICogQHBhcmFtIHtmdW5jdGlvbn0gY2FsbGJhY2tcbiAqIEByZXR1cm4ge2Z1bmN0aW9ufVxuICovXG5mdW5jdGlvbiBtZW1vaXplU3RyaW5nT25seShjYWxsYmFjaykge1xuICB2YXIgY2FjaGUgPSB7fTtcbiAgcmV0dXJuIGZ1bmN0aW9uKHN0cmluZykge1xuICAgIGlmIChjYWNoZS5oYXNPd25Qcm9wZXJ0eShzdHJpbmcpKSB7XG4gICAgICByZXR1cm4gY2FjaGVbc3RyaW5nXTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIGNhY2hlW3N0cmluZ10gPSBjYWxsYmFjay5jYWxsKHRoaXMsIHN0cmluZyk7XG4gICAgfVxuICB9O1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IG1lbW9pemVTdHJpbmdPbmx5O1xuIiwiKGZ1bmN0aW9uIChwcm9jZXNzKXtcbi8qKlxuICogQ29weXJpZ2h0IDIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgbW9uaXRvckNvZGVVc2VcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIGludmFyaWFudCA9IHJlcXVpcmUoXCIuL2ludmFyaWFudFwiKTtcblxuLyoqXG4gKiBQcm92aWRlcyBvcGVuLXNvdXJjZSBjb21wYXRpYmxlIGluc3RydW1lbnRhdGlvbiBmb3IgbW9uaXRvcmluZyBjZXJ0YWluIEFQSVxuICogdXNlcyBiZWZvcmUgd2UncmUgcmVhZHkgdG8gaXNzdWUgYSB3YXJuaW5nIG9yIHJlZmFjdG9yLiBJdCBhY2NlcHRzIGFuIGV2ZW50XG4gKiBuYW1lIHdoaWNoIG1heSBvbmx5IGNvbnRhaW4gdGhlIGNoYXJhY3RlcnMgW2EtejAtOV9dIGFuZCBhbiBvcHRpb25hbCBkYXRhXG4gKiBvYmplY3Qgd2l0aCBmdXJ0aGVyIGluZm9ybWF0aW9uLlxuICovXG5cbmZ1bmN0aW9uIG1vbml0b3JDb2RlVXNlKGV2ZW50TmFtZSwgZGF0YSkge1xuICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgIGV2ZW50TmFtZSAmJiAhL1teYS16MC05X10vLnRlc3QoZXZlbnROYW1lKSxcbiAgICAnWW91IG11c3QgcHJvdmlkZSBhbiBldmVudE5hbWUgdXNpbmcgb25seSB0aGUgY2hhcmFjdGVycyBbYS16MC05X10nXG4gICkgOiBpbnZhcmlhbnQoZXZlbnROYW1lICYmICEvW15hLXowLTlfXS8udGVzdChldmVudE5hbWUpKSk7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gbW9uaXRvckNvZGVVc2U7XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKCdfcHJvY2VzcycpKSIsIihmdW5jdGlvbiAocHJvY2Vzcyl7XG4vKipcbiAqIENvcHlyaWdodCAyMDEzLTIwMTQsIEZhY2Vib29rLCBJbmMuXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIEJTRC1zdHlsZSBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLiBBbiBhZGRpdGlvbmFsIGdyYW50XG4gKiBvZiBwYXRlbnQgcmlnaHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgUEFURU5UUyBmaWxlIGluIHRoZSBzYW1lIGRpcmVjdG9yeS5cbiAqXG4gKiBAcHJvdmlkZXNNb2R1bGUgb25seUNoaWxkXG4gKi9cblwidXNlIHN0cmljdFwiO1xuXG52YXIgUmVhY3RFbGVtZW50ID0gcmVxdWlyZShcIi4vUmVhY3RFbGVtZW50XCIpO1xuXG52YXIgaW52YXJpYW50ID0gcmVxdWlyZShcIi4vaW52YXJpYW50XCIpO1xuXG4vKipcbiAqIFJldHVybnMgdGhlIGZpcnN0IGNoaWxkIGluIGEgY29sbGVjdGlvbiBvZiBjaGlsZHJlbiBhbmQgdmVyaWZpZXMgdGhhdCB0aGVyZVxuICogaXMgb25seSBvbmUgY2hpbGQgaW4gdGhlIGNvbGxlY3Rpb24uIFRoZSBjdXJyZW50IGltcGxlbWVudGF0aW9uIG9mIHRoaXNcbiAqIGZ1bmN0aW9uIGFzc3VtZXMgdGhhdCBhIHNpbmdsZSBjaGlsZCBnZXRzIHBhc3NlZCB3aXRob3V0IGEgd3JhcHBlciwgYnV0IHRoZVxuICogcHVycG9zZSBvZiB0aGlzIGhlbHBlciBmdW5jdGlvbiBpcyB0byBhYnN0cmFjdCBhd2F5IHRoZSBwYXJ0aWN1bGFyIHN0cnVjdHVyZVxuICogb2YgY2hpbGRyZW4uXG4gKlxuICogQHBhcmFtIHs/b2JqZWN0fSBjaGlsZHJlbiBDaGlsZCBjb2xsZWN0aW9uIHN0cnVjdHVyZS5cbiAqIEByZXR1cm4ge1JlYWN0Q29tcG9uZW50fSBUaGUgZmlyc3QgYW5kIG9ubHkgYFJlYWN0Q29tcG9uZW50YCBjb250YWluZWQgaW4gdGhlXG4gKiBzdHJ1Y3R1cmUuXG4gKi9cbmZ1bmN0aW9uIG9ubHlDaGlsZChjaGlsZHJlbikge1xuICAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WID8gaW52YXJpYW50KFxuICAgIFJlYWN0RWxlbWVudC5pc1ZhbGlkRWxlbWVudChjaGlsZHJlbiksXG4gICAgJ29ubHlDaGlsZCBtdXN0IGJlIHBhc3NlZCBhIGNoaWxkcmVuIHdpdGggZXhhY3RseSBvbmUgY2hpbGQuJ1xuICApIDogaW52YXJpYW50KFJlYWN0RWxlbWVudC5pc1ZhbGlkRWxlbWVudChjaGlsZHJlbikpKTtcbiAgcmV0dXJuIGNoaWxkcmVuO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IG9ubHlDaGlsZDtcblxufSkuY2FsbCh0aGlzLHJlcXVpcmUoJ19wcm9jZXNzJykpIiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIHBlcmZvcm1hbmNlXG4gKiBAdHlwZWNoZWNrc1xuICovXG5cblwidXNlIHN0cmljdFwiO1xuXG52YXIgRXhlY3V0aW9uRW52aXJvbm1lbnQgPSByZXF1aXJlKFwiLi9FeGVjdXRpb25FbnZpcm9ubWVudFwiKTtcblxudmFyIHBlcmZvcm1hbmNlO1xuXG5pZiAoRXhlY3V0aW9uRW52aXJvbm1lbnQuY2FuVXNlRE9NKSB7XG4gIHBlcmZvcm1hbmNlID1cbiAgICB3aW5kb3cucGVyZm9ybWFuY2UgfHxcbiAgICB3aW5kb3cubXNQZXJmb3JtYW5jZSB8fFxuICAgIHdpbmRvdy53ZWJraXRQZXJmb3JtYW5jZTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBwZXJmb3JtYW5jZSB8fCB7fTtcbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBwZXJmb3JtYW5jZU5vd1xuICogQHR5cGVjaGVja3NcbiAqL1xuXG52YXIgcGVyZm9ybWFuY2UgPSByZXF1aXJlKFwiLi9wZXJmb3JtYW5jZVwiKTtcblxuLyoqXG4gKiBEZXRlY3QgaWYgd2UgY2FuIHVzZSBgd2luZG93LnBlcmZvcm1hbmNlLm5vdygpYCBhbmQgZ3JhY2VmdWxseSBmYWxsYmFjayB0b1xuICogYERhdGUubm93KClgIGlmIGl0IGRvZXNuJ3QgZXhpc3QuIFdlIG5lZWQgdG8gc3VwcG9ydCBGaXJlZm94IDwgMTUgZm9yIG5vd1xuICogYmVjYXVzZSBvZiBGYWNlYm9vaydzIHRlc3RpbmcgaW5mcmFzdHJ1Y3R1cmUuXG4gKi9cbmlmICghcGVyZm9ybWFuY2UgfHwgIXBlcmZvcm1hbmNlLm5vdykge1xuICBwZXJmb3JtYW5jZSA9IERhdGU7XG59XG5cbnZhciBwZXJmb3JtYW5jZU5vdyA9IHBlcmZvcm1hbmNlLm5vdy5iaW5kKHBlcmZvcm1hbmNlKTtcblxubW9kdWxlLmV4cG9ydHMgPSBwZXJmb3JtYW5jZU5vdztcbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBzZXRJbm5lckhUTUxcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIEV4ZWN1dGlvbkVudmlyb25tZW50ID0gcmVxdWlyZShcIi4vRXhlY3V0aW9uRW52aXJvbm1lbnRcIik7XG5cbnZhciBXSElURVNQQUNFX1RFU1QgPSAvXlsgXFxyXFxuXFx0XFxmXS87XG52YXIgTk9OVklTSUJMRV9URVNUID0gLzwoIS0tfGxpbmt8bm9zY3JpcHR8bWV0YXxzY3JpcHR8c3R5bGUpWyBcXHJcXG5cXHRcXGZcXC8+XS87XG5cbi8qKlxuICogU2V0IHRoZSBpbm5lckhUTUwgcHJvcGVydHkgb2YgYSBub2RlLCBlbnN1cmluZyB0aGF0IHdoaXRlc3BhY2UgaXMgcHJlc2VydmVkXG4gKiBldmVuIGluIElFOC5cbiAqXG4gKiBAcGFyYW0ge0RPTUVsZW1lbnR9IG5vZGVcbiAqIEBwYXJhbSB7c3RyaW5nfSBodG1sXG4gKiBAaW50ZXJuYWxcbiAqL1xudmFyIHNldElubmVySFRNTCA9IGZ1bmN0aW9uKG5vZGUsIGh0bWwpIHtcbiAgbm9kZS5pbm5lckhUTUwgPSBodG1sO1xufTtcblxuaWYgKEV4ZWN1dGlvbkVudmlyb25tZW50LmNhblVzZURPTSkge1xuICAvLyBJRTg6IFdoZW4gdXBkYXRpbmcgYSBqdXN0IGNyZWF0ZWQgbm9kZSB3aXRoIGlubmVySFRNTCBvbmx5IGxlYWRpbmdcbiAgLy8gd2hpdGVzcGFjZSBpcyByZW1vdmVkLiBXaGVuIHVwZGF0aW5nIGFuIGV4aXN0aW5nIG5vZGUgd2l0aCBpbm5lckhUTUxcbiAgLy8gd2hpdGVzcGFjZSBpbiByb290IFRleHROb2RlcyBpcyBhbHNvIGNvbGxhcHNlZC5cbiAgLy8gQHNlZSBxdWlya3Ntb2RlLm9yZy9idWdyZXBvcnRzL2FyY2hpdmVzLzIwMDQvMTEvaW5uZXJodG1sX2FuZF90Lmh0bWxcblxuICAvLyBGZWF0dXJlIGRldGVjdGlvbjsgb25seSBJRTggaXMga25vd24gdG8gYmVoYXZlIGltcHJvcGVybHkgbGlrZSB0aGlzLlxuICB2YXIgdGVzdEVsZW1lbnQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKTtcbiAgdGVzdEVsZW1lbnQuaW5uZXJIVE1MID0gJyAnO1xuICBpZiAodGVzdEVsZW1lbnQuaW5uZXJIVE1MID09PSAnJykge1xuICAgIHNldElubmVySFRNTCA9IGZ1bmN0aW9uKG5vZGUsIGh0bWwpIHtcbiAgICAgIC8vIE1hZ2ljIHRoZW9yeTogSUU4IHN1cHBvc2VkbHkgZGlmZmVyZW50aWF0ZXMgYmV0d2VlbiBhZGRlZCBhbmQgdXBkYXRlZFxuICAgICAgLy8gbm9kZXMgd2hlbiBwcm9jZXNzaW5nIGlubmVySFRNTCwgaW5uZXJIVE1MIG9uIHVwZGF0ZWQgbm9kZXMgc3VmZmVyc1xuICAgICAgLy8gZnJvbSB3b3JzZSB3aGl0ZXNwYWNlIGJlaGF2aW9yLiBSZS1hZGRpbmcgYSBub2RlIGxpa2UgdGhpcyB0cmlnZ2Vyc1xuICAgICAgLy8gdGhlIGluaXRpYWwgYW5kIG1vcmUgZmF2b3JhYmxlIHdoaXRlc3BhY2UgYmVoYXZpb3IuXG4gICAgICAvLyBUT0RPOiBXaGF0IHRvIGRvIG9uIGEgZGV0YWNoZWQgbm9kZT9cbiAgICAgIGlmIChub2RlLnBhcmVudE5vZGUpIHtcbiAgICAgICAgbm9kZS5wYXJlbnROb2RlLnJlcGxhY2VDaGlsZChub2RlLCBub2RlKTtcbiAgICAgIH1cblxuICAgICAgLy8gV2UgYWxzbyBpbXBsZW1lbnQgYSB3b3JrYXJvdW5kIGZvciBub24tdmlzaWJsZSB0YWdzIGRpc2FwcGVhcmluZyBpbnRvXG4gICAgICAvLyB0aGluIGFpciBvbiBJRTgsIHRoaXMgb25seSBoYXBwZW5zIGlmIHRoZXJlIGlzIG5vIHZpc2libGUgdGV4dFxuICAgICAgLy8gaW4tZnJvbnQgb2YgdGhlIG5vbi12aXNpYmxlIHRhZ3MuIFBpZ2d5YmFjayBvbiB0aGUgd2hpdGVzcGFjZSBmaXhcbiAgICAgIC8vIGFuZCBzaW1wbHkgY2hlY2sgaWYgYW55IG5vbi12aXNpYmxlIHRhZ3MgYXBwZWFyIGluIHRoZSBzb3VyY2UuXG4gICAgICBpZiAoV0hJVEVTUEFDRV9URVNULnRlc3QoaHRtbCkgfHxcbiAgICAgICAgICBodG1sWzBdID09PSAnPCcgJiYgTk9OVklTSUJMRV9URVNULnRlc3QoaHRtbCkpIHtcbiAgICAgICAgLy8gUmVjb3ZlciBsZWFkaW5nIHdoaXRlc3BhY2UgYnkgdGVtcG9yYXJpbHkgcHJlcGVuZGluZyBhbnkgY2hhcmFjdGVyLlxuICAgICAgICAvLyBcXHVGRUZGIGhhcyB0aGUgcG90ZW50aWFsIGFkdmFudGFnZSBvZiBiZWluZyB6ZXJvLXdpZHRoL2ludmlzaWJsZS5cbiAgICAgICAgbm9kZS5pbm5lckhUTUwgPSAnXFx1RkVGRicgKyBodG1sO1xuXG4gICAgICAgIC8vIGRlbGV0ZURhdGEgbGVhdmVzIGFuIGVtcHR5IGBUZXh0Tm9kZWAgd2hpY2ggb2Zmc2V0cyB0aGUgaW5kZXggb2YgYWxsXG4gICAgICAgIC8vIGNoaWxkcmVuLiBEZWZpbml0ZWx5IHdhbnQgdG8gYXZvaWQgdGhpcy5cbiAgICAgICAgdmFyIHRleHROb2RlID0gbm9kZS5maXJzdENoaWxkO1xuICAgICAgICBpZiAodGV4dE5vZGUuZGF0YS5sZW5ndGggPT09IDEpIHtcbiAgICAgICAgICBub2RlLnJlbW92ZUNoaWxkKHRleHROb2RlKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB0ZXh0Tm9kZS5kZWxldGVEYXRhKDAsIDEpO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBub2RlLmlubmVySFRNTCA9IGh0bWw7XG4gICAgICB9XG4gICAgfTtcbiAgfVxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHNldElubmVySFRNTDtcbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBzaGFsbG93RXF1YWxcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxuLyoqXG4gKiBQZXJmb3JtcyBlcXVhbGl0eSBieSBpdGVyYXRpbmcgdGhyb3VnaCBrZXlzIG9uIGFuIG9iamVjdCBhbmQgcmV0dXJuaW5nXG4gKiBmYWxzZSB3aGVuIGFueSBrZXkgaGFzIHZhbHVlcyB3aGljaCBhcmUgbm90IHN0cmljdGx5IGVxdWFsIGJldHdlZW5cbiAqIG9iakEgYW5kIG9iakIuIFJldHVybnMgdHJ1ZSB3aGVuIHRoZSB2YWx1ZXMgb2YgYWxsIGtleXMgYXJlIHN0cmljdGx5IGVxdWFsLlxuICpcbiAqIEByZXR1cm4ge2Jvb2xlYW59XG4gKi9cbmZ1bmN0aW9uIHNoYWxsb3dFcXVhbChvYmpBLCBvYmpCKSB7XG4gIGlmIChvYmpBID09PSBvYmpCKSB7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cbiAgdmFyIGtleTtcbiAgLy8gVGVzdCBmb3IgQSdzIGtleXMgZGlmZmVyZW50IGZyb20gQi5cbiAgZm9yIChrZXkgaW4gb2JqQSkge1xuICAgIGlmIChvYmpBLmhhc093blByb3BlcnR5KGtleSkgJiZcbiAgICAgICAgKCFvYmpCLmhhc093blByb3BlcnR5KGtleSkgfHwgb2JqQVtrZXldICE9PSBvYmpCW2tleV0pKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICB9XG4gIC8vIFRlc3QgZm9yIEIncyBrZXlzIG1pc3NpbmcgZnJvbSBBLlxuICBmb3IgKGtleSBpbiBvYmpCKSB7XG4gICAgaWYgKG9iakIuaGFzT3duUHJvcGVydHkoa2V5KSAmJiAhb2JqQS5oYXNPd25Qcm9wZXJ0eShrZXkpKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICB9XG4gIHJldHVybiB0cnVlO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHNoYWxsb3dFcXVhbDtcbiIsIi8qKlxuICogQ29weXJpZ2h0IDIwMTMtMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSBzaG91bGRVcGRhdGVSZWFjdENvbXBvbmVudFxuICogQHR5cGVjaGVja3Mgc3RhdGljLW9ubHlcbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxuLyoqXG4gKiBHaXZlbiBhIGBwcmV2RWxlbWVudGAgYW5kIGBuZXh0RWxlbWVudGAsIGRldGVybWluZXMgaWYgdGhlIGV4aXN0aW5nXG4gKiBpbnN0YW5jZSBzaG91bGQgYmUgdXBkYXRlZCBhcyBvcHBvc2VkIHRvIGJlaW5nIGRlc3Ryb3llZCBvciByZXBsYWNlZCBieSBhIG5ld1xuICogaW5zdGFuY2UuIEJvdGggYXJndW1lbnRzIGFyZSBlbGVtZW50cy4gVGhpcyBlbnN1cmVzIHRoYXQgdGhpcyBsb2dpYyBjYW5cbiAqIG9wZXJhdGUgb24gc3RhdGVsZXNzIHRyZWVzIHdpdGhvdXQgYW55IGJhY2tpbmcgaW5zdGFuY2UuXG4gKlxuICogQHBhcmFtIHs/b2JqZWN0fSBwcmV2RWxlbWVudFxuICogQHBhcmFtIHs/b2JqZWN0fSBuZXh0RWxlbWVudFxuICogQHJldHVybiB7Ym9vbGVhbn0gVHJ1ZSBpZiB0aGUgZXhpc3RpbmcgaW5zdGFuY2Ugc2hvdWxkIGJlIHVwZGF0ZWQuXG4gKiBAcHJvdGVjdGVkXG4gKi9cbmZ1bmN0aW9uIHNob3VsZFVwZGF0ZVJlYWN0Q29tcG9uZW50KHByZXZFbGVtZW50LCBuZXh0RWxlbWVudCkge1xuICBpZiAocHJldkVsZW1lbnQgJiYgbmV4dEVsZW1lbnQgJiZcbiAgICAgIHByZXZFbGVtZW50LnR5cGUgPT09IG5leHRFbGVtZW50LnR5cGUgJiZcbiAgICAgIHByZXZFbGVtZW50LmtleSA9PT0gbmV4dEVsZW1lbnQua2V5ICYmXG4gICAgICBwcmV2RWxlbWVudC5fb3duZXIgPT09IG5leHRFbGVtZW50Ll9vd25lcikge1xuICAgIHJldHVybiB0cnVlO1xuICB9XG4gIHJldHVybiBmYWxzZTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBzaG91bGRVcGRhdGVSZWFjdENvbXBvbmVudDtcbiIsIihmdW5jdGlvbiAocHJvY2Vzcyl7XG4vKipcbiAqIENvcHlyaWdodCAyMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIHRvQXJyYXlcbiAqIEB0eXBlY2hlY2tzXG4gKi9cblxudmFyIGludmFyaWFudCA9IHJlcXVpcmUoXCIuL2ludmFyaWFudFwiKTtcblxuLyoqXG4gKiBDb252ZXJ0IGFycmF5LWxpa2Ugb2JqZWN0cyB0byBhcnJheXMuXG4gKlxuICogVGhpcyBBUEkgYXNzdW1lcyB0aGUgY2FsbGVyIGtub3dzIHRoZSBjb250ZW50cyBvZiB0aGUgZGF0YSB0eXBlLiBGb3IgbGVzc1xuICogd2VsbCBkZWZpbmVkIGlucHV0cyB1c2UgY3JlYXRlQXJyYXlGcm9tLlxuICpcbiAqIEBwYXJhbSB7b2JqZWN0fGZ1bmN0aW9ufGZpbGVsaXN0fSBvYmpcbiAqIEByZXR1cm4ge2FycmF5fVxuICovXG5mdW5jdGlvbiB0b0FycmF5KG9iaikge1xuICB2YXIgbGVuZ3RoID0gb2JqLmxlbmd0aDtcblxuICAvLyBTb21lIGJyb3dzZSBidWlsdGluIG9iamVjdHMgY2FuIHJlcG9ydCB0eXBlb2YgJ2Z1bmN0aW9uJyAoZS5nLiBOb2RlTGlzdCBpblxuICAvLyBvbGQgdmVyc2lvbnMgb2YgU2FmYXJpKS5cbiAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAhQXJyYXkuaXNBcnJheShvYmopICYmXG4gICAgKHR5cGVvZiBvYmogPT09ICdvYmplY3QnIHx8IHR5cGVvZiBvYmogPT09ICdmdW5jdGlvbicpLFxuICAgICd0b0FycmF5OiBBcnJheS1saWtlIG9iamVjdCBleHBlY3RlZCdcbiAgKSA6IGludmFyaWFudCghQXJyYXkuaXNBcnJheShvYmopICYmXG4gICh0eXBlb2Ygb2JqID09PSAnb2JqZWN0JyB8fCB0eXBlb2Ygb2JqID09PSAnZnVuY3Rpb24nKSkpO1xuXG4gIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgdHlwZW9mIGxlbmd0aCA9PT0gJ251bWJlcicsXG4gICAgJ3RvQXJyYXk6IE9iamVjdCBuZWVkcyBhIGxlbmd0aCBwcm9wZXJ0eSdcbiAgKSA6IGludmFyaWFudCh0eXBlb2YgbGVuZ3RoID09PSAnbnVtYmVyJykpO1xuXG4gIChcInByb2R1Y3Rpb25cIiAhPT0gcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPyBpbnZhcmlhbnQoXG4gICAgbGVuZ3RoID09PSAwIHx8XG4gICAgKGxlbmd0aCAtIDEpIGluIG9iaixcbiAgICAndG9BcnJheTogT2JqZWN0IHNob3VsZCBoYXZlIGtleXMgZm9yIGluZGljZXMnXG4gICkgOiBpbnZhcmlhbnQobGVuZ3RoID09PSAwIHx8XG4gIChsZW5ndGggLSAxKSBpbiBvYmopKTtcblxuICAvLyBPbGQgSUUgZG9lc24ndCBnaXZlIGNvbGxlY3Rpb25zIGFjY2VzcyB0byBoYXNPd25Qcm9wZXJ0eS4gQXNzdW1lIGlucHV0c1xuICAvLyB3aXRob3V0IG1ldGhvZCB3aWxsIHRocm93IGR1cmluZyB0aGUgc2xpY2UgY2FsbCBhbmQgc2tpcCBzdHJhaWdodCB0byB0aGVcbiAgLy8gZmFsbGJhY2suXG4gIGlmIChvYmouaGFzT3duUHJvcGVydHkpIHtcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKG9iaik7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgLy8gSUUgPCA5IGRvZXMgbm90IHN1cHBvcnQgQXJyYXkjc2xpY2Ugb24gY29sbGVjdGlvbnMgb2JqZWN0c1xuICAgIH1cbiAgfVxuXG4gIC8vIEZhbGwgYmFjayB0byBjb3B5aW5nIGtleSBieSBrZXkuIFRoaXMgYXNzdW1lcyBhbGwga2V5cyBoYXZlIGEgdmFsdWUsXG4gIC8vIHNvIHdpbGwgbm90IHByZXNlcnZlIHNwYXJzZWx5IHBvcHVsYXRlZCBpbnB1dHMuXG4gIHZhciByZXQgPSBBcnJheShsZW5ndGgpO1xuICBmb3IgKHZhciBpaSA9IDA7IGlpIDwgbGVuZ3RoOyBpaSsrKSB7XG4gICAgcmV0W2lpXSA9IG9ialtpaV07XG4gIH1cbiAgcmV0dXJuIHJldDtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSB0b0FycmF5O1xuXG59KS5jYWxsKHRoaXMscmVxdWlyZSgnX3Byb2Nlc3MnKSkiLCIoZnVuY3Rpb24gKHByb2Nlc3Mpe1xuLyoqXG4gKiBDb3B5cmlnaHQgMjAxMy0yMDE0LCBGYWNlYm9vaywgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBCU0Qtc3R5bGUgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS4gQW4gYWRkaXRpb25hbCBncmFudFxuICogb2YgcGF0ZW50IHJpZ2h0cyBjYW4gYmUgZm91bmQgaW4gdGhlIFBBVEVOVFMgZmlsZSBpbiB0aGUgc2FtZSBkaXJlY3RvcnkuXG4gKlxuICogQHByb3ZpZGVzTW9kdWxlIHRyYXZlcnNlQWxsQ2hpbGRyZW5cbiAqL1xuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIFJlYWN0RWxlbWVudCA9IHJlcXVpcmUoXCIuL1JlYWN0RWxlbWVudFwiKTtcbnZhciBSZWFjdEluc3RhbmNlSGFuZGxlcyA9IHJlcXVpcmUoXCIuL1JlYWN0SW5zdGFuY2VIYW5kbGVzXCIpO1xuXG52YXIgaW52YXJpYW50ID0gcmVxdWlyZShcIi4vaW52YXJpYW50XCIpO1xuXG52YXIgU0VQQVJBVE9SID0gUmVhY3RJbnN0YW5jZUhhbmRsZXMuU0VQQVJBVE9SO1xudmFyIFNVQlNFUEFSQVRPUiA9ICc6JztcblxuLyoqXG4gKiBUT0RPOiBUZXN0IHRoYXQ6XG4gKiAxLiBgbWFwQ2hpbGRyZW5gIHRyYW5zZm9ybXMgc3RyaW5ncyBhbmQgbnVtYmVycyBpbnRvIGBSZWFjdFRleHRDb21wb25lbnRgLlxuICogMi4gaXQoJ3Nob3VsZCBmYWlsIHdoZW4gc3VwcGxpZWQgZHVwbGljYXRlIGtleScsIGZ1bmN0aW9uKCkge1xuICogMy4gVGhhdCBhIHNpbmdsZSBjaGlsZCBhbmQgYW4gYXJyYXkgd2l0aCBvbmUgaXRlbSBoYXZlIHRoZSBzYW1lIGtleSBwYXR0ZXJuLlxuICogfSk7XG4gKi9cblxudmFyIHVzZXJQcm92aWRlZEtleUVzY2FwZXJMb29rdXAgPSB7XG4gICc9JzogJz0wJyxcbiAgJy4nOiAnPTEnLFxuICAnOic6ICc9Midcbn07XG5cbnZhciB1c2VyUHJvdmlkZWRLZXlFc2NhcGVSZWdleCA9IC9bPS46XS9nO1xuXG5mdW5jdGlvbiB1c2VyUHJvdmlkZWRLZXlFc2NhcGVyKG1hdGNoKSB7XG4gIHJldHVybiB1c2VyUHJvdmlkZWRLZXlFc2NhcGVyTG9va3VwW21hdGNoXTtcbn1cblxuLyoqXG4gKiBHZW5lcmF0ZSBhIGtleSBzdHJpbmcgdGhhdCBpZGVudGlmaWVzIGEgY29tcG9uZW50IHdpdGhpbiBhIHNldC5cbiAqXG4gKiBAcGFyYW0geyp9IGNvbXBvbmVudCBBIGNvbXBvbmVudCB0aGF0IGNvdWxkIGNvbnRhaW4gYSBtYW51YWwga2V5LlxuICogQHBhcmFtIHtudW1iZXJ9IGluZGV4IEluZGV4IHRoYXQgaXMgdXNlZCBpZiBhIG1hbnVhbCBrZXkgaXMgbm90IHByb3ZpZGVkLlxuICogQHJldHVybiB7c3RyaW5nfVxuICovXG5mdW5jdGlvbiBnZXRDb21wb25lbnRLZXkoY29tcG9uZW50LCBpbmRleCkge1xuICBpZiAoY29tcG9uZW50ICYmIGNvbXBvbmVudC5rZXkgIT0gbnVsbCkge1xuICAgIC8vIEV4cGxpY2l0IGtleVxuICAgIHJldHVybiB3cmFwVXNlclByb3ZpZGVkS2V5KGNvbXBvbmVudC5rZXkpO1xuICB9XG4gIC8vIEltcGxpY2l0IGtleSBkZXRlcm1pbmVkIGJ5IHRoZSBpbmRleCBpbiB0aGUgc2V0XG4gIHJldHVybiBpbmRleC50b1N0cmluZygzNik7XG59XG5cbi8qKlxuICogRXNjYXBlIGEgY29tcG9uZW50IGtleSBzbyB0aGF0IGl0IGlzIHNhZmUgdG8gdXNlIGluIGEgcmVhY3RpZC5cbiAqXG4gKiBAcGFyYW0geyp9IGtleSBDb21wb25lbnQga2V5IHRvIGJlIGVzY2FwZWQuXG4gKiBAcmV0dXJuIHtzdHJpbmd9IEFuIGVzY2FwZWQgc3RyaW5nLlxuICovXG5mdW5jdGlvbiBlc2NhcGVVc2VyUHJvdmlkZWRLZXkodGV4dCkge1xuICByZXR1cm4gKCcnICsgdGV4dCkucmVwbGFjZShcbiAgICB1c2VyUHJvdmlkZWRLZXlFc2NhcGVSZWdleCxcbiAgICB1c2VyUHJvdmlkZWRLZXlFc2NhcGVyXG4gICk7XG59XG5cbi8qKlxuICogV3JhcCBhIGBrZXlgIHZhbHVlIGV4cGxpY2l0bHkgcHJvdmlkZWQgYnkgdGhlIHVzZXIgdG8gZGlzdGluZ3Vpc2ggaXQgZnJvbVxuICogaW1wbGljaXRseS1nZW5lcmF0ZWQga2V5cyBnZW5lcmF0ZWQgYnkgYSBjb21wb25lbnQncyBpbmRleCBpbiBpdHMgcGFyZW50LlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBrZXkgVmFsdWUgb2YgYSB1c2VyLXByb3ZpZGVkIGBrZXlgIGF0dHJpYnV0ZVxuICogQHJldHVybiB7c3RyaW5nfVxuICovXG5mdW5jdGlvbiB3cmFwVXNlclByb3ZpZGVkS2V5KGtleSkge1xuICByZXR1cm4gJyQnICsgZXNjYXBlVXNlclByb3ZpZGVkS2V5KGtleSk7XG59XG5cbi8qKlxuICogQHBhcmFtIHs/Kn0gY2hpbGRyZW4gQ2hpbGRyZW4gdHJlZSBjb250YWluZXIuXG4gKiBAcGFyYW0geyFzdHJpbmd9IG5hbWVTb0ZhciBOYW1lIG9mIHRoZSBrZXkgcGF0aCBzbyBmYXIuXG4gKiBAcGFyYW0geyFudW1iZXJ9IGluZGV4U29GYXIgTnVtYmVyIG9mIGNoaWxkcmVuIGVuY291bnRlcmVkIHVudGlsIHRoaXMgcG9pbnQuXG4gKiBAcGFyYW0geyFmdW5jdGlvbn0gY2FsbGJhY2sgQ2FsbGJhY2sgdG8gaW52b2tlIHdpdGggZWFjaCBjaGlsZCBmb3VuZC5cbiAqIEBwYXJhbSB7Pyp9IHRyYXZlcnNlQ29udGV4dCBVc2VkIHRvIHBhc3MgaW5mb3JtYXRpb24gdGhyb3VnaG91dCB0aGUgdHJhdmVyc2FsXG4gKiBwcm9jZXNzLlxuICogQHJldHVybiB7IW51bWJlcn0gVGhlIG51bWJlciBvZiBjaGlsZHJlbiBpbiB0aGlzIHN1YnRyZWUuXG4gKi9cbnZhciB0cmF2ZXJzZUFsbENoaWxkcmVuSW1wbCA9XG4gIGZ1bmN0aW9uKGNoaWxkcmVuLCBuYW1lU29GYXIsIGluZGV4U29GYXIsIGNhbGxiYWNrLCB0cmF2ZXJzZUNvbnRleHQpIHtcbiAgICB2YXIgbmV4dE5hbWUsIG5leHRJbmRleDtcbiAgICB2YXIgc3VidHJlZUNvdW50ID0gMDsgIC8vIENvdW50IG9mIGNoaWxkcmVuIGZvdW5kIGluIHRoZSBjdXJyZW50IHN1YnRyZWUuXG4gICAgaWYgKEFycmF5LmlzQXJyYXkoY2hpbGRyZW4pKSB7XG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGNoaWxkcmVuLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHZhciBjaGlsZCA9IGNoaWxkcmVuW2ldO1xuICAgICAgICBuZXh0TmFtZSA9IChcbiAgICAgICAgICBuYW1lU29GYXIgK1xuICAgICAgICAgIChuYW1lU29GYXIgPyBTVUJTRVBBUkFUT1IgOiBTRVBBUkFUT1IpICtcbiAgICAgICAgICBnZXRDb21wb25lbnRLZXkoY2hpbGQsIGkpXG4gICAgICAgICk7XG4gICAgICAgIG5leHRJbmRleCA9IGluZGV4U29GYXIgKyBzdWJ0cmVlQ291bnQ7XG4gICAgICAgIHN1YnRyZWVDb3VudCArPSB0cmF2ZXJzZUFsbENoaWxkcmVuSW1wbChcbiAgICAgICAgICBjaGlsZCxcbiAgICAgICAgICBuZXh0TmFtZSxcbiAgICAgICAgICBuZXh0SW5kZXgsXG4gICAgICAgICAgY2FsbGJhY2ssXG4gICAgICAgICAgdHJhdmVyc2VDb250ZXh0XG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHZhciB0eXBlID0gdHlwZW9mIGNoaWxkcmVuO1xuICAgICAgdmFyIGlzT25seUNoaWxkID0gbmFtZVNvRmFyID09PSAnJztcbiAgICAgIC8vIElmIGl0J3MgdGhlIG9ubHkgY2hpbGQsIHRyZWF0IHRoZSBuYW1lIGFzIGlmIGl0IHdhcyB3cmFwcGVkIGluIGFuIGFycmF5XG4gICAgICAvLyBzbyB0aGF0IGl0J3MgY29uc2lzdGVudCBpZiB0aGUgbnVtYmVyIG9mIGNoaWxkcmVuIGdyb3dzXG4gICAgICB2YXIgc3RvcmFnZU5hbWUgPVxuICAgICAgICBpc09ubHlDaGlsZCA/IFNFUEFSQVRPUiArIGdldENvbXBvbmVudEtleShjaGlsZHJlbiwgMCkgOiBuYW1lU29GYXI7XG4gICAgICBpZiAoY2hpbGRyZW4gPT0gbnVsbCB8fCB0eXBlID09PSAnYm9vbGVhbicpIHtcbiAgICAgICAgLy8gQWxsIG9mIHRoZSBhYm92ZSBhcmUgcGVyY2VpdmVkIGFzIG51bGwuXG4gICAgICAgIGNhbGxiYWNrKHRyYXZlcnNlQ29udGV4dCwgbnVsbCwgc3RvcmFnZU5hbWUsIGluZGV4U29GYXIpO1xuICAgICAgICBzdWJ0cmVlQ291bnQgPSAxO1xuICAgICAgfSBlbHNlIGlmICh0eXBlID09PSAnc3RyaW5nJyB8fCB0eXBlID09PSAnbnVtYmVyJyB8fFxuICAgICAgICAgICAgICAgICBSZWFjdEVsZW1lbnQuaXNWYWxpZEVsZW1lbnQoY2hpbGRyZW4pKSB7XG4gICAgICAgIGNhbGxiYWNrKHRyYXZlcnNlQ29udGV4dCwgY2hpbGRyZW4sIHN0b3JhZ2VOYW1lLCBpbmRleFNvRmFyKTtcbiAgICAgICAgc3VidHJlZUNvdW50ID0gMTtcbiAgICAgIH0gZWxzZSBpZiAodHlwZSA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgKFwicHJvZHVjdGlvblwiICE9PSBwcm9jZXNzLmVudi5OT0RFX0VOViA/IGludmFyaWFudChcbiAgICAgICAgICAhY2hpbGRyZW4gfHwgY2hpbGRyZW4ubm9kZVR5cGUgIT09IDEsXG4gICAgICAgICAgJ3RyYXZlcnNlQWxsQ2hpbGRyZW4oLi4uKTogRW5jb3VudGVyZWQgYW4gaW52YWxpZCBjaGlsZDsgRE9NICcgK1xuICAgICAgICAgICdlbGVtZW50cyBhcmUgbm90IHZhbGlkIGNoaWxkcmVuIG9mIFJlYWN0IGNvbXBvbmVudHMuJ1xuICAgICAgICApIDogaW52YXJpYW50KCFjaGlsZHJlbiB8fCBjaGlsZHJlbi5ub2RlVHlwZSAhPT0gMSkpO1xuICAgICAgICBmb3IgKHZhciBrZXkgaW4gY2hpbGRyZW4pIHtcbiAgICAgICAgICBpZiAoY2hpbGRyZW4uaGFzT3duUHJvcGVydHkoa2V5KSkge1xuICAgICAgICAgICAgbmV4dE5hbWUgPSAoXG4gICAgICAgICAgICAgIG5hbWVTb0ZhciArIChuYW1lU29GYXIgPyBTVUJTRVBBUkFUT1IgOiBTRVBBUkFUT1IpICtcbiAgICAgICAgICAgICAgd3JhcFVzZXJQcm92aWRlZEtleShrZXkpICsgU1VCU0VQQVJBVE9SICtcbiAgICAgICAgICAgICAgZ2V0Q29tcG9uZW50S2V5KGNoaWxkcmVuW2tleV0sIDApXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgbmV4dEluZGV4ID0gaW5kZXhTb0ZhciArIHN1YnRyZWVDb3VudDtcbiAgICAgICAgICAgIHN1YnRyZWVDb3VudCArPSB0cmF2ZXJzZUFsbENoaWxkcmVuSW1wbChcbiAgICAgICAgICAgICAgY2hpbGRyZW5ba2V5XSxcbiAgICAgICAgICAgICAgbmV4dE5hbWUsXG4gICAgICAgICAgICAgIG5leHRJbmRleCxcbiAgICAgICAgICAgICAgY2FsbGJhY2ssXG4gICAgICAgICAgICAgIHRyYXZlcnNlQ29udGV4dFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHN1YnRyZWVDb3VudDtcbiAgfTtcblxuLyoqXG4gKiBUcmF2ZXJzZXMgY2hpbGRyZW4gdGhhdCBhcmUgdHlwaWNhbGx5IHNwZWNpZmllZCBhcyBgcHJvcHMuY2hpbGRyZW5gLCBidXRcbiAqIG1pZ2h0IGFsc28gYmUgc3BlY2lmaWVkIHRocm91Z2ggYXR0cmlidXRlczpcbiAqXG4gKiAtIGB0cmF2ZXJzZUFsbENoaWxkcmVuKHRoaXMucHJvcHMuY2hpbGRyZW4sIC4uLilgXG4gKiAtIGB0cmF2ZXJzZUFsbENoaWxkcmVuKHRoaXMucHJvcHMubGVmdFBhbmVsQ2hpbGRyZW4sIC4uLilgXG4gKlxuICogVGhlIGB0cmF2ZXJzZUNvbnRleHRgIGlzIGFuIG9wdGlvbmFsIGFyZ3VtZW50IHRoYXQgaXMgcGFzc2VkIHRocm91Z2ggdGhlXG4gKiBlbnRpcmUgdHJhdmVyc2FsLiBJdCBjYW4gYmUgdXNlZCB0byBzdG9yZSBhY2N1bXVsYXRpb25zIG9yIGFueXRoaW5nIGVsc2UgdGhhdFxuICogdGhlIGNhbGxiYWNrIG1pZ2h0IGZpbmQgcmVsZXZhbnQuXG4gKlxuICogQHBhcmFtIHs/Kn0gY2hpbGRyZW4gQ2hpbGRyZW4gdHJlZSBvYmplY3QuXG4gKiBAcGFyYW0geyFmdW5jdGlvbn0gY2FsbGJhY2sgVG8gaW52b2tlIHVwb24gdHJhdmVyc2luZyBlYWNoIGNoaWxkLlxuICogQHBhcmFtIHs/Kn0gdHJhdmVyc2VDb250ZXh0IENvbnRleHQgZm9yIHRyYXZlcnNhbC5cbiAqIEByZXR1cm4geyFudW1iZXJ9IFRoZSBudW1iZXIgb2YgY2hpbGRyZW4gaW4gdGhpcyBzdWJ0cmVlLlxuICovXG5mdW5jdGlvbiB0cmF2ZXJzZUFsbENoaWxkcmVuKGNoaWxkcmVuLCBjYWxsYmFjaywgdHJhdmVyc2VDb250ZXh0KSB7XG4gIGlmIChjaGlsZHJlbiA9PSBudWxsKSB7XG4gICAgcmV0dXJuIDA7XG4gIH1cblxuICByZXR1cm4gdHJhdmVyc2VBbGxDaGlsZHJlbkltcGwoY2hpbGRyZW4sICcnLCAwLCBjYWxsYmFjaywgdHJhdmVyc2VDb250ZXh0KTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSB0cmF2ZXJzZUFsbENoaWxkcmVuO1xuXG59KS5jYWxsKHRoaXMscmVxdWlyZSgnX3Byb2Nlc3MnKSkiLCIoZnVuY3Rpb24gKHByb2Nlc3Mpe1xuLyoqXG4gKiBDb3B5cmlnaHQgMjAxNCwgRmFjZWJvb2ssIEluYy5cbiAqIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQlNELXN0eWxlIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuIEFuIGFkZGl0aW9uYWwgZ3JhbnRcbiAqIG9mIHBhdGVudCByaWdodHMgY2FuIGJlIGZvdW5kIGluIHRoZSBQQVRFTlRTIGZpbGUgaW4gdGhlIHNhbWUgZGlyZWN0b3J5LlxuICpcbiAqIEBwcm92aWRlc01vZHVsZSB3YXJuaW5nXG4gKi9cblxuXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBlbXB0eUZ1bmN0aW9uID0gcmVxdWlyZShcIi4vZW1wdHlGdW5jdGlvblwiKTtcblxuLyoqXG4gKiBTaW1pbGFyIHRvIGludmFyaWFudCBidXQgb25seSBsb2dzIGEgd2FybmluZyBpZiB0aGUgY29uZGl0aW9uIGlzIG5vdCBtZXQuXG4gKiBUaGlzIGNhbiBiZSB1c2VkIHRvIGxvZyBpc3N1ZXMgaW4gZGV2ZWxvcG1lbnQgZW52aXJvbm1lbnRzIGluIGNyaXRpY2FsXG4gKiBwYXRocy4gUmVtb3ZpbmcgdGhlIGxvZ2dpbmcgY29kZSBmb3IgcHJvZHVjdGlvbiBlbnZpcm9ubWVudHMgd2lsbCBrZWVwIHRoZVxuICogc2FtZSBsb2dpYyBhbmQgZm9sbG93IHRoZSBzYW1lIGNvZGUgcGF0aHMuXG4gKi9cblxudmFyIHdhcm5pbmcgPSBlbXB0eUZ1bmN0aW9uO1xuXG5pZiAoXCJwcm9kdWN0aW9uXCIgIT09IHByb2Nlc3MuZW52Lk5PREVfRU5WKSB7XG4gIHdhcm5pbmcgPSBmdW5jdGlvbihjb25kaXRpb24sIGZvcm1hdCApIHtmb3IgKHZhciBhcmdzPVtdLCRfXzA9MiwkX18xPWFyZ3VtZW50cy5sZW5ndGg7JF9fMDwkX18xOyRfXzArKykgYXJncy5wdXNoKGFyZ3VtZW50c1skX18wXSk7XG4gICAgaWYgKGZvcm1hdCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICdgd2FybmluZyhjb25kaXRpb24sIGZvcm1hdCwgLi4uYXJncylgIHJlcXVpcmVzIGEgd2FybmluZyAnICtcbiAgICAgICAgJ21lc3NhZ2UgYXJndW1lbnQnXG4gICAgICApO1xuICAgIH1cblxuICAgIGlmICghY29uZGl0aW9uKSB7XG4gICAgICB2YXIgYXJnSW5kZXggPSAwO1xuICAgICAgY29uc29sZS53YXJuKCdXYXJuaW5nOiAnICsgZm9ybWF0LnJlcGxhY2UoLyVzL2csIGZ1bmN0aW9uKCkgIHtyZXR1cm4gYXJnc1thcmdJbmRleCsrXTt9KSk7XG4gICAgfVxuICB9O1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHdhcm5pbmc7XG5cbn0pLmNhbGwodGhpcyxyZXF1aXJlKCdfcHJvY2VzcycpKSIsIm1vZHVsZS5leHBvcnRzID0gcmVxdWlyZSgnLi9saWIvUmVhY3QnKTtcbiIsIi8qKiBAanN4IFJlYWN0LkRPTSAqL1xudmFyIFJlYWN0ID0gcmVxdWlyZSgncmVhY3QnKSxcbi8vLyAgICBub3Rmb3VuZCA9IHJlcXVpcmUoJ05vdEZvdW5kTW9kdWxlJyksXG5cbkJ1ZyA9IFJlYWN0LmNyZWF0ZUNsYXNzKHtkaXNwbGF5TmFtZTogJ0J1ZycsXG4gICAgcmVuZGVyOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiAoXG4gICAgICAgICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KFwiZGl2XCIsIG51bGwsIFwiT0shXCIpXG4gICAgICAgICk7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gQnVnO1xuIiwiLyoqIEBqc3ggUmVhY3QuRE9NICovXG52YXIgUmVhY3QgPSByZXF1aXJlKCdyZWFjdCcpLFxuXG5MaW1pdFNlbGVjdCA9IFJlYWN0LmNyZWF0ZUNsYXNzKHtkaXNwbGF5TmFtZTogJ0xpbWl0U2VsZWN0JyxcbiAgICByZW5kZXI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIG9wdGlvbnMgPSBbXSxcbiAgICAgICAgICAgIEk7XG5cbiAgICAgICAgZm9yIChJPTA7STx0aGlzLnByb3BzLm1heDtJKyspIHtcbiAgICAgICAgICAgIG9wdGlvbnMucHVzaChcbiAgICAgICAgICAgICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KFwib3B0aW9uXCIsIG51bGwsIEkrMSlcbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gKFxuICAgICAgICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChcInNlbGVjdFwiLCBudWxsLCBcbiAgICAgICAgICAgICBvcHRpb25zXG4gICAgICAgICAgICApXG4gICAgICAgICk7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gTGltaXRTZWxlY3Q7XG4iLCIvKiogQGpzeCBSZWFjdC5ET00gKi9cbnZhciBSZWFjdCA9IHJlcXVpcmUoJ3JlYWN0JyksXG5cblBhdGggPSBSZWFjdC5jcmVhdGVDbGFzcyh7ZGlzcGxheU5hbWU6ICdQYXRoJyxcbiAgICByZW5kZXI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHBhdGhzID0gdGhpcy5wcm9wcy5wYXRoLm1hcChmdW5jdGlvbiAoUCkge1xuICAgICAgICAgICAgcmV0dXJuIChcbiAgICAgICAgICAgICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KFwibGlcIiwgbnVsbCwgUmVhY3QuY3JlYXRlRWxlbWVudChcImFcIiwge2hyZWY6ICcvY2F0ZS8nICsgUC5pZH0sIFAudGl0bGUpKVxuICAgICAgICAgICAgKTtcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiAoXG4gICAgICAgICAgICBSZWFjdC5jcmVhdGVFbGVtZW50KFwidWxcIiwge2NsYXNzTmFtZTogXCJwYXRoXCJ9LCBcbiAgICAgICAgICAgICBwYXRoc1xuICAgICAgICAgICAgKVxuICAgICAgICApO1xuICAgIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFBhdGg7XG4iLCIvKiogQGpzeCBSZWFjdC5ET00gKi9cbnZhciBSZWFjdCA9IHJlcXVpcmUoJ3JlYWN0JyksXG4gICAgTGltaXRTZWxlY3QgPSByZXF1aXJlKCcuL0xpbWl0U2VsZWN0LmpzeCcpLFxuXG5Qcm9kdWN0ID0gUmVhY3QuY3JlYXRlQ2xhc3Moe2Rpc3BsYXlOYW1lOiAnUHJvZHVjdCcsXG4gICAgZ2V0SW5pdGlhbFN0YXRlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB7c2VsZWN0ZWRTcGVjOiB0aGlzLnByb3BzLnNwZWNzWzBdLmlkfTtcbiAgICB9LFxuICAgIGhhbmRsZVNwZWNDaGFuZ2U6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7c2VsZWN0ZWRTcGVjOiBldmVudC50YXJnZXQudmFsdWV9KTtcbiAgICB9LFxuICAgIHJlbmRlcjogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgc3BlY3MgPSBbXSxcbiAgICAgICAgICAgIG1heCxcbiAgICAgICAgICAgIEk7XG5cbiAgICAgICAgZm9yIChJPTA7STx0aGlzLnByb3BzLnNwZWNzLmxlbmd0aDtJKyspIHtcbiAgICAgICAgICAgIGlmICh0aGlzLnByb3BzLnNwZWNzW0ldLmlkID09IHRoaXMuc3RhdGUuc2VsZWN0ZWRTcGVjKSB7XG4gICAgICAgICAgICAgICAgbWF4ID0gdGhpcy5wcm9wcy5zcGVjc1tJXS5saW1pdDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHNwZWNzLnB1c2goXG4gICAgICAgICAgICAgICAgUmVhY3QuY3JlYXRlRWxlbWVudChcIm9wdGlvblwiLCB7dmFsdWU6IHRoaXMucHJvcHMuc3BlY3NbSV0uaWR9LCB0aGlzLnByb3BzLnNwZWNzW0ldLnRpdGxlKVxuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiAoXG5SZWFjdC5jcmVhdGVFbGVtZW50KFwiZGl2XCIsIG51bGwsIFxuIFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJoMVwiLCBudWxsLCB0aGlzLnByb3BzLnRpdGxlKSwgXG4gUmVhY3QuY3JlYXRlRWxlbWVudChcInBcIiwgbnVsbCwgdGhpcy5wcm9wcy5kZXNjcmlwdGlvbiksIFxuIFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJzcGFuXCIsIG51bGwsIFwiUHJpY2U6IFwiLCBSZWFjdC5jcmVhdGVFbGVtZW50KFwiaVwiLCBudWxsLCBcIiRcIiksIFJlYWN0LmNyZWF0ZUVsZW1lbnQoXCJiXCIsIG51bGwsIHRoaXMucHJvcHMucHJpY2UpKSwgXG4gUmVhY3QuY3JlYXRlRWxlbWVudChcImRpdlwiLCBudWxsLCBcIlBpY2sgYSBzcGVjOlwiLCBSZWFjdC5jcmVhdGVFbGVtZW50KFwic2VsZWN0XCIsIHtvbkNoYW5nZTogdGhpcy5oYW5kbGVTcGVjQ2hhbmdlLCB2YWx1ZTogdGhpcy5zdGF0ZS5zZWxlY3RlZFNwZWN9LCBzcGVjcyksIFxuICBSZWFjdC5jcmVhdGVFbGVtZW50KExpbWl0U2VsZWN0LCB7bWF4OiBtYXh9KVxuIClcbilcbiAgICAgICAgKTtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBQcm9kdWN0O1xuIl19