[
  {
    "path": ".eslintignore",
    "content": "ui\r\ncoverage\r\n"
  },
  {
    "path": ".eslintrc.json",
    "content": "{\r\n  \"extends\": \"eslint:recommended\",\r\n  \"env\": {\r\n    \"node\":  true,\r\n    \"es6\": true,\r\n    \"mocha\": true\r\n  },\r\n  \"rules\": {\r\n    \"semi\": [2, \"always\"],\r\n    \"require-yield\": 0,\r\n    \"strict\": [\"error\", \"global\"],\r\n    \"no-unused-vars\": [\"error\", { \"vars\": \"all\", \"args\": \"none\" }],\r\n    \"quotes\": [\"error\", \"single\", { \"avoidEscape\": true } ],\r\n    \"space-before-function-paren\": [\"error\", \"never\"]\r\n  }\r\n}\r\n"
  },
  {
    "path": ".gitignore",
    "content": "logs\r\n*.log\r\nnpm-debug.log*\r\npids\r\n*.pid\r\n*.seed\r\n*.rdb\r\n*.DS_STORE\r\nlib-cov\r\ncoverage\r\n.nyc_output\r\n.grunt\r\n.lock-wscript\r\nbuild/Release\r\nnode_modules\r\njspm_packages\r\n.npm\r\n.node_repl_history\r\n"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"ui\"]\r\n\tpath = ui\r\n\turl = https://github.com/MiniProfiler/ui.git\r\n"
  },
  {
    "path": ".npmignore",
    "content": "coverage\r\ntests\r\nnode_modules\r\nexamples\r\n.travis.yml"
  },
  {
    "path": ".travis.yml",
    "content": "language: node_js\r\nnode_js:\r\n  - \"8\"\r\n  - \"stable\"\r\n\r\nsudo: required\r\n\r\nservices:\r\n  - docker\r\n\r\nbefore_script:\r\n  - npm run start-services\r\n  - npm run lint\r\n  - sleep 3\r\n\r\nafter_script:\r\n  - npm run coverage\r\n  - npm run check-coverage\r\n  - npm run update-coveralls\r\n\r\nnotifications:\r\n  email:\r\n    on_success: never\r\n    on_failure: change\r\n"
  },
  {
    "path": "README.md",
    "content": "# MiniProfiler for Node.js\r\n\r\nNode.js implementation of Stack Exchange's MiniProfiler\r\n\r\n[![NPM](https://img.shields.io/npm/v/miniprofiler.svg)](https://www.npmjs.com/package/miniprofiler)\r\n[![Build](https://travis-ci.org/MiniProfiler/node.svg?branch=master)](https://travis-ci.org/MiniProfiler/node)\r\n[![Coverage](https://coveralls.io/repos/github/MiniProfiler/node/badge.svg?branch=master)](https://coveralls.io/github/MiniProfiler/node?branch=master)\r\n![Dependencies](https://david-dm.org/MiniProfiler/node.svg)\r\n![devDependencies](https://david-dm.org/MiniProfiler/node/dev-status.svg#info=devDependencies)\r\n\r\n## Demonstration\r\n\r\nVisit [http://miniprofiler-demo.herokuapp.com](http://miniprofiler-demo.herokuapp.com) for a live demonstration.\r\n\r\n## Installation\r\n\r\n```bash\r\n$ npm install miniprofiler\r\n```\r\n\r\nYou can hook up your application with any of the following packages are available on npm:\r\n\r\n| Name      | About     | Version   |\r\n|-----------|-----------|-----------|\r\n| `miniprofiler-http` | Profile http(s) requests | [![NPM](https://img.shields.io/npm/v/miniprofiler-http.svg)](https://www.npmjs.com/package/miniprofiler-http) |\r\n| `miniprofiler-pg` | Profile [pg](https://www.npmjs.com/package/pg) queries | [![NPM](https://img.shields.io/npm/v/miniprofiler-pg.svg)](https://www.npmjs.com/package/miniprofiler-pg) |\r\n| `miniprofiler-redis`| Profile [redis](https://www.npmjs.com/package/redis) calls | [![NPM](https://img.shields.io/npm/v/miniprofiler-redis.svg)](https://www.npmjs.com/package/miniprofiler-redis) |\r\n\r\n## Usage\r\n\r\n### Simple usage with express.js\r\n\r\n`server.js`\r\n\r\n```javascript\r\nvar express = require('express')\r\n  , miniprofiler = require('miniprofiler')\r\n  , app = express();\r\n\r\napp.set('view engine', 'pug');\r\napp.use(miniprofiler.express());\r\n\r\napp.get('/', function(req, res) {\r\n  req.miniprofiler.step('Step 1', function() {\r\n    req.miniprofiler.step('Step 2', function() {\r\n      res.render('index');\r\n    });\r\n  });\r\n});\r\n\r\napp.listen(8080);\r\n```\r\n\r\n`index.pug`\r\n\r\n```javascript\r\ndoctype html\r\nhtml\r\n  head\r\n    title MiniProfiler Node.js Example\r\n  body\r\n    h1 Home Page\r\n    | !{miniprofiler.include()}\r\n```\r\n\r\nWhen visiting `localhost:8080`, you should see this.\r\n\r\n![](/examples/images/example0.png)\r\n\r\n## API\r\n\r\n### `miniprofiler.{framework}([options])`\r\n\r\nReplace `{framework}` with koa, express or hapi.\r\n\r\nThis function returns a framework specific middleware that is responsible for initializing MiniProfiler on each request.\r\n\r\n#### `options` object properties\r\n| Property  | Default   | Description |\r\n|-----------|-----------|-------------|\r\n| enable    | Always returns true | function(req, res) => boolean; this function is used to determine if the profiler should be enabled for the current request |\r\n| authorize | Always returns true | function(req, res) => boolean; this function is used to determine if the current request should be able to see the profiling results |\r\n\r\n### `miniprofiler.{framework}.for([provider])`\r\n\r\n`provider` is a call for any of the supported providers listed [here](#installation).\r\n\r\n### `miniprofiler.configure([options])`\r\n\r\n#### `options` object properties\r\n| Property  | Default   | Description |\r\n|-----------|-----------|-------------|\r\n| storage   | InMemoryStorage({ max: 100, maxAge: 1000 \\* 60 \\* 60 }) | InMemoryStorage or RedisStorage; used to store or fetch a string JSON blob of profiling information |\r\n| ignoredPaths | [ ] | string array ; any request whose `url` property is in ignoredPaths will not be profiled |\r\n| trivialDurationThresholdMilliseconds | 2.5 | double ; any step lasting longer than this will be considered trivial, and hidden by default |\r\n| popupShowTimeWithChildren | false | boolean ; whether or not to include the \"time with children\" column |\r\n| popupRenderPosition       | left  | 'left', 'right', 'bottomLeft' or 'bottomRight' ; which side of the screen to display timings on |\r\n\r\n#### `options.storage` examples\r\n\r\n#### InMemoryStorage\r\n\r\n```\r\nminiprofiler.configure({\r\n  storage: miniprofiler.storage.InMemoryStorage({ lruCacheOptions });\r\n})\r\n```\r\n\r\nRefer to [lru-cache](https://www.npmjs.com/package/lru-cache) documentation for `lruCacheOptions`.\r\n\r\n#### RedisStorage\r\n\r\n```\r\nminiprofiler.configure({\r\n  storage: miniprofiler.storage.RedisStorage(client);\r\n})\r\n```\r\n\r\nWhere `client` is an instance of [redis.createClient](https://www.npmjs.com/package/redis).\r\n"
  },
  {
    "path": "lib/async-context.js",
    "content": "'use strict';\n\nconst asyncHooks = require('async_hooks');\n\nclass AsyncContext {\n  constructor() {\n    this.map = new Map();\n    asyncHooks.createHook({\n      init: (id, _type, triggerId) => {\n        if (this.map.has(triggerId))\n          this.map.set(id, this.map.get(triggerId));\n      },\n      destroy: (id) => this.map.delete(id)\n    }).enable();\n  }\n\n  get() {\n    const id = asyncHooks.executionAsyncId();\n    if (this.map.has(id))\n      return this.map.get(id);\n  }\n\n  set(val) {\n    this.map.set(asyncHooks.executionAsyncId(), val);\n  }\n}\n\nmodule.exports = new AsyncContext();\n"
  },
  {
    "path": "lib/client-parser.js",
    "content": "'use strict';\r\n\r\n var _ = require('./utils.js');\r\n\r\nlet insertInOrder = (array, timing) => {\r\n  if (timing.Start <= 0)\r\n    return;\r\n\r\n  for(let key in array) {\r\n    if (timing.Start <= array[key].Start) {\r\n      return array.splice(key, 0, timing);\r\n    }\r\n  }\r\n\r\n  return array.push(timing);\r\n};\r\n\r\nmodule.exports = (postData) => {\r\n  let preffix = 'clientPerformance[timing][';\r\n\r\n  let postDataTimings = { };\r\n  let clientTimings = [ ];\r\n  let navigationStart = 0;\r\n\r\n  for(let postDataKey in postData) {\r\n    if (postDataKey.startsWith(preffix)) {\r\n      let key = postDataKey.substring(preffix.length, postDataKey.length - 1);\r\n      if (key == 'navigationStart')\r\n        navigationStart = parseInt(postData[postDataKey]);\r\n      else\r\n        postDataTimings[key] = parseInt(postData[postDataKey]);\r\n    }\r\n  }\r\n\r\n  if (!navigationStart)\r\n    return null;\r\n\r\n  for(let key in postDataTimings) {\r\n    if (key.endsWith('Start')) {\r\n\r\n      let eventName = key.slice(0, -5);\r\n      let eventStartTime = postDataTimings[`${eventName}Start`];\r\n      let eventEndTime = postDataTimings[`${eventName}End`];\r\n\r\n      let timing = {\r\n        Name: _.toTitleCase(eventName),\r\n        Start: eventStartTime - navigationStart,\r\n        Duration: eventEndTime - eventStartTime\r\n      };\r\n\r\n      if (!timing.Duration) {\r\n        timing.Name = _.toTitleCase(`${eventName}Start`);\r\n        timing.Duration = -1;\r\n      }\r\n\r\n      insertInOrder(clientTimings, timing);\r\n\r\n    } else if (!key.endsWith('End')) {\r\n      insertInOrder(clientTimings, {\r\n        Name: _.toTitleCase(key),\r\n        Start: postDataTimings[key] - navigationStart,\r\n        Duration: -1\r\n      });\r\n    }\r\n  }\r\n\r\n  return {\r\n    RedirectCount: parseInt(postData['clientPerformance[navigation][redirectCount]']),\r\n    Timings: clientTimings\r\n  };\r\n};\r\n"
  },
  {
    "path": "lib/middlewares/express.js",
    "content": "'use strict';\r\n\r\nconst asyncContext = require('../async-context');\r\n\r\nmodule.exports = {\r\n  buildMiddleware: function(provider) {\r\n    return function(req, res, next) {\r\n      provider.handler(req, res, next);\r\n    };\r\n  },\r\n  mainMiddleware: function(enable, authorize, handleRequest, cls) {\r\n    return function(req, res, next) {\r\n      handleRequest(enable, authorize, req, res).then((handled) => {\r\n        res.locals.miniprofiler = req.miniprofiler;\r\n\r\n        asyncContext.set(req.miniprofiler);\r\n        Object.defineProperty(req, 'miniprofiler', { get: () => asyncContext.get() });\r\n\r\n        var render = res.render;\r\n        res.render = function() {\r\n          var renderArguments = arguments;\r\n          req.miniprofiler.step(`Render: ${arguments[0]}`, function() {\r\n            render.apply(res, renderArguments);\r\n          });\r\n        };\r\n\r\n        if (!handled)\r\n          next();\r\n      }).catch(next);\r\n    };\r\n  }\r\n};\r\n"
  },
  {
    "path": "lib/middlewares/hapi.js",
    "content": "'use strict';\r\n\r\nconst asyncContext = require('../async-context');\r\n\r\nmodule.exports = {\r\n  buildMiddleware: function(provider) {\r\n    var plugin = {\r\n      register: (server, options, next) => {\r\n        server.ext('onRequest', function(request, reply) {\r\n          provider.handler(request.raw.req, request.raw.res, () => {\r\n            return reply.continue();\r\n          });\r\n        });\r\n        next();\r\n      }\r\n    };\r\n\r\n    plugin.register.attributes = {\r\n      name: `miniprofiler-hapi-${provider.name}`,\r\n      version: require('../../package.json').version\r\n    };\r\n\r\n    return plugin;\r\n  },\r\n  mainMiddleware: function(enable, authorize, handleRequest) {\r\n    var plugin = {\r\n      register: (server, options, next) => {\r\n        server.ext('onRequest', function(request, reply) {\r\n          handleRequest(enable, authorize, request.raw.req, request.raw.res).then((handled) => {\r\n            asyncContext.set(request.raw.req.miniprofiler);\r\n            Object.defineProperty(request.app, 'miniprofiler', { get: () => asyncContext.get() });\r\n            Object.defineProperty(request.raw.req, 'miniprofiler', { get: () => asyncContext.get() });\r\n\r\n            if (!handled)\r\n              reply.continue();\r\n          });\r\n        });\r\n        next();\r\n      }\r\n    };\r\n\r\n    plugin.register.attributes = {\r\n      name: 'miniprofiler-hapi',\r\n      version: require('../../package.json').version\r\n    };\r\n\r\n    //That's a bad monkey patch, didn't like it, needs refactor...\r\n    plugin.vision = (server) => {\r\n      var view = server._replier._decorations['view'];\r\n\r\n      server._replier._decorations['view'] = function(template, context, options) {\r\n        var viewArguments = arguments;\r\n        this.request.raw.req.miniprofiler.step(`Render: ${template}`, () => {\r\n          return view.apply(this, viewArguments);\r\n        });\r\n      };\r\n    };\r\n\r\n    return plugin;\r\n  }\r\n};\r\n"
  },
  {
    "path": "lib/middlewares/koa.js",
    "content": "'use strict';\r\n\r\nconst asyncContext = require('../async-context');\r\n\r\nmodule.exports = {\r\n  buildMiddleware: function(provider) {\r\n    return function *(next) {\r\n      yield new Promise((resolve, reject) => {\r\n        provider.handler(this.req, this.res, resolve);\r\n      });\r\n      yield next;\r\n    };\r\n  },\r\n  mainMiddleware: function(enable, authorize, handleRequest) {\r\n    return function *(next) {\r\n      var handled = yield handleRequest(enable, authorize, this.req, this.res);\r\n\r\n      asyncContext.set(this.req.miniprofiler);\r\n      Object.defineProperty(this.state, 'miniprofiler', { get: () => asyncContext.get() });\r\n      Object.defineProperty(this.req, 'miniprofiler', { get: () => asyncContext.get() });\r\n\r\n      if (this.render) {\r\n        var render = this.render;\r\n        this.render = function() {\r\n          return new Promise((resolve, reject) => {\r\n            var renderArguments = arguments;\r\n            this.req.miniprofiler.step(`Render: ${arguments[0]}`, function() {\r\n              render.apply(this, renderArguments);\r\n              resolve();\r\n            });\r\n          });\r\n        };\r\n      }\r\n\r\n      if (!handled)\r\n        yield next;\r\n    };\r\n  }\r\n};\r\n"
  },
  {
    "path": "lib/miniprofiler.js",
    "content": "'use strict';\r\n\r\n/*\r\n *  MiniProfiler implementation for node.js.\r\n *\r\n *  Apache License, Version 2.0\r\n *\r\n *  Kevin Montrose, 2013 @kevin-montrose\r\n *  Matt Jibson, 2013 @mjibsonF\r\n *  Guilherme Oenning, 2016 @goenning\r\n */\r\n\r\nvar _ = require('./utils.js');\r\nvar qs = require('querystring');\r\nvar url = require('url');\r\nvar ui = require('./ui.js');\r\nvar clientParser = require('./client-parser.js');\r\n\r\nconst hostname = require('os').hostname;\r\nvar ignoredPaths = [];\r\nvar trivialDurationThresholdMilliseconds = 2.5;\r\nvar popupShowTimeWithChildren = false;\r\nvar popupRenderPosition = 'left';\r\nvar resourcePath = '/mini-profiler-resources/';\r\n\r\nexports.storage = {\r\n  InMemoryStorage: require('./storages/inmemory.js'),\r\n  RedisStorage: require('./storages/redis.js')\r\n};\r\n\r\nvar storage = new exports.storage.InMemoryStorage({ max: 100, maxAge: 1000 * 60 * 60 });\r\n\r\nexports.configure = configure;\r\nconfigure();\r\n\r\nfor (let framework of ['koa', 'express', 'hapi']) {\r\n  let func = require(`./middlewares/${framework}.js`);\r\n\r\n  exports[framework] = function(options) {\r\n    options = options || {};\r\n\r\n    if (!options.enable) options.enable = () => { return true; };\r\n    if (!options.authorize) options.authorize = () => { return true; };\r\n\r\n    return func.mainMiddleware(options.enable, options.authorize, handleRequest);\r\n  };\r\n\r\n  exports[framework].for = func.buildMiddleware;\r\n}\r\n\r\nvar version = require('../package.json').version;\r\n\r\nvar contentTypes = {\r\n  css: 'text/css',\r\n  js: 'text/javascript',\r\n  tmpl: 'text/html; charset=utf-8'\r\n};\r\n\r\nfunction getPath(req) {\r\n  return url.parse(req.url).path;\r\n}\r\n\r\nfunction handleRequest(enable, authorize, req, res) {\r\n  return new Promise((resolve, reject) => {\r\n    var enabled = enable(req, res);\r\n    var authorized = authorize(req, res);\r\n    var requestPath = url.parse(req.url).pathname;\r\n\r\n    for (let ignoredPath of ignoredPaths) {\r\n      if (requestPath.startsWith(ignoredPath)) {\r\n        enabled = false;\r\n        break;\r\n      }\r\n    }\r\n\r\n    if (!requestPath.startsWith(resourcePath)) {\r\n      var extension = startProfiling(req, enabled, authorized);\r\n      if (enabled) {\r\n        res.on('finish', () => {\r\n          stopProfiling(extension, req);\r\n        });\r\n        res.setHeader('X-MiniProfiler-Ids', `[\"${extension.id}\"]`);\r\n      }\r\n      return resolve(false);\r\n    }\r\n\r\n    if (!authorized) {\r\n      res.writeHead(401, { 'Content-Type': 'text/plain; charset=utf-8' });\r\n      res.end('');\r\n      return resolve(true);\r\n    }\r\n\r\n    if (!enabled) {\r\n      res.writeHead(404, { 'Content-Type': 'text/plain; charset=utf-8' });\r\n      res.end('MiniProfiler is disabled');\r\n      return resolve(true);\r\n    }\r\n\r\n    var segments = _.compact(requestPath.split('/'));\r\n    var lastPathSegment = segments[segments.length - 1];\r\n    var handler = (lastPathSegment == 'results') ? results : assets;\r\n    handler(req, res, lastPathSegment, (result) => {\r\n      res.writeHead(result.status, { 'Content-Type': result.type });\r\n      res.end(result.body);\r\n      resolve(true);\r\n    });\r\n  });\r\n}\r\n\r\nfunction assets(req, res, lastPathSegment, done) {\r\n  ui.readFile(lastPathSegment, function(err, data) {\r\n    if (err) {\r\n      done({\r\n        type: 'text/plain; charset=utf-8',\r\n        status: 404,\r\n        body: 'Resource unavailable.'\r\n      });\r\n    } else {\r\n      var rs = lastPathSegment.split('.');\r\n      res.setHeader('Cache-Control', 'public, max-age=31557600');\r\n      done({\r\n        type: contentTypes[rs[rs.length - 1]],\r\n        status: 200,\r\n        body: data\r\n      });\r\n    }\r\n  });\r\n}\r\n\r\nfunction results(req, res, lastPathSegment, done) {\r\n  var proc = function(post, done) {\r\n\r\n    var query = url.parse(req.url, true).query;\r\n    var id = post.id || query.id;\r\n    var popup = post.popup || query.popup;\r\n    var timing = (req.method === 'POST') ? clientParser(post) : null;\r\n\r\n    storage.get(id, (err, data) => {\r\n\r\n      if (!data) {\r\n        done({\r\n          type: 'text/plain; charset=utf-8',\r\n          status: 404,\r\n          body: `Id '${id}' not found.`\r\n        });\r\n        return;\r\n      }\r\n\r\n      var json = JSON.parse(data);\r\n      if (timing) {\r\n        json.ClientTimings = timing;\r\n        data = JSON.stringify(json);\r\n        storage.set(id, data);\r\n      }\r\n\r\n      if (popup == '1') {\r\n        done({\r\n          type: 'application/json',\r\n          status: 200,\r\n          body: data\r\n        });\r\n        return;\r\n      }\r\n\r\n      done({\r\n        type: 'text/html; charset=utf-8',\r\n        status: 200,\r\n        body: ui.share({\r\n          name: json.Name,\r\n          duration: json.DurationMilliseconds,\r\n          path: resourcePath,\r\n          json: data,\r\n          includes: include(id),\r\n          version: version\r\n        })\r\n      });\r\n    });\r\n  };\r\n\r\n  var body = '';\r\n  req.on('data', function(data) {\r\n    body += data;\r\n  });\r\n\r\n  req.on('end', function() {\r\n    var post = qs.parse(body);\r\n    proc(post, done);\r\n  });\r\n}\r\n\r\nfunction include(id) {\r\n  return ui.partial({\r\n    path: resourcePath,\r\n    position: popupRenderPosition,\r\n    showChildren: popupShowTimeWithChildren,\r\n    trivialMilliseconds: trivialDurationThresholdMilliseconds,\r\n\r\n    version: version,\r\n    currentId: id,\r\n    ids: id,\r\n    showTrivial: true,\r\n    maxTracesToShow: 15,\r\n    showControls: true,\r\n    authorized: true,\r\n    toggleShortcut: '',\r\n    startHidden: false\r\n  });\r\n}\r\n\r\n/*\r\n * Setup profiling.  This function may only be called once, subsequent calls are ignored.\r\n *\r\n * This must be called before the first call to startProfiling.\r\n *\r\n * options is an optional object, which can have the following fields:\r\n *  - storage: InMemoryStorage or RedisStorage; used to store or fetch a string JSON blob of profiling information\r\n *  - ignoredPaths: string array ; any request whose `url` property is in ignoredPaths will not be profiled\r\n *  - trivialDurationThresholdMilliseconds: double ; any step lasting longer than this will be considered trivial, and hidden by default\r\n *  - popupShowTimeWithChildren: boolean ; whether or not to include the \"time with children\" column\r\n *  - popupRenderPosition: 'left', 'right', 'bottomLeft', 'bottomRight' ; which side of the screen to display timings on\r\n *  - resourcePath: string ; if your site root is in a subdirectory, specify here, e.g., /siteroot\r\n */\r\nfunction configure(options) {\r\n  options = options || {};\r\n\r\n  ignoredPaths = options.ignoredPaths || ignoredPaths;\r\n  trivialDurationThresholdMilliseconds = options.trivialDurationThresholdMilliseconds || trivialDurationThresholdMilliseconds;\r\n  popupShowTimeWithChildren = options.popupShowTimeWithChildren || popupShowTimeWithChildren;\r\n  popupRenderPosition = options.popupRenderPosition || popupRenderPosition;\r\n  storage = options.storage || storage;\r\n  resourcePath = `${options.resourcePath ? options.resourcePath.replace(/\\/$/, '') : ''}${resourcePath}`;\r\n}\r\n\r\n/*\r\n * Begins profiling the given request.\r\n */\r\nfunction startProfiling(request, enabled, authorized) {\r\n  var currentRequestExtension = {\r\n    enabled: enabled,\r\n    authorized: authorized\r\n  };\r\n\r\n  if (enabled) {\r\n    var path = getPath(request);\r\n    currentRequestExtension.id = _.uuid();\r\n    currentRequestExtension.startDate = Date.now();\r\n    currentRequestExtension.startTime = process.hrtime();\r\n    currentRequestExtension.stopTime = null;\r\n    currentRequestExtension.stepGraph = makeStep(path, currentRequestExtension.startTime, null);\r\n    currentRequestExtension.customTimings = {};\r\n  }\r\n\r\n  currentRequestExtension.timeQuery = function() {\r\n    var args = Array.prototype.slice.call(arguments, enabled ? 0 : 3);\r\n    if (enabled) {\r\n      args.unshift(currentRequestExtension);\r\n      timeQuery.apply(this, args);\r\n    } else {\r\n      arguments[2].apply(this, args);\r\n    }\r\n  };\r\n\r\n  currentRequestExtension.startTimeQuery = function(type, query) {\r\n    return startTimeQuery.call(this, currentRequestExtension, type, query);\r\n  };\r\n\r\n  currentRequestExtension.stopTimeQuery = function(timing) {\r\n    return stopTimeQuery.call(this, timing);\r\n  };\r\n\r\n  currentRequestExtension.step = function(name, call) {\r\n    if (enabled) {\r\n      step(name, request, call);\r\n    } else {\r\n      call();\r\n    }\r\n  };\r\n\r\n  currentRequestExtension.include = function() {\r\n    return enabled && authorized ? include(currentRequestExtension.id) : '';\r\n  };\r\n\r\n  request.miniprofiler = currentRequestExtension;\r\n\r\n  return currentRequestExtension;\r\n}\r\n\r\n/*\r\n * Stops profiling the given request.\r\n */\r\nfunction stopProfiling(extension, request) {\r\n  var time = process.hrtime();\r\n\r\n  extension.stopTime = time;\r\n  extension.stepGraph.stopTime = time;\r\n\r\n  var json = describePerformance(extension, request);\r\n  storage.set(extension.id, JSON.stringify(json));\r\n}\r\n\r\n/*\r\n * Wraps an invokation of `call` in a step named `name`.\r\n *\r\n * You should only use this method directly in cases when calls to addProfiling won't suffice.\r\n */\r\nfunction step(name, request, call) {\r\n  var time = process.hrtime();\r\n\r\n  var extension = request.miniprofiler;\r\n\r\n  var newStep = makeStep(name, time, extension.stepGraph);\r\n  extension.stepGraph.steps.push(newStep);\r\n  extension.stepGraph = newStep;\r\n\r\n  var result;\r\n  if (call.length) {\r\n    result = call(() => {\r\n      unstep(name, request);\r\n    });\r\n  } else {\r\n    try {\r\n      result = call();\r\n    } finally {\r\n      unstep(name, request);\r\n    }\r\n  }\r\n\r\n  return result;\r\n}\r\n\r\n/*\r\n *  Called to time a query, like to SQL or Redis, that completes with a callback\r\n *\r\n *  `type` can be any string, it is used to group query types in timings.\r\n *  `query` is a string representing the query, this is what is recorded as having run.\r\n *\r\n *  `executeFunction` is invoked with any additional parameters following it.\r\n *\r\n *  Any function passed as a parameter to `executeFunction` will be instrumented to detect\r\n *  when the query has completed.  Implicitly, any execution of a callback is considered\r\n *  to have ended the query.\r\n */\r\nfunction timeQuery(extension, type, query, executeFunction) {\r\n  var timing = startTimeQuery(extension, type, query);\r\n  var params = Array.prototype.slice.call(arguments, 4);\r\n\r\n  for (var i = 0; i < params.length; i++) {\r\n    if (_.isFunction(params[i])) {\r\n      var param = params[i];\r\n      params[i] = function() {\r\n        extension.stopTimeQuery(timing);\r\n        var ret = param.apply(this, arguments);\r\n        return ret;\r\n      };\r\n    }\r\n  }\r\n\r\n  var ret = executeFunction.apply(this, params);\r\n  return ret;\r\n}\r\n\r\nfunction stopTimeQuery(timing) {\r\n  timing.stopTime = process.hrtime();\r\n}\r\n\r\nfunction startTimeQuery(extension, type, query) {\r\n  var time = process.hrtime();\r\n  var startDate = Date.now();\r\n\r\n  extension.stepGraph.customTimings[type] = extension.stepGraph.customTimings[type] || [];\r\n\r\n  var customTiming = {\r\n    id: _.uuid(),\r\n    executeType: type,\r\n    commandString: _.escape(query),\r\n    startTime: time,\r\n    startDate: startDate,\r\n    callStack: new Error().stack\r\n  };\r\n\r\n  extension.stepGraph.customTimings[type].push(customTiming);\r\n\r\n  return customTiming;\r\n}\r\n\r\nfunction unstep(name, request) {\r\n  var time = process.hrtime();\r\n  var extension = request.miniprofiler;\r\n  extension.stepGraph.stopTime = time;\r\n  // step back up\r\n  extension.stepGraph = extension.stepGraph.parent;\r\n}\r\n\r\nfunction describePerformance(root, request) {\r\n  var ret = {};\r\n\r\n  ret.Id = root.id;\r\n  ret.Name = getPath(request);\r\n  ret.Started = root.startDate;\r\n  ret.MachineName = hostname();\r\n  ret.Root = describeTimings(root.stepGraph, root.stepGraph);\r\n  ret.ClientTimings = null;\r\n  ret.DurationMilliseconds = ret.Root.DurationMilliseconds;\r\n\r\n  return ret;\r\n}\r\n\r\nfunction diff(start, stop) {\r\n  var deltaSecs = stop[0] - start[0];\r\n  var deltaNanoSecs = stop[1] - start[1];\r\n\r\n  var elapsedMs = deltaSecs * 1000 + deltaNanoSecs / 1000000;\r\n\r\n  return elapsedMs;\r\n}\r\n\r\nfunction callStack(stack) {\r\n  var sp = stack.split('\\n');\r\n  var ret = [];\r\n  for (var i = 2; i < sp.length; i++) {\r\n    var st = sp[i].trim().split(' ');\r\n    ret.push(st[1]);\r\n  }\r\n  return ret.join(' ');\r\n}\r\n\r\nfunction describeTimings(timing, root) {\r\n  var id = _.uuid();\r\n  var name = timing.name;\r\n  var elapsedMs = diff(timing.startTime, timing.stopTime);\r\n  var sinceRootMs = diff(root.startTime, timing.startTime);\r\n  var customTimings = describeCustomTimings(timing.customTimings, root);\r\n\r\n  var children = [];\r\n  for (var i = 0; i < timing.steps.length; i++) {\r\n    var step = timing.steps[i];\r\n    children.push(describeTimings(step, root));\r\n  }\r\n\r\n  return {\r\n    Id: id,\r\n    Name: name,\r\n    DurationMilliseconds: elapsedMs,\r\n    StartMilliseconds: sinceRootMs,\r\n    Children: children,\r\n    CustomTimings: customTimings\r\n  };\r\n}\r\n\r\nfunction describeCustomTimings(customTimings, root) {\r\n  var ret = {};\r\n  for (var prop in customTimings) {\r\n\r\n    var arr = customTimings[prop];\r\n    var retArr = [];\r\n\r\n    for (var i = 0; i < arr.length; i++) {\r\n      var timing = {};\r\n      timing.Id = arr[i].id;\r\n      timing.ExecuteType = arr[i].executeType;\r\n      timing.CommandString = arr[i].commandString;\r\n      timing.StartMilliseconds = diff(root.startTime, arr[i].startTime);\r\n      timing.DurationMilliseconds = diff(arr[i].startTime, arr[i].stopTime);\r\n      timing.StackTraceSnippet = callStack(arr[i].callStack);\r\n\r\n      retArr.push(timing);\r\n    }\r\n\r\n    ret[prop] = retArr;\r\n  }\r\n\r\n  return ret;\r\n}\r\n\r\nfunction makeStep(name, time, parent) {\r\n  return { name: name, startTime: time, stopTime: null, parent: parent, steps: [], customTimings: {} };\r\n}"
  },
  {
    "path": "lib/storages/inmemory.js",
    "content": "'use strict';\r\n\r\nvar LRU = require('lru-cache');\r\nlet miniprofilerHashKey = '_miniprofiler_';\r\n\r\nfunction InMemoryStorage(options) {\r\n  this.key = function(id) {\r\n    return `${miniprofilerHashKey}${id}`;\r\n  };\r\n\r\n  this.cache = LRU(options);\r\n\r\n  this.get = function(id, callback) {\r\n    var data = this.cache.get(this.key(id));\r\n    if (data)\r\n      callback(null, data);\r\n    else\r\n      callback(new Error(`Id '${id}' not found.`));\r\n  };\r\n\r\n  this.set = function(id, json) {\r\n    this.cache.set(this.key(id), json);\r\n  };\r\n}\r\n\r\nmodule.exports = InMemoryStorage;"
  },
  {
    "path": "lib/storages/redis.js",
    "content": "'use strict';\r\n\r\nlet miniprofilerHashKey = '_miniprofiler_';\r\n\r\nfunction RedisStorage(redisClient, maxAge) {\r\n  this.maxAge = maxAge || 3600;\r\n\r\n  this.key = function(id) {\r\n    return `${miniprofilerHashKey}${id}`;\r\n  };\r\n\r\n  this.get = function(id, callback) {\r\n    redisClient.get(this.key(id), callback);\r\n  };\r\n\r\n  this.set = function(id, json) {\r\n    let key = this.key(id);\r\n    redisClient.set(key, json, (err, data) => {\r\n      redisClient.expire(key, this.maxAge);\r\n    });\r\n  };\r\n}\r\n\r\nmodule.exports = RedisStorage;"
  },
  {
    "path": "lib/ui.js",
    "content": "'use strict';\r\n\r\nconst fileStore = { };\r\n\r\nconst fs = require('fs');\r\nconst path = require('path');\r\nconst _ = require('./utils.js');\r\nconst includesDir = path.join(__dirname, '../ui');\r\n\r\nconst readFile = (name, callback) => {\r\n  if (fileStore[name]) {\r\n    callback(null, fileStore[name]);\r\n  } else {\r\n    fs.readFile(path.join(includesDir, name), 'utf-8', (err, text) => {\r\n      fileStore[name] = text;\r\n      callback(err, text);\r\n    });\r\n  }\r\n};\r\n\r\nconst templates = {\r\n  partial: _.template(fs.readFileSync(path.join(includesDir, 'include.partial.html')).toString()),\r\n  share: _.template(fs.readFileSync(path.join(includesDir, 'share.html')).toString())\r\n};\r\n\r\nconst partial = (options) => templates.partial(options);\r\n\r\nconst share = (options) => templates.share(options);\r\n\r\nmodule.exports = { readFile, partial, share };\r\n"
  },
  {
    "path": "lib/utils.js",
    "content": "'use strict';\n\nconst isFunction = (obj) => {\n  return typeof obj == 'function' || false;\n};\n\nconst tagsToReplace = {\n  '&': '&amp;',\n  '<': '&lt;',\n  '>': '&gt;',\n  '\"': '&quot;',\n  \"'\": '&#x27;',\n  '`': '&#x60;'\n};\n\nconst escape = (str) => {\n  return str.replace(/[&<>]/g, function(tag) {\n    return tagsToReplace[tag] || tag;\n  });\n};\n\nconst compact = (arr) => {\n  return arr.filter((v) => v);\n};\n\nconst uuid = () => {\n  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {\n    var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);\n    return v.toString(16);\n  });\n};\n\nconst toTitleCase = (str) => {\n  return str.replace(/ /g,'').split(/(?=[A-Z])/).join(' ').replace(/^.| ./g, (m) => {\n    return m.toUpperCase();\n  });\n};\n\nconst template = (content) => {\n  return (options) => {\n    return content.replace(/{(.+?)}/g, (match, key) => {\n      return options[key];\n    });\n  };\n};\n\nmodule.exports = {\n  isFunction, escape, compact, uuid, toTitleCase, template\n};\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"miniprofiler\",\n  \"version\": \"2.0.0\",\n  \"description\": \"A simple but effective mini-profiler.\",\n  \"main\": \"lib/miniprofiler.js\",\n  \"scripts\": {\n    \"start-services\": \"docker run -d -p 6060:6379 redis\",\n    \"lint\": \"eslint .\",\n    \"test\": \"mocha tests/ -c\",\n    \"coverage\": \"istanbul cover ./node_modules/mocha/bin/_mocha -- tests/ -R spec\",\n    \"check-coverage\": \"istanbul check-coverage --statements 95 --branches 95 --functions 95 --lines 95\",\n    \"update-coveralls\": \"cat coverage/lcov.info | node ./node_modules/coveralls/bin/coveralls.js\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/MiniProfiler/node.git\"\n  },\n  \"bugs\": {\n    \"url\": \"http://github.com/MiniProfiler/node/issues\"\n  },\n  \"author\": \"Guilherme Oenning <oenning.ti@gmail.com> (http://goenning.net/)\",\n  \"contributors\": [\n    \"Matt Jibson <matt.jibson@gmail.com> (https://mattjibson.com/)\",\n    \"Kevin Montrose\"\n  ],\n  \"license\": \"Apache-2.0\",\n  \"readmeFilename\": \"README.md\",\n  \"dependencies\": {\n    \"lru-cache\": \"^4.0.1\"\n  },\n  \"tags\": [\n    \"profiler\",\n    \"performance\",\n    \"profiling\",\n    \"timing\",\n    \"web profiling\"\n  ],\n  \"devDependencies\": {\n    \"chai\": \"^3.5.0\",\n    \"coveralls\": \"^2.11.11\",\n    \"docker-ip\": \"^2.0.1\",\n    \"eslint\": \"^6.6.0\",\n    \"express\": \"^4.13.4\",\n    \"hapi\": \"^13.5.0\",\n    \"istanbul\": \"^0.4.3\",\n    \"koa\": \"^1.2.1\",\n    \"koa-route\": \"^2.4.2\",\n    \"koa-views\": \"^4.1.0\",\n    \"debug\": \"^2.6.1\",\n    \"mocha\": \"^2.5.3\",\n    \"pug\": \"^2.0.0-beta2\",\n    \"redis\": \"^3.1.1\",\n    \"request\": \"^2.73.0\",\n    \"vision\": \"^4.1.0\"\n  }\n}\n"
  },
  {
    "path": "tests/assets-test.js",
    "content": "'use strict';\r\n\r\nvar expect = require('chai').expect;\r\nvar fs = require('fs');\r\n\r\nmodule.exports = function(server) {\r\n  describe('Assets Tests', function() {\r\n    before(server.setUp.bind(null, 'default'));\r\n    after(server.tearDown);\r\n\r\n    var files = [\r\n      'includes.css',\r\n      'includes.css',\r\n      'includes.tmpl',\r\n      'includes.js'\r\n    ];\r\n\r\n    files.forEach((file) => {\r\n      it(`Should return ${file} file`, function(done) {\r\n        server.get(`/mini-profiler-resources/${file}`, (err, response, body) => {\r\n          fs.readFile(`./ui/${file}`, 'utf-8', (err, content) => {\r\n            expect(body).to.be.equal(content);\r\n            done();\r\n          });\r\n        });\r\n      });\r\n    });\r\n\r\n    it('Unknown file should return 404', function(done) {\r\n      server.get('/mini-profiler-resources/unknown.js', (err, response, body) => {\r\n        expect(response.statusCode).to.be.equal(404);\r\n        expect(body).to.be.equal('Resource unavailable.');\r\n        expect(response.headers['content-type']).to.be.equal('text/plain; charset=utf-8');\r\n        done();\r\n      });\r\n    });\r\n\r\n  });\r\n};\r\n"
  },
  {
    "path": "tests/basic-test.js",
    "content": "'use strict';\n\nvar expect = require('chai').expect;\nvar pkg = require('../package.json');\n\nmodule.exports = function(server) {\n  describe('Basic Tests', function() {\n    before(server.setUp.bind(null, 'default'));\n    after(server.tearDown);\n\n    it('Profiled routes should always return Profiler ID', function(done) {\n      server.get('/', (err, response) => {\n        expect(response.headers).to.include.keys('x-miniprofiler-ids');\n        done();\n      });\n    });\n\n    it('Index page should include MiniProfiler javascript', function(done) {\n      server.get('/', (err, response, body) => {\n        var ids = JSON.parse(response.headers['x-miniprofiler-ids']);\n        expect(ids).to.have.lengthOf(1);\n\n        expect(body.trim()).to.be.equal(`<script async type=\"text/javascript\" id=\"mini-profiler\" src=\"/mini-profiler-resources/includes.js?v=${pkg.version}\" data-version=\"${pkg.version}\" data-path=\"/mini-profiler-resources/\" data-current-id=\"${ids[0]}\" data-ids=\"${ids[0]}\" data-position=\"left\" data-trivial=\"true\" data-children=\"false\" data-max-traces=\"15\" data-controls=\"true\" data-authorized=\"true\" data-toggle-shortcut=\"\" data-start-hidden=\"false\" data-trivial-milliseconds=\"2.5\"></script>`);\n        done();\n      });\n    });\n\n    it('Should return url parameters on results response', function(done) {\n      server.get('/?key1=value1&key2=value2', (err, response, body) => {\n        var ids = JSON.parse(response.headers['x-miniprofiler-ids']);\n        expect(ids).to.have.lengthOf(1);\n\n        server.get(`/mini-profiler-resources/results?id=${ids[0]}&popup=1`, (err, response, body) => {\n          var result = JSON.parse(body);\n          expect(result.Id).to.equal(ids[0]);\n          expect(result.Name).to.equal('/?key1=value1&key2=value2');\n          expect(result.Root.Children).to.be.empty;\n\n          done();\n        });\n      });\n    });\n\n  });\n};\n"
  },
  {
    "path": "tests/client-test.js",
    "content": "'use strict';\r\n\r\nvar expect = require('chai').expect;\r\n\r\nmodule.exports = function(server) {\r\n  describe('Client Timing Tests', function() {\r\n    before(server.setUp.bind(null, 'default'));\r\n    after(server.tearDown);\r\n\r\n    it('should return client timing data that is sent on POST', function(done) {\r\n      server.get('/', (err, response) => {\r\n        var ids = JSON.parse(response.headers['x-miniprofiler-ids']);\r\n\r\n        server.post('/mini-profiler-resources/results', {\r\n          id: ids[0],\r\n          popup: 1,\r\n          clientPerformance: {\r\n            navigation: {\r\n              redirectCount: 0\r\n            },\r\n            timing: {\r\n              navigationStart: 1000,\r\n              responseEnd: 1014,\r\n              loadEventStart: 1080,\r\n              requestStart: 1001,\r\n              secureConnectionStart: 0,\r\n              loadEventEnd: 1112,\r\n              responseStart: 1002,\r\n              'First Paint Time':1200\r\n            }\r\n          }\r\n        }, (err, response, body) => {\r\n          var data = JSON.parse(body);\r\n          expect(data.ClientTimings).to.be.deep.equal({\r\n            RedirectCount: 0,\r\n            Timings: [{\r\n              Name: 'Request Start',\r\n              Start: 1,\r\n              Duration: -1\r\n            },{\r\n              Name: 'Response',\r\n              Start: 2,\r\n              Duration: 12\r\n            },{\r\n              Name: 'Load Event',\r\n              Start: 80,\r\n              Duration: 32\r\n            },{\r\n              Name: 'First Paint Time',\r\n              Start: 200,\r\n              Duration: -1\r\n            }]\r\n          });\r\n          done();\r\n        });\r\n      });\r\n    });\r\n\r\n    it('should not return client timing when data is not sent via POST', function(done) {\r\n      server.get('/', (err, response) => {\r\n        var ids = JSON.parse(response.headers['x-miniprofiler-ids']);\r\n\r\n        server.post('/mini-profiler-resources/results', {\r\n          id: ids[0],\r\n          popup: 1\r\n        }, (err, response, body) => {\r\n          var data = JSON.parse(body);\r\n          expect(data.ClientTimings).to.be.null;\r\n          done();\r\n        });\r\n      });\r\n    });\r\n\r\n  });\r\n\r\n};\r\n"
  },
  {
    "path": "tests/concurrent-async-test.js",
    "content": "'use strict';\n\nvar expect = require('chai').expect;\n\nmodule.exports = function(server) {\n  describe('Concurrent Async Requests', function() {\n    before(server.setUp.bind(null, 'async'));\n    after(server.tearDown);\n\n    it('Each profile runs on its own context', function(done) {\n      let countDone = 0;\n      const partialDone = () => { if (++countDone === 2) done(); };\n\n      server.get('/', (err, response) => {\n        var ids = JSON.parse(response.headers['x-miniprofiler-ids']);\n        expect(ids).to.have.lengthOf(1);\n\n        server.post('/mini-profiler-resources/results/', { id: ids[0], popup: 1 }, (err, response, body) => {\n          var result = JSON.parse(body);\n          expect(result.Root.CustomTimings.async).to.have.lengthOf(2);\n          partialDone();\n        });\n      });\n\n      server.get('/?once=true', (err, response) => {\n        var ids = JSON.parse(response.headers['x-miniprofiler-ids']);\n        expect(ids).to.have.lengthOf(1);\n\n        server.post('/mini-profiler-resources/results/', { id: ids[0], popup: 1 }, (err, response, body) => {\n          var result = JSON.parse(body);\n          expect(result.Root.CustomTimings.async).to.have.lengthOf(1);\n          partialDone();\n        });\n      });\n    });\n  });\n};\n"
  },
  {
    "path": "tests/custom-config-test.js",
    "content": "'use strict';\r\n\r\nvar expect = require('chai').expect;\r\nvar pkg = require('../package.json');\r\n\r\nmodule.exports = function(server) {\r\n  describe('Custom Configuration Tests', function() {\r\n    this.timeout(5000);\r\n\r\n    before(server.setUp.bind(null, 'custom-config'));\r\n    after(server.tearDown);\r\n\r\n    it('should include MiniProfiler javascript with custom settings', function(done) {\r\n      server.get('/', (err, response, body) => {\r\n        var ids = JSON.parse(response.headers['x-miniprofiler-ids']);\r\n        expect(ids).to.have.lengthOf(1);\r\n\r\n        expect(body.trim()).to.be.equal(`<script async type=\"text/javascript\" id=\"mini-profiler\" src=\"/mini-profiler-resources/includes.js?v=${pkg.version}\" data-version=\"${pkg.version}\" data-path=\"/mini-profiler-resources/\" data-current-id=\"${ids[0]}\" data-ids=\"${ids[0]}\" data-position=\"right\" data-trivial=\"true\" data-children=\"false\" data-max-traces=\"15\" data-controls=\"true\" data-authorized=\"true\" data-toggle-shortcut=\"\" data-start-hidden=\"false\" data-trivial-milliseconds=\"2.5\"></script>`);\r\n        done();\r\n      });\r\n    });\r\n\r\n    it('should get/set timing from redis storage', function(done) {\r\n      server.get('/?key=value', (err, response, body) => {\r\n        var ids = JSON.parse(response.headers['x-miniprofiler-ids']);\r\n        expect(ids).to.have.lengthOf(1);\r\n\r\n        server.post('/mini-profiler-resources/results', { id: ids[0], popup: 1 }, (err, response, body) => {\r\n          var result = JSON.parse(body);\r\n          expect(result.Id).to.equal(ids[0]);\r\n          expect(result.Name).to.equal('/?key=value');\r\n          expect(result.Root.Children).to.be.empty;\r\n\r\n          done();\r\n        });\r\n      });\r\n    });\r\n\r\n    it('should not get timing about from ignored paths', function(done) {\r\n      server.get('/hidden', (err, response, body) => {\r\n        expect(response.headers).to.not.include.keys('x-miniprofiler-ids');\r\n        done();\r\n      });\r\n    });\r\n\r\n  });\r\n};\r\n"
  },
  {
    "path": "tests/index.js",
    "content": "'use strict';\r\n\r\nvar fs = require('fs');\r\nvar servers = require('./servers');\r\n\r\nvar testCases = fs.readdirSync('./tests').filter((file) => file.endsWith('-test.js'));\r\n\r\nfor (var server of servers) {\r\n  describe(`[${server.framework}]`, function() {\r\n    for (var testCase of testCases) {\r\n      require(`./${testCase}`)(server);\r\n    }\r\n  });\r\n}\r\n"
  },
  {
    "path": "tests/render-test.js",
    "content": "'use strict';\r\n\r\nvar expect = require('chai').expect;\r\n\r\nmodule.exports = function(server) {\r\n\r\n  describe('Render Tests', function() {\r\n    before(server.setUp.bind(null, 'render'));\r\n    after(server.tearDown);\r\n\r\n    it('Should add render step', function(done) {\r\n      server.get('/', (err, response) => {\r\n        var ids = JSON.parse(response.headers['x-miniprofiler-ids']);\r\n        expect(ids).to.have.lengthOf(1);\r\n\r\n        server.post('/mini-profiler-resources/results', { id: ids[0], popup: 1 }, (err, response, body) => {\r\n          var result = JSON.parse(body);\r\n          expect(result.Id).to.equal(ids[0]);\r\n          expect(result.Name).to.equal('/');\r\n          expect(result.Root.Children).to.have.lengthOf(1);\r\n\r\n          expect(result.Root.Children[0].Name).to.equal('Render: index');\r\n          expect(result.Root.Children[0].Children).to.be.empty;\r\n\r\n          done();\r\n        });\r\n      });\r\n    });\r\n\r\n    it('Should add render step inside another step', function(done) {\r\n      server.get('/inside-step', (err, response) => {\r\n        var ids = JSON.parse(response.headers['x-miniprofiler-ids']);\r\n        expect(ids).to.have.lengthOf(1);\r\n\r\n        server.post('/mini-profiler-resources/results', { id: ids[0], popup: 1 }, (err, response, body) => {\r\n          var result = JSON.parse(body);\r\n          \r\n          expect(result.Id).to.equal(ids[0]);\r\n          expect(result.Name).to.equal('/inside-step');\r\n          expect(result.Root.Children).to.have.lengthOf(1);\r\n\r\n          expect(result.Root.Children[0].Name).to.equal('Step 1');\r\n          expect(result.Root.Children[0].Children).to.have.lengthOf(1);\r\n          expect(result.Root.Children[0].CustomTimings).to.have.property('custom');\r\n          expect(result.Root.Children[0].CustomTimings.custom).to.have.lengthOf(1);\r\n\r\n          expect(result.Root.Children[0].Children[0].Name).to.be.equal('Render: index');\r\n          expect(result.Root.Children[0].Children[0].Children).to.be.empty;\r\n\r\n          done();\r\n        });\r\n      });\r\n    });\r\n\r\n  });\r\n\r\n};\r\n"
  },
  {
    "path": "tests/servers/async-provider.js",
    "content": "'use strict';\n\nmodule.exports = function(obj) {\n  return {\n    name: 'dummy-async',\n    handler: function(req, res, next) {\n      obj.asyncFn = function() {\n        const timing = req.miniprofiler.startTimeQuery('async', 'dummy call');\n\n        return new Promise(resolve => {\n          setTimeout(() => {\n            req.miniprofiler.stopTimeQuery(timing);\n            resolve();\n          }, 25);\n        });\n      };\n\n      next();\n    }\n  };\n};\n"
  },
  {
    "path": "tests/servers/dummy-module.js",
    "content": "'use strict';\n\nmodule.exports = {\n\tasyncFn: () => Promise.resolve()\n};\n"
  },
  {
    "path": "tests/servers/dummy-provider.js",
    "content": "'use strict';\r\n\r\nmodule.exports = function() {\r\n  return {\r\n    name: 'dummy',\r\n    handler: function(req, res, next) {\r\n      next();\r\n    }\r\n  };\r\n};"
  },
  {
    "path": "tests/servers/express/async.js",
    "content": "'use strict';\n\nvar miniprofiler = require('../../../lib/miniprofiler.js');\nvar dummyModule = require('../dummy-module');\nvar express = require('express');\n\nvar app = express();\n\napp.use(miniprofiler.express());\napp.use(miniprofiler.express.for(require('../async-provider.js')(dummyModule)));\n\napp.get('/', (req, res) => {\n\tdummyModule.asyncFn().then(() => {\n\t\tPromise.resolve(req.query.once ? undefined : dummyModule.asyncFn())\n      .then(() => res.send(res.locals.miniprofiler.include()));\n\t});\n});\n\nmodule.exports = app;\n"
  },
  {
    "path": "tests/servers/express/custom-config.js",
    "content": "'use strict';\r\n\r\nvar miniprofiler = require('../../../lib/miniprofiler.js');\r\nvar express = require('express');\r\nvar ip = require('docker-ip');\r\nvar redis = require('redis');\r\nvar client = redis.createClient(6060, ip());\r\n\r\nvar app = express();\r\n\r\nminiprofiler.configure({\r\n\tpopupRenderPosition: 'right',\r\n\tstorage: new miniprofiler.storage.RedisStorage(client),\r\n  ignoredPaths: [ '/hidden' ]\r\n});\r\n\r\napp.use(miniprofiler.express());\r\n\r\napp.get('/', (req, res) => {\r\n\tres.send(res.locals.miniprofiler.include());\r\n});\r\n\r\napp.get('/hidden', (req, res) => {\r\n  res.send('This won\\'t be profiled.');\r\n});\r\n\r\nmodule.exports = app;\r\n"
  },
  {
    "path": "tests/servers/express/default.js",
    "content": "'use strict';\r\n\r\nvar miniprofiler = require('../../../lib/miniprofiler.js');\r\nvar express = require('express');\r\n\r\nvar app = express();\r\n\r\napp.use(miniprofiler.express());\r\napp.use(miniprofiler.express.for(require('../dummy-provider.js')()));\r\n\r\napp.get('/', (req, res) => {\r\n\tres.send(res.locals.miniprofiler.include());\r\n});\r\n\r\napp.get('/step', (req, res) => {\r\n  req.miniprofiler.step('Step', () => {\r\n    res.send(res.locals.miniprofiler.include());\r\n  });\r\n});\r\n\r\napp.get('/step-two', (req, res) => {\r\n  req.miniprofiler.step('Step 1', () => {\r\n    req.miniprofiler.step('Step 2', () => {\r\n      res.send(res.locals.miniprofiler.include());\r\n    });\r\n  });\r\n});\r\n\r\napp.get('/step-parallel', (req, res) => {\r\n\tvar count = 0;\r\n\tvar finish = () => {\r\n\t\tif (++count == 2)\r\n\t\t\tres.send(res.locals.miniprofiler.include());\r\n\t};\r\n\r\n  req.miniprofiler.step('Step 1', finish);\r\n  req.miniprofiler.step('Step 2', finish);\r\n});\r\n\r\napp.get('/js-sleep', function(req, res) {\r\n\treq.miniprofiler.timeQuery('custom', 'Sleeping...', setTimeout, function() {\r\n\t\tres.send(res.locals.miniprofiler.include());\r\n\t}, 50);\r\n});\r\n\r\napp.get('/js-sleep-start-stop', function(req, res) {\r\n\tvar timing = req.miniprofiler.startTimeQuery('custom', 'Sleeping...');\r\n\tsetTimeout(function() {\r\n\t\treq.miniprofiler.stopTimeQuery(timing);\r\n\t\tres.send(res.locals.miniprofiler.include());\r\n\t}, 50);\r\n});\r\n\r\nmodule.exports = app;\r\n"
  },
  {
    "path": "tests/servers/express/index.js",
    "content": "'use strict';\r\n\r\nvar server;\r\n\r\nmodule.exports = {\r\n  start: function(name, port, done) {\r\n    var app = require(`./${name}.js`);\r\n    server = app.listen(port, done);\r\n  },\r\n  stop: function(done) {\r\n    server.close(done);\r\n  }\r\n};\r\n"
  },
  {
    "path": "tests/servers/express/render.js",
    "content": "'use strict';\r\n\r\nvar miniprofiler = require('../../../lib/miniprofiler.js');\r\nvar express = require('express');\r\n\r\nvar app = express();\r\n\r\napp.use(miniprofiler.express());\r\napp.set('view engine', 'pug');\r\napp.set('views', './tests/servers/views');\r\n\r\napp.get('/', (req, res) => {\r\n  res.render('index', { title: 'Hey', message: 'Hello there!' });\r\n});\r\n\r\napp.get('/inside-step', (req, res) => {\r\n  req.miniprofiler.step('Step 1', (unstep) => {\r\n    req.miniprofiler.timeQuery('custom', 'Sleeping...', setTimeout, function() {\r\n      res.render('index', { title: 'Hey', message: 'Hello there!' });\r\n      unstep();\r\n    }, 50);\r\n  });\r\n});\r\n\r\nmodule.exports = app;\r\n"
  },
  {
    "path": "tests/servers/express/unauthorized.js",
    "content": "'use strict';\r\n\r\nvar miniprofiler = require('../../../lib/miniprofiler.js');\r\nvar express = require('express');\r\n\r\nvar app = express();\r\n\r\nvar options = {\r\n  authorize: (req) => {\r\n    return false;\r\n  }\r\n};\r\n\r\napp.use(miniprofiler.express(options));\r\n\r\napp.get('/', (req, res) => {\r\n\tres.send(res.locals.miniprofiler.include());\r\n});\r\n\r\nmodule.exports = app;\r\n"
  },
  {
    "path": "tests/servers/express/unprofiled.js",
    "content": "'use strict';\r\n\r\nvar miniprofiler = require('../../../lib/miniprofiler.js');\r\nvar express = require('express');\r\n\r\nvar app = express();\r\n\r\nvar options = {\r\n  enable: (req) => {\r\n    return false;\r\n  }\r\n};\r\n\r\napp.use(miniprofiler.express(options));\r\n\r\napp.get('/', (req, res) => {\r\n\treq.miniprofiler.timeQuery('custom', 'Sleeping...', setTimeout, function() {\r\n    req.miniprofiler.step('Step 1', () => {\r\n      res.send(res.locals.miniprofiler.include());\r\n    });\r\n\t}, 50);\r\n});\r\n\r\nmodule.exports = app;\r\n"
  },
  {
    "path": "tests/servers/hapi/async.js",
    "content": "'use strict';\n\nvar miniprofiler = require('../../../lib/miniprofiler.js');\nvar dummyModule = require('../dummy-module');\nconst Hapi = require('hapi');\n\nconst server = new Hapi.Server();\nserver.connection({ port: 8083 });\n\nserver.register(miniprofiler.hapi(), (err) => {\n  if (err) throw err;\n});\n\nserver.register(miniprofiler.hapi.for(require('../async-provider.js')(dummyModule)), (err) => {\n  if (err) throw err;\n});\n\nserver.route({\n  method: 'GET',\n  path:'/',\n  handler: function(request, reply) {\n    dummyModule.asyncFn().then(() => {\n      Promise.resolve(request.query.once ? undefined : dummyModule.asyncFn())\n        .then(() => reply(request.app.miniprofiler.include()));\n    });\n  }\n});\n\nmodule.exports = server;\n"
  },
  {
    "path": "tests/servers/hapi/custom-config.js",
    "content": "'use strict';\r\n\r\nvar miniprofiler = require('../../../lib/miniprofiler.js');\r\n\r\nconst Hapi = require('hapi');\r\n\r\nvar ip = require('docker-ip');\r\nvar redis = require('redis');\r\nvar client = redis.createClient(6060, ip());\r\n\r\nconst server = new Hapi.Server();\r\nserver.connection({ port: 8083 });\r\n\r\nminiprofiler.configure({\r\n\tpopupRenderPosition: 'right',\r\n\tstorage: new miniprofiler.storage.RedisStorage(client),\r\n  ignoredPaths: [ '/hidden' ]\r\n});\r\n\r\nserver.register(miniprofiler.hapi(), (err) => {\r\n  if (err) throw (err);\r\n});\r\n\r\nserver.route({\r\n  method: 'GET',\r\n  path:'/',\r\n  handler: function(request, reply) {\r\n    return reply(request.app.miniprofiler.include());\r\n  }\r\n});\r\n\r\nserver.route({\r\n  method: 'GET',\r\n  path:'/hidden',\r\n  handler: function(request, reply) {\r\n    return reply('This won\\'t be profiled.');\r\n  }\r\n});\r\n\r\nmodule.exports = server;\r\n"
  },
  {
    "path": "tests/servers/hapi/default.js",
    "content": "'use strict';\r\n\r\nvar miniprofiler = require('../../../lib/miniprofiler.js');\r\nconst Hapi = require('hapi');\r\n\r\nconst server = new Hapi.Server();\r\nserver.connection({ port: 8083 });\r\n\r\nserver.register(miniprofiler.hapi(), (err) => {\r\n  if (err) throw err;\r\n});\r\n\r\nserver.register(miniprofiler.hapi.for(require('../dummy-provider.js')()), (err) => {\r\n  if (err) throw err;\r\n});\r\n\r\nserver.route({\r\n  method: 'GET',\r\n  path:'/',\r\n  handler: function(request, reply) {\r\n    return reply(request.app.miniprofiler.include());\r\n  }\r\n});\r\n\r\nserver.route({\r\n  method: 'GET',\r\n  path:'/step',\r\n  handler: function(request, reply) {\r\n    request.raw.req.miniprofiler.step('Step', () => {\r\n      return reply(request.app.miniprofiler.include());\r\n    });\r\n  }\r\n});\r\n\r\nserver.route({\r\n  method: 'GET',\r\n  path:'/step-two',\r\n  handler: function(request, reply) {\r\n    request.raw.req.miniprofiler.step('Step 1', () => {\r\n      request.raw.req.miniprofiler.step('Step 2', () => {\r\n        return reply(request.app.miniprofiler.include());\r\n      });\r\n    });\r\n  }\r\n});\r\n\r\nserver.route({\r\n  method: 'GET',\r\n  path:'/step-parallel',\r\n  handler: function(request, reply) {\r\n    var count = 0;\r\n    var finish = () => {\r\n    if (++count == 2)\r\n      return reply(request.app.miniprofiler.include());\r\n    };\r\n\r\n    request.raw.req.miniprofiler.step('Step 1', finish);\r\n    request.raw.req.miniprofiler.step('Step 2', finish);\r\n  }\r\n});\r\n\r\nserver.route({\r\n  method: 'GET',\r\n  path:'/js-sleep',\r\n  handler: function(request, reply) {\r\n    request.raw.req.miniprofiler.timeQuery('custom', 'Sleeping...', setTimeout, () => {\r\n      return reply(request.app.miniprofiler.include());\r\n    }, 50);\r\n  }\r\n});\r\n\r\nserver.route({\r\n  method: 'GET',\r\n  path:'/js-sleep-start-stop',\r\n  handler: function(request, reply) {\r\n    var timing = request.raw.req.miniprofiler.startTimeQuery('custom', 'Sleeping...');\r\n    setTimeout(function() {\r\n      request.raw.req.miniprofiler.stopTimeQuery(timing);\r\n      return reply(request.app.miniprofiler.include());\r\n    }, 50);\r\n  }\r\n});\r\n\r\nmodule.exports = server;\r\n"
  },
  {
    "path": "tests/servers/hapi/index.js",
    "content": "'use strict';\r\n\r\nvar server;\r\n\r\nmodule.exports = {\r\n  start: function(name, port, done) {\r\n    server = require(`./${name}.js`);\r\n    server.start(done);\r\n  },\r\n  stop: function(done) {\r\n    server.stop({ }, done);\r\n  }\r\n};\r\n"
  },
  {
    "path": "tests/servers/hapi/render.js",
    "content": "'use strict';\r\n\r\nvar miniprofiler = require('../../../lib/miniprofiler.js');\r\nconst Hapi = require('hapi');\r\nconst vision = require('vision');\r\n\r\nconst server = new Hapi.Server();\r\nserver.connection({ port: 8083 });\r\n\r\nserver.register(miniprofiler.hapi(), (err) => {\r\n  if (err) throw (err);\r\n});\r\n\r\nserver.register(vision, (err) => {\r\n  if (err) throw (err);\r\n\r\n  server.views({\r\n    engines: { pug: require('pug') },\r\n    path: './tests/servers/views'\r\n  });\r\n\r\n  miniprofiler.hapi().vision(server);\r\n});\r\n\r\nserver.route({\r\n  method: 'GET',\r\n  path:'/',\r\n  handler: function(request, reply) {\r\n    reply.view('index', { title: 'Hey', message: 'Hello there!' });\r\n  }\r\n});\r\n\r\nserver.route({\r\n  method: 'GET',\r\n  path:'/inside-step',\r\n  handler: function(request, reply) {\r\n    request.app.miniprofiler.step('Step 1', (unstep) => {\r\n      request.app.miniprofiler.timeQuery('custom', 'Sleeping...', setTimeout, function() {\r\n        reply.view('index', { title: 'Hey', message: 'Hello there!' });\r\n        unstep();\r\n      }, 50);\r\n    });\r\n  }\r\n});\r\n\r\nmodule.exports = server;\r\n"
  },
  {
    "path": "tests/servers/hapi/unauthorized.js",
    "content": "'use strict';\r\n\r\nvar miniprofiler = require('../../../lib/miniprofiler.js');\r\nconst Hapi = require('hapi');\r\n\r\nconst server = new Hapi.Server();\r\nserver.connection({ port: 8083 });\r\n\r\nvar options = {\r\n  authorize: (req) => {\r\n    return false;\r\n  }\r\n};\r\n\r\nserver.register(miniprofiler.hapi(options), (err) => {\r\n  if (err) throw (err);\r\n});\r\n\r\nserver.route({\r\n  method: 'GET',\r\n  path:'/',\r\n  handler: function(request, reply) {\r\n    return reply(request.app.miniprofiler.include());\r\n  }\r\n});\r\n\r\nmodule.exports = server;\r\n"
  },
  {
    "path": "tests/servers/hapi/unprofiled.js",
    "content": "'use strict';\r\n\r\nvar miniprofiler = require('../../../lib/miniprofiler.js');\r\nconst Hapi = require('hapi');\r\n\r\nconst server = new Hapi.Server();\r\nserver.connection({ port: 8083 });\r\n\r\nvar options = {\r\n  enable: (req) => {\r\n    return false;\r\n  }\r\n};\r\n\r\nserver.register(miniprofiler.hapi(options), (err) => {\r\n  if (err) throw (err);\r\n});\r\n\r\nserver.route({\r\n  method: 'GET',\r\n  path:'/',\r\n  handler: function(request, reply) {\r\n    request.raw.req.miniprofiler.timeQuery('custom', 'Sleeping...', setTimeout, () => {\r\n      request.raw.req.miniprofiler.step('Step 1', () => {\r\n        return reply(request.app.miniprofiler.include());\r\n      });\r\n    }, 50);\r\n  }\r\n});\r\n\r\nmodule.exports = server;\r\n"
  },
  {
    "path": "tests/servers/index.js",
    "content": "'use strict';\r\n\r\nvar request = require('request');\r\nvar frameworks = {\r\n  'koa': { 'port': 8081 },\r\n  'express': { 'port': 8082 },\r\n  'hapi': { 'port': 8083 }\r\n};\r\n\r\nvar all = [ ];\r\n\r\nfor (let fw in frameworks) {\r\n  var server = require(`./${fw}`);\r\n  server.framework = fw;\r\n  frameworks[fw].server = server;\r\n\r\n  server.setUp = function(name, done) {\r\n    Object.keys(require.cache).forEach((key) => { delete require.cache[key]; });\r\n    frameworks[fw].server.start(name, frameworks[fw].port, done);\r\n  };\r\n\r\n  server.tearDown = function(done) {\r\n    frameworks[fw].server.stop(done);\r\n  };\r\n\r\n  server.get = (path, cb) => {\r\n    request.get(`http://localhost:${frameworks[fw].port}${path}`, (err, response, body) => {\r\n      cb(err, response, body);\r\n    });\r\n  };\r\n\r\n  server.post = (path, params, cb) => {\r\n    request.post({url: `http://localhost:${frameworks[fw].port}${path}`, form: params }, (err, response, body) => {\r\n      cb(err, response, body);\r\n    });\r\n  };\r\n\r\n  all.push(server);\r\n}\r\n\r\nmodule.exports = all;\r\n"
  },
  {
    "path": "tests/servers/koa/async.js",
    "content": "'use strict';\n\nvar miniprofiler = require('../../../lib/miniprofiler.js');\nvar dummyModule = require('../dummy-module');\nvar koa = require('koa');\nvar route = require('koa-route');\nvar app = koa();\n\napp.use(miniprofiler.koa());\napp.use(miniprofiler.koa.for(require('../async-provider.js')(dummyModule)));\n\napp.use(route.get('/', function *(){\n  yield dummyModule.asyncFn().then(() => {\n    return Promise.resolve(this.query.once ? undefined : dummyModule.asyncFn())\n      .then(() => { this.body = this.state.miniprofiler.include(); });\n  });\n}));\n\nmodule.exports = app;\n"
  },
  {
    "path": "tests/servers/koa/custom-config.js",
    "content": "'use strict';\r\n\r\nvar miniprofiler = require('../../../lib/miniprofiler.js');\r\nvar koa = require('koa');\r\nvar route = require('koa-route');\r\nvar app = koa();\r\nvar ip = require('docker-ip');\r\nvar redis = require('redis');\r\n\r\nvar client = redis.createClient(6060, ip());\r\n\r\nminiprofiler.configure({\r\n\tpopupRenderPosition: 'right',\r\n\tstorage: new miniprofiler.storage.RedisStorage(client),\r\n  ignoredPaths: [ '/hidden' ]\r\n});\r\n\r\napp.use(miniprofiler.koa());\r\n\r\napp.use(route.get('/', function *(){\r\n  this.body = this.state.miniprofiler.include();\r\n}));\r\n\r\napp.use(route.get('/hidden', function *(){\r\n  this.body = 'This won\\'t be profiled.';\r\n}));\r\n\r\nmodule.exports = app;\r\n"
  },
  {
    "path": "tests/servers/koa/default.js",
    "content": "'use strict';\r\n\r\nvar miniprofiler = require('../../../lib/miniprofiler.js');\r\nvar koa = require('koa');\r\nvar route = require('koa-route');\r\nvar app = koa();\r\n\r\napp.use(miniprofiler.koa());\r\napp.use(miniprofiler.koa.for(require('../dummy-provider.js')()));\r\n\r\napp.use(route.get('/', function *(){\r\n  this.body = this.state.miniprofiler.include();\r\n}));\r\n\r\napp.use(route.get('/step', function *(){\r\n  this.req.miniprofiler.step('Step', () => {\r\n    this.body = this.state.miniprofiler.include();\r\n  });\r\n}));\r\n\r\napp.use(route.get('/step-two', function *(){\r\n  this.req.miniprofiler.step('Step 1', () => {\r\n    this.req.miniprofiler.step('Step 2', () => {\r\n      this.body = this.state.miniprofiler.include();\r\n    });\r\n  });\r\n}));\r\n\r\napp.use(route.get('/step-parallel', function *(){\r\n\tvar count = 0;\r\n\tvar finish = () => {\r\n\t\tif (++count == 2)\r\n      this.body = this.state.miniprofiler.include();\r\n\t};\r\n\r\n  this.req.miniprofiler.step('Step 1', finish);\r\n  this.req.miniprofiler.step('Step 2', finish);\r\n}));\r\n\r\napp.use(route.get('/js-sleep', function *(){\r\n  yield new Promise((resolve, reject) => {\r\n    this.req.miniprofiler.timeQuery('custom', 'Sleeping...', setTimeout, () => {\r\n      this.body = this.state.miniprofiler.include();\r\n      resolve();\r\n    }, 50);\r\n  });\r\n}));\r\n\r\napp.use(route.get('/js-sleep-start-stop', function *(){\r\n  yield new Promise((resolve, reject) => {\r\n    var timing = this.req.miniprofiler.startTimeQuery('custom', 'Sleeping...');\r\n    setTimeout(() => {\r\n      this.req.miniprofiler.stopTimeQuery(timing);\r\n      this.body = this.state.miniprofiler.include();\r\n      resolve();\r\n    }, 50);\r\n  });\r\n}));\r\n\r\nmodule.exports = app;\r\n"
  },
  {
    "path": "tests/servers/koa/index.js",
    "content": "'use strict';\r\n\r\nvar server;\r\n\r\nmodule.exports = {\r\n  start: function(name, port, done) {\r\n    var app = require(`./${name}.js`);\r\n    server = app.listen(port, done);\r\n  },\r\n  stop: function(done) {\r\n    server.close(done);\r\n  }\r\n};\r\n"
  },
  {
    "path": "tests/servers/koa/render.js",
    "content": "'use strict';\r\n\r\nvar miniprofiler = require('../../../lib/miniprofiler.js');\r\nvar koa = require('koa');\r\nvar route = require('koa-route');\r\nvar views = require('koa-views');\r\nvar app = koa();\r\n\r\napp.use(views('./tests/servers/views', { extension: 'pug' }));\r\n\r\napp.use(miniprofiler.koa());\r\n\r\napp.use(route.get('/', function *(){\r\n  yield this.render('index', { title: 'Hey', message: 'Hello there!' });\r\n}));\r\n\r\napp.use(route.get('/inside-step', function *(){\r\n  yield new Promise((resolve, reject) => {\r\n    this.req.miniprofiler.step('Step 1', (unstep) => {\r\n      this.req.miniprofiler.timeQuery('custom', 'Sleeping...', setTimeout, () => {\r\n        this.render('index', { title: 'Hey', message: 'Hello there!' }).then(() => {\r\n          unstep();\r\n          resolve();\r\n        });\r\n      }, 50);\r\n    });\r\n  });\r\n}));\r\n\r\nmodule.exports = app;\r\n"
  },
  {
    "path": "tests/servers/koa/unauthorized.js",
    "content": "'use strict';\r\n\r\nvar miniprofiler = require('../../../lib/miniprofiler.js');\r\nvar koa = require('koa');\r\nvar route = require('koa-route');\r\n\r\nvar app = koa();\r\n\r\nvar options = {\r\n  authorize: (req) => {\r\n    return false;\r\n  }\r\n};\r\n\r\napp.use(miniprofiler.koa(options));\r\n\r\napp.use(route.get('/', function *(){\r\n  this.body = this.state.miniprofiler.include();\r\n}));\r\n\r\nmodule.exports = app;\r\n"
  },
  {
    "path": "tests/servers/koa/unprofiled.js",
    "content": "'use strict';\r\n\r\nvar miniprofiler = require('../../../lib/miniprofiler.js');\r\nvar koa = require('koa');\r\nvar route = require('koa-route');\r\n\r\nvar app = koa();\r\n\r\nvar options = {\r\n  enable: (req) => {\r\n    return false;\r\n  }\r\n};\r\n\r\napp.use(miniprofiler.koa(options));\r\n\r\napp.use(route.get('/', function *(){\r\n  yield new Promise((resolve, reject) => {\r\n    this.req.miniprofiler.timeQuery('custom', 'Sleeping...', setTimeout, () => {\r\n      this.req.miniprofiler.step('Step 1', () => {\r\n        this.body = this.state.miniprofiler.include();\r\n        resolve();\r\n      });\r\n    }, 50);\r\n  });\r\n}));\r\n\r\nmodule.exports = app;\r\n"
  },
  {
    "path": "tests/servers/views/index.pug",
    "content": "html\r\n  head\r\n    title= title\r\n  body\r\n    h1= message"
  },
  {
    "path": "tests/share-test.js",
    "content": "'use strict';\r\n\r\nvar expect = require('chai').expect;\r\n\r\nmodule.exports = function(server) {\r\n  describe('Share Tests', function() {\r\n    before(server.setUp.bind(null, 'default'));\r\n    after(server.tearDown);\r\n\r\n    var expectOkResponse = (done) => (err, response, body) => {\r\n      expect(response.statusCode).to.be.equal(200);\r\n      expect(response.headers['content-type']).to.be.equal('text/html; charset=utf-8');\r\n      done();\r\n    };\r\n\r\n    var expectNotFoundResponse = (done) => (err, response, body) => {\r\n      expect(response.statusCode).to.be.equal(404);\r\n      expect(response.headers['content-type']).to.be.equal('text/plain; charset=utf-8');\r\n      done();\r\n    };\r\n\r\n    it('[GET] Valid profiled id should render share page', function(done) {\r\n      server.get('/', (err, response) => {\r\n        var ids = JSON.parse(response.headers['x-miniprofiler-ids']);\r\n\r\n        server.get(`/mini-profiler-resources/results?id=${ids[0]}`, expectOkResponse(done));\r\n\r\n      });\r\n    });\r\n\r\n    it('[POST] Valid profiled id should render share page', function(done) {\r\n      server.get('/', (err, response) => {\r\n        var ids = JSON.parse(response.headers['x-miniprofiler-ids']);\r\n\r\n        server.post('/mini-profiler-resources/results', { id: ids[0] }, expectOkResponse(done));\r\n\r\n      });\r\n    });\r\n\r\n    it('[GET] Invalid profiled id should render 404', function(done) {\r\n      server.get('/mini-profiler-resources/results?id=123', expectNotFoundResponse(done));\r\n    });\r\n\r\n    it('[POST] Invalid profiled id should render 404', function(done) {\r\n      server.post('/mini-profiler-resources/results', { id: 123 }, expectNotFoundResponse(done));\r\n    });\r\n\r\n  });\r\n\r\n};\r\n"
  },
  {
    "path": "tests/step-test.js",
    "content": "'use strict';\r\n\r\nvar expect = require('chai').expect;\r\n\r\nmodule.exports = function(server) {\r\n  describe('Step Tests', function() {\r\n    before(server.setUp.bind(null, 'default'));\r\n    after(server.tearDown);\r\n\r\n    it('Index route should not profile any step', function(done) {\r\n      server.get('/', (err, response) => {\r\n        var ids = JSON.parse(response.headers['x-miniprofiler-ids']);\r\n        expect(ids).to.have.lengthOf(1);\r\n\r\n        server.post('/mini-profiler-resources/results', { id: ids[0], popup: 1 }, (err, response, body) => {\r\n          var result = JSON.parse(body);\r\n          expect(result.Id).to.equal(ids[0]);\r\n          expect(result.Name).to.equal('/');\r\n          expect(result.Root.Children).to.be.empty;\r\n\r\n          done();\r\n        });\r\n      });\r\n    });\r\n\r\n    it('/step route should profile one step', function(done) {\r\n      server.get('/step', (err, response) => {\r\n        var ids = JSON.parse(response.headers['x-miniprofiler-ids']);\r\n        expect(ids).to.have.lengthOf(1);\r\n\r\n        server.post('/mini-profiler-resources/results', { id: ids[0], popup: 1 }, (err, response, body) => {\r\n          var result = JSON.parse(body);\r\n          expect(result.Id).to.equal(ids[0]);\r\n          expect(result.Name).to.equal('/step');\r\n          expect(result.Root.Children).to.have.lengthOf(1);\r\n\r\n          expect(result.Root.Children[0].Name).to.equal('Step');\r\n          expect(result.Root.Children[0].Children).to.be.empty;\r\n\r\n          done();\r\n        });\r\n      });\r\n    });\r\n\r\n    it('step-two route should profile two nested step', function(done) {\r\n      server.get('/step-two', (err, response) => {\r\n        var ids = JSON.parse(response.headers['x-miniprofiler-ids']);\r\n        expect(ids).to.have.lengthOf(1);\r\n\r\n        server.post('/mini-profiler-resources/results', { id: ids[0], popup: 1 }, (err, response, body) => {\r\n          var result = JSON.parse(body);\r\n          expect(result.Id).to.equal(ids[0]);\r\n          expect(result.Name).to.equal('/step-two');\r\n          expect(result.Root.Children).to.have.lengthOf(1);\r\n\r\n          expect(result.Root.Children[0].Name).to.equal('Step 1');\r\n          expect(result.Root.Children[0].Children).to.have.lengthOf(1);\r\n\r\n          expect(result.Root.Children[0].Children[0].Name).to.equal('Step 2');\r\n          expect(result.Root.Children[0].Children[0].Children).to.be.empty;\r\n          done();\r\n        });\r\n      });\r\n    });\r\n\r\n    it('/step-parallel route should profile two nested step', function(done) {\r\n      server.get('/step-parallel', (err, response) => {\r\n        var ids = JSON.parse(response.headers['x-miniprofiler-ids']);\r\n        expect(ids).to.have.lengthOf(1);\r\n\r\n        server.post('/mini-profiler-resources/results', { id: ids[0], popup: 1 }, (err, response, body) => {\r\n          var result = JSON.parse(body);\r\n          expect(result.Id).to.equal(ids[0]);\r\n          expect(result.Name).to.equal('/step-parallel');\r\n          expect(result.Root.Children).to.have.lengthOf(2);\r\n\r\n          expect(result.Root.Children[0].Name).to.equal('Step 1');\r\n          expect(result.Root.Children[0].Children).to.be.empty;\r\n\r\n          expect(result.Root.Children[1].Name).to.equal('Step 2');\r\n          expect(result.Root.Children[1].Children).to.be.empty;\r\n          done();\r\n        });\r\n      });\r\n    });\r\n  });\r\n};\r\n"
  },
  {
    "path": "tests/timequery-test.js",
    "content": "'use strict';\r\n\r\nvar expect = require('chai').expect;\r\n\r\nmodule.exports = function(server) {\r\n  describe('Time Query Tests', function() {\r\n    before(server.setUp.bind(null, 'default'));\r\n    after(server.tearDown);\r\n\r\n    for(let url of ['/js-sleep', '/js-sleep-start-stop']) {\r\n      it(`Custom timed query should be profiled for url '${url}'`, function(done) {\r\n        server.get(url, (err, response) => {\r\n          var ids = JSON.parse(response.headers['x-miniprofiler-ids']);\r\n          expect(ids).to.have.lengthOf(1);\r\n\r\n          server.post('/mini-profiler-resources/results/', { id: ids[0], popup: 1 }, (err, response, body) => {\r\n            var result = JSON.parse(body);\r\n\r\n            expect(result.Id).to.equal(ids[0]);\r\n            expect(result.Name).to.equal(url);\r\n            expect(result.DurationMilliseconds).to.be.above(40);\r\n            expect(result.Root.Children).to.be.empty;\r\n            expect(result.Root.CustomTimings).to.have.property('custom');\r\n            expect(result.Root.CustomTimings.custom).to.have.lengthOf(1);\r\n\r\n            expect(result.Root.CustomTimings.custom[0].ExecuteType).to.be.equal('custom');\r\n            expect(result.Root.CustomTimings.custom[0].CommandString).to.be.equal('Sleeping...');\r\n            expect(result.Root.CustomTimings.custom[0].DurationMilliseconds).to.be.below(result.DurationMilliseconds);\r\n            done();\r\n          });\r\n        });\r\n\r\n      });\r\n    }\r\n\r\n  });\r\n};\r\n"
  },
  {
    "path": "tests/unauthorized-test.js",
    "content": "'use strict';\r\n\r\nvar expect = require('chai').expect;\r\n\r\nmodule.exports = function(server) {\r\n  describe('Unauthorized Tests', function() {\r\n    before(server.setUp.bind(null, 'unauthorized'));\r\n    after(server.tearDown);\r\n\r\n    it('should return profile ID', function(done) {\r\n      server.get('/', (err, response, body) => {\r\n        expect(response.headers).to.include.keys('x-miniprofiler-ids');\r\n        expect(body).to.be.equal('');\r\n        done();\r\n      });\r\n    });\r\n\r\n    it('should not allow user to get timing information from ID', function(done) {\r\n      server.get('/', (err, response) => {\r\n        var ids = JSON.parse(response.headers['x-miniprofiler-ids']);\r\n\r\n        server.post('/mini-profiler-resources/results', { id: ids[0], popup: 1 }, (err, response, body) => {\r\n          expect(response.statusCode).to.be.equal(401);\r\n          expect(body).to.be.equal('');\r\n          done();\r\n        });\r\n      });\r\n    });\r\n\r\n  });\r\n\r\n};\r\n"
  },
  {
    "path": "tests/unprofiled-test.js",
    "content": "'use strict';\r\n\r\nvar expect = require('chai').expect;\r\n\r\nmodule.exports = function(server) {\r\n  describe('Unprofiled Tests', function() {\r\n    before(server.setUp.bind(null, 'unprofiled'));\r\n    after(server.tearDown);\r\n\r\n    it('should not return profile ID', function(done) {\r\n      server.get('/', (err, response) => {\r\n        expect(response.headers).to.not.include.keys('x-miniprofiler-ids');\r\n        done();\r\n      });\r\n    });\r\n\r\n    it('should not include asset', function(done) {\r\n      server.get('/', (err, response, body) => {\r\n        expect(body).to.be.equal('');\r\n        done();\r\n      });\r\n    });\r\n\r\n    var paths = [\r\n      '/',\r\n      '/includes.css',\r\n      '/results',\r\n      '/results?id=2'\r\n    ];\r\n\r\n    paths.forEach((path) => {\r\n      it(`should not respond for '${path}'`, function(done) {\r\n        server.get(`/mini-profiler-resources${path}`, (err, response, body) => {\r\n          expect(response.statusCode).to.be.equal(404);\r\n          expect(response.headers['content-type']).to.be.equal('text/plain; charset=utf-8');\r\n          expect(body).to.be.equal('MiniProfiler is disabled');\r\n          done();\r\n        });\r\n      });\r\n    });\r\n  });\r\n\r\n};\r\n"
  }
]