benchpress
Version:
Benchpress - a framework for e2e performance tests
230 lines • 42.1 kB
JavaScript
import { bind } from 'angular2/src/core/di';
import { ListWrapper, StringMapWrapper } from 'angular2/src/facade/collection';
import { Json, isPresent, isBlank, StringWrapper, NumberWrapper } from 'angular2/src/facade/lang';
import { BaseException } from 'angular2/src/facade/exceptions';
import { WebDriverExtension, PerfLogFeatures } from '../web_driver_extension';
import { WebDriverAdapter } from '../web_driver_adapter';
import { Options } from '../common_options';
/**
* Set the following 'traceCategories' to collect metrics in Chrome:
* 'v8,blink.console,disabled-by-default-devtools.timeline,devtools.timeline'
*
* In order to collect the frame rate related metrics, add 'benchmark'
* to the list above.
*/
export class ChromeDriverExtension extends WebDriverExtension {
constructor(_driver, userAgent) {
super();
this._driver = _driver;
this._majorChromeVersion = this._parseChromeVersion(userAgent);
}
// TODO(tbosch): use static values when our transpiler supports them
static get BINDINGS() { return _PROVIDERS; }
_parseChromeVersion(userAgent) {
if (isBlank(userAgent)) {
return -1;
}
var v = StringWrapper.split(userAgent, /Chrom(e|ium)\//g)[2];
if (isBlank(v)) {
return -1;
}
v = v.split('.')[0];
if (isBlank(v)) {
return -1;
}
return NumberWrapper.parseInt(v, 10);
}
gc() { return this._driver.executeScript('window.gc()'); }
timeBegin(name) {
return this._driver.executeScript(`console.time('${name}');`);
}
timeEnd(name, restartName = null) {
var script = `console.timeEnd('${name}');`;
if (isPresent(restartName)) {
script += `console.time('${restartName}');`;
}
return this._driver.executeScript(script);
}
// See [Chrome Trace Event
// Format](https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/edit)
readPerfLog() {
// TODO(tbosch): Chromedriver bug https://code.google.com/p/chromedriver/issues/detail?id=1098
// Need to execute at least one command so that the browser logs can be read out!
return this._driver.executeScript('1+1')
.then((_) => this._driver.logs('performance'))
.then((entries) => {
var events = [];
entries.forEach(entry => {
var message = Json.parse(entry['message'])['message'];
if (StringWrapper.equals(message['method'], 'Tracing.dataCollected')) {
events.push(message['params']);
}
if (StringWrapper.equals(message['method'], 'Tracing.bufferUsage')) {
throw new BaseException('The DevTools trace buffer filled during the test!');
}
});
return this._convertPerfRecordsToEvents(events);
});
}
_convertPerfRecordsToEvents(chromeEvents, normalizedEvents = null) {
if (isBlank(normalizedEvents)) {
normalizedEvents = [];
}
var majorGCPids = {};
chromeEvents.forEach((event) => {
var categories = this._parseCategories(event['cat']);
var name = event['name'];
if (this._isEvent(categories, name, ['blink.console'])) {
normalizedEvents.push(normalizeEvent(event, { 'name': name }));
}
else if (this._isEvent(categories, name, ['benchmark'], 'BenchmarkInstrumentation::ImplThreadRenderingStats')) {
// TODO(goderbauer): Instead of BenchmarkInstrumentation::ImplThreadRenderingStats the
// following events should be used (if available) for more accurate measurments:
// 1st choice: vsync_before - ground truth on Android
// 2nd choice: BenchmarkInstrumentation::DisplayRenderingStats - available on systems with
// new surfaces framework (not broadly enabled yet)
// 3rd choice: BenchmarkInstrumentation::ImplThreadRenderingStats - fallback event that is
// always available if something is rendered
var frameCount = event['args']['data']['frame_count'];
if (frameCount > 1) {
throw new BaseException('multi-frame render stats not supported');
}
if (frameCount == 1) {
normalizedEvents.push(normalizeEvent(event, { 'name': 'frame' }));
}
}
else if (this._isEvent(categories, name, ['disabled-by-default-devtools.timeline'], 'Rasterize') ||
this._isEvent(categories, name, ['disabled-by-default-devtools.timeline'], 'CompositeLayers')) {
normalizedEvents.push(normalizeEvent(event, { 'name': 'render' }));
}
else if (this._majorChromeVersion < 45) {
var normalizedEvent = this._processAsPreChrome45Event(event, categories, majorGCPids);
if (normalizedEvent != null)
normalizedEvents.push(normalizedEvent);
}
else {
var normalizedEvent = this._processAsPostChrome44Event(event, categories);
if (normalizedEvent != null)
normalizedEvents.push(normalizedEvent);
}
});
return normalizedEvents;
}
_processAsPreChrome45Event(event, categories, majorGCPids) {
var name = event['name'];
var args = event['args'];
var pid = event['pid'];
var ph = event['ph'];
if (this._isEvent(categories, name, ['disabled-by-default-devtools.timeline'], 'FunctionCall') &&
(isBlank(args) || isBlank(args['data']) ||
!StringWrapper.equals(args['data']['scriptName'], 'InjectedScript'))) {
return normalizeEvent(event, { 'name': 'script' });
}
else if (this._isEvent(categories, name, ['disabled-by-default-devtools.timeline'], 'RecalculateStyles') ||
this._isEvent(categories, name, ['disabled-by-default-devtools.timeline'], 'Layout') ||
this._isEvent(categories, name, ['disabled-by-default-devtools.timeline'], 'UpdateLayerTree') ||
this._isEvent(categories, name, ['disabled-by-default-devtools.timeline'], 'Paint')) {
return normalizeEvent(event, { 'name': 'render' });
}
else if (this._isEvent(categories, name, ['disabled-by-default-devtools.timeline'], 'GCEvent')) {
var normArgs = {
'usedHeapSize': isPresent(args['usedHeapSizeAfter']) ? args['usedHeapSizeAfter'] :
args['usedHeapSizeBefore']
};
if (StringWrapper.equals(ph, 'E')) {
normArgs['majorGc'] = isPresent(majorGCPids[pid]) && majorGCPids[pid];
}
majorGCPids[pid] = false;
return normalizeEvent(event, { 'name': 'gc', 'args': normArgs });
}
else if (this._isEvent(categories, name, ['v8'], 'majorGC') &&
StringWrapper.equals(ph, 'B')) {
majorGCPids[pid] = true;
}
return null; // nothing useful in this event
}
_processAsPostChrome44Event(event, categories) {
var name = event['name'];
var args = event['args'];
if (this._isEvent(categories, name, ['devtools.timeline', 'v8'], 'MajorGC')) {
var normArgs = {
'majorGc': true,
'usedHeapSize': isPresent(args['usedHeapSizeAfter']) ? args['usedHeapSizeAfter'] :
args['usedHeapSizeBefore']
};
return normalizeEvent(event, { 'name': 'gc', 'args': normArgs });
}
else if (this._isEvent(categories, name, ['devtools.timeline', 'v8'], 'MinorGC')) {
var normArgs = {
'majorGc': false,
'usedHeapSize': isPresent(args['usedHeapSizeAfter']) ? args['usedHeapSizeAfter'] :
args['usedHeapSizeBefore']
};
return normalizeEvent(event, { 'name': 'gc', 'args': normArgs });
}
else if (this._isEvent(categories, name, ['devtools.timeline', 'v8'], 'FunctionCall') &&
(isBlank(args) || isBlank(args['data']) ||
(!StringWrapper.equals(args['data']['scriptName'], 'InjectedScript') &&
!StringWrapper.equals(args['data']['scriptName'], '')))) {
return normalizeEvent(event, { 'name': 'script' });
}
else if (this._isEvent(categories, name, ['devtools.timeline', 'blink'], 'UpdateLayoutTree')) {
return normalizeEvent(event, { 'name': 'render' });
}
else if (this._isEvent(categories, name, ['devtools.timeline'], 'UpdateLayerTree') ||
this._isEvent(categories, name, ['devtools.timeline'], 'Layout') ||
this._isEvent(categories, name, ['devtools.timeline'], 'Paint')) {
return normalizeEvent(event, { 'name': 'render' });
}
else if (this._isEvent(categories, name, ['devtools.timeline'], 'ResourceReceivedData')) {
let normArgs = { 'encodedDataLength': args['data']['encodedDataLength'] };
return normalizeEvent(event, { 'name': 'receivedData', 'args': normArgs });
}
else if (this._isEvent(categories, name, ['devtools.timeline'], 'ResourceSendRequest')) {
let data = args['data'];
let normArgs = { 'url': data['url'], 'method': data['requestMethod'] };
return normalizeEvent(event, { 'name': 'sendRequest', 'args': normArgs });
}
else if (this._isEvent(categories, name, ['blink.user_timing'], 'navigationStart')) {
return normalizeEvent(event, { 'name': name });
}
return null; // nothing useful in this event
}
_parseCategories(categories) { return categories.split(','); }
_isEvent(eventCategories, eventName, expectedCategories, expectedName = null) {
var hasCategories = expectedCategories.reduce((value, cat) => { return value && ListWrapper.contains(eventCategories, cat); }, true);
return isBlank(expectedName) ? hasCategories :
hasCategories && StringWrapper.equals(eventName, expectedName);
}
perfLogFeatures() {
return new PerfLogFeatures({ render: true, gc: true, frameCapture: true, userTiming: true });
}
supports(capabilities) {
return this._majorChromeVersion != -1 &&
StringWrapper.equals(capabilities['browserName'].toLowerCase(), 'chrome');
}
}
function normalizeEvent(chromeEvent, data) {
var ph = chromeEvent['ph'];
if (StringWrapper.equals(ph, 'S')) {
ph = 'b';
}
else if (StringWrapper.equals(ph, 'F')) {
ph = 'e';
}
var result = { 'pid': chromeEvent['pid'], 'ph': ph, 'cat': 'timeline', 'ts': chromeEvent['ts'] / 1000 };
if (chromeEvent['ph'] === 'X') {
var dur = chromeEvent['dur'];
if (isBlank(dur)) {
dur = chromeEvent['tdur'];
}
result['dur'] = isBlank(dur) ? 0.0 : dur / 1000;
}
StringMapWrapper.forEach(data, (value, prop) => { result[prop] = value; });
return result;
}
var _PROVIDERS = [
bind(ChromeDriverExtension)
.toFactory((driver, userAgent) => new ChromeDriverExtension(driver, userAgent), [WebDriverAdapter, Options.USER_AGENT])
];
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hyb21lX2RyaXZlcl9leHRlbnNpb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJkaWZmaW5nX3BsdWdpbl93cmFwcGVyLW91dHB1dF9wYXRoLXhCTElCclZSLnRtcC9iZW5jaHByZXNzL3NyYy93ZWJkcml2ZXIvY2hyb21lX2RyaXZlcl9leHRlbnNpb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ik9BQU8sRUFBQyxJQUFJLEVBQW9CLE1BQU0sc0JBQXNCO09BQ3JELEVBQUMsV0FBVyxFQUFFLGdCQUFnQixFQUFDLE1BQU0sZ0NBQWdDO09BQ3JFLEVBQ0wsSUFBSSxFQUNKLFNBQVMsRUFDVCxPQUFPLEVBRVAsYUFBYSxFQUNiLGFBQWEsRUFDZCxNQUFNLDBCQUEwQjtPQUMxQixFQUFDLGFBQWEsRUFBbUIsTUFBTSxnQ0FBZ0M7T0FFdkUsRUFBQyxrQkFBa0IsRUFBRSxlQUFlLEVBQUMsTUFBTSx5QkFBeUI7T0FDcEUsRUFBQyxnQkFBZ0IsRUFBQyxNQUFNLHVCQUF1QjtPQUMvQyxFQUFDLE9BQU8sRUFBQyxNQUFNLG1CQUFtQjtBQUV6Qzs7Ozs7O0dBTUc7QUFDSCwyQ0FBMkMsa0JBQWtCO0lBTTNELFlBQW9CLE9BQXlCLEVBQUUsU0FBaUI7UUFDOUQsT0FBTyxDQUFDO1FBRFUsWUFBTyxHQUFQLE9BQU8sQ0FBa0I7UUFFM0MsSUFBSSxDQUFDLG1CQUFtQixHQUFHLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUNqRSxDQUFDO0lBUkQsb0VBQW9FO0lBQ3BFLFdBQVcsUUFBUSxLQUFpQixNQUFNLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQztJQVNoRCxtQkFBbUIsQ0FBQyxTQUFpQjtRQUMzQyxFQUFFLENBQUMsQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQ3ZCLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNaLENBQUM7UUFDRCxJQUFJLENBQUMsR0FBRyxhQUFhLENBQUMsS0FB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QUMscUJBQXFCLENBQUM7U0FDdEIsU0FBUyxDQUFDLENBQUMsTUFBTSxFQUFFLFNBQVMsS0FBSyxJQUFJLHFCQUFxQixDQUFDLE1BQU0sRUFBRSxTQUFTLENBQUMsRUFDbkUsQ0FBQyxnQkFBZ0IsRUFBRSxPQUFPLENBQUMsVUFBVSxDQUFDLENBQUM7Q0FDdkQsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7YmluZCwgcHJvdmlkZSwgUHJvdmlkZXJ9IGZyb20gJ2FuZ3VsYXIyL3NyYy9jb3JlL2RpJztcbmltcG9ydCB7TGlzdFdyYXBwZXIsIFN0cmluZ01hcFdyYXBwZXJ9IGZyb20gJ2FuZ3VsYXIyL3NyYy9mYWNhZGUvY29sbGVjdGlvbic7XG5pbXBvcnQge1xuICBKc29uLFxuICBpc1ByZXNlbnQsXG4gIGlzQmxhbmssXG4gIFJlZ0V4cFdyYXBwZXIsXG4gIFN0cmluZ1dyYXBwZXIsXG4gIE51bWJlcldyYXBwZXJcbn0gZnJvbSAnYW5ndWxhcjIvc3JjL2ZhY2FkZS9sYW5nJztcbmltcG9ydCB7QmFzZUV4Y2VwdGlvbiwgV3JhcHBlZEV4Y2VwdGlvbn0gZnJvbSAnYW5ndWxhcjIvc3JjL2ZhY2FkZS9leGNlcHRpb25zJztcblxuaW1wb3J0IHtXZWJEcml2ZXJFeHRlbnNpb24sIFBlcmZMb2dGZWF0dXJlc30gZnJvbSAnLi4vd2ViX2RyaXZlcl9leHRlbnNpb24nO1xuaW1wb3J0IHtXZWJEcml2ZXJBZGFwdGVyfSBmcm9tICcuLi93ZWJfZHJpdmVyX2FkYXB0ZXInO1xuaW1wb3J0IHtPcHRpb25zfSBmcm9tICcuLi9jb21tb25fb3B0aW9ucyc7XG5cbi8qKlxuICogU2V0IHRoZSBmb2xsb3dpbmcgJ3RyYWNlQ2F0ZWdvcmllcycgdG8gY29sbGVjdCBtZXRyaWNzIGluIENocm9tZTpcbiAqICd2OCxibGluay5jb25zb2xlLGRpc2FibGVkLWJ5LWRlZmF1bHQtZGV2dG9vbHMudGltZWxpbmUsZGV2dG9vbHMudGltZWxpbmUnXG4gKlxuICogSW4gb3JkZXIgdG8gY29sbGVjdCB0aGUgZnJhbWUgcmF0ZSByZWxhdGVkIG1ldHJpY3MsIGFkZCAnYmVuY2htYXJrJ1xuICogdG8gdGhlIGxpc3QgYWJvdmUuXG4gKi9cbmV4cG9ydCBjbGFzcyBDaHJvbWVEcml2ZXJFeHRlbnNpb24gZXh0ZW5kcyBXZWJEcml2ZXJFeHRlbnNpb24ge1xuICAvLyBUT0RPKHRib3NjaCk6IHVzZSBzdGF0aWMgdmFsdWVzIHdoZW4gb3VyIHRyYW5zcGlsZXIgc3VwcG9ydHMgdGhlbVxuICBzdGF0aWMgZ2V0IEJJTkRJTkdTKCk6IFByb3ZpZGVyW10geyByZXR1cm4gX1BST1ZJREVSUzsgfVxuXG4gIHByaXZhdGUgX21ham9yQ2hyb21lVmVyc2lvbjogbnVtYmVyO1xuXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgX2RyaXZlcjogV2ViRHJpdmVyQWRhcHRlciwgdXNlckFnZW50OiBzdHJpbmcpIHtcbiAgICBzdXBlcigpO1xuICAgIHRoaXMuX21ham9yQ2hyb21lVmVyc2lvbiA9IHRoaXMuX3BhcnNlQ2hyb21lVmVyc2lvbih1c2VyQWdlbnQpO1xuICB9XG5cbiAgcHJpdmF0ZSBfcGFyc2VDaHJvbWVWZXJzaW9uKHVzZXJBZ2VudDogc3RyaW5nKTogbnVtYmVyIHtcbiAgICBpZiAoaXNCbGFuayh1c2VyQWdlbnQpKSB7XG4gICAgICByZXR1cm4gLTE7XG4gICAgfVxuICAgIHZhciB2ID0gU3RyaW5nV3JhcHBlci5zcGxpdCh1c2VyQWdlbnQsIC9DaHJvbShlfGl1bSlcXC8vZylbMl07XG4gICAgaWYgKGlzQmxhbmsodikpIHtcbiAgICAgIHJldHVybiAtMTtcbiAgICB9XG4gICAgdiA9IHYuc3BsaXQoJy4nKVswXTtcbiAgICBpZiAoaXNCbGFuayh2KSkge1xuICAgICAgcmV0dXJuIC0xO1xuICAgIH1cbiAgICByZXR1cm4gTnVtYmVyV3JhcHBlci5wYXJzZUludCh2LCAxMCk7XG4gIH1cblxuICBnYygpIHsgcmV0dXJuIHRoaXMuX2RyaXZlci5leGVjdXRlU2NyaXB0KCd3aW5kb3cuZ2MoKScpOyB9XG5cbiAgdGltZUJlZ2luKG5hbWU6IHN0cmluZyk6IFByb21pc2U8YW55PiB7XG4gICAgcmV0dXJuIHRoaXMuX2RyaXZlci5leGVjdXRlU2NyaXB0KGBjb25zb2xlLnRpbWUoJyR7bmFtZX0nKTtgKTtcbiAgfVxuXG4gIHRpbWVFbmQobmFtZTogc3RyaW5nLCByZXN0YXJ0TmFtZTogc3RyaW5nID0gbnVsbCk6IFByb21pc2U8YW55PiB7XG4gICAgdmFyIHNjcmlwdCA9IGBjb25zb2xlLnRpbWVFbmQoJyR7bmFtZX0nKTtgO1xuICAgIGlmIChpc1ByZXNlbnQocmVzdGFydE5hbWUpKSB7XG4gICAgICBzY3JpcHQgKz0gYGNvbnNvbGUudGltZSgnJHtyZXN0YXJ0TmFtZX0nKTtgXG4gICAgfVxuICAgIHJldHVybiB0aGlzLl9kcml2ZXIuZXhlY3V0ZVNjcmlwdChzY3JpcHQpO1xuICB9XG5cbiAgLy8gU2VlIFtDaHJvbWUgVHJhY2UgRXZlbnRcbiAgLy8gRm9ybWF0XShodHRwczovL2RvY3MuZ29vZ2xlLmNvbS9kb2N1bWVudC9kLzFDdkFDbHZGZnlBNVItUGhZVW1uNU9PUXRZTUg0aDZJMG5Tc0tjaE5BeVNVL2VkaXQpXG4gIHJlYWRQZXJmTG9nKCk6IFByb21pc2U8YW55PiB7XG4gICAgLy8gVE9ETyh0Ym9zY2gpOiBDaHJvbWVkcml2ZXIgYnVnIGh0dHBzOi8vY29kZS5nb29nbGUuY29tL3AvY2hyb21lZHJpdmVyL2lzc3Vlcy9kZXRhaWw/aWQ9MTA5OFxuICAgIC8vIE5lZWQgdG8gZXhlY3V0ZSBhdCBsZWFzdCBvbmUgY29tbWFuZCBzbyB0aGF0IHRoZSBicm93c2VyIGxvZ3MgY2FuIGJlIHJlYWQgb3V0IVxuICAgIHJldHVybiB0aGlzLl9kcml2ZXIuZXhlY3V0ZVNjcmlwdCgnMSsxJylcbiAgICAgICAgLnRoZW4oKF8pID0+IHRoaXMuX2RyaXZlci5sb2dzKCdwZXJmb3JtYW5jZScpKVxuICAgICAgICAudGhlbigoZW50cmllcykgPT4ge1xuICAgICAgICAgIHZhciBldmVudHMgPSBbXTtcbiAgICAgICAgICBlbnRyaWVzLmZvckVhY2goZW50cnkgPT4ge1xuICAgICAgICAgICAgdmFyIG1lc3NhZ2UgPSBKc29uLnBhcnNlKGVudHJ5WydtZXNzYWdlJ10pWydtZXNzYWdlJ107XG4gICAgICAgICAgICBpZiAoU3RyaW5nV3JhcHBlci5lcXVhbHMobWVzc2FnZVsnbWV0aG9kJ10sICdUcmFjaW5nLmRhdGFDb2xsZWN0ZWQnKSkge1xuICAgICAgICAgICAgICBldmVudHMucHVzaChtZXNzYWdlWydwYXJhbXMnXSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoU3RyaW5nV3JhcHBlci5lcXVhbHMobWVzc2FnZVsnbWV0aG9kJ10sICdUcmFjaW5nLmJ1ZmZlclVzYWdlJykpIHtcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IEJhc2VFeGNlcHRpb24oJ1RoZSBEZXZUb29scyB0cmFjZSBidWZmZXIgZmlsbGVkIGR1cmluZyB0aGUgdGVzdCEnKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KTtcbiAgICAgICAgICByZXR1cm4gdGhpcy5fY29udmVydFBlcmZSZWNvcmRzVG9FdmVudHMoZXZlbnRzKTtcbiAgICAgICAgfSk7XG4gIH1cblxuICBwcml2YXRlIF9jb252ZXJ0UGVyZlJlY29yZHNUb0V2ZW50cyhjaHJvbWVFdmVudHM6IEFycmF5PHtba2V5OiBzdHJpbmddOiBhbnl9PixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbm9ybWFsaXplZEV2ZW50czogQXJyYXk8e1trZXk6IHN0cmluZ106IGFueX0+ID0gbnVsbCkge1xuICAgIGlmIChpc0JsYW5rKG5vcm1hbGl6ZWRFdmVudHMpKSB7XG4gICAgICBub3JtYWxpemVkRXZlbnRzID0gW107XG4gICAgfVxuICAgIHZhciBtYWpvckdDUGlkcyA9IHt9O1xuICAgIGNocm9tZUV2ZW50cy5mb3JFYWNoKChldmVudCkgPT4ge1xuICAgICAgdmFyIGNhdGVnb3JpZXMgPSB0aGlzLl9wYXJzZUNhdGVnb3JpZXMoZXZlbnRbJ2NhdCddKTtcbiAgICAgIHZhciBuYW1lID0gZXZlbnRbJ25hbWUnXTtcbiAgICAgIGlmICh0aGlzLl9pc0V2ZW50KGNhdGVnb3JpZXMsIG5hbWUsIFsnYmxpbmsuY29uc29sZSddKSkge1xuICAgICAgICBub3JtYWxpemVkRXZlbnRzLnB1c2gobm9ybWFsaXplRXZlbnQoZXZlbnQsIHsnbmFtZSc6IG5hbWV9KSk7XG4gICAgICB9IGVsc2UgaWYgKHRoaXMuX2lzRXZlbnQoY2F0ZWdvcmllcywgbmFtZSwgWydiZW5jaG1hcmsnXSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnQmVuY2htYXJrSW5zdHJ1bWVudGF0aW9uOjpJbXBsVGhyZWFkUmVuZGVyaW5nU3RhdHMnKSkge1xuICAgICAgICAvLyBUT0RPKGdvZGVyYmF1ZXIpOiBJbnN0ZWFkIG9mIEJlbmNobWFya0luc3RydW1lbnRhdGlvbjo6SW1wbFRocmVhZFJlbmRlcmluZ1N0YXRzIHRoZVxuICAgICAgICAvLyBmb2xsb3dpbmcgZXZlbnRzIHNob3VsZCBiZSB1c2VkIChpZiBhdmFpbGFibGUpIGZvciBtb3JlIGFjY3VyYXRlIG1lYXN1cm1lbnRzOlxuICAgICAgICAvLyAgIDFzdCBjaG9pY2U6IHZzeW5jX2JlZm9yZSAtIGdyb3VuZCB0cnV0aCBvbiBBbmRyb2lkXG4gICAgICAgIC8vICAgMm5kIGNob2ljZTogQmVuY2htYXJrSW5zdHJ1bWVudGF0aW9uOjpEaXNwbGF5UmVuZGVyaW5nU3RhdHMgLSBhdmFpbGFibGUgb24gc3lzdGVtcyB3aXRoXG4gICAgICAgIC8vICAgICAgICAgICAgICAgbmV3IHN1cmZhY2VzIGZyYW1ld29yayAobm90IGJyb2FkbHkgZW5hYmxlZCB5ZXQpXG4gICAgICAgIC8vICAgM3JkIGNob2ljZTogQmVuY2htYXJrSW5zdHJ1bWVudGF0aW9uOjpJbXBsVGhyZWFkUmVuZGVyaW5nU3RhdHMgLSBmYWxsYmFjayBldmVudCB0aGF0IGlzXG4gICAgICAgIC8vICAgICAgICAgICAgICAgYWx3YXlzIGF2YWlsYWJsZSBpZiBzb21ldGhpbmcgaXMgcmVuZGVyZWRcbiAgICAgICAgdmFyIGZyYW1lQ291bnQgPSBldmVudFsnYXJncyddWydkYXRhJ11bJ2ZyYW1lX2NvdW50J107XG4gICAgICAgIGlmIChmcmFtZUNvdW50ID4gMSkge1xuICAgICAgICAgIHRocm93IG5ldyBCYXNlRXhjZXB0aW9uKCdtdWx0aS1mcmFtZSByZW5kZXIgc3RhdHMgbm90IHN1cHBvcnRlZCcpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChmcmFtZUNvdW50ID09IDEpIHtcbiAgICAgICAgICBub3JtYWxpemVkRXZlbnRzLnB1c2gobm9ybWFsaXplRXZlbnQoZXZlbnQsIHsnbmFtZSc6ICdmcmFtZSd9KSk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAodGhpcy5faXNFdmVudChjYXRlZ29yaWVzLCBuYW1lLCBbJ2Rpc2FibGVkLWJ5LWRlZmF1bHQtZGV2dG9vbHMudGltZWxpbmUnXSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnUmFzdGVyaXplJykgfHxcbiAgICAgICAgICAgICAgICAgdGhpcy5faXNFdmVudChjYXRlZ29yaWVzLCBuYW1lLCBbJ2Rpc2FibGVkLWJ5LWRlZmF1bHQtZGV2dG9vbHMudGltZWxpbmUnXSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnQ29tcG9zaXRlTGF5ZXJzJykpIHtcbiAgICAgICAgbm9ybWFsaXplZEV2ZW50cy5wdXNoKG5vcm1hbGl6ZUV2ZW50KGV2ZW50LCB7J25hbWUnOiAncmVuZGVyJ30pKTtcbiAgICAgIH0gZWxzZSBpZiAodGhpcy5fbWFqb3JDaHJvbWVWZXJzaW9uIDwgNDUpIHtcbiAgICAgICAgdmFyIG5vcm1hbGl6ZWRFdmVudCA9IHRoaXMuX3Byb2Nlc3NBc1ByZUNocm9tZTQ1RXZlbnQoZXZlbnQsIGNhdGVnb3JpZXMsIG1ham9yR0NQaWRzKTtcbiAgICAgICAgaWYgKG5vcm1hbGl6ZWRFdmVudCAhPSBudWxsKSBub3JtYWxpemVkRXZlbnRzLnB1c2gobm9ybWFsaXplZEV2ZW50KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHZhciBub3JtYWxpemVkRXZlbnQgPSB0aGlzLl9wcm9jZXNzQXNQb3N0Q2hyb21lNDRFdmVudChldmVudCwgY2F0ZWdvcmllcyk7XG4gICAgICAgIGlmIChub3JtYWxpemVkRXZlbnQgIT0gbnVsbCkgbm9ybWFsaXplZEV2ZW50cy5wdXNoKG5vcm1hbGl6ZWRFdmVudCk7XG4gICAgICB9XG4gICAgfSk7XG4gICAgcmV0dXJuIG5vcm1hbGl6ZWRFdmVudHM7XG4gIH1cblxuICBwcml2YXRlIF9wcm9jZXNzQXNQcmVDaHJvbWU0NUV2ZW50KGV2ZW50LCBjYXRlZ29yaWVzLCBtYWpvckdDUGlkcykge1xuICAgIHZhciBuYW1lID0gZXZlbnRbJ25hbWUnXTtcbiAgICB2YXIgYXJncyA9IGV2ZW50WydhcmdzJ107XG4gICAgdmFyIHBpZCA9IGV2ZW50WydwaWQnXTtcbiAgICB2YXIgcGggPSBldmVudFsncGgnXTtcbiAgICBpZiAodGhpcy5faXNFdmVudChjYXRlZ29yaWVzLCBuYW1lLCBbJ2Rpc2FibGVkLWJ5LWRlZmF1bHQtZGV2dG9vbHMudGltZWxpbmUnXSxcbiAgICAgICAgICAgICAgICAgICAgICAnRnVuY3Rpb25DYWxsJykgJiZcbiAgICAgICAgKGlzQmxhbmsoYXJncykgfHwgaXNCbGFuayhhcmdzWydkYXRhJ10pIHx8XG4gICAgICAgICAhU3RyaW5nV3JhcHBlci5lcXVhbHMoYXJnc1snZGF0YSddWydzY3JpcHROYW1lJ10sICdJbmplY3RlZFNjcmlwdCcpKSkge1xuICAgICAgcmV0dXJuIG5vcm1hbGl6ZUV2ZW50KGV2ZW50LCB7J25hbWUnOiAnc2NyaXB0J30pO1xuICAgIH0gZWxzZSBpZiAodGhpcy5faXNFdmVudChjYXRlZ29yaWVzLCBuYW1lLCBbJ2Rpc2FibGVkLWJ5LWRlZmF1bHQtZGV2dG9vbHMudGltZWxpbmUnXSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1JlY2FsY3VsYXRlU3R5bGVzJykgfHxcbiAgICAgICAgICAgICAgIHRoaXMuX2lzRXZlbnQoY2F0ZWdvcmllcywgbmFtZSwgWydkaXNhYmxlZC1ieS1kZWZhdWx0LWRldnRvb2xzLnRpbWVsaW5lJ10sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICdMYXlvdXQnKSB8fFxuICAgICAgICAgICAgICAgdGhpcy5faXNFdmVudChjYXRlZ29yaWVzLCBuYW1lLCBbJ2Rpc2FibGVkLWJ5LWRlZmF1bHQtZGV2dG9vbHMudGltZWxpbmUnXSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1VwZGF0ZUxheWVyVHJlZScpIHx8XG4gICAgICAgICAgICAgICB0aGlzLl9pc0V2ZW50KGNhdGVnb3JpZXMsIG5hbWUsIFsnZGlzYWJsZWQtYnktZGVmYXVsdC1kZXZ0b29scy50aW1lbGluZSddLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnUGFpbnQnKSkge1xuICAgICAgcmV0dXJuIG5vcm1hbGl6ZUV2ZW50KGV2ZW50LCB7J25hbWUnOiAncmVuZGVyJ30pO1xuICAgIH0gZWxzZSBpZiAodGhpcy5faXNFdmVudChjYXRlZ29yaWVzLCBuYW1lLCBbJ2Rpc2FibGVkLWJ5LWRlZmF1bHQtZGV2dG9vbHMudGltZWxpbmUnXSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0dDRXZlbnQnKSkge1xuICAgICAgdmFyIG5vcm1BcmdzID0ge1xuICAgICAgICAndXNlZEhlYXBTaXplJzogaXNQcmVzZW50KGFyZ3NbJ3VzZWRIZWFwU2l6ZUFmdGVyJ10pID8gYXJnc1sndXNlZEhlYXBTaXplQWZ0ZXInXSA6XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcmdzWyd1c2VkSGVhcFNpemVCZWZvcmUnXVxuICAgICAgfTtcbiAgICAgIGlmIChTdHJpbmdXcmFwcGVyLmVxdWFscyhwaCwgJ0UnKSkge1xuICAgICAgICBub3JtQXJnc1snbWFqb3JHYyddID0gaXNQcmVzZW50KG1ham9yR0NQaWRzW3BpZF0pICYmIG1ham9yR0NQaWRzW3BpZF07XG4gICAgICB9XG4gICAgICBtYWpvckdDUGlkc1twaWRdID0gZmFsc2U7XG4gICAgICByZXR1cm4gbm9ybWFsaXplRXZlbnQoZXZlbnQsIHsnbmFtZSc6ICdnYycsICdhcmdzJzogbm9ybUFyZ3N9KTtcbiAgICB9IGVsc2UgaWYgKHRoaXMuX2lzRXZlbnQoY2F0ZWdvcmllcywgbmFtZSwgWyd2OCddLCAnbWFqb3JHQycpICYmXG4gICAgICAgICAgICAgICBTdHJpbmdXcmFwcGVyLmVxdWFscyhwaCwgJ0InKSkge1xuICAgICAgbWFqb3JHQ1BpZHNbcGlkXSA9IHRydWU7XG4gICAgfVxuICAgIHJldHVybiBudWxsOyAgLy8gbm90aGluZyB1c2VmdWwgaW4gdGhpcyBldmVudFxuICB9XG5cbiAgcHJpdmF0ZSBfcHJvY2Vzc0FzUG9zdENocm9tZTQ0RXZlbnQoZXZlbnQsIGNhdGVnb3JpZXMpIHtcbiAgICB2YXIgbmFtZSA9IGV2ZW50WyduYW1lJ107XG4gICAgdmFyIGFyZ3MgPSBldmVudFsnYXJncyddO1xuICAgIGlmICh0aGlzLl9pc0V2ZW50KGNhdGVnb3JpZXMsIG5hbWUsIFsnZGV2dG9vbHMudGltZWxpbmUnLCAndjgnXSwgJ01ham9yR0MnKSkge1xuICAgICAgdmFyIG5vcm1BcmdzID0ge1xuICAgICAgICAnbWFqb3JHYyc6IHRydWUsXG4gICAgICAgICd1c2VkSGVhcFNpemUnOiBpc1ByZXNlbnQoYXJnc1sndXNlZEhlYXBTaXplQWZ0ZXInXSkgPyBhcmdzWyd1c2VkSGVhcFNpemVBZnRlciddIDpcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFyZ3NbJ3VzZWRIZWFwU2l6ZUJlZm9yZSddXG4gICAgICB9O1xuICAgICAgcmV0dXJuIG5vcm1hbGl6ZUV2ZW50KGV2ZW50LCB7J25hbWUnOiAnZ2MnLCAnYXJncyc6IG5vcm1BcmdzfSk7XG4gICAgfSBlbHNlIGlmICh0aGlzLl9pc0V2ZW50KGNhdGVnb3JpZXMsIG5hbWUsIFsnZGV2dG9vbHMudGltZWxpbmUnLCAndjgnXSwgJ01pbm9yR0MnKSkge1xuICAgICAgdmFyIG5vcm1BcmdzID0ge1xuICAgICAgICAnbWFqb3JHYyc6IGZhbHNlLFxuICAgICAgICAndXNlZEhlYXBTaXplJzogaXNQcmVzZW50KGFyZ3NbJ3VzZWRIZWFwU2l6ZUFmdGVyJ10pID8gYXJnc1sndXNlZEhlYXBTaXplQWZ0ZXInXSA6XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhcmdzWyd1c2VkSGVhcFNpemVCZWZvcmUnXVxuICAgICAgfTtcbiAgICAgIHJldHVybiBub3JtYWxpemVFdmVudChldmVudCwgeyduYW1lJzogJ2djJywgJ2FyZ3MnOiBub3JtQXJnc30pO1xuICAgIH0gZWxzZSBpZiAodGhpcy5faXNFdmVudChjYXRlZ29yaWVzLCBuYW1lLCBbJ2RldnRvb2xzLnRpbWVsaW5lJywgJ3Y4J10sICdGdW5jdGlvbkNhbGwnKSAmJlxuICAgICAgICAgICAgICAgKGlzQmxhbmsoYXJncykgfHwgaXNCbGFuayhhcmdzWydkYXRhJ10pIHx8XG4gICAgICAgICAgICAgICAgKCFTdHJpbmdXcmFwcGVyLmVxdWFscyhhcmdzWydkYXRhJ11bJ3NjcmlwdE5hbWUnXSwgJ0luamVjdGVkU2NyaXB0JykgJiZcbiAgICAgICAgICAgICAgICAgIVN0cmluZ1dyYXBwZXIuZXF1YWxzKGFyZ3NbJ2RhdGEnXVsnc2NyaXB0TmFtZSddLCAnJykpKSkge1xuICAgICAgcmV0dXJuIG5vcm1hbGl6ZUV2ZW50KGV2ZW50LCB7J25hbWUnOiAnc2NyaXB0J30pO1xuICAgIH0gZWxzZSBpZiAodGhpcy5faXNFdmVudChjYXRlZ29yaWVzLCBuYW1lLCBbJ2RldnRvb2xzLnRpbWVsaW5lJywgJ2JsaW5rJ10sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICdVcGRhdGVMYXlvdXRUcmVlJykpIHtcbiAgICAgIHJldHVybiBub3JtYWxpemVFdmVudChldmVudCwgeyduYW1lJzogJ3JlbmRlcid9KTtcbiAgICB9IGVsc2UgaWYgKHRoaXMuX2lzRXZlbnQoY2F0ZWdvcmllcywgbmFtZSwgWydkZXZ0b29scy50aW1lbGluZSddLCAnVXBkYXRlTGF5ZXJUcmVlJykgfHxcbiAgICAgICAgICAgICAgIHRoaXMuX2lzRXZlbnQoY2F0ZWdvcmllcywgbmFtZSwgWydkZXZ0b29scy50aW1lbGluZSddLCAnTGF5b3V0JykgfHxcbiAgICAgICAgICAgICAgIHRoaXMuX2lzRXZlbnQoY2F0ZWdvcmllcywgbmFtZSwgWydkZXZ0b29scy50aW1lbGluZSddLCAnUGFpbnQnKSkge1xuICAgICAgcmV0dXJuIG5vcm1hbGl6ZUV2ZW50KGV2ZW50LCB7J25hbWUnOiAncmVuZGVyJ30pO1xuICAgIH0gZWxzZSBpZiAodGhpcy5faXNFdmVudChjYXRlZ29yaWVzLCBuYW1lLCBbJ2RldnRvb2xzLnRpbWVsaW5lJ10sICdSZXNvdXJjZVJlY2VpdmVkRGF0YScpKSB7XG4gICAgICBsZXQgbm9ybUFyZ3MgPSB7J2VuY29kZWREYXRhTGVuZ3RoJzogYXJnc1snZGF0YSddWydlbmNvZGVkRGF0YUxlbmd0aCddfTtcbiAgICAgIHJldHVybiBub3JtYWxpemVFdmVudChldmVudCwgeyduYW1lJzogJ3JlY2VpdmVkRGF0YScsICdhcmdzJzogbm9ybUFyZ3N9KTtcbiAgICB9IGVsc2UgaWYgKHRoaXMuX2lzRXZlbnQoY2F0ZWdvcmllcywgbmFtZSwgWydkZXZ0b29scy50aW1lbGluZSddLCAnUmVzb3VyY2VTZW5kUmVxdWVzdCcpKSB7XG4gICAgICBsZXQgZGF0YSA9IGFyZ3NbJ2RhdGEnXTtcbiAgICAgIGxldCBub3JtQXJncyA9IHsndXJsJzogZGF0YVsndXJsJ10sICdtZXRob2QnOiBkYXRhWydyZXF1ZXN0TWV0aG9kJ119O1xuICAgICAgcmV0dXJuIG5vcm1hbGl6ZUV2ZW50KGV2ZW50LCB7J25hbWUnOiAnc2VuZFJlcXVlc3QnLCAnYXJncyc6IG5vcm1BcmdzfSk7XG4gICAgfSBlbHNlIGlmICh0aGlzLl9pc0V2ZW50KGNhdGVnb3JpZXMsIG5hbWUsIFsnYmxpbmsudXNlcl90aW1pbmcnXSwgJ25hdmlnYXRpb25TdGFydCcpKSB7XG4gICAgICByZXR1cm4gbm9ybWFsaXplRXZlbnQoZXZlbnQsIHsnbmFtZSc6IG5hbWV9KTtcbiAgICB9XG4gICAgcmV0dXJuIG51bGw7ICAvLyBub3RoaW5nIHVzZWZ1bCBpbiB0aGlzIGV2ZW50XG4gIH1cblxuICBwcml2YXRlIF9wYXJzZUNhdGVnb3JpZXMoY2F0ZWdvcmllczogc3RyaW5nKTogc3RyaW5nW10geyByZXR1cm4gY2F0ZWdvcmllcy5zcGxpdCgnLCcpOyB9XG5cbiAgcHJpdmF0ZSBfaXNFdmVudChldmVudENhdGVnb3JpZXM6IHN0cmluZ1tdLCBldmVudE5hbWU6IHN0cmluZywgZXhwZWN0ZWRDYXRlZ29yaWVzOiBzdHJpbmdbXSxcbiAgICAgICAgICAgICAgICAgICBleHBlY3RlZE5hbWU6IHN0cmluZyA9IG51bGwpOiBib29sZWFuIHtcbiAgICB2YXIgaGFzQ2F0ZWdvcmllcyA9IGV4cGVjdGVkQ2F0ZWdvcmllcy5yZWR1Y2UoXG4gICAgICAgICh2YWx1ZSwgY2F0KSA9PiB7IHJldHVybiB2YWx1ZSAmJiBMaXN0V3JhcHBlci5jb250YWlucyhldmVudENhdGVnb3JpZXMsIGNhdCk7IH0sIHRydWUpO1xuICAgIHJldHVybiBpc0JsYW5rKGV4cGVjdGVkTmFtZSkgPyBoYXNDYXRlZ29yaWVzIDpcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGFzQ2F0ZWdvcmllcyAmJiBTdHJpbmdXcmFwcGVyLmVxdWFscyhldmVudE5hbWUsIGV4cGVjdGVkTmFtZSk7XG4gIH1cblxuICBwZXJmTG9nRmVhdHVyZXMoKTogUGVyZkxvZ0ZlYXR1cmVzIHtcbiAgICByZXR1cm4gbmV3IFBlcmZMb2dGZWF0dXJlcyh7cmVuZGVyOiB0cnVlLCBnYzogdHJ1ZSwgZnJhbWVDYXB0dXJlOiB0cnVlLCB1c2VyVGltaW5nOiB0cnVlfSk7XG4gIH1cblxuICBzdXBwb3J0cyhjYXBhYmlsaXRpZXM6IHtba2V5OiBzdHJpbmddOiBhbnl9KTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuX21ham9yQ2hyb21lVmVyc2lvbiAhPSAtMSAmJlxuICAgICAgICAgICBTdHJpbmdXcmFwcGVyLmVxdWFscyhjYXBhYmlsaXRpZXNbJ2Jyb3dzZXJOYW1lJ10udG9Mb3dlckNhc2UoKSwgJ2Nocm9tZScpO1xuICB9XG59XG5cbmZ1bmN0aW9uIG5vcm1hbGl6ZUV2ZW50KGNocm9tZUV2ZW50OiB7W2tleTogc3RyaW5nXTogYW55fSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGRhdGE6IHtba2V5OiBzdHJpbmddOiBhbnl9KToge1trZXk6IHN0cmluZ106IGFueX0ge1xuICB2YXIgcGggPSBjaHJvbWVFdmVudFsncGgnXTtcbiAgaWYgKFN0cmluZ1dyYXBwZXIuZXF1YWxzKHBoLCAnUycpKSB7XG4gICAgcGggPSAnYic7XG4gIH0gZWxzZSBpZiAoU3RyaW5nV3JhcHBlci5lcXVhbHMocGgsICdGJykpIHtcbiAgICBwaCA9ICdlJztcbiAgfVxuICB2YXIgcmVzdWx0ID1cbiAgICAgIHsncGlkJzogY2hyb21lRXZlbnRbJ3BpZCddLCAncGgnOiBwaCwgJ2NhdCc6ICd0aW1lbGluZScsICd0cyc6IGNocm9tZUV2ZW50Wyd0cyddIC8gMTAwMH07XG4gIGlmIChjaHJvbWVFdmVudFsncGgnXSA9PT0gJ1gnKSB7XG4gICAgdmFyIGR1ciA9IGNocm9tZUV2ZW50WydkdXInXTtcbiAgICBpZiAoaXNCbGFuayhkdXIpKSB7XG4gICAgICBkdXIgPSBjaHJvbWVFdmVudFsndGR1ciddO1xuICAgIH1cbiAgICByZXN1bHRbJ2R1ciddID0gaXNCbGFuayhkdXIpID8gMC4wIDogZHVyIC8gMTAwMDtcbiAgfVxuICBTdHJpbmdNYXBXcmFwcGVyLmZvckVhY2goZGF0YSwgKHZhbHVlLCBwcm9wKSA9PiB7IHJlc3VsdFtwcm9wXSA9IHZhbHVlOyB9KTtcbiAgcmV0dXJuIHJlc3VsdDtcbn1cblxudmFyIF9QUk9WSURFUlMgPSBbXG4gIGJpbmQoQ2hyb21lRHJpdmVyRXh0ZW5zaW9uKVxuICAgICAgLnRvRmFjdG9yeSgoZHJpdmVyLCB1c2VyQWdlbnQpID0+IG5ldyBDaHJvbWVEcml2ZXJFeHRlbnNpb24oZHJpdmVyLCB1c2VyQWdlbnQpLFxuICAgICAgICAgICAgICAgICBbV2ViRHJpdmVyQWRhcHRlciwgT3B0aW9ucy5VU0VSX0FHRU5UXSlcbl07XG4iXX0=