├── .gitignore ├── README.md ├── css └── flamegraph.css ├── inc ├── class-qm-collector.php └── class-qm-output-html.php ├── js └── d3-flame-graph │ ├── LICENSE │ ├── bower.json │ ├── bower_components │ ├── d3-tip │ │ ├── .bower.json │ │ ├── LICENSE │ │ ├── README.md │ │ ├── bower.json │ │ ├── index.js │ │ └── package.json │ ├── d3 │ │ ├── .bower.json │ │ ├── LICENSE │ │ ├── README.md │ │ ├── bower.json │ │ ├── d3.js │ │ └── d3.min.js │ └── lodash │ │ ├── .bower.json │ │ ├── LICENSE │ │ ├── bower.json │ │ ├── lodash.js │ │ └── lodash.min.js │ └── src │ ├── d3.flameGraph.css │ └── d3.flameGraph.js └── query-monitor-flamegraph.php /.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/humanmade/query-monitor-flamegraph/bae55d3a12f9648ac9a15daf7ab45c92b9451085/.gitignore -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 9 | 10 | 11 | 14 | 17 | 18 |
4 | Query Monitor Flamegraph
5 | This Query Monitor extension will add profiling framegraphs to Query Monitor via the xhprof PHP extension. 6 |
8 |
12 | A Human Made project. Maintained by @joehoyle. 13 | 15 | 16 |
19 | 20 | ![](https://cloud.githubusercontent.com/assets/161683/18526915/87445e9c-7a90-11e6-8d87-3624c3268a1f.gif) 21 | 22 | ## Install Instructions 23 | 24 | 1. Have the [Query Monitor](https://github.com/johnbillion/query-monitor) plugin installed and activated. 25 | 1. Have the [xhprof](https://pecl.php.net/package/xhprof) PHP extension installed. 26 | 1. Install this plugin :) 27 | 1. Add a call to `xhprof_sample_enable();` to your `wp-config.php` 28 | 29 | ## Versions of XHProf 30 | 31 | Unfortunately XHProf is not actively maintained and has some shortcomings. Flamegraph makes use of the `xhprof_sample_enable()` function which by is hardcoded to 100ms intervals with the official XHProf extension. There's several forks and updates to XHProf, refer to the table below: 32 | 33 | |Project|Compatible|Notes| 34 | |---|---|---| 35 | |[XHProf Official](https://pecl.php.net/package/xhprof)|yes|Note: Doesn't support PHP 7. Is restricted to 100ms interval sampling, making it useless for the most part.| 36 | |[XHProf with configurable sampling](https://github.com/phacility/xhprof/pull/80)|yes|Note: Doesn't support PHP 7. Best solution! However, you'll need to build from source.| 37 | |[Tideways](https://tideways.io/profiler/xhprof-for-php7-php5.6)|no|Tideways is an XHProf fork, however doesn't support `*_sample_enabled`. See https://github.com/tideways/php-profiler-extension/issues/26.| 38 | |[XHProf PHP7 fork](https://github.com/RustJason/xhprof/tree/php7)|no|Doesn't support `xhprof_sample_enabled`| 39 | 40 | If you know of any other XHProf forks or compatible output libraries, be sure to let me know! 41 | -------------------------------------------------------------------------------- /css/flamegraph.css: -------------------------------------------------------------------------------- 1 | .timestack-flamegraph { 2 | min-height: 400px; 3 | position: relative; 4 | } 5 | 6 | .timestack-flamegraph > ul.timestack-split-timeline { 7 | position: absolute; 8 | bottom: 0; 9 | left: 0; 10 | right: 0; 11 | } 12 | 13 | ul.timestack-split-timeline { 14 | list-style: none; 15 | margin: 0; 16 | padding: 0 !important; 17 | position: relative; 18 | height: 20px; 19 | margin-top: -20px !important; 20 | } 21 | 22 | ul.timestack-split-timeline > li { 23 | float: left; 24 | display: block; 25 | height: 20px; 26 | box-sizing: border-box; 27 | position: relative; 28 | /*border-right: 1px solid rgba(0,0,0,.3);*/ 29 | border-radius: 2px; 30 | position: relative; 31 | } 32 | 33 | ul.timestack-split-timeline > li:after { 34 | display: block; 35 | position: absolute; 36 | top: 0; 37 | left: 0; 38 | bottom: 0; 39 | right: 0; 40 | content: attr(data-name); 41 | overflow: hidden; 42 | padding: 1px 4px; 43 | opacity: .3; 44 | font-weight: bold; 45 | font-size: 10px; 46 | } 47 | -------------------------------------------------------------------------------- /inc/class-qm-collector.php: -------------------------------------------------------------------------------- 1 | data = $this->folded_to_hierarchical( $stack ); 43 | } 44 | 45 | protected function folded_to_hierarchical( $stack ) { 46 | 47 | $nodes = array( (object) array( 48 | 'name' => 'main()', 49 | 'value' => 1, 50 | 'children' => [], 51 | ) ); 52 | 53 | foreach ( $stack as $time => $call_stack ) { 54 | $call_stack = explode( '==>', $call_stack ); 55 | 56 | 57 | $nodes = $this->add_children_to_nodes( $nodes, $call_stack ); 58 | } 59 | 60 | return $nodes; 61 | } 62 | 63 | /** 64 | * Accepts [ Node, Node ], [ main, wp-settings, sleep ] 65 | */ 66 | protected function add_children_to_nodes( $nodes, $children ) { 67 | $last_node = $nodes ? $nodes[ count( $nodes ) - 1 ] : null; 68 | $this_child = $children[0]; 69 | $time = (int) ini_get( 'xhprof.sampling_interval' ); 70 | 71 | if ( ! $time ) { 72 | $time = 100000; 73 | } 74 | if ( $last_node && $last_node->name === $this_child ) { 75 | $node = $last_node; 76 | $node->value += ( $time / 1000 ); 77 | } else { 78 | $nodes[] = $node = (object) array( 79 | 'name' => $this_child, 80 | 'value' => $time / 1000, 81 | 'children' => array(), 82 | ); 83 | } 84 | if ( count( $children ) > 1 ) { 85 | $node->children = $this->add_children_to_nodes( $node->children, array_slice( $children, 1 ) ); 86 | } 87 | 88 | return $nodes; 89 | 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /inc/class-qm-output-html.php: -------------------------------------------------------------------------------- 1 | 34 | 35 |
36 |
37 | 38 |
39 | 40 | 45 | 68 |
69 | " 7 | ], 8 | "description": "A d3.js library to produce flame graphs.", 9 | "main": "src/d3.flame.js", 10 | "keywords": [ 11 | "flame", 12 | "graph", 13 | "flamegraph", 14 | "performance", 15 | "d3", 16 | "d3js" 17 | ], 18 | "license": "Apache-2.0", 19 | "ignore": [ 20 | "**/.*", 21 | "node_modules", 22 | "bower_components", 23 | "test", 24 | "tests" 25 | ], 26 | "dependencies": { 27 | "d3": "~3.5.5", 28 | "d3-tip": "~0.6.7", 29 | "lodash": "~3.10.1" 30 | }, 31 | "resolutions": { 32 | "d3": "3.5.5" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /js/d3-flame-graph/bower_components/d3-tip/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "d3-tip", 3 | "version": "0.6.8", 4 | "main": "index.js", 5 | "ignore": [ 6 | "**/.*", 7 | "node_modules", 8 | "components", 9 | "bower_components", 10 | "examples", 11 | "Makefile", 12 | "docs" 13 | ], 14 | "dependencies": { 15 | "d3": "^3.5.5" 16 | }, 17 | "homepage": "https://github.com/Caged/d3-tip", 18 | "_release": "0.6.8", 19 | "_resolution": { 20 | "type": "version", 21 | "tag": "v0.6.8", 22 | "commit": "92bd167db0c3c24e895e7405376630be79b53a0b" 23 | }, 24 | "_source": "https://github.com/Caged/d3-tip.git", 25 | "_target": "~0.6.7", 26 | "_originalSource": "d3-tip" 27 | } -------------------------------------------------------------------------------- /js/d3-flame-graph/bower_components/d3-tip/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2013 Justin Palmer 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /js/d3-flame-graph/bower_components/d3-tip/README.md: -------------------------------------------------------------------------------- 1 | # d3.tip: Tooltips for d3.js visualizations 2 | 3 | [![](https://github-images.s3.amazonaws.com/skitch/Screen_Shot_2013-04-08_at_11.40.10_AM-20130408-114054.png)](http://bl.ocks.org/Caged/6476579) 4 | 5 | * [See a live demo](http://bl.ocks.org/Caged/6476579) 6 | * [Example code](/examples) 7 | 8 | ### API Docs 9 | See the [API Documentation](docs/index.md) 10 | 11 | ### Download Latest Version 12 | * [Development Version](https://raw.github.com/Caged/d3-tip/master/index.js) : **6kb** / **~2kb gzipped** 13 | 14 | ### Install with Bower 15 | ``` 16 | bower install d3-tip 17 | ``` 18 | 19 | ### Quick Usage 20 | ```javascript 21 | /* Initialize tooltip */ 22 | tip = d3.tip().attr('class', 'd3-tip').html(function(d) { return d; }); 23 | 24 | /* Invoke the tip in the context of your visualization */ 25 | vis.call(tip) 26 | 27 | vis.selectAll('rect') 28 | .data(data) 29 | .enter().append('rect') 30 | .attr('width', function() { return x.rangeBand() }) 31 | .attr('height', function(d) { return h - y(d) }) 32 | .attr('y', function(d) { return y(d) }) 33 | .attr('x', function(d, i) { return x(i) }) 34 | .on('mouseover', tip.show) 35 | .on('mouseout', tip.hide) 36 | ``` 37 | 38 | If you want basic styling, you can include `example-styles.css` using a service like 39 | rawgithub.com. 40 | 41 | ```html 42 | 43 | ``` 44 | -------------------------------------------------------------------------------- /js/d3-flame-graph/bower_components/d3-tip/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "d3-tip", 3 | "version": "0.6.8", 4 | "main": "index.js", 5 | "ignore": [ 6 | "**/.*", 7 | "node_modules", 8 | "components", 9 | "bower_components", 10 | "examples", 11 | "Makefile", 12 | "docs" 13 | ], 14 | "dependencies": { 15 | "d3": "^3.5.5" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /js/d3-flame-graph/bower_components/d3-tip/index.js: -------------------------------------------------------------------------------- 1 | // d3.tip 2 | // Copyright (c) 2013 Justin Palmer 3 | // 4 | // Tooltips for d3.js SVG visualizations 5 | 6 | (function (root, factory) { 7 | if (typeof define === 'function' && define.amd) { 8 | // AMD. Register as an anonymous module with d3 as a dependency. 9 | define(['d3'], factory) 10 | } else if (typeof module === 'object' && module.exports) { 11 | // CommonJS 12 | module.exports = function(d3) { 13 | d3.tip = factory(d3) 14 | return d3.tip 15 | } 16 | } else { 17 | // Browser global. 18 | root.d3.tip = factory(root.d3) 19 | } 20 | }(this, function (d3) { 21 | 22 | // Public - contructs a new tooltip 23 | // 24 | // Returns a tip 25 | return function() { 26 | var direction = d3_tip_direction, 27 | offset = d3_tip_offset, 28 | html = d3_tip_html, 29 | node = initNode(), 30 | svg = null, 31 | point = null, 32 | target = null 33 | 34 | function tip(vis) { 35 | svg = getSVGNode(vis) 36 | point = svg.createSVGPoint() 37 | document.body.appendChild(node) 38 | } 39 | 40 | // Public - show the tooltip on the screen 41 | // 42 | // Returns a tip 43 | tip.show = function() { 44 | var args = Array.prototype.slice.call(arguments) 45 | if(args[args.length - 1] instanceof SVGElement) target = args.pop() 46 | 47 | var content = html.apply(this, args), 48 | poffset = offset.apply(this, args), 49 | dir = direction.apply(this, args), 50 | nodel = getNodeEl(), 51 | i = directions.length, 52 | coords, 53 | scrollTop = document.documentElement.scrollTop || document.body.scrollTop, 54 | scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft 55 | 56 | nodel.html(content) 57 | .style({ opacity: 1, 'pointer-events': 'all' }) 58 | 59 | while(i--) nodel.classed(directions[i], false) 60 | coords = direction_callbacks.get(dir).apply(this) 61 | nodel.classed(dir, true).style({ 62 | top: (coords.top + poffset[0]) + scrollTop + 'px', 63 | left: (coords.left + poffset[1]) + scrollLeft + 'px' 64 | }) 65 | 66 | return tip 67 | } 68 | 69 | // Public - hide the tooltip 70 | // 71 | // Returns a tip 72 | tip.hide = function() { 73 | var nodel = getNodeEl() 74 | nodel.style({ opacity: 0, 'pointer-events': 'none' }) 75 | return tip 76 | } 77 | 78 | // Public: Proxy attr calls to the d3 tip container. Sets or gets attribute value. 79 | // 80 | // n - name of the attribute 81 | // v - value of the attribute 82 | // 83 | // Returns tip or attribute value 84 | tip.attr = function(n, v) { 85 | if (arguments.length < 2 && typeof n === 'string') { 86 | return getNodeEl().attr(n) 87 | } else { 88 | var args = Array.prototype.slice.call(arguments) 89 | d3.selection.prototype.attr.apply(getNodeEl(), args) 90 | } 91 | 92 | return tip 93 | } 94 | 95 | // Public: Proxy style calls to the d3 tip container. Sets or gets a style value. 96 | // 97 | // n - name of the property 98 | // v - value of the property 99 | // 100 | // Returns tip or style property value 101 | tip.style = function(n, v) { 102 | if (arguments.length < 2 && typeof n === 'string') { 103 | return getNodeEl().style(n) 104 | } else { 105 | var args = Array.prototype.slice.call(arguments) 106 | d3.selection.prototype.style.apply(getNodeEl(), args) 107 | } 108 | 109 | return tip 110 | } 111 | 112 | // Public: Set or get the direction of the tooltip 113 | // 114 | // v - One of n(north), s(south), e(east), or w(west), nw(northwest), 115 | // sw(southwest), ne(northeast) or se(southeast) 116 | // 117 | // Returns tip or direction 118 | tip.direction = function(v) { 119 | if (!arguments.length) return direction 120 | direction = v == null ? v : d3.functor(v) 121 | 122 | return tip 123 | } 124 | 125 | // Public: Sets or gets the offset of the tip 126 | // 127 | // v - Array of [x, y] offset 128 | // 129 | // Returns offset or 130 | tip.offset = function(v) { 131 | if (!arguments.length) return offset 132 | offset = v == null ? v : d3.functor(v) 133 | 134 | return tip 135 | } 136 | 137 | // Public: sets or gets the html value of the tooltip 138 | // 139 | // v - String value of the tip 140 | // 141 | // Returns html value or tip 142 | tip.html = function(v) { 143 | if (!arguments.length) return html 144 | html = v == null ? v : d3.functor(v) 145 | 146 | return tip 147 | } 148 | 149 | // Public: destroys the tooltip and removes it from the DOM 150 | // 151 | // Returns a tip 152 | tip.destroy = function() { 153 | if(node) { 154 | getNodeEl().remove(); 155 | node = null; 156 | } 157 | return tip; 158 | } 159 | 160 | function d3_tip_direction() { return 'n' } 161 | function d3_tip_offset() { return [0, 0] } 162 | function d3_tip_html() { return ' ' } 163 | 164 | var direction_callbacks = d3.map({ 165 | n: direction_n, 166 | s: direction_s, 167 | e: direction_e, 168 | w: direction_w, 169 | nw: direction_nw, 170 | ne: direction_ne, 171 | sw: direction_sw, 172 | se: direction_se 173 | }), 174 | 175 | directions = direction_callbacks.keys() 176 | 177 | function direction_n() { 178 | var bbox = getScreenBBox() 179 | return { 180 | top: bbox.n.y - node.offsetHeight, 181 | left: bbox.n.x - node.offsetWidth / 2 182 | } 183 | } 184 | 185 | function direction_s() { 186 | var bbox = getScreenBBox() 187 | return { 188 | top: bbox.s.y, 189 | left: bbox.s.x - node.offsetWidth / 2 190 | } 191 | } 192 | 193 | function direction_e() { 194 | var bbox = getScreenBBox() 195 | return { 196 | top: bbox.e.y - node.offsetHeight / 2, 197 | left: bbox.e.x 198 | } 199 | } 200 | 201 | function direction_w() { 202 | var bbox = getScreenBBox() 203 | return { 204 | top: bbox.w.y - node.offsetHeight / 2, 205 | left: bbox.w.x - node.offsetWidth 206 | } 207 | } 208 | 209 | function direction_nw() { 210 | var bbox = getScreenBBox() 211 | return { 212 | top: bbox.nw.y - node.offsetHeight, 213 | left: bbox.nw.x - node.offsetWidth 214 | } 215 | } 216 | 217 | function direction_ne() { 218 | var bbox = getScreenBBox() 219 | return { 220 | top: bbox.ne.y - node.offsetHeight, 221 | left: bbox.ne.x 222 | } 223 | } 224 | 225 | function direction_sw() { 226 | var bbox = getScreenBBox() 227 | return { 228 | top: bbox.sw.y, 229 | left: bbox.sw.x - node.offsetWidth 230 | } 231 | } 232 | 233 | function direction_se() { 234 | var bbox = getScreenBBox() 235 | return { 236 | top: bbox.se.y, 237 | left: bbox.e.x 238 | } 239 | } 240 | 241 | function initNode() { 242 | var node = d3.select(document.createElement('div')) 243 | node.style({ 244 | position: 'absolute', 245 | top: 0, 246 | opacity: 0, 247 | 'pointer-events': 'none', 248 | 'box-sizing': 'border-box' 249 | }) 250 | 251 | return node.node() 252 | } 253 | 254 | function getSVGNode(el) { 255 | el = el.node() 256 | if(el.tagName.toLowerCase() === 'svg') 257 | return el 258 | 259 | return el.ownerSVGElement 260 | } 261 | 262 | function getNodeEl() { 263 | if(node === null) { 264 | node = initNode(); 265 | // re-add node to DOM 266 | document.body.appendChild(node); 267 | }; 268 | return d3.select(node); 269 | } 270 | 271 | // Private - gets the screen coordinates of a shape 272 | // 273 | // Given a shape on the screen, will return an SVGPoint for the directions 274 | // n(north), s(south), e(east), w(west), ne(northeast), se(southeast), nw(northwest), 275 | // sw(southwest). 276 | // 277 | // +-+-+ 278 | // | | 279 | // + + 280 | // | | 281 | // +-+-+ 282 | // 283 | // Returns an Object {n, s, e, w, nw, sw, ne, se} 284 | function getScreenBBox() { 285 | var targetel = target || d3.event.target; 286 | 287 | while ('undefined' === typeof targetel.getScreenCTM && 'undefined' === targetel.parentNode) { 288 | targetel = targetel.parentNode; 289 | } 290 | 291 | var bbox = {}, 292 | matrix = targetel.getScreenCTM(), 293 | tbbox = targetel.getBBox(), 294 | width = tbbox.width, 295 | height = tbbox.height, 296 | x = tbbox.x, 297 | y = tbbox.y 298 | 299 | point.x = x 300 | point.y = y 301 | bbox.nw = point.matrixTransform(matrix) 302 | point.x += width 303 | bbox.ne = point.matrixTransform(matrix) 304 | point.y += height 305 | bbox.se = point.matrixTransform(matrix) 306 | point.x -= width 307 | bbox.sw = point.matrixTransform(matrix) 308 | point.y -= height / 2 309 | bbox.w = point.matrixTransform(matrix) 310 | point.x += width 311 | bbox.e = point.matrixTransform(matrix) 312 | point.x -= width / 2 313 | point.y -= height / 2 314 | bbox.n = point.matrixTransform(matrix) 315 | point.y += height 316 | bbox.s = point.matrixTransform(matrix) 317 | 318 | return bbox 319 | } 320 | 321 | return tip 322 | }; 323 | 324 | })); 325 | -------------------------------------------------------------------------------- /js/d3-flame-graph/bower_components/d3-tip/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "d3-tip", 3 | "version": "0.6.8", 4 | "description": "Tooltips for d3 svg visualizations", 5 | "author": "Justin Palmer (http://labratrevenge.com/d3-tip)", 6 | "main": "index.js", 7 | "directories": { 8 | "doc": "docs", 9 | "example": "examples" 10 | }, 11 | "scripts": { 12 | "test": "echo \"Error: no test specified\" && exit 1" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/Caged/d3-tip" 17 | }, 18 | "keywords": [ 19 | "d3", 20 | "tooltip" 21 | ], 22 | "license": "MIT", 23 | "bugs": { 24 | "url": "https://github.com/Caged/d3-tip/issues" 25 | }, 26 | "homepage": "https://github.com/Caged/d3-tip", 27 | "dependencies": { 28 | "d3": "^3.5.5" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /js/d3-flame-graph/bower_components/d3/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "d3", 3 | "description": "A JavaScript visualization library for HTML and SVG.", 4 | "main": "d3.js", 5 | "license": "BSD-3-Clause", 6 | "ignore": [], 7 | "homepage": "https://github.com/mbostock-bower/d3-bower", 8 | "version": "3.5.17", 9 | "_release": "3.5.17", 10 | "_resolution": { 11 | "type": "version", 12 | "tag": "v3.5.17", 13 | "commit": "abe0262a205c9f3755c3a757de4dfd1d49f34b24" 14 | }, 15 | "_source": "https://github.com/mbostock-bower/d3-bower.git", 16 | "_target": "~3.5.5", 17 | "_originalSource": "d3" 18 | } -------------------------------------------------------------------------------- /js/d3-flame-graph/bower_components/d3/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010-2016, Michael Bostock 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * The name Michael Bostock may not be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL MICHAEL BOSTOCK BE LIABLE FOR ANY DIRECT, 21 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 22 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 24 | OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 26 | EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /js/d3-flame-graph/bower_components/d3/README.md: -------------------------------------------------------------------------------- 1 | # Data-Driven Documents 2 | 3 | 4 | 5 | **D3.js** is a JavaScript library for manipulating documents based on data. **D3** helps you bring data to life using HTML, SVG, and CSS. **D3** emphasizes web standards and combines powerful visualization components with a data-driven approach to DOM manipulation, giving you the full capabilities of modern browsers without tying yourself to a proprietary framework. 6 | 7 | Want to learn more? [See the wiki.](https://github.com/mbostock/d3/wiki) 8 | 9 | For examples, [see the gallery](https://github.com/mbostock/d3/wiki/Gallery) and [mbostock’s bl.ocks](http://bl.ocks.org/mbostock). 10 | 11 | ## Good News, Everyone! 12 | 13 | The next major release of D3, 4.0, is coming! See the [4.0 development branch](https://github.com/mbostock/d3/tree/4) and read the [new API reference](https://github.com/mbostock/d3/blob/4/README.md) to get ready. 14 | -------------------------------------------------------------------------------- /js/d3-flame-graph/bower_components/d3/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "d3", 3 | "description": "A JavaScript visualization library for HTML and SVG.", 4 | "main": "d3.js", 5 | "license": "BSD-3-Clause", 6 | "ignore": [] 7 | } 8 | -------------------------------------------------------------------------------- /js/d3-flame-graph/bower_components/lodash/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lodash", 3 | "main": "lodash.js", 4 | "ignore": [ 5 | ".*", 6 | "*.custom.*", 7 | "*.log", 8 | "*.map", 9 | "*.md", 10 | "lodash.src.js", 11 | "component.json", 12 | "package.json", 13 | "doc", 14 | "node_modules", 15 | "perf", 16 | "test", 17 | "vendor" 18 | ], 19 | "homepage": "https://github.com/lodash/lodash", 20 | "version": "3.10.1", 21 | "_release": "3.10.1", 22 | "_resolution": { 23 | "type": "version", 24 | "tag": "3.10.1", 25 | "commit": "ef20b4290cc4fe7551c82a552ea7ffa76548eec8" 26 | }, 27 | "_source": "https://github.com/lodash/lodash.git", 28 | "_target": "~3.10.1", 29 | "_originalSource": "lodash" 30 | } -------------------------------------------------------------------------------- /js/d3-flame-graph/bower_components/lodash/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2012-2015 The Dojo Foundation 2 | Based on Underscore.js, copyright 2009-2015 Jeremy Ashkenas, 3 | DocumentCloud and Investigative Reporters & Editors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /js/d3-flame-graph/bower_components/lodash/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lodash", 3 | "main": "lodash.js", 4 | "ignore": [ 5 | ".*", 6 | "*.custom.*", 7 | "*.log", 8 | "*.map", 9 | "*.md", 10 | "lodash.src.js", 11 | "component.json", 12 | "package.json", 13 | "doc", 14 | "node_modules", 15 | "perf", 16 | "test", 17 | "vendor" 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /js/d3-flame-graph/bower_components/lodash/lodash.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * lodash 3.10.1 (Custom Build) lodash.com/license | Underscore.js 1.8.3 underscorejs.org/LICENSE 4 | * Build: `lodash modern -o ./lodash.js` 5 | */ 6 | ;(function(){function n(n,t){if(n!==t){var r=null===n,e=n===w,u=n===n,o=null===t,i=t===w,f=t===t;if(n>t&&!o||!u||r&&!i&&f||e&&f)return 1;if(n=n&&9<=n&&13>=n||32==n||160==n||5760==n||6158==n||8192<=n&&(8202>=n||8232==n||8233==n||8239==n||8287==n||12288==n||65279==n); 8 | }function v(n,t){for(var r=-1,e=n.length,u=-1,o=[];++r=F&&gu&&lu?new Dn(t):null,c=t.length;a&&(i=Mn,f=false,t=a);n:for(;++oi(t,a,0)&&u.push(a);return u}function at(n,t){var r=true;return Su(n,function(n,e,u){return r=!!t(n,e,u)}),r}function ct(n,t,r,e){var u=e,o=u;return Su(n,function(n,i,f){i=+t(n,i,f),(r(i,u)||i===e&&i===o)&&(u=i, 14 | o=n)}),o}function lt(n,t){var r=[];return Su(n,function(n,e,u){t(n,e,u)&&r.push(n)}),r}function st(n,t,r,e){var u;return r(n,function(n,r,o){return t(n,r,o)?(u=e?r:n,false):void 0}),u}function pt(n,t,r,e){e||(e=[]);for(var u=-1,o=n.length;++ut&&(t=-t>u?0:u+t),r=r===w||r>u?u:+r||0,0>r&&(r+=u),u=t>r?0:r-t>>>0,t>>>=0,r=Be(u);++e=c)break n;o=e[o],u*="asc"===o||true===o?1:-1;break n}u=t.b-r.b}return u})}function $t(n,t){ 21 | var r=0;return Su(n,function(n,e,u){r+=+t(n,e,u)||0}),r}function St(n,t){var e=-1,u=xr(),o=n.length,i=u===r,f=i&&o>=F,a=f&&gu&&lu?new Dn(void 0):null,c=[];a?(u=Mn,i=false):(f=false,a=t?[]:c);n:for(;++eu(a,s,0)&&((t||f)&&a.push(s),c.push(l))}return c}function Ft(n,t){for(var r=-1,e=t.length,u=Be(e);++r>>1,i=n[o];(r?i<=t:iu?w:o,u=1);++e=F)return t.plant(e).value();for(var u=0,n=r?o[u].apply(this,n):e;++uarguments.length;return typeof e=="function"&&o===w&&Oo(r)?n(r,e,u,i):Ot(r,wr(e,o,4),u,i,t)}}function sr(n,t,r,e,u,o,i,f,a,c){function l(){for(var m=arguments.length,b=m,j=Be(m);b--;)j[b]=arguments[b];if(e&&(j=Mt(j,e,u)),o&&(j=qt(j,o,i)),_||y){var b=l.placeholder,k=v(j,b),m=m-k.length;if(mt?0:t)):[]}function Pr(n,t,r){var e=n?n.length:0;return e?((r?Ur(n,t,r):null==t)&&(t=1),t=e-(+t||0),Et(n,0,0>t?0:t)):[]}function Kr(n){return n?n[0]:w}function Vr(n,t,e){var u=n?n.length:0;if(!u)return-1;if(typeof e=="number")e=0>e?bu(u+e,0):e;else if(e)return e=Lt(n,t), 42 | er?bu(u+r,0):r||0,typeof n=="string"||!Oo(n)&&be(n)?r<=u&&-1t?0:+t||0,e);++r=n&&(t=w),r}}function ae(n,t,r){function e(t,r){r&&iu(r),a=p=h=w,t&&(_=ho(),c=n.apply(s,f),p||a||(f=s=w))}function u(){var n=t-(ho()-l);0>=n||n>t?e(h,a):p=su(u,n)}function o(){e(g,p); 46 | }function i(){if(f=arguments,l=ho(),s=this,h=g&&(p||!y),false===v)var r=y&&!p;else{a||y||(_=l);var e=v-(l-_),i=0>=e||e>v;i?(a&&(a=iu(a)),_=l,c=n.apply(s,f)):a||(a=su(o,e))}return i&&p?p=iu(p):p||t===v||(p=su(u,t)),r&&(i=true,c=n.apply(s,f)),!i||p||a||(f=s=w),c}var f,a,c,l,s,p,h,_=0,v=false,g=true;if(typeof n!="function")throw new Ge(L);if(t=0>t?0:+t||0,true===r)var y=true,g=false;else ge(r)&&(y=!!r.leading,v="maxWait"in r&&bu(+r.maxWait||0,t),g="trailing"in r?!!r.trailing:g);return i.cancel=function(){p&&iu(p),a&&iu(a), 47 | _=0,a=p=h=w},i}function ce(n,t){function r(){var e=arguments,u=t?t.apply(this,e):e[0],o=r.cache;return o.has(u)?o.get(u):(e=n.apply(this,e),r.cache=o.set(u,e),e)}if(typeof n!="function"||t&&typeof t!="function")throw new Ge(L);return r.cache=new ce.Cache,r}function le(n,t){if(typeof n!="function")throw new Ge(L);return t=bu(t===w?n.length-1:+t||0,0),function(){for(var r=arguments,e=-1,u=bu(r.length-t,0),o=Be(u);++et}function pe(n){return h(n)&&Er(n)&&nu.call(n,"callee")&&!cu.call(n,"callee")}function he(n,t,r,e){return e=(r=typeof r=="function"?Bt(r,e,3):w)?r(n,t):w,e===w?dt(n,t,r):!!e}function _e(n){return h(n)&&typeof n.message=="string"&&ru.call(n)==P}function ve(n){return ge(n)&&ru.call(n)==K}function ge(n){var t=typeof n;return!!n&&("object"==t||"function"==t)}function ye(n){ 49 | return null==n?false:ve(n)?uu.test(Qe.call(n)):h(n)&&Rn.test(n)}function de(n){return typeof n=="number"||h(n)&&ru.call(n)==V}function me(n){var t;if(!h(n)||ru.call(n)!=Z||pe(n)||!(nu.call(n,"constructor")||(t=n.constructor,typeof t!="function"||t instanceof t)))return false;var r;return ht(n,function(n,t){r=t}),r===w||nu.call(n,r)}function we(n){return ge(n)&&ru.call(n)==Y}function be(n){return typeof n=="string"||h(n)&&ru.call(n)==G}function xe(n){return h(n)&&Sr(n.length)&&!!Sn[ru.call(n)]}function Ae(n,t){ 50 | return nt||!n||!mu(t))return r;do t%2&&(r+=n),t=yu(t/2),n+=n;while(t);return r}function We(n,t,r){var e=n;return(n=u(n))?(r?Ur(e,t,r):null==t)?n.slice(g(n),y(n)+1):(t+="",n.slice(o(n,t),i(n,t)+1)):n}function $e(n,t,r){return r&&Ur(n,t,r)&&(t=w),n=u(n),n.match(t||Wn)||[]}function Se(n,t,r){return r&&Ur(n,t,r)&&(t=w),h(n)?Ne(n):ut(n,t)}function Fe(n){ 52 | return n}function Ne(n){return bt(ot(n,true))}function Te(n,t,r){if(null==r){var e=ge(t),u=e?zo(t):w;((u=u&&u.length?gt(t,u):w)?u.length:e)||(u=false,r=t,t=n,n=this)}u||(u=gt(t,zo(t)));var o=true,e=-1,i=ve(n),f=u.length;false===r?o=false:ge(r)&&"chain"in r&&(o=r.chain);for(;++e=$)return r}else n=0;return Lu(r,e)}}(),Mu=le(function(n,t){ 55 | return h(n)&&Er(n)?ft(n,pt(t,false,true)):[]}),qu=tr(),Pu=tr(true),Ku=le(function(n){for(var t=n.length,e=t,u=Be(l),o=xr(),i=o===r,f=[];e--;){var a=n[e]=Er(a=n[e])?a:[];u[e]=i&&120<=a.length&&gu&&lu?new Dn(e&&a):null}var i=n[0],c=-1,l=i?i.length:0,s=u[0];n:for(;++c(s?Mn(s,a):o(f,a,0))){for(e=t;--e;){var p=u[e];if(0>(p?Mn(p,a):o(n[e],a,0)))continue n}s&&s.push(a),f.push(a)}return f}),Vu=le(function(t,r){r=pt(r);var e=rt(t,r);return It(t,r.sort(n)),e}),Zu=vr(),Yu=vr(true),Gu=le(function(n){return St(pt(n,false,true)); 56 | }),Ju=le(function(n,t){return Er(n)?ft(n,t):[]}),Xu=le(Jr),Hu=le(function(n){var t=n.length,r=2--n?t.apply(this,arguments):void 0}},Nn.ary=function(n,t,r){return r&&Ur(n,t,r)&&(t=w),t=n&&null==t?n.length:bu(+t||0,0),gr(n,E,w,w,w,w,t)},Nn.assign=Co,Nn.at=no,Nn.before=fe,Nn.bind=_o,Nn.bindAll=vo,Nn.bindKey=go,Nn.callback=Se,Nn.chain=Qr,Nn.chunk=function(n,t,r){t=(r?Ur(n,t,r):null==t)?1:bu(yu(t)||1,1),r=0;for(var e=n?n.length:0,u=-1,o=Be(vu(e/t));rr&&(r=-r>u?0:u+r),e=e===w||e>u?u:+e||0,0>e&&(e+=u),u=r>e?0:e>>>0,r>>>=0;rt?0:t)):[]},Nn.takeRight=function(n,t,r){var e=n?n.length:0;return e?((r?Ur(n,t,r):null==t)&&(t=1),t=e-(+t||0),Et(n,0>t?0:t)):[]},Nn.takeRightWhile=function(n,t,r){ 71 | return n&&n.length?Nt(n,wr(t,r,3),false,true):[]},Nn.takeWhile=function(n,t,r){return n&&n.length?Nt(n,wr(t,r,3)):[]},Nn.tap=function(n,t,r){return t.call(r,n),n},Nn.throttle=function(n,t,r){var e=true,u=true;if(typeof n!="function")throw new Ge(L);return false===r?e=false:ge(r)&&(e="leading"in r?!!r.leading:e,u="trailing"in r?!!r.trailing:u),ae(n,t,{leading:e,maxWait:+t,trailing:u})},Nn.thru=ne,Nn.times=function(n,t,r){if(n=yu(n),1>n||!mu(n))return[];var e=-1,u=Be(xu(n,4294967295));for(t=Bt(t,r,1);++ee?u[e]=t(e):t(e); 72 | return u},Nn.toArray=je,Nn.toPlainObject=ke,Nn.transform=function(n,t,r,e){var u=Oo(n)||xe(n);return t=wr(t,e,4),null==r&&(u||ge(n)?(e=n.constructor,r=u?Oo(n)?new e:[]:$u(ve(e)?e.prototype:w)):r={}),(u?Pn:_t)(n,function(n,e,u){return t(r,n,e,u)}),r},Nn.union=Gu,Nn.uniq=Gr,Nn.unzip=Jr,Nn.unzipWith=Xr,Nn.values=Ee,Nn.valuesIn=function(n){return Ft(n,Re(n))},Nn.where=function(n,t){return re(n,bt(t))},Nn.without=Ju,Nn.wrap=function(n,t){return t=null==t?Fe:t,gr(t,R,w,[n],[])},Nn.xor=function(){for(var n=-1,t=arguments.length;++nr?0:+r||0,e),r-=t.length,0<=r&&n.indexOf(t,r)==r},Nn.escape=function(n){return(n=u(n))&&hn.test(n)?n.replace(sn,c):n},Nn.escapeRegExp=function(n){return(n=u(n))&&bn.test(n)?n.replace(wn,l):n||"(?:)"},Nn.every=te,Nn.find=ro,Nn.findIndex=qu,Nn.findKey=$o,Nn.findLast=eo, 75 | Nn.findLastIndex=Pu,Nn.findLastKey=So,Nn.findWhere=function(n,t){return ro(n,bt(t))},Nn.first=Kr,Nn.floor=ni,Nn.get=function(n,t,r){return n=null==n?w:yt(n,Dr(t),t+""),n===w?r:n},Nn.gt=se,Nn.gte=function(n,t){return n>=t},Nn.has=function(n,t){if(null==n)return false;var r=nu.call(n,t);if(!r&&!Wr(t)){if(t=Dr(t),n=1==t.length?n:yt(n,Et(t,0,-1)),null==n)return false;t=Zr(t),r=nu.call(n,t)}return r||Sr(n.length)&&Cr(t,n.length)&&(Oo(n)||pe(n))},Nn.identity=Fe,Nn.includes=ee,Nn.indexOf=Vr,Nn.inRange=function(n,t,r){ 76 | return t=+t||0,r===w?(r=t,t=0):r=+r||0,n>=xu(t,r)&&nr?bu(e+r,0):xu(r||0,e-1))+1;else if(r)return u=Lt(n,t,true)-1,n=n[u],(t===t?t===n:n!==n)?u:-1; 78 | if(t!==t)return p(n,u,true);for(;u--;)if(n[u]===t)return u;return-1},Nn.lt=Ae,Nn.lte=function(n,t){return n<=t},Nn.max=ti,Nn.min=ri,Nn.noConflict=function(){return Zn._=eu,this},Nn.noop=Le,Nn.now=ho,Nn.pad=function(n,t,r){n=u(n),t=+t;var e=n.length;return er?0:+r||0,n.length),n.lastIndexOf(t,r)==r},Nn.sum=function(n,t,r){if(r&&Ur(n,t,r)&&(t=w),t=wr(t,r,3),1==t.length){n=Oo(n)?n:zr(n),r=n.length;for(var e=0;r--;)e+=+t(n[r])||0;n=e}else n=$t(n,t);return n},Nn.template=function(n,t,r){var e=Nn.templateSettings;r&&Ur(n,t,r)&&(t=r=w),n=u(n),t=nt(tt({},r||t),e,Qn),r=nt(tt({},t.imports),e.imports,Qn); 81 | var o,i,f=zo(r),a=Ft(r,f),c=0;r=t.interpolate||Cn;var l="__p+='";r=Ze((t.escape||Cn).source+"|"+r.source+"|"+(r===gn?jn:Cn).source+"|"+(t.evaluate||Cn).source+"|$","g");var p="sourceURL"in t?"//# sourceURL="+t.sourceURL+"\n":"";if(n.replace(r,function(t,r,e,u,f,a){return e||(e=u),l+=n.slice(c,a).replace(Un,s),r&&(o=true,l+="'+__e("+r+")+'"),f&&(i=true,l+="';"+f+";\n__p+='"),e&&(l+="'+((__t=("+e+"))==null?'':__t)+'"),c=a+t.length,t}),l+="';",(t=t.variable)||(l="with(obj){"+l+"}"),l=(i?l.replace(fn,""):l).replace(an,"$1").replace(cn,"$1;"), 82 | l="function("+(t||"obj")+"){"+(t?"":"obj||(obj={});")+"var __t,__p=''"+(o?",__e=_.escape":"")+(i?",__j=Array.prototype.join;function print(){__p+=__j.call(arguments,'')}":";")+l+"return __p}",t=Jo(function(){return qe(f,p+"return "+l).apply(w,a)}),t.source=l,_e(t))throw t;return t},Nn.trim=We,Nn.trimLeft=function(n,t,r){var e=n;return(n=u(n))?n.slice((r?Ur(e,t,r):null==t)?g(n):o(n,t+"")):n},Nn.trimRight=function(n,t,r){var e=n;return(n=u(n))?(r?Ur(e,t,r):null==t)?n.slice(0,y(n)+1):n.slice(0,i(n,t+"")+1):n; 83 | },Nn.trunc=function(n,t,r){r&&Ur(n,t,r)&&(t=w);var e=U;if(r=W,null!=t)if(ge(t)){var o="separator"in t?t.separator:o,e="length"in t?+t.length||0:e;r="omission"in t?u(t.omission):r}else e=+t||0;if(n=u(n),e>=n.length)return n;if(e-=r.length,1>e)return r;if(t=n.slice(0,e),null==o)return t+r;if(we(o)){if(n.slice(e).search(o)){var i,f=n.slice(0,e);for(o.global||(o=Ze(o.source,(kn.exec(o)||"")+"g")),o.lastIndex=0;n=o.exec(f);)i=n.index;t=t.slice(0,null==i?e:i)}}else n.indexOf(o,e)!=e&&(o=t.lastIndexOf(o), 84 | -1u.__dir__?"Right":"")}),u},zn.prototype[n+"Right"]=function(t){return this.reverse()[n](t).reverse()}}),Pn(["filter","map","takeWhile"],function(n,t){ 86 | var r=t+1,e=r!=T;zn.prototype[n]=function(n,t){var u=this.clone();return u.__iteratees__.push({iteratee:wr(n,t,1),type:r}),u.__filtered__=u.__filtered__||e,u}}),Pn(["first","last"],function(n,t){var r="take"+(t?"Right":"");zn.prototype[n]=function(){return this[r](1).value()[0]}}),Pn(["initial","rest"],function(n,t){var r="drop"+(t?"":"Right");zn.prototype[n]=function(){return this.__filtered__?new zn(this):this[r](1)}}),Pn(["pluck","where"],function(n,t){var r=t?"filter":"map",e=t?bt:ze;zn.prototype[n]=function(n){ 87 | return this[r](e(n))}}),zn.prototype.compact=function(){return this.filter(Fe)},zn.prototype.reject=function(n,t){return n=wr(n,t,1),this.filter(function(t){return!n(t)})},zn.prototype.slice=function(n,t){n=null==n?0:+n||0;var r=this;return r.__filtered__&&(0t)?new zn(r):(0>n?r=r.takeRight(-n):n&&(r=r.drop(n)),t!==w&&(t=+t||0,r=0>t?r.dropRight(-t):r.take(t-n)),r)},zn.prototype.takeRightWhile=function(n,t){return this.reverse().takeWhile(n,t).reverse()},zn.prototype.toArray=function(){return this.take(Ru); 88 | },_t(zn.prototype,function(n,t){var r=/^(?:filter|map|reject)|While$/.test(t),e=/^(?:first|last)$/.test(t),u=Nn[e?"take"+("last"==t?"Right":""):t];u&&(Nn.prototype[t]=function(){function t(n){return e&&i?u(n,1)[0]:u.apply(w,Jn([n],o))}var o=e?[1]:arguments,i=this.__chain__,f=this.__wrapped__,a=!!this.__actions__.length,c=f instanceof zn,l=o[0],s=c||Oo(f);return s&&r&&typeof l=="function"&&1!=l.length&&(c=s=false),l={func:ne,args:[t],thisArg:w},a=c&&!a,e&&!i?a?(f=f.clone(),f.__actions__.push(l),n.call(f)):u.call(w,this.value())[0]:!e&&s?(f=a?f:new zn(this), 89 | f=n.apply(f,o),f.__actions__.push(l),new Ln(f,i)):this.thru(t)})}),Pn("join pop push replace shift sort splice split unshift".split(" "),function(n){var t=(/^(?:replace|split)$/.test(n)?He:Je)[n],r=/^(?:push|sort|unshift)$/.test(n)?"tap":"thru",e=/^(?:join|pop|replace|shift)$/.test(n);Nn.prototype[n]=function(){var n=arguments;return e&&!this.__chain__?t.apply(this.value(),n):this[r](function(r){return t.apply(r,n)})}}),_t(zn.prototype,function(n,t){var r=Nn[t];if(r){var e=r.name+"";(Wu[e]||(Wu[e]=[])).push({ 90 | name:t,func:r})}}),Wu[sr(w,A).name]=[{name:"wrapper",func:w}],zn.prototype.clone=function(){var n=new zn(this.__wrapped__);return n.__actions__=qn(this.__actions__),n.__dir__=this.__dir__,n.__filtered__=this.__filtered__,n.__iteratees__=qn(this.__iteratees__),n.__takeCount__=this.__takeCount__,n.__views__=qn(this.__views__),n},zn.prototype.reverse=function(){if(this.__filtered__){var n=new zn(this);n.__dir__=-1,n.__filtered__=true}else n=this.clone(),n.__dir__*=-1;return n},zn.prototype.value=function(){ 91 | var n,t=this.__wrapped__.value(),r=this.__dir__,e=Oo(t),u=0>r,o=e?t.length:0;n=o;for(var i=this.__views__,f=0,a=-1,c=i.length;++a"'`]/g,pn=RegExp(ln.source),hn=RegExp(sn.source),_n=/<%-([\s\S]+?)%>/g,vn=/<%([\s\S]+?)%>/g,gn=/<%=([\s\S]+?)%>/g,yn=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\n\\]|\\.)*?\1)\]/,dn=/^\w*$/,mn=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\n\\]|\\.)*?)\2)\]/g,wn=/^[:!,]|[\\^$.*+?()[\]{}|\/]|(^[0-9a-fA-Fnrtuvx])|([\n\r\u2028\u2029])/g,bn=RegExp(wn.source),xn=/[\u0300-\u036f\ufe20-\ufe23]/g,An=/\\(\\)?/g,jn=/\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g,kn=/\w*$/,In=/^0[xX]/,Rn=/^\[object .+?Constructor\]$/,On=/^\d+$/,En=/[\xc0-\xd6\xd8-\xde\xdf-\xf6\xf8-\xff]/g,Cn=/($^)/,Un=/['\n\r\u2028\u2029\\]/g,Wn=RegExp("[A-Z\\xc0-\\xd6\\xd8-\\xde]+(?=[A-Z\\xc0-\\xd6\\xd8-\\xde][a-z\\xdf-\\xf6\\xf8-\\xff]+)|[A-Z\\xc0-\\xd6\\xd8-\\xde]?[a-z\\xdf-\\xf6\\xf8-\\xff]+|[A-Z\\xc0-\\xd6\\xd8-\\xde]+|[0-9]+","g"),$n="Array ArrayBuffer Date Error Float32Array Float64Array Function Int8Array Int16Array Int32Array Math Number Object RegExp Set String _ clearTimeout isFinite parseFloat parseInt setTimeout TypeError Uint8Array Uint8ClampedArray Uint16Array Uint32Array WeakMap".split(" "),Sn={}; 94 | Sn[X]=Sn[H]=Sn[Q]=Sn[nn]=Sn[tn]=Sn[rn]=Sn[en]=Sn[un]=Sn[on]=true,Sn[B]=Sn[D]=Sn[J]=Sn[M]=Sn[q]=Sn[P]=Sn[K]=Sn["[object Map]"]=Sn[V]=Sn[Z]=Sn[Y]=Sn["[object Set]"]=Sn[G]=Sn["[object WeakMap]"]=false;var Fn={};Fn[B]=Fn[D]=Fn[J]=Fn[M]=Fn[q]=Fn[X]=Fn[H]=Fn[Q]=Fn[nn]=Fn[tn]=Fn[V]=Fn[Z]=Fn[Y]=Fn[G]=Fn[rn]=Fn[en]=Fn[un]=Fn[on]=true,Fn[P]=Fn[K]=Fn["[object Map]"]=Fn["[object Set]"]=Fn["[object WeakMap]"]=false;var Nn={"\xc0":"A","\xc1":"A","\xc2":"A","\xc3":"A","\xc4":"A","\xc5":"A","\xe0":"a","\xe1":"a","\xe2":"a", 95 | "\xe3":"a","\xe4":"a","\xe5":"a","\xc7":"C","\xe7":"c","\xd0":"D","\xf0":"d","\xc8":"E","\xc9":"E","\xca":"E","\xcb":"E","\xe8":"e","\xe9":"e","\xea":"e","\xeb":"e","\xcc":"I","\xcd":"I","\xce":"I","\xcf":"I","\xec":"i","\xed":"i","\xee":"i","\xef":"i","\xd1":"N","\xf1":"n","\xd2":"O","\xd3":"O","\xd4":"O","\xd5":"O","\xd6":"O","\xd8":"O","\xf2":"o","\xf3":"o","\xf4":"o","\xf5":"o","\xf6":"o","\xf8":"o","\xd9":"U","\xda":"U","\xdb":"U","\xdc":"U","\xf9":"u","\xfa":"u","\xfb":"u","\xfc":"u","\xdd":"Y", 96 | "\xfd":"y","\xff":"y","\xc6":"Ae","\xe6":"ae","\xde":"Th","\xfe":"th","\xdf":"ss"},Tn={"&":"&","<":"<",">":">",'"':""","'":"'","`":"`"},Ln={"&":"&","<":"<",">":">",""":'"',"'":"'","`":"`"},zn={"function":true,object:true},Bn={0:"x30",1:"x31",2:"x32",3:"x33",4:"x34",5:"x35",6:"x36",7:"x37",8:"x38",9:"x39",A:"x41",B:"x42",C:"x43",D:"x44",E:"x45",F:"x46",a:"x61",b:"x62",c:"x63",d:"x64",e:"x65",f:"x66",n:"x6e",r:"x72",t:"x74",u:"x75",v:"x76",x:"x78"},Dn={"\\":"\\", 97 | "'":"'","\n":"n","\r":"r","\u2028":"u2028","\u2029":"u2029"},Mn=zn[typeof exports]&&exports&&!exports.nodeType&&exports,qn=zn[typeof module]&&module&&!module.nodeType&&module,Pn=zn[typeof self]&&self&&self.Object&&self,Kn=zn[typeof window]&&window&&window.Object&&window,Vn=qn&&qn.exports===Mn&&Mn,Zn=Mn&&qn&&typeof global=="object"&&global&&global.Object&&global||Kn!==(this&&this.window)&&Kn||Pn||this,Yn=m();typeof define=="function"&&typeof define.amd=="object"&&define.amd?(Zn._=Yn, define(function(){ 98 | return Yn})):Mn&&qn?Vn?(qn.exports=Yn)._=Yn:Mn._=Yn:Zn._=Yn}).call(this); -------------------------------------------------------------------------------- /js/d3-flame-graph/src/d3.flameGraph.css: -------------------------------------------------------------------------------- 1 | .d3-flame-graph rect { 2 | stroke: #EEEEEE; 3 | fill-opacity: .8; 4 | } 5 | 6 | .d3-flame-graph rect:hover { 7 | stroke: #474747; 8 | stroke-width: 0.5; 9 | cursor: pointer; 10 | } 11 | 12 | .d3-flame-graph .label { 13 | pointer-events: none; 14 | white-space: nowrap; 15 | text-overflow: ellipsis; 16 | overflow: hidden; 17 | font-size: 12px; 18 | font-family: Verdana; 19 | margin-left: 4px; 20 | margin-right: 4px; 21 | line-height: 1.5; 22 | padding: 0 0 0; 23 | font-weight: 400; 24 | color: black; 25 | text-align: left; 26 | } 27 | 28 | .d3-flame-graph .fade { 29 | opacity: 0.6 !important; 30 | } 31 | 32 | .d3-flame-graph .title { 33 | font-size: 20px; 34 | font-family: Verdana; 35 | } 36 | 37 | .d3-flame-graph-tip { 38 | line-height: 1; 39 | font-family: Verdana; 40 | font-size: 12px; 41 | padding: 12px; 42 | background: rgba(0, 0, 0, 0.8); 43 | color: #fff; 44 | z-index: 9999; 45 | border-radius: 2px; 46 | pointer-events: none; 47 | } 48 | 49 | /* Creates a small triangle extender for the tooltip */ 50 | .d3-flame-graph-tip:after { 51 | box-sizing: border-box; 52 | display: inline; 53 | font-size: 10px; 54 | width: 100%; 55 | line-height: 1; 56 | color: rgba(0, 0, 0, 0.8); 57 | position: absolute; 58 | pointer-events: none; 59 | } 60 | 61 | /* Northward tooltips */ 62 | .d3-flame-graph-tip.n:after { 63 | content: "\25BC"; 64 | margin: -1px 0 0 0; 65 | top: 100%; 66 | left: 0; 67 | text-align: center; 68 | } 69 | 70 | /* Eastward tooltips */ 71 | .d3-flame-graph-tip.e:after { 72 | content: "\25C0"; 73 | margin: -4px 0 0 0; 74 | top: 50%; 75 | left: -8px; 76 | } 77 | 78 | /* Southward tooltips */ 79 | .d3-flame-graph-tip.s:after { 80 | content: "\25B2"; 81 | margin: 0 0 1px 0; 82 | top: -8px; 83 | left: 0; 84 | text-align: center; 85 | } 86 | 87 | /* Westward tooltips */ 88 | .d3-flame-graph-tip.w:after { 89 | content: "\25B6"; 90 | margin: -4px 0 0 -1px; 91 | top: 50%; 92 | left: 100%; 93 | } 94 | -------------------------------------------------------------------------------- /js/d3-flame-graph/src/d3.flameGraph.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | function flameGraph() { 5 | 6 | var w = 960, // graph width 7 | h = 540, // graph height 8 | c = 18, // cell height 9 | selection = null, // selection 10 | tooltip = true, // enable tooltip 11 | title = "", // graph title 12 | transitionDuration = 750, 13 | transitionEase = "cubic-in-out", // tooltip offset 14 | sort = true, 15 | reversed = false, // reverse the graph direction 16 | clickHandler = null; 17 | 18 | var tip = d3.tip() 19 | .direction("s") 20 | .offset([8, 0]) 21 | .attr('class', 'd3-flame-graph-tip') 22 | .html(function(d) { return label(d); }); 23 | 24 | var labelFormat = function(d) { 25 | return d.name + " (" + d3.round(100 * d.dx, 3) + "%, " + d.value + " samples)"; 26 | }; 27 | 28 | function setDetails(t) { 29 | var details = document.getElementById("details"); 30 | if (details) 31 | details.innerHTML = t; 32 | } 33 | 34 | function label(d) { 35 | if (!d.dummy) { 36 | return labelFormat(d); 37 | } else { 38 | return ""; 39 | } 40 | } 41 | 42 | function name(d) { 43 | return d.name; 44 | } 45 | 46 | var colorMapper = function(d) { 47 | return d.highlight ? "#E600E6" : colorHash(d.name); 48 | }; 49 | 50 | function generateHash(name) { 51 | // Return a vector (0.0->1.0) that is a hash of the input string. 52 | // The hash is computed to favor early characters over later ones, so 53 | // that strings with similar starts have similar vectors. Only the first 54 | // 6 characters are considered. 55 | var hash = 0, weight = 1, max_hash = 0, mod = 10, max_char = 6; 56 | if (name) { 57 | for (var i = 0; i < name.length; i++) { 58 | if (i > max_char) { break; } 59 | hash += weight * (name.charCodeAt(i) % mod); 60 | max_hash += weight * (mod - 1); 61 | weight *= 0.70; 62 | } 63 | if (max_hash > 0) { hash = hash / max_hash; } 64 | } 65 | return hash; 66 | } 67 | 68 | function colorHash(name) { 69 | // Return an rgb() color string that is a hash of the provided name, 70 | // and with a warm palette. 71 | var vector = 0; 72 | if (name) { 73 | name = name.replace(/.*`/, ""); // drop module name if present 74 | name = name.replace(/\(.*/, ""); // drop extra info 75 | vector = generateHash(name); 76 | } 77 | var r = 200 + Math.round(55 * vector); 78 | var g = 0 + Math.round(230 * (1 - vector)); 79 | var b = 0 + Math.round(55 * (1 - vector)); 80 | return "rgb(" + r + "," + g + "," + b + ")"; 81 | } 82 | 83 | function augment(data) { 84 | // Augment partitioning layout with "dummy" nodes so that internal nodes' 85 | // values dictate their width. Annoying, but seems to be least painful 86 | // option. https://github.com/mbostock/d3/pull/574 87 | if (data.children && (data.children.length > 0)) { 88 | data.children.forEach(augment); 89 | var childValues = 0; 90 | data.children.forEach(function(child) { 91 | childValues += child.value; 92 | }); 93 | if (childValues < data.value) { 94 | data.children.push( 95 | { 96 | "name": "", 97 | "value": data.value - childValues, 98 | "dummy": true 99 | } 100 | ); 101 | } 102 | } 103 | } 104 | 105 | function hide(d) { 106 | if(!d.original) { 107 | d.original = d.value; 108 | } 109 | d.value = 0; 110 | if(d.children) { 111 | d.children.forEach(hide); 112 | } 113 | } 114 | 115 | function show(d) { 116 | d.fade = false; 117 | if(d.original) { 118 | d.value = d.original; 119 | } 120 | if(d.children) { 121 | d.children.forEach(show); 122 | } 123 | } 124 | 125 | function getSiblings(d) { 126 | var siblings = []; 127 | if (d.parent) { 128 | var me = d.parent.children.indexOf(d); 129 | siblings = d.parent.children.slice(0); 130 | siblings.splice(me, 1); 131 | } 132 | return siblings; 133 | } 134 | 135 | function hideSiblings(d) { 136 | var siblings = getSiblings(d); 137 | siblings.forEach(function(s) { 138 | hide(s); 139 | }); 140 | if(d.parent) { 141 | hideSiblings(d.parent); 142 | } 143 | } 144 | 145 | function fadeAncestors(d) { 146 | if(d.parent) { 147 | d.parent.fade = true; 148 | fadeAncestors(d.parent); 149 | } 150 | } 151 | 152 | function getRoot(d) { 153 | if(d.parent) { 154 | return getRoot(d.parent); 155 | } 156 | return d; 157 | } 158 | 159 | function zoom(d) { 160 | tip.hide(d); 161 | hideSiblings(d); 162 | show(d); 163 | fadeAncestors(d); 164 | update(); 165 | if (typeof clickHandler === 'function') { 166 | clickHandler(d); 167 | } 168 | } 169 | 170 | function searchTree(d, term) { 171 | var re = new RegExp(term), 172 | searchResults = []; 173 | 174 | function searchInner(d) { 175 | var label = d.name; 176 | 177 | if (d.children) { 178 | d.children.forEach(function (child) { 179 | searchInner(child); 180 | }); 181 | } 182 | 183 | if (label.match(re)) { 184 | d.highlight = true; 185 | searchResults.push(d); 186 | } else { 187 | d.highlight = false; 188 | } 189 | } 190 | 191 | searchInner(d); 192 | return searchResults; 193 | } 194 | 195 | function clear(d) { 196 | d.highlight = false; 197 | if(d.children) { 198 | d.children.forEach(function(child) { 199 | clear(child); 200 | }); 201 | } 202 | } 203 | 204 | function doSort(a, b) { 205 | if (typeof sort === 'function') { 206 | return sort(a, b); 207 | } else if (sort) { 208 | return d3.ascending(a.name, b.name); 209 | } else { 210 | return 0; 211 | } 212 | } 213 | 214 | var partition = d3.layout.partition() 215 | .sort(doSort) 216 | .value(function(d) {return d.v || d.value;}) 217 | .children(function(d) {return d.c || d.children;}); 218 | 219 | function update() { 220 | 221 | selection.each(function(data) { 222 | 223 | var x = d3.scale.linear().range([0, w]), 224 | y = d3.scale.linear().range([0, c]); 225 | 226 | var nodes = partition(data); 227 | 228 | var kx = w / data.dx; 229 | 230 | var g = d3.select(this).select("svg").selectAll("g").data(nodes); 231 | 232 | g.transition() 233 | .duration(transitionDuration) 234 | .ease(transitionEase) 235 | .attr("transform", function(d) { return "translate(" + x(d.x) + "," 236 | + (reversed ? y(d.depth) : (h - y(d.depth) - c)) + ")"; }); 237 | 238 | g.select("rect").transition() 239 | .duration(transitionDuration) 240 | .ease(transitionEase) 241 | .attr("width", function(d) { return d.dx * kx; }); 242 | 243 | var node = g.enter() 244 | .append("svg:g") 245 | .attr("transform", function(d) { return "translate(" + x(d.x) + "," 246 | + (reversed ? y(d.depth) : (h - y(d.depth) - c)) + ")"; }); 247 | 248 | node.append("svg:rect") 249 | .attr("width", function(d) { return d.dx * kx; }); 250 | 251 | if (!tooltip) 252 | node.append("svg:title"); 253 | 254 | node.append("foreignObject") 255 | .append("xhtml:div"); 256 | 257 | g.attr("width", function(d) { return d.dx * kx; }) 258 | .attr("height", function(d) { return c; }) 259 | .attr("name", function(d) { return d.name; }) 260 | .attr("class", function(d) { return d.fade ? "frame fade" : "frame"; }); 261 | 262 | g.select("rect") 263 | .attr("height", function(d) { return c; }) 264 | .attr("fill", function(d) { return colorMapper(d); }) 265 | .style("visibility", function(d) {return d.dummy ? "hidden" : "visible";}); 266 | 267 | if (!tooltip) 268 | g.select("title") 269 | .text(label); 270 | 271 | g.select("foreignObject") 272 | .attr("width", function(d) { return d.dx * kx; }) 273 | .attr("height", function(d) { return c; }) 274 | .select("div") 275 | .attr("class", "label") 276 | .style("display", function(d) { return (d.dx * kx < 35) || d.dummy ? "none" : "block";}) 277 | .text(name); 278 | 279 | g.on('click', zoom); 280 | 281 | g.exit().remove(); 282 | 283 | g.on('mouseover', function(d) { 284 | if(!d.dummy) { 285 | if (tooltip) tip.show(d); 286 | setDetails(label(d)); 287 | } 288 | }).on('mouseout', function(d) { 289 | if(!d.dummy) { 290 | if (tooltip) tip.hide(d); 291 | setDetails(""); 292 | } 293 | }); 294 | }); 295 | } 296 | 297 | function merge(data, samples) { 298 | samples.forEach(function (sample) { 299 | var node = _.find(data, function (element) { 300 | return element.name === sample.name; 301 | }); 302 | 303 | if (node) { 304 | node.value += sample.value; 305 | if (sample.children) { 306 | if (!node.children) { 307 | node.children = []; 308 | } 309 | merge(node.children, sample.children) 310 | } 311 | } else { 312 | data.push(sample); 313 | } 314 | }); 315 | } 316 | 317 | function chart(s) { 318 | 319 | selection = s; 320 | 321 | if (!arguments.length) return chart; 322 | 323 | selection.each(function(data) { 324 | 325 | var svg = d3.select(this) 326 | .append("svg:svg") 327 | .attr("width", w) 328 | .attr("height", h) 329 | .attr("class", "partition d3-flame-graph") 330 | .call(tip); 331 | 332 | svg.append("svg:text") 333 | .attr("class", "title") 334 | .attr("text-anchor", "middle") 335 | .attr("y", "25") 336 | .attr("x", w/2) 337 | .attr("fill", "#808080") 338 | .text(title); 339 | 340 | augment(data); 341 | 342 | // "creative" fix for node ordering when partition is called for the first time 343 | partition(data); 344 | 345 | }); 346 | 347 | // first draw 348 | update(); 349 | } 350 | 351 | chart.height = function (_) { 352 | if (!arguments.length) { return h; } 353 | h = _; 354 | return chart; 355 | }; 356 | 357 | chart.width = function (_) { 358 | if (!arguments.length) { return w; } 359 | w = _; 360 | return chart; 361 | }; 362 | 363 | chart.cellHeight = function (_) { 364 | if (!arguments.length) { return c; } 365 | c = _; 366 | return chart; 367 | }; 368 | 369 | chart.tooltip = function (_) { 370 | if (!arguments.length) { return tooltip; } 371 | if (typeof _ === "function") { 372 | tip = _; 373 | } 374 | tooltip = true; 375 | return chart; 376 | }; 377 | 378 | chart.title = function (_) { 379 | if (!arguments.length) { return title; } 380 | title = _; 381 | return chart; 382 | }; 383 | 384 | chart.transitionDuration = function (_) { 385 | if (!arguments.length) { return transitionDuration; } 386 | transitionDuration = _; 387 | return chart; 388 | }; 389 | 390 | chart.transitionEase = function (_) { 391 | if (!arguments.length) { return transitionEase; } 392 | transitionEase = _; 393 | return chart; 394 | }; 395 | 396 | chart.sort = function (_) { 397 | if (!arguments.length) { return sort; } 398 | sort = _; 399 | return chart; 400 | }; 401 | 402 | chart.reversed = function (_) { 403 | if (!arguments.length) { return reversed; } 404 | reversed = _; 405 | return chart; 406 | }; 407 | 408 | chart.label = function(_) { 409 | if (!arguments.length) { return labelFormat; } 410 | labelFormat = _; 411 | return chart; 412 | }; 413 | 414 | chart.search = function(term) { 415 | var searchResults = []; 416 | selection.each(function(data) { 417 | searchResults = searchTree(data, term); 418 | update(); 419 | }); 420 | return searchResults; 421 | }; 422 | 423 | chart.clear = function() { 424 | selection.each(function(data) { 425 | clear(data); 426 | update(); 427 | }); 428 | }; 429 | 430 | chart.zoomTo = function(d) { 431 | zoom(d); 432 | }; 433 | 434 | chart.resetZoom = function() { 435 | selection.each(function (data) { 436 | zoom(data); // zoom to root 437 | }); 438 | }; 439 | 440 | chart.onClick = function(_) { 441 | if (!arguments.length) { 442 | return clickHandler; 443 | } 444 | clickHandler = _; 445 | return chart; 446 | }; 447 | 448 | chart.merge = function(samples) { 449 | selection.each(function (data) { 450 | merge([data], [samples]); 451 | augment(data); 452 | }); 453 | update(); 454 | } 455 | 456 | chart.color = function(_) { 457 | if (!arguments.length) { return colorMapper; } 458 | colorMapper = _; 459 | return chart; 460 | }; 461 | 462 | return chart; 463 | } 464 | 465 | if (typeof module !== 'undefined' && module.exports){ 466 | module.exports = flameGraph; 467 | } 468 | else { 469 | d3.flameGraph = flameGraph; 470 | } 471 | })(); 472 | -------------------------------------------------------------------------------- /query-monitor-flamegraph.php: -------------------------------------------------------------------------------- 1 |