Code coverage report for lib/addons/__tests__/fluxMixin-test.js

Statements: 94.98% (208 / 219)      Branches: 53.33% (16 / 30)      Functions: 100% (52 / 52)      Lines: 100% (195 / 195)      Ignored: none     

All files » lib/addons/__tests__/ » fluxMixin-test.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476    3   48   2   3   64   1   1   1 1 1 1   1   1 1     1 1 1 16   16 16       1   1     9             1     1 1 32   32   32 32   32         1   1     18             1     1 1 16   16   16 16 16     1   1     1         22       1 1 1     1   1   1   1   1 1     1 1   1           1       1         1               1   1   1     1 1   1     1 1 1   1   1     1         1       1 1 1   1   1 1   1     1 1   1   1   1         1   1   1         1         1       1   1 1   1   1           1 1 1   1   1   1       1 1   1   1   1 1   1         1 1   1   1   1 2         1   1           1 1   1       2   2           2       2       1   1 1   1 1     1 1   1       2         3       1   1   1   1     1 1   1   1   1   2         1   1           1 1   1   1   1   1   1           1 1 1 1   1 1   1   1 1   1   1 1   1         1 1   1   1   1   1   1         1 1 1   1   1 1   1 1 1       1 1 1   1   1   2       2           1   1               1 1       1       1          
"use strict";
 
var _interopRequire = function (obj) { return obj && obj.__esModule ? obj["default"] : obj; };
 
var _get = function get(object, property, receiver) { var desc = Object.getOwnPropertyDescriptor(object, property); Iif (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else Eif ("value" in desc && desc.writable) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } };
 
var _prototypeProperties = function (child, staticProps, instanceProps) { Iif (staticProps) Object.defineProperties(child, staticProps); Eif (instanceProps) Object.defineProperties(child.prototype, instanceProps); };
 
var _inherits = function (subClass, superClass) { Iif (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); Eif (superClass) subClass.__proto__ = superClass; };
 
var _classCallCheck = function (instance, Constructor) { Iif (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } };
 
var fluxMixin = _interopRequire(require("../fluxMixin"));
 
var _Flux = require("../../Flux");
 
var Flummox = _Flux.Flummox;
var Store = _Flux.Store;
var Actions = _Flux.Actions;
var sinon = _interopRequire(require("sinon"));
 
var React = _interopRequire(require("react/addons"));
 
