fusion-plugin-rpc
Version:
Fetch data on the server and client with an RPC style interface.
379 lines (375 loc) • 50.4 kB
JavaScript
"use strict";
var _events = _interopRequireDefault(require("events"));
var _fusionCore = _interopRequireWildcard(require("fusion-core"));
var _fusionTokens = require("fusion-tokens");
var _fusionTestUtils = require("fusion-test-utils");
var _fusionPluginUniversalEvents = require("fusion-plugin-universal-events");
var _fusionPluginI18n = require("fusion-plugin-i18n");
var _browser = _interopRequireDefault(require("../browser"));
var _createMockEmitter = _interopRequireDefault(require("./create-mock-emitter"));
var _tokens = require("../tokens");
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/** Copyright (c) 2018 Uber Technologies, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
const MockPluginToken = (0, _fusionCore.createToken)('test-plugin-token');
function createTestFixture() {
const mockFetch = (...args) => Promise.resolve({
json: () => ({
status: 'success',
data: args
})
});
// @ts-ignore
const mockEmitter = new _events.default();
const mockEmitterPlugin = (0, _fusionCore.createPlugin)({
provides: () => mockEmitter
});
const mockI18nPlugin = (0, _fusionCore.createPlugin)({
provides: () => ({
from: () => ({
locale: 'el-GR',
load: async () => {},
translate: () => ''
})
})
});
const app = new _fusionCore.default('content', el => el);
// @ts-ignore
app.register(_fusionTokens.FetchToken, mockFetch);
app.register(_fusionPluginUniversalEvents.UniversalEventsToken, mockEmitterPlugin);
app.register(_fusionPluginI18n.I18nToken, mockI18nPlugin);
app.register(MockPluginToken, _browser.default);
return app;
}
test('success status request', done => {
const mockEmitter = (0, _createMockEmitter.default)({
emit(type, payload) {
expect(type).toBe('rpc:method-client');
expect(payload.method).toBe('test');
expect(payload.status).toBe('success');
expect(typeof payload.timing).toBe('number');
}
});
const app = createTestFixture();
app.register(_fusionPluginUniversalEvents.UniversalEventsToken, mockEmitter);
let wasResolved = false;
(0, _fusionTestUtils.getSimulator)(app, (0, _fusionCore.createPlugin)({
deps: {
rpcFactory: MockPluginToken
},
provides: deps => {
const rpc = deps.rpcFactory.from({
memoized: new Map()
});
expect(typeof rpc.request).toBe('function');
expect(rpc.request('test') instanceof Promise).toBeTruthy();
rpc.request('test').then(([url, options]) => {
expect(url).toBe('/api/test?localeCode=el-GR');
expect(options.method).toBe('POST');
expect(options.headers['Content-Type']).toBe('application/json');
expect(options.body).toBe('{}');
done();
}).catch(e => {
// $FlowFixMe
done.fail(e);
});
wasResolved = true;
}
}));
expect(wasResolved).toBeTruthy();
});
test('success status request with additional query params', done => {
const mockEmitter = (0, _createMockEmitter.default)({
emit(type, payload) {
expect(type).toBe('rpc:method-client');
expect(payload.method).toBe('test');
expect(payload.status).toBe('success');
expect(typeof payload.timing).toBe('number');
}
});
const app = createTestFixture();
app.register(_fusionPluginUniversalEvents.UniversalEventsToken, mockEmitter);
app.register(_tokens.RPCQueryParamsToken, {
from() {
return [['hello', 'world']];
}
});
let wasResolved = false;
(0, _fusionTestUtils.getSimulator)(app, (0, _fusionCore.createPlugin)({
deps: {
rpcFactory: MockPluginToken
},
provides: deps => {
const rpc = deps.rpcFactory.from({
memoized: new Map()
});
expect(typeof rpc.request).toBe('function');
expect(rpc.request('test') instanceof Promise).toBeTruthy();
rpc.request('test').then(([url, options]) => {
expect(url).toBe('/api/test?hello=world&localeCode=el-GR');
expect(options.method).toBe('POST');
expect(options.headers['Content-Type']).toBe('application/json');
expect(options.body).toBe('{}');
done();
}).catch(e => {
// $FlowFixMe
done.fail(e);
});
wasResolved = true;
}
}));
expect(wasResolved).toBeTruthy();
});
test('success status request (with custom api path)', done => {
const app = createTestFixture();
app.register(_tokens.RPCHandlersConfigToken, {
apiPath: 'test/api/path'
});
let wasResolved = false;
(0, _fusionTestUtils.getSimulator)(app, (0, _fusionCore.createPlugin)({
deps: {
rpcFactory: MockPluginToken
},
provides: deps => {
const rpc = deps.rpcFactory.from({
memoized: new Map()
});
expect(typeof rpc.request).toBe('function');
expect(rpc.request('test') instanceof Promise).toBeTruthy();
rpc.request('test').then(([url, options]) => {
expect(url).toBe('/test/api/path/test?localeCode=el-GR');
expect(options.method).toBe('POST');
expect(options.headers['Content-Type']).toBe('application/json');
expect(options.body).toBe('{}');
done();
}).catch(e => {
// $FlowFixMe
done.fail(e);
});
wasResolved = true;
}
}));
expect(wasResolved).toBeTruthy();
});
test('success status request (with custom api path containing slashes)', done => {
const app = createTestFixture();
app.register(_tokens.RPCHandlersConfigToken, {
apiPath: '///test/api///path/'
});
let wasResolved = false;
(0, _fusionTestUtils.getSimulator)(app, (0, _fusionCore.createPlugin)({
deps: {
rpcFactory: MockPluginToken
},
provides: deps => {
const rpc = deps.rpcFactory.from({
memoized: new Map()
});
expect(typeof rpc.request).toBe('function');
expect(rpc.request('test') instanceof Promise).toBeTruthy();
rpc.request('test').then(([url, options]) => {
expect(url).toBe('/test/api/path/test?localeCode=el-GR');
expect(options.method).toBe('POST');
expect(options.headers['Content-Type']).toBe('application/json');
expect(options.body).toBe('{}');
done();
}).catch(e => {
// $FlowFixMe
done.fail(e);
});
wasResolved = true;
}
}));
expect(wasResolved).toBeTruthy();
});
test('success status request w/args and header', done => {
const mockEmitter = (0, _createMockEmitter.default)({
emit(type, payload) {
expect(type).toBe('rpc:method-client');
expect(payload.method).toBe('test');
expect(payload.status).toBe('success');
expect(typeof payload.timing).toBe('number');
}
});
const app = createTestFixture();
// $FlowFixMe
app.register(_fusionPluginUniversalEvents.UniversalEventsToken, mockEmitter);
let wasResolved = false;
(0, _fusionTestUtils.getSimulator)(app, (0, _fusionCore.createPlugin)({
deps: {
rpcFactory: MockPluginToken
},
provides: deps => {
const rpc = deps.rpcFactory.from({
memoized: new Map()
});
expect(typeof rpc.request).toBe('function');
expect(rpc.request('test') instanceof Promise).toBeTruthy();
rpc.request('test', {
args: 1
}, {
'test-header': 'header value'
}).then(([url, options]) => {
expect(url).toBe('/api/test?localeCode=el-GR');
expect(options.method).toBe('POST');
expect(options.headers['Content-Type']).toBe('application/json');
expect(options.headers['test-header']).toBe('header value');
expect(options.body).toBe('{"args":1}');
done();
}).catch(e => {
// $FlowFixMe
done.fail(e);
});
wasResolved = true;
}
}));
expect(wasResolved).toBeTruthy();
});
test('success status request w/args and options', done => {
const mockEmitter = (0, _createMockEmitter.default)({
emit(type, payload) {
expect(type).toBe('rpc:method-client');
expect(payload.method).toBe('test');
expect(payload.status).toBe('success');
expect(typeof payload.timing).toBe('number');
}
});
const app = createTestFixture();
// $FlowFixMe
app.register(_fusionPluginUniversalEvents.UniversalEventsToken, mockEmitter);
let wasResolved = false;
(0, _fusionTestUtils.getSimulator)(app, (0, _fusionCore.createPlugin)({
deps: {
rpcFactory: MockPluginToken
},
provides: deps => {
const rpc = deps.rpcFactory.from({
memoized: new Map()
});
expect(typeof rpc.request).toBe('function');
expect(rpc.request('test') instanceof Promise).toBeTruthy();
rpc.request('test', {
args: 1
}, null, {
credentials: 'omit'
}).then(([url, options]) => {
expect(url).toBe('/api/test?localeCode=el-GR');
expect(options.method).toBe('POST');
expect(options.headers['Content-Type']).toBe('application/json');
expect(options.credentials).toBe('omit');
expect(options.body).toBe('{"args":1}');
done();
}).catch(e => {
// $FlowFixMe
done.fail(e);
});
wasResolved = true;
}
}));
expect(wasResolved).toBeTruthy();
});
test('success status request w/form data', done => {
const mockEmitter = (0, _createMockEmitter.default)({
emit(type, payload) {
expect(type).toBe('rpc:method-client');
expect(payload.method).toBe('test');
expect(payload.status).toBe('success');
expect(typeof payload.timing).toBe('number');
}
});
const app = createTestFixture();
// $FlowFixMe
app.register(_fusionPluginUniversalEvents.UniversalEventsToken, mockEmitter);
let wasResolved = false;
(0, _fusionTestUtils.getSimulator)(app, (0, _fusionCore.createPlugin)({
deps: {
rpcFactory: MockPluginToken
},
provides: deps => {
const rpc = deps.rpcFactory.from({
memoized: new Map()
});
expect(typeof rpc.request).toBe('function');
expect(rpc.request('test') instanceof Promise).toBeTruthy();
/* eslint-disable cup/no-undef */
const formData = new FormData();
formData.append('random', 'some-random');
formData.append('foo', 'foo content');
const mockFile_1 = new File(['foo'], 'foo.csv', {
type: 'text/csv'
});
const mockFile_2 = new File(['bar'], 'bar.csv', {
type: 'text/csv'
});
formData.append('fooFile', mockFile_1);
formData.append('barFile', mockFile_2);
/* eslint-enable cup/no-undef */
rpc.request('test', formData).then(([url, options]) => {
expect(url).toBe('/api/test?localeCode=el-GR');
expect(options.method).toBe('POST');
expect(options.headers['Content-Type']).toBe(undefined);
// In tests or log, this will show up as `{}`. Don't be fooled~
expect(options.body).toBe(formData);
expect(Array.from(options.body.entries())).toEqual([['random', 'some-random'], ['foo', 'foo content'], ['fooFile', mockFile_1], ['barFile', mockFile_2]]);
done();
}).catch(e => {
// $FlowFixMe
done.fail(e);
});
wasResolved = true;
}
}));
expect(wasResolved).toBeTruthy();
});
test('failure status request', done => {
const mockFetchAsFailure = () => Promise.resolve({
json: () => ({
status: 'failure',
data: 'failure data'
})
});
const mockEmitter = (0, _createMockEmitter.default)({
emit(type, payload) {
expect(type).toBe('rpc:method-client');
expect(payload.method).toBe('test');
expect(payload.status).toBe('failure');
expect(typeof payload.timing).toBe('number');
expect(payload.error).toBe('failure data');
}
});
const app = createTestFixture();
// @ts-ignore
app.register(_fusionTokens.FetchToken, mockFetchAsFailure);
// $FlowFixMe
app.register(_fusionPluginUniversalEvents.UniversalEventsToken, mockEmitter);
let wasResolved = false;
(0, _fusionTestUtils.getSimulator)(app, (0, _fusionCore.createPlugin)({
deps: {
rpcFactory: MockPluginToken
},
provides: deps => {
const rpc = deps.rpcFactory.from({
memoized: new Map()
});
expect(typeof rpc.request).toBe('function');
const testRequest = rpc.request('test');
expect(testRequest instanceof Promise).toBeTruthy();
testRequest.then(() => {
// @ts-ignore
done.fail(() => new Error('should reject promise'));
}).catch(e => {
expect(e).toBe('failure data');
done();
});
wasResolved = true;
}
}));
expect(wasResolved).toBeTruthy();
});
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJNb2NrUGx1Z2luVG9rZW4iLCJjcmVhdGVUb2tlbiIsImNyZWF0ZVRlc3RGaXh0dXJlIiwibW9ja0ZldGNoIiwiYXJncyIsIlByb21pc2UiLCJyZXNvbHZlIiwianNvbiIsInN0YXR1cyIsImRhdGEiLCJtb2NrRW1pdHRlciIsIk1vY2tFbWl0dGVyIiwibW9ja0VtaXR0ZXJQbHVnaW4iLCJjcmVhdGVQbHVnaW4iLCJwcm92aWRlcyIsIm1vY2tJMThuUGx1Z2luIiwiZnJvbSIsImxvY2FsZSIsImxvYWQiLCJ0cmFuc2xhdGUiLCJhcHAiLCJBcHAiLCJlbCIsInJlZ2lzdGVyIiwiRmV0Y2hUb2tlbiIsIlVuaXZlcnNhbEV2ZW50c1Rva2VuIiwiSTE4blRva2VuIiwiUlBDUGx1Z2luIiwidGVzdCIsImRvbmUiLCJjcmVhdGVNb2NrRW1pdHRlciIsImVtaXQiLCJ0eXBlIiwicGF5bG9hZCIsImV4cGVjdCIsInRvQmUiLCJtZXRob2QiLCJ0aW1pbmciLCJ3YXNSZXNvbHZlZCIsImdldFNpbXVsYXRvciIsImRlcHMiLCJycGNGYWN0b3J5IiwicnBjIiwibWVtb2l6ZWQiLCJNYXAiLCJyZXF1ZXN0IiwidG9CZVRydXRoeSIsInRoZW4iLCJ1cmwiLCJvcHRpb25zIiwiaGVhZGVycyIsImJvZHkiLCJjYXRjaCIsImUiLCJmYWlsIiwiUlBDUXVlcnlQYXJhbXNUb2tlbiIsIlJQQ0hhbmRsZXJzQ29uZmlnVG9rZW4iLCJhcGlQYXRoIiwiY3JlZGVudGlhbHMiLCJmb3JtRGF0YSIsIkZvcm1EYXRhIiwiYXBwZW5kIiwibW9ja0ZpbGVfMSIsIkZpbGUiLCJtb2NrRmlsZV8yIiwidW5kZWZpbmVkIiwiQXJyYXkiLCJlbnRyaWVzIiwidG9FcXVhbCIsIm1vY2tGZXRjaEFzRmFpbHVyZSIsImVycm9yIiwidGVzdFJlcXVlc3QiLCJFcnJvciJdLCJzb3VyY2VzIjpbInNyYy9fX3Rlc3RzX18vaW5kZXguYnJvd3Nlci50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKiogQ29weXJpZ2h0IChjKSAyMDE4IFViZXIgVGVjaG5vbG9naWVzLCBJbmMuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuXG4gKlxuICovXG5cbmltcG9ydCBNb2NrRW1pdHRlciBmcm9tICdldmVudHMnO1xuXG5pbXBvcnQgQXBwLCB7Y3JlYXRlUGx1Z2luLCBjcmVhdGVUb2tlbn0gZnJvbSAnZnVzaW9uLWNvcmUnO1xuaW1wb3J0IHtGZXRjaFRva2VufSBmcm9tICdmdXNpb24tdG9rZW5zJztcbmltcG9ydCB7Z2V0U2ltdWxhdG9yfSBmcm9tICdmdXNpb24tdGVzdC11dGlscyc7XG5pbXBvcnQgdHlwZSB7VG9rZW59IGZyb20gJ2Z1c2lvbi1jb3JlJztcbmltcG9ydCB7VW5pdmVyc2FsRXZlbnRzVG9rZW59IGZyb20gJ2Z1c2lvbi1wbHVnaW4tdW5pdmVyc2FsLWV2ZW50cyc7XG5pbXBvcnQge0kxOG5Ub2tlbn0gZnJvbSAnZnVzaW9uLXBsdWdpbi1pMThuJztcblxuaW1wb3J0IFJQQ1BsdWdpbiBmcm9tICcuLi9icm93c2VyJztcbmltcG9ydCB0eXBlIHtJRW1pdHRlcn0gZnJvbSAnLi4vdHlwZXMnO1xuaW1wb3J0IGNyZWF0ZU1vY2tFbWl0dGVyIGZyb20gJy4vY3JlYXRlLW1vY2stZW1pdHRlcic7XG5pbXBvcnQge1JQQ0hhbmRsZXJzQ29uZmlnVG9rZW4sIFJQQ1F1ZXJ5UGFyYW1zVG9rZW59IGZyb20gJy4uL3Rva2Vucyc7XG5cbmNvbnN0IE1vY2tQbHVnaW5Ub2tlbjogVG9rZW48YW55PiA9IGNyZWF0ZVRva2VuKCd0ZXN0LXBsdWdpbi10b2tlbicpO1xuZnVuY3Rpb24gY3JlYXRlVGVzdEZpeHR1cmUoKSB7XG4gIGNvbnN0IG1vY2tGZXRjaCA9ICguLi5hcmdzKSA9PlxuICAgIFByb21pc2UucmVzb2x2ZSh7anNvbjogKCkgPT4gKHtzdGF0dXM6ICdzdWNjZXNzJywgZGF0YTogYXJnc30pfSk7XG4gIC8vIEB0cy1pZ25vcmVcbiAgY29uc3QgbW9ja0VtaXR0ZXI6IElFbWl0dGVyID0gbmV3IE1vY2tFbWl0dGVyKCkgYXMgYW55O1xuICBjb25zdCBtb2NrRW1pdHRlclBsdWdpbiA9IGNyZWF0ZVBsdWdpbih7XG4gICAgcHJvdmlkZXM6ICgpID0+IG1vY2tFbWl0dGVyLFxuICB9KTtcbiAgY29uc3QgbW9ja0kxOG5QbHVnaW4gPSBjcmVhdGVQbHVnaW4oe1xuICAgIHByb3ZpZGVzOiAoKSA9PiAoe1xuICAgICAgZnJvbTogKCkgPT4gKHtcbiAgICAgICAgbG9jYWxlOiAnZWwtR1InLFxuICAgICAgICBsb2FkOiBhc3luYyAoKSA9PiB7fSxcbiAgICAgICAgdHJhbnNsYXRlOiAoKSA9PiAnJyxcbiAgICAgIH0pLFxuICAgIH0pLFxuICB9KTtcblxuICBjb25zdCBhcHAgPSBuZXcgQXBwKCdjb250ZW50JywgKGVsKSA9PiBlbCk7XG4gIC8vIEB0cy1pZ25vcmVcbiAgYXBwLnJlZ2lzdGVyKEZldGNoVG9rZW4sIG1vY2tGZXRjaCk7XG4gIGFwcC5yZWdpc3RlcihVbml2ZXJzYWxFdmVudHNUb2tlbiwgbW9ja0VtaXR0ZXJQbHVnaW4pO1xuICBhcHAucmVnaXN0ZXIoSTE4blRva2VuLCBtb2NrSTE4blBsdWdpbik7XG4gIGFwcC5yZWdpc3RlcihNb2NrUGx1Z2luVG9rZW4sIFJQQ1BsdWdpbik7XG4gIHJldHVybiBhcHA7XG59XG5cbnRlc3QoJ3N1Y2Nlc3Mgc3RhdHVzIHJlcXVlc3QnLCAoZG9uZSkgPT4ge1xuICBjb25zdCBtb2NrRW1pdHRlciA9IGNyZWF0ZU1vY2tFbWl0dGVyKHtcbiAgICBlbWl0KHR5cGUsIHBheWxvYWQpIHtcbiAgICAgIGV4cGVjdCh0eXBlKS50b0JlKCdycGM6bWV0aG9kLWNsaWVudCcpO1xuICAgICAgZXhwZWN0KHBheWxvYWQubWV0aG9kKS50b0JlKCd0ZXN0Jyk7XG4gICAgICBleHBlY3QocGF5bG9hZC5zdGF0dXMpLnRvQmUoJ3N1Y2Nlc3MnKTtcbiAgICAgIGV4cGVjdCh0eXBlb2YgcGF5bG9hZC50aW1pbmcpLnRvQmUoJ251bWJlcicpO1xuICAgIH0sXG4gIH0pO1xuICBjb25zdCBhcHAgPSBjcmVhdGVUZXN0Rml4dHVyZSgpO1xuICBhcHAucmVnaXN0ZXIoVW5pdmVyc2FsRXZlbnRzVG9rZW4sIG1vY2tFbWl0dGVyKTtcblxuICBsZXQgd2FzUmVzb2x2ZWQgPSBmYWxzZTtcbiAgZ2V0U2ltdWxhdG9yKFxuICAgIGFwcCxcbiAgICBjcmVhdGVQbHVnaW4oe1xuICAgICAgZGVwczoge3JwY0ZhY3Rvcnk6IE1vY2tQbHVnaW5Ub2tlbn0sXG4gICAgICBwcm92aWRlczogKGRlcHMpID0+IHtcbiAgICAgICAgY29uc3QgcnBjID0gZGVwcy5ycGNGYWN0b3J5LmZyb20oe1xuICAgICAgICAgIG1lbW9pemVkOiBuZXcgTWFwKCksXG4gICAgICAgIH0pO1xuICAgICAgICBleHBlY3QodHlwZW9mIHJwYy5yZXF1ZXN0KS50b0JlKCdmdW5jdGlvbicpO1xuICAgICAgICBleHBlY3QocnBjLnJlcXVlc3QoJ3Rlc3QnKSBpbnN0YW5jZW9mIFByb21pc2UpLnRvQmVUcnV0aHkoKTtcbiAgICAgICAgcnBjXG4gICAgICAgICAgLnJlcXVlc3QoJ3Rlc3QnKVxuICAgICAgICAgIC50aGVuKChbdXJsLCBvcHRpb25zXSkgPT4ge1xuICAgICAgICAgICAgZXhwZWN0KHVybCkudG9CZSgnL2FwaS90ZXN0P2xvY2FsZUNvZGU9ZWwtR1InKTtcbiAgICAgICAgICAgIGV4cGVjdChvcHRpb25zLm1ldGhvZCkudG9CZSgnUE9TVCcpO1xuICAgICAgICAgICAgZXhwZWN0KG9wdGlvbnMuaGVhZGVyc1snQ29udGVudC1UeXBlJ10pLnRvQmUoJ2FwcGxpY2F0aW9uL2pzb24nKTtcbiAgICAgICAgICAgIGV4cGVjdChvcHRpb25zLmJvZHkpLnRvQmUoJ3t9Jyk7XG4gICAgICAgICAgICBkb25lKCk7XG4gICAgICAgICAgfSlcbiAgICAgICAgICAuY2F0Y2goKGUpID0+IHtcbiAgICAgICAgICAgIC8vICRGbG93Rml4TWVcbiAgICAgICAgICAgIGRvbmUuZmFpbChlKTtcbiAgICAgICAgICB9KTtcblxuICAgICAgICB3YXNSZXNvbHZlZCA9IHRydWU7XG4gICAgICB9LFxuICAgIH0pXG4gICk7XG5cbiAgZXhwZWN0KHdhc1Jlc29sdmVkKS50b0JlVHJ1dGh5KCk7XG59KTtcblxudGVzdCgnc3VjY2VzcyBzdGF0dXMgcmVxdWVzdCB3aXRoIGFkZGl0aW9uYWwgcXVlcnkgcGFyYW1zJywgKGRvbmUpID0+IHtcbiAgY29uc3QgbW9ja0VtaXR0ZXIgPSBjcmVhdGVNb2NrRW1pdHRlcih7XG4gICAgZW1pdCh0eXBlLCBwYXlsb2FkKSB7XG4gICAgICBleHBlY3QodHlwZSkudG9CZSgncnBjOm1ldGhvZC1jbGllbnQnKTtcbiAgICAgIGV4cGVjdChwYXlsb2FkLm1ldGhvZCkudG9CZSgndGVzdCcpO1xuICAgICAgZXhwZWN0KHBheWxvYWQuc3RhdHVzKS50b0JlKCdzdWNjZXNzJyk7XG4gICAgICBleHBlY3QodHlwZW9mIHBheWxvYWQudGltaW5nKS50b0JlKCdudW1iZXInKTtcbiAgICB9LFxuICB9KTtcbiAgY29uc3QgYXBwID0gY3JlYXRlVGVzdEZpeHR1cmUoKTtcbiAgYXBwLnJlZ2lzdGVyKFVuaXZlcnNhbEV2ZW50c1Rva2VuLCBtb2NrRW1pdHRlcik7XG4gIGFwcC5yZWdpc3RlcihSUENRdWVyeVBhcmFtc1Rva2VuLCB7XG4gICAgZnJvbSgpIHtcbiAgICAgIHJldHVybiBbWydoZWxsbycsICd3b3JsZCddXTtcbiAgICB9LFxuICB9KTtcblxuICBsZXQgd2FzUmVzb2x2ZWQgPSBmYWxzZTtcbiAgZ2V0U2ltdWxhdG9yKFxuICAgIGFwcCxcbiAgICBjcmVhdGVQbHVnaW4oe1xuICAgICAgZGVwczoge3JwY0ZhY3Rvcnk6IE1vY2tQbHVnaW5Ub2tlbn0sXG4gICAgICBwcm92aWRlczogKGRlcHMpID0+IHtcbiAgICAgICAgY29uc3QgcnBjID0gZGVwcy5ycGNGYWN0b3J5LmZyb20oe1xuICAgICAgICAgIG1lbW9pemVkOiBuZXcgTWFwKCksXG4gICAgICAgIH0pO1xuICAgICAgICBleHBlY3QodHlwZW9mIHJwYy5yZXF1ZXN0KS50b0JlKCdmdW5jdGlvbicpO1xuICAgICAgICBleHBlY3QocnBjLnJlcXVlc3QoJ3Rlc3QnKSBpbnN0YW5jZW9mIFByb21pc2UpLnRvQmVUcnV0aHkoKTtcbiAgICAgICAgcnBjXG4gICAgICAgICAgLnJlcXVlc3QoJ3Rlc3QnKVxuICAgICAgICAgIC50aGVuKChbdXJsLCBvcHRpb25zXSkgPT4ge1xuICAgICAgICAgICAgZXhwZWN0KHVybCkudG9CZSgnL2FwaS90ZXN0P2hlbGxvPXdvcmxkJmxvY2FsZUNvZGU9ZWwtR1InKTtcbiAgICAgICAgICAgIGV4cGVjdChvcHRpb25zLm1ldGhvZCkudG9CZSgnUE9TVCcpO1xuICAgICAgICAgICAgZXhwZWN0KG9wdGlvbnMuaGVhZGVyc1snQ29udGVudC1UeXBlJ10pLnRvQmUoJ2FwcGxpY2F0aW9uL2pzb24nKTtcbiAgICAgICAgICAgIGV4cGVjdChvcHRpb25zLmJvZHkpLnRvQmUoJ3t9Jyk7XG4gICAgICAgICAgICBkb25lKCk7XG4gICAgICAgICAgfSlcbiAgICAgICAgICAuY2F0Y2goKGUpID0+IHtcbiAgICAgICAgICAgIC8vICRGbG93Rml4TWVcbiAgICAgICAgICAgIGRvbmUuZmFpbChlKTtcbiAgICAgICAgICB9KTtcblxuICAgICAgICB3YXNSZXNvbHZlZCA9IHRydWU7XG4gICAgICB9LFxuICAgIH0pXG4gICk7XG5cbiAgZXhwZWN0KHdhc1Jlc29sdmVkKS50b0JlVHJ1dGh5KCk7XG59KTtcblxudGVzdCgnc3VjY2VzcyBzdGF0dXMgcmVxdWVzdCAod2l0aCBjdXN0b20gYXBpIHBhdGgpJywgKGRvbmUpID0+IHtcbiAgY29uc3QgYXBwID0gY3JlYXRlVGVzdEZpeHR1cmUoKTtcblxuICBhcHAucmVnaXN0ZXIoUlBDSGFuZGxlcnNDb25maWdUb2tlbiwge2FwaVBhdGg6ICd0ZXN0L2FwaS9wYXRoJ30pO1xuXG4gIGxldCB3YXNSZXNvbHZlZCA9IGZhbHNlO1xuICBnZXRTaW11bGF0b3IoXG4gICAgYXBwLFxuICAgIGNyZWF0ZVBsdWdpbih7XG4gICAgICBkZXBzOiB7cnBjRmFjdG9yeTogTW9ja1BsdWdpblRva2VufSxcbiAgICAgIHByb3ZpZGVzOiAoZGVwcykgPT4ge1xuICAgICAgICBjb25zdCBycGMgPSBkZXBzLnJwY0ZhY3RvcnkuZnJvbSh7XG4gICAgICAgICAgbWVtb2l6ZWQ6IG5ldyBNYXAoKSxcbiAgICAgICAgfSk7XG4gICAgICAgIGV4cGVjdCh0eXBlb2YgcnBjLnJlcXVlc3QpLnRvQmUoJ2Z1bmN0aW9uJyk7XG4gICAgICAgIGV4cGVjdChycGMucmVxdWVzdCgndGVzdCcpIGluc3RhbmNlb2YgUHJvbWlzZSkudG9CZVRydXRoeSgpO1xuICAgICAgICBycGNcbiAgICAgICAgICAucmVxdWVzdCgndGVzdCcpXG4gICAgICAgICAgLnRoZW4oKFt1cmwsIG9wdGlvbnNdKSA9PiB7XG4gICAgICAgICAgICBleHBlY3QodXJsKS50b0JlKCcvdGVzdC9hcGkvcGF0aC90ZXN0P2xvY2FsZUNvZGU9ZWwtR1InKTtcbiAgICAgICAgICAgIGV4cGVjdChvcHRpb25zLm1ldGhvZCkudG9CZSgnUE9TVCcpO1xuICAgICAgICAgICAgZXhwZWN0KG9wdGlvbnMuaGVhZGVyc1snQ29udGVudC1UeXBlJ10pLnRvQmUoJ2FwcGxpY2F0aW9uL2pzb24nKTtcbiAgICAgICAgICAgIGV4cGVjdChvcHRpb25zLmJvZHkpLnRvQmUoJ3t9Jyk7XG4gICAgICAgICAgICBkb25lKCk7XG4gICAgICAgICAgfSlcbiAgICAgICAgICAuY2F0Y2goKGUpID0+IHtcbiAgICAgICAgICAgIC8vICRGbG93Rml4TWVcbiAgICAgICAgICAgIGRvbmUuZmFpbChlKTtcbiAgICAgICAgICB9KTtcblxuICAgICAgICB3YXNSZXNvbHZlZCA9IHRydWU7XG4gICAgICB9LFxuICAgIH0pXG4gICk7XG5cbiAgZXhwZWN0KHdhc1Jlc29sdmVkKS50b0JlVHJ1dGh5KCk7XG59KTtcblxudGVzdCgnc3VjY2VzcyBzdGF0dXMgcmVxdWVzdCAod2l0aCBjdXN0b20gYXBpIHBhdGggY29udGFpbmluZyBzbGFzaGVzKScsIChkb25lKSA9PiB7XG4gIGNvbnN0IGFwcCA9IGNyZWF0ZVRlc3RGaXh0dXJlKCk7XG5cbiAgYXBwLnJlZ2lzdGVyKFJQQ0hhbmRsZXJzQ29uZmlnVG9rZW4sIHthcGlQYXRoOiAnLy8vdGVzdC9hcGkvLy9wYXRoLyd9KTtcblxuICBsZXQgd2FzUmVzb2x2ZWQgPSBmYWxzZTtcbiAgZ2V0U2ltdWxhdG9yKFxuICAgIGFwcCxcbiAgICBjcmVhdGVQbHVnaW4oe1xuICAgICAgZGVwczoge3JwY0ZhY3Rvcnk6IE1vY2tQbHVnaW5Ub2tlbn0sXG4gICAgICBwcm92aWRlczogKGRlcHMpID0+IHtcbiAgICAgICAgY29uc3QgcnBjID0gZGVwcy5ycGNGYWN0b3J5LmZyb20oe1xuICAgICAgICAgIG1lbW9pemVkOiBuZXcgTWFwKCksXG4gICAgICAgIH0pO1xuICAgICAgICBleHBlY3QodHlwZW9mIHJwYy5yZXF1ZXN0KS50b0JlKCdmdW5jdGlvbicpO1xuICAgICAgICBleHBlY3QocnBjLnJlcXVlc3QoJ3Rlc3QnKSBpbnN0YW5jZW9mIFByb21pc2UpLnRvQmVUcnV0aHkoKTtcbiAgICAgICAgcnBjXG4gICAgICAgICAgLnJlcXVlc3QoJ3Rlc3QnKVxuICAgICAgICAgIC50aGVuKChbdXJsLCBvcHRpb25zXSkgPT4ge1xuICAgICAgICAgICAgZXhwZWN0KHVybCkudG9CZSgnL3Rlc3QvYXBpL3BhdGgvdGVzdD9sb2NhbGVDb2RlPWVsLUdSJyk7XG4gICAgICAgICAgICBleHBlY3Qob3B0aW9ucy5tZXRob2QpLnRvQmUoJ1BPU1QnKTtcbiAgICAgICAgICAgIGV4cGVjdChvcHRpb25zLmhlYWRlcnNbJ0NvbnRlbnQtVHlwZSddKS50b0JlKCdhcHBsaWNhdGlvbi9qc29uJyk7XG4gICAgICAgICAgICBleHBlY3Qob3B0aW9ucy5ib2R5KS50b0JlKCd7fScpO1xuICAgICAgICAgICAgZG9uZSgpO1xuICAgICAgICAgIH0pXG4gICAgICAgICAgLmNhdGNoKChlKSA9PiB7XG4gICAgICAgICAgICAvLyAkRmxvd0ZpeE1lXG4gICAgICAgICAgICBkb25lLmZhaWwoZSk7XG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgd2FzUmVzb2x2ZWQgPSB0cnVlO1xuICAgICAgfSxcbiAgICB9KVxuICApO1xuXG4gIGV4cGVjdCh3YXNSZXNvbHZlZCkudG9CZVRydXRoeSgpO1xufSk7XG5cbnRlc3QoJ3N1Y2Nlc3Mgc3RhdHVzIHJlcXVlc3Qgdy9hcmdzIGFuZCBoZWFkZXInLCAoZG9uZSkgPT4ge1xuICBjb25zdCBtb2NrRW1pdHRlciA9IGNyZWF0ZU1vY2tFbWl0dGVyKHtcbiAgICBlbWl0KHR5cGUsIHBheWxvYWQpIHtcbiAgICAgIGV4cGVjdCh0eXBlKS50b0JlKCdycGM6bWV0aG9kLWNsaWVudCcpO1xuICAgICAgZXhwZWN0KHBheWxvYWQubWV0aG9kKS50b0JlKCd0ZXN0Jyk7XG4gICAgICBleHBlY3QocGF5bG9hZC5zdGF0dXMpLnRvQmUoJ3N1Y2Nlc3MnKTtcbiAgICAgIGV4cGVjdCh0eXBlb2YgcGF5bG9hZC50aW1pbmcpLnRvQmUoJ251bWJlcicpO1xuICAgIH0sXG4gIH0pO1xuICBjb25zdCBhcHAgPSBjcmVhdGVUZXN0Rml4dHVyZSgpO1xuICAvLyAkRmxvd0ZpeE1lXG4gIGFwcC5yZWdpc3RlcihVbml2ZXJzYWxFdmVudHNUb2tlbiwgbW9ja0VtaXR0ZXIpO1xuXG4gIGxldCB3YXNSZXNvbHZlZCA9IGZhbHNlO1xuICBnZXRTaW11bGF0b3IoXG4gICAgYXBwLFxuICAgIGNyZWF0ZVBsdWdpbih7XG4gICAgICBkZXBzOiB7cnBjRmFjdG9yeTogTW9ja1BsdWdpblRva2VufSxcbiAgICAgIHByb3ZpZGVzOiAoZGVwcykgPT4ge1xuICAgICAgICBjb25zdCBycGMgPSBkZXBzLnJwY0ZhY3RvcnkuZnJvbSh7XG4gICAgICAgICAgbWVtb2l6ZWQ6IG5ldyBNYXAoKSxcbiAgICAgICAgfSk7XG4gICAgICAgIGV4cGVjdCh0eXBlb2YgcnBjLnJlcXVlc3QpLnRvQmUoJ2Z1bmN0aW9uJyk7XG4gICAgICAgIGV4cGVjdChycGMucmVxdWVzdCgndGVzdCcpIGluc3RhbmNlb2YgUHJvbWlzZSkudG9CZVRydXRoeSgpO1xuICAgICAgICBycGNcbiAgICAgICAgICAucmVxdWVzdCgndGVzdCcsIHthcmdzOiAxfSwgeyd0ZXN0LWhlYWRlcic6ICdoZWFkZXIgdmFsdWUnfSlcbiAgICAgICAgICAudGhlbigoW3VybCwgb3B0aW9uc10pID0+IHtcbiAgICAgICAgICAgIGV4cGVjdCh1cmwpLnRvQmUoJy9hcGkvdGVzdD9sb2NhbGVDb2RlPWVsLUdSJyk7XG4gICAgICAgICAgICBleHBlY3Qob3B0aW9ucy5tZXRob2QpLnRvQmUoJ1BPU1QnKTtcbiAgICAgICAgICAgIGV4cGVjdChvcHRpb25zLmhlYWRlcnNbJ0NvbnRlbnQtVHlwZSddKS50b0JlKCdhcHBsaWNhdGlvbi9qc29uJyk7XG4gICAgICAgICAgICBleHBlY3Qob3B0aW9ucy5oZWFkZXJzWyd0ZXN0LWhlYWRlciddKS50b0JlKCdoZWFkZXIgdmFsdWUnKTtcbiAgICAgICAgICAgIGV4cGVjdChvcHRpb25zLmJvZHkpLnRvQmUoJ3tcImFyZ3NcIjoxfScpO1xuICAgICAgICAgICAgZG9uZSgpO1xuICAgICAgICAgIH0pXG4gICAgICAgICAgLmNhdGNoKChlKSA9PiB7XG4gICAgICAgICAgICAvLyAkRmxvd0ZpeE1lXG4gICAgICAgICAgICBkb25lLmZhaWwoZSk7XG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgd2FzUmVzb2x2ZWQgPSB0cnVlO1xuICAgICAgfSxcbiAgICB9KVxuICApO1xuXG4gIGV4cGVjdCh3YXNSZXNvbHZlZCkudG9CZVRydXRoeSgpO1xufSk7XG5cbnRlc3QoJ3N1Y2Nlc3Mgc3RhdHVzIHJlcXVlc3Qgdy9hcmdzIGFuZCBvcHRpb25zJywgKGRvbmUpID0+IHtcbiAgY29uc3QgbW9ja0VtaXR0ZXIgPSBjcmVhdGVNb2NrRW1pdHRlcih7XG4gICAgZW1pdCh0eXBlLCBwYXlsb2FkKSB7XG4gICAgICBleHBlY3QodHlwZSkudG9CZSgncnBjOm1ldGhvZC1jbGllbnQnKTtcbiAgICAgIGV4cGVjdChwYXlsb2FkLm1ldGhvZCkudG9CZSgndGVzdCcpO1xuICAgICAgZXhwZWN0KHBheWxvYWQuc3RhdHVzKS50b0JlKCdzdWNjZXNzJyk7XG4gICAgICBleHBlY3QodHlwZW9mIHBheWxvYWQudGltaW5nKS50b0JlKCdudW1iZXInKTtcbiAgICB9LFxuICB9KTtcbiAgY29uc3QgYXBwID0gY3JlYXRlVGVzdEZpeHR1cmUoKTtcbiAgLy8gJEZsb3dGaXhNZVxuICBhcHAucmVnaXN0ZXIoVW5pdmVyc2FsRXZlbnRzVG9rZW4sIG1vY2tFbWl0dGVyKTtcblxuICBsZXQgd2FzUmVzb2x2ZWQgPSBmYWxzZTtcbiAgZ2V0U2ltdWxhdG9yKFxuICAgIGFwcCxcbiAgICBjcmVhdGVQbHVnaW4oe1xuICAgICAgZGVwczoge3JwY0ZhY3Rvcnk6IE1vY2tQbHVnaW5Ub2tlbn0sXG4gICAgICBwcm92aWRlczogKGRlcHMpID0+IHtcbiAgICAgICAgY29uc3QgcnBjID0gZGVwcy5ycGNGYWN0b3J5LmZyb20oe1xuICAgICAgICAgIG1lbW9pemVkOiBuZXcgTWFwKCksXG4gICAgICAgIH0pO1xuICAgICAgICBleHBlY3QodHlwZW9mIHJwYy5yZXF1ZXN0KS50b0JlKCdmdW5jdGlvbicpO1xuICAgICAgICBleHBlY3QocnBjLnJlcXVlc3QoJ3Rlc3QnKSBpbnN0YW5jZW9mIFByb21pc2UpLnRvQmVUcnV0aHkoKTtcbiAgICAgICAgcnBjXG4gICAgICAgICAgLnJlcXVlc3QoJ3Rlc3QnLCB7YXJnczogMX0sIG51bGwsIHtjcmVkZW50aWFsczogJ29taXQnfSlcbiAgICAgICAgICAudGhlbigoW3VybCwgb3B0aW9uc10pID0+IHtcbiAgICAgICAgICAgIGV4cGVjdCh1cmwpLnRvQmUoJy9hcGkvdGVzdD9sb2NhbGVDb2RlPWVsLUdSJyk7XG4gICAgICAgICAgICBleHBlY3Qob3B0aW9ucy5tZXRob2QpLnRvQmUoJ1BPU1QnKTtcbiAgICAgICAgICAgIGV4cGVjdChvcHRpb25zLmhlYWRlcnNbJ0NvbnRlbnQtVHlwZSddKS50b0JlKCdhcHBsaWNhdGlvbi9qc29uJyk7XG4gICAgICAgICAgICBleHBlY3Qob3B0aW9ucy5jcmVkZW50aWFscykudG9CZSgnb21pdCcpO1xuICAgICAgICAgICAgZXhwZWN0KG9wdGlvbnMuYm9keSkudG9CZSgne1wiYXJnc1wiOjF9Jyk7XG4gICAgICAgICAgICBkb25lKCk7XG4gICAgICAgICAgfSlcbiAgICAgICAgICAuY2F0Y2goKGUpID0+IHtcbiAgICAgICAgICAgIC8vICRGbG93Rml4TWVcbiAgICAgICAgICAgIGRvbmUuZmFpbChlKTtcbiAgICAgICAgICB9KTtcblxuICAgICAgICB3YXNSZXNvbHZlZCA9IHRydWU7XG4gICAgICB9LFxuICAgIH0pXG4gICk7XG5cbiAgZXhwZWN0KHdhc1Jlc29sdmVkKS50b0JlVHJ1dGh5KCk7XG59KTtcblxudGVzdCgnc3VjY2VzcyBzdGF0dXMgcmVxdWVzdCB3L2Zvcm0gZGF0YScsIChkb25lKSA9PiB7XG4gIGNvbnN0IG1vY2tFbWl0dGVyID0gY3JlYXRlTW9ja0VtaXR0ZXIoe1xuICAgIGVtaXQodHlwZSwgcGF5bG9hZCkge1xuICAgICAgZXhwZWN0KHR5cGUpLnRvQmUoJ3JwYzptZXRob2QtY2xpZW50Jyk7XG4gICAgICBleHBlY3QocGF5bG9hZC5tZXRob2QpLnRvQmUoJ3Rlc3QnKTtcbiAgICAgIGV4cGVjdChwYXlsb2FkLnN0YXR1cykudG9CZSgnc3VjY2VzcycpO1xuICAgICAgZXhwZWN0KHR5cGVvZiBwYXlsb2FkLnRpbWluZykudG9CZSgnbnVtYmVyJyk7XG4gICAgfSxcbiAgfSk7XG4gIGNvbnN0IGFwcCA9IGNyZWF0ZVRlc3RGaXh0dXJlKCk7XG4gIC8vICRGbG93Rml4TWVcbiAgYXBwLnJlZ2lzdGVyKFVuaXZlcnNhbEV2ZW50c1Rva2VuLCBtb2NrRW1pdHRlcik7XG5cbiAgbGV0IHdhc1Jlc29sdmVkID0gZmFsc2U7XG4gIGdldFNpbXVsYXRvcihcbiAgICBhcHAsXG4gICAgY3JlYXRlUGx1Z2luKHtcbiAgICAgIGRlcHM6IHtycGNGYWN0b3J5OiBNb2NrUGx1Z2luVG9rZW59LFxuICAgICAgcHJvdmlkZXM6IChkZXBzKSA9PiB7XG4gICAgICAgIGNvbnN0IHJwYyA9IGRlcHMucnBjRmFjdG9yeS5mcm9tKHtcbiAgICAgICAgICBtZW1vaXplZDogbmV3IE1hcCgpLFxuICAgICAgICB9KTtcbiAgICAgICAgZXhwZWN0KHR5cGVvZiBycGMucmVxdWVzdCkudG9CZSgnZnVuY3Rpb24nKTtcbiAgICAgICAgZXhwZWN0KHJwYy5yZXF1ZXN0KCd0ZXN0JykgaW5zdGFuY2VvZiBQcm9taXNlKS50b0JlVHJ1dGh5KCk7XG4gICAgICAgIC8qIGVzbGludC1kaXNhYmxlIGN1cC9uby11bmRlZiAqL1xuICAgICAgICBjb25zdCBmb3JtRGF0YSA9IG5ldyBGb3JtRGF0YSgpO1xuICAgICAgICBmb3JtRGF0YS5hcHBlbmQoJ3JhbmRvbScsICdzb21lLXJhbmRvbScpO1xuICAgICAgICBmb3JtRGF0YS5hcHBlbmQoJ2ZvbycsICdmb28gY29udGVudCcpO1xuXG4gICAgICAgIGNvbnN0IG1vY2tGaWxlXzEgPSBuZXcgRmlsZShbJ2ZvbyddLCAnZm9vLmNzdicsIHt0eXBlOiAndGV4dC9jc3YnfSk7XG4gICAgICAgIGNvbnN0IG1vY2tGaWxlXzIgPSBuZXcgRmlsZShbJ2JhciddLCAnYmFyLmNzdicsIHt0eXBlOiAndGV4dC9jc3YnfSk7XG5cbiAgICAgICAgZm9ybURhdGEuYXBwZW5kKCdmb29GaWxlJywgbW9ja0ZpbGVfMSk7XG4gICAgICAgIGZvcm1EYXRhLmFwcGVuZCgnYmFyRmlsZScsIG1vY2tGaWxlXzIpO1xuXG4gICAgICAgIC8qIGVzbGludC1lbmFibGUgY3VwL25vLXVuZGVmICovXG5cbiAgICAgICAgcnBjXG4gICAgICAgICAgLnJlcXVlc3QoJ3Rlc3QnLCBmb3JtRGF0YSlcbiAgICAgICAgICAudGhlbigoW3VybCwgb3B0aW9uc10pID0+IHtcbiAgICAgICAgICAgIGV4cGVjdCh1cmwpLnRvQmUoJy9hcGkvdGVzdD9sb2NhbGVDb2RlPWVsLUdSJyk7XG4gICAgICAgICAgICBleHBlY3Qob3B0aW9ucy5tZXRob2QpLnRvQmUoJ1BPU1QnKTtcbiAgICAgICAgICAgIGV4cGVjdChvcHRpb25zLmhlYWRlcnNbJ0NvbnRlbnQtVHlwZSddKS50b0JlKHVuZGVmaW5lZCk7XG4gICAgICAgICAgICAvLyBJbiB0ZXN0cyBvciBsb2csIHRoaXMgd2lsbCBzaG93IHVwIGFzIGB7fWAuIERvbid0IGJlIGZvb2xlZH5cbiAgICAgICAgICAgIGV4cGVjdChvcHRpb25zLmJvZHkpLnRvQmUoZm9ybURhdGEpO1xuICAgICAgICAgICAgZXhwZWN0KEFycmF5LmZyb20ob3B0aW9ucy5ib2R5LmVudHJpZXMoKSkpLnRvRXF1YWwoW1xuICAgICAgICAgICAgICBbJ3JhbmRvbScsICdzb21lLXJhbmRvbSddLFxuICAgICAgICAgICAgICBbJ2ZvbycsICdmb28gY29udGVudCddLFxuICAgICAgICAgICAgICBbJ2Zvb0ZpbGUnLCBtb2NrRmlsZV8xXSxcbiAgICAgICAgICAgICAgWydiYXJGaWxlJywgbW9ja0ZpbGVfMl0sXG4gICAgICAgICAgICBdKTtcbiAgICAgICAgICAgIGRvbmUoKTtcbiAgICAgICAgICB9KVxuICAgICAgICAgIC5jYXRjaCgoZSkgPT4ge1xuICAgICAgICAgICAgLy8gJEZsb3dGaXhNZVxuICAgICAgICAgICAgZG9uZS5mYWlsKGUpO1xuICAgICAgICAgIH0pO1xuXG4gICAgICAgIHdhc1Jlc29sdmVkID0gdHJ1ZTtcbiAgICAgIH0sXG4gICAgfSlcbiAgKTtcblxuICBleHBlY3Qod2FzUmVzb2x2ZWQpLnRvQmVUcnV0aHkoKTtcbn0pO1xuXG50ZXN0KCdmYWlsdXJlIHN0YXR1cyByZXF1ZXN0JywgKGRvbmUpID0+IHtcbiAgY29uc3QgbW9ja0ZldGNoQXNGYWlsdXJlID0gKCkgPT5cbiAgICBQcm9taXNlLnJlc29sdmUoe1xuICAgICAganNvbjogKCkgPT4gKHtzdGF0dXM6ICdmYWlsdXJlJywgZGF0YTogJ2ZhaWx1cmUgZGF0YSd9KSxcbiAgICB9KTtcbiAgY29uc3QgbW9ja0VtaXR0ZXIgPSBjcmVhdGVNb2NrRW1pdHRlcih7XG4gICAgZW1pdCh0eXBlLCBwYXlsb2FkKSB7XG4gICAgICBleHBlY3QodHlwZSkudG9CZSgncnBjOm1ldGhvZC1jbGllbnQnKTtcbiAgICAgIGV4cGVjdChwYXlsb2FkLm1ldGhvZCkudG9CZSgndGVzdCcpO1xuICAgICAgZXhwZWN0KHBheWxvYWQuc3RhdHVzKS50b0JlKCdmYWlsdXJlJyk7XG4gICAgICBleHBlY3QodHlwZW9mIHBheWxvYWQudGltaW5nKS50b0JlKCdudW1iZXInKTtcbiAgICAgIGV4cGVjdChwYXlsb2FkLmVycm9yKS50b0JlKCdmYWlsdXJlIGRhdGEnKTtcbiAgICB9LFxuICB9KTtcblxuICBjb25zdCBhcHAgPSBjcmVhdGVUZXN0Rml4dHVyZSgpO1xuICAvLyBAdHMtaWdub3JlXG4gIGFwcC5yZWdpc3RlcihGZXRjaFRva2VuLCBtb2NrRmV0Y2hBc0ZhaWx1cmUpO1xuICAvLyAkRmxvd0ZpeE1lXG4gIGFwcC5yZWdpc3RlcihVbml2ZXJzYWxFdmVudHNUb2tlbiwgbW9ja0VtaXR0ZXIpO1xuXG4gIGxldCB3YXNSZXNvbHZlZCA9IGZhbHNlO1xuICBnZXRTaW11bGF0b3IoXG4gICAgYXBwLFxuICAgIGNyZWF0ZVBsdWdpbih7XG4gICAgICBkZXBzOiB7cnBjRmFjdG9yeTogTW9ja1BsdWdpblRva2VufSxcbiAgICAgIHByb3ZpZGVzOiAoZGVwcykgPT4ge1xuICAgICAgICBjb25zdCBycGMgPSBkZXBzLnJwY0ZhY3RvcnkuZnJvbSh7XG4gICAgICAgICAgbWVtb2l6ZWQ6IG5ldyBNYXAoKSxcbiAgICAgICAgfSk7XG4gICAgICAgIGV4cGVjdCh0eXBlb2YgcnBjLnJlcXVlc3QpLnRvQmUoJ2Z1bmN0aW9uJyk7XG4gICAgICAgIGNvbnN0IHRlc3RSZXF1ZXN0ID0gcnBjLnJlcXVlc3QoJ3Rlc3QnKTtcbiAgICAgICAgZXhwZWN0KHRlc3RSZXF1ZXN0IGluc3RhbmNlb2YgUHJvbWlzZSkudG9CZVRydXRoeSgpO1xuICAgICAgICB0ZXN0UmVxdWVzdFxuICAgICAgICAgIC50aGVuKCgpID0+IHtcbiAgICAgICAgICAgIC8vIEB0cy1pZ25vcmVcbiAgICAgICAgICAgIGRvbmUuZmFpbCgoKSA9PiBuZXcgRXJyb3IoJ3Nob3VsZCByZWplY3QgcHJvbWlzZScpKTtcbiAgICAgICAgICB9KVxuICAgICAgICAgIC5jYXRjaCgoZSkgPT4ge1xuICAgICAgICAgICAgZXhwZWN0KGUpLnRvQmUoJ2ZhaWx1cmUgZGF0YScpO1xuICAgICAgICAgICAgZG9uZSgpO1xuICAgICAgICAgIH0pO1xuXG4gICAgICAgIHdhc1Jlc29sdmVkID0gdHJ1ZTtcbiAgICAgIH0sXG4gICAgfSlcbiAgKTtcblxuICBleHBlY3Qod2FzUmVzb2x2ZWQpLnRvQmVUcnV0aHkoKTtcbn0pO1xuIl0sIm1hcHBpbmdzIjoiOztBQU9BO0FBRUE7QUFDQTtBQUNBO0FBRUE7QUFDQTtBQUVBO0FBRUE7QUFDQTtBQUFzRTtBQUFBO0FBQUE7QUFuQnRFO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFnQkEsTUFBTUEsZUFBMkIsR0FBRyxJQUFBQyx1QkFBVyxFQUFDLG1CQUFtQixDQUFDO0FBQ3BFLFNBQVNDLGlCQUFpQixHQUFHO0VBQzNCLE1BQU1DLFNBQVMsR0FBRyxDQUFDLEdBQUdDLElBQUksS0FDeEJDLE9BQU8sQ0FBQ0MsT0FBTyxDQUFDO0lBQUNDLElBQUksRUFBRSxPQUFPO01BQUNDLE1BQU0sRUFBRSxTQUFTO01BQUVDLElBQUksRUFBRUw7SUFBSSxDQUFDO0VBQUMsQ0FBQyxDQUFDO0VBQ2xFO0VBQ0EsTUFBTU0sV0FBcUIsR0FBRyxJQUFJQyxlQUFXLEVB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