{"action":"created","comment":{"url":"https://api.github.com/repos/atom/atom/pulls/comments/144850427","pull_request_review_id":69564599,"id":144850427,"diff_hunk":"@@ -0,0 +1,705 @@\n+const path = require('path')\n+\n+const _ = require('underscore-plus')\n+const fs = require('fs-plus')\n+const {Emitter, Disposable} = require('event-kit')\n+const TextBuffer = require('text-buffer')\n+const {watchPath} = require('./path-watcher')\n+\n+const DefaultDirectoryProvider = require('./default-directory-provider')\n+const Model = require('./model')\n+const GitRepositoryProvider = require('./git-repository-provider')\n+\n+// Extended: Represents a project that's opened in Atom.\n+//\n+// An instance of this class is always available as the `atom.project` global.\n+module.exports =\n+class Project extends Model {\n+  /*\n+  Section: Construction and Destruction\n+  */\n+\n+  constructor ({notificationManager, packageManager, config, applicationDelegate}) {\n+    super()\n+    this.notificationManager = notificationManager\n+    this.applicationDelegate = applicationDelegate\n+    this.emitter = new Emitter()\n+    this.buffers = []\n+    this.rootDirectories = []\n+    this.repositories = []\n+    this.directoryProviders = []\n+    this.defaultDirectoryProvider = new DefaultDirectoryProvider()\n+    this.repositoryPromisesByPath = new Map()\n+    this.repositoryProviders = [new GitRepositoryProvider(this, config)]\n+    this.loadPromisesByPath = {}\n+    this.watcherPromisesByPath = {}\n+    this.retiredBufferIDs = new Set()\n+    this.retiredBufferPaths = new Set()\n+    this.consumeServices(packageManager)\n+  }\n+\n+  destroyed () {\n+    for (let buffer of this.buffers.slice()) { buffer.destroy() }\n+    for (let repository of this.repositories.slice()) {\n+      if (repository != null) repository.destroy()\n+    }\n+    for (let path in this.watcherPromisesByPath) {\n+      this.watcherPromisesByPath[path].then(watcher => { watcher.dispose() })\n+    }\n+    this.rootDirectories = []\n+    this.repositories = []\n+  }\n+\n+  reset (packageManager) {\n+    this.emitter.dispose()\n+    this.emitter = new Emitter()\n+\n+    for (let buffer of this.buffers) {\n+      if (buffer != null) buffer.destroy()\n+    }\n+    this.buffers = []\n+    this.setPaths([])\n+    this.loadPromisesByPath = {}\n+    this.retiredBufferIDs = new Set()\n+    this.retiredBufferPaths = new Set()\n+    this.consumeServices(packageManager)\n+  }\n+\n+  destroyUnretainedBuffers () {\n+    for (let buffer of this.getBuffers()) {\n+      if (!buffer.isRetained()) buffer.destroy()\n+    }\n+  }\n+\n+  /*\n+  Section: Serialization\n+  */\n+\n+  deserialize (state) {\n+    this.retiredBufferIDs = new Set()\n+    this.retiredBufferPaths = new Set()\n+\n+    const handleBufferState = (bufferState) => {\n+      if (bufferState.shouldDestroyOnFileDelete == null) {\n+        bufferState.shouldDestroyOnFileDelete = () => atom.config.get('core.closeDeletedFileTabs')\n+      }\n+\n+      // Use a little guilty knowledge of the way TextBuffers are serialized.\n+      // This allows TextBuffers that have never been saved (but have filePaths) to be deserialized, but prevents\n+      // TextBuffers backed by files that have been deleted from being saved.\n+      bufferState.mustExist = bufferState.digestWhenLastPersisted !== false\n+\n+      return TextBuffer.deserialize(bufferState).catch((_) => {\n+        this.retiredBufferIDs.add(bufferState.id)\n+        this.retiredBufferPaths.add(bufferState.filePath)\n+        return null\n+      })\n+    }\n+\n+    const bufferPromises = []\n+    for (let bufferState of state.buffers) {\n+      bufferPromises.push(handleBufferState(bufferState))\n+    }\n+\n+    return Promise.all(bufferPromises).then(buffers => {\n+      this.buffers = buffers.filter(Boolean)\n+      for (let buffer of this.buffers) {\n+        this.subscribeToBuffer(buffer)\n+      }\n+      this.setPaths(state.paths || [], {mustExist: true, exact: true})\n+    })\n+  }\n+\n+  serialize (options = {}) {\n+    return {\n+      deserializer: 'Project',\n+      paths: this.getPaths(),\n+      buffers: _.compact(this.buffers.map(function (buffer) {\n+        if (buffer.isRetained()) {\n+          const isUnloading = options.isUnloading === true\n+          return buffer.serialize({markerLayers: isUnloading, history: isUnloading})\n+        }\n+      }))\n+    }\n+  }\n+\n+  /*\n+  Section: Event Subscription\n+  */\n+\n+  // Public: Invoke the given callback when the project paths change.\n+  //\n+  // * `callback` {Function} to be called after the project paths change.\n+  //    * `projectPaths` An {Array} of {String} project paths.\n+  //\n+  // Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.\n+  onDidChangePaths (callback) {\n+    return this.emitter.on('did-change-paths', callback)\n+  }\n+\n+  // Public: Invoke the given callback when a text buffer is added to the\n+  // project.\n+  //\n+  // * `callback` {Function} to be called when a text buffer is added.\n+  //   * `buffer` A {TextBuffer} item.\n+  //\n+  // Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.\n+  onDidAddBuffer (callback) {\n+    return this.emitter.on('did-add-buffer', callback)\n+  }\n+\n+  // Public: Invoke the given callback with all current and future text\n+  // buffers in the project.\n+  //\n+  // * `callback` {Function} to be called with current and future text buffers.\n+  //   * `buffer` A {TextBuffer} item.\n+  //\n+  // Returns a {Disposable} on which `.dispose()` can be called to unsubscribe.\n+  observeBuffers (callback) {\n+    for (let buffer of this.getBuffers()) { callback(buffer) }\n+    return this.onDidAddBuffer(callback)\n+  }\n+\n+  // Extended: Invoke a callback when a filesystem change occurs within any open\n+  // project path.\n+  //\n+  // ```js\n+  // const disposable = atom.project.onDidChangeFiles(events => {\n+  //   for (const event of events) {\n+  //     // \"created\", \"modified\", \"deleted\", or \"renamed\"\n+  //     console.log(`Event action: ${event.type}`)\n+  //\n+  //     // absolute path to the filesystem entry that was touched\n+  //     console.log(`Event path: ${event.path}`)\n+  //\n+  //     if (event.type === 'renamed') {\n+  //       console.log(`.. renamed from: ${event.oldPath}`)\n+  //     }\n+  //   }\n+  // }\n+  //\n+  // disposable.dispose()\n+  // ```\n+  //\n+  // To watch paths outside of open projects, use the `watchPaths` function instead; see {PathWatcher}.\n+  //\n+  // When writing tests against functionality that uses this method, be sure to wait for the\n+  // {Promise} returned by {getWatcherPromise()} before manipulating the filesystem to ensure that\n+  // the watcher is receiving events.\n+  //\n+  // * `callback` {Function} to be called with batches of filesystem events reported by\n+  //   the operating system.\n+  //    * `events` An {Array} of objects that describe a batch of filesystem events.\n+  //     * `action` {String} describing the filesystem action that occurred. One of `\"created\"`,\n+  //       `\"modified\"`, `\"deleted\"`, or `\"renamed\"`.\n+  //     * `path` {String} containing the absolute path to the filesystem entry\n+  //       that was acted upon.\n+  //     * `oldPath` For rename events, {String} containing the filesystem entry's\n+  //       former absolute path.\n+  //\n+  // Returns a {Disposable} to manage this event subscription.\n+  onDidChangeFiles (callback) {\n+    return this.emitter.on('did-change-files', callback)\n+  }\n+\n+  /*\n+  Section: Accessing the git repository\n+  */\n+\n+  // Public: Get an {Array} of {GitRepository}s associated with the project's\n+  // directories.\n+  //\n+  // This method will be removed in 2.0 because it does synchronous I/O.\n+  // Prefer the following, which evaluates to a {Promise} that resolves to an\n+  // {Array} of {Repository} objects:\n+  // ```\n+  // Promise.all(atom.project.getDirectories().map(\n+  //     atom.project.repositoryForDirectory.bind(atom.project)))\n+  // ```\n+  getRepositories () {\n+    return this.repositories\n+  }\n+\n+  // Public: Get the repository for a given directory asynchronously.\n+  //\n+  // * `directory` {Directory} for which to get a {Repository}.\n+  //\n+  // Returns a {Promise} that resolves with either:\n+  // * {Repository} if a repository can be created for the given directory\n+  // * `null` if no repository can be created for the given directory.\n+  repositoryForDirectory (directory) {\n+    const pathForDirectory = directory.getRealPathSync()\n+    let promise = this.repositoryPromisesByPath.get(pathForDirectory)\n+    if (!promise) {\n+      const promises = this.repositoryProviders.map((provider) =>\n+        provider.repositoryForDirectory(directory)\n+      )\n+      promise = Promise.all(promises).then((repositories) => {\n+        const repo = repositories.find((repo) => repo != null) || null\n+\n+        // If no repository is found, remove the entry for the directory in\n+        // @repositoryPromisesByPath in case some other RepositoryProvider is\n+        // registered in the future that could supply a Repository for the\n+        // directory.\n+        if (repo == null) this.repositoryPromisesByPath.delete(pathForDirectory)\n+\n+        if (repo && repo.onDidDestroy) {\n+          repo.onDidDestroy(() => this.repositoryPromisesByPath.delete(pathForDirectory))\n+        }\n+\n+        return repo\n+      })\n+      this.repositoryPromisesByPath.set(pathForDirectory, promise)\n+    }\n+    return promise\n+  }\n+\n+  /*\n+  Section: Managing Paths\n+  */\n+\n+  // Public: Get an {Array} of {String}s containing the paths of the project's\n+  // directories.\n+  getPaths () {\n+    return this.rootDirectories.map((rootDirectory) => rootDirectory.getPath())\n+  }\n+\n+  // Public: Set the paths of the project's directories.\n+  //\n+  // * `projectPaths` {Array} of {String} paths.\n+  // * `options` An optional {Object} that may contain the following keys:\n+  //   * `mustExist` If `true`, throw an Error if any `projectPaths` do not exist. Any remaining `projectPaths` that\n+  //     do exist will still be added to the project. Default: `false`.\n+  //   * `exact` If `true`, only add a `projectPath` if it names an existing directory. If `false` and any `projectPath`\n+  //     is a file or does not exist, its parent directory will be added instead. Default: `false`.\n+  setPaths (projectPaths, options = {}) {\n+    for (let repository of this.repositories) {\n+      if (repository != null) repository.destroy()\n+    }\n+    this.rootDirectories = []\n+    this.repositories = []\n+\n+    for (let path in this.watcherPromisesByPath) {\n+      this.watcherPromisesByPath[path].then(watcher => { watcher.dispose() })\n+    }\n+    this.watcherPromisesByPath = {}\n+\n+    const missingProjectPaths = []\n+    for (let projectPath of projectPaths) {\n+      try {\n+        this.addPath(projectPath, {emitEvent: false, mustExist: true, exact: options.exact === true})\n+      } catch (e) {\n+        if (e.missingProjectPaths != null) {\n+          missingProjectPaths.push(...e.missingProjectPaths)\n+        } else {\n+          throw e\n+        }\n+      }\n+    }\n+\n+    this.emitter.emit('did-change-paths', projectPaths)\n+\n+    if ((options.mustExist === true) && (missingProjectPaths.length > 0)) {\n+      const err = new Error('One or more project directories do not exist')\n+      err.missingProjectPaths = missingProjectPaths\n+      throw err\n+    }\n+  }\n+\n+  // Public: Add a path to the project's list of root paths\n+  //\n+  // * `projectPath` {String} The path to the directory to add.\n+  // * `options` An optional {Object} that may contain the following keys:\n+  //   * `mustExist` If `true`, throw an Error if the `projectPath` does not exist. If `false`, a `projectPath` that does\n+  //     not exist is ignored. Default: `false`.\n+  //   * `exact` If `true`, only add `projectPath` if it names an existing directory. If `false`, if `projectPath` is a\n+  //     a file or does not exist, its parent directory will be added instead.\n+  addPath (projectPath, options = {}) {\n+    const directory = this.getDirectoryForProjectPath(projectPath)\n+\n+    let ok = true\n+    if (options.exact === true) {\n+      ok = (directory.getPath() === projectPath)\n+    }\n+    ok = ok && directory.existsSync()\n+\n+    if (!ok) {\n+      if (options.mustExist === true) {\n+        const err = new Error(`Project directory ${directory} does not exist`)\n+        err.missingProjectPaths = [projectPath]\n+        throw err\n+      } else {\n+        return\n+      }\n+    }\n+\n+    for (let existingDirectory of this.getDirectories()) {\n+      if (existingDirectory.getPath() === directory.getPath()) { return }\n+    }\n+\n+    this.rootDirectories.push(directory)\n+    this.watcherPromisesByPath[directory.getPath()] = watchPath(directory.getPath(), {}, events => {\n+      // Stop event delivery immediately on removal of a rootDirectory, even if its watcher\n+      // promise has yet to resolve at the time of removal\n+      if (this.rootDirectories.includes(directory)) {\n+        this.emitter.emit('did-change-files', events)\n+      }\n+    })\n+\n+    for (let path in this.watcherPromisesByPath) {\n+      if (!this.rootDirectories.find(dir => dir.getPath() === path)) {\n+        this.watcherPromisesByPath[path].then(watcher => { watcher.dispose() })\n+      }\n+    }","path":"src/project.js","position":353,"original_position":353,"commit_id":"5ec9d0f1347eda1aecea72ab00348a56eb3d0ec6","original_commit_id":"5ec9d0f1347eda1aecea72ab00348a56eb3d0ec6","user":{"login":"smashwilson","id":17565,"avatar_url":"https://avatars2.githubusercontent.com/u/17565?v=4","gravatar_id":"","url":"https://api.github.com/users/smashwilson","html_url":"https://github.com/smashwilson","followers_url":"https://api.github.com/users/smashwilson/followers","following_url":"https://api.github.com/users/smashwilson/following{/other_user}","gists_url":"https://api.github.com/users/smashwilson/gists{/gist_id}","starred_url":"https://api.github.com/users/smashwilson/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/smashwilson/subscriptions","organizations_url":"https://api.github.com/users/smashwilson/orgs","repos_url":"https://api.github.com/users/smashwilson/repos","events_url":"https://api.github.com/users/smashwilson/events{/privacy}","received_events_url":"https://api.github.com/users/smashwilson/received_events","type":"User","site_admin":true},"body":"Oh yikes. I remember getting a bit confused about which collections contained paths and which contained Directory objects... looks like I missed one!\r\n\r\n> Note that this PR also renames the `root` local to `path` to clarify that we know the item is a _path_, but we don't know whether it is a _root_ path.)\r\n\r\nI'm :+1: on renaming `root` to clarify this, but I'd advise against calling it `path`. I've hit too many problems with inadvertently shadowing or overwriting the import from node's \"path\" module :smile: How about `rootPath`?","created_at":"2017-10-16T13:45:15Z","updated_at":"2017-10-16T13:45:15Z","html_url":"https://github.com/atom/atom/pull/15898#discussion_r144850427","pull_request_url":"https://api.github.com/repos/atom/atom/pulls/15898","author_association":"OWNER","_links":{"self":{"href":"https://api.github.com/repos/atom/atom/pulls/comments/144850427"},"html":{"href":"https://github.com/atom/atom/pull/15898#discussion_r144850427"},"pull_request":{"href":"https://api.github.com/repos/atom/atom/pulls/15898"}},"in_reply_to_id":144731498},"pull_request":{"url":"https://api.github.com/repos/atom/atom/pulls/15898","id":146667320,"html_url":"https://github.com/atom/atom/pull/15898","diff_url":"https://github.com/atom/atom/pull/15898.diff","patch_url":"https://github.com/atom/atom/pull/15898.patch","issue_url":"https://api.github.com/repos/atom/atom/issues/15898","number":15898,"state":"open","locked":false,"title":"Decaffeinate `src/project.coffee`","user":{"login":"jasonrudolph","id":2988,"avatar_url":"https://avatars3.githubusercontent.com/u/2988?v=4","gravatar_id":"","url":"https://api.github.com/users/jasonrudolph","html_url":"https://github.com/jasonrudolph","followers_url":"https://api.github.com/users/jasonrudolph/followers","following_url":"https://api.github.com/users/jasonrudolph/following{/other_user}","gists_url":"https://api.github.com/users/jasonrudolph/gists{/gist_id}","starred_url":"https://api.github.com/users/jasonrudolph/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jasonrudolph/subscriptions","organizations_url":"https://api.github.com/users/jasonrudolph/orgs","repos_url":"https://api.github.com/users/jasonrudolph/repos","events_url":"https://api.github.com/users/jasonrudolph/events{/privacy}","received_events_url":"https://api.github.com/users/jasonrudolph/received_events","type":"User","site_admin":true},"body":"This change converts the `Project` class to JavaScript with [standard style](https://standardjs.com).","created_at":"2017-10-15T20:31:03Z","updated_at":"2017-10-16T13:45:15Z","closed_at":null,"merged_at":null,"merge_commit_sha":"21662df2237e8798426303c2c4a1fe325b98529c","assignee":null,"assignees":[],"requested_reviewers":[],"milestone":null,"commits_url":"https://api.github.com/repos/atom/atom/pulls/15898/commits","review_comments_url":"https://api.github.com/repos/atom/atom/pulls/15898/comments","review_comment_url":"https://api.github.com/repos/atom/atom/pulls/comments{/number}","comments_url":"https://api.github.com/repos/atom/atom/issues/15898/comments","statuses_url":"https://api.github.com/repos/atom/atom/statuses/5ec9d0f1347eda1aecea72ab00348a56eb3d0ec6","head":{"label":"atom:decaf-project","ref":"decaf-project","sha":"5ec9d0f1347eda1aecea72ab00348a56eb3d0ec6","user":{"login":"atom","id":1089146,"avatar_url":"https://avatars2.githubusercontent.com/u/1089146?v=4","gravatar_id":"","url":"https://api.github.com/users/atom","html_url":"https://github.com/atom","followers_url":"https://api.github.com/users/atom/followers","following_url":"https://api.github.com/users/atom/following{/other_user}","gists_url":"https://api.github.com/users/atom/gists{/gist_id}","starred_url":"https://api.github.com/users/atom/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/atom/subscriptions","organizations_url":"https://api.github.com/users/atom/orgs","repos_url":"https://api.github.com/users/atom/repos","events_url":"https://api.github.com/users/atom/events{/privacy}","received_events_url":"https://api.github.com/users/atom/received_events","type":"Organization","site_admin":false},"repo":{"id":3228505,"name":"atom","full_name":"atom/atom","owner":{"login":"atom","id":1089146,"avatar_url":"https://avatars2.githubusercontent.com/u/1089146?v=4","gravatar_id":"","url":"https://api.github.com/users/atom","html_url":"https://github.com/atom","followers_url":"https://api.github.com/users/atom/followers","following_url":"https://api.github.com/users/atom/following{/other_user}","gists_url":"https://api.github.com/users/atom/gists{/gist_id}","starred_url":"https://api.github.com/users/atom/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/atom/subscriptions","organizations_url":"https://api.github.com/users/atom/orgs","repos_url":"https://api.github.com/users/atom/repos","events_url":"https://api.github.com/users/atom/events{/privacy}","received_events_url":"https://api.github.com/users/atom/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/atom/atom","description":":atom: The hackable text editor","fork":false,"url":"https://api.github.com/repos/atom/atom","forks_url":"https://api.github.com/repos/atom/atom/forks","keys_url":"https://api.github.com/repos/atom/atom/keys{/key_id}","collaborators_url":"https://api.github.com/repos/atom/atom/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/atom/atom/teams","hooks_url":"https://api.github.com/repos/atom/atom/hooks","issue_events_url":"https://api.github.com/repos/atom/atom/issues/events{/number}","events_url":"https://api.github.com/repos/atom/atom/events","assignees_url":"https://api.github.com/repos/atom/atom/assignees{/user}","branches_url":"https://api.github.com/repos/atom/atom/branches{/branch}","tags_url":"https://api.github.com/repos/atom/atom/tags","blobs_url":"https://api.github.com/repos/atom/atom/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/atom/atom/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/atom/atom/git/refs{/sha}","trees_url":"https://api.github.com/repos/atom/atom/git/trees{/sha}","statuses_url":"https://api.github.com/repos/atom/atom/statuses/{sha}","languages_url":"https://api.github.com/repos/atom/atom/languages","stargazers_url":"https://api.github.com/repos/atom/atom/stargazers","contributors_url":"https://api.github.com/repos/atom/atom/contributors","subscribers_url":"https://api.github.com/repos/atom/atom/subscribers","subscription_url":"https://api.github.com/repos/atom/atom/subscription","commits_url":"https://api.github.com/repos/atom/atom/commits{/sha}","git_commits_url":"https://api.github.com/repos/atom/atom/git/commits{/sha}","comments_url":"https://api.github.com/repos/atom/atom/comments{/number}","issue_comment_url":"https://api.github.com/repos/atom/atom/issues/comments{/number}","contents_url":"https://api.github.com/repos/atom/atom/contents/{+path}","compare_url":"https://api.github.com/repos/atom/atom/compare/{base}...{head}","merges_url":"https://api.github.com/repos/atom/atom/merges","archive_url":"https://api.github.com/repos/atom/atom/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/atom/atom/downloads","issues_url":"https://api.github.com/repos/atom/atom/issues{/number}","pulls_url":"https://api.github.com/repos/atom/atom/pulls{/number}","milestones_url":"https://api.github.com/repos/atom/atom/milestones{/number}","notifications_url":"https://api.github.com/repos/atom/atom/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/atom/atom/labels{/name}","releases_url":"https://api.github.com/repos/atom/atom/releases{/id}","deployments_url":"https://api.github.com/repos/atom/atom/deployments","created_at":"2012-01-20T18:18:21Z","updated_at":"2017-10-16T12:51:56Z","pushed_at":"2017-10-16T10:09:33Z","git_url":"git://github.com/atom/atom.git","ssh_url":"git@github.com:atom/atom.git","clone_url":"https://github.com/atom/atom.git","svn_url":"https://github.com/atom/atom","homepage":"https://atom.io","size":299099,"stargazers_count":40954,"watchers_count":40954,"language":"JavaScript","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":7602,"mirror_url":null,"open_issues_count":942,"forks":7602,"open_issues":942,"watchers":40954,"default_branch":"master"}},"base":{"label":"atom:master","ref":"master","sha":"8952cd315d44b7730ed686c2be14a9dc32d1e529","user":{"login":"atom","id":1089146,"avatar_url":"https://avatars2.githubusercontent.com/u/1089146?v=4","gravatar_id":"","url":"https://api.github.com/users/atom","html_url":"https://github.com/atom","followers_url":"https://api.github.com/users/atom/followers","following_url":"https://api.github.com/users/atom/following{/other_user}","gists_url":"https://api.github.com/users/atom/gists{/gist_id}","starred_url":"https://api.github.com/users/atom/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/atom/subscriptions","organizations_url":"https://api.github.com/users/atom/orgs","repos_url":"https://api.github.com/users/atom/repos","events_url":"https://api.github.com/users/atom/events{/privacy}","received_events_url":"https://api.github.com/users/atom/received_events","type":"Organization","site_admin":false},"repo":{"id":3228505,"name":"atom","full_name":"atom/atom","owner":{"login":"atom","id":1089146,"avatar_url":"https://avatars2.githubusercontent.com/u/1089146?v=4","gravatar_id":"","url":"https://api.github.com/users/atom","html_url":"https://github.com/atom","followers_url":"https://api.github.com/users/atom/followers","following_url":"https://api.github.com/users/atom/following{/other_user}","gists_url":"https://api.github.com/users/atom/gists{/gist_id}","starred_url":"https://api.github.com/users/atom/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/atom/subscriptions","organizations_url":"https://api.github.com/users/atom/orgs","repos_url":"https://api.github.com/users/atom/repos","events_url":"https://api.github.com/users/atom/events{/privacy}","received_events_url":"https://api.github.com/users/atom/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/atom/atom","description":":atom: The hackable text editor","fork":false,"url":"https://api.github.com/repos/atom/atom","forks_url":"https://api.github.com/repos/atom/atom/forks","keys_url":"https://api.github.com/repos/atom/atom/keys{/key_id}","collaborators_url":"https://api.github.com/repos/atom/atom/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/atom/atom/teams","hooks_url":"https://api.github.com/repos/atom/atom/hooks","issue_events_url":"https://api.github.com/repos/atom/atom/issues/events{/number}","events_url":"https://api.github.com/repos/atom/atom/events","assignees_url":"https://api.github.com/repos/atom/atom/assignees{/user}","branches_url":"https://api.github.com/repos/atom/atom/branches{/branch}","tags_url":"https://api.github.com/repos/atom/atom/tags","blobs_url":"https://api.github.com/repos/atom/atom/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/atom/atom/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/atom/atom/git/refs{/sha}","trees_url":"https://api.github.com/repos/atom/atom/git/trees{/sha}","statuses_url":"https://api.github.com/repos/atom/atom/statuses/{sha}","languages_url":"https://api.github.com/repos/atom/atom/languages","stargazers_url":"https://api.github.com/repos/atom/atom/stargazers","contributors_url":"https://api.github.com/repos/atom/atom/contributors","subscribers_url":"https://api.github.com/repos/atom/atom/subscribers","subscription_url":"https://api.github.com/repos/atom/atom/subscription","commits_url":"https://api.github.com/repos/atom/atom/commits{/sha}","git_commits_url":"https://api.github.com/repos/atom/atom/git/commits{/sha}","comments_url":"https://api.github.com/repos/atom/atom/comments{/number}","issue_comment_url":"https://api.github.com/repos/atom/atom/issues/comments{/number}","contents_url":"https://api.github.com/repos/atom/atom/contents/{+path}","compare_url":"https://api.github.com/repos/atom/atom/compare/{base}...{head}","merges_url":"https://api.github.com/repos/atom/atom/merges","archive_url":"https://api.github.com/repos/atom/atom/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/atom/atom/downloads","issues_url":"https://api.github.com/repos/atom/atom/issues{/number}","pulls_url":"https://api.github.com/repos/atom/atom/pulls{/number}","milestones_url":"https://api.github.com/repos/atom/atom/milestones{/number}","notifications_url":"https://api.github.com/repos/atom/atom/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/atom/atom/labels{/name}","releases_url":"https://api.github.com/repos/atom/atom/releases{/id}","deployments_url":"https://api.github.com/repos/atom/atom/deployments","created_at":"2012-01-20T18:18:21Z","updated_at":"2017-10-16T12:51:56Z","pushed_at":"2017-10-16T10:09:33Z","git_url":"git://github.com/atom/atom.git","ssh_url":"git@github.com:atom/atom.git","clone_url":"https://github.com/atom/atom.git","svn_url":"https://github.com/atom/atom","homepage":"https://atom.io","size":299099,"stargazers_count":40954,"watchers_count":40954,"language":"JavaScript","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":7602,"mirror_url":null,"open_issues_count":942,"forks":7602,"open_issues":942,"watchers":40954,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/atom/atom/pulls/15898"},"html":{"href":"https://github.com/atom/atom/pull/15898"},"issue":{"href":"https://api.github.com/repos/atom/atom/issues/15898"},"comments":{"href":"https://api.github.com/repos/atom/atom/issues/15898/comments"},"review_comments":{"href":"https://api.github.com/repos/atom/atom/pulls/15898/comments"},"review_comment":{"href":"https://api.github.com/repos/atom/atom/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/atom/atom/pulls/15898/commits"},"statuses":{"href":"https://api.github.com/repos/atom/atom/statuses/5ec9d0f1347eda1aecea72ab00348a56eb3d0ec6"}},"author_association":"OWNER"}}
{"actor":{"display_login":"smashwilson"}}