763 lines
91 KiB
JavaScript
Raw Normal View History

/**
* Copyright (c) 2016-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
'use strict';
/*eslint no-bitwise: "off"*/
/*eslint no-console-disallow: "off"*/
// TODO: future features
// put in a module.exports
// filtering / search
// pivot around frames in the middle of a stack by callers / callees
// graphing?
function StringInterner(){// eslint-disable-line no-unused-vars
var strings=[];
var ids={};
return{
intern:function internString(s){
var find=ids[s];
if(find===undefined){
var id=strings.length;
ids[s]=id;
strings.push(s);
return id;
}else{
return find;
}
},
get:function getString(id){
return strings[id];
}};
}
function StackRegistry(){// eslint-disable-line no-unused-vars
return{
root:{id:0},
nodeCount:1,
maxDepth:-1,
stackIdMap:null,
insert:function insertNode(parent,frameId){
if(this.stackIdMap!==null){
throw'stacks already flattened';
}
var node=parent[frameId];
if(node===undefined){
node={id:this.nodeCount};
this.nodeCount++;
parent[frameId]=node;
}
return node;
},
get:function getStackArray(id){
return this.stackIdMap[id];
},
flatten:function flattenStacks(){
if(this.stackIdMap!==null){
return;
}
var stackFrameCount=0;
function countStacks(tree,depth){
var leaf=true;
for(var frameId in tree){
if(frameId!=='id'){
leaf=countStacks(tree[frameId],depth+1);
}
}
if(leaf){
stackFrameCount+=depth;
}
return false;
}
countStacks(this.root,0);
console.log('size needed to store stacks: '+(stackFrameCount*4).toString()+'B');
var stackIdMap=new Array(this.nodeCount);
var stackArray=new Int32Array(stackFrameCount);
var maxStackDepth=0;
stackFrameCount=0;
function flattenStacksImpl(tree,stack){
var childStack=void 0;
maxStackDepth=Math.max(maxStackDepth,stack.length);
for(var frameId in tree){
if(frameId!=='id'){
stack.push(Number(frameId));
childStack=flattenStacksImpl(tree[frameId],stack);
stack.pop();
}
}
var id=tree.id;
if(id<0||id>=stackIdMap.length||stackIdMap[id]!==undefined){
throw'invalid stack id!';
}
if(childStack!==undefined){
// each child must have our stack as a prefix, so just use that
stackIdMap[id]=childStack.subarray(0,stack.length);
}else{
var newStack=stackArray.subarray(stackFrameCount,stackFrameCount+stack.length);
stackFrameCount+=stack.length;
for(var i=0;i<stack.length;i++){
newStack[i]=stack[i];
}
stackIdMap[id]=newStack;
}
return stackIdMap[id];
}
flattenStacksImpl(this.root,[]);
this.root=null;
this.stackIdMap=stackIdMap;
this.maxDepth=maxStackDepth;
}};
}
function AggrowData(columns){// eslint-disable-line no-unused-vars
var columnCount=columns.length;
var columnConverter=columns.map(function(c){
switch(c.type){
case'int':// stores raw value
return function(i){return i;};
case'string':// stores interned id of string
return function(s){return c.strings.intern(s);};
case'stack':// stores id of stack node
return function(s){return s.id;};
default:
throw'unknown AggrowData column type';}
});
return{
data:new Int32Array(0),
columns:columns,
rowCount:0,
rowInserter:function rowInserter(numRows){
console.log(
'increasing row data from '+(this.data.length*4).toLocaleString()+' B to '+
(this.data.length*4+numRows*columnCount*4).toLocaleString()+' B');
var newData=new Int32Array(this.data.length+numRows*columnCount);
newData.set(this.data);
var currOffset=this.data.length;
var endOffset=newData.length;
this.data=newData;
this.rowCount=newData.length/columnCount;
return{
insertRow:function insertRow(){
if(currOffset>=endOffset){
throw'tried to insert data off end of added range';
}
if(arguments.length!==columnCount){
throw'expected data for '+columnCount.toString()+' columns, got'+
arguments.length.toString()+' columns';
}
for(var i=0;i<arguments.length;i++){
newData[currOffset+i]=columnConverter[i](arguments[i]);
}
currOffset+=columnCount;
},
done:function done(){
if(currOffset!==endOffset){
throw'unfilled rows';
}
}};
}};
}
function Aggrow(aggrowData){
var columns=aggrowData.columns;
var columnCount=columns.length;
var data=aggrowData.data;
function columnIndex(columnName,columnType){
var index=columns.findIndex(function(c){return c.name===columnName&&c.type===columnType;});
if(index<0){
throw'did not find data column '+columnName+' with type '+columnType;
}
return index;
}
for(var i=0;i<columns.length;i++){
if(columns[i].type==='stack'){
columns[i].stacks.flatten();
}
}
return{
expander:new AggrowExpander(aggrowData.rowCount),
addSumAggregator:function addSumAggregator(aggregatorName,columnName){
var index=columnIndex(columnName,'int');
return this.expander.addAggregator(
aggregatorName,
function aggregateSize(indices){
var size=0;
for(var _i=0;_i<indices.length;_i++){
var row=indices[_i];
size+=data[row*columnCount+index];
}
return size;
},
function(value){return value.toLocaleString();},
function(a,b){return b-a;});
},
addCountAggregator:function addCountAggregator(aggregatorName){
return this.expander.addAggregator(
aggregatorName,
function aggregateCount(indices){
return indices.length;
},
function(value){return value.toLocaleString();},
function(a,b){return b-a;});
},
addStringExpander:function addStringExpander(expanderName,columnName){
var index=columnIndex(columnName,'string');
var strings=columns[index].strings;
return this.expander.addFieldExpander(
expanderName,
function(row){return strings.get(data[row*columnCount+index]);},
function(rowA,rowB){return data[rowA*columnCount+index]-data[rowB*columnCount+index];});
},
addNumberExpander:function addNumberExpander(expanderName,columnName){
var index=columnIndex(columnName,'int');
return this.expander.addFieldExpander(
expanderName,
function(row){return data[row*columnCount+index].toLocaleString();},
function(rowA,rowB){return data[rowA*columnCount+index]-data[rowB*columnCount+index];});
},
addPointerExpander:function addPointerExpander(expanderName,columnName){
var index=columnIndex(columnName,'int');
return this.expander.addFieldExpander(
expanderName,
function(row){return'0x'+(data[row*columnCount+index]>>>0).toString();},
function(rowA,rowB){return data[rowA*columnCount+index]-data[rowB*columnCount+index];});
},
addStackExpander:function addStackExpander(expanderName,columnName,formatter){
// TODO: options for caller/callee, pivoting
var index=columnIndex(columnName,'stack');
var stacks=columns[index].stacks;
return this.expander.addCalleeStackExpander(
expanderName,
stacks.maxDepth,
function(row){return stacks.get(data[row*columnCount+index]);},
formatter);
}};
}
function AggrowExpander(numRows){// eslint-disable-line no-unused-vars
// expander ID definitions
var FIELD_EXPANDER_ID_MIN=0x0000;
var FIELD_EXPANDER_ID_MAX=0x7fff;
var STACK_EXPANDER_ID_MIN=0x8000;
var STACK_EXPANDER_ID_MAX=0xffff;
// used for row.expander which reference state.activeExpanders (with frame index masked in)
var INVALID_ACTIVE_EXPANDER=-1;
var ACTIVE_EXPANDER_MASK=0xffff;
var ACTIVE_EXPANDER_FRAME_SHIFT=16;
// aggregator ID definitions
var AGGREGATOR_ID_MAX=0xffff;
// active aggragators can have sort order changed in the reference
var ACTIVE_AGGREGATOR_MASK=0xffff;
var ACTIVE_AGGREGATOR_ASC_BIT=0x10000;
// tree node state definitions
var NODE_EXPANDED_BIT=0x0001;// this row is expanded
var NODE_REAGGREGATE_BIT=0x0002;// children need aggregates
var NODE_REORDER_BIT=0x0004;// children need to be sorted
var NODE_REPOSITION_BIT=0x0008;// children need position
var NODE_INDENT_SHIFT=16;
function calleeFrameIdGetter(stack,depth){
return stack[depth];
}
function callerFrameIdGetter(stack,depth){
return stack[stack.length-depth-1];
}
function createStackComparers(stackGetter,frameIdGetter,maxStackDepth){
var comparers=new Array(maxStackDepth);var _loop=function _loop(
depth){
var captureDepth=depth;// NB: to capture depth per loop iteration
comparers[depth]=function calleeStackComparer(rowA,rowB){
var a=stackGetter(rowA);
var b=stackGetter(rowB);
// NB: we put the stacks that are too short at the top,
// so they can be grouped into the '<exclusive>' bucket
if(a.length<=captureDepth&&b.length<=captureDepth){
return 0;
}else if(a.length<=captureDepth){
return-1;
}else if(b.length<=captureDepth){
return 1;
}
return frameIdGetter(a,captureDepth)-frameIdGetter(b,captureDepth);
};};for(var depth=0;depth<maxStackDepth;depth++){_loop(depth);
}
return comparers;
}
function createTreeNode(parent,label,indices,expander){
var indent=parent===null?0:(parent.state>>>NODE_INDENT_SHIFT)+1;
var state=NODE_REPOSITION_BIT|
NODE_REAGGREGATE_BIT|
NODE_REORDER_BIT|
indent<<NODE_INDENT_SHIFT;
return{
parent:parent,// null if root
children:null,// array of children nodes
label:label,// string to show in UI
indices:indices,// row indices under this node
aggregates:null,// result of aggregate on indices
expander:expander,// index into state.activeExpanders
top:0,// y position of top row (in rows)
height:1,// number of rows including children
state:state};
}
function noSortOrder(a,b){
return 0;
}
var indices=new Int32Array(numRows);
for(var i=0;i<numRows;i++){
indices[i]=i;
}
var state={
fieldExpanders:[],// tree expanders that expand on simple values
stackExpanders:[],// tree expanders that expand stacks
activeExpanders:[],// index into field or stack expanders, hierarchy of tree
aggregators:[],// all available aggregators, might not be used
activeAggregators:[],// index into aggregators, to actually compute
sorter:noSortOrder,// compare function that uses sortOrder to sort row.children
root:createTreeNode(null,'<root>',indices,INVALID_ACTIVE_EXPANDER)};
function evaluateAggregate(row){
var activeAggregators=state.activeAggregators;
var aggregates=new Array(activeAggregators.length);
for(var j=0;j<activeAggregators.length;j++){
var aggregator=state.aggregators[activeAggregators[j]];
aggregates[j]=aggregator.aggregator(row.indices);
}
row.aggregates=aggregates;
row.state|=NODE_REAGGREGATE_BIT;
}
function evaluateAggregates(row){
if((row.state&NODE_EXPANDED_BIT)!==0){
var children=row.children;
for(var _i2=0;_i2<children.length;_i2++){
evaluateAggregate(children[_i2]);
}
row.state|=NODE_REORDER_BIT;
}
row.state^=NODE_REAGGREGATE_BIT;
}
function evaluateOrder(row){
if((row.state&NODE_EXPANDED_BIT)!==0){
var children=row.children;
for(var _i3=0;_i3<children.length;_i3++){
var child=children[_i3];
child.state|=NODE_REORDER_BIT;
}
children.sort(state.sorter);
row.state|=NODE_REPOSITION_BIT;
}
row.state^=NODE_REORDER_BIT;
}
function evaluatePosition(row){
if((row.state&NODE_EXPANDED_BIT)!==0){
var children=row.children;
var childTop=row.top+1;
for(var _i4=0;_i4<children.length;_i4++){
var child=children[_i4];
if(child.top!==childTop){
child.top=childTop;
child.state|=NODE_REPOSITION_BIT;
}
childTop+=child.height;
}
}
row.state^=NODE_REPOSITION_BIT;
}
function getRowsImpl(row,top,height,result){
if((row.state&NODE_REAGGREGATE_BIT)!==0){
evaluateAggregates(row);
}
if((row.state&NODE_REORDER_BIT)!==0){
evaluateOrder(row);
}
if((row.state&NODE_REPOSITION_BIT)!==0){
evaluatePosition(row);
}
if(row.top>=top&&row.top<top+height){
if(result[row.top-top]!=null){
throw'getRows put more than one row at position '+row.top+' into result';
}
result[row.top-top]=row;
}
if((row.state&NODE_EXPANDED_BIT)!==0){
var children=row.children;
for(var _i5=0;_i5<children.length;_i5++){
var child=children[_i5];
if(child.top<top+height&&top<child.top+child.height){
getRowsImpl(child,top,height,result);
}
}
}
}
function updateHeight(row,heightChange){
while(row!==null){
row.height+=heightChange;
row.state|=NODE_REPOSITION_BIT;
row=row.parent;
}
}
function addChildrenWithFieldExpander(row,expander,nextActiveIndex){
var rowIndices=row.indices;
var comparer=expander.comparer;
rowIndices.sort(comparer);
var begin=0;
var end=1;
row.children=[];
while(end<rowIndices.length){
if(comparer(rowIndices[begin],rowIndices[end])!==0){
row.children.push(createTreeNode(
row,
expander.name+': '+expander.formatter(rowIndices[begin]),
rowIndices.subarray(begin,end),
nextActiveIndex));
begin=end;
}
end++;
}
row.children.push(createTreeNode(
row,
expander.name+': '+expander.formatter(rowIndices[begin]),
rowIndices.subarray(begin,end),
nextActiveIndex));
}
function addChildrenWithStackExpander(row,expander,activeIndex,depth,nextActiveIndex){
var rowIndices=row.indices;
var stackGetter=expander.stackGetter;
var frameIdGetter=expander.frameIdGetter;
var frameGetter=expander.frameGetter;
var comparer=expander.comparers[depth];
var expandNextFrame=activeIndex|depth+1<<ACTIVE_EXPANDER_FRAME_SHIFT;
rowIndices.sort(comparer);
var columnName='';
if(depth===0){
columnName=expander.name+': ';
}
// put all the too-short stacks under <exclusive>
var begin=0;
var beginStack=null;
row.children=[];
while(begin<rowIndices.length){
beginStack=stackGetter(rowIndices[begin]);
if(beginStack.length>depth){
break;
}
begin++;
}
if(begin>0){
row.children.push(createTreeNode(
row,
columnName+'<exclusive>',
rowIndices.subarray(0,begin),
nextActiveIndex));
}
// aggregate the rest under frames
if(begin<rowIndices.length){
var end=begin+1;
while(end<rowIndices.length){
var endStack=stackGetter(rowIndices[end]);
if(frameIdGetter(beginStack,depth)!==frameIdGetter(endStack,depth)){
row.children.push(createTreeNode(
row,
columnName+frameGetter(frameIdGetter(beginStack,depth)),
rowIndices.subarray(begin,end),
expandNextFrame));
begin=end;
beginStack=endStack;
}
end++;
}
row.children.push(createTreeNode(
row,
columnName+frameGetter(frameIdGetter(beginStack,depth)),
rowIndices.subarray(begin,end),
expandNextFrame));
}
}
function contractRow(row){
if((row.state&NODE_EXPANDED_BIT)===0){
throw'can not contract row, already contracted';
}
row.state^=NODE_EXPANDED_BIT;
var heightChange=1-row.height;
updateHeight(row,heightChange);
}
function pruneExpanders(row,oldExpander,newExpander){
row.state|=NODE_REPOSITION_BIT;
if(row.expander===oldExpander){
row.state|=NODE_REAGGREGATE_BIT|NODE_REORDER_BIT|NODE_REPOSITION_BIT;
if((row.state&NODE_EXPANDED_BIT)!==0){
contractRow(row);
}
row.children=null;
row.expander=newExpander;
}else{
row.state|=NODE_REPOSITION_BIT;
var children=row.children;
if(children!=null){
for(var _i6=0;_i6<children.length;_i6++){
var child=children[_i6];
pruneExpanders(child,oldExpander,newExpander);
}
}
}
}
return{
addFieldExpander:function addFieldExpander(name,formatter,comparer){
if(FIELD_EXPANDER_ID_MIN+state.fieldExpanders.length>=FIELD_EXPANDER_ID_MAX){
throw'too many field expanders!';
}
state.fieldExpanders.push({
name:name,// name for column
formatter:formatter,// row index -> display string
comparer:comparer});
return FIELD_EXPANDER_ID_MIN+state.fieldExpanders.length-1;
},
addCalleeStackExpander:function addCalleeStackExpander(name,maxStackDepth,stackGetter,frameGetter){
if(STACK_EXPANDER_ID_MIN+state.fieldExpanders.length>=STACK_EXPANDER_ID_MAX){
throw'too many stack expanders!';
}
state.stackExpanders.push({
name:name,// name for column
stackGetter:stackGetter,// row index -> stack array
comparers:createStackComparers(stackGetter,calleeFrameIdGetter,maxStackDepth),// depth -> comparer
frameIdGetter:calleeFrameIdGetter,// (stack, depth) -> string id
frameGetter:frameGetter});
return STACK_EXPANDER_ID_MIN+state.stackExpanders.length-1;
},
addCallerStackExpander:function addCallerStackExpander(name,maxStackDepth,stackGetter,frameGetter){
if(STACK_EXPANDER_ID_MIN+state.fieldExpanders.length>=STACK_EXPANDER_ID_MAX){
throw'too many stack expanders!';
}
state.stackExpanders.push({
name:name,
stackGetter:stackGetter,
comparers:createStackComparers(stackGetter,callerFrameIdGetter,maxStackDepth),
frameIdGetter:callerFrameIdGetter,
frameGetter:frameGetter});
return STACK_EXPANDER_ID_MIN+state.stackExpanders.length-1;
},
getExpanders:function getExpanders(){
var expanders=[];
for(var _i7=0;_i7<state.fieldExpanders.length;_i7++){
expanders.push(FIELD_EXPANDER_ID_MIN+_i7);
}
for(var _i8=0;_i8<state.stackExpanders.length;_i8++){
expanders.push(STACK_EXPANDER_ID_MIN+_i8);
}
return expanders;
},
getExpanderName:function getExpanderName(id){
if(id>=FIELD_EXPANDER_ID_MIN&&id<=FIELD_EXPANDER_ID_MAX){
return state.fieldExpanders[id-FIELD_EXPANDER_ID_MIN].name;
}else if(id>=STACK_EXPANDER_ID_MIN&&id<=STACK_EXPANDER_ID_MAX){
return state.stackExpanders[id-STACK_EXPANDER_ID_MIN].name;
}
throw'Unknown expander ID '+id.toString();
},
setActiveExpanders:function setActiveExpanders(ids){
for(var _i9=0;_i9<ids.length;_i9++){
var id=ids[_i9];
if(id>=FIELD_EXPANDER_ID_MIN&&id<=FIELD_EXPANDER_ID_MAX){
if(id-FIELD_EXPANDER_ID_MIN>=state.fieldExpanders.length){
throw'field expander for id '+id.toString()+' does not exist!';
}
}else if(id>=STACK_EXPANDER_ID_MIN&&id<=STACK_EXPANDER_ID_MAX){
if(id-STACK_EXPANDER_ID_MIN>=state.stackExpanders.length){
throw'stack expander for id '+id.toString()+' does not exist!';
}
}
}
for(var _i10=0;_i10<ids.length;_i10++){
if(state.activeExpanders.length<=_i10){
pruneExpanders(state.root,INVALID_ACTIVE_EXPANDER,_i10);
break;
}else if(ids[_i10]!==state.activeExpanders[_i10]){
pruneExpanders(state.root,_i10,_i10);
break;
}
}
// TODO: if ids is prefix of activeExpanders, we need to make an expander invalid
state.activeExpanders=ids.slice();
},
getActiveExpanders:function getActiveExpanders(){
return state.activeExpanders.slice();
},
addAggregator:function addAggregator(name,aggregator,formatter,sorter){
if(state.aggregators.length>=AGGREGATOR_ID_MAX){
throw'too many aggregators!';
}
state.aggregators.push({
name:name,// name for column
aggregator:aggregator,// index array -> aggregate value
formatter:formatter,// aggregate value -> display string
sorter:sorter});
return state.aggregators.length-1;
},
getAggregators:function getAggregators(){
var aggregators=[];
for(var _i11=0;_i11<state.aggregators.length;_i11++){
aggregators.push(_i11);
}
return aggregators;
},
getAggregatorName:function getAggregatorName(id){
return state.aggregators[id&ACTIVE_AGGREGATOR_MASK].name;
},
setActiveAggregators:function setActiveAggregators(ids){
for(var _i12=0;_i12<ids.length;_i12++){
var id=ids[_i12]&ACTIVE_AGGREGATOR_MASK;
if(id<0||id>state.aggregators.length){
throw'aggregator id '+id.toString()+' not valid';
}
}
state.activeAggregators=ids.slice();
// NB: evaluate root here because dirty bit is for children
// so someone has to start with root, and it might as well be right away
evaluateAggregate(state.root);
var sorter=noSortOrder;var _loop2=function _loop2(
_i13){
var ascending=(ids[_i13]&ACTIVE_AGGREGATOR_ASC_BIT)!==0;
var id=ids[_i13]&ACTIVE_AGGREGATOR_MASK;
var comparer=state.aggregators[id].sorter;
var captureSorter=sorter;
var captureIndex=_i13;
sorter=function sorter(a,b){
var c=comparer(a.aggregates[captureIndex],b.aggregates[captureIndex]);
if(c===0){
return captureSorter(a,b);
}
return ascending?-c:c;
};};for(var _i13=ids.length-1;_i13>=0;_i13--){_loop2(_i13);
}
state.sorter=sorter;
state.root.state|=NODE_REORDER_BIT;
},
getActiveAggregators:function getActiveAggregators(){
return state.activeAggregators.slice();
},
getRows:function getRows(top,height){
var result=new Array(height);
for(var _i14=0;_i14<height;_i14++){
result[_i14]=null;
}
getRowsImpl(state.root,top,height,result);
return result;
},
getRowLabel:function getRowLabel(row){
return row.label;
},
getRowIndent:function getRowIndent(row){
return row.state>>>NODE_INDENT_SHIFT;
},
getRowAggregate:function getRowAggregate(row,index){
var aggregator=state.aggregators[state.activeAggregators[index]];
return aggregator.formatter(row.aggregates[index]);
},
getHeight:function getHeight(){
return state.root.height;
},
canExpand:function canExpand(row){
return(row.state&NODE_EXPANDED_BIT)===0&&row.expander!==INVALID_ACTIVE_EXPANDER;
},
canContract:function canContract(row){
return(row.state&NODE_EXPANDED_BIT)!==0;
},
expand:function expand(row){
if((row.state&NODE_EXPANDED_BIT)!==0){
throw'can not expand row, already expanded';
}
if(row.height!==1){
throw'unexpanded row has height '+row.height.toString()+' != 1';
}
if(row.children===null){// first expand, generate children
var activeIndex=row.expander&ACTIVE_EXPANDER_MASK;
var nextActiveIndex=activeIndex+1;// NB: if next is stack, frame is 0
if(nextActiveIndex>=state.activeExpanders.length){
nextActiveIndex=INVALID_ACTIVE_EXPANDER;
}
if(activeIndex>=state.activeExpanders.length){
throw'invalid active expander index '+activeIndex.toString();
}
var exId=state.activeExpanders[activeIndex];
if(exId>=FIELD_EXPANDER_ID_MIN&&
exId<FIELD_EXPANDER_ID_MIN+state.fieldExpanders.length){
var expander=state.fieldExpanders[exId-FIELD_EXPANDER_ID_MIN];
addChildrenWithFieldExpander(row,expander,nextActiveIndex);
}else if(exId>=STACK_EXPANDER_ID_MIN&&
exId<STACK_EXPANDER_ID_MIN+state.stackExpanders.length){
var depth=row.expander>>>ACTIVE_EXPANDER_FRAME_SHIFT;
var _expander=state.stackExpanders[exId-STACK_EXPANDER_ID_MIN];
addChildrenWithStackExpander(row,_expander,activeIndex,depth,nextActiveIndex);
}else{
throw'state.activeIndex '+activeIndex.toString()+
' has invalid expander'+exId.toString();
}
}
row.state|=NODE_EXPANDED_BIT|
NODE_REAGGREGATE_BIT|NODE_REORDER_BIT|NODE_REPOSITION_BIT;
var heightChange=0;
for(var _i15=0;_i15<row.children.length;_i15++){
heightChange+=row.children[_i15].height;
}
updateHeight(row,heightChange);
// if children only contains one node, then expand it as well
if(row.children.length===1&&this.canExpand(row.children[0])){
this.expand(row.children[0]);
}
},
contract:function contract(row){
contractRow(row);
}};
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9hZ2dyb3cuanMiXSwibmFtZXMiOlsiU3RyaW5nSW50ZXJuZXIiLCJzdHJpbmdzIiwiaWRzIiwiaW50ZXJuIiwiaW50ZXJuU3RyaW5nIiwicyIsImZpbmQiLCJ1bmRlZmluZWQiLCJpZCIsImxlbmd0aCIsInB1c2giLCJnZXQiLCJnZXRTdHJpbmciLCJTdGFja1JlZ2lzdHJ5Iiwicm9vdCIsIm5vZGVDb3VudCIsIm1heERlcHRoIiwic3RhY2tJZE1hcCIsImluc2VydCIsImluc2VydE5vZGUiLCJwYXJlbnQiLCJmcmFtZUlkIiwibm9kZSIsImdldFN0YWNrQXJyYXkiLCJmbGF0dGVuIiwiZmxhdHRlblN0YWNrcyIsInN0YWNrRnJhbWVDb3VudCIsImNvdW50U3RhY2tzIiwidHJlZSIsImRlcHRoIiwibGVhZiIsImNvbnNvbGUiLCJsb2ciLCJ0b1N0cmluZyIsIkFycmF5Iiwic3RhY2tBcnJheSIsIkludDMyQXJyYXkiLCJtYXhTdGFja0RlcHRoIiwiZmxhdHRlblN0YWNrc0ltcGwiLCJzdGFjayIsImNoaWxkU3RhY2siLCJNYXRoIiwibWF4IiwiTnVtYmVyIiwicG9wIiwic3ViYXJyYXkiLCJuZXdTdGFjayIsImkiLCJBZ2dyb3dEYXRhIiwiY29sdW1ucyIsImNvbHVtbkNvdW50IiwiY29sdW1uQ29udmVydGVyIiwibWFwIiwiYyIsInR5cGUiLCJkYXRhIiwicm93Q291bnQiLCJyb3dJbnNlcnRlciIsIm51bVJvd3MiLCJ0b0xvY2FsZVN0cmluZyIsIm5ld0RhdGEiLCJzZXQiLCJjdXJyT2Zmc2V0IiwiZW5kT2Zmc2V0IiwiaW5zZXJ0Um93IiwiYXJndW1lbnRzIiwiZG9uZSIsIkFnZ3JvdyIsImFnZ3Jvd0RhdGEiLCJjb2x1bW5JbmRleCIsImNvbHVtbk5hbWUiLCJjb2x1bW5UeXBlIiwiaW5kZXgiLCJmaW5kSW5kZXgiLCJuYW1lIiwic3RhY2tzIiwiZXhwYW5kZXIiLCJBZ2dyb3dFeHBhbmRlciIsImFkZFN1bUFnZ3JlZ2F0b3IiLCJhZ2dyZWdhdG9yTmFtZSIsImFkZEFnZ3JlZ2F0b3IiLCJhZ2dyZWdhdGVTaXplIiwiaW5kaWNlcyIsInNpemUiLCJyb3ciLCJ2YWx1ZSIsImEiLCJiIiwiYWRkQ291bnRBZ2dyZWdhdG9yIiwiYWdncmVnYXRlQ291bnQiLCJhZGRTdHJpbmdFeHBhbmRlciIsImV4cGFuZGVyTmFtZSIsImFkZEZpZWxkRXhwYW5kZXIiLCJyb3dBIiwicm93QiIsImFkZE51bWJlckV4cGFuZGVyIiwiYWRkUG9pbnRlckV4cGFuZGVyIiwiYWRkU3RhY2tFeHBhbmRlciIsImZvcm1hdHRlciIsImFkZENhbGxlZVN0YWNrRXhwYW5kZXIiLCJGSUVMRF9FWFBBTkRFUl9JRF9NSU4iLCJGSUVMRF9FWFBBTkRFUl9JRF9NQVgiLCJTVEFDS19FWFBBTkRFUl9JRF9NSU4iLCJTVEFDS19FWFBBTkRFUl9JRF9NQVgiLCJJTlZBTElEX0FDVElWRV9FWFBBTkRFUiIsIkFDVElWRV9FWFBBTkRFUl9NQVNLIiwiQUNUSVZFX0VYUEFOREVSX0ZSQU1FX1NISUZUIiwiQUdHUkVHQVRPUl9JRF9NQVgiLCJBQ1RJVkVfQUdHUkVHQVRPUl9NQVNLIiwiQUNUSVZFX0FHR1JFR0FUT1JfQVNDX0JJVCIsIk5PREVfRVhQQU5ERURfQklUIiwiTk9ERV9SRUFHR1JFR0FURV9CSVQiLCJOT0RFX1JFT1JERVJfQklUIiwiTk9ERV9SRVBPU0lUSU9OX0JJVCIsIk5PREVfSU5ERU5UX1NISUZUIiwiY2FsbGVlRnJhbWVJZEdldHRlciIsImNhbGxlckZyYW1lSWRHZXR0ZXIiLCJjcmVhdGVTdGFja0NvbXBhcmVycyIsInN0YWNrR2V0dGVyIiwiZnJhbWVJZEdldHRlciIsImNvbXBhcmVycyIsImNhcHR1cmVEZXB0aCIsImNhbGxlZVN0YWNrQ29tcGFyZXIiLCJjcmVhdGVUcmVlTm9kZSIsImxhYmVsIiwiaW5kZW50Iiwic3RhdGUiLCJjaGlsZHJlbiIsImFnZ3JlZ2F0ZXMiLCJ0b3AiLCJoZWlnaHQiLCJub1NvcnRPcmRlciIsImZpZWxkRXhwYW5kZXJzIiwic3RhY2tFeHBhbmRlcnMiLCJhY3RpdmVFeHBhbmRlcnMiLCJhZ2dyZWdhdG9ycyIsImFjdGl2ZUFnZ3JlZ2F0b3JzIiwic29ydGVyIiwiZXZhbHVhdGVBZ2dyZWdhdGUiLCJqIiwiYWdncmVnYXRvciIsImV2YWx1YXRlQWdncmVnYXRlcyIsImV2YWx1YXRlT3JkZXIiLCJjaGlsZCIsInNvcnQiLCJldmFsdWF0ZVBvc2l0aW9uIiwiY2hpbGRUb3AiLCJnZXRSb3dzSW1wbCIsInJlc3VsdCIsInVwZGF0ZUhlaWdodCIsImhlaWdodENoYW5nZSIsImFkZENoaWxkcmVuV2l0aEZpZWxkRXhwYW5kZXIiLCJuZXh0QWN0aXZlSW5kZXgiLCJyb3dJbmRpY2VzIiwiY29tcGFyZXIiLCJiZWdpbiIsImVuZCIsImFkZENoaWxkcmVuV2l0aFN0YWNrRXhwYW5kZXIiLCJhY3RpdmVJbmRleCIsImZyYW1lR2V0dGVyIiwiZXhwYW5kTmV4dEZyYW1lIiwiYmVnaW5TdGFjayIsImVuZFN0YWNrIiwiY29udHJhY3RSb3ciLCJwcnVuZUV4cGFuZGVycyIsIm9sZEV4cGFuZGVyIiwibmV3RXhwYW5kZXIiLCJhZGRDYWxsZXJTdGFja0V4cGFuZGVyIiwiZ2V0RXhwYW5kZXJzIiwiZXhwYW5kZXJzIiwiZ2V0RXhwYW5kZXJOYW1lIiwic2V0QWN0aXZlRXhwYW5kZXJzIiwic2xpY2UiLCJnZXRBY3RpdmVFeHBhbmRlcnMiLCJnZXRBZ2dyZWdhdG9ycyIsImdldEFnZ3JlZ2F0b3JOYW1lIiwic2V0QWN0aXZlQWdncmVnYXRvcnMiLCJhc2NlbmRpbmciLCJjYXB0dXJlU29ydGVyIiwiY2FwdHVyZUluZGV4IiwiZ2V0QWN0aXZlQWdncmVnYXRvcnMiLCJnZXRSb3dzIiwiZ2V0Um93TGFiZWwiLCJnZXRSb3dJbmRlbnQiLCJnZXRSb3dBZ2dyZWdhdGUiLCJnZXRIZWlnaHQiLCJjYW5FeHBhbmQiLCJjYW5Db250cmFjdCIsImV4cGFuZCIsImV4SWQiLCJjb250cmFjdCJdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7O0FBUUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsUUFBU0EsZUFBVCxFQUEwQixDQUFFO0FBQzFCLEdBQU1DLFNBQVUsRUFBaEI7QUFDQSxHQUFNQyxLQUFNLEVBQVo7QUFDQSxNQUFPO0FBQ0xDLE9BQVEsUUFBU0MsYUFBVCxDQUFzQkMsQ0FBdEIsQ0FBeUI7QUFDL0IsR0FBTUMsTUFBT0osSUFBSUcsQ0FBSixDQUFiO0FBQ0EsR0FBSUMsT0FBU0MsU0FBYixDQUF3QjtBQUN0QixHQUFNQyxJQUFLUCxRQUFRUSxNQUFuQjtBQUNBUCxJQUFJRyxDQUFKLEVBQVNHLEVBQVQ7QUFDQVAsUUFBUVMsSUFBUixDQUFhTCxDQUFiO0FBQ0EsTUFBT0csR0FBUDtBQUNELENBTEQsSUFLTztBQUNML
// @generated