{"action":"created","comment":{"url":"https://api.github.com/repos/apple/swift/pulls/comments/171750934","pull_request_review_id":100660470,"id":171750934,"diff_hunk":"@@ -214,3 +194,121 @@ func _combineHashValues(_ firstValue: Int, _ secondValue: Int) -> Int {\n   x ^= UInt(bitPattern: secondValue) &+ magic &+ (x &<< 6) &+ (x &>> 2)\n   return Int(bitPattern: x)\n }\n+\n+/// An unsafe wrapper around a stateful hash function, presenting a faux purely\n+/// functional interface to eliminate ARC overhead.\n+///\n+/// This is not a true value type; calling `appending` or `finalized` actually\n+/// mutates `self`'s state.\n+@_fixed_layout\n+public struct _UnsafeHasher {\n+  @_versioned\n+  internal let _rawState: UnsafeMutableRawPointer\n+\n+  internal var _state: UnsafeMutablePointer<_Hasher> {\n+    @inline(__always)\n+    get { return _rawState.assumingMemoryBound(to: _Hasher.self) }\n+  }\n+\n+  @inline(__always)\n+  @_versioned\n+  internal init(_ state: UnsafeMutablePointer<_Hasher>) {\n+    self._rawState = UnsafeMutableRawPointer(state)\n+  }\n+\n+  @_versioned\n+  // not @_inlineable\n+  @effects(readonly) // FIXME(hasher): Unjustified\n+  static func hashValue<H: Hashable>(for pointer: UnsafePointer<H>) -> Int {\n+    var hasher = _Hasher()\n+    return withUnsafeMutablePointer(to: &hasher) { p in\n+      return pointer.pointee._hash(into: _UnsafeHasher(p))._finalized()\n+    }\n+  }\n+\n+  @_versioned\n+  // not @_inlineable\n+  @effects(readonly)\n+  internal func appending(bits value: UInt) -> _UnsafeHasher {\n+    // The effects attribute is a lie; however, it enables the compiler to\n+    // eliminate unnecessary retain/releases protecting Hashable state around\n+    // calls to `_Hasher.append(_:)`.\n+    //","path":"stdlib/public/core/Hashing.swift","position":163,"original_position":163,"commit_id":"5f31aeedd4ac93cd7caa9ce705cd5ba7860e5a74","original_commit_id":"5f31aeedd4ac93cd7caa9ce705cd5ba7860e5a74","user":{"login":"lorentey","id":608696,"avatar_url":"https://avatars3.githubusercontent.com/u/608696?v=4","gravatar_id":"","url":"https://api.github.com/users/lorentey","html_url":"https://github.com/lorentey","followers_url":"https://api.github.com/users/lorentey/followers","following_url":"https://api.github.com/users/lorentey/following{/other_user}","gists_url":"https://api.github.com/users/lorentey/gists{/gist_id}","starred_url":"https://api.github.com/users/lorentey/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lorentey/subscriptions","organizations_url":"https://api.github.com/users/lorentey/orgs","repos_url":"https://api.github.com/users/lorentey/repos","events_url":"https://api.github.com/users/lorentey/events{/privacy}","received_events_url":"https://api.github.com/users/lorentey/received_events","type":"User","site_admin":false},"body":"The fun thing is that a fully immutable SipHash implementation (with a 100% valid `@effect(readonly)` declaration) actually performed surprisingly well, considering it had to keep passing around five words. In use it looked exactly the same as this one, except it actually was a real value type.\r\n\r\nHowever, its performance relied on the size/layout of the hasher state being part of the ABI -- hence the clever replacement. Struct resiliency may cause performance problems for the `@effects(releasenone)` mutating case, too -- we'll have to find out.","created_at":"2018-03-02T02:18:57Z","updated_at":"2018-03-02T02:18:58Z","html_url":"https://github.com/apple/swift/pull/14913#discussion_r171750934","pull_request_url":"https://api.github.com/repos/apple/swift/pulls/14913","author_association":"MEMBER","_links":{"self":{"href":"https://api.github.com/repos/apple/swift/pulls/comments/171750934"},"html":{"href":"https://github.com/apple/swift/pull/14913#discussion_r171750934"},"pull_request":{"href":"https://api.github.com/repos/apple/swift/pulls/14913"}},"in_reply_to_id":171743987},"pull_request":{"url":"https://api.github.com/repos/apple/swift/pulls/14913","id":172338528,"html_url":"https://github.com/apple/swift/pull/14913","diff_url":"https://github.com/apple/swift/pull/14913.diff","patch_url":"https://github.com/apple/swift/pull/14913.patch","issue_url":"https://api.github.com/repos/apple/swift/issues/14913","number":14913,"state":"open","locked":false,"title":"🛑 Use SipHash-1-3 for all hashing, through a resilient hashing interface","user":{"login":"lorentey","id":608696,"avatar_url":"https://avatars3.githubusercontent.com/u/608696?v=4","gravatar_id":"","url":"https://api.github.com/users/lorentey","html_url":"https://github.com/lorentey","followers_url":"https://api.github.com/users/lorentey/followers","following_url":"https://api.github.com/users/lorentey/following{/other_user}","gists_url":"https://api.github.com/users/lorentey/gists{/gist_id}","starred_url":"https://api.github.com/users/lorentey/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lorentey/subscriptions","organizations_url":"https://api.github.com/users/lorentey/orgs","repos_url":"https://api.github.com/users/lorentey/repos","events_url":"https://api.github.com/users/lorentey/events{/privacy}","received_events_url":"https://api.github.com/users/lorentey/received_events","type":"User","site_admin":false},"body":"This PR implements resilient hashing for stdlib types and types with synthesized `Hashable` implementations. It changes the standard hash function to SipHash-1-3 with a per-execution random seed.\r\n\r\n### Background \r\n\r\nHash tables are probabilistic data structures; their expected performance depends on (implicit and largely unknown) assumptions on the statistical distribution of their keys and the properties of the hash function that is used to derive bucket indices for individual key values.\r\n\r\nWeak hash functions can enable accidental (or deliberate) skewing of the key distribution in such a way that collisions become more likely. In extreme cases, lookup performance may become linear rather than the promised O(1), which may turn other operations using lookups quadratic rather than linear, etc. This is not a hypothetical concern: there have been major cases of successful denial of service attacks targeted against hash tables implemented in various programming languages and libraries.\r\n\r\nIn general purpose collection types like Swift's `Set` or `Dictionary`, we can't meaningfully constrain the distribution of keys. Our only option to protect against hash collision cascades is to choose a hash function that's strong enough to handle *all* key distributions, ideally even those that deliberately try to defeat it.\r\n\r\n### The Status Quo\r\n\r\nOur current approach is not particularly great in this regard: the choice of the hash function is mostly in the hands of the programmer implementing `hashValue`, and we provide no public API to guide them. Implementing a good hash function requires careful consideration and specialist knowledge; it takes time and effort they clearly can't be expected to invest. \r\n\r\nTo fix this, we should start by improving cases where `hashValue` is under Swift's control: inside the Standard Library and in `Hashable` implementations synthesized by the compiler. For these, we currently rely on two underscored functions:\r\n\r\n- `_mixInt: (Int) -> Int` was designed to be used as a `hashValue` post-processing tool in hashed collections, improving distribution of user-generated hash values so that occupied buckets are less likely to bunch together in long chains. It does a fine job on this task; however, `hash ^= _mixInt(foo)` has been widely (mis)used as a rudimentary compression function, providing essentially no protection against even trivial accidental collisions.\r\n- `_combineHashes: (Int, Int) -> Int` is our recently introduced hash compression function, used in synthesized `Hashable` implementations. Its current implementation wasn't designed to protect against deliberate collisions, even if we were to seed it with a random key. Unfortunately, its stateless interface severely limits the scope of hash functions it can implement. For example, SipHash needs to maintain 256 bits of state; it is not possible to fit that into this interface.\r\n\r\nThis PR intends to improve matters by standardizing on a high quality hash function, SipHash, for use inside the standard library and inside compiler-synthesized `Hashable` implementations. (SipHash is already implemented in the stdlib, but so far it has been sitting there largely unused.)\r\n\r\nThis PR does not introduce public API to help with manual `Hashable` implementations -- but it provides the first step towards providing one.\r\n\r\n### Requirements\r\n\r\n- **Stateful hash function** -- We need to be able to support hash functions with a state larger than a single pointer-sized integer.\r\n- **Random hash seeding** -- `Hashable` has been documented since Swift 1.0 to allow per-execution hash seeds, but so far we have only implemented random seeds for Strings on non-Apple platforms. Random seeding makes hash values harder to predict; we need to enable it on all platforms and all `Hashable` types. (In some contexts, we may want to go further and introduce local seeds for each Dictionary capacity (or even instance). But a per-execution seed is the obvious first step.)\r\n- **Resiliency** -- To enable us to replace/evolve the hash function in future versions of the stdlib, the hash algorithm must not be baked into types implementing `Hashable`; it must be implemented entirely behind resiliency boundaries. (Ideally this includes the size/layout of the state, not just the code itself.)\r\n\r\n### New `Hashable` Requirement\r\n\r\nTo satisfy these constraints, this PR adds a new requirement to `Hashable` that allows the hash function to be supplied externally:\r\n\r\n```swift\r\nprotocol Hashable {\r\n  var hashValue: Int { get } // Existing public interface\r\n  func _hash(into hasher: _UnsafeHasher) -> _UnsafeHasher // New internal hotness\r\n}\r\n```\r\n\r\nThe new requirement is not designed to be manually implemented outside the stdlib, so it remains underscored, with a default implementation. `hashValue` remains the public API for manual hashing. To help users provide high-quality `hashValue` implementations, we may expose the stdlib's resilient hash function as API later; that API is to be designed, but it will be likely close to the mutating interface of `_SipHash13`.\r\n\r\n`_UnsafeHasher` represents the internal state of the hash function. It provides a faux-pure interface to append additional bits to the hash function, mixing them into the state. Its only public API is `appending<H>(_:)`, for appending arbitrary hashable values. For example, here is the derived `Hashable` implementation for a simple `Book` struct:\r\n\r\n```swift\r\nstruct Book: Hashable {\r\n  let title: String\r\n  let authors: [Author]\r\n  let pageCount: Int\r\n\r\n  @derived var hashValue: Int { \r\n    return _hashValue(for: self) \r\n  }\r\n  @derived func _hash(into hasher: _UnsafeHasher) -> _UnsafeHasher {\r\n    return hasher\r\n      .appending(title)\r\n      .appending(authors)\r\n      .appending(pageCount)\r\n  }\r\n}\r\n```\r\n\r\nWhile it looks like a purely functional type, `_UnsafeHasher` is in fact just a wrapper around an opaque pointer to a stack-allocated hash state; the functional interface makes it easier to eliminate ARC operations around calls into the opaque functions implementing SipHash. (It has the `Unsafe` prefix because it is not actually a value type; it is not safe to copy it around or to hold onto it after returning from `_hash(into:)`.)\r\n\r\n`_UnsafeHasher` intentionally has no public initializers and no public finalizers.\r\n\r\n### Synthesized `Hashable` Implementations\r\n\r\nSynthesized implementations of `Hashable` now generate a `_hash(into:)` implementation that does the actual work of hashing a type's components. The generated `hashValue` implementation simply instantiates a new hasher and feeds it to `_hash(into:)`.\r\n\r\nBecause `_hash(into:)` has a default implementation, this PR synthesizes custom implementations of it in an underhanded way, piggybacking on the `hashValue` derivation. This is not ideal, but this method led to the fewest actual problems -- see the commit message for e3d0e48 detailing a nicer alternative that turned out to be worse in practice, at least without further work.\r\n\r\n### Per-execution Random Hash Seed\r\n\r\nIntroducing a per-execution hash seed fulfills a long-standing prophecy in the documentation about hash values not being stable across different executions. Indeed, not even integers return a predictable `hashValue` any more:\r\n\r\n```shell\r\n$ cat hash.swift\r\nprint(\"42.hashValue = \\(42.hashValue)\")\r\n$ swiftc hash.swift\r\n$ ./hash\r\n42.hashValue = 4676625759386310310\r\n$ ./hash\r\n42.hashValue = -2488622482260669029\r\n```\r\n\r\n(The hash values remain stable within the same process, though.) To enable repeatable results in cases like unit testing, the 128-bit hash seed is exposed as `_Hashing.secretKey`; setting it to a fixed constant value disables randomization. Currently this needs to be done before the first `Set` or `Dictionary` is created. `StdlibUnitTest.TestSuite` in the Swift test suite automatically zeroes out the key when it is first instantiated.\r\n\r\n### Performance\r\n\r\nSipHash is more reliable, but it's also a bit more complicated than `_mixInt`/`_combineHashes`. Resiliency also adds a little bit of extra overhead. At the end of the day, #14442 measured these changes to cost up to +80% performance on our microbenchmarks. I expect we'll be able to optimize things further after this lands.\r\n\r\n<!-- If this pull request resolves any bugs in the Swift bug tracker, provide a link: -->\r\nResolves rdar://problem/24109692, rdar://problem/35052153","created_at":"2018-03-01T20:01:46Z","updated_at":"2018-03-02T02:18:58Z","closed_at":null,"merged_at":null,"merge_commit_sha":"e89c93044815d807d047de7c5b97864af6d70592","assignee":null,"assignees":[],"requested_reviewers":[{"login":"moiseev","id":64011,"avatar_url":"https://avatars3.githubusercontent.com/u/64011?v=4","gravatar_id":"","url":"https://api.github.com/users/moiseev","html_url":"https://github.com/moiseev","followers_url":"https://api.github.com/users/moiseev/followers","following_url":"https://api.github.com/users/moiseev/following{/other_user}","gists_url":"https://api.github.com/users/moiseev/gists{/gist_id}","starred_url":"https://api.github.com/users/moiseev/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/moiseev/subscriptions","organizations_url":"https://api.github.com/users/moiseev/orgs","repos_url":"https://api.github.com/users/moiseev/repos","events_url":"https://api.github.com/users/moiseev/events{/privacy}","received_events_url":"https://api.github.com/users/moiseev/received_events","type":"User","site_admin":false},{"login":"milseman","id":235334,"avatar_url":"https://avatars0.githubusercontent.com/u/235334?v=4","gravatar_id":"","url":"https://api.github.com/users/milseman","html_url":"https://github.com/milseman","followers_url":"https://api.github.com/users/milseman/followers","following_url":"https://api.github.com/users/milseman/following{/other_user}","gists_url":"https://api.github.com/users/milseman/gists{/gist_id}","starred_url":"https://api.github.com/users/milseman/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/milseman/subscriptions","organizations_url":"https://api.github.com/users/milseman/orgs","repos_url":"https://api.github.com/users/milseman/repos","events_url":"https://api.github.com/users/milseman/events{/privacy}","received_events_url":"https://api.github.com/users/milseman/received_events","type":"User","site_admin":false},{"login":"lancep","id":1613881,"avatar_url":"https://avatars2.githubusercontent.com/u/1613881?v=4","gravatar_id":"","url":"https://api.github.com/users/lancep","html_url":"https://github.com/lancep","followers_url":"https://api.github.com/users/lancep/followers","following_url":"https://api.github.com/users/lancep/following{/other_user}","gists_url":"https://api.github.com/users/lancep/gists{/gist_id}","starred_url":"https://api.github.com/users/lancep/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lancep/subscriptions","organizations_url":"https://api.github.com/users/lancep/orgs","repos_url":"https://api.github.com/users/lancep/repos","events_url":"https://api.github.com/users/lancep/events{/privacy}","received_events_url":"https://api.github.com/users/lancep/received_events","type":"User","site_admin":false},{"login":"airspeedswift","id":8058277,"avatar_url":"https://avatars1.githubusercontent.com/u/8058277?v=4","gravatar_id":"","url":"https://api.github.com/users/airspeedswift","html_url":"https://github.com/airspeedswift","followers_url":"https://api.github.com/users/airspeedswift/followers","following_url":"https://api.github.com/users/airspeedswift/following{/other_user}","gists_url":"https://api.github.com/users/airspeedswift/gists{/gist_id}","starred_url":"https://api.github.com/users/airspeedswift/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/airspeedswift/subscriptions","organizations_url":"https://api.github.com/users/airspeedswift/orgs","repos_url":"https://api.github.com/users/airspeedswift/repos","events_url":"https://api.github.com/users/airspeedswift/events{/privacy}","received_events_url":"https://api.github.com/users/airspeedswift/received_events","type":"User","site_admin":false}],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/apple/swift/pulls/14913/commits","review_comments_url":"https://api.github.com/repos/apple/swift/pulls/14913/comments","review_comment_url":"https://api.github.com/repos/apple/swift/pulls/comments{/number}","comments_url":"https://api.github.com/repos/apple/swift/issues/14913/comments","statuses_url":"https://api.github.com/repos/apple/swift/statuses/5f31aeedd4ac93cd7caa9ce705cd5ba7860e5a74","head":{"label":"lorentey:resilient-hashing","ref":"resilient-hashing","sha":"5f31aeedd4ac93cd7caa9ce705cd5ba7860e5a74","user":{"login":"lorentey","id":608696,"avatar_url":"https://avatars3.githubusercontent.com/u/608696?v=4","gravatar_id":"","url":"https://api.github.com/users/lorentey","html_url":"https://github.com/lorentey","followers_url":"https://api.github.com/users/lorentey/followers","following_url":"https://api.github.com/users/lorentey/following{/other_user}","gists_url":"https://api.github.com/users/lorentey/gists{/gist_id}","starred_url":"https://api.github.com/users/lorentey/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lorentey/subscriptions","organizations_url":"https://api.github.com/users/lorentey/orgs","repos_url":"https://api.github.com/users/lorentey/repos","events_url":"https://api.github.com/users/lorentey/events{/privacy}","received_events_url":"https://api.github.com/users/lorentey/received_events","type":"User","site_admin":false},"repo":{"id":50289371,"name":"swift","full_name":"lorentey/swift","owner":{"login":"lorentey","id":608696,"avatar_url":"https://avatars3.githubusercontent.com/u/608696?v=4","gravatar_id":"","url":"https://api.github.com/users/lorentey","html_url":"https://github.com/lorentey","followers_url":"https://api.github.com/users/lorentey/followers","following_url":"https://api.github.com/users/lorentey/following{/other_user}","gists_url":"https://api.github.com/users/lorentey/gists{/gist_id}","starred_url":"https://api.github.com/users/lorentey/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lorentey/subscriptions","organizations_url":"https://api.github.com/users/lorentey/orgs","repos_url":"https://api.github.com/users/lorentey/repos","events_url":"https://api.github.com/users/lorentey/events{/privacy}","received_events_url":"https://api.github.com/users/lorentey/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/lorentey/swift","description":"The Swift Programming Language","fork":true,"url":"https://api.github.com/repos/lorentey/swift","forks_url":"https://api.github.com/repos/lorentey/swift/forks","keys_url":"https://api.github.com/repos/lorentey/swift/keys{/key_id}","collaborators_url":"https://api.github.com/repos/lorentey/swift/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/lorentey/swift/teams","hooks_url":"https://api.github.com/repos/lorentey/swift/hooks","issue_events_url":"https://api.github.com/repos/lorentey/swift/issues/events{/number}","events_url":"https://api.github.com/repos/lorentey/swift/events","assignees_url":"https://api.github.com/repos/lorentey/swift/assignees{/user}","branches_url":"https://api.github.com/repos/lorentey/swift/branches{/branch}","tags_url":"https://api.github.com/repos/lorentey/swift/tags","blobs_url":"https://api.github.com/repos/lorentey/swift/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/lorentey/swift/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/lorentey/swift/git/refs{/sha}","trees_url":"https://api.github.com/repos/lorentey/swift/git/trees{/sha}","statuses_url":"https://api.github.com/repos/lorentey/swift/statuses/{sha}","languages_url":"https://api.github.com/repos/lorentey/swift/languages","stargazers_url":"https://api.github.com/repos/lorentey/swift/stargazers","contributors_url":"https://api.github.com/repos/lorentey/swift/contributors","subscribers_url":"https://api.github.com/repos/lorentey/swift/subscribers","subscription_url":"https://api.github.com/repos/lorentey/swift/subscription","commits_url":"https://api.github.com/repos/lorentey/swift/commits{/sha}","git_commits_url":"https://api.github.com/repos/lorentey/swift/git/commits{/sha}","comments_url":"https://api.github.com/repos/lorentey/swift/comments{/number}","issue_comment_url":"https://api.github.com/repos/lorentey/swift/issues/comments{/number}","contents_url":"https://api.github.com/repos/lorentey/swift/contents/{+path}","compare_url":"https://api.github.com/repos/lorentey/swift/compare/{base}...{head}","merges_url":"https://api.github.com/repos/lorentey/swift/merges","archive_url":"https://api.github.com/repos/lorentey/swift/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/lorentey/swift/downloads","issues_url":"https://api.github.com/repos/lorentey/swift/issues{/number}","pulls_url":"https://api.github.com/repos/lorentey/swift/pulls{/number}","milestones_url":"https://api.github.com/repos/lorentey/swift/milestones{/number}","notifications_url":"https://api.github.com/repos/lorentey/swift/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/lorentey/swift/labels{/name}","releases_url":"https://api.github.com/repos/lorentey/swift/releases{/id}","deployments_url":"https://api.github.com/repos/lorentey/swift/deployments","created_at":"2016-01-24T13:42:07Z","updated_at":"2016-01-24T13:42:21Z","pushed_at":"2018-03-01T20:55:21Z","git_url":"git://github.com/lorentey/swift.git","ssh_url":"git@github.com:lorentey/swift.git","clone_url":"https://github.com/lorentey/swift.git","svn_url":"https://github.com/lorentey/swift","homepage":"https://swift.org/","size":253670,"stargazers_count":0,"watchers_count":0,"language":"C++","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0"},"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"apple:master","ref":"master","sha":"34e77c0f258a989fd800d4b471d136fc11151558","user":{"login":"apple","id":10639145,"avatar_url":"https://avatars0.githubusercontent.com/u/10639145?v=4","gravatar_id":"","url":"https://api.github.com/users/apple","html_url":"https://github.com/apple","followers_url":"https://api.github.com/users/apple/followers","following_url":"https://api.github.com/users/apple/following{/other_user}","gists_url":"https://api.github.com/users/apple/gists{/gist_id}","starred_url":"https://api.github.com/users/apple/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/apple/subscriptions","organizations_url":"https://api.github.com/users/apple/orgs","repos_url":"https://api.github.com/users/apple/repos","events_url":"https://api.github.com/users/apple/events{/privacy}","received_events_url":"https://api.github.com/users/apple/received_events","type":"Organization","site_admin":false},"repo":{"id":44838949,"name":"swift","full_name":"apple/swift","owner":{"login":"apple","id":10639145,"avatar_url":"https://avatars0.githubusercontent.com/u/10639145?v=4","gravatar_id":"","url":"https://api.github.com/users/apple","html_url":"https://github.com/apple","followers_url":"https://api.github.com/users/apple/followers","following_url":"https://api.github.com/users/apple/following{/other_user}","gists_url":"https://api.github.com/users/apple/gists{/gist_id}","starred_url":"https://api.github.com/users/apple/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/apple/subscriptions","organizations_url":"https://api.github.com/users/apple/orgs","repos_url":"https://api.github.com/users/apple/repos","events_url":"https://api.github.com/users/apple/events{/privacy}","received_events_url":"https://api.github.com/users/apple/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/apple/swift","description":"The Swift Programming Language","fork":false,"url":"https://api.github.com/repos/apple/swift","forks_url":"https://api.github.com/repos/apple/swift/forks","keys_url":"https://api.github.com/repos/apple/swift/keys{/key_id}","collaborators_url":"https://api.github.com/repos/apple/swift/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/apple/swift/teams","hooks_url":"https://api.github.com/repos/apple/swift/hooks","issue_events_url":"https://api.github.com/repos/apple/swift/issues/events{/number}","events_url":"https://api.github.com/repos/apple/swift/events","assignees_url":"https://api.github.com/repos/apple/swift/assignees{/user}","branches_url":"https://api.github.com/repos/apple/swift/branches{/branch}","tags_url":"https://api.github.com/repos/apple/swift/tags","blobs_url":"https://api.github.com/repos/apple/swift/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/apple/swift/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/apple/swift/git/refs{/sha}","trees_url":"https://api.github.com/repos/apple/swift/git/trees{/sha}","statuses_url":"https://api.github.com/repos/apple/swift/statuses/{sha}","languages_url":"https://api.github.com/repos/apple/swift/languages","stargazers_url":"https://api.github.com/repos/apple/swift/stargazers","contributors_url":"https://api.github.com/repos/apple/swift/contributors","subscribers_url":"https://api.github.com/repos/apple/swift/subscribers","subscription_url":"https://api.github.com/repos/apple/swift/subscription","commits_url":"https://api.github.com/repos/apple/swift/commits{/sha}","git_commits_url":"https://api.github.com/repos/apple/swift/git/commits{/sha}","comments_url":"https://api.github.com/repos/apple/swift/comments{/number}","issue_comment_url":"https://api.github.com/repos/apple/swift/issues/comments{/number}","contents_url":"https://api.github.com/repos/apple/swift/contents/{+path}","compare_url":"https://api.github.com/repos/apple/swift/compare/{base}...{head}","merges_url":"https://api.github.com/repos/apple/swift/merges","archive_url":"https://api.github.com/repos/apple/swift/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/apple/swift/downloads","issues_url":"https://api.github.com/repos/apple/swift/issues{/number}","pulls_url":"https://api.github.com/repos/apple/swift/pulls{/number}","milestones_url":"https://api.github.com/repos/apple/swift/milestones{/number}","notifications_url":"https://api.github.com/repos/apple/swift/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/apple/swift/labels{/name}","releases_url":"https://api.github.com/repos/apple/swift/releases{/id}","deployments_url":"https://api.github.com/repos/apple/swift/deployments","created_at":"2015-10-23T21:15:07Z","updated_at":"2018-03-02T01:36:40Z","pushed_at":"2018-03-02T02:11:19Z","git_url":"git://github.com/apple/swift.git","ssh_url":"git@github.com:apple/swift.git","clone_url":"https://github.com/apple/swift.git","svn_url":"https://github.com/apple/swift","homepage":"https://swift.org/","size":267491,"stargazers_count":42790,"watchers_count":42790,"language":"C++","has_issues":false,"has_projects":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":6723,"mirror_url":null,"archived":false,"open_issues_count":278,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0"},"forks":6723,"open_issues":278,"watchers":42790,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/apple/swift/pulls/14913"},"html":{"href":"https://github.com/apple/swift/pull/14913"},"issue":{"href":"https://api.github.com/repos/apple/swift/issues/14913"},"comments":{"href":"https://api.github.com/repos/apple/swift/issues/14913/comments"},"review_comments":{"href":"https://api.github.com/repos/apple/swift/pulls/14913/comments"},"review_comment":{"href":"https://api.github.com/repos/apple/swift/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/apple/swift/pulls/14913/commits"},"statuses":{"href":"https://api.github.com/repos/apple/swift/statuses/5f31aeedd4ac93cd7caa9ce705cd5ba7860e5a74"}},"author_association":"MEMBER"}}
{"actor":{"display_login":"lorentey"}}