var PropTypes = React.PropTypes;
var TestUtils = React.addons.TestUtils;
 
 
describe("fluxMixin", function () {
  var TestActions = (function (Actions) {
    function TestActions() {
      _classCallCheck(this, TestActions);
 
      Eif (Actions != null) {
        Actions.apply(this, arguments);
      }
    }
 
    _inherits(TestActions, Actions);
 
    _prototypeProperties(TestActions, null, {
      getSomething: {
        value: function getSomething(something) {
          return something;
        },
        writable: true,
        configurable: true
      }
    });
 
    return TestActions;
  })(Actions);
 
  var TestStore = (function (Store) {
    function TestStore(flux) {
      _classCallCheck(this, TestStore);
 
      _get(Object.getPrototypeOf(TestStore.prototype), "constructor", this).call(this);
 
      var testActions = flux.getActions("test");
      this.register(testActions.getSomething, this.handleGetSomething);
 
      this.state = {
        something: null
      };
    }
 
    _inherits(TestStore, Store);
 
    _prototypeProperties(TestStore, null, {
      handleGetSomething: {
        value: function handleGetSomething(something) {
          this.setState({ something: something });
        },
        writable: true,
        configurable: true
      }
    });
 
    return TestStore;
  })(Store);
 
  var Flux = (function (Flummox) {
    function Flux() {
      _classCallCheck(this, Flux);
 
      _get(Object.getPrototypeOf(Flux.prototype), "constructor", this).call(this);
 
      this.createActions("test", TestActions);
      this.createStore("test", TestStore, this);
      this.createStore("test2", TestStore, this);
    }
 
    _inherits(Flux, Flummox);
 
    return Flux;
  })(Flummox);
 
  var ComponentWithFluxMixin = React.createClass({
    displayName: "ComponentWithFluxMixin",
    mixins: [fluxMixin()],
 
    render: function render() {
      return null;
    }
  });
 
  it("gets flux from either props or context", function () {
    var flux = new Flux();
    var contextComponent = undefined,
        propsComponent = undefined;
 
    var ContextComponent = addContext(ComponentWithFluxMixin, { flux: flux }, { flux: React.PropTypes.instanceOf(Flummox) });
 
    var tree = TestUtils.renderIntoDocument(React.createElement(ContextComponent, { keys: "test" }));
 
    contextComponent = TestUtils.findRenderedComponentWithType(tree, ComponentWithFluxMixin);
 
    propsComponent = TestUtils.renderIntoDocument(React.createElement(ComponentWithFluxMixin, { key: "test", flux: flux }));
 
    expect(contextComponent.flux).to.be.an["instanceof"](Flummox);
    expect(propsComponent.flux).to.be.an["instanceof"](Flummox);
  });
 
  it("exposes flux as context", function () {
    var flux = new Flux();
 
    var ChildComponent = React.createClass({
      displayName: "ChildComponent",
      contextTypes: {
        flux: PropTypes.instanceOf(Flummox) },
 
      render: function render() {
        return React.createElement("div", null);
      }
    });
 
    var Component = React.createClass({
      displayName: "Component",
      mixins: [fluxMixin()],
 
      render: function render() {
        return React.createElement(
          "div",
          null,
          React.createElement(ChildComponent, { key: "test" })
        );
      }
    });
 
    var tree = TestUtils.renderIntoDocument(React.createElement(Component, { flux: flux }));
 
    var childComponent = TestUtils.findRenderedComponentWithType(tree, ChildComponent);
 
    expect(childComponent.context.flux).to.equal(flux);
  });
 
  it("throws error if neither props or context is set", function () {
    var flux = new Flux();
 
    expect(TestUtils.renderIntoDocument.bind(null, React.createElement(ComponentWithFluxMixin, null))).to["throw"]("fluxMixin: Could not find Flux instance. Ensure that your component " + "has either `this.context.flux` or `this.props.flux`.");
  });
 
  it("ignores change event after unmounted", function () {
    var flux = new Flux();
    flux.getActions("test").getSomething("foo");
 
    var getterMap = {
      test: function (store) {
        return { something: store.state.something };
      }
    };
    var Component = React.createClass({
      displayName: "Component",
      mixins: [fluxMixin(getterMap)],
 
      render: function render() {
        return null;
      }
    });
 
    var container = document.createElement("div");
    var component = React.render(React.createElement(Component, { flux: flux }), container);
    var listener = flux.getStore("test").listeners("change")[0];
 
    React.unmountComponentAtNode(container);
 
    flux.getActions("test").getSomething("bar");
    listener();
 
    expect(component.state.something).to.equal("foo");
  });
 
  it("uses #connectToStores() to get initial state", function () {
    var flux = new Flux();
 
    flux.getActions("test").getSomething("foobar");
 
    var getterMap = {
      test: function (store) {
        return {
          something: store.state.something,
          custom: true };
      } };
 
    var mixin = fluxMixin(getterMap);
 
    var connectToStores = sinon.spy(mixin, "connectToStores");
 
    var Component = React.createClass({
      displayName: "Component",
      mixins: [mixin],
 
      getInitialState: function getInitialState() {
        return {
          foobar: "baz" };
      },
 
      render: function render() {
        return null;
      }
    });
 
    var component = TestUtils.renderIntoDocument(React.createElement(Component, { key: "test", flux: flux }));
 
    expect(connectToStores.calledOnce).to.be["true"];
    expect(connectToStores.firstCall.args[0]).to.equal(getterMap);
 
    expect(flux.getStore("test").listeners("change")).to.have.length(1);
 
    expect(component.state).to.deep.equal({
      something: "foobar",
      custom: true,
      foobar: "baz" });
  });
 
  describe("#connectToStores", function () {
    it("returns initial state", function () {
      var flux = new Flux();
 
      var component = TestUtils.renderIntoDocument(React.createElement(ComponentWithFluxMixin, { key: "test", flux: flux }));
 
      var initialState = component.connectToStores("test");
 
      expect(initialState).to.deep.equal({
        something: null });
    });
 
    it("merges store state with component state on change", function () {
      var flux = new Flux();
 
      var component = TestUtils.renderIntoDocument(React.createElement(ComponentWithFluxMixin, { key: "test", flux: flux }));
 
      component.setState({ otherThing: "barbaz" });
 
      component.connectToStores("test");
      flux.getActions("test").getSomething("foobar");
 
      expect(component.state).to.deep.equal({
        something: "foobar",
        otherThing: "barbaz" });
    });
 
    it("uses custom state getter, if given", function () {
      var flux = new Flux();
 
      var component = TestUtils.renderIntoDocument(React.createElement(ComponentWithFluxMixin, { key: "test", flux: flux }));
 
      component.setState({ otherThing: "barbaz" });
 
      component.connectToStores("test", function (store) {
        return {
          something: store.state.something,
          custom: true };
      });
 
      flux.getActions("test").getSomething("foobar");
 
      expect(component.state).to.deep.equal({
        something: "foobar",
        otherThing: "barbaz",
        custom: true });
    });
 
    it("binds state getter to component", function () {
      var flux = new Flux();
 
      var Component = React.createClass({
        displayName: "Component",
        mixins: [fluxMixin({
          test: function (store) {
            this.someComponentMethod("some arg");
 
            return {
              something: store.state.something,
              custom: true };
          } })],
 
        render: function render() {
          return null;
        },
 
        someComponentMethod: function someComponentMethod(string) {
          return string;
        }
      });
 
      var component = TestUtils.renderIntoDocument(React.createElement(Component, { key: "test", flux: flux }));
 
      var someComponentMethod = sinon.spy(component, "someComponentMethod");
      flux.getActions("test").getSomething("foobar");
 
      expect(someComponentMethod.calledOnce).to.be["true"];
      expect(someComponentMethod.firstCall.args[0]).to.equal("some arg");
    });
 
    it("syncs with store after prop change", function () {
      var flux = new Flux();
 
      var Component = React.createClass({
        displayName: "Component",
        mixins: [fluxMixin({
          test: function (store) {
            return {
              foo: "foo is " + this.props.foo };
          } })],
 
        render: function render() {
          return null;
        }
      });
 
      var component = TestUtils.renderIntoDocument(React.createElement(Component, { key: "test", flux: flux, foo: "bar" }));
 
      expect(component.state.foo).to.equal("foo is bar");
 
      component.setProps({ foo: "baz" });
 
      expect(component.state.foo).to.equal("foo is baz");
    });
 
    it("accepts object of keys to state getters", function () {
      var flux = new Flux();
 
      var component = TestUtils.renderIntoDocument(React.createElement(ComponentWithFluxMixin, { key: "test", flux: flux }));
 
      component.setState({ otherThing: "barbaz" });
 
      component.connectToStores({
        test: function (store) {
          return {
            something: store.state.something,
            custom: true };
        } });
 
      flux.getActions("test").getSomething("foobar");
 
      expect(component.state).to.deep.equal({
        something: "foobar",
        otherThing: "barbaz",
        custom: true });
    });
 
    it("calls default state getter once with array of stores", function () {
      var flux = new Flux();
 
      flux.getStore("test2").setState({ otherThing: "barbaz" });
 
      var component = TestUtils.renderIntoDocument(React.createElement(ComponentWithFluxMixin, { key: "test", flux: flux }));
 
      component.connectToStores(["test", "test2"]);
 
      flux.getActions("test").getSomething("foobar");
 
      expect(component.state).to.deep.equal({
        something: "foobar",
        otherThing: "barbaz"
      });
    });
 
    it("calls custom state getter once with array of stores", function () {
      var flux = new Flux();
      var testStore = flux.getStore("test");
      var test2Store = flux.getStore("test2");
 
      testStore._testId = "test";
      test2Store._testId = "test2";
 
      var component = TestUtils.renderIntoDocument(React.createElement(ComponentWithFluxMixin, { key: "test", flux: flux }));
 
      var stateGetter = sinon.stub().returns({ foo: "bar" });
      var state = component.connectToStores(["test", "test2"], stateGetter);
 
      expect(stateGetter.calledOnce).to.be["true"];
      // Use _testId as unique identifier on store.
      expect(stateGetter.firstCall.args[0][0]._testId).to.equal("test");
      expect(stateGetter.firstCall.args[0][1]._testId).to.equal("test2");
 
      expect(state).to.deep.equal({
        foo: "bar"
      });
    });
 
    it("uses default getter if null is passed as getter", function () {
      var flux = new Flux();
 
      var component = TestUtils.renderIntoDocument(React.createElement(ComponentWithFluxMixin, { key: "test", flux: flux }));
 
      component.setState({ otherThing: "barbaz" });
 
      component.connectToStores("test", null);
 
      flux.getActions("test").getSomething("foobar");
 
      expect(component.state).to.deep.equal({
        something: "foobar",
        otherThing: "barbaz" });
    });
 
    it("removes listener before unmounting", function () {
      var flux = new Flux();
      var div = document.createElement("div");
 
      var component = React.render(React.createElement(ComponentWithFluxMixin, { flux: flux }), div);
 
      var store = flux.getStore("test");
      component.connectToStores("test");
 
      expect(store.listeners("change").length).to.equal(1);
      React.unmountComponentAtNode(div);
      expect(store.listeners("change").length).to.equal(0);
    });
  });
 
  describe("#getStoreState", function () {
    it("gets combined state of connected stores", function () {
      var flux = new Flux();
 
      var component = TestUtils.renderIntoDocument(React.createElement(ComponentWithFluxMixin, { key: "test", flux: flux }));
 
      component.connectToStores({
        test: function (store) {
          return {
            foo: "bar" };
        },
        test2: function (store) {
          return {
            bar: "baz"
          };
        }
      });
 
      component.setState({ baz: "foo" });
 
      expect(component.getStoreState()).to.deep.equal({
        foo: "bar",
        bar: "baz"
      });
    });
  });
});
 
