{"action":"created","comment":{"url":"https://api.github.com/repos/strongloop/loopback-boot/pulls/comments/63143692","id":63143692,"diff_hunk":"@@ -0,0 +1,202 @@\n+var assert = require('assert');\n+var async = require('async');\n+var utils = require('./utils');\n+var path = require('path');\n+var pluginLoader = require('./plugin-loader');\n+var debug = require('debug')('loopback:boot:bootstrapper');\n+var Promise = global.Promise || require('bluebird');\n+\n+module.exports = function(options) {\n+  return new Bootstrapper(options);\n+};\n+\n+module.exports.Bootstrapper = Bootstrapper;\n+\n+function createPromiseCallback() {\n+  var cb;\n+  var promise = new Promise(function(resolve, reject) {\n+    cb = function(err, data) {\n+      if (err) return reject(err);\n+      return resolve(data);\n+    };\n+  });\n+  cb.promise = promise;\n+  return cb;\n+}\n+\n+var builtinPlugins = [\n+  'application', 'datasource', 'model', 'mixin',\n+  'middleware', 'component', 'boot-script', 'swagger',\n+];\n+\n+var builtinPhases = [\n+  'load', 'compile', 'starting', 'start', 'started',\n+];\n+\n+function loadAndRegisterPlugins(bootstrapper, options) {\n+  var loader = pluginLoader(options);\n+  var loaderContext = {};\n+  loader.load(loaderContext);\n+  loader.compile(loaderContext);\n+\n+  for (var i in loaderContext.instructions.pluginScripts) {\n+    bootstrapper.use('/boot/' + i, loaderContext.instructions.pluginScripts[i]);\n+  }\n+}\n+\n+/**\n+ * Create a new Bootstrapper with options\n+ * @param options\n+ * @constructor\n+ */\n+function Bootstrapper(options) {\n+  this.plugins = [];\n+  options = options || {};\n+\n+  if (typeof options === 'string') {\n+    options = { appRootDir: options };\n+  }\n+\n+  var appRootDir = options.appRootDir = options.appRootDir || process.cwd();\n+  var env = options.env || process.env.NODE_ENV || 'development';\n+\n+  var appConfigRootDir = options.appConfigRootDir || appRootDir;\n+\n+  options.rootDir = appConfigRootDir;\n+  options.env = env;\n+  this.options = options;\n+\n+  this.phases = options.phases || builtinPhases;\n+  this.builtinPlugins = options.plugins || builtinPlugins;\n+  assert(Array.isArray(this.phases), 'Invalid phases: ' + this.phases);\n+  assert(Array.isArray(this.plugins), 'Invalid plugins: ' +\n+    this.builtinPlugins);\n+\n+  var self = this;\n+  self.builtinPlugins.forEach(function(p) {\n+    var factory = require('./plugins/' + p);\n+    self.use('/boot/' + p, factory(options));\n+  });\n+\n+  try {\n+    loadAndRegisterPlugins(self, options);\n+  } catch (err) {\n+    debug(err);\n+  }\n+}\n+\n+/**\n+ * Register a handler to a given path\n+ * @param {String} path\n+ * @param {Function} handler\n+ */\n+Bootstrapper.prototype.use = function(path, handler) {\n+  var plugin = {\n+    path: path,\n+    handler: handler,\n+  };\n+  this.plugins.push(plugin);\n+};\n+\n+/**\n+ * Get a list of plugins for the given path\n+ * @param {String} path\n+ * @returns {*}\n+ */\n+Bootstrapper.prototype.getPlugins = function(path) {\n+  if (path[path.length - 1] !== '/') {\n+    path = path + '/';\n+  }\n+  return this.plugins.filter(function(p) {\n+    return p.path.indexOf(path) === 0;\n+  });\n+};\n+\n+/**\n+ * Get a list of extensions for the given path\n+ * @param {String} path\n+ * @returns {*}\n+ */\n+Bootstrapper.prototype.getExtensions = function(path) {\n+  if (path[path.length - 1] !== '/') {\n+    path = path + '/';\n+  }\n+  return this.plugins.filter(function(p) {\n+    if (p.path.indexOf(path) === -1) return false;\n+    var name = p.path.substring(path.length);\n+    return name && name.indexOf('/') === -1;\n+  });\n+};\n+\n+/**\n+ * Add more phases. The order of phases is decided by the sequence of phase\n+ * names\n+ * @param {String[]} phases An array of phase names\n+ * @returns {String[]} New list of phases\n+ */\n+Bootstrapper.prototype.addPhases = function(phases) {\n+  this.phases = utils.mergePhaseNameLists(this.phases, phases || []);\n+  return this.phases;\n+};\n+\n+/**\n+ * Invoke the plugins phase by phase with the given context\n+ * @param {Object} context Context object\n+ * @param {Function} done Callback function. If not provided, a promise will be\n+ * returned\n+ * @returns {*}\n+ */\n+Bootstrapper.prototype.run = function(context, done) {\n+  if (!done) {\n+    done = createPromiseCallback();\n+  }\n+  var options = this.options;\n+  var appRootDir = options.appRootDir = options.appRootDir || process.cwd();\n+  var env = options.env || process.env.NODE_ENV || 'development';\n+\n+  var appConfigRootDir = options.appConfigRootDir || appRootDir;\n+\n+  options.rootDir = appConfigRootDir;\n+  options.env = env;\n+\n+  context = context || {};\n+\n+  var phases = context.phases || this.phases;\n+  var bootPlugins = this.getExtensions('/boot');\n+  async.eachSeries(phases, function(phase, cb1) {\n+    debug('Phase %s', phase);\n+    async.eachSeries(bootPlugins, function(plugin, cb2) {\n+      var result;\n+      if (typeof plugin.handler[phase] === 'function') {\n+        debug('Invoking %s.%s', plugin.handler.name, phase);\n+        try {\n+          if (plugin.handler[phase].length === 2) {\n+            plugin.handler[phase](context, cb2);\n+          } else {\n+            result = plugin.handler[phase](context);\n+            if (typeof Promise !== 'undefined') {\n+              Promise.resolve(result).then(function(value) {\n+                cb2(null, value);\n+              }).catch(function(err) {\n+                debug(err);\n+                cb2(err);\n+              });\n+            } else {\n+              cb2(null, result);\n+            }\n+          }\n+        } catch (err) {\n+          debug(err);","path":"lib/bootstrapper.js","position":189,"original_position":189,"commit_id":"cc61b364e2ba1a41abcdb4552d1a479bb227ef45","original_commit_id":"cc61b364e2ba1a41abcdb4552d1a479bb227ef45","user":{"login":"bajtos","id":1140553,"avatar_url":"https://avatars.githubusercontent.com/u/1140553?v=3","gravatar_id":"","url":"https://api.github.com/users/bajtos","html_url":"https://github.com/bajtos","followers_url":"https://api.github.com/users/bajtos/followers","following_url":"https://api.github.com/users/bajtos/following{/other_user}","gists_url":"https://api.github.com/users/bajtos/gists{/gist_id}","starred_url":"https://api.github.com/users/bajtos/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bajtos/subscriptions","organizations_url":"https://api.github.com/users/bajtos/orgs","repos_url":"https://api.github.com/users/bajtos/repos","events_url":"https://api.github.com/users/bajtos/events{/privacy}","received_events_url":"https://api.github.com/users/bajtos/received_events","type":"User","site_admin":false},"body":"Ditto.","created_at":"2016-05-13T07:41:05Z","updated_at":"2016-05-13T07:41:05Z","html_url":"https://github.com/strongloop/loopback-boot/pull/181#discussion_r63143692","pull_request_url":"https://api.github.com/repos/strongloop/loopback-boot/pulls/181","_links":{"self":{"href":"https://api.github.com/repos/strongloop/loopback-boot/pulls/comments/63143692"},"html":{"href":"https://github.com/strongloop/loopback-boot/pull/181#discussion_r63143692"},"pull_request":{"href":"https://api.github.com/repos/strongloop/loopback-boot/pulls/181"}}},"pull_request":{"url":"https://api.github.com/repos/strongloop/loopback-boot/pulls/181","id":65801382,"html_url":"https://github.com/strongloop/loopback-boot/pull/181","diff_url":"https://github.com/strongloop/loopback-boot/pull/181.diff","patch_url":"https://github.com/strongloop/loopback-boot/pull/181.patch","issue_url":"https://api.github.com/repos/strongloop/loopback-boot/issues/181","number":181,"state":"open","locked":false,"title":"Initial PoC to refactor loopback-boot","user":{"login":"raymondfeng","id":540892,"avatar_url":"https://avatars.githubusercontent.com/u/540892?v=3","gravatar_id":"","url":"https://api.github.com/users/raymondfeng","html_url":"https://github.com/raymondfeng","followers_url":"https://api.github.com/users/raymondfeng/followers","following_url":"https://api.github.com/users/raymondfeng/following{/other_user}","gists_url":"https://api.github.com/users/raymondfeng/gists{/gist_id}","starred_url":"https://api.github.com/users/raymondfeng/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/raymondfeng/subscriptions","organizations_url":"https://api.github.com/users/raymondfeng/orgs","repos_url":"https://api.github.com/users/raymondfeng/repos","events_url":"https://api.github.com/users/raymondfeng/events{/privacy}","received_events_url":"https://api.github.com/users/raymondfeng/received_events","type":"User","site_admin":false},"body":"The current boot process consists of three steps: \r\n- load \r\n- compile\r\n- execute\r\n\r\nIt hard-codes logic to handle various artifact types:\r\n- data source\r\n- model\r\n- mixin\r\n- middleware\r\n- boot script\r\n\r\nThe problems with the current design/implementation are:\r\n- lack of extensibility \r\n- no clean separation of different types of artifacts\r\n\r\nThe PR proposes the following changes:\r\n- refactor logic of processing artifacts into their own classes\r\n- introduce `Container` as the main class for bootstrapping and build a registry of handlers during boot to organize them by a hierarchy denoted by path\r\n- adopt `middleware` like registration and invocation\r\n  - container.use(path, handler)\r\n  - container.run(context, done)\r\n- allow more phases during boot\r\n- explore dependency injection\r\n- \r\n\r\nConnect to #188","created_at":"2016-04-08T15:13:52Z","updated_at":"2016-05-13T07:41:05Z","closed_at":null,"merged_at":null,"merge_commit_sha":"04a91bbece9cfd9e6d7eb96c3d06ddb430dd793d","assignee":{"login":"raymondfeng","id":540892,"avatar_url":"https://avatars.githubusercontent.com/u/540892?v=3","gravatar_id":"","url":"https://api.github.com/users/raymondfeng","html_url":"https://github.com/raymondfeng","followers_url":"https://api.github.com/users/raymondfeng/followers","following_url":"https://api.github.com/users/raymondfeng/following{/other_user}","gists_url":"https://api.github.com/users/raymondfeng/gists{/gist_id}","starred_url":"https://api.github.com/users/raymondfeng/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/raymondfeng/subscriptions","organizations_url":"https://api.github.com/users/raymondfeng/orgs","repos_url":"https://api.github.com/users/raymondfeng/repos","events_url":"https://api.github.com/users/raymondfeng/events{/privacy}","received_events_url":"https://api.github.com/users/raymondfeng/received_events","type":"User","site_admin":false},"milestone":null,"commits_url":"https://api.github.com/repos/strongloop/loopback-boot/pulls/181/commits","review_comments_url":"https://api.github.com/repos/strongloop/loopback-boot/pulls/181/comments","review_comment_url":"https://api.github.com/repos/strongloop/loopback-boot/pulls/comments{/number}","comments_url":"https://api.github.com/repos/strongloop/loopback-boot/issues/181/comments","statuses_url":"https://api.github.com/repos/strongloop/loopback-boot/statuses/cc61b364e2ba1a41abcdb4552d1a479bb227ef45","head":{"label":"strongloop:feature/extensibility","ref":"feature/extensibility","sha":"cc61b364e2ba1a41abcdb4552d1a479bb227ef45","user":{"login":"strongloop","id":3020012,"avatar_url":"https://avatars.githubusercontent.com/u/3020012?v=3","gravatar_id":"","url":"https://api.github.com/users/strongloop","html_url":"https://github.com/strongloop","followers_url":"https://api.github.com/users/strongloop/followers","following_url":"https://api.github.com/users/strongloop/following{/other_user}","gists_url":"https://api.github.com/users/strongloop/gists{/gist_id}","starred_url":"https://api.github.com/users/strongloop/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/strongloop/subscriptions","organizations_url":"https://api.github.com/users/strongloop/orgs","repos_url":"https://api.github.com/users/strongloop/repos","events_url":"https://api.github.com/users/strongloop/events{/privacy}","received_events_url":"https://api.github.com/users/strongloop/received_events","type":"Organization","site_admin":false},"repo":{"id":20100867,"name":"loopback-boot","full_name":"strongloop/loopback-boot","owner":{"login":"strongloop","id":3020012,"avatar_url":"https://avatars.githubusercontent.com/u/3020012?v=3","gravatar_id":"","url":"https://api.github.com/users/strongloop","html_url":"https://github.com/strongloop","followers_url":"https://api.github.com/users/strongloop/followers","following_url":"https://api.github.com/users/strongloop/following{/other_user}","gists_url":"https://api.github.com/users/strongloop/gists{/gist_id}","starred_url":"https://api.github.com/users/strongloop/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/strongloop/subscriptions","organizations_url":"https://api.github.com/users/strongloop/orgs","repos_url":"https://api.github.com/users/strongloop/repos","events_url":"https://api.github.com/users/strongloop/events{/privacy}","received_events_url":"https://api.github.com/users/strongloop/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/strongloop/loopback-boot","description":"Convention-based bootstrapper for LoopBack applications","fork":false,"url":"https://api.github.com/repos/strongloop/loopback-boot","forks_url":"https://api.github.com/repos/strongloop/loopback-boot/forks","keys_url":"https://api.github.com/repos/strongloop/loopback-boot/keys{/key_id}","collaborators_url":"https://api.github.com/repos/strongloop/loopback-boot/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/strongloop/loopback-boot/teams","hooks_url":"https://api.github.com/repos/strongloop/loopback-boot/hooks","issue_events_url":"https://api.github.com/repos/strongloop/loopback-boot/issues/events{/number}","events_url":"https://api.github.com/repos/strongloop/loopback-boot/events","assignees_url":"https://api.github.com/repos/strongloop/loopback-boot/assignees{/user}","branches_url":"https://api.github.com/repos/strongloop/loopback-boot/branches{/branch}","tags_url":"https://api.github.com/repos/strongloop/loopback-boot/tags","blobs_url":"https://api.github.com/repos/strongloop/loopback-boot/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/strongloop/loopback-boot/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/strongloop/loopback-boot/git/refs{/sha}","trees_url":"https://api.github.com/repos/strongloop/loopback-boot/git/trees{/sha}","statuses_url":"https://api.github.com/repos/strongloop/loopback-boot/statuses/{sha}","languages_url":"https://api.github.com/repos/strongloop/loopback-boot/languages","stargazers_url":"https://api.github.com/repos/strongloop/loopback-boot/stargazers","contributors_url":"https://api.github.com/repos/strongloop/loopback-boot/contributors","subscribers_url":"https://api.github.com/repos/strongloop/loopback-boot/subscribers","subscription_url":"https://api.github.com/repos/strongloop/loopback-boot/subscription","commits_url":"https://api.github.com/repos/strongloop/loopback-boot/commits{/sha}","git_commits_url":"https://api.github.com/repos/strongloop/loopback-boot/git/commits{/sha}","comments_url":"https://api.github.com/repos/strongloop/loopback-boot/comments{/number}","issue_comment_url":"https://api.github.com/repos/strongloop/loopback-boot/issues/comments{/number}","contents_url":"https://api.github.com/repos/strongloop/loopback-boot/contents/{+path}","compare_url":"https://api.github.com/repos/strongloop/loopback-boot/compare/{base}...{head}","merges_url":"https://api.github.com/repos/strongloop/loopback-boot/merges","archive_url":"https://api.github.com/repos/strongloop/loopback-boot/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/strongloop/loopback-boot/downloads","issues_url":"https://api.github.com/repos/strongloop/loopback-boot/issues{/number}","pulls_url":"https://api.github.com/repos/strongloop/loopback-boot/pulls{/number}","milestones_url":"https://api.github.com/repos/strongloop/loopback-boot/milestones{/number}","notifications_url":"https://api.github.com/repos/strongloop/loopback-boot/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/strongloop/loopback-boot/labels{/name}","releases_url":"https://api.github.com/repos/strongloop/loopback-boot/releases{/id}","deployments_url":"https://api.github.com/repos/strongloop/loopback-boot/deployments","created_at":"2014-05-23T13:41:51Z","updated_at":"2016-04-19T16:57:44Z","pushed_at":"2016-05-06T04:53:02Z","git_url":"git://github.com/strongloop/loopback-boot.git","ssh_url":"git@github.com:strongloop/loopback-boot.git","clone_url":"https://github.com/strongloop/loopback-boot.git","svn_url":"https://github.com/strongloop/loopback-boot","homepage":null,"size":581,"stargazers_count":35,"watchers_count":35,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":52,"mirror_url":null,"open_issues_count":32,"forks":52,"open_issues":32,"watchers":35,"default_branch":"master"}},"base":{"label":"strongloop:master","ref":"master","sha":"51a699af01c68d61011be2f7258e47e516c1c34e","user":{"login":"strongloop","id":3020012,"avatar_url":"https://avatars.githubusercontent.com/u/3020012?v=3","gravatar_id":"","url":"https://api.github.com/users/strongloop","html_url":"https://github.com/strongloop","followers_url":"https://api.github.com/users/strongloop/followers","following_url":"https://api.github.com/users/strongloop/following{/other_user}","gists_url":"https://api.github.com/users/strongloop/gists{/gist_id}","starred_url":"https://api.github.com/users/strongloop/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/strongloop/subscriptions","organizations_url":"https://api.github.com/users/strongloop/orgs","repos_url":"https://api.github.com/users/strongloop/repos","events_url":"https://api.github.com/users/strongloop/events{/privacy}","received_events_url":"https://api.github.com/users/strongloop/received_events","type":"Organization","site_admin":false},"repo":{"id":20100867,"name":"loopback-boot","full_name":"strongloop/loopback-boot","owner":{"login":"strongloop","id":3020012,"avatar_url":"https://avatars.githubusercontent.com/u/3020012?v=3","gravatar_id":"","url":"https://api.github.com/users/strongloop","html_url":"https://github.com/strongloop","followers_url":"https://api.github.com/users/strongloop/followers","following_url":"https://api.github.com/users/strongloop/following{/other_user}","gists_url":"https://api.github.com/users/strongloop/gists{/gist_id}","starred_url":"https://api.github.com/users/strongloop/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/strongloop/subscriptions","organizations_url":"https://api.github.com/users/strongloop/orgs","repos_url":"https://api.github.com/users/strongloop/repos","events_url":"https://api.github.com/users/strongloop/events{/privacy}","received_events_url":"https://api.github.com/users/strongloop/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/strongloop/loopback-boot","description":"Convention-based bootstrapper for LoopBack applications","fork":false,"url":"https://api.github.com/repos/strongloop/loopback-boot","forks_url":"https://api.github.com/repos/strongloop/loopback-boot/forks","keys_url":"https://api.github.com/repos/strongloop/loopback-boot/keys{/key_id}","collaborators_url":"https://api.github.com/repos/strongloop/loopback-boot/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/strongloop/loopback-boot/teams","hooks_url":"https://api.github.com/repos/strongloop/loopback-boot/hooks","issue_events_url":"https://api.github.com/repos/strongloop/loopback-boot/issues/events{/number}","events_url":"https://api.github.com/repos/strongloop/loopback-boot/events","assignees_url":"https://api.github.com/repos/strongloop/loopback-boot/assignees{/user}","branches_url":"https://api.github.com/repos/strongloop/loopback-boot/branches{/branch}","tags_url":"https://api.github.com/repos/strongloop/loopback-boot/tags","blobs_url":"https://api.github.com/repos/strongloop/loopback-boot/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/strongloop/loopback-boot/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/strongloop/loopback-boot/git/refs{/sha}","trees_url":"https://api.github.com/repos/strongloop/loopback-boot/git/trees{/sha}","statuses_url":"https://api.github.com/repos/strongloop/loopback-boot/statuses/{sha}","languages_url":"https://api.github.com/repos/strongloop/loopback-boot/languages","stargazers_url":"https://api.github.com/repos/strongloop/loopback-boot/stargazers","contributors_url":"https://api.github.com/repos/strongloop/loopback-boot/contributors","subscribers_url":"https://api.github.com/repos/strongloop/loopback-boot/subscribers","subscription_url":"https://api.github.com/repos/strongloop/loopback-boot/subscription","commits_url":"https://api.github.com/repos/strongloop/loopback-boot/commits{/sha}","git_commits_url":"https://api.github.com/repos/strongloop/loopback-boot/git/commits{/sha}","comments_url":"https://api.github.com/repos/strongloop/loopback-boot/comments{/number}","issue_comment_url":"https://api.github.com/repos/strongloop/loopback-boot/issues/comments{/number}","contents_url":"https://api.github.com/repos/strongloop/loopback-boot/contents/{+path}","compare_url":"https://api.github.com/repos/strongloop/loopback-boot/compare/{base}...{head}","merges_url":"https://api.github.com/repos/strongloop/loopback-boot/merges","archive_url":"https://api.github.com/repos/strongloop/loopback-boot/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/strongloop/loopback-boot/downloads","issues_url":"https://api.github.com/repos/strongloop/loopback-boot/issues{/number}","pulls_url":"https://api.github.com/repos/strongloop/loopback-boot/pulls{/number}","milestones_url":"https://api.github.com/repos/strongloop/loopback-boot/milestones{/number}","notifications_url":"https://api.github.com/repos/strongloop/loopback-boot/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/strongloop/loopback-boot/labels{/name}","releases_url":"https://api.github.com/repos/strongloop/loopback-boot/releases{/id}","deployments_url":"https://api.github.com/repos/strongloop/loopback-boot/deployments","created_at":"2014-05-23T13:41:51Z","updated_at":"2016-04-19T16:57:44Z","pushed_at":"2016-05-06T04:53:02Z","git_url":"git://github.com/strongloop/loopback-boot.git","ssh_url":"git@github.com:strongloop/loopback-boot.git","clone_url":"https://github.com/strongloop/loopback-boot.git","svn_url":"https://github.com/strongloop/loopback-boot","homepage":null,"size":581,"stargazers_count":35,"watchers_count":35,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":52,"mirror_url":null,"open_issues_count":32,"forks":52,"open_issues":32,"watchers":35,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/strongloop/loopback-boot/pulls/181"},"html":{"href":"https://github.com/strongloop/loopback-boot/pull/181"},"issue":{"href":"https://api.github.com/repos/strongloop/loopback-boot/issues/181"},"comments":{"href":"https://api.github.com/repos/strongloop/loopback-boot/issues/181/comments"},"review_comments":{"href":"https://api.github.com/repos/strongloop/loopback-boot/pulls/181/comments"},"review_comment":{"href":"https://api.github.com/repos/strongloop/loopback-boot/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/strongloop/loopback-boot/pulls/181/commits"},"statuses":{"href":"https://api.github.com/repos/strongloop/loopback-boot/statuses/cc61b364e2ba1a41abcdb4552d1a479bb227ef45"}}}}