GitHub PullRequestReviewCommentEvent at 2014-12-18 01:51:10
Repository: meteor
Actor: ekatek
Payload: {"action":"created","comment":{"url":"https://api.github.com/repos/meteor/meteor/pulls/comments/22019679","id":22019679,"diff_hunk":"@@ -0,0 +1,1158 @@\n+// These commands deal with aggregating local package data with the information\n+// contained in the Meteor Package Server. They also deal with presenting this\n+// to the user in various human or machine-readable ways.\n+var _ = require('underscore');\n+var archinfo = require('./archinfo.js');\n+var buildmessage = require('./buildmessage.js');\n+var catalog = require('./catalog.js');\n+var Console = require(\"./console.js\").Console;\n+var files = require('./files.js');\n+var isopackets = require('./isopackets.js');\n+var main = require('./main.js');\n+var projectContextModule = require('./project-context.js');\n+var utils = require('./utils.js');\n+\n+// We want these queries to be relatively fast, so we will only refresh the\n+// catalog if it is > 15 minutes old\n+var DEFAULT_MAX_AGE_MS = 15 * 60 * 1000;\n+\n+// Maximum number of recent versions of a package or a release that we should\n+// return to the user, unless a more complete mode is requested.\n+var MAX_RECENT_VERSIONS = 5;\n+\n+// XXX: Remove this if/when we do a Troposphere migration to backfill release\n+// version publication times.\n+// Estimate the publication date for a release. Since we have failed to keep\n+// track of publication times of release versions in the past, we will try to\n+// guess that the release was published at the same time as the tool.\n+var getReleaseVersionPublishedOn = function (versionRecord) {\n+  if (versionRecord.published) {\n+    return new Date(versionRecord.published);\n+  }\n+  // We don't know when the release was published. Luckily, since there is no\n+  // way to use the tool outside of a release, and we always change the tool\n+  // between releases, it is a good bet that the release was published on the\n+  // same day as the tool.\n+  var toolPackage = versionRecord.tool.split('@');\n+  var toolName = toolPackage[0];\n+  var toolVersion = toolPackage[1];\n+  var toolRecord = catalog.official.getVersion(toolName, toolVersion);\n+  return new Date(toolRecord.published);\n+};\n+\n+// Convert package version dependencies into a more helpful format for output in\n+// 'meteor show'.\n+var formatDependencies = function (versionDependencies) {\n+  var dependencies = _.map(\n+    // The dependency on 'meteor' was almost certainly added automatically, by\n+    // Isobuild. Returning this to the user will only cause confusion.\n+    _.omit(versionDependencies, \"meteor\"),\n+    function (dep, depName) {\n+      // We will only consider this a weak dependency if all of its references\n+      // are marked as weak.\n+      var weak = _.every(dep.references, function (ref) {\n+        return !! ref.weak;\n+      });\n+      return {\n+        name: depName,\n+        constraint: dep.constraint,\n+        weak: weak\n+      };\n+  });\n+  return dependencies;\n+};\n+\n+// Converts an object to an EJSON string with the right spacing.\n+var convertToEJSON = function (data) {\n+  var EJSON = isopackets.load('ejson').ejson.EJSON;\n+  return EJSON.stringify(data, { indent: true }) + \"\\n\";\n+};\n+\n+// Takes in a string and pads it with whitespace to the length of the longest\n+// possible date string.\n+var padLongformDate = function (dateStr) {\n+  var numSpaces = utils.maxDateLength - dateStr.length;\n+  return dateStr + Array(numSpaces + 1).join(' ');\n+};\n+\n+// In order to get access to local package data, we need to create a local\n+// package catalog. The best way to do that is to create a temporary\n+// ProjectContext and let it handle catalog initialization. When we do, we need\n+// to make sure that it is aware of all the local packages that we might care\n+// about.\n+//\n+// This function returns such a ProjectContext, and takes in the following\n+// options:\n+//  - appDir: If we are running in the context of an app, this will contain the\n+//    root of the app. We want to make sure to grab the data from the app's\n+//    local packages.\n+//  - packageDir: If we are running in a package directory, this will contain\n+//    the source root of that package. If we are running from inside a package,\n+//    we want that package to show up in our results.\n+var getTempContext = function (options) {\n+  var projectContext;\n+  // If we are running in an app, we will use it to create a\n+  // (mostly immutable) projectContext.\n+  if (options.appDir) {\n+    projectContext = new projectContextModule.ProjectContext({\n+      projectDir: options.appDir,\n+      // Don't change the state of the app.\n+      neverWriteProjectConstraintsFile: true\n+    });\n+  } else {\n+    // We're not in an app, so we will create a temporary app and use it to load\n+    // the local catalog. If a local packageDir exists, include it manually.\n+    var currentPackageDir = options.packageDir ? [options.packageDir] : [];\n+    var tempProjectDir = files.mkdtemp('meteor-show');\n+    projectContext = new projectContextModule.ProjectContext({\n+      projectDir: tempProjectDir,\n+      explicitlyAddedLocalPackageDirs: currentPackageDir,\n+      neverWriteProjectConstraintsFile: true,\n+      neverWritePackageMap: true\n+    });\n+  }\n+\n+  // It is possible that we can't process package.js files in our local packages\n+  // and have to exit early. This is unfortunate, but we can't search local\n+  // packages if we can't read them. If this turns out to be a frequent problem,\n+  // we can give a warning, instead of failing in the future. For now, we want\n+  // to err on the side of consistency.\n+  main.captureAndExit(\"=> Errors while reading local packages:\", function () {\n+    projectContext.initializeCatalog();\n+  });\n+  return projectContext;\n+};\n+\n+///////////////////////////////////////////////////////////////////////////////\n+// show\n+///////////////////////////////////////////////////////////////////////////////\n+\n+// Print an error message if the user asks about an unknown item.\n+var itemNotFound = function (item) {\n+  Console.error(item + \": not found\");\n+  utils.explainIfRefreshFailed();\n+  return 1;\n+};\n+\n+// The two classes below collect and print relevant information about Meteor\n+// packages and Meteor releases, respectively. Specifically, they query the\n+// official catalog and, if applicable, relevant local sources. They also handle\n+// the details of printing their data to the screen.\n+//\n+// A query class has:\n+//  - data: an object representing the data it has collected in response to the query.\n+//  - a print method, that take options as an argument and prints the results to\n+//    the terminal.\n+\n+\n+// This class deals with information related to packages. To deal with local\n+// packages, it has to interact with the projectContext.\n+//\n+// The constructor takes in the meta-record of the package and the following\n+// options:\n+//   - projectContext: a projectContext that we can use to look up information\n+//     on local packages.\n+//   - version: (optional) query for a specific version of this package.\n+//   - showArchitectures: (optional) collect and process data on architectures that are\n+//     available for different versions of this package.\n+//   - showHiddenVersions: (optional) return information about all the versions of the\n+//     package, including pre-releases and un-migrate versions.\n+//   - showDependencies: (optional) return information information about\n+//     versions' dependencies.\n+var PackageQuery = function (record, options) {\n+  var self = this;\n+\n+  // This is the record in the packages collection. It contains things like\n+  // maintainers, and the package homepage.\n+  self.metaRecord = record;\n+  self.name = record.name;\n+\n+  // This argument is required -- we use it to look up data. If it has not been\n+  // passed in, fail early.\n+  if (! options.projectContext) {\n+    throw Error(\"Missing required argument: projectContext\");\n+  }\n+  self.projectContext = options.projectContext;\n+  self.localCatalog = options.projectContext.localCatalog;\n+\n+  // Processing per-version availability architectures & dependencies is\n+  // expensive, so we don't do it unless we are asked to.\n+  self.showArchitectures = options.showArchitectures;\n+  self.showDependencies = options.showDependencies;\n+\n+  // We don't want to show pre-releases and un-migrated versions to the user\n+  // unless they explicitly ask us about it.\n+  self.showHiddenVersions = options.showHiddenVersions;\n+\n+  // Collect the data for this package, including looking up any specific\n+  // package version that we care about.\n+  if (options.version) {\n+    var versionRecord = self._getVersionRecord(options.version);\n+    if (! versionRecord) {\n+      self.data = null;\n+      return;\n+    }\n+    self.data =  versionRecord.local ?\n+      self._getLocalVersion(versionRecord) : self._getOfficialVersion(versionRecord);\n+  } else {\n+    self.data = self._collectPackageData();\n+  }\n+};\n+\n+_.extend(PackageQuery.prototype, {\n+  // Find and return a version record for a given version. Mark the version\n+  // record as local, if it is a local version of the package.\n+  _getVersionRecord: function (version) {\n+    var self = this;\n+\n+    // We allow local version to override remote versions in meteor show, so we\n+    // should start by checking if this is a local version first.\n+    var versionRecord = self.localCatalog.getLatestVersion(self.name);\n+\n+    // If we asked for \"local\" as the version number, and found any local version\n+    // at all, we are done.\n+    if (version === \"local\") {\n+      return _.extend(versionRecord, { local: true });\n+    }\n+\n+    // We have a local record, and its version matches the version that we asked\n+    // for, so we are done.\n+    if (versionRecord && (versionRecord.version === version)) {\n+      return _.extend(versionRecord, { local: true });\n+    }\n+\n+    // If we haven't found a local record, or if the local record that we found\n+    // doesn't match the version that we asked for, then we have to go look in\n+    // the server catalog.\n+    versionRecord = catalog.official.getVersion(self.name, version);\n+    return versionRecord;\n+  },\n+  // Print the query information to screen.\n+  //\n+  // options:\n+  //   - ejson: Don't pretty-print the data. Return a machine-readable ejson\n+  //     object.\n+  print: function (options) {\n+    var self = this;\n+\n+    // If we are asking for an EJSON-style output, we will only print out the\n+    // relevant fields.\n+    if (options.ejson) {\n+      var versionFields = [\n+        \"name\", \"version\", \"description\", \"summary\", \"git\", \"dependencies\",\n+        \"publishedBy\", \"publishedOn\", \"installed\", \"local\", \"architectures\"\n+      ];\n+      var packageFields =\n+        [ \"name\", \"homepage\", \"maintainers\", \"versions\", \"totalVersions\" ];\n+      var fields = self.data.version ? versionFields : packageFields;\n+      Console.rawInfo(convertToEJSON(_.pick(self.data, fields)));\n+      return;\n+    }\n+\n+    // Otherwise, display the information that we have. If we were asking about\n+    // a specific version, display that. Otherwise, display package metadata in\n+    // general.\n+    if (self.data.version) {\n+      self._displayVersion(self.data);\n+      return;\n+    }\n+    self._displayPackage(self.data);\n+  },\n+  // Aggregates data about the package as a whole. Returns an object with the\n+  // following keys:\n+  //\n+  // - name: package name\n+  // - maintainers: an array of usernames of maintainers\n+  // - homepage: string homepage\n+  // - totalVersions: total number of versions that this package has, including\n+  //   local and hidden versions.\n+  // - defaultVersion: a default version: use this version to look up\n+  //   per-version information that is relevant to the package as a whole, such\n+  //   as git, description,etc.\n+  // - versions: an array of objects representing versions of this package.\n+  _collectPackageData: function () {\n+    var self = this;\n+    var data = {\n+      name: self.metaRecord.name,\n+      maintainers: _.pluck(self.metaRecord.maintainers, \"username\"),\n+      homepage: self.metaRecord.homepage\n+    };\n+\n+    // Collect surface information about available versions, starting with the\n+    // versions available on the server.\n+    var serverVersionRecords =\n+          catalog.official.getSortedVersionRecords(self.name);\n+    var totalVersions = serverVersionRecords.length;\n+\n+    // If we are not going to show hidden versions, then we shouldn't waste time\n+    // on them. Trim the serverVersionRecords array to only have the top\n+    // MAX_RECENT_VERSIONS migrated, official versions.\n+    if (! self.showHiddenVersions) {\n+      serverVersionRecords =\n+        _.filter(serverVersionRecords, function (vr) {\n+          return ! vr.unmigrated && vr.version.indexOf(\"-\") === -1;\n+      });\n+      serverVersionRecords = _.last(serverVersionRecords, MAX_RECENT_VERSIONS);\n+    };\n+\n+    // Process the catalog records into our preferred format, and look up any\n+    // other per-version information that we might need.\n+    data[\"versions\"] = _.map(serverVersionRecords, function (versionRecord) {\n+      return self._getOfficialVersion(versionRecord);\n+    });\n+\n+    // The local version doesn't count against the version limit. Look up relevant\n+    // information about the local version.\n+    var localVersion = self.localCatalog.getLatestVersion(self.name);\n+    if (localVersion) {\n+      var local = self._getLocalVersion(localVersion);\n+      data[\"versions\"].push(local);\n+      totalVersions++;\n+    }\n+\n+    // Record the total number of versions, including the ones we hid from the user.\n+    data[\"totalVersions\"] = totalVersions;\n+\n+    // Some per-version information gets displayed with the rest of the package\n+    // information.  We want to use the right version for that. (We don't want\n+    // to display data from unofficial or un-migrated versions just because they\n+    // are recent.)\n+    data[\"defaultVersion\"] =\n+          localVersion ||\n+          catalog.official.getLatestMainlineVersion(self.name) ||\n+          _.last(data.versions);\n+\n+    return data;\n+  },\n+  // Takes in a version record from the official catalog and looks up extra\n+  // information that's relevant to this PackageQuery.\n+  //\n+  // - name: package Name\n+  // - version: package version\n+  // - summary: version summary/short description (from Package.describe)\n+  // - description: long-form description (from the README.md)\n+  // - publishedBy: username of the publisher\n+  // - publishedOn: date of publication\n+  // - git: git URL for this version\n+  // - installed: true if the package exists in warehouse, and is therefore\n+  //   available for use offline.\n+  // - architectures: (optional) if self.showArchitectures is true, returns an\n+  //   array of system architectures for which that package is available.\n+  // - dependencies: (optional) if self.showDependencies is true, return an\n+  //   array of objects denoting that package's dependencies. The objects have\n+  //   the following keys:\n+  //     - packageName: name of the dependency\n+  //     - constraint: constraint for that dependency\n+  //     - weak: true if this is a weak dependency.\n+  _getOfficialVersion: function (versionRecord) {\n+    var self = this;\n+    var version = versionRecord.version;\n+    var name = self.name;\n+    var data = {\n+      name: name,\n+      version: version,\n+      summary: versionRecord.description,\n+      description: versionRecord.longDescription,\n+      publishedBy:\n+      versionRecord.publishedBy && versionRecord.publishedBy.username,\n+      publishedOn: new Date(versionRecord.published),\n+      git: versionRecord.git\n+    };\n+\n+    // Processing and formating architectures takes time, so we don't want to\n+    // do this if we don't have to.\n+    if (self.showArchitectures) {\n+      var allBuilds = catalog.official.getAllBuilds(self.name, version);\n+      var architectures = _.map(allBuilds, function (build) {\n+        return build['buildArchitectures'] &&\n+          build.buildArchitectures.split('+')[0];\n+      });\n+      data[\"architectures\"] = architectures;\n+    }\n+\n+    // Processing and formating dependencies also takes time, so we would\n+    // rather not do it if we don't have to.\n+    if (self.showDependencies) {\n+      data[\"dependencies\"] = formatDependencies(versionRecord.dependencies);\n+    }\n+\n+    // We want to figure out if we have already downloaded this package, and,\n+    // therefore, can use it offline.\n+    var tropohouse = self.projectContext.tropohouse;\n+    try {\n+      data[\"installed\"] = tropohouse.installed({\n+        packageName: name,\n+        version: version\n+      });\n+    } catch (e) {\n+      // If we get any sort of error that isn't ENOENT, something is wrong, but\n+      // the corruption might only extend to a specific version that you will\n+      // never use. It would be awkward to fail 'meteor show' forever because of\n+      // that. Print an error message, so we can track this down, but don't\n+      // throw.\n+      if (e.code !== 'ENOENT') {\n+        Console.error(e);\n+      }\n+      data[\"installed\"] = false;\n+    }\n+    return data;\n+  },\n+\n+  // Takes in a version record from the local catalog and looks up extra\n+  // information that's relevant to this PackageQuery. Returns an object with\n+  // the following keys.\n+  //\n+  // - name: package Name\n+  // - version: package version\n+  // - summary: version summary/short description (from Package.describe)\n+  // - description: long-form description (from the README.md)\n+  // - git: git URL for this version\n+  // - local: always true (denotes that this is a local package).\n+  // - directory: source directory of this package.\n+  // - dependencies: (optional) if self.showDependencies is true, return an\n+  //   array of objects denoting that package's dependencies. The objects have\n+  //   the following keys:\n+  //     - packageName: name of the dependency\n+  //     - constraint: constraint for that dependency\n+  //     - weak: true if this is a weak dependency.\n+  _getLocalVersion: function (localRecord) {\n+    var self = this;\n+    var data =  {\n+      name: self.name,\n+      summary: localRecord.description,\n+      git: localRecord.git,\n+      local: true\n+    };\n+\n+    // Get the source directory.\n+    var packageSource = self.localCatalog.getPackageSource(self.name);\n+    data[\"directory\"] = packageSource.sourceRoot;\n+\n+    // If the version was not explicitly set by the user, the catalog backfills\n+    // a placeholder version for the constraint solver. We don't want to show\n+    // that version to the user.\n+    data[\"version\"] = packageSource.versionExplicitlyProvided ?\n+      localRecord.version : \"local\";\n+\n+    // Processing dependencies takes time, and we don't want to do it if we\n+    // don't have to.\n+    if (self.showDependencies) {\n+      data[\"dependencies\"] = formatDependencies(localRecord.dependencies);\n+    }\n+\n+    return data;\n+  },\n+  // Displays version information from this PackageQuery to the terminal in a human-friendly\n+  // format. Takes in an object that contains some, but not all, of the following keys:\n+  //\n+  // - name: (mandatory) package Name\n+  // - version: (mandatory) package version\n+  // - summary: version summary/short description (from Package.describe)\n+  // - publishedBy: username of the publisher\n+  // - publishedOn: date of publication\n+  // - description: long-form description (from the README.md)\n+  // - git: git URL for this version.\n+  // - local: true for a local version of a package.\n+  // - directory: source directory of this package.\n+  // - installed: true if the package exists in warehouse, and is therefore\n+  //   available for use offline.\n+  // - architectures: (optional) if self.showArchitectures is true, returns an\n+  //   array of system architectures for which that package is available.\n+  // - dependencies: (mandatory, but may be empty) an array of package\n+  //   dependencies, as objects with the following keys:\n+  //     - packageName: name of the dependency\n+  //     - constraint: constraint for that dependency\n+  //     - weak: true if this is a weak dependency.\n+  _displayVersion: function (data) {\n+    var self = this;\n+    Console.info(\"Package:\", data.name);\n+    Console.info(\"Version:\", data.version);\n+    if (data.summary) {\n+      Console.info(\"Summary:\", data.summary);\n+    }\n+    if (data.publishedBy) {\n+      var publisher = data.publishedBy;\n+      var pubDate = utils.longformDate(data.publishedOn);\n+      Console.info(\"Published by\", publisher, \"on\", pubDate);\n+    }\n+    if (data.git) {\n+      Console.info(\"Git:\", Console.url(data.git));\n+    }\n+    if (data.directory) {\n+      Console.info(\"Directory:\", Console.path(data.directory));\n+    }\n+    Console.info();\n+\n+    // If we don't have a long-form description, print the summary. (If we don't\n+    // have a summary, print nothing).\n+    if (data.description || data.summary) {\n+      Console.info(data.description || data.summary);","path":"tools/commands-packages-query.js","position":489,"original_position":489,"commit_id":"14b1b8b69d688878151609a6ab60b40d791e7ded","original_commit_id":"14b1b8b69d688878151609a6ab60b40d791e7ded","user":{"login":"ekatek","id":5854061,"avatar_url":"https://avatars.githubusercontent.com/u/5854061?v=3","gravatar_id":"","url":"https://api.github.com/users/ekatek","html_url":"https://github.com/ekatek","followers_url":"https://api.github.com/users/ekatek/followers","following_url":"https://api.github.com/users/ekatek/following{/other_user}","gists_url":"https://api.github.com/users/ekatek/gists{/gist_id}","starred_url":"https://api.github.com/users/ekatek/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ekatek/subscriptions","organizations_url":"https://api.github.com/users/ekatek/orgs","repos_url":"https://api.github.com/users/ekatek/repos","events_url":"https://api.github.com/users/ekatek/events{/privacy}","received_events_url":"https://api.github.com/users/ekatek/received_events","type":"User","site_admin":false},"body":"I'd rather print the summary twice, honestly. I think printing nothing in the description is going to make for a mediocre user experience when they run 'meteor show' for a package. We should give them something, and the description is in a far more obvious location, visually.","created_at":"2014-12-18T01:51:10Z","updated_at":"2014-12-18T01:51:10Z","html_url":"https://github.com/meteor/meteor/pull/3309#discussion_r22019679","pull_request_url":"https://api.github.com/repos/meteor/meteor/pulls/3309","_links":{"self":{"href":"https://api.github.com/repos/meteor/meteor/pulls/comments/22019679"},"html":{"href":"https://github.com/meteor/meteor/pull/3309#discussion_r22019679"},"pull_request":{"href":"https://api.github.com/repos/meteor/meteor/pulls/3309"}}},"pull_request":{"url":"https://api.github.com/repos/meteor/meteor/pulls/3309","id":26268969,"html_url":"https://github.com/meteor/meteor/pull/3309","diff_url":"https://github.com/meteor/meteor/pull/3309.diff","patch_url":"https://github.com/meteor/meteor/pull/3309.patch","issue_url":"https://api.github.com/repos/meteor/meteor/issues/3309","number":3309,"state":"open","locked":false,"title":"Show revamp","user":{"login":"ekatek","id":5854061,"avatar_url":"https://avatars.githubusercontent.com/u/5854061?v=3","gravatar_id":"","url":"https://api.github.com/users/ekatek","html_url":"https://github.com/ekatek","followers_url":"https://api.github.com/users/ekatek/followers","following_url":"https://api.github.com/users/ekatek/following{/other_user}","gists_url":"https://api.github.com/users/ekatek/gists{/gist_id}","starred_url":"https://api.github.com/users/ekatek/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ekatek/subscriptions","organizations_url":"https://api.github.com/users/ekatek/orgs","repos_url":"https://api.github.com/users/ekatek/repos","events_url":"https://api.github.com/users/ekatek/events{/privacy}","received_events_url":"https://api.github.com/users/ekatek/received_events","type":"User","site_admin":false},"body":"Complete rewrite of 'meteor show', with tests. See commit messages for more details.\r\n\r\nThis is part of the work on the Meteor tool to get longform package descriptions from README.md files into 'meteor show'. It is safe-contained enough, that it makes sense to submit it for review.\r\n\r\n(I won't merge to devel until all the README work is complete -- note that this is being pulled to a staging branch).","created_at":"2014-12-18T00:28:02Z","updated_at":"2014-12-18T01:51:10Z","closed_at":null,"merged_at":null,"merge_commit_sha":"de576429c568c0d26488e6ca4906cbd7ef158bda","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/meteor/meteor/pulls/3309/commits","review_comments_url":"https://api.github.com/repos/meteor/meteor/pulls/3309/comments","review_comment_url":"https://api.github.com/repos/meteor/meteor/pulls/comments/{number}","comments_url":"https://api.github.com/repos/meteor/meteor/issues/3309/comments","statuses_url":"https://api.github.com/repos/meteor/meteor/statuses/14b1b8b69d688878151609a6ab60b40d791e7ded","head":{"label":"meteor:show-revamp","ref":"show-revamp","sha":"14b1b8b69d688878151609a6ab60b40d791e7ded","user":{"login":"meteor","id":789528,"avatar_url":"https://avatars.githubusercontent.com/u/789528?v=3","gravatar_id":"","url":"https://api.github.com/users/meteor","html_url":"https://github.com/meteor","followers_url":"https://api.github.com/users/meteor/followers","following_url":"https://api.github.com/users/meteor/following{/other_user}","gists_url":"https://api.github.com/users/meteor/gists{/gist_id}","starred_url":"https://api.github.com/users/meteor/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/meteor/subscriptions","organizations_url":"https://api.github.com/users/meteor/orgs","repos_url":"https://api.github.com/users/meteor/repos","events_url":"https://api.github.com/users/meteor/events{/privacy}","received_events_url":"https://api.github.com/users/meteor/received_events","type":"Organization","site_admin":false},"repo":{"id":3214406,"name":"meteor","full_name":"meteor/meteor","owner":{"login":"meteor","id":789528,"avatar_url":"https://avatars.githubusercontent.com/u/789528?v=3","gravatar_id":"","url":"https://api.github.com/users/meteor","html_url":"https://github.com/meteor","followers_url":"https://api.github.com/users/meteor/followers","following_url":"https://api.github.com/users/meteor/following{/other_user}","gists_url":"https://api.github.com/users/meteor/gists{/gist_id}","starred_url":"https://api.github.com/users/meteor/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/meteor/subscriptions","organizations_url":"https://api.github.com/users/meteor/orgs","repos_url":"https://api.github.com/users/meteor/repos","events_url":"https://api.github.com/users/meteor/events{/privacy}","received_events_url":"https://api.github.com/users/meteor/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/meteor/meteor","description":"Meteor, an ultra-simple, database-everywhere, data-on-the-wire, pure-Javascript web framework.","fork":false,"url":"https://api.github.com/repos/meteor/meteor","forks_url":"https://api.github.com/repos/meteor/meteor/forks","keys_url":"https://api.github.com/repos/meteor/meteor/keys{/key_id}","collaborators_url":"https://api.github.com/repos/meteor/meteor/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/meteor/meteor/teams","hooks_url":"https://api.github.com/repos/meteor/meteor/hooks","issue_events_url":"https://api.github.com/repos/meteor/meteor/issues/events{/number}","events_url":"https://api.github.com/repos/meteor/meteor/events","assignees_url":"https://api.github.com/repos/meteor/meteor/assignees{/user}","branches_url":"https://api.github.com/repos/meteor/meteor/branches{/branch}","tags_url":"https://api.github.com/repos/meteor/meteor/tags","blobs_url":"https://api.github.com/repos/meteor/meteor/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/meteor/meteor/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/meteor/meteor/git/refs{/sha}","trees_url":"https://api.github.com/repos/meteor/meteor/git/trees{/sha}","statuses_url":"https://api.github.com/repos/meteor/meteor/statuses/{sha}","languages_url":"https://api.github.com/repos/meteor/meteor/languages","stargazers_url":"https://api.github.com/repos/meteor/meteor/stargazers","contributors_url":"https://api.github.com/repos/meteor/meteor/contributors","subscribers_url":"https://api.github.com/repos/meteor/meteor/subscribers","subscription_url":"https://api.github.com/repos/meteor/meteor/subscription","commits_url":"https://api.github.com/repos/meteor/meteor/commits{/sha}","git_commits_url":"https://api.github.com/repos/meteor/meteor/git/commits{/sha}","comments_url":"https://api.github.com/repos/meteor/meteor/comments{/number}","issue_comment_url":"https://api.github.com/repos/meteor/meteor/issues/comments/{number}","contents_url":"https://api.github.com/repos/meteor/meteor/contents/{+path}","compare_url":"https://api.github.com/repos/meteor/meteor/compare/{base}...{head}","merges_url":"https://api.github.com/repos/meteor/meteor/merges","archive_url":"https://api.github.com/repos/meteor/meteor/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/meteor/meteor/downloads","issues_url":"https://api.github.com/repos/meteor/meteor/issues{/number}","pulls_url":"https://api.github.com/repos/meteor/meteor/pulls{/number}","milestones_url":"https://api.github.com/repos/meteor/meteor/milestones{/number}","notifications_url":"https://api.github.com/repos/meteor/meteor/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/meteor/meteor/labels{/name}","releases_url":"https://api.github.com/repos/meteor/meteor/releases{/id}","created_at":"2012-01-19T01:58:17Z","updated_at":"2014-12-18T00:54:58Z","pushed_at":"2014-12-18T01:43:28Z","git_url":"git://github.com/meteor/meteor.git","ssh_url":"git@github.com:meteor/meteor.git","clone_url":"https://github.com/meteor/meteor.git","svn_url":"https://github.com/meteor/meteor","homepage":"www.meteor.com","size":142866,"stargazers_count":21319,"watchers_count":21319,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":2352,"mirror_url":null,"open_issues_count":330,"forks":2352,"open_issues":330,"watchers":21319,"default_branch":"devel"}},"base":{"label":"meteor:readme-staging","ref":"readme-staging","sha":"06f65cff503750dac9486ffc70ca2d40e3182f6d","user":{"login":"meteor","id":789528,"avatar_url":"https://avatars.githubusercontent.com/u/789528?v=3","gravatar_id":"","url":"https://api.github.com/users/meteor","html_url":"https://github.com/meteor","followers_url":"https://api.github.com/users/meteor/followers","following_url":"https://api.github.com/users/meteor/following{/other_user}","gists_url":"https://api.github.com/users/meteor/gists{/gist_id}","starred_url":"https://api.github.com/users/meteor/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/meteor/subscriptions","organizations_url":"https://api.github.com/users/meteor/orgs","repos_url":"https://api.github.com/users/meteor/repos","events_url":"https://api.github.com/users/meteor/events{/privacy}","received_events_url":"https://api.github.com/users/meteor/received_events","type":"Organization","site_admin":false},"repo":{"id":3214406,"name":"meteor","full_name":"meteor/meteor","owner":{"login":"meteor","id":789528,"avatar_url":"https://avatars.githubusercontent.com/u/789528?v=3","gravatar_id":"","url":"https://api.github.com/users/meteor","html_url":"https://github.com/meteor","followers_url":"https://api.github.com/users/meteor/followers","following_url":"https://api.github.com/users/meteor/following{/other_user}","gists_url":"https://api.github.com/users/meteor/gists{/gist_id}","starred_url":"https://api.github.com/users/meteor/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/meteor/subscriptions","organizations_url":"https://api.github.com/users/meteor/orgs","repos_url":"https://api.github.com/users/meteor/repos","events_url":"https://api.github.com/users/meteor/events{/privacy}","received_events_url":"https://api.github.com/users/meteor/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/meteor/meteor","description":"Meteor, an ultra-simple, database-everywhere, data-on-the-wire, pure-Javascript web framework.","fork":false,"url":"https://api.github.com/repos/meteor/meteor","forks_url":"https://api.github.com/repos/meteor/meteor/forks","keys_url":"https://api.github.com/repos/meteor/meteor/keys{/key_id}","collaborators_url":"https://api.github.com/repos/meteor/meteor/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/meteor/meteor/teams","hooks_url":"https://api.github.com/repos/meteor/meteor/hooks","issue_events_url":"https://api.github.com/repos/meteor/meteor/issues/events{/number}","events_url":"https://api.github.com/repos/meteor/meteor/events","assignees_url":"https://api.github.com/repos/meteor/meteor/assignees{/user}","branches_url":"https://api.github.com/repos/meteor/meteor/branches{/branch}","tags_url":"https://api.github.com/repos/meteor/meteor/tags","blobs_url":"https://api.github.com/repos/meteor/meteor/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/meteor/meteor/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/meteor/meteor/git/refs{/sha}","trees_url":"https://api.github.com/repos/meteor/meteor/git/trees{/sha}","statuses_url":"https://api.github.com/repos/meteor/meteor/statuses/{sha}","languages_url":"https://api.github.com/repos/meteor/meteor/languages","stargazers_url":"https://api.github.com/repos/meteor/meteor/stargazers","contributors_url":"https://api.github.com/repos/meteor/meteor/contributors","subscribers_url":"https://api.github.com/repos/meteor/meteor/subscribers","subscription_url":"https://api.github.com/repos/meteor/meteor/subscription","commits_url":"https://api.github.com/repos/meteor/meteor/commits{/sha}","git_commits_url":"https://api.github.com/repos/meteor/meteor/git/commits{/sha}","comments_url":"https://api.github.com/repos/meteor/meteor/comments{/number}","issue_comment_url":"https://api.github.com/repos/meteor/meteor/issues/comments/{number}","contents_url":"https://api.github.com/repos/meteor/meteor/contents/{+path}","compare_url":"https://api.github.com/repos/meteor/meteor/compare/{base}...{head}","merges_url":"https://api.github.com/repos/meteor/meteor/merges","archive_url":"https://api.github.com/repos/meteor/meteor/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/meteor/meteor/downloads","issues_url":"https://api.github.com/repos/meteor/meteor/issues{/number}","pulls_url":"https://api.github.com/repos/meteor/meteor/pulls{/number}","milestones_url":"https://api.github.com/repos/meteor/meteor/milestones{/number}","notifications_url":"https://api.github.com/repos/meteor/meteor/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/meteor/meteor/labels{/name}","releases_url":"https://api.github.com/repos/meteor/meteor/releases{/id}","created_at":"2012-01-19T01:58:17Z","updated_at":"2014-12-18T00:54:58Z","pushed_at":"2014-12-18T01:43:28Z","git_url":"git://github.com/meteor/meteor.git","ssh_url":"git@github.com:meteor/meteor.git","clone_url":"https://github.com/meteor/meteor.git","svn_url":"https://github.com/meteor/meteor","homepage":"www.meteor.com","size":142866,"stargazers_count":21319,"watchers_count":21319,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":2352,"mirror_url":null,"open_issues_count":330,"forks":2352,"open_issues":330,"watchers":21319,"default_branch":"devel"}},"_links":{"self":{"href":"https://api.github.com/repos/meteor/meteor/pulls/3309"},"html":{"href":"https://github.com/meteor/meteor/pull/3309"},"issue":{"href":"https://api.github.com/repos/meteor/meteor/issues/3309"},"comments":{"href":"https://api.github.com/repos/meteor/meteor/issues/3309/comments"},"review_comments":{"href":"https://api.github.com/repos/meteor/meteor/pulls/3309/comments"},"review_comment":{"href":"https://api.github.com/repos/meteor/meteor/pulls/comments/{number}"},"commits":{"href":"https://api.github.com/repos/meteor/meteor/pulls/3309/commits"},"statuses":{"href":"https://api.github.com/repos/meteor/meteor/statuses/14b1b8b69d688878151609a6ab60b40d791e7ded"}}}}