function addContext(Component, context, contextTypes) {
  return React.createClass({
    childContextTypes: contextTypes,
 
    getChildContext: function getChildContext() {
      return context;
    },
 
    render: function render() {
      return React.createElement(Component, this.props);
    }
  });
}
 
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9hZGRvbnMvX190ZXN0c19fL2ZsdXhNaXhpbi10ZXN0LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7OztJQUFPLFNBQVMsMkJBQU0sY0FBYzs7b0JBQ0ksWUFBWTs7SUFBM0MsT0FBTyxTQUFQLE9BQU87SUFBRSxLQUFLLFNBQUwsS0FBSztJQUFFLE9BQU8sU0FBUCxPQUFPO0lBQ3pCLEtBQUssMkJBQU0sT0FBTzs7SUFFbEIsS0FBSywyQkFBTSxjQUFjOztJQUMxQixTQUFTLEdBQUssS0FBSyxDQUFuQixTQUFTO0lBQ1QsU0FBUyxHQUFLLEtBQUssQ0FBQyxNQUFNLENBQTFCLFNBQVM7OztBQUVmLFFBQVEsQ0FBQyxXQUFXLEVBQUUsWUFBTTtNQUVwQixXQUFXLGNBQVMsT0FBTzthQUEzQixXQUFXOzRCQUFYLFdBQVc7O1VBQVMsT0FBTztBQUFQLGVBQU87Ozs7Y0FBM0IsV0FBVyxFQUFTLE9BQU87O3lCQUEzQixXQUFXO0FBQ2Ysa0JBQVk7ZUFBQSxzQkFBQyxTQUFTLEVBQUU7QUFDdEIsaUJBQU8sU0FBUyxDQUFDO1NBQ2xCOzs7Ozs7V0FIRyxXQUFXO0tBQVMsT0FBTzs7TUFNM0IsU0FBUyxjQUFTLEtBQUs7QUFDaEIsYUFEUCxTQUFTLENBQ0QsSUFBSTs0QkFEWixTQUFTOztBQUVYLGlDQUZFLFNBQVMsNkNBRUg7O0FBRVIsVUFBSSxXQUFXLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsQ0FBQztBQUMxQyxVQUFJLENBQUMsUUFBUSxDQUFDLFdBQVcsQ0FBQyxZQUFZLEVBQUUsSUFBSSxDQUFDLGtCQUFrQixDQUFDLENBQUM7O0FBRWpFLFVBQUksQ0FBQyxLQUFLLEdBQUc7QUFDWCxpQkFBUyxFQUFFLElBQUk7T0FDaEIsQ0FBQztLQUNIOztjQVZHLFNBQVMsRUFBUyxLQUFLOzt5QkFBdkIsU0FBUztBQVliLHdCQUFrQjtlQUFBLDRCQUFDLFNBQVMsRUFBRTtBQUM1QixjQUFJLENBQUMsUUFBUSxDQUFD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SSxFQUFFLENBQUM7O0FBRXRCLFVBQUksU0FBUyxHQUFHLFNBQVMsQ0FBQyxrQkFBa0IsQ0FDMUMsb0JBQUMsc0JBQXNCLElBQUMsR0FBRyxFQUFDLE1BQU0sRUFBQyxJQUFJLEVBQUUsSUFBSSxBQUFDLEdBQUcsQ0FDbEQsQ0FBQzs7QUFFRixlQUFTLENBQUMsZUFBZSxDQUFDO0FBQ3hCLFlBQUksRUFBRSxVQUFBLEtBQUs7aUJBQUs7QUFDZCxlQUFHLEVBQUUsS0FBSyxFQUNYO1NBQUM7QUFDRixhQUFLLEVBQUUsVUFBQSxLQUFLO2lCQUFLO0FBQ2YsZUFBRyxFQUFFLEtBQUs7V0FDWDtTQUFDO09BQ0gsQ0FBQyxDQUFDOztBQUVILGVBQVMsQ0FBQyxRQUFRLENBQUMsRUFBRSxHQUFHLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQzs7QUFFbkMsWUFBTSxDQUFDLFNBQVMsQ0FBQyxhQUFhLEVBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDO0FBQzlDLFdBQUcsRUFBRSxLQUFLO0FBQ1YsV0FBRyxFQUFFLEtBQUs7T0FDWCxDQUFDLENBQUM7S0FDSixDQUFDLENBQUM7R0FDSixDQUFDLENBQUM7Q0FFSixDQUFDLENBQUM7O0FBRUgsU0FBUyxVQUFVLENBQUMsU0FBUyxFQUFFLE9BQU8sRUFBRSxZQUFZLEVBQUU7QUFDcEQsU0FBTyxLQUFLLENBQUMsV0FBVyxDQUFDO0FBQ3ZCLHFCQUFpQixFQUFFLFlBQVk7O0FBRS9CLG1CQUFlLEVBQUEsMkJBQUc7QUFDaEIsYUFBTyxPQUFPLENBQUM7S0FDaEI7O0FBRUQsVUFBTSxFQUFBLGtCQUFHO0FBQ1AsYUFBTyxvQkFBQyxTQUFTLEVBQUssSUFBSSxDQUFDLEtBQUssQ0FBSSxDQUFDO0tBQ3RDO0dBQ0YsQ0FBQyxDQUFDO0NBQ0oiLCJmaWxlIjoibGliL2FkZG9ucy9fX3Rlc3RzX18vZmx1eE1peGluLXRlc3QuanMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgZmx1eE1peGluIGZyb20gJy4uL2ZsdXhNaXhpbic7XG5pbXBvcnQgeyBGbHVtbW94LCBTdG9yZSwgQWN0aW9ucyB9IGZyb20gJy4uLy4uL0ZsdXgnO1xuaW1wb3J0IHNpbm9uIGZyb20gJ3Npbm9uJztcblxuaW1wb3J0IFJlYWN0IGZyb20gJ3JlYWN0L2FkZG9ucyc7XG5sZXQgeyBQcm9wVHlwZXMgfSA9IFJlYWN0O1xubGV0IHsgVGVzdFV0aWxzIH0gPSBSZWFjdC5hZGRvbnM7XG5cbmRlc2NyaWJlKCdmbHV4TWl4aW4nLCAoKSA9PiB7XG5cbiAgY2xhc3MgVGVzdEFjdGlvbnMgZXh0ZW5kcyBBY3Rpb25zIHtcbiAgICBnZXRTb21ldGhpbmcoc29tZXRoaW5nKSB7XG4gICAgICByZXR1cm4gc29tZXRoaW5nO1xuICAgIH1cbiAgfVxuXG4gIGNsYXNzIFRlc3RTdG9yZSBleHRlbmRzIFN0b3JlIHtcbiAgICBjb25zdHJ1Y3RvcihmbHV4KSB7XG4gICAgICBzdXBlcigpO1xuXG4gICAgICBsZXQgdGVzdEFjdGlvbnMgPSBmbHV4LmdldEFjdGlvbnMoJ3Rlc3QnKTtcbiAgICAgIHRoaXMucmVnaXN0ZXIodGVzdEFjdGlvbnMuZ2V0U29tZXRoaW5nLCB0aGlzLmhhbmRsZUdldFNvbWV0aGluZyk7XG5cbiAgICAgIHRoaXMuc3RhdGUgPSB7XG4gICAgICAgIHNvbWV0aGluZzogbnVsbFxuICAgICAgfTtcbiAgICB9XG5cbiAgICBoYW5kbGVHZXRTb21ldGhpbmcoc29tZXRoaW5nKSB7XG4gICAgICB0aGlzLnNldFN0YXRlKHsgc29tZXRoaW5nIH0pO1xuICAgIH1cbiAgfVxuXG4gIGNsYXNzIEZsdXggZXh0ZW5kcyBGbHVtbW94IHtcbiAgICBjb25zdHJ1Y3RvcigpIHtcbiAgICAgIHN1cGVyKCk7XG5cbiAgICAgIHRoaXMuY3JlYXRlQWN0aW9ucygndGVzdCcsIFRlc3RBY3Rpb25zKTtcbiAgICAgIHRoaXMuY3JlYXRlU3RvcmUoJ3Rlc3QnLCBUZXN0U3RvcmUsIHRoaXMpO1xuICAgICAgdGhpcy5jcmVhdGVTdG9yZSgndGVzdDInLCBUZXN0U3RvcmUsIHRoaXMpO1xuICAgIH1cbiAgfVxuXG4gIGxldCBDb21wb25lbnRXaXRoRmx1eE1peGluID0gUmVhY3QuY3JlYXRlQ2xhc3Moe1xuICAgIG1peGluczogW2ZsdXhNaXhpbigpXSxcblxuICAgIHJlbmRlcigpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgfSk7XG5cbiAgaXQoJ2dldHMgZmx1eCBmcm9tIGVpdGhlciBwcm9wcyBvciBjb250ZXh0JywgKCkgPT4ge1xuICAgIGxldCBmbHV4ID0gbmV3IEZsdXgoKTtcbiAgICBsZXQgY29udGV4dENvbXBvbmVudCwgcHJvcHNDb21wb25lbnQ7XG5cbiAgICBsZXQgQ29udGV4dENvbXBvbmVudCA9IGFkZENvbnRleHQoXG4gICAgICBDb21wb25lbnRXaXRoRmx1eE1peGluLFxuICAgICAgeyBmbHV4IH0sXG4gICAgICB7IGZsdXg6IFJlYWN0LlByb3BUeXBlcy5pbnN0YW5jZU9mKEZsdW1tb3gpIH1cbiAgICApO1xuXG4gICAgbGV0IHRyZWUgPSBUZXN0VXRpbHMucmVuZGVySW50b0RvY3VtZW50KFxuICAgICAgPENvbnRleHRDb21wb25lbnQga2V5cz1cInRlc3RcIiAvPlxuICAgICk7XG5cbiAgICBjb250ZXh0Q29tcG9uZW50ID0gVGVzdFV0aWxzLmZpbmRSZW5kZXJlZENvbXBvbmVudFdpdGhUeXBlKFxuICAgICAgdHJlZSwgQ29tcG9uZW50V2l0aEZsdXhNaXhpblxuICAgICk7XG5cbiAgICBwcm9wc0NvbXBvbmVudCA9IFRlc3RVdGlscy5yZW5kZXJJbnRvRG9jdW1lbnQoXG4gICAgICA8Q29tcG9uZW50V2l0aEZsdXhNaXhpbiBrZXk9XCJ0ZXN0XCIgZmx1eD17Zmx1eH0gLz5cbiAgICApO1xuXG4gICAgZXhwZWN0KGNvbnRleHRDb21wb25lbnQuZmx1eCkudG8uYmUuYW4uaW5zdGFuY2VvZihGbHVtbW94KTtcbiAgICBleHBlY3QocHJvcHNDb21wb25lbnQuZmx1eCkudG8uYmUuYW4uaW5zdGFuY2VvZihGbHVtbW94KTtcbiAgfSk7XG5cbiAgaXQoJ2V4cG9zZXMgZmx1eCBhcyBjb250ZXh0JywgKCkgPT4ge1xuICAgIGxldCBmbHV4ID0gbmV3IEZsdXgoKTtcblxuICAgIGxldCBDaGlsZENvbXBvbmVudCA9IFJlYWN0LmNyZWF0ZUNsYXNzKHtcbiAgICAgIGNvbnRleHRUeXBlczoge1xuICAgICAgICBmbHV4OiBQcm9wVHlwZXMuaW5zdGFuY2VPZihGbHVtbW94KSxcbiAgICAgIH0sXG5cbiAgICAgIHJlbmRlcigpIHtcbiAgICAgICAgcmV0dXJuIDxkaXYgLz47XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICBsZXQgQ29tcG9uZW50ID0gUmVhY3QuY3JlYXRlQ2xhc3Moe1xuICAgICAgbWl4aW5zOiBbZmx1eE1peGluKCldLFxuXG4gICAgICByZW5kZXIoKSB7XG4gICAgICAgIHJldHVybiAoXG4gICAgICAgICAgPGRpdj5cbiAgICAgICAgICAgIDxDaGlsZENvbXBvbmVudCBrZXk9XCJ0ZXN0XCIgLz5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIGxldCB0cmVlID0gVGVzdFV0aWxzLnJlbmRlckludG9Eb2N1bWVudCg8Q29tcG9uZW50IGZsdXg9e2ZsdXh9IC8+KTtcblxuICAgIGxldCBjaGlsZENvbXBvbmVudCA9IFRlc3RVdGlscy5maW5kUmVuZGVyZWRDb21wb25lbnRXaXRoVHlwZShcbiAgICAgIHRyZWUsXG4gICAgICBDaGlsZENvbXBvbmVudFxuICAgICk7XG5cbiAgICBleHBlY3QoY2hpbGRDb21wb25lbnQuY29udGV4dC5mbHV4KS50by5lcXVhbChmbHV4KTtcbiAgfSk7XG5cbiAgaXQoJ3Rocm93cyBlcnJvciBpZiBuZWl0aGVyIHByb3BzIG9yIGNvbnRleHQgaXMgc2V0JywgKCkgPT4ge1xuICAgIGxldCBmbHV4ID0gbmV3IEZsdXgoKTtcblxuICAgIGV4cGVjdChUZXN0VXRpbHMucmVuZGVySW50b0RvY3VtZW50LmJpbmQobnVsbCwgPENvbXBvbmVudFdpdGhGbHV4TWl4aW4gLz4pKVxuICAgICAgLnRvLnRocm93KFxuICAgICAgICAnZmx1eE1peGluOiBDb3VsZCBub3QgZmluZCBGbHV4IGluc3RhbmNlLiBFbnN1cmUgdGhhdCB5b3VyIGNvbXBvbmVudCAnXG4gICAgICArICdoYXMgZWl0aGVyIGB0aGlzLmNvbnRleHQuZmx1eGAgb3IgYHRoaXMucHJvcHMuZmx1eGAuJ1xuICAgICAgKTtcbiAgfSk7XG5cbiAgaXQoJ2lnbm9yZXMgY2hhbmdlIGV2ZW50IGFmdGVyIHVubW91bnRlZCcsICgpID0+IHtcbiAgICBsZXQgZmx1eCA9IG5ldyBGbHV4KCk7XG4gICAgZmx1eC5nZXRBY3Rpb25zKCd0ZXN0JykuZ2V0U29tZXRoaW5nKCdmb28nKTtcblxuICAgIGxldCBnZXR0ZXJNYXAgPSB7XG4gICAgICB0ZXN0OiBzdG9yZSA9PiAoeyBzb21ldGhpbmc6IHN0b3JlLnN0YXRlLnNvbWV0aGluZyB9KVxuICAgIH07XG4gICAgbGV0IENvbXBvbmVudCA9IFJlYWN0LmNyZWF0ZUNsYXNzKHtcbiAgICAgIG1peGluczogW2ZsdXhNaXhpbihnZXR0ZXJNYXApXSxcblxuICAgICAgcmVuZGVyKCkge1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIGxldCBjb250YWluZXIgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKTtcbiAgICBsZXQgY29tcG9uZW50ID0gUmVhY3QucmVuZGVyKDxDb21wb25lbnQgZmx1eD17Zmx1eH0gLz4sIGNvbnRhaW5lcik7XG4gICAgbGV0IGxpc3RlbmVyID0gZmx1eC5nZXRTdG9yZSgndGVzdCcpLmxpc3RlbmVycygnY2hhbmdlJylbMF07XG5cbiAgICBSZWFjdC51bm1vdW50Q29tcG9uZW50QXROb2RlKGNvbnRhaW5lcik7XG5cbiAgICBmbHV4LmdldEFjdGlvbnMoJ3Rlc3QnKS5nZXRTb21ldGhpbmcoJ2JhcicpO1xuICAgIGxpc3RlbmVyKCk7XG5cbiAgICBleHBlY3QoY29tcG9uZW50LnN0YXRlLnNvbWV0aGluZykudG8uZXF1YWwoJ2ZvbycpO1xuICB9KTtcblxuICBpdCgndXNlcyAjY29ubmVjdFRvU3RvcmVzKCkgdG8gZ2V0IGluaXRpYWwgc3RhdGUnLCAoKSA9PiB7XG4gICAgbGV0IGZsdXggPSBuZXcgRmx1eCgpO1xuXG4gICAgZmx1eC5nZXRBY3Rpb25zKCd0ZXN0JykuZ2V0U29tZXRoaW5nKCdmb29iYXInKTtcblxuICAgIGxldCBnZXR0ZXJNYXAgPSB7XG4gICAgICB0ZXN0OiBzdG9yZSA9PiAoe1xuICAgICAgICBzb21ldGhpbmc6IHN0b3JlLnN0YXRlLnNvbWV0aGluZyxcbiAgICAgICAgY3VzdG9tOiB0cnVlLFxuICAgICAgfSksXG4gICAgfTtcblxuICAgIGxldCBtaXhpbiA9IGZsdXhNaXhpbihnZXR0ZXJNYXApO1xuXG4gICAgbGV0IGNvbm5lY3RUb1N0b3JlcyA9IHNpbm9uLnNweShtaXhpbiwgJ2Nvbm5lY3RUb1N0b3JlcycpO1xuXG4gICAgbGV0IENvbXBvbmVudCA9IFJlYWN0LmNyZWF0ZUNsYXNzKHtcbiAgICAgIG1peGluczogW21peGluXSxcblxuICAgICAgZ2V0SW5pdGlhbFN0YXRlKCkge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIGZvb2JhcjogJ2JheicsXG4gICAgICAgIH07XG4gICAgICB9LFxuXG4gICAgICByZW5kZXIoKSB7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgbGV0IGNvbXBvbmVudCA9IFRlc3RVdGlscy5yZW5kZXJJbnRvRG9jdW1lbnQoXG4gICAgICA8Q29tcG9uZW50IGtleT1cInRlc3RcIiBmbHV4PXtmbHV4fSAvPlxuICAgICk7XG5cbiAgICBleHBlY3QoY29ubmVjdFRvU3RvcmVzLmNhbGxlZE9uY2UpLnRvLmJlLnRydWU7XG4gICAgZXhwZWN0KGNvbm5lY3RUb1N0b3Jlcy5maXJzdENhbGwuYXJnc1swXSkudG8uZXF1YWwoZ2V0dGVyTWFwKTtcblxuICAgIGV4cGVjdChmbHV4LmdldFN0b3JlKCd0ZXN0JykubGlzdGVuZXJzKCdjaGFuZ2UnKSkudG8uaGF2ZS5sZW5ndGgoMSk7XG5cbiAgICBleHBlY3QoY29tcG9uZW50LnN0YXRlKS50by5kZWVwLmVxdWFsKHtcbiAgICAgIHNvbWV0aGluZzogJ2Zvb2JhcicsXG4gICAgICBjdXN0b206IHRydWUsXG4gICAgICBmb29iYXI6ICdiYXonLFxuICAgIH0pO1xuXG4gIH0pO1xuXG4gIGRlc2NyaWJlKCcjY29ubmVjdFRvU3RvcmVzJywgKCkgPT4ge1xuXG4gICAgaXQoJ3JldHVybnMgaW5pdGlhbCBzdGF0ZScsICgpID0+IHtcbiAgICAgIGxldCBmbHV4ID0gbmV3IEZsdXgoKTtcblxuICAgICAgbGV0IGNvbXBvbmVudCA9IFRlc3RVdGlscy5yZW5kZXJJbnRvRG9jdW1lbnQoXG4gICAgICAgIDxDb21wb25lbnRXaXRoRmx1eE1peGluIGtleT1cInRlc3RcIiBmbHV4PXtmbHV4fSAvPlxuICAgICAgKTtcblxuICAgICAgbGV0IGluaXRpYWxTdGF0ZSA9IGNvbXBvbmVudC5jb25uZWN0VG9TdG9yZXMoJ3Rlc3QnKTtcblxuICAgICAgZXhwZWN0KGluaXRpYWxTdGF0ZSkudG8uZGVlcC5lcXVhbCh7XG4gICAgICAgIHNvbWV0aGluZzogbnVsbCxcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgaXQoJ21lcmdlcyBzdG9yZSBzdGF0ZSB3aXRoIGNvbXBvbmVudCBzdGF0ZSBvbiBjaGFuZ2UnLCAoKSA9PiB7XG4gICAgICBsZXQgZmx1eCA9IG5ldyBGbHV4KCk7XG5cbiAgICAgIGxldCBjb21wb25lbnQgPSBUZXN0VXRpbHMucmVuZGVySW50b0RvY3VtZW50KFxuICAgICAgICA8Q29tcG9uZW50V2l0aEZsdXhNaXhpbiBrZXk9XCJ0ZXN0XCIgZmx1eD17Zmx1eH0gLz5cbiAgICAgICk7XG5cbiAgICAgIGNvbXBvbmVudC5zZXRTdGF0ZSh7IG90aGVyVGhpbmc6ICdiYXJiYXonIH0pO1xuXG4gICAgICBjb21wb25lbnQuY29ubmVjdFRvU3RvcmVzKCd0ZXN0Jyk7XG4gICAgICBmbHV4LmdldEFjdGlvbnMoJ3Rlc3QnKS5nZXRTb21ldGhpbmcoJ2Zvb2JhcicpO1xuXG4gICAgICBleHBlY3QoY29tcG9uZW50LnN0YXRlKS50by5kZWVwLmVxdWFsKHtcbiAgICAgICAgc29tZXRoaW5nOiAnZm9vYmFyJyxcbiAgICAgICAgb3RoZXJUaGluZzogJ2JhcmJheicsXG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIGl0KCd1c2VzIGN1c3RvbSBzdGF0ZSBnZXR0ZXIsIGlmIGdpdmVuJywgKCkgPT4ge1xuICAgICAgbGV0IGZsdXggPSBuZXcgRmx1eCgpO1xuXG4gICAgICBsZXQgY29tcG9uZW50ID0gVGVzdFV0aWxzLnJlbmRlckludG9Eb2N1bWVudChcbiAgICAgICAgPENvbXBvbmVudFdpdGhGbHV4TWl4aW4ga2V5PVwidGVzdFwiIGZsdXg9e2ZsdXh9IC8+XG4gICAgICApO1xuXG4gICAgICBjb21wb25lbnQuc2V0U3RhdGUoeyBvdGhlclRoaW5nOiAnYmFyYmF6JyB9KTtcblxuICAgICAgY29tcG9uZW50LmNvbm5lY3RUb1N0b3JlcygndGVzdCcsIHN0b3JlID0+IHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICBzb21ldGhpbmc6IHN0b3JlLnN0YXRlLnNvbWV0aGluZyxcbiAgICAgICAgICBjdXN0b206IHRydWUsXG4gICAgICAgIH07XG4gICAgICB9KTtcblxuICAgICAgZmx1eC5nZXRBY3Rpb25zKCd0ZXN0JykuZ2V0U29tZXRoaW5nKCdmb29iYXInKTtcblxuICAgICAgZXhwZWN0KGNvbXBvbmVudC5zdGF0ZSkudG8uZGVlcC5lcXVhbCh7XG4gICAgICAgIHNvbWV0aGluZzogJ2Zvb2JhcicsXG4gICAgICAgIG90aGVyVGhpbmc6ICdiYXJiYXonLFxuICAgICAgICBjdXN0b206IHRydWUsXG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIGl0KCdiaW5kcyBzdGF0ZSBnZXR0ZXIgdG8gY29tcG9uZW50JywgKCkgPT4ge1xuICAgICAgbGV0IGZsdXggPSBuZXcgRmx1eCgpO1xuXG4gICAgICBsZXQgQ29tcG9uZW50ID0gUmVhY3QuY3JlYXRlQ2xhc3Moe1xuICAgICAgICBtaXhpbnM6IFtmbHV4TWl4aW4oe1xuICAgICAgICAgIHRlc3Q6IGZ1bmN0aW9uKHN0b3JlKSB7XG4gICAgICAgICAgICB0aGlzLnNvbWVDb21wb25lbnRNZXRob2QoJ3NvbWUgYXJnJyk7XG5cbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgIHNvbWV0aGluZzogc3RvcmUuc3RhdGUuc29tZXRoaW5nLFxuICAgICAgICAgICAgICBjdXN0b206IHRydWUsXG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH0sXG4gICAgICAgIH0pXSxcblxuICAgICAgICByZW5kZXIoKSB7XG4gICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH0sXG5cbiAgICAgICAgc29tZUNvbXBvbmVudE1ldGhvZChzdHJpbmcpIHtcbiAgICAgICAgICByZXR1cm4gc3RyaW5nO1xuICAgICAgICB9XG4gICAgICB9KTtcblxuICAgICAgbGV0IGNvbXBvbmVudCA9IFRlc3RVdGlscy5yZW5kZXJJbnRvRG9jdW1lbnQoXG4gICAgICAgIDxDb21wb25lbnQga2V5PVwidGVzdFwiIGZsdXg9e2ZsdXh9IC8+XG4gICAgICApO1xuXG4gICAgICBsZXQgc29tZUNvbXBvbmVudE1ldGhvZCA9IHNpbm9uLnNweShjb21wb25lbnQsICdzb21lQ29tcG9uZW50TWV0aG9kJyk7XG4gICAgICBmbHV4LmdldEFjdGlvbnMoJ3Rlc3QnKS5nZXRTb21ldGhpbmcoJ2Zvb2JhcicpO1xuXG4gICAgICBleHBlY3Qoc29tZUNvbXBvbmVudE1ldGhvZC5jYWxsZWRPbmNlKS50by5iZS50cnVlO1xuICAgICAgZXhwZWN0KHNvbWVDb21wb25lbnRNZXRob2QuZmlyc3RDYWxsLmFyZ3NbMF0pLnRvLmVxdWFsKCdzb21lIGFyZycpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3N5bmNzIHdpdGggc3RvcmUgYWZ0ZXIgcHJvcCBjaGFuZ2UnLCAoKSA9PiB7XG4gICAgICBsZXQgZmx1eCA9IG5ldyBGbHV4KCk7XG5cbiAgICAgIGxldCBDb21wb25lbnQgPSBSZWFjdC5jcmVhdGVDbGFzcyh7XG4gICAgICAgIG1peGluczogW2ZsdXhNaXhpbih7XG4gICAgICAgICAgdGVzdDogZnVuY3Rpb24oc3RvcmUpIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgIGZvbzogJ2ZvbyBpcyAnICsgdGhpcy5wcm9wcy5mb28sXG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH0sXG4gICAgICAgIH0pXSxcblxuICAgICAgICByZW5kZXIoKSB7XG4gICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuXG4gICAgICBsZXQgY29tcG9uZW50ID0gVGVzdFV0aWxzLnJlbmRlckludG9Eb2N1bWVudChcbiAgICAgICAgPENvbXBvbmVudCBrZXk9XCJ0ZXN0XCIgZmx1eD17Zmx1eH0gZm9vPVwiYmFyXCIgLz5cbiAgICAgICk7XG5cbiAgICAgIGV4cGVjdChjb21wb25lbnQuc3RhdGUuZm9vKS50by5lcXVhbCgnZm9vIGlzIGJhcicpO1xuXG4gICAgICBjb21wb25lbnQuc2V0UHJvcHMoeyBmb286ICdiYXonIH0pO1xuXG4gICAgICBleHBlY3QoY29tcG9uZW50LnN0YXRlLmZvbykudG8uZXF1YWwoJ2ZvbyBpcyBiYXonKTtcbiAgICB9KTtcblxuICAgIGl0KCdhY2NlcHRzIG9iamVjdCBvZiBrZXlzIHRvIHN0YXRlIGdldHRlcnMnLCAoKSA9PiB7XG4gICAgICBsZXQgZmx1eCA9IG5ldyBGbHV4KCk7XG5cbiAgICAgIGxldCBjb21wb25lbnQgPSBUZXN0VXRpbHMucmVuZGVySW50b0RvY3VtZW50KFxuICAgICAgICA8Q29tcG9uZW50V2l0aEZsdXhNaXhpbiBrZXk9XCJ0ZXN0XCIgZmx1eD17Zmx1eH0gLz5cbiAgICAgICk7XG5cbiAgICAgIGNvbXBvbmVudC5zZXRTdGF0ZSh7IG90aGVyVGhpbmc6ICdiYXJiYXonIH0pO1xuXG4gICAgICBjb21wb25lbnQuY29ubmVjdFRvU3RvcmVzKHtcbiAgICAgICAgdGVzdDogc3RvcmUgPT4gKHtcbiAgICAgICAgICBzb21ldGhpbmc6IHN0b3JlLnN0YXRlLnNvbWV0aGluZyxcbiAgICAgICAgICBjdXN0b206IHRydWUsXG4gICAgICAgIH0pLFxuICAgICAgfSk7XG5cbiAgICAgIGZsdXguZ2V0QWN0aW9ucygndGVzdCcpLmdldFNvbWV0aGluZygnZm9vYmFyJyk7XG5cbiAgICAgIGV4cGVjdChjb21wb25lbnQuc3RhdGUpLnRvLmRlZXAuZXF1YWwoe1xuICAgICAgICBzb21ldGhpbmc6ICdmb29iYXInLFxuICAgICAgICBvdGhlclRoaW5nOiAnYmFyYmF6JyxcbiAgICAgICAgY3VzdG9tOiB0cnVlLFxuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICBpdCgnY2FsbHMgZGVmYXVsdCBzdGF0ZSBnZXR0ZXIgb25jZSB3aXRoIGFycmF5IG9mIHN0b3JlcycsICgpID0+IHtcbiAgICAgIGxldCBmbHV4ID0gbmV3IEZsdXgoKTtcblxuICAgICAgZmx1eC5nZXRTdG9yZSgndGVzdDInKS5zZXRTdGF0ZSh7IG90aGVyVGhpbmc6ICdiYXJiYXonIH0pO1xuXG4gICAgICBsZXQgY29tcG9uZW50ID0gVGVzdFV0aWxzLnJlbmRlckludG9Eb2N1bWVudChcbiAgICAgICAgPENvbXBvbmVudFdpdGhGbHV4TWl4aW4ga2V5PVwidGVzdFwiIGZsdXg9e2ZsdXh9IC8+XG4gICAgICApO1xuXG4gICAgICBjb21wb25lbnQuY29ubmVjdFRvU3RvcmVzKFsndGVzdCcsICd0ZXN0MiddKTtcblxuICAgICAgZmx1eC5nZXRBY3Rpb25zKCd0ZXN0JykuZ2V0U29tZXRoaW5nKCdmb29iYXInKTtcblxuICAgICAgZXhwZWN0KGNvbXBvbmVudC5zdGF0ZSkudG8uZGVlcC5lcXVhbCh7XG4gICAgICAgIHNvbWV0aGluZzogJ2Zvb2JhcicsXG4gICAgICAgIG90aGVyVGhpbmc6ICdiYXJiYXonXG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIGl0KCdjYWxscyBjdXN0b20gc3RhdGUgZ2V0dGVyIG9uY2Ugd2l0aCBhcnJheSBvZiBzdG9yZXMnLCAoKSA9PiB7XG4gICAgICBsZXQgZmx1eCA9IG5ldyBGbHV4KCk7XG4gICAgICBsZXQgdGVzdFN0b3JlID0gZmx1eC5nZXRTdG9yZSgndGVzdCcpO1xuICAgICAgbGV0IHRlc3QyU3RvcmUgPSBmbHV4LmdldFN0b3JlKCd0ZXN0MicpO1xuXG4gICAgICB0ZXN0U3RvcmUuX3Rlc3RJZCA9ICd0ZXN0JztcbiAgICAgIHRlc3QyU3RvcmUuX3Rlc3RJZCA9ICd0ZXN0Mic7XG5cbiAgICAgIGxldCBjb21wb25lbnQgPSBUZXN0VXRpbHMucmVuZGVySW50b0RvY3VtZW50KFxuICAgICAgICA8Q29tcG9uZW50V2l0aEZsdXhNaXhpbiBrZXk9XCJ0ZXN0XCIgZmx1eD17Zmx1eH0gLz5cbiAgICAgICk7XG5cbiAgICAgIGxldCBzdGF0ZUdldHRlciA9IHNpbm9uLnN0dWIoKS5yZXR1cm5zKHsgZm9vOiAnYmFyJyB9KTtcbiAgICAgIGxldCBzdGF0ZSA9IGNvbXBvbmVudC5jb25uZWN0VG9TdG9yZXMoWyd0ZXN0JywgJ3Rlc3QyJ10sIHN0YXRlR2V0dGVyKTtcblxuICAgICAgZXhwZWN0KHN0YXRlR2V0dGVyLmNhbGxlZE9uY2UpLnRvLmJlLnRydWU7XG4gICAgICAvLyBVc2UgX3Rlc3RJZCBhcyB1bmlxdWUgaWRlbnRpZmllciBvbiBzdG9yZS5cbiAgICAgIGV4cGVjdChzdGF0ZUdldHRlci5maXJzdENhbGwuYXJnc1swXVswXS5fdGVzdElkKS50by5lcXVhbCgndGVzdCcpO1xuICAgICAgZXhwZWN0KHN0YXRlR2V0dGVyLmZpcnN0Q2FsbC5hcmdzWzBdWzFdLl90ZXN0SWQpLnRvLmVxdWFsKCd0ZXN0MicpO1xuXG4gICAgICBleHBlY3Qoc3RhdGUpLnRvLmRlZXAuZXF1YWwoe1xuICAgICAgICBmb286ICdiYXInXG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIGl0KCd1c2VzIGRlZmF1bHQgZ2V0dGVyIGlmIG51bGwgaXMgcGFzc2VkIGFzIGdldHRlcicsICgpID0+IHtcbiAgICAgIGxldCBmbHV4ID0gbmV3IEZsdXgoKTtcblxuICAgICAgbGV0IGNvbXBvbmVudCA9IFRlc3RVdGlscy5yZW5kZXJJbnRvRG9jdW1lbnQoXG4gICAgICAgIDxDb21wb25lbnRXaXRoRmx1eE1peGluIGtleT1cInRlc3RcIiBmbHV4PXtmbHV4fSAvPlxuICAgICAgKTtcblxuICAgICAgY29tcG9uZW50LnNldFN0YXRlKHsgb3RoZXJUaGluZzogJ2JhcmJheicgfSk7XG5cbiAgICAgIGNvbXBvbmVudC5jb25uZWN0VG9TdG9yZXMoJ3Rlc3QnLCBudWxsKTtcblxuICAgICAgZmx1eC5nZXRBY3Rpb25zKCd0ZXN0JykuZ2V0U29tZXRoaW5nKCdmb29iYXInKTtcblxuICAgICAgZXhwZWN0KGNvbXBvbmVudC5zdGF0ZSkudG8uZGVlcC5lcXVhbCh7XG4gICAgICAgIHNvbWV0aGluZzogJ2Zvb2JhcicsXG4gICAgICAgIG90aGVyVGhpbmc6ICdiYXJiYXonLFxuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICBpdCgncmVtb3ZlcyBsaXN0ZW5lciBiZWZvcmUgdW5tb3VudGluZycsICgpID0+IHtcbiAgICAgIGxldCBmbHV4ID0gbmV3IEZsdXgoKTtcbiAgICAgIGxldCBkaXYgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKTtcblxuICAgICAgbGV0IGNvbXBvbmVudCA9IFJlYWN0LnJlbmRlcig8Q29tcG9uZW50V2l0aEZsdXhNaXhpbiBmbHV4PXtmbHV4fSAvPiwgZGl2KTtcblxuICAgICAgbGV0IHN0b3JlID0gZmx1eC5nZXRTdG9yZSgndGVzdCcpO1xuICAgICAgY29tcG9uZW50LmNvbm5lY3RUb1N0b3JlcygndGVzdCcpO1xuXG4gICAgICBleHBlY3Qoc3RvcmUubGlzdGVuZXJzKCdjaGFuZ2UnKS5sZW5ndGgpLnRvLmVxdWFsKDEpO1xuICAgICAgUmVhY3QudW5tb3VudENvbXBvbmVudEF0Tm9kZShkaXYpO1xuICAgICAgZXhwZWN0KHN0b3JlLmxpc3RlbmVycygnY2hhbmdlJykubGVuZ3RoKS50by5lcXVhbCgwKTtcbiAgICB9KTtcblxuICB9KTtcblxuICBkZXNjcmliZSgnI2dldFN0b3JlU3RhdGUnLCAoKSA9PiB7XG4gICAgaXQoJ2dldHMgY29tYmluZWQgc3RhdGUgb2YgY29ubmVjdGVkIHN0b3JlcycsICgpID0+IHtcbiAgICAgIGxldCBmbHV4ID0gbmV3IEZsdXgoKTtcblxuICAgICAgbGV0IGNvbXBvbmVudCA9IFRlc3RVdGlscy5yZW5kZXJJbnRvRG9jdW1lbnQoXG4gICAgICAgIDxDb21wb25lbnRXaXRoRmx1eE1peGluIGtleT1cInRlc3RcIiBmbHV4PXtmbHV4fSAvPlxuICAgICAgKTtcblxuICAgICAgY29tcG9uZW50LmNvbm5lY3RUb1N0b3Jlcyh7XG4gICAgICAgIHRlc3Q6IHN0b3JlID0+ICh7XG4gICAgICAgICAgZm9vOiAnYmFyJyxcbiAgICAgICAgfSksXG4gICAgICAgIHRlc3QyOiBzdG9yZSA9PiAoe1xuICAgICAgICAgIGJhcjogJ2JheidcbiAgICAgICAgfSlcbiAgICAgIH0pO1xuXG4gICAgICBjb21wb25lbnQuc2V0U3RhdGUoeyBiYXo6ICdmb28nIH0pO1xuXG4gICAgICBleHBlY3QoY29tcG9uZW50LmdldFN0b3JlU3RhdGUoKSkudG8uZGVlcC5lcXVhbCh7XG4gICAgICAgIGZvbzogJ2JhcicsXG4gICAgICAgIGJhcjogJ2JheidcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9KTtcblxufSk7XG5cbmZ1bmN0aW9uIGFkZENvbnRleHQoQ29tcG9uZW50LCBjb250ZXh0LCBjb250ZXh0VHlwZXMpIHtcbiAgcmV0dXJuIFJlYWN0LmNyZWF0ZUNsYXNzKHtcbiAgICBjaGlsZENvbnRleHRUeXBlczogY29udGV4dFR5cGVzLFxuXG4gICAgZ2V0Q2hpbGRDb250ZXh0KCkge1xuICAgICAgcmV0dXJuIGNvbnRleHQ7XG4gICAgfSxcblxuICAgIHJlbmRlcigpIHtcbiAgICAgIHJldHVybiA8Q29tcG9uZW50IHsuLi50aGlzLnByb3BzfSAvPjtcbiAgICB9XG4gIH0pO1xufVxuIl19