├── .editorconfig ├── .eslintrc ├── .gitignore ├── .npmignore ├── .travis.yml ├── example.js ├── index.js ├── lib ├── api-stubs.js ├── devtools-monkeypatches.js ├── timeline-model-treeview.js └── timeline-model.js ├── license ├── package-lock.json ├── package.json ├── readme.md └── test ├── assets ├── devtools-homepage-w-screenshots-trace.json ├── grayscale.jpg ├── mdn-fling.json ├── progressive-app.json ├── trace-from-webpagetest.json └── trace-in-object-format.json ├── speedline.js └── test.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "google", 3 | "env": { 4 | "node": true 5 | }, 6 | "rules": { 7 | // "off" or 0 - turn the rule off 8 | // "warn" or 1 - turn the rule on as a warning (doesn’t affect exit code) 9 | // "error" or 2 - turn the rule on as an error (exit code is 1 when triggered) 10 | "no-multiple-empty-lines": 0, 11 | "padded-blocks": 0, 12 | "curly": [0, "multi-line"], 13 | "max-len": [1, 120, { 14 | "ignoreComments": true, 15 | "ignoreUrls": true, 16 | "tabWidth": 2 17 | }], 18 | "no-implicit-coercion": [2, { 19 | "boolean": false, 20 | "number": true, 21 | "string": true 22 | }], 23 | "no-unused-expressions": [2, { 24 | "allowShortCircuit": true, 25 | "allowTernary": false 26 | }], 27 | "no-unused-vars": [1, { 28 | "vars": "all", 29 | "args": "after-used", 30 | "argsIgnorePattern": "(^reject$|^_$)", 31 | "varsIgnorePattern": "(^_$|andboxedModel$)" 32 | }], 33 | "quotes": [2, "single"], 34 | "require-jsdoc": 0, 35 | "valid-jsdoc": 0 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | test 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "8.0" 4 | - "lts/*" 5 | - "node" 6 | cache: 7 | directories: 8 | - node_modules 9 | -------------------------------------------------------------------------------- /example.js: -------------------------------------------------------------------------------- 1 | const filenames = [ 2 | 'test/assets/mdn-fling.json', 3 | 'test/assets/devtools-homepage-w-screenshots-trace.json' 4 | ]; 5 | 6 | var fs = require('fs'); 7 | var TraceToTimelineModel = require('.'); 8 | 9 | if (!console.group) { 10 | console.group = n => console.log(n, ':'); 11 | console.groupEnd = _ => console.log(''); 12 | } 13 | 14 | function dumpScreenshot(filmStripModel) { 15 | var frames = filmStripModel.frames(); 16 | var framesLen = frames.length; 17 | if (framesLen >= 1) { 18 | frames[framesLen - 1].imageDataPromise() 19 | .then(data => Promise.resolve('data:image/jpg;base64,' + data)) 20 | .then(img => { 21 | console.log('Filmstrip model last screenshot:\n', img.substr(0, 50) + '...'); 22 | }); 23 | } 24 | } 25 | 26 | function dumpTree(tree, timeValue) { 27 | var result = new Map(); 28 | tree.children.forEach((value, key) => result.set(key, value[timeValue].toFixed(1))); 29 | return result; 30 | } 31 | 32 | function report(filename) { 33 | var events = fs.readFileSync(filename, 'utf8'); 34 | 35 | var model = new TraceToTimelineModel(events); 36 | 37 | console.group(filename); 38 | 39 | console.log('Timeline model events:\n', model.timelineModel().mainThreadEvents().length); 40 | console.log('IR model interactions\n', model.interactionModel().interactionRecords().length); 41 | console.log('Frame model frames:\n', model.frameModel().frames().length); 42 | console.log('Filmstrip model screenshots:\n', model.filmStripModel().frames().length); 43 | dumpScreenshot(model.filmStripModel()); 44 | 45 | var topDown = model.topDown(); 46 | console.log('Top down tree total time:\n', topDown.totalTime); 47 | console.log('Top down tree, not grouped:\n', dumpTree(topDown, 'totalTime')); 48 | 49 | console.log('Bottom up tree leaves:\n', [...model.bottomUp().children.entries()].length); 50 | var bottomUpURL = model.bottomUpGroupBy('URL'); 51 | var secondTopCost = [...bottomUpURL.children.values()][1]; 52 | console.log('bottom up tree, grouped by URL', dumpTree(bottomUpURL, 'selfTime')); 53 | console.log('Bottom up tree, grouped, 2nd top URL:\n', secondTopCost.totalTime.toFixed(2), secondTopCost.id); 54 | 55 | var bottomUpSubdomain = model.bottomUpGroupBy('Subdomain'); 56 | console.log('Bottom up tree, grouped by top subdomain:\n', dumpTree(bottomUpSubdomain, 'selfTime')); 57 | 58 | var bottomUpByName = model.bottomUpGroupBy('EventName'); 59 | console.log('Bottom up tree grouped by EventName:\n', dumpTree(bottomUpByName, 'selfTime')); 60 | 61 | // console.log('Tracing model:\n', model.tracingModel()) 62 | // console.log('Timeline model:\n', model.timelineModel()) 63 | // console.log('IR model:\n', model.interactionModel()) 64 | // console.log('Frame model:\n', model.frameModel()) 65 | // console.log('Filmstrip model:\n', model.filmStripModel()) 66 | 67 | // console.log('Top down tree:\n', model.topDown()) 68 | // console.log('Bottom up tree:\n', model.bottomUp()) 69 | // console.log('Top down tree, grouped by URL:\n', model.topDownGroupedUnsorted) 70 | // console.log('Bottom up tree grouped by URL:\n', model.bottomUpGroupBy('None')) 71 | console.groupEnd(filename); 72 | } 73 | 74 | filenames.forEach(report); 75 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var fs = require('fs'); 4 | var vm = require('vm'); 5 | 6 | /* eslint-disable no-native-reassign */ 7 | if (typeof __dirname === 'undefined') { 8 | __dirname = ''; 9 | } 10 | /* eslint-enable no-native-reassign */ 11 | 12 | class ModelAPI { 13 | 14 | constructor(events) { 15 | 16 | // Everything happens in a sandboxed vm context, to keep globals and natives separate. 17 | // First, sandboxed contexts don't have any globals from node, so we whitelist a few we'll provide for it. 18 | var glob = {require: require, global: global, console: console, __dirname: __dirname}; 19 | // We read in our script to run, and create a vm.Script object 20 | /* eslint-disable no-path-concat */ 21 | var script = new vm.Script(fs.readFileSync(__dirname + '/lib/timeline-model.js', 'utf8')); 22 | /* eslint-enable no-path-concat */ 23 | // We create a new V8 context with our globals 24 | var ctx = vm.createContext(glob); 25 | // We evaluate the `vm.Script` in the new context 26 | script.runInContext(ctx); 27 | // We pull the local `instance` variable out, to use as our proxy object 28 | this.sandbox = ctx.sandboxedModel; 29 | this.sandbox.init(events); 30 | 31 | return this; 32 | } 33 | 34 | timelineModel() { 35 | return this.sandbox.timelineModel(); 36 | } 37 | 38 | tracingModel() { 39 | return this.sandbox.tracingModel(); 40 | } 41 | 42 | topDown(startTime = 0, endTime = Infinity) { 43 | return this.sandbox.topDown(startTime, endTime); 44 | } 45 | 46 | topDownGroupBy(grouping, startTime = 0, endTime = Infinity) { 47 | return this.sandbox.topDownGroupBy(grouping, startTime, endTime); 48 | } 49 | 50 | bottomUp(startTime = 0, endTime = Infinity) { 51 | return this.sandbox.bottomUp(startTime, endTime); 52 | } 53 | 54 | /** 55 | * @ param {!String} grouping Allowed values: None Category Subdomain Domain URL Name 56 | * @ return {!WebInspector.TimelineProfileTree.Node} A grouped and sorted tree 57 | */ 58 | bottomUpGroupBy(grouping, startTime = 0, endTime = Infinity) { 59 | return this.sandbox.bottomUpGroupBy(grouping, startTime, endTime); 60 | } 61 | 62 | frameModel() { 63 | return this.sandbox.frameModel(); 64 | } 65 | 66 | filmStripModel() { 67 | return this.sandbox.filmStripModel(); 68 | } 69 | 70 | 71 | interactionModel() { 72 | return this.sandbox.interactionModel(); 73 | } 74 | } 75 | 76 | module.exports = ModelAPI; 77 | -------------------------------------------------------------------------------- /lib/api-stubs.js: -------------------------------------------------------------------------------- 1 | /* global Protocol UI SDK DataGrid */ 2 | 3 | const noop = function() { }; 4 | 5 | // other neccessary stubs 6 | Protocol.TargetBase = noop; 7 | Protocol.Agents = {}; 8 | 9 | UI.VBox = noop; 10 | UI.TreeElement = noop; 11 | 12 | DataGrid.ViewportDataGrid = noop; 13 | DataGrid.ViewportDataGridNode = noop; 14 | 15 | SDK.targetManager = {}; 16 | SDK.targetManager.mainTarget = noop; 17 | -------------------------------------------------------------------------------- /lib/devtools-monkeypatches.js: -------------------------------------------------------------------------------- 1 | /* global Runtime Common Bindings */ 2 | 3 | Runtime.experiments = {}; 4 | Runtime.experiments.isEnabled = exp => exp === 'timelineLatencyInfo'; 5 | 6 | Common.moduleSetting = function(module) { 7 | return {get: _ => module === 'showNativeFunctionsInJSProfile'}; 8 | }; 9 | 10 | // DevTools makes a few assumptions about using backing storage to hold traces. 11 | Bindings.DeferredTempFile = function() {}; 12 | Bindings.DeferredTempFile.prototype = { 13 | write: _ => { }, 14 | remove: _ => { }, 15 | finishWriting: _ => { } 16 | }; 17 | -------------------------------------------------------------------------------- /lib/timeline-model-treeview.js: -------------------------------------------------------------------------------- 1 | 2 | // this duplicates some work inside of TimelineTreeView, SortedDataGrid and beyond. 3 | // It's pretty difficult to extract, so we forked. 4 | 5 | /* global Timeline DataGrid self */ 6 | 7 | function TimelineModelTreeView(model) { 8 | this._rootNode = model; 9 | } 10 | 11 | // from Timeline.TimelineTreeView._sortingChanged 12 | // but tweaked so this._dataGrid.sortColumnId() is set as to sortItem 13 | // and this._dataGrid.isSortOrderAscending() is set as (sortOrder !== 'asc') 14 | TimelineModelTreeView.prototype.sortingChanged = function(sortItem, sortOrder) { 15 | if (!sortItem) 16 | return; 17 | var sortFunction; 18 | switch (sortItem) { 19 | case 'startTime': 20 | sortFunction = compareStartTime; 21 | break; 22 | case 'self': 23 | sortFunction = compareNumericField.bind(null, 'selfTime'); 24 | break; 25 | case 'total': 26 | sortFunction = compareNumericField.bind(null, 'totalTime'); 27 | break; 28 | case 'activity': 29 | sortFunction = compareName; 30 | break; 31 | default: 32 | console.assert(false, 'Unknown sort field: ' + sortItem); 33 | return; 34 | } 35 | return this.sortNodes(sortFunction, sortOrder !== 'asc'); 36 | 37 | // these functions adjusted to handle Map entries() rather than objects 38 | function compareNumericField(field, a, b) { 39 | var nodeA = (a[1]); 40 | var nodeB = (b[1]); 41 | return nodeA[field] - nodeB[field]; 42 | } 43 | 44 | function compareStartTime(a, b) { 45 | var nodeA = (a[1]); 46 | var nodeB = (b[1]); 47 | return nodeA.event.startTime - nodeB.event.startTime; 48 | } 49 | 50 | function compareName(a, b) { 51 | var nodeA = (a[1]); 52 | var nodeB = (b[1]); 53 | var nameA = Timeline.TimelineTreeView.eventNameForSorting(nodeA.event); 54 | var nameB = Timeline.TimelineTreeView.eventNameForSorting(nodeB.event); 55 | return nameA.localeCompare(nameB); 56 | } 57 | 58 | }; 59 | 60 | // from SortableDataGrid.sortNodes() 61 | TimelineModelTreeView.prototype.sortNodes = function(comparator, reverseMode) { 62 | this._sortingFunction = DataGrid.SortableDataGrid.Comparator.bind(null, comparator, reverseMode); 63 | sortChildren(this._rootNode, this._sortingFunction, reverseMode); 64 | }; 65 | 66 | /** 67 | * sortChildren has major changes, as it now works on Maps rather than Arrays 68 | * from SortableDataGrid._sortChildren() 69 | * @param {WebInspector.TimelineProfileTree.Node} parent 70 | * @param {any} sortingFunction 71 | */ 72 | function sortChildren(parent, sortingFunction) { 73 | if (!parent.children) return; 74 | parent.children = new Map([...parent.children.entries()].sort(sortingFunction)); 75 | for (var i = 0; i < parent.children.length; ++i) 76 | recalculateSiblings(parent.children[i], i); 77 | for (var child of parent.children.values()) 78 | sortChildren(child, sortingFunction); 79 | } 80 | 81 | /** 82 | * from DataGrid.recalculateSiblings() 83 | * @param {WebInspector.TimelineProfileTree.Node} node 84 | * @param {any} myIndex 85 | */ 86 | function recalculateSiblings(node, myIndex) { 87 | if (!node.parent) 88 | return; 89 | 90 | var previousChild = node.parent.children[myIndex - 1] || null; 91 | if (previousChild) 92 | previousChild.nextSibling = node; 93 | node.previousSibling = previousChild; 94 | 95 | var nextChild = node.parent.children[myIndex + 1] || null; 96 | if (nextChild) 97 | nextChild.previousSibling = node; 98 | node.nextSibling = nextChild; 99 | } 100 | 101 | self.TimelineModelTreeView = TimelineModelTreeView; 102 | -------------------------------------------------------------------------------- /lib/timeline-model.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* global TimelineModel SDK Bindings Timeline TimelineModelTreeView */ 4 | 5 | const fs = require('fs'); 6 | const resolve = require('resolve'); 7 | 8 | // In order to maintain consistent global scope across the files, 9 | // and share natives like Array, etc, We will eval things within our sandbox 10 | function requireval(path) { 11 | const res = resolve.sync(path, {basedir: __dirname}); 12 | const filesrc = fs.readFileSync(res, 'utf8'); 13 | // eslint-disable-next-line no-eval 14 | eval(filesrc + '\n\n//# sourceURL=' + path); 15 | } 16 | 17 | // establish our sandboxed globals 18 | this.window = this.self = this.global = this; 19 | this.console = console; 20 | 21 | // establish our sandboxed globals 22 | this.Runtime = class {}; 23 | this.Protocol = class {}; 24 | this.TreeElement = class {}; 25 | 26 | // from generated externs. 27 | // As of node 7.3, instantiating these globals must be here rather than in api-stubs.js 28 | this.Accessibility = {}; 29 | this.Animation = {}; 30 | this.Audits = {}; 31 | this.Audits2 = {}; 32 | this.Audits2Worker = {}; 33 | this.Bindings = {}; 34 | this.CmModes = {}; 35 | this.Common = {}; 36 | this.Components = {}; 37 | this.Console = {}; 38 | this.DataGrid = {}; 39 | this.Devices = {}; 40 | this.Diff = {}; 41 | this.Elements = {}; 42 | this.Emulation = {}; 43 | this.Extensions = {}; 44 | this.FormatterWorker = {}; 45 | this.Gonzales = {}; 46 | this.HeapSnapshotWorker = {}; 47 | this.Host = {}; 48 | this.LayerViewer = {}; 49 | this.Layers = {}; 50 | this.Main = {}; 51 | this.Network = {}; 52 | this.Persistence = {}; 53 | this.Platform = {}; 54 | this.Profiler = {}; 55 | this.Resources = {}; 56 | this.Sass = {}; 57 | this.Screencast = {}; 58 | this.SDK = {}; 59 | this.Security = {}; 60 | this.Services = {}; 61 | this.Settings = {}; 62 | this.Snippets = {}; 63 | this.SourceFrame = {}; 64 | this.Sources = {}; 65 | this.Terminal = {}; 66 | this.TextEditor = {}; 67 | this.Timeline = {}; 68 | this.TimelineModel = {}; 69 | this.ToolboxBootstrap = {}; 70 | this.UI = {}; 71 | this.UtilitySharedWorker = {}; 72 | this.WorkerService = {}; 73 | this.Workspace = {}; 74 | 75 | requireval('./lib/api-stubs.js'); 76 | 77 | // chrome devtools frontend 78 | requireval('chrome-devtools-frontend/front_end/common/Object.js'); 79 | requireval('chrome-devtools-frontend/front_end/common/Console.js'); 80 | requireval('chrome-devtools-frontend/front_end/platform/utilities.js'); 81 | requireval('chrome-devtools-frontend/front_end/common/ParsedURL.js'); 82 | requireval('chrome-devtools-frontend/front_end/common/UIString.js'); 83 | requireval('chrome-devtools-frontend/front_end/sdk/Target.js'); 84 | requireval('chrome-devtools-frontend/front_end/sdk/LayerTreeBase.js'); 85 | requireval('chrome-devtools-frontend/front_end/common/SegmentedRange.js'); 86 | requireval('chrome-devtools-frontend/front_end/bindings/TempFile.js'); 87 | requireval('chrome-devtools-frontend/front_end/sdk/TracingModel.js'); 88 | requireval('chrome-devtools-frontend/front_end/sdk/ProfileTreeModel.js'); 89 | requireval('chrome-devtools-frontend/front_end/timeline/TimelineUIUtils.js'); 90 | requireval('chrome-devtools-frontend/front_end/timeline_model/TimelineJSProfile.js'); 91 | requireval('chrome-devtools-frontend/front_end/sdk/CPUProfileDataModel.js'); 92 | requireval('chrome-devtools-frontend/front_end/layers/LayerTreeModel.js'); 93 | requireval('chrome-devtools-frontend/front_end/timeline_model/TimelineModel.js'); 94 | requireval('chrome-devtools-frontend/front_end/data_grid/SortableDataGrid.js'); 95 | 96 | requireval('chrome-devtools-frontend/front_end/timeline/TimelineTreeView.js'); 97 | requireval('chrome-devtools-frontend/front_end/timeline_model/TimelineProfileTree.js'); 98 | requireval('chrome-devtools-frontend/front_end/sdk/FilmStripModel.js'); 99 | requireval('chrome-devtools-frontend/front_end/timeline_model/TimelineIRModel.js'); 100 | requireval('chrome-devtools-frontend/front_end/timeline_model/TimelineFrameModel.js'); 101 | 102 | // minor configurations 103 | requireval('./lib/devtools-monkeypatches.js'); 104 | 105 | // polyfill the bottom-up and topdown tree sorting 106 | requireval('./lib/timeline-model-treeview.js'); 107 | 108 | class SandboxedModel { 109 | 110 | init(events) { 111 | // build empty models. (devtools) tracing model & timeline model 112 | // from Timeline.TimelinePanel() constructor 113 | const tracingModelBackingStorage = new Bindings.TempFileBackingStorage('tracing'); 114 | this._tracingModel = new SDK.TracingModel(tracingModelBackingStorage); 115 | this._timelineModel = new TimelineModel.TimelineModel(Timeline.TimelineUIUtils.visibleEventsFilter()); 116 | 117 | if (typeof events === 'string') events = JSON.parse(events); 118 | // WebPagetest trace files put events in object under key `traceEvents` 119 | if (events.hasOwnProperty('traceEvents')) events = events.traceEvents; 120 | // WebPageTest trace files often have an empty object at index 0 121 | if (Object.keys(events[0]).length === 0) events.shift(); 122 | 123 | 124 | // reset models 125 | // from Timeline.TimelinePanel._clear() 126 | this._timelineModel.reset(); 127 | 128 | // populates with events, and call TracingModel.tracingComplete() 129 | this._tracingModel.setEventsForTest(events); 130 | 131 | // generate timeline model 132 | // from Timeline.TimelinePanel.loadingComplete() 133 | const loadedFromFile = true; 134 | this._timelineModel.setEvents(this._tracingModel, loadedFromFile); 135 | 136 | return this; 137 | } 138 | 139 | _createGroupingFunction(groupBy) { 140 | return Timeline.AggregatedTimelineTreeView.prototype._groupingFunction(groupBy); 141 | } 142 | 143 | timelineModel() { 144 | return this._timelineModel; 145 | } 146 | 147 | tracingModel() { 148 | return this._tracingModel; 149 | } 150 | 151 | topDown(startTime = 0, endTime = Infinity) { 152 | return this.topDownGroupBy(Timeline.AggregatedTimelineTreeView.GroupBy.None, startTime, endTime); 153 | } 154 | 155 | topDownGroupBy(grouping, startTime = 0, endTime = Infinity) { 156 | const filters = []; 157 | filters.push(Timeline.TimelineUIUtils.visibleEventsFilter()); 158 | filters.push(new TimelineModel.ExcludeTopLevelFilter()); 159 | const nonessentialEvents = [ 160 | TimelineModel.TimelineModel.RecordType.EventDispatch, 161 | TimelineModel.TimelineModel.RecordType.FunctionCall, 162 | TimelineModel.TimelineModel.RecordType.TimerFire 163 | ]; 164 | filters.push(new TimelineModel.ExclusiveNameFilter(nonessentialEvents)); 165 | 166 | const groupingAggregator = this._createGroupingFunction(Timeline.AggregatedTimelineTreeView.GroupBy[grouping]); 167 | const topDownGrouped = TimelineModel.TimelineProfileTree.buildTopDown(this._timelineModel.mainThreadEvents(), 168 | filters, startTime, endTime, groupingAggregator); 169 | 170 | // from Timeline.CallTreeTimelineTreeView._buildTree() 171 | if (grouping !== Timeline.AggregatedTimelineTreeView.GroupBy.None) 172 | new TimelineModel.TimelineAggregator().performGrouping(topDownGrouped); // group in-place 173 | 174 | new TimelineModelTreeView(topDownGrouped).sortingChanged('total', 'desc'); 175 | return topDownGrouped; 176 | } 177 | 178 | bottomUp(startTime = 0, endTime = Infinity) { 179 | return this.bottomUpGroupBy(Timeline.AggregatedTimelineTreeView.GroupBy.None, startTime, endTime); 180 | } 181 | 182 | /** 183 | * @param {!string} grouping Allowed values: None Category Subdomain Domain URL EventName 184 | * @return {!TimelineModel.TimelineProfileTree.Node} A grouped and sorted tree 185 | */ 186 | bottomUpGroupBy(grouping, startTime = 0, endTime = Infinity) { 187 | const topDown = this.topDownGroupBy(grouping, startTime, endTime); 188 | 189 | const bottomUpGrouped = TimelineModel.TimelineProfileTree.buildBottomUp(topDown); 190 | new TimelineModelTreeView(bottomUpGrouped).sortingChanged('self', 'desc'); 191 | 192 | // todo: understand why an empty key'd entry is created here 193 | bottomUpGrouped.children.delete(''); 194 | return bottomUpGrouped; 195 | } 196 | 197 | frameModel() { 198 | const frameModel = new TimelineModel.TimelineFrameModel(event => 199 | Timeline.TimelineUIUtils.eventStyle(event).category.name 200 | ); 201 | frameModel.addTraceEvents({ /* target */ }, 202 | this._timelineModel.inspectedTargetEvents(), this._timelineModel.sessionId() || ''); 203 | return frameModel; 204 | } 205 | 206 | filmStripModel() { 207 | return new SDK.FilmStripModel(this._tracingModel); 208 | } 209 | 210 | interactionModel() { 211 | const irModel = new TimelineModel.TimelineIRModel(); 212 | irModel.populate(this._timelineModel); 213 | return irModel; 214 | } 215 | } 216 | 217 | var sandboxedModel = new SandboxedModel(); 218 | // no exports as we're a sandboxed/eval'd module. 219 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | Copyright 2015 Google Inc. All Rights Reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "devtools-timeline-model", 3 | "version": "1.3.2", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "acorn": { 8 | "version": "5.3.0", 9 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.3.0.tgz", 10 | "integrity": "sha512-Yej+zOJ1Dm/IMZzzj78OntP/r3zHEaKcyNoU2lAaxPtrseM6rF0xwqoz5Q5ysAiED9hTjI2hgtvLXitlCN1/Ug==", 11 | "dev": true 12 | }, 13 | "acorn-jsx": { 14 | "version": "3.0.1", 15 | "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", 16 | "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", 17 | "dev": true, 18 | "requires": { 19 | "acorn": "3.3.0" 20 | }, 21 | "dependencies": { 22 | "acorn": { 23 | "version": "3.3.0", 24 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", 25 | "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", 26 | "dev": true 27 | } 28 | } 29 | }, 30 | "ajv": { 31 | "version": "4.11.8", 32 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", 33 | "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", 34 | "dev": true, 35 | "requires": { 36 | "co": "4.6.0", 37 | "json-stable-stringify": "1.0.1" 38 | } 39 | }, 40 | "ajv-keywords": { 41 | "version": "1.5.1", 42 | "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz", 43 | "integrity": "sha1-MU3QpLM2j609/NxU7eYXG4htrzw=", 44 | "dev": true 45 | }, 46 | "ansi-escapes": { 47 | "version": "1.4.0", 48 | "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", 49 | "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=", 50 | "dev": true 51 | }, 52 | "ansi-regex": { 53 | "version": "2.1.1", 54 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", 55 | "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", 56 | "dev": true 57 | }, 58 | "ansi-styles": { 59 | "version": "2.2.1", 60 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", 61 | "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", 62 | "dev": true 63 | }, 64 | "argparse": { 65 | "version": "1.0.9", 66 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", 67 | "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", 68 | "dev": true, 69 | "requires": { 70 | "sprintf-js": "1.0.3" 71 | } 72 | }, 73 | "array-find-index": { 74 | "version": "1.0.2", 75 | "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", 76 | "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", 77 | "dev": true 78 | }, 79 | "array-union": { 80 | "version": "1.0.2", 81 | "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", 82 | "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", 83 | "dev": true, 84 | "requires": { 85 | "array-uniq": "1.0.3" 86 | } 87 | }, 88 | "array-uniq": { 89 | "version": "1.0.3", 90 | "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", 91 | "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", 92 | "dev": true 93 | }, 94 | "arrify": { 95 | "version": "1.0.1", 96 | "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", 97 | "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", 98 | "dev": true 99 | }, 100 | "babar": { 101 | "version": "0.0.3", 102 | "resolved": "https://registry.npmjs.org/babar/-/babar-0.0.3.tgz", 103 | "integrity": "sha1-LzlNSlkY9+GunlQI6alvP5Ne4eI=", 104 | "dev": true, 105 | "requires": { 106 | "colors": "0.6.2" 107 | } 108 | }, 109 | "balanced-match": { 110 | "version": "1.0.0", 111 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 112 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 113 | "dev": true 114 | }, 115 | "brace-expansion": { 116 | "version": "1.1.8", 117 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", 118 | "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", 119 | "dev": true, 120 | "requires": { 121 | "balanced-match": "1.0.0", 122 | "concat-map": "0.0.1" 123 | } 124 | }, 125 | "builtin-modules": { 126 | "version": "1.1.1", 127 | "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", 128 | "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", 129 | "dev": true 130 | }, 131 | "caller-path": { 132 | "version": "0.1.0", 133 | "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", 134 | "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", 135 | "dev": true, 136 | "requires": { 137 | "callsites": "0.2.0" 138 | } 139 | }, 140 | "callsites": { 141 | "version": "0.2.0", 142 | "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", 143 | "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", 144 | "dev": true 145 | }, 146 | "camelcase": { 147 | "version": "2.1.1", 148 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", 149 | "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", 150 | "dev": true 151 | }, 152 | "camelcase-keys": { 153 | "version": "2.1.0", 154 | "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", 155 | "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", 156 | "dev": true, 157 | "requires": { 158 | "camelcase": "2.1.1", 159 | "map-obj": "1.0.1" 160 | } 161 | }, 162 | "chalk": { 163 | "version": "1.1.3", 164 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", 165 | "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", 166 | "dev": true, 167 | "requires": { 168 | "ansi-styles": "2.2.1", 169 | "escape-string-regexp": "1.0.5", 170 | "has-ansi": "2.0.0", 171 | "strip-ansi": "3.0.1", 172 | "supports-color": "2.0.0" 173 | } 174 | }, 175 | "chrome-devtools-frontend": { 176 | "version": "1.0.445684", 177 | "resolved": "https://registry.npmjs.org/chrome-devtools-frontend/-/chrome-devtools-frontend-1.0.445684.tgz", 178 | "integrity": "sha1-hUATGDYCTfK3D+kNAyKvNokx12I=" 179 | }, 180 | "circular-json": { 181 | "version": "0.3.3", 182 | "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", 183 | "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", 184 | "dev": true 185 | }, 186 | "cli-cursor": { 187 | "version": "1.0.2", 188 | "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", 189 | "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", 190 | "dev": true, 191 | "requires": { 192 | "restore-cursor": "1.0.1" 193 | } 194 | }, 195 | "cli-width": { 196 | "version": "2.2.0", 197 | "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", 198 | "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", 199 | "dev": true 200 | }, 201 | "co": { 202 | "version": "4.6.0", 203 | "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", 204 | "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", 205 | "dev": true 206 | }, 207 | "code-point-at": { 208 | "version": "1.1.0", 209 | "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", 210 | "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", 211 | "dev": true 212 | }, 213 | "colors": { 214 | "version": "0.6.2", 215 | "resolved": "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz", 216 | "integrity": "sha1-JCP+ZnisDF2uiFLl0OW+CMmXq8w=", 217 | "dev": true 218 | }, 219 | "commander": { 220 | "version": "2.3.0", 221 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.3.0.tgz", 222 | "integrity": "sha1-/UMOiJgy7DU7ms0d4hfBHLPu+HM=", 223 | "dev": true 224 | }, 225 | "concat-map": { 226 | "version": "0.0.1", 227 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 228 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 229 | "dev": true 230 | }, 231 | "concat-stream": { 232 | "version": "1.6.0", 233 | "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", 234 | "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", 235 | "dev": true, 236 | "requires": { 237 | "inherits": "2.0.3", 238 | "readable-stream": "2.3.3", 239 | "typedarray": "0.0.6" 240 | } 241 | }, 242 | "core-util-is": { 243 | "version": "1.0.2", 244 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 245 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", 246 | "dev": true 247 | }, 248 | "currently-unhandled": { 249 | "version": "0.4.1", 250 | "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", 251 | "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", 252 | "dev": true, 253 | "requires": { 254 | "array-find-index": "1.0.2" 255 | } 256 | }, 257 | "d": { 258 | "version": "1.0.0", 259 | "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", 260 | "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", 261 | "dev": true, 262 | "requires": { 263 | "es5-ext": "0.10.38" 264 | } 265 | }, 266 | "debug": { 267 | "version": "2.6.9", 268 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 269 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 270 | "dev": true, 271 | "requires": { 272 | "ms": "2.0.0" 273 | } 274 | }, 275 | "decamelize": { 276 | "version": "1.2.0", 277 | "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", 278 | "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", 279 | "dev": true 280 | }, 281 | "deep-assign": { 282 | "version": "1.0.0", 283 | "resolved": "https://registry.npmjs.org/deep-assign/-/deep-assign-1.0.0.tgz", 284 | "integrity": "sha1-sJJ0O+hCfcYh6gBnzex+cN0Z83s=", 285 | "dev": true, 286 | "requires": { 287 | "is-obj": "1.0.1" 288 | } 289 | }, 290 | "deep-is": { 291 | "version": "0.1.3", 292 | "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", 293 | "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", 294 | "dev": true 295 | }, 296 | "del": { 297 | "version": "2.2.2", 298 | "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", 299 | "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", 300 | "dev": true, 301 | "requires": { 302 | "globby": "5.0.0", 303 | "is-path-cwd": "1.0.0", 304 | "is-path-in-cwd": "1.0.0", 305 | "object-assign": "4.1.1", 306 | "pify": "2.3.0", 307 | "pinkie-promise": "2.0.1", 308 | "rimraf": "2.6.2" 309 | } 310 | }, 311 | "devtools-timeline-model": { 312 | "version": "1.3.1", 313 | "resolved": "https://registry.npmjs.org/devtools-timeline-model/-/devtools-timeline-model-1.3.1.tgz", 314 | "integrity": "sha1-J+m4SdRa1Q5dNnVlfUrrv3qRlmk=", 315 | "dev": true, 316 | "requires": { 317 | "chrome-devtools-frontend": "1.0.445684", 318 | "resolve": "1.1.7" 319 | } 320 | }, 321 | "diff": { 322 | "version": "1.4.0", 323 | "resolved": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz", 324 | "integrity": "sha1-fyjS657nsVqX79ic5j3P2qPMur8=", 325 | "dev": true 326 | }, 327 | "doctrine": { 328 | "version": "1.5.0", 329 | "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", 330 | "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", 331 | "dev": true, 332 | "requires": { 333 | "esutils": "2.0.2", 334 | "isarray": "1.0.0" 335 | } 336 | }, 337 | "error-ex": { 338 | "version": "1.3.1", 339 | "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", 340 | "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", 341 | "dev": true, 342 | "requires": { 343 | "is-arrayish": "0.2.1" 344 | } 345 | }, 346 | "es5-ext": { 347 | "version": "0.10.38", 348 | "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.38.tgz", 349 | "integrity": "sha512-jCMyePo7AXbUESwbl8Qi01VSH2piY9s/a3rSU/5w/MlTIx8HPL1xn2InGN8ejt/xulcJgnTO7vqNtOAxzYd2Kg==", 350 | "dev": true, 351 | "requires": { 352 | "es6-iterator": "2.0.3", 353 | "es6-symbol": "3.1.1" 354 | } 355 | }, 356 | "es6-iterator": { 357 | "version": "2.0.3", 358 | "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", 359 | "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", 360 | "dev": true, 361 | "requires": { 362 | "d": "1.0.0", 363 | "es5-ext": "0.10.38", 364 | "es6-symbol": "3.1.1" 365 | } 366 | }, 367 | "es6-map": { 368 | "version": "0.1.5", 369 | "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", 370 | "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", 371 | "dev": true, 372 | "requires": { 373 | "d": "1.0.0", 374 | "es5-ext": "0.10.38", 375 | "es6-iterator": "2.0.3", 376 | "es6-set": "0.1.5", 377 | "es6-symbol": "3.1.1", 378 | "event-emitter": "0.3.5" 379 | } 380 | }, 381 | "es6-set": { 382 | "version": "0.1.5", 383 | "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", 384 | "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", 385 | "dev": true, 386 | "requires": { 387 | "d": "1.0.0", 388 | "es5-ext": "0.10.38", 389 | "es6-iterator": "2.0.3", 390 | "es6-symbol": "3.1.1", 391 | "event-emitter": "0.3.5" 392 | } 393 | }, 394 | "es6-symbol": { 395 | "version": "3.1.1", 396 | "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", 397 | "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", 398 | "dev": true, 399 | "requires": { 400 | "d": "1.0.0", 401 | "es5-ext": "0.10.38" 402 | } 403 | }, 404 | "es6-weak-map": { 405 | "version": "2.0.2", 406 | "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz", 407 | "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=", 408 | "dev": true, 409 | "requires": { 410 | "d": "1.0.0", 411 | "es5-ext": "0.10.38", 412 | "es6-iterator": "2.0.3", 413 | "es6-symbol": "3.1.1" 414 | } 415 | }, 416 | "escape-string-regexp": { 417 | "version": "1.0.5", 418 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 419 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 420 | "dev": true 421 | }, 422 | "escope": { 423 | "version": "3.6.0", 424 | "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", 425 | "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=", 426 | "dev": true, 427 | "requires": { 428 | "es6-map": "0.1.5", 429 | "es6-weak-map": "2.0.2", 430 | "esrecurse": "4.2.0", 431 | "estraverse": "4.2.0" 432 | } 433 | }, 434 | "eslint": { 435 | "version": "2.13.1", 436 | "resolved": "https://registry.npmjs.org/eslint/-/eslint-2.13.1.tgz", 437 | "integrity": "sha1-5MyPoPAJ+4KaquI4VaKTYL4fbBE=", 438 | "dev": true, 439 | "requires": { 440 | "chalk": "1.1.3", 441 | "concat-stream": "1.6.0", 442 | "debug": "2.6.9", 443 | "doctrine": "1.5.0", 444 | "es6-map": "0.1.5", 445 | "escope": "3.6.0", 446 | "espree": "3.5.2", 447 | "estraverse": "4.2.0", 448 | "esutils": "2.0.2", 449 | "file-entry-cache": "1.3.1", 450 | "glob": "7.1.2", 451 | "globals": "9.18.0", 452 | "ignore": "3.3.7", 453 | "imurmurhash": "0.1.4", 454 | "inquirer": "0.12.0", 455 | "is-my-json-valid": "2.17.1", 456 | "is-resolvable": "1.1.0", 457 | "js-yaml": "3.10.0", 458 | "json-stable-stringify": "1.0.1", 459 | "levn": "0.3.0", 460 | "lodash": "4.17.4", 461 | "mkdirp": "0.5.1", 462 | "optionator": "0.8.2", 463 | "path-is-absolute": "1.0.1", 464 | "path-is-inside": "1.0.2", 465 | "pluralize": "1.2.1", 466 | "progress": "1.1.8", 467 | "require-uncached": "1.0.3", 468 | "shelljs": "0.6.1", 469 | "strip-json-comments": "1.0.4", 470 | "table": "3.8.3", 471 | "text-table": "0.2.0", 472 | "user-home": "2.0.0" 473 | } 474 | }, 475 | "eslint-config-google": { 476 | "version": "0.4.0", 477 | "resolved": "https://registry.npmjs.org/eslint-config-google/-/eslint-config-google-0.4.0.tgz", 478 | "integrity": "sha1-aQoVGLVJKBkNggmWCgAV3hURD0U=", 479 | "dev": true, 480 | "requires": { 481 | "eslint-config-xo": "0.10.1" 482 | } 483 | }, 484 | "eslint-config-xo": { 485 | "version": "0.10.1", 486 | "resolved": "https://registry.npmjs.org/eslint-config-xo/-/eslint-config-xo-0.10.1.tgz", 487 | "integrity": "sha1-GxVB7sgYyQ9J/OgK0jcZxtH6uXM=", 488 | "dev": true, 489 | "requires": { 490 | "deep-assign": "1.0.0" 491 | } 492 | }, 493 | "espree": { 494 | "version": "3.5.2", 495 | "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.2.tgz", 496 | "integrity": "sha512-sadKeYwaR/aJ3stC2CdvgXu1T16TdYN+qwCpcWbMnGJ8s0zNWemzrvb2GbD4OhmJ/fwpJjudThAlLobGbWZbCQ==", 497 | "dev": true, 498 | "requires": { 499 | "acorn": "5.3.0", 500 | "acorn-jsx": "3.0.1" 501 | } 502 | }, 503 | "esprima": { 504 | "version": "4.0.0", 505 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", 506 | "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==", 507 | "dev": true 508 | }, 509 | "esrecurse": { 510 | "version": "4.2.0", 511 | "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.0.tgz", 512 | "integrity": "sha1-+pVo2Y04I/mkHZHpAtyrnqblsWM=", 513 | "dev": true, 514 | "requires": { 515 | "estraverse": "4.2.0", 516 | "object-assign": "4.1.1" 517 | } 518 | }, 519 | "estraverse": { 520 | "version": "4.2.0", 521 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", 522 | "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", 523 | "dev": true 524 | }, 525 | "esutils": { 526 | "version": "2.0.2", 527 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", 528 | "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", 529 | "dev": true 530 | }, 531 | "event-emitter": { 532 | "version": "0.3.5", 533 | "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", 534 | "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", 535 | "dev": true, 536 | "requires": { 537 | "d": "1.0.0", 538 | "es5-ext": "0.10.38" 539 | } 540 | }, 541 | "exit-hook": { 542 | "version": "1.1.1", 543 | "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", 544 | "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=", 545 | "dev": true 546 | }, 547 | "fast-levenshtein": { 548 | "version": "2.0.6", 549 | "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", 550 | "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", 551 | "dev": true 552 | }, 553 | "figures": { 554 | "version": "1.7.0", 555 | "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", 556 | "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", 557 | "dev": true, 558 | "requires": { 559 | "escape-string-regexp": "1.0.5", 560 | "object-assign": "4.1.1" 561 | } 562 | }, 563 | "file-entry-cache": { 564 | "version": "1.3.1", 565 | "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-1.3.1.tgz", 566 | "integrity": "sha1-RMYepgeuS+nBQC9B9EJwy/4zT/g=", 567 | "dev": true, 568 | "requires": { 569 | "flat-cache": "1.3.0", 570 | "object-assign": "4.1.1" 571 | } 572 | }, 573 | "find-up": { 574 | "version": "1.1.2", 575 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", 576 | "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", 577 | "dev": true, 578 | "requires": { 579 | "path-exists": "2.1.0", 580 | "pinkie-promise": "2.0.1" 581 | } 582 | }, 583 | "flat-cache": { 584 | "version": "1.3.0", 585 | "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz", 586 | "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=", 587 | "dev": true, 588 | "requires": { 589 | "circular-json": "0.3.3", 590 | "del": "2.2.2", 591 | "graceful-fs": "4.1.11", 592 | "write": "0.2.1" 593 | } 594 | }, 595 | "fs.realpath": { 596 | "version": "1.0.0", 597 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 598 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 599 | "dev": true 600 | }, 601 | "generate-function": { 602 | "version": "2.0.0", 603 | "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", 604 | "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=", 605 | "dev": true 606 | }, 607 | "generate-object-property": { 608 | "version": "1.2.0", 609 | "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", 610 | "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", 611 | "dev": true, 612 | "requires": { 613 | "is-property": "1.0.2" 614 | } 615 | }, 616 | "get-stdin": { 617 | "version": "4.0.1", 618 | "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", 619 | "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", 620 | "dev": true 621 | }, 622 | "glob": { 623 | "version": "7.1.2", 624 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", 625 | "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", 626 | "dev": true, 627 | "requires": { 628 | "fs.realpath": "1.0.0", 629 | "inflight": "1.0.6", 630 | "inherits": "2.0.3", 631 | "minimatch": "3.0.4", 632 | "once": "1.4.0", 633 | "path-is-absolute": "1.0.1" 634 | } 635 | }, 636 | "globals": { 637 | "version": "9.18.0", 638 | "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", 639 | "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", 640 | "dev": true 641 | }, 642 | "globby": { 643 | "version": "5.0.0", 644 | "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", 645 | "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", 646 | "dev": true, 647 | "requires": { 648 | "array-union": "1.0.2", 649 | "arrify": "1.0.1", 650 | "glob": "7.1.2", 651 | "object-assign": "4.1.1", 652 | "pify": "2.3.0", 653 | "pinkie-promise": "2.0.1" 654 | } 655 | }, 656 | "graceful-fs": { 657 | "version": "4.1.11", 658 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", 659 | "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", 660 | "dev": true 661 | }, 662 | "growl": { 663 | "version": "1.9.2", 664 | "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", 665 | "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=", 666 | "dev": true 667 | }, 668 | "has-ansi": { 669 | "version": "2.0.0", 670 | "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", 671 | "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", 672 | "dev": true, 673 | "requires": { 674 | "ansi-regex": "2.1.1" 675 | } 676 | }, 677 | "hosted-git-info": { 678 | "version": "2.5.0", 679 | "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz", 680 | "integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg==", 681 | "dev": true 682 | }, 683 | "ignore": { 684 | "version": "3.3.7", 685 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.7.tgz", 686 | "integrity": "sha512-YGG3ejvBNHRqu0559EOxxNFihD0AjpvHlC/pdGKd3X3ofe+CoJkYazwNJYTNebqpPKN+VVQbh4ZFn1DivMNuHA==", 687 | "dev": true 688 | }, 689 | "imurmurhash": { 690 | "version": "0.1.4", 691 | "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", 692 | "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", 693 | "dev": true 694 | }, 695 | "indent-string": { 696 | "version": "2.1.0", 697 | "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", 698 | "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", 699 | "dev": true, 700 | "requires": { 701 | "repeating": "2.0.1" 702 | } 703 | }, 704 | "inflight": { 705 | "version": "1.0.6", 706 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 707 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 708 | "dev": true, 709 | "requires": { 710 | "once": "1.4.0", 711 | "wrappy": "1.0.2" 712 | } 713 | }, 714 | "inherits": { 715 | "version": "2.0.3", 716 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 717 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", 718 | "dev": true 719 | }, 720 | "inquirer": { 721 | "version": "0.12.0", 722 | "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz", 723 | "integrity": "sha1-HvK/1jUE3wvHV4X/+MLEHfEvB34=", 724 | "dev": true, 725 | "requires": { 726 | "ansi-escapes": "1.4.0", 727 | "ansi-regex": "2.1.1", 728 | "chalk": "1.1.3", 729 | "cli-cursor": "1.0.2", 730 | "cli-width": "2.2.0", 731 | "figures": "1.7.0", 732 | "lodash": "4.17.4", 733 | "readline2": "1.0.1", 734 | "run-async": "0.1.0", 735 | "rx-lite": "3.1.2", 736 | "string-width": "1.0.2", 737 | "strip-ansi": "3.0.1", 738 | "through": "2.3.8" 739 | } 740 | }, 741 | "is-arrayish": { 742 | "version": "0.2.1", 743 | "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", 744 | "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", 745 | "dev": true 746 | }, 747 | "is-builtin-module": { 748 | "version": "1.0.0", 749 | "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", 750 | "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", 751 | "dev": true, 752 | "requires": { 753 | "builtin-modules": "1.1.1" 754 | } 755 | }, 756 | "is-finite": { 757 | "version": "1.0.2", 758 | "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", 759 | "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", 760 | "dev": true, 761 | "requires": { 762 | "number-is-nan": "1.0.1" 763 | } 764 | }, 765 | "is-fullwidth-code-point": { 766 | "version": "1.0.0", 767 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", 768 | "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", 769 | "dev": true, 770 | "requires": { 771 | "number-is-nan": "1.0.1" 772 | } 773 | }, 774 | "is-my-json-valid": { 775 | "version": "2.17.1", 776 | "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.17.1.tgz", 777 | "integrity": "sha512-Q2khNw+oBlWuaYvEEHtKSw/pCxD2L5Rc1C+UQme9X6JdRDh7m5D7HkozA0qa3DUkQ6VzCnEm8mVIQPyIRkI5sQ==", 778 | "dev": true, 779 | "requires": { 780 | "generate-function": "2.0.0", 781 | "generate-object-property": "1.2.0", 782 | "jsonpointer": "4.0.1", 783 | "xtend": "4.0.1" 784 | } 785 | }, 786 | "is-obj": { 787 | "version": "1.0.1", 788 | "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", 789 | "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", 790 | "dev": true 791 | }, 792 | "is-path-cwd": { 793 | "version": "1.0.0", 794 | "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", 795 | "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", 796 | "dev": true 797 | }, 798 | "is-path-in-cwd": { 799 | "version": "1.0.0", 800 | "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz", 801 | "integrity": "sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=", 802 | "dev": true, 803 | "requires": { 804 | "is-path-inside": "1.0.1" 805 | } 806 | }, 807 | "is-path-inside": { 808 | "version": "1.0.1", 809 | "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", 810 | "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", 811 | "dev": true, 812 | "requires": { 813 | "path-is-inside": "1.0.2" 814 | } 815 | }, 816 | "is-property": { 817 | "version": "1.0.2", 818 | "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", 819 | "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", 820 | "dev": true 821 | }, 822 | "is-resolvable": { 823 | "version": "1.1.0", 824 | "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", 825 | "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", 826 | "dev": true 827 | }, 828 | "is-utf8": { 829 | "version": "0.2.1", 830 | "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", 831 | "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", 832 | "dev": true 833 | }, 834 | "isarray": { 835 | "version": "1.0.0", 836 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 837 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", 838 | "dev": true 839 | }, 840 | "jade": { 841 | "version": "0.26.3", 842 | "resolved": "https://registry.npmjs.org/jade/-/jade-0.26.3.tgz", 843 | "integrity": "sha1-jxDXl32NefL2/4YqgbBRPMslaGw=", 844 | "dev": true, 845 | "requires": { 846 | "commander": "0.6.1", 847 | "mkdirp": "0.3.0" 848 | }, 849 | "dependencies": { 850 | "commander": { 851 | "version": "0.6.1", 852 | "resolved": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz", 853 | "integrity": "sha1-+mihT2qUXVTbvlDYzbMyDp47GgY=", 854 | "dev": true 855 | }, 856 | "mkdirp": { 857 | "version": "0.3.0", 858 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz", 859 | "integrity": "sha1-G79asbqCevI1dRQ0kEJkVfSB/h4=", 860 | "dev": true 861 | } 862 | } 863 | }, 864 | "jpeg-js": { 865 | "version": "0.1.2", 866 | "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.1.2.tgz", 867 | "integrity": "sha1-E1uZLAV1yYXPoPSUoyJ+0jhYPs4=", 868 | "dev": true 869 | }, 870 | "js-yaml": { 871 | "version": "3.10.0", 872 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.10.0.tgz", 873 | "integrity": "sha512-O2v52ffjLa9VeM43J4XocZE//WT9N0IiwDa3KSHH7Tu8CtH+1qM8SIZvnsTh6v+4yFy5KUY3BHUVwjpfAWsjIA==", 874 | "dev": true, 875 | "requires": { 876 | "argparse": "1.0.9", 877 | "esprima": "4.0.0" 878 | } 879 | }, 880 | "json-stable-stringify": { 881 | "version": "1.0.1", 882 | "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", 883 | "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", 884 | "dev": true, 885 | "requires": { 886 | "jsonify": "0.0.0" 887 | } 888 | }, 889 | "jsonify": { 890 | "version": "0.0.0", 891 | "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", 892 | "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", 893 | "dev": true 894 | }, 895 | "jsonpointer": { 896 | "version": "4.0.1", 897 | "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", 898 | "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", 899 | "dev": true 900 | }, 901 | "levn": { 902 | "version": "0.3.0", 903 | "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", 904 | "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", 905 | "dev": true, 906 | "requires": { 907 | "prelude-ls": "1.1.2", 908 | "type-check": "0.3.2" 909 | } 910 | }, 911 | "load-json-file": { 912 | "version": "1.1.0", 913 | "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", 914 | "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", 915 | "dev": true, 916 | "requires": { 917 | "graceful-fs": "4.1.11", 918 | "parse-json": "2.2.0", 919 | "pify": "2.3.0", 920 | "pinkie-promise": "2.0.1", 921 | "strip-bom": "2.0.0" 922 | } 923 | }, 924 | "lodash": { 925 | "version": "4.17.4", 926 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", 927 | "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", 928 | "dev": true 929 | }, 930 | "loud-rejection": { 931 | "version": "1.6.0", 932 | "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", 933 | "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", 934 | "dev": true, 935 | "requires": { 936 | "currently-unhandled": "0.4.1", 937 | "signal-exit": "3.0.2" 938 | } 939 | }, 940 | "lru-cache": { 941 | "version": "2.7.3", 942 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", 943 | "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", 944 | "dev": true 945 | }, 946 | "map-obj": { 947 | "version": "1.0.1", 948 | "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", 949 | "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", 950 | "dev": true 951 | }, 952 | "meow": { 953 | "version": "3.7.0", 954 | "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", 955 | "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", 956 | "dev": true, 957 | "requires": { 958 | "camelcase-keys": "2.1.0", 959 | "decamelize": "1.2.0", 960 | "loud-rejection": "1.6.0", 961 | "map-obj": "1.0.1", 962 | "minimist": "1.2.0", 963 | "normalize-package-data": "2.4.0", 964 | "object-assign": "4.1.1", 965 | "read-pkg-up": "1.0.1", 966 | "redent": "1.0.0", 967 | "trim-newlines": "1.0.0" 968 | }, 969 | "dependencies": { 970 | "minimist": { 971 | "version": "1.2.0", 972 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", 973 | "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", 974 | "dev": true 975 | } 976 | } 977 | }, 978 | "minimatch": { 979 | "version": "3.0.4", 980 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 981 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 982 | "dev": true, 983 | "requires": { 984 | "brace-expansion": "1.1.8" 985 | } 986 | }, 987 | "minimist": { 988 | "version": "0.0.8", 989 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 990 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", 991 | "dev": true 992 | }, 993 | "mkdirp": { 994 | "version": "0.5.1", 995 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 996 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 997 | "dev": true, 998 | "requires": { 999 | "minimist": "0.0.8" 1000 | } 1001 | }, 1002 | "mocha": { 1003 | "version": "2.5.3", 1004 | "resolved": "https://registry.npmjs.org/mocha/-/mocha-2.5.3.tgz", 1005 | "integrity": "sha1-FhvlvetJZ3HrmzV0UFC2IrWu/Fg=", 1006 | "dev": true, 1007 | "requires": { 1008 | "commander": "2.3.0", 1009 | "debug": "2.2.0", 1010 | "diff": "1.4.0", 1011 | "escape-string-regexp": "1.0.2", 1012 | "glob": "3.2.11", 1013 | "growl": "1.9.2", 1014 | "jade": "0.26.3", 1015 | "mkdirp": "0.5.1", 1016 | "supports-color": "1.2.0", 1017 | "to-iso-string": "0.0.2" 1018 | }, 1019 | "dependencies": { 1020 | "debug": { 1021 | "version": "2.2.0", 1022 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", 1023 | "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", 1024 | "dev": true, 1025 | "requires": { 1026 | "ms": "0.7.1" 1027 | } 1028 | }, 1029 | "escape-string-regexp": { 1030 | "version": "1.0.2", 1031 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz", 1032 | "integrity": "sha1-Tbwv5nTnGUnK8/smlc5/LcHZqNE=", 1033 | "dev": true 1034 | }, 1035 | "glob": { 1036 | "version": "3.2.11", 1037 | "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz", 1038 | "integrity": "sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0=", 1039 | "dev": true, 1040 | "requires": { 1041 | "inherits": "2.0.3", 1042 | "minimatch": "0.3.0" 1043 | } 1044 | }, 1045 | "minimatch": { 1046 | "version": "0.3.0", 1047 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz", 1048 | "integrity": "sha1-J12O2qxPG7MyZHIInnlJyDlGmd0=", 1049 | "dev": true, 1050 | "requires": { 1051 | "lru-cache": "2.7.3", 1052 | "sigmund": "1.0.1" 1053 | } 1054 | }, 1055 | "ms": { 1056 | "version": "0.7.1", 1057 | "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", 1058 | "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", 1059 | "dev": true 1060 | }, 1061 | "supports-color": { 1062 | "version": "1.2.0", 1063 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-1.2.0.tgz", 1064 | "integrity": "sha1-/x7R5hFp0Gs88tWI4YixjYhH4X4=", 1065 | "dev": true 1066 | } 1067 | } 1068 | }, 1069 | "ms": { 1070 | "version": "2.0.0", 1071 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 1072 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", 1073 | "dev": true 1074 | }, 1075 | "mute-stream": { 1076 | "version": "0.0.5", 1077 | "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz", 1078 | "integrity": "sha1-j7+rsKmKJT0xhDMfno3rc3L6xsA=", 1079 | "dev": true 1080 | }, 1081 | "normalize-package-data": { 1082 | "version": "2.4.0", 1083 | "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", 1084 | "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", 1085 | "dev": true, 1086 | "requires": { 1087 | "hosted-git-info": "2.5.0", 1088 | "is-builtin-module": "1.0.0", 1089 | "semver": "5.5.0", 1090 | "validate-npm-package-license": "3.0.1" 1091 | } 1092 | }, 1093 | "number-is-nan": { 1094 | "version": "1.0.1", 1095 | "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", 1096 | "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", 1097 | "dev": true 1098 | }, 1099 | "object-assign": { 1100 | "version": "4.1.1", 1101 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 1102 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", 1103 | "dev": true 1104 | }, 1105 | "once": { 1106 | "version": "1.4.0", 1107 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 1108 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 1109 | "dev": true, 1110 | "requires": { 1111 | "wrappy": "1.0.2" 1112 | } 1113 | }, 1114 | "onetime": { 1115 | "version": "1.1.0", 1116 | "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", 1117 | "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", 1118 | "dev": true 1119 | }, 1120 | "optionator": { 1121 | "version": "0.8.2", 1122 | "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", 1123 | "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", 1124 | "dev": true, 1125 | "requires": { 1126 | "deep-is": "0.1.3", 1127 | "fast-levenshtein": "2.0.6", 1128 | "levn": "0.3.0", 1129 | "prelude-ls": "1.1.2", 1130 | "type-check": "0.3.2", 1131 | "wordwrap": "1.0.0" 1132 | } 1133 | }, 1134 | "os-homedir": { 1135 | "version": "1.0.2", 1136 | "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", 1137 | "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", 1138 | "dev": true 1139 | }, 1140 | "parse-json": { 1141 | "version": "2.2.0", 1142 | "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", 1143 | "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", 1144 | "dev": true, 1145 | "requires": { 1146 | "error-ex": "1.3.1" 1147 | } 1148 | }, 1149 | "path-exists": { 1150 | "version": "2.1.0", 1151 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", 1152 | "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", 1153 | "dev": true, 1154 | "requires": { 1155 | "pinkie-promise": "2.0.1" 1156 | } 1157 | }, 1158 | "path-is-absolute": { 1159 | "version": "1.0.1", 1160 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 1161 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 1162 | "dev": true 1163 | }, 1164 | "path-is-inside": { 1165 | "version": "1.0.2", 1166 | "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", 1167 | "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", 1168 | "dev": true 1169 | }, 1170 | "path-type": { 1171 | "version": "1.1.0", 1172 | "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", 1173 | "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", 1174 | "dev": true, 1175 | "requires": { 1176 | "graceful-fs": "4.1.11", 1177 | "pify": "2.3.0", 1178 | "pinkie-promise": "2.0.1" 1179 | } 1180 | }, 1181 | "pify": { 1182 | "version": "2.3.0", 1183 | "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", 1184 | "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", 1185 | "dev": true 1186 | }, 1187 | "pinkie": { 1188 | "version": "2.0.4", 1189 | "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", 1190 | "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", 1191 | "dev": true 1192 | }, 1193 | "pinkie-promise": { 1194 | "version": "2.0.1", 1195 | "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", 1196 | "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", 1197 | "dev": true, 1198 | "requires": { 1199 | "pinkie": "2.0.4" 1200 | } 1201 | }, 1202 | "pluralize": { 1203 | "version": "1.2.1", 1204 | "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz", 1205 | "integrity": "sha1-0aIUg/0iu0HlihL6NCGCMUCJfEU=", 1206 | "dev": true 1207 | }, 1208 | "prelude-ls": { 1209 | "version": "1.1.2", 1210 | "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", 1211 | "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", 1212 | "dev": true 1213 | }, 1214 | "process-nextick-args": { 1215 | "version": "1.0.7", 1216 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", 1217 | "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", 1218 | "dev": true 1219 | }, 1220 | "progress": { 1221 | "version": "1.1.8", 1222 | "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", 1223 | "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", 1224 | "dev": true 1225 | }, 1226 | "read-pkg": { 1227 | "version": "1.1.0", 1228 | "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", 1229 | "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", 1230 | "dev": true, 1231 | "requires": { 1232 | "load-json-file": "1.1.0", 1233 | "normalize-package-data": "2.4.0", 1234 | "path-type": "1.1.0" 1235 | } 1236 | }, 1237 | "read-pkg-up": { 1238 | "version": "1.0.1", 1239 | "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", 1240 | "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", 1241 | "dev": true, 1242 | "requires": { 1243 | "find-up": "1.1.2", 1244 | "read-pkg": "1.1.0" 1245 | } 1246 | }, 1247 | "readable-stream": { 1248 | "version": "2.3.3", 1249 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", 1250 | "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", 1251 | "dev": true, 1252 | "requires": { 1253 | "core-util-is": "1.0.2", 1254 | "inherits": "2.0.3", 1255 | "isarray": "1.0.0", 1256 | "process-nextick-args": "1.0.7", 1257 | "safe-buffer": "5.1.1", 1258 | "string_decoder": "1.0.3", 1259 | "util-deprecate": "1.0.2" 1260 | } 1261 | }, 1262 | "readline2": { 1263 | "version": "1.0.1", 1264 | "resolved": "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz", 1265 | "integrity": "sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU=", 1266 | "dev": true, 1267 | "requires": { 1268 | "code-point-at": "1.1.0", 1269 | "is-fullwidth-code-point": "1.0.0", 1270 | "mute-stream": "0.0.5" 1271 | } 1272 | }, 1273 | "redent": { 1274 | "version": "1.0.0", 1275 | "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", 1276 | "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", 1277 | "dev": true, 1278 | "requires": { 1279 | "indent-string": "2.1.0", 1280 | "strip-indent": "1.0.1" 1281 | } 1282 | }, 1283 | "repeating": { 1284 | "version": "2.0.1", 1285 | "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", 1286 | "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", 1287 | "dev": true, 1288 | "requires": { 1289 | "is-finite": "1.0.2" 1290 | } 1291 | }, 1292 | "require-uncached": { 1293 | "version": "1.0.3", 1294 | "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", 1295 | "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", 1296 | "dev": true, 1297 | "requires": { 1298 | "caller-path": "0.1.0", 1299 | "resolve-from": "1.0.1" 1300 | } 1301 | }, 1302 | "resolve": { 1303 | "version": "1.1.7", 1304 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", 1305 | "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=" 1306 | }, 1307 | "resolve-from": { 1308 | "version": "1.0.1", 1309 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", 1310 | "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", 1311 | "dev": true 1312 | }, 1313 | "restore-cursor": { 1314 | "version": "1.0.1", 1315 | "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", 1316 | "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", 1317 | "dev": true, 1318 | "requires": { 1319 | "exit-hook": "1.1.1", 1320 | "onetime": "1.1.0" 1321 | } 1322 | }, 1323 | "rimraf": { 1324 | "version": "2.6.2", 1325 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", 1326 | "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", 1327 | "dev": true, 1328 | "requires": { 1329 | "glob": "7.1.2" 1330 | } 1331 | }, 1332 | "run-async": { 1333 | "version": "0.1.0", 1334 | "resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz", 1335 | "integrity": "sha1-yK1KXhEGYeQCp9IbUw4AnyX444k=", 1336 | "dev": true, 1337 | "requires": { 1338 | "once": "1.4.0" 1339 | } 1340 | }, 1341 | "rx-lite": { 1342 | "version": "3.1.2", 1343 | "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz", 1344 | "integrity": "sha1-Gc5QLKVyZl87ZHsQk5+X/RYV8QI=", 1345 | "dev": true 1346 | }, 1347 | "safe-buffer": { 1348 | "version": "5.1.1", 1349 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", 1350 | "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", 1351 | "dev": true 1352 | }, 1353 | "semver": { 1354 | "version": "5.5.0", 1355 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", 1356 | "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", 1357 | "dev": true 1358 | }, 1359 | "shelljs": { 1360 | "version": "0.6.1", 1361 | "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.6.1.tgz", 1362 | "integrity": "sha1-7GIRvtGSBEIIj+D3Cyg3Iy7SyKg=", 1363 | "dev": true 1364 | }, 1365 | "sigmund": { 1366 | "version": "1.0.1", 1367 | "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", 1368 | "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", 1369 | "dev": true 1370 | }, 1371 | "signal-exit": { 1372 | "version": "3.0.2", 1373 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", 1374 | "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", 1375 | "dev": true 1376 | }, 1377 | "slice-ansi": { 1378 | "version": "0.0.4", 1379 | "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", 1380 | "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", 1381 | "dev": true 1382 | }, 1383 | "spdx-correct": { 1384 | "version": "1.0.2", 1385 | "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", 1386 | "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", 1387 | "dev": true, 1388 | "requires": { 1389 | "spdx-license-ids": "1.2.2" 1390 | } 1391 | }, 1392 | "spdx-expression-parse": { 1393 | "version": "1.0.4", 1394 | "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz", 1395 | "integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=", 1396 | "dev": true 1397 | }, 1398 | "spdx-license-ids": { 1399 | "version": "1.2.2", 1400 | "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz", 1401 | "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=", 1402 | "dev": true 1403 | }, 1404 | "speedline": { 1405 | "version": "0.1.2", 1406 | "resolved": "https://registry.npmjs.org/speedline/-/speedline-0.1.2.tgz", 1407 | "integrity": "sha1-bGfzcXvLYDzHlaaO0x6/1n3w7uc=", 1408 | "dev": true, 1409 | "requires": { 1410 | "babar": "0.0.3", 1411 | "devtools-timeline-model": "1.3.1", 1412 | "jpeg-js": "0.1.2", 1413 | "loud-rejection": "1.6.0", 1414 | "meow": "3.7.0" 1415 | } 1416 | }, 1417 | "sprintf-js": { 1418 | "version": "1.0.3", 1419 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 1420 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", 1421 | "dev": true 1422 | }, 1423 | "string-width": { 1424 | "version": "1.0.2", 1425 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", 1426 | "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", 1427 | "dev": true, 1428 | "requires": { 1429 | "code-point-at": "1.1.0", 1430 | "is-fullwidth-code-point": "1.0.0", 1431 | "strip-ansi": "3.0.1" 1432 | } 1433 | }, 1434 | "string_decoder": { 1435 | "version": "1.0.3", 1436 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", 1437 | "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", 1438 | "dev": true, 1439 | "requires": { 1440 | "safe-buffer": "5.1.1" 1441 | } 1442 | }, 1443 | "strip-ansi": { 1444 | "version": "3.0.1", 1445 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", 1446 | "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", 1447 | "dev": true, 1448 | "requires": { 1449 | "ansi-regex": "2.1.1" 1450 | } 1451 | }, 1452 | "strip-bom": { 1453 | "version": "2.0.0", 1454 | "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", 1455 | "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", 1456 | "dev": true, 1457 | "requires": { 1458 | "is-utf8": "0.2.1" 1459 | } 1460 | }, 1461 | "strip-indent": { 1462 | "version": "1.0.1", 1463 | "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", 1464 | "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", 1465 | "dev": true, 1466 | "requires": { 1467 | "get-stdin": "4.0.1" 1468 | } 1469 | }, 1470 | "strip-json-comments": { 1471 | "version": "1.0.4", 1472 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", 1473 | "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=", 1474 | "dev": true 1475 | }, 1476 | "supports-color": { 1477 | "version": "2.0.0", 1478 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", 1479 | "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", 1480 | "dev": true 1481 | }, 1482 | "table": { 1483 | "version": "3.8.3", 1484 | "resolved": "https://registry.npmjs.org/table/-/table-3.8.3.tgz", 1485 | "integrity": "sha1-K7xULw/amGGnVdOUf+/Ys/UThV8=", 1486 | "dev": true, 1487 | "requires": { 1488 | "ajv": "4.11.8", 1489 | "ajv-keywords": "1.5.1", 1490 | "chalk": "1.1.3", 1491 | "lodash": "4.17.4", 1492 | "slice-ansi": "0.0.4", 1493 | "string-width": "2.1.1" 1494 | }, 1495 | "dependencies": { 1496 | "ansi-regex": { 1497 | "version": "3.0.0", 1498 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", 1499 | "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", 1500 | "dev": true 1501 | }, 1502 | "is-fullwidth-code-point": { 1503 | "version": "2.0.0", 1504 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", 1505 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", 1506 | "dev": true 1507 | }, 1508 | "string-width": { 1509 | "version": "2.1.1", 1510 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", 1511 | "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", 1512 | "dev": true, 1513 | "requires": { 1514 | "is-fullwidth-code-point": "2.0.0", 1515 | "strip-ansi": "4.0.0" 1516 | } 1517 | }, 1518 | "strip-ansi": { 1519 | "version": "4.0.0", 1520 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", 1521 | "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", 1522 | "dev": true, 1523 | "requires": { 1524 | "ansi-regex": "3.0.0" 1525 | } 1526 | } 1527 | } 1528 | }, 1529 | "text-table": { 1530 | "version": "0.2.0", 1531 | "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", 1532 | "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", 1533 | "dev": true 1534 | }, 1535 | "through": { 1536 | "version": "2.3.8", 1537 | "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", 1538 | "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", 1539 | "dev": true 1540 | }, 1541 | "to-iso-string": { 1542 | "version": "0.0.2", 1543 | "resolved": "https://registry.npmjs.org/to-iso-string/-/to-iso-string-0.0.2.tgz", 1544 | "integrity": "sha1-TcGeZk38y+Jb2NtQiwDG2hWCVdE=", 1545 | "dev": true 1546 | }, 1547 | "trim-newlines": { 1548 | "version": "1.0.0", 1549 | "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", 1550 | "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", 1551 | "dev": true 1552 | }, 1553 | "type-check": { 1554 | "version": "0.3.2", 1555 | "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", 1556 | "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", 1557 | "dev": true, 1558 | "requires": { 1559 | "prelude-ls": "1.1.2" 1560 | } 1561 | }, 1562 | "typedarray": { 1563 | "version": "0.0.6", 1564 | "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", 1565 | "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", 1566 | "dev": true 1567 | }, 1568 | "user-home": { 1569 | "version": "2.0.0", 1570 | "resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz", 1571 | "integrity": "sha1-nHC/2Babwdy/SGBODwS4tJzenp8=", 1572 | "dev": true, 1573 | "requires": { 1574 | "os-homedir": "1.0.2" 1575 | } 1576 | }, 1577 | "util-deprecate": { 1578 | "version": "1.0.2", 1579 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 1580 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", 1581 | "dev": true 1582 | }, 1583 | "validate-npm-package-license": { 1584 | "version": "3.0.1", 1585 | "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", 1586 | "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", 1587 | "dev": true, 1588 | "requires": { 1589 | "spdx-correct": "1.0.2", 1590 | "spdx-expression-parse": "1.0.4" 1591 | } 1592 | }, 1593 | "wordwrap": { 1594 | "version": "1.0.0", 1595 | "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", 1596 | "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", 1597 | "dev": true 1598 | }, 1599 | "wrappy": { 1600 | "version": "1.0.2", 1601 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1602 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 1603 | "dev": true 1604 | }, 1605 | "write": { 1606 | "version": "0.2.1", 1607 | "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", 1608 | "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", 1609 | "dev": true, 1610 | "requires": { 1611 | "mkdirp": "0.5.1" 1612 | } 1613 | }, 1614 | "xtend": { 1615 | "version": "4.0.1", 1616 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", 1617 | "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", 1618 | "dev": true 1619 | } 1620 | } 1621 | } 1622 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "devtools-timeline-model", 3 | "version": "1.4.0", 4 | "description": "Parse raw trace data into the Chrome DevTools' structured profiling data models", 5 | "license": "Apache-2.0", 6 | "repository": "paulirish/devtools-timeline-model", 7 | "author": { 8 | "name": "Paul Irish", 9 | "url": "github.com/paulirish" 10 | }, 11 | "scripts": { 12 | "test": "npm run unit && npm run lint", 13 | "unit": "mocha $(find ./test -name '*.js') --timeout 10000", 14 | "lint": "eslint .", 15 | "watch": "find . -name \"*.js\" | grep -v \"node_modules\" | grep -v \"test\" | entr npm run test", 16 | "watchlint": "find . -name \"*.js\" | grep -v \"node_modules\" | grep -v \"test\" | entr npm run lint" 17 | }, 18 | "main": "index.js", 19 | "keywords": [ 20 | "devtools", 21 | "chrome", 22 | "performance", 23 | "profiling", 24 | "timeline" 25 | ], 26 | "dependencies": { 27 | "chrome-devtools-frontend": "1.0.445684", 28 | "resolve": "1.1.7" 29 | }, 30 | "devDependencies": { 31 | "eslint": "^2.4.0", 32 | "eslint-config-google": "^0.4.0", 33 | "mocha": "^2.3.3", 34 | "speedline": "0.1.2" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # devtools-timeline-model [![Build Status](https://travis-ci.org/paulirish/devtools-timeline-model.svg?branch=master)](https://travis-ci.org/paulirish/devtools-timeline-model) 2 | 3 | 4 | **Unsupported**. 5 | 6 | Now we recommend you use another library for parsing traces.. See https://github.com/jlfwong/speedscope/blob/main/src/import/chrome.ts and https://github.com/saucelabs/tracelib and https://github.com/GoogleChrome/lighthouse/tree/master/lighthouse-core/lib/tracehouse 7 | 8 | Cheers 9 | 10 | 11 | --------------------- 12 | 13 | > Parse raw trace data into the Chrome DevTools' structured profiling data models 14 | 15 | If you use something like [big-rig](https://github.com/googlechrome/big-rig) or [automated-chrome-profiling](https://github.com/paulirish/automated-chrome-profiling#timeline-recording) you may end up with raw trace data. It's pretty raw. This module will parse that stuff into something a bit more consumable, and should help you with higher level analysis. 16 | 17 | 18 | ## Install 19 | 20 | ```sh 21 | $ npm install --save devtools-timeline-model 22 | ``` 23 | [![NPM devtools-timeline-model package](https://img.shields.io/npm/v/devtools-timeline-model.svg)](https://npmjs.org/package/devtools-timeline-model) 24 | 25 | ## Usage 26 | 27 | ```js 28 | var filename = 'demo/mdn-fling.json' 29 | var events = require('fs').readFileSync(filename, 'utf8') 30 | 31 | var DevtoolsTimelineModel = require('devtools-timeline-model'); 32 | // events can be either a string of the trace data or the JSON.parse'd equivalent 33 | var model = new DevtoolsTimelineModel(events) 34 | 35 | // tracing model 36 | model.tracingModel() 37 | // timeline model, all events 38 | model.timelineModel() 39 | // interaction model, incl scroll, click, animations 40 | model.interactionModel() 41 | // frame model, incl frame durations 42 | model.frameModel() 43 | // filmstrip model, incl screenshots 44 | model.filmStripModel() 45 | 46 | // topdown tree 47 | model.topDown() 48 | // bottom up tree 49 | model.bottomUp() 50 | // bottom up tree, grouped by URL 51 | model.bottomUpGroupBy('URL') // accepts: None Category Subdomain Domain URL EventName 52 | 53 | // see example.js for API examples. 54 | ``` 55 | 56 | ![image](https://cloud.githubusercontent.com/assets/39191/13832447/7b4dffde-eb99-11e5-8f7e-f1afcf999fd6.png) 57 | 58 | These objects are huge. You'll want to explore them in a UI like [devtool](https://github.com/Jam3/devtool). 59 | ![image](https://cloud.githubusercontent.com/assets/39191/13832411/390270ec-eb99-11e5-8dc9-c647c1b62c9d.png) 60 | 61 | 62 | ## Dev 63 | 64 | ```sh 65 | npm i 66 | brew install entr 67 | gls index.js lib/*.js | entr node example.js 68 | ``` 69 | 70 | ## Sandboxing WebInspector for Node 71 | 72 | Requiring the DevTools frontend looks rather straightforward at first. (`global.WebInspector = {}`, then start `require()`ing the files, in dependency order). However, there are two problems that crop up: 73 | 74 | 1. The frontend requires ~five globals and they currently must be added to the global context to work. 75 | 2. `utilities.js` adds a number of methods to native object prototypes, such as Array, Object, and typed arrays. 76 | 77 | `devtools-timeline-model` addresses that by sandboxing the WebInspector into it's own context. Here's how it works: 78 | 79 | ##### index.js 80 | ```js 81 | // First, sandboxed contexts don't have any globals from node, so we whitelist a few we'll provide for it. 82 | var glob = { require: require, global: global, console: console, process, process, __dirname: __dirname } 83 | // We read in our script to run, and create a vm.Script object 84 | var script = new vm.Script(fs.readFileSync(__dirname + "/lib/timeline-model.js", 'utf8')) 85 | // We create a new V8 context with our globals 86 | var ctx = vm.createContext(glob) 87 | // We evaluate the `vm.Script` in the new context 88 | var output = script.runInContext(ctx) 89 | ``` 90 | ##### (sandboxed) timeline-model.js 91 | ```js 92 | // establish our sandboxed globals 93 | this.window = this.self = this.global = this 94 | 95 | // We locally eval, as the node module scope isn't appropriate for the browser-centric DevTools frontend 96 | function requireval(path){ 97 | var filesrc = fs.readFileSync(__dirname + '/node_modules/' + path, 'utf8'); 98 | eval(filesrc + '\n\n//# sourceURL=' + path); 99 | } 100 | 101 | // polyfills, then the real chrome devtools frontend 102 | requireval('../lib/api-stubs.js') 103 | requireval('chrome-devtools-frontend/front_end/common/Object.js') 104 | requireval('chrome-devtools-frontend/front_end/common/SegmentedRange.js') 105 | requireval('chrome-devtools-frontend/front_end/platform/utilities.js') 106 | requireval('chrome-devtools-frontend/front_end/sdk/Target.js') 107 | // ... 108 | ``` 109 | ##### index.js 110 | ``` 111 | // After that's all done, we pull the local `instance` variable out, to use as our proxy object 112 | this.sandbox = ctx.instance; 113 | ``` 114 | 115 | Debugging is harder, as most tools aren't used to this setup. While `devtool` doesn't work well, you can have it run `lib/devtools-timeline-model.js` directly, which is fairly succesful. The classic `node-inspector` does work pretty well with the sandboxed script, though the workflow is a little worse than `devtool`'s. 116 | 117 | 118 | 119 | ## License 120 | 121 | Apache © [Paul Irish](https://github.com/paulirish/) 122 | -------------------------------------------------------------------------------- /test/assets/grayscale.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulirish/devtools-timeline-model/373292d8e738ce505ea2626974938667637f786c/test/assets/grayscale.jpg -------------------------------------------------------------------------------- /test/speedline.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const fs = require('fs'); 4 | const assert = require('assert'); 5 | 6 | const frame = require('speedline/lib/frame'); 7 | const speedIndex = require('speedline/lib/speed-index'); 8 | 9 | const tracefilename = './test/assets/devtools-homepage-w-screenshots-trace.json'; 10 | const tracejsonfilename = './test/assets/progressive-app.json'; 11 | const ssfilename = './test/assets/grayscale.jpg'; 12 | 13 | function calculateVisualProgressFromImages(images, delay) { 14 | const baseTs = new Date().getTime(); 15 | 16 | const frames = images.map((imgPath, i) => { 17 | const imgBuff = fs.readFileSync(imgPath); 18 | return frame.create(imgBuff, baseTs + i * delay); 19 | }); 20 | 21 | return speedIndex.calculateVisualProgress(frames); 22 | } 23 | 24 | /* global describe, it */ 25 | describe('speedline compat', function() { 26 | it('extract frames from timeline should returns an array of frames', done => { 27 | frame.extractFramesFromTimeline(tracefilename).then(frames => { 28 | assert.ok(Array.isArray(frames), 'Frames is an array'); 29 | done(); 30 | }); 31 | }); 32 | 33 | it('extract frames should support json', done => { 34 | const trace = JSON.parse(fs.readFileSync(tracejsonfilename, 'utf-8')); 35 | frame.extractFramesFromTimeline(trace).then(frames => { 36 | assert.ok(Array.isArray(frames), 'Frames is an array'); 37 | done(); 38 | }); 39 | }); 40 | 41 | it('visual progress should be 100 if there is a single frame only', done => { 42 | const frames = calculateVisualProgressFromImages([ssfilename]); 43 | assert.equal(frames[0].getProgress(), 100); 44 | done(); 45 | }); 46 | }); 47 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var fs = require('fs'); 4 | const assert = require('assert'); 5 | 6 | var TimelineModel = require('../'); 7 | 8 | const traceInArrayFormatFilename = './test/assets/devtools-homepage-w-screenshots-trace.json'; 9 | const traceInObjectFormatFilename = './test/assets/trace-in-object-format.json'; 10 | const webpagetestTraceFilename = './test/assets/trace-from-webpagetest.json'; 11 | 12 | var events = fs.readFileSync(traceInArrayFormatFilename, 'utf8'); 13 | var model; 14 | 15 | /* global describe, it */ 16 | describe('Web Inspector obj', function() { 17 | it('Array native globals dont leak', () => { 18 | assert.equal(Array.prototype.peekLast, undefined); 19 | }); 20 | 21 | it('WebInspector global doesn\'t leak', () => { 22 | assert.equal('Runtime' in global, false); 23 | assert.equal('TreeElement' in global, false); 24 | assert.equal('WorkerRuntime' in global, false); 25 | assert.equal('Protocol' in global, false); 26 | }); 27 | }); 28 | 29 | 30 | describe('DevTools Timeline Model', function() { 31 | it('doesn\'t throw an exception', () => { 32 | model = new TimelineModel(events); 33 | }); 34 | 35 | it('Multiple instances don\'t conflict', () => { 36 | let model1; 37 | let model2; 38 | assert.doesNotThrow(_ => { 39 | model1 = new TimelineModel(events); 40 | model2 = new TimelineModel(events); 41 | }); 42 | const events1 = model1.timelineModel().mainThreadEvents().length; 43 | const events2 = model2.timelineModel().mainThreadEvents().length; 44 | assert.equal(events1, events2); 45 | }); 46 | 47 | it('metrics returned are expected', () => { 48 | assert.equal(model.timelineModel().mainThreadEvents().length, 7721); 49 | assert.equal(model.interactionModel().interactionRecords().length, 0); 50 | assert.equal(model.frameModel().frames().length, 16); 51 | }); 52 | 53 | it('top-down profile', () => { 54 | const leavesCount = model.topDown().children.size; 55 | // console.log([...model.topDown().children.values()].map(e => [e.id, e.totalTime.toFixed(1)])); 56 | 57 | assert.equal(leavesCount, 18); 58 | const time = model.topDown().totalTime.toFixed(2); 59 | assert.equal(time, '555.01'); 60 | }); 61 | 62 | it('bottom-up profile', () => { 63 | const leavesCount = model.bottomUp().children.size; 64 | assert.equal(leavesCount, 220); 65 | var bottomUpURL = model.bottomUpGroupBy('URL'); 66 | const topCosts = [...bottomUpURL.children.values()]; 67 | const time = topCosts[0].totalTime.toFixed(2); 68 | const url = topCosts[0].id; 69 | assert.equal(time, '76.26'); 70 | assert.equal(url, 'https://s.ytimg.com/yts/jsbin/www-embed-lightweight-vflu_2b1k/www-embed-lightweight.js'); 71 | }); 72 | 73 | it('bottom-up profile - group by eventname', () => { 74 | const bottomUpByName = model.bottomUpGroupBy('EventName'); 75 | const leavesCount = bottomUpByName.children.size; 76 | assert.equal(leavesCount, 13); 77 | const topCosts = [...bottomUpByName.children.values()]; 78 | const time = topCosts[0].selfTime.toFixed(2); 79 | const name = topCosts[0].id; 80 | assert.equal(time, '187.75'); 81 | assert.equal(name, 'Layout'); 82 | }); 83 | 84 | it('bottom-up profile - group by subdomain', () => { 85 | const bottomUpByName = model.bottomUpGroupBy('Subdomain'); 86 | const topCosts = [...bottomUpByName.children.values()]; 87 | const time = topCosts[1].selfTime.toFixed(2); 88 | const name = topCosts[1].id; 89 | assert.equal(time, '44.33'); 90 | assert.equal(name, 'developers.google.com'); 91 | }); 92 | 93 | it('frame model', () => { 94 | const frameModel = model.frameModel(); 95 | assert.equal(frameModel.frames().length, 16); 96 | }); 97 | 98 | it('film strip model', () => { 99 | const filmStrip = model.filmStripModel(); 100 | assert.equal(filmStrip.frames().length, 16); 101 | }); 102 | 103 | it('interaction model', () => { 104 | const interactionModel = model.interactionModel(); 105 | assert.equal(interactionModel.interactionRecords().length, 0); 106 | }); 107 | 108 | it('limits by startTime', () => { 109 | const bottomUpByURL = model.bottomUpGroupBy('URL', 316224076.300); 110 | const leavesCount = bottomUpByURL.children.size; 111 | assert.equal(leavesCount, 14); 112 | const topCosts = [...bottomUpByURL.children.values()]; 113 | const url = topCosts[1].id; 114 | assert.equal(url, 'https://www.google-analytics.com/analytics.js'); 115 | }); 116 | 117 | it('limits by endTime', () => { 118 | const bottomUpByURL = model.bottomUpGroupBy('URL', 0, 316223621.274); 119 | const leavesCount = bottomUpByURL.children.size; 120 | assert.equal(leavesCount, 1); 121 | const topCosts = [...bottomUpByURL.children.values()]; 122 | const url = topCosts[0].id; 123 | assert.equal(url, 'https://developers.google.com/web/tools/chrome-devtools/?hl=en'); 124 | }); 125 | }); 126 | 127 | 128 | // ideas for tests 129 | // bottom up tree returns in self desc order 130 | // top down tree returns in total desc order 131 | // no entry in trees with empty ID 132 | 133 | 134 | // https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview#heading=h.q8di1j2nawlp 135 | describe('Supports Trace Events in JSON Object format', function() { 136 | const events = fs.readFileSync(traceInObjectFormatFilename, 'utf8'); 137 | let model; 138 | 139 | it('does not throw an exception', () => { 140 | assert.doesNotThrow(_ => { 141 | model = new TimelineModel(events); 142 | }); 143 | }); 144 | 145 | it('creates correctly formatted model', () => { 146 | assert.equal(model.timelineModel().mainThreadEvents().length, 8254); 147 | assert.equal(model.interactionModel().interactionRecords().length, 0); 148 | assert.equal(model.frameModel().frames().length, 12); 149 | }); 150 | }); 151 | 152 | // WebPageTest generated trace 153 | describe('Strips initial empty object from WebPageTest trace', function() { 154 | const events = fs.readFileSync(webpagetestTraceFilename, 'utf8'); 155 | let model; 156 | 157 | it('does not throw an exception', () => { 158 | assert.doesNotThrow(_ => { 159 | model = new TimelineModel(events); 160 | }); 161 | }); 162 | 163 | it('creates correctly formatted model', () => { 164 | assert.equal(model.timelineModel().mainThreadEvents().length, 609); 165 | assert.equal(model.interactionModel().interactionRecords().length, 0); 166 | assert.equal(model.frameModel().frames().length, 0); 167 | }); 168 | 169 | }); 170 | --------------------------------------------------------------------------------