{"action":"created","comment":{"url":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/pulls/comments/46507809","id":46507809,"diff_hunk":"@@ -0,0 +1,543 @@\n+/*!\n+ * Copyright 2015 Google Inc. All Rights Reserved.\n+ *\n+ * Licensed under the Apache License, Version 2.0 (the \"License\");\n+ * you may not use this file except in compliance with the License.\n+ * You may obtain a copy of the License at\n+ *\n+ *      http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an \"AS IS\" BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+ * See the License for the specific language governing permissions and\n+ * limitations under the License.\n+ */\n+\n+/*!\n+ * @module logging\n+ */\n+\n+'use strict';\n+\n+var arrify = require('arrify');\n+var extend = require('extend');\n+var format = require('string-format-obj');\n+var is = require('is');\n+var nodeutil = require('util');\n+\n+/**\n+ * @type {module:storage/bucket}\n+ * @private\n+ */\n+var Bucket = require('../storage/bucket.js');\n+\n+/**\n+ * @type {module:bigquery/dataset}\n+ * @private\n+ */\n+var Dataset = require('../bigquery/dataset.js');\n+\n+/**\n+ * @type {module:logging/log}\n+ * @private\n+ */\n+var Log = require('./log.js');\n+\n+/**\n+ * @type {module:common/service}\n+ * @private\n+ */\n+var Service = require('../common/service.js');\n+\n+/**\n+ * @type {module:logging/service}\n+ * @private\n+ */\n+var ServiceClass = require('./service.js');\n+\n+/**\n+ * @type {module:logging/sink}\n+ * @private\n+ */\n+var Sink = require('./sink.js');\n+\n+/**\n+ * @type {module:common/streamrouter}\n+ * @private\n+ */\n+var streamRouter = require('../common/stream-router.js');\n+\n+/**\n+ * @type {module:pubsub/topic}\n+ * @private\n+ */\n+var Topic = require('../pubsub/topic.js');\n+\n+/**\n+ * @type {module:common/util}\n+ * @private\n+ */\n+var util = require('../common/util.js');\n+\n+/**\n+ * [Google Cloud Logging](https://cloud.google.com/logging/docs) collects and\n+ * stores logs from applications and services on the Google Cloud Platform:\n+ *\n+ *   - Export your logs to Google Cloud Storage, Google BigQuery, or Google\n+ *     Cloud Pub/Sub.\n+ *   - Integrate third-party logs from your virtual machine instances by\n+ *     installing the logging agent, `google-fluentd`.\n+ *\n+ * @alias module:logging\n+ * @constructor\n+ *\n+ * @resource [What is Google Cloud Logging?]{@link https://cloud.google.com/logging/docs}\n+ * @resource [Introduction to the Cloud Logging API]{@link https://cloud.google.com/logging/docs/api}\n+ *\n+ * @param {object} options - [Configuration object](#/docs/?method=gcloud).\n+ *\n+ * @example\n+ * var gcloud = require('gcloud')({\n+ *   keyFilename: '/path/to/keyfile.json',\n+ *   projectId: 'grape-spaceship-123'\n+ * });\n+ *\n+ * var logging = gcloud.logging();\n+ */\n+function Logging(options) {\n+  if (!(this instanceof Logging)) {\n+    options = util.normalizeArguments(this, options);\n+    return new Logging(options);\n+  }\n+\n+  var config = {\n+    baseUrl: 'https://logging.googleapis.com/v1beta3',\n+    scopes: ['https://www.googleapis.com/auth/logging.admin']\n+  };\n+\n+  Service.call(this, config, options);\n+}\n+\n+nodeutil.inherits(Logging, Service);\n+\n+// jscs:disable maximumLineLength\n+/**\n+ * Create a sink.\n+ *\n+ * **This method only works if you are authenticated as yourself, e.g. using the\n+ * gcloud SDK.**\n+ *\n+ * @resource [Sink Overview]{@link https://cloud.google.com/logging/docs/api/ref/rest/v1beta3/projects.sinks}\n+ * @resource [Advanced Logs Filters]{@link https://cloud.google.com/logging/docs/view/advanced_filters}\n+ * @resource [projects.sinks.create API Documentation]{@link https://cloud.google.com/logging/docs/api/ref/rest/v1beta3/projects.sinks/create}\n+ *\n+ * @throws {Error} if a name is not provided.\n+ * @throws {Error} if a config object is not provided.\n+ *\n+ * @param {string} name - Name of the sink.\n+ * @param {object} config - See a\n+ *     [Sink resource](https://cloud.google.com/logging/docs/api/ref/rest/v1beta3/projects.logServices.sinks#LogSink).\n+ * @param {module:storage/bucket|module:bigquery/dataset|module:pubsub/topic} config.destination -\n+ *     The destination. If a GCS Bucket object is provided, the proper ACL scope\n+ *     will be granted to the bucket.\n+ * @param {string=} config.filter - An advanced logs filter. Only log entries\n+ *     matching the filter are written.\n+ * @param {function} callback - The callback function.\n+ * @param {?error} callback.err - An error returned while making this request.\n+ * @param {module:loggin/sink} callback.sink - The created Sink object.\n+ * @param {object} callback.apiResponse - The full API response.\n+ *\n+ * @example\n+ * var gcs = gcloud.storage();\n+ *\n+ * var config = {\n+ *   destination: gcs.bucket('logging-bucket'),\n+ *   filter: 'metadata.severity = ALERT'\n+ * };\n+ *\n+ * function callback(err, sink, apiResponse) {\n+ *   // `sink` is a Sink object.\n+ * }\n+ *\n+ * logging.createSink('new-sink-name', config, callback);\n+ */\n+Logging.prototype.createSink = function(name, config, callback) {\n+  // jscs:enable maximumLineLength\n+  var self = this;\n+\n+  if (!is.string(name)) {\n+    throw new Error('A sink name must be provided.');\n+  }\n+\n+  if (!is.object(config)) {\n+    throw new Error('A sink configuration object must be provided.');\n+  }\n+\n+  if (config.destination instanceof Bucket) {\n+    var bucket = config.destination;\n+\n+    // Set the proper permissions on the bucket.\n+    bucket.acl.owners.addGroup('cloud-logs@google.com', function(err, apiResp) {\n+      if (err) {\n+        callback(err, null, apiResp);\n+        return;\n+      }\n+\n+      config.destination = 'storage.googleapis.com/' + bucket.name;\n+\n+      self.createSink(name, config, callback);\n+    });\n+\n+    return;\n+  }\n+\n+  if (config.destination instanceof Dataset) {\n+    var dataset = config.destination;\n+\n+    config.destination = format('{baseUrl}/projects/{pId}/datasets/{dId}', {\n+      baseUrl: 'bigquery.googleapis.com',\n+      pId: dataset.parent.projectId,\n+      dId: dataset.id\n+    });\n+  }\n+\n+  if (config.destination instanceof Topic) {\n+    var topic = config.destination;\n+\n+    config.destination = format('{baseUrl}/{topicName}', {\n+      baseUrl: 'pubsub.googleapis.com',\n+      topicName: topic.name\n+    });\n+  }\n+\n+  this.request({\n+    method: 'POST',\n+    uri: '/sinks',\n+    json: extend({}, config, {\n+      name: name\n+    })\n+  }, function(err, resp) {\n+    if (err) {\n+      callback(err, null, resp);\n+      return;\n+    }\n+\n+    var sink = self.sink(resp.name);\n+    sink.metadata = resp;\n+\n+    callback(null, sink, resp);\n+  });\n+};\n+\n+/**\n+ * List the logs in this project. **Only logs that have entries are listed.**\n+ *\n+ * @resource [projects.logs.list API Documentation]{@link https://cloud.google.com/logging/docs/api/ref/rest/v1beta3/projects.logs/list}\n+ *\n+ * @param {object=} options - Services filtering options.\n+ * @param {boolean} options.autoPaginate - Have pagination handled\n+ *     automatically. Default: true.\n+ * @param {number} options.pageSize - Maximum number of logs to return.\n+ * @param {string} options.pageToken - A previously-returned page token\n+ *     representing part of the larger set of results to view.\n+ * @param {function} callback - The callback function.\n+ * @param {?error} callback.err - An error returned while making this request.\n+ * @param {module:logging/log[]} callback.logs - Log objects from your project.\n+ * @param {?object} callback.nextQuery - If present, query with this object to\n+ *     check for more results.\n+ * @param {object} callback.apiResponse - The full API response.\n+ *\n+ * @example\n+ * logging.getLogs(function(err, logs) {\n+ *   // logs is an array of `Log` objects.\n+ * });\n+ *\n+ * //-\n+ * // To control how many API requests are made and page through the results\n+ * // manually, set `autoPaginate` to `false`.\n+ * //-\n+ * function callback(err, logs, nextQuery, apiResponse) {\n+ *   if (nextQuery) {\n+ *     // More results exist.\n+ *     logging.getLogs(nextQuery, callback);\n+ *   }\n+ * }\n+ *\n+ * logging.getLogs({\n+ *   autoPaginate: false\n+ * }, callback);\n+ *\n+ * //-\n+ * // Get the logs from your project as a readable object stream.\n+ * //-\n+ * logging.getLogs()\n+ *   .on('error', console.error)\n+ *   .on('data', function(log) {\n+ *     // `log` is an `Log` object.\n+ *   })\n+ *   .on('end', function() {\n+ *     // All logs retrieved.\n+ *   });\n+ *\n+ * //-\n+ * // If you anticipate many results, you can end a stream early to prevent\n+ * // unnecessary processing and API requests.\n+ * //-\n+ * logging.getLogs()\n+ *   .on('data', function(service) {\n+ *     this.end();\n+ *   });\n+ */\n+Logging.prototype.getLogs = function(options, callback) {\n+  var self = this;\n+\n+  if (is.fn(options)) {\n+    callback = options;\n+    options = {};\n+  }\n+\n+  this.request({\n+    uri: '/logs',\n+    qs: options\n+  }, function(err, resp) {\n+    if (err) {\n+      callback(err, null, null, resp);\n+      return;\n+    }\n+\n+    var nextQuery = null;\n+\n+    if (resp.nextPageToken) {\n+      nextQuery = extend({}, options, {\n+        pageToken: resp.nextPageToken\n+      });\n+    }\n+\n+    var logs = arrify(resp.logs).map(function(log) {\n+      var logInstance = self.log(log.name);\n+      logInstance.metadata = log;\n+      return logInstance;\n+    });\n+\n+    callback(null, logs, nextQuery, resp);\n+  });\n+};\n+\n+/**\n+ * List the log services that have entries in this project.\n+ *\n+ * @resource [projects.logServices.list API Documentation]{@link https://cloud.google.com/logging/docs/api/ref/rest/v1beta3/projects.logServices/list}\n+ *\n+ * @param {object=} options - Services filtering options.\n+ * @param {boolean} options.autoPaginate - Have pagination handled\n+ *     automatically. Default: true.\n+ * @param {number} options.pageSize - Maximum number of services to return.\n+ * @param {string} options.pageToken - A previously-returned page token\n+ *     representing part of the larger set of results to view.\n+ * @param {function} callback - The callback function.\n+ * @param {?error} callback.err - An error returned while making this request.\n+ * @param {module:logging/service[]} callback.services - Service objects from\n+ *     your project.\n+ * @param {?object} callback.nextQuery - If present, query with this object to\n+ *     check for more results.\n+ * @param {object} callback.apiResponse - The full API response.\n+ *\n+ * @example\n+ * logging.getServices(function(err, services) {\n+ *   // services is an array of `Service` objects.\n+ * });\n+ *\n+ * //-\n+ * // To control how many API requests are made and page through the results\n+ * // manually, set `autoPaginate` to `false`.\n+ * //-\n+ * function callback(err, services, nextQuery, apiResponse) {\n+ *   if (nextQuery) {\n+ *     // More results exist.\n+ *     logging.getServices(nextQuery, callback);\n+ *   }\n+ * }\n+ *\n+ * logging.getServices({\n+ *   autoPaginate: false\n+ * }, callback);\n+ *\n+ * //-\n+ * // Get the services from your project as a readable object stream.\n+ * //-\n+ * logging.getServices()\n+ *   .on('error', console.error)\n+ *   .on('data', function(service) {\n+ *     // `service` is an `Service` object.\n+ *   })\n+ *   .on('end', function() {\n+ *     // All services retrieved.\n+ *   });\n+ *\n+ * //-\n+ * // If you anticipate many results, you can end a stream early to prevent\n+ * // unnecessary processing and API requests.\n+ * //-\n+ * logging.getServices()\n+ *   .on('data', function(service) {\n+ *     this.end();\n+ *   });\n+ */\n+Logging.prototype.getServices = function(options, callback) {\n+  var self = this;\n+\n+  if (is.fn(options)) {\n+    callback = options;\n+    options = {};\n+  }\n+\n+  this.request({\n+    uri: '/logServices',\n+    qs: options\n+  }, function(err, resp) {\n+    if (err) {\n+      callback(err, null, null, resp);\n+      return;\n+    }\n+\n+    var nextQuery = null;\n+\n+    if (resp.nextPageToken) {\n+      nextQuery = extend({}, options, {\n+        pageToken: resp.nextPageToken\n+      });\n+    }\n+\n+    var services = arrify(resp.logServices).map(function(service) {\n+      var serviceInstance = self.service(service.name);\n+      serviceInstance.metadata = service;\n+      return serviceInstance;\n+    });\n+\n+    callback(null, services, nextQuery, resp);\n+  });\n+};\n+\n+/*! Developer Documentation\n+ *\n+ * The JSON API doesn't support any query options. We still hold a place for an\n+ * `options` argument so StreamRouter still works... and in case the API ever\n+ * does support it, like all of the other `list` operations do!\n+ *\n+ * @param {object=} options - Query object.\n+ */\n+/**\n+ * Get the sinks associated with this project.\n+ *\n+ * @resource [projects.sinks.list API Documentation]{@link https://cloud.google.com/logging/docs/api/ref/rest/v1beta3/projects.sinks/list}\n+ *\n+ * @param {function} callback - The callback function.\n+ * @param {?error} callback.err - An error returned while making this request.\n+ * @param {module:logging/sink[]} callback.sinks - Sink objects.\n+ * @param {object} callback.apiResponse - The full API response.\n+ *\n+ * @example\n+ * logging.getSinks(function(err, sinks) {\n+ *   // sinks is an array of Sink objects.\n+ * });\n+ *\n+ * //-\n+ * // Get the sinks from your project as a readable object stream.\n+ * //-\n+ * logging.getSinks()\n+ *   .on('error', console.error)\n+ *   .on('data', function(sink) {\n+ *     // `sink` is a Sink object.\n+ *   })\n+ *   .on('end', function() {\n+ *     // All sinks retrieved.\n+ *   });\n+ */\n+Logging.prototype.getSinks = function(options, callback) {\n+  var self = this;\n+\n+  if (is.fn(options)) {\n+    callback = options;\n+    options = {};\n+  }\n+\n+  this.request({\n+    uri: '/sinks'\n+  }, function(err, resp) {\n+    if (err) {\n+      callback(err, null, null, resp);\n+      return;\n+    }\n+\n+    var nextQuery = null;\n+\n+    if (resp.nextPageToken) {","path":"lib/logging/index.js","position":475,"original_position":475,"commit_id":"310017043fba58daad17834e0b95cff9ba615229","original_commit_id":"310017043fba58daad17834e0b95cff9ba615229","user":{"login":"filipjs","id":6122364,"avatar_url":"https://avatars.githubusercontent.com/u/6122364?v=3","gravatar_id":"","url":"https://api.github.com/users/filipjs","html_url":"https://github.com/filipjs","followers_url":"https://api.github.com/users/filipjs/followers","following_url":"https://api.github.com/users/filipjs/following{/other_user}","gists_url":"https://api.github.com/users/filipjs/gists{/gist_id}","starred_url":"https://api.github.com/users/filipjs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/filipjs/subscriptions","organizations_url":"https://api.github.com/users/filipjs/orgs","repos_url":"https://api.github.com/users/filipjs/repos","events_url":"https://api.github.com/users/filipjs/events{/privacy}","received_events_url":"https://api.github.com/users/filipjs/received_events","type":"User","site_admin":false},"body":"v1beta3 doesn't support ListSinks pagination\r\n","created_at":"2015-12-03T02:58:33Z","updated_at":"2015-12-03T02:58:33Z","html_url":"https://github.com/GoogleCloudPlatform/gcloud-node/pull/865#discussion_r46507809","pull_request_url":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/pulls/865","_links":{"self":{"href":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/pulls/comments/46507809"},"html":{"href":"https://github.com/GoogleCloudPlatform/gcloud-node/pull/865#discussion_r46507809"},"pull_request":{"href":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/pulls/865"}}},"pull_request":{"url":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/pulls/865","id":45100907,"html_url":"https://github.com/GoogleCloudPlatform/gcloud-node/pull/865","diff_url":"https://github.com/GoogleCloudPlatform/gcloud-node/pull/865.diff","patch_url":"https://github.com/GoogleCloudPlatform/gcloud-node/pull/865.patch","issue_url":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/issues/865","number":865,"state":"open","locked":false,"title":"introduce Logging support","user":{"login":"stephenplusplus","id":723048,"avatar_url":"https://avatars.githubusercontent.com/u/723048?v=3","gravatar_id":"","url":"https://api.github.com/users/stephenplusplus","html_url":"https://github.com/stephenplusplus","followers_url":"https://api.github.com/users/stephenplusplus/followers","following_url":"https://api.github.com/users/stephenplusplus/following{/other_user}","gists_url":"https://api.github.com/users/stephenplusplus/gists{/gist_id}","starred_url":"https://api.github.com/users/stephenplusplus/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/stephenplusplus/subscriptions","organizations_url":"https://api.github.com/users/stephenplusplus/orgs","repos_url":"https://api.github.com/users/stephenplusplus/repos","events_url":"https://api.github.com/users/stephenplusplus/events{/privacy}","received_events_url":"https://api.github.com/users/stephenplusplus/received_events","type":"User","site_admin":false},"body":"Fixes #842\r\n\r\n#### Must Reads\r\n- Introduction to the Cloud Logging API: https://cloud.google.com/logging/docs/api/\r\n- Docs: https://stephenplusplus.github.io/gcloud-node/#/docs/master/logging\r\n\r\n#### To Dos\r\n\r\n- [ ] Enable Cloud Logging API on System Test Account\r\n- [x] Document createSink.config.filter\r\n- [x] Inherit from Service / ServiceObject\r\n- **Support Sink destinations**\r\n  - [x] Storage Bucket\r\n  - [x] BigQuery Dataset\r\n  - [x] Pub/Sub Topic\r\n- **Docs**\r\n  - [x] Readme\r\n  - [x] JSDocs\r\n  - [x] Site\r\n- **Tests**\r\n  - [x] System\r\n  - Unit\r\n    - [x] Index\r\n    - [x] Log\r\n    - [x] Service\r\n    - [x] Sink\r\n\r\n#### Preview\r\n\r\n```js\r\nvar gcloud = require('gcloud')({/* credentials */});\r\nvar logging = gcloud.logging();\r\n```\r\n\r\n##### Logs\r\n```js\r\nlogging.getLogs(function(err, logs) {});\r\nvar log = logging.log('my-log');\r\n\r\n// Insert logs:\r\nvar logEntry = {\r\n  metadata: {\r\n    severity: 'INFO'\r\n    timestamp: new Date().toJSON()\r\n  },\r\n  data: {\r\n    delegate: process.env.USER\r\n  }\r\n};\r\n\r\nlog.insert([logEntry, ...], function(err) {});\r\n\r\n// Insert via object stream source\r\nvar logStream = log.createWriteStream();\r\n\r\nlogStream.on('finish', function(err) {\r\n  // All entries have been written.\r\n});\r\n\r\nlogStream.end({ /* log entry */ });\r\n```\r\n\r\n##### Sinks\r\n```js\r\nvar gcs = gcloud.storage();\r\n\r\nlogging.getSinks(function(err, sinks) {});\r\n\r\nlogging.createSink('new-sink-name', {\r\n   // If a bucket, its ACL will be granted with the right privileges:\r\n  destination: gcs.bucket('my-logging-bucket')\r\n}, function(err, sink) {});\r\n\r\nvar sink = logging.sink('my-sink-name');\r\nsink.getMetadata(function(err, metadata) {});\r\nsink.setMetadata({/*...*/}, function(err) {});\r\nsink.setFilter('name:*', function(err) {});\r\n```\r\n\r\n##### Services\r\n```js\r\nlogging.getServices(function(err, services) {});\r\nvar service = logging.service('compute.googleapis.com');\r\n\r\nservice.getIndexes(function(err, indexes) {});\r\n```","created_at":"2015-09-15T20:53:46Z","updated_at":"2015-12-03T02:58:33Z","closed_at":null,"merged_at":null,"merge_commit_sha":"7747e4785eda2c184626200e60ae0bb607a73991","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/pulls/865/commits","review_comments_url":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/pulls/865/comments","review_comment_url":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/pulls/comments{/number}","comments_url":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/issues/865/comments","statuses_url":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/statuses/310017043fba58daad17834e0b95cff9ba615229","head":{"label":"stephenplusplus:spp--logging","ref":"spp--logging","sha":"310017043fba58daad17834e0b95cff9ba615229","user":{"login":"stephenplusplus","id":723048,"avatar_url":"https://avatars.githubusercontent.com/u/723048?v=3","gravatar_id":"","url":"https://api.github.com/users/stephenplusplus","html_url":"https://github.com/stephenplusplus","followers_url":"https://api.github.com/users/stephenplusplus/followers","following_url":"https://api.github.com/users/stephenplusplus/following{/other_user}","gists_url":"https://api.github.com/users/stephenplusplus/gists{/gist_id}","starred_url":"https://api.github.com/users/stephenplusplus/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/stephenplusplus/subscriptions","organizations_url":"https://api.github.com/users/stephenplusplus/orgs","repos_url":"https://api.github.com/users/stephenplusplus/repos","events_url":"https://api.github.com/users/stephenplusplus/events{/privacy}","received_events_url":"https://api.github.com/users/stephenplusplus/received_events","type":"User","site_admin":false},"repo":{"id":22482767,"name":"gcloud-node","full_name":"stephenplusplus/gcloud-node","owner":{"login":"stephenplusplus","id":723048,"avatar_url":"https://avatars.githubusercontent.com/u/723048?v=3","gravatar_id":"","url":"https://api.github.com/users/stephenplusplus","html_url":"https://github.com/stephenplusplus","followers_url":"https://api.github.com/users/stephenplusplus/followers","following_url":"https://api.github.com/users/stephenplusplus/following{/other_user}","gists_url":"https://api.github.com/users/stephenplusplus/gists{/gist_id}","starred_url":"https://api.github.com/users/stephenplusplus/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/stephenplusplus/subscriptions","organizations_url":"https://api.github.com/users/stephenplusplus/orgs","repos_url":"https://api.github.com/users/stephenplusplus/repos","events_url":"https://api.github.com/users/stephenplusplus/events{/privacy}","received_events_url":"https://api.github.com/users/stephenplusplus/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/stephenplusplus/gcloud-node","description":"Google Cloud Node Client Library","fork":true,"url":"https://api.github.com/repos/stephenplusplus/gcloud-node","forks_url":"https://api.github.com/repos/stephenplusplus/gcloud-node/forks","keys_url":"https://api.github.com/repos/stephenplusplus/gcloud-node/keys{/key_id}","collaborators_url":"https://api.github.com/repos/stephenplusplus/gcloud-node/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/stephenplusplus/gcloud-node/teams","hooks_url":"https://api.github.com/repos/stephenplusplus/gcloud-node/hooks","issue_events_url":"https://api.github.com/repos/stephenplusplus/gcloud-node/issues/events{/number}","events_url":"https://api.github.com/repos/stephenplusplus/gcloud-node/events","assignees_url":"https://api.github.com/repos/stephenplusplus/gcloud-node/assignees{/user}","branches_url":"https://api.github.com/repos/stephenplusplus/gcloud-node/branches{/branch}","tags_url":"https://api.github.com/repos/stephenplusplus/gcloud-node/tags","blobs_url":"https://api.github.com/repos/stephenplusplus/gcloud-node/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/stephenplusplus/gcloud-node/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/stephenplusplus/gcloud-node/git/refs{/sha}","trees_url":"https://api.github.com/repos/stephenplusplus/gcloud-node/git/trees{/sha}","statuses_url":"https://api.github.com/repos/stephenplusplus/gcloud-node/statuses/{sha}","languages_url":"https://api.github.com/repos/stephenplusplus/gcloud-node/languages","stargazers_url":"https://api.github.com/repos/stephenplusplus/gcloud-node/stargazers","contributors_url":"https://api.github.com/repos/stephenplusplus/gcloud-node/contributors","subscribers_url":"https://api.github.com/repos/stephenplusplus/gcloud-node/subscribers","subscription_url":"https://api.github.com/repos/stephenplusplus/gcloud-node/subscription","commits_url":"https://api.github.com/repos/stephenplusplus/gcloud-node/commits{/sha}","git_commits_url":"https://api.github.com/repos/stephenplusplus/gcloud-node/git/commits{/sha}","comments_url":"https://api.github.com/repos/stephenplusplus/gcloud-node/comments{/number}","issue_comment_url":"https://api.github.com/repos/stephenplusplus/gcloud-node/issues/comments{/number}","contents_url":"https://api.github.com/repos/stephenplusplus/gcloud-node/contents/{+path}","compare_url":"https://api.github.com/repos/stephenplusplus/gcloud-node/compare/{base}...{head}","merges_url":"https://api.github.com/repos/stephenplusplus/gcloud-node/merges","archive_url":"https://api.github.com/repos/stephenplusplus/gcloud-node/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/stephenplusplus/gcloud-node/downloads","issues_url":"https://api.github.com/repos/stephenplusplus/gcloud-node/issues{/number}","pulls_url":"https://api.github.com/repos/stephenplusplus/gcloud-node/pulls{/number}","milestones_url":"https://api.github.com/repos/stephenplusplus/gcloud-node/milestones{/number}","notifications_url":"https://api.github.com/repos/stephenplusplus/gcloud-node/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/stephenplusplus/gcloud-node/labels{/name}","releases_url":"https://api.github.com/repos/stephenplusplus/gcloud-node/releases{/id}","created_at":"2014-07-31T19:55:20Z","updated_at":"2015-07-31T17:14:21Z","pushed_at":"2015-12-02T01:42:05Z","git_url":"git://github.com/stephenplusplus/gcloud-node.git","ssh_url":"git@github.com:stephenplusplus/gcloud-node.git","clone_url":"https://github.com/stephenplusplus/gcloud-node.git","svn_url":"https://github.com/stephenplusplus/gcloud-node","homepage":"","size":12624,"stargazers_count":1,"watchers_count":1,"language":"JavaScript","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":true,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":1,"default_branch":"master"}},"base":{"label":"GoogleCloudPlatform:master","ref":"master","sha":"7e75ae10dd82b46566494d7e051ca4413c7ee422","user":{"login":"GoogleCloudPlatform","id":2810941,"avatar_url":"https://avatars.githubusercontent.com/u/2810941?v=3","gravatar_id":"","url":"https://api.github.com/users/GoogleCloudPlatform","html_url":"https://github.com/GoogleCloudPlatform","followers_url":"https://api.github.com/users/GoogleCloudPlatform/followers","following_url":"https://api.github.com/users/GoogleCloudPlatform/following{/other_user}","gists_url":"https://api.github.com/users/GoogleCloudPlatform/gists{/gist_id}","starred_url":"https://api.github.com/users/GoogleCloudPlatform/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/GoogleCloudPlatform/subscriptions","organizations_url":"https://api.github.com/users/GoogleCloudPlatform/orgs","repos_url":"https://api.github.com/users/GoogleCloudPlatform/repos","events_url":"https://api.github.com/users/GoogleCloudPlatform/events{/privacy}","received_events_url":"https://api.github.com/users/GoogleCloudPlatform/received_events","type":"Organization","site_admin":false},"repo":{"id":19483273,"name":"gcloud-node","full_name":"GoogleCloudPlatform/gcloud-node","owner":{"login":"GoogleCloudPlatform","id":2810941,"avatar_url":"https://avatars.githubusercontent.com/u/2810941?v=3","gravatar_id":"","url":"https://api.github.com/users/GoogleCloudPlatform","html_url":"https://github.com/GoogleCloudPlatform","followers_url":"https://api.github.com/users/GoogleCloudPlatform/followers","following_url":"https://api.github.com/users/GoogleCloudPlatform/following{/other_user}","gists_url":"https://api.github.com/users/GoogleCloudPlatform/gists{/gist_id}","starred_url":"https://api.github.com/users/GoogleCloudPlatform/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/GoogleCloudPlatform/subscriptions","organizations_url":"https://api.github.com/users/GoogleCloudPlatform/orgs","repos_url":"https://api.github.com/users/GoogleCloudPlatform/repos","events_url":"https://api.github.com/users/GoogleCloudPlatform/events{/privacy}","received_events_url":"https://api.github.com/users/GoogleCloudPlatform/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/GoogleCloudPlatform/gcloud-node","description":"Google Cloud Client Library for Node.js","fork":false,"url":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node","forks_url":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/forks","keys_url":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/keys{/key_id}","collaborators_url":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/teams","hooks_url":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/hooks","issue_events_url":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/issues/events{/number}","events_url":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/events","assignees_url":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/assignees{/user}","branches_url":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/branches{/branch}","tags_url":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/tags","blobs_url":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/git/refs{/sha}","trees_url":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/git/trees{/sha}","statuses_url":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/statuses/{sha}","languages_url":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/languages","stargazers_url":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/stargazers","contributors_url":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/contributors","subscribers_url":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/subscribers","subscription_url":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/subscription","commits_url":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/commits{/sha}","git_commits_url":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/git/commits{/sha}","comments_url":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/comments{/number}","issue_comment_url":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/issues/comments{/number}","contents_url":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/contents/{+path}","compare_url":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/compare/{base}...{head}","merges_url":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/merges","archive_url":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/downloads","issues_url":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/issues{/number}","pulls_url":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/pulls{/number}","milestones_url":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/milestones{/number}","notifications_url":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/labels{/name}","releases_url":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/releases{/id}","created_at":"2014-05-06T06:18:00Z","updated_at":"2015-12-02T11:08:42Z","pushed_at":"2015-12-02T01:42:41Z","git_url":"git://github.com/GoogleCloudPlatform/gcloud-node.git","ssh_url":"git@github.com:GoogleCloudPlatform/gcloud-node.git","clone_url":"https://github.com/GoogleCloudPlatform/gcloud-node.git","svn_url":"https://github.com/GoogleCloudPlatform/gcloud-node","homepage":"https://googlecloudplatform.github.io/gcloud-node/","size":12935,"stargazers_count":589,"watchers_count":589,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":true,"forks_count":116,"mirror_url":null,"open_issues_count":36,"forks":116,"open_issues":36,"watchers":589,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/pulls/865"},"html":{"href":"https://github.com/GoogleCloudPlatform/gcloud-node/pull/865"},"issue":{"href":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/issues/865"},"comments":{"href":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/issues/865/comments"},"review_comments":{"href":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/pulls/865/comments"},"review_comment":{"href":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/pulls/865/commits"},"statuses":{"href":"https://api.github.com/repos/GoogleCloudPlatform/gcloud-node/statuses/310017043fba58daad17834e0b95cff9ba615229"}}}}