{"action":"created","comment":{"url":"https://api.github.com/repos/ampproject/amphtml/pulls/comments/81876638","pull_request_review_id":2822773,"id":81876638,"diff_hunk":"@@ -171,226 +113,100 @@ describe('amp-ad-3p-impl', () => {\n       sandbox.stub(adCid, 'getAdCid', () => {\n         return Promise.resolve(undefined);\n       });\n-      return getAd().then(ad => {\n-        const src = ad.firstChild.getAttribute('src');\n+      return ad3p.layoutCallback().then(() => {\n+        const src = ad3p.element.firstChild.getAttribute('src');\n         expect(src).to.contain('\"clientId\":null');\n       });\n     });\n-  });\n \n-  describe('no content handler', () => {\n-    it('should display fallback when there is one and hide placeholder', () => {\n-      return getAd(undefined, undefined, ad => {\n-        const fallback = createElementWithAttributes(document, 'div', {\n-          fallback: '',\n-        });\n-        const placeholder = createElementWithAttributes(document, 'div', {\n-          placeholder: '',\n-        });\n-        ad.appendChild(fallback);\n-        ad.appendChild(placeholder);\n-        expect(placeholder).to.not.have.class('amp-hidden');\n-        return ad;\n-      }).then(ad => {\n-        sandbox.stub(\n-            ad.implementation_, 'deferMutate', function(callback) {\n-              callback();\n-            });\n-        expect(ad).to.not.have.class('amp-notsupported');\n-        const placeholderEl = ad.querySelector('[placeholder]');\n-\n-        ad.implementation_.noContentHandler_();\n-        expect(ad).to.have.class('amp-notsupported');\n-        expect(placeholderEl).to.have.class('amp-hidden');\n-      });\n+    it('should reject if no canonical URL provided', () => {\n+      win.document.head.innerHTML = '';\n+      return expect(ad3p.layoutCallback())\n+          .to.eventually.be.rejectedWith('canonical');\n     });\n \n-    it('should try to change height to 0 and collapse w/o fallback', () => {\n-      return getAd(undefined, undefined, ad => {\n-        return ad;\n-      }).then(ad => {\n-        sandbox.stub(\n-            ad.implementation_, 'deferMutate', function(callback) {\n-              callback();\n-            });\n-        ad.style.position = 'absolute';\n-        ad.style.top = '300px';\n-        ad.style.left = '50px';\n-        expect(ad.style.display).to.not.equal('none');\n-\n-        let changeHeightResolve;\n-        const changeHeightPromise = new Promise(resolve => {\n-          changeHeightResolve = resolve;});\n-        sandbox.stub(ad.implementation_, 'attemptChangeHeight', newHeight => {\n-          expect(newHeight).to.equal(0);\n-          changeHeightResolve();\n-          return Promise.resolve();\n-        });\n-        const collapseSpy = sandbox.spy(ad.implementation_, 'collapse');\n-\n-        ad.implementation_.noContentHandler_();\n-        return changeHeightPromise.then(() => {\n-          expect(collapseSpy).to.have.been.called;\n-          expect(ad.style.display).to.equal('none');\n-        });\n-      });\n+    it('should reject if no type attribute provided', () => {\n+      ad3p.element.removeAttribute('type');\n+      return expect(ad3p.layoutCallback())\n+          .to.eventually.be.rejectedWith('type');\n     });\n \n-    it('should destroy non-master iframe', () => {\n-      return getAd().then(ad => {\n-        ad.implementation_.iframe_.setAttribute(\n-            'name', 'frame_doubleclick_0');\n-        sandbox.stub(\n-            ad.implementation_, 'deferMutate', function(callback) {\n-              callback();\n-            });\n-        ad.implementation_.noContentHandler_();\n-        expect(ad.implementation_.iframe_).to.be.null;\n-      });\n+    it('should throw on position:fixed', () => {\n+      ad3p.element.style.position = 'fixed';\n+      ad3p.onLayoutMeasure();\n+      expect(() => ad3p.layoutCallback()).to.throw('position:fixed');\n     });\n \n-    it('should not destroy a master iframe', () => {\n-      return getAd().then(ad => {\n-        ad.implementation_.iframe_.setAttribute(\n-            'name', 'frame_doubleclick_master');\n-        sandbox.stub(\n-            ad.implementation_, 'deferMutate', function(callback) {\n-              callback();\n-            });\n-        ad.implementation_.noContentHandler_();\n-        expect(ad.implementation_.iframe_).to.not.be.null;\n-      });\n-    });\n-  });\n+    it('should throw on parent being position:fixed', () => {\n+      const adContainerElement = win.document.createElement('div');\n+      adContainerElement.style.position = 'fixed';\n+      win.document.body.appendChild(adContainerElement);\n+      const ad3p = createAmpAd(win);\n+      adContainerElement.appendChild(ad3p.element);\n \n-  describe('renderOutsideViewport', () => {\n-    it('should not return false after scrolling, then false for 1s', () => {\n-      let clock;\n-      return getAd(undefined, undefined, ad => {\n-        clock = lolex.install(ad.implementation_.win);\n-        expect(ad.implementation_.renderOutsideViewport()).not.to.be.false;\n-        return ad;\n-      }).then(ad => {\n-        const impl = ad.implementation_;\n-        expect(impl.renderOutsideViewport()).to.be.false;\n-        clock.tick(900);\n-        expect(impl.renderOutsideViewport()).to.be.false;\n-        clock.tick(100);\n-        expect(impl.renderOutsideViewport()).not.to.be.false;\n-      });\n+      ad3p.onLayoutMeasure();\n+      expect(() => ad3p.layoutCallback()).to.throw('position:fixed');\n     });\n \n-    it('should prefer-viewability-over-views', () => {\n-      let clock;\n-      return getAd({\n-        width: 300,\n-        height: 250,\n-        type: '_ping_',\n-        src: 'https://testsrc',\n-        'data-valid': 'true',\n-        // Test precedence\n-        'data-width': '6666',\n-        'data-loading-strategy': 'prefer-viewability-over-views',\n-      }, undefined, ad => {\n-        clock = lolex.install(ad.implementation_.win);\n-        expect(ad.implementation_.renderOutsideViewport()).not.to.be.false;\n-        return ad;\n-      }).then(ad => {\n-        const impl = ad.implementation_;\n-        expect(impl.renderOutsideViewport()).to.be.false;\n-        clock.tick(900);\n-        expect(impl.renderOutsideViewport()).to.be.false;\n-        clock.tick(100);\n-        expect(impl.renderOutsideViewport()).to.equal(1.25);\n-      });\n+    it('should allow position:fixed with whitelisted ad container', () => {\n+      const adContainerElement = win.document.createElement('amp-sticky-ad');\n+      adContainerElement.style.position = 'fixed';\n+      win.document.body.appendChild(adContainerElement);\n+      const ad3p = createAmpAd(win);\n+      adContainerElement.appendChild(ad3p.element);\n+      ad3p.onLayoutMeasure();\n+      return ad3p.layoutCallback();\n     });\n-  });\n \n-  it('should add container info when ad has a container', () => {\n-    return getAdInAdContainer().then(obj => {\n-      const ampAd = obj.ampAd;\n-      const impl = ampAd.implementation_;\n-      expect(ampAd.getAttribute('amp-container-element')).to.be.null;\n-      impl.onLayoutMeasure();\n-      return impl.layoutCallback().then(() => {\n-        const src = ampAd.firstChild.getAttribute('src');\n+    it('should allow position:fixed with whitelisted ad container', () => {\n+      const adContainerElement = win.document.createElement('amp-sticky-ad');\n+      adContainerElement.style.position = 'fixed';\n+      win.document.body.appendChild(adContainerElement);\n+      const ad3p = createAmpAd(win);\n+      adContainerElement.appendChild(ad3p.element);\n+      ad3p.onLayoutMeasure();\n+      return ad3p.layoutCallback().then(() => {\n+        const src = ad3p.element.firstChild.getAttribute('src');\n         expect(src).to.contain('\"container\":\"AMP-STICKY-AD\"');\n       });\n     });\n   });\n-});\n \n-\n-/*\n-Create an iframe with an ad inside it.\n-Returns a promise for when the ad is usable for testing that produces\n-an object with properties related to the created iframe and utility methods:\n-- win: The created window.\n-- doc: The created document.\n-- iframe: The host iframe element. Useful for e.g. resizing.\n-- awaitEvent: A function that returns a promise for when the given custom\n-  event fired at least the given number of times.\n-- errors: Array of console.error fired during page load.\n-*/\n-// Please note undefined and null are different for opt_canonical\n-function getAd(opt_attributes, opt_canonical, opt_handleElement,\n-    opt_beforeLayoutCallback) {\n-  const attributes = opt_attributes || {\n-    width: 300,\n-    height: 250,\n-    type: '_ping_',\n-    src: 'https://testsrc',\n-    'data-valid': 'true',\n-  };\n-  let canonical = opt_canonical;\n-  if (opt_canonical === undefined) {\n-    canonical = 'https://schema.org';\n-  }\n-  return createIframePromise(undefined, opt_beforeLayoutCallback)\n-      .then(iframe => {\n-        iframe.iframe.style.height = '400px';\n-        iframe.iframe.style.width = '400px';\n-        markElementScheduledForTesting(iframe.win, 'amp-user-notification');\n-        if (canonical) {\n-          const link = createElementWithAttributes(iframe.doc, 'link', {\n-            rel: 'canonical',\n-            href: canonical,\n-          });\n-          iframe.doc.head.appendChild(link);\n+  describe('preconnectCallback', () => {\n+    it('should add prefeches', done => {\n+      ad3p.buildCallback();\n+      ad3p.preconnectCallback();\n+      setTimeout(() => {\n+        let fetches = win.document.querySelectorAll('link[rel=prefetch]');\n+        if (!fetches.length) {\n+          fetches = win.document.querySelectorAll('link[rel=preload]');\n         }\n-        let a = createElementWithAttributes(iframe.doc, 'amp-ad', attributes);\n+        expect(fetches).to.have.length(2);\n+        expect(fetches[0]).to.have.property('href',\n+            'http://ads.localhost:9876/dist.3p/current/frame.max.html');\n+        expect(fetches[1]).to.have.property('href',\n+            'http://ads.localhost:9876/dist.3p/current/integration.js');\n+\n+        const preconnects =\n+            win.document.querySelectorAll('link[rel=preconnect]');\n+        expect(preconnects[preconnects.length - 1]).to.have.property('href',\n+            'https://testsrc/');\n+        done();\n+      }, 0);\n+    });\n+  });\n \n-        // Make document long.\n-        a.style.marginBottom = '1000px';\n-        if (opt_handleElement) {\n-          a = opt_handleElement(a);\n-        }\n-        return iframe.addElement(a);\n-      });\n-}\n+  // TODO: add test for noContentHandler_()","path":"extensions/amp-ad/0.1/test/test-amp-ad-3p-impl.js","position":476,"original_position":476,"commit_id":"c438fe511d6f734f1439a543762019b7f126dfd4","original_commit_id":"c438fe511d6f734f1439a543762019b7f126dfd4","user":{"login":"zhouyx","id":5419904,"avatar_url":"https://avatars.githubusercontent.com/u/5419904?v=3","gravatar_id":"","url":"https://api.github.com/users/zhouyx","html_url":"https://github.com/zhouyx","followers_url":"https://api.github.com/users/zhouyx/followers","following_url":"https://api.github.com/users/zhouyx/following{/other_user}","gists_url":"https://api.github.com/users/zhouyx/gists{/gist_id}","starred_url":"https://api.github.com/users/zhouyx/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/zhouyx/subscriptions","organizations_url":"https://api.github.com/users/zhouyx/orgs","repos_url":"https://api.github.com/users/zhouyx/repos","events_url":"https://api.github.com/users/zhouyx/events{/privacy}","received_events_url":"https://api.github.com/users/zhouyx/received_events","type":"User","site_admin":false},"body":"The code for `noContentHandler_` may be moved outside 3p-ad-impl later. But before that let's keep still keep the test.","created_at":"2016-10-04T23:39:23Z","updated_at":"2016-10-04T23:40:38Z","html_url":"https://github.com/ampproject/amphtml/pull/5417#discussion_r81876638","pull_request_url":"https://api.github.com/repos/ampproject/amphtml/pulls/5417","_links":{"self":{"href":"https://api.github.com/repos/ampproject/amphtml/pulls/comments/81876638"},"html":{"href":"https://github.com/ampproject/amphtml/pull/5417#discussion_r81876638"},"pull_request":{"href":"https://api.github.com/repos/ampproject/amphtml/pulls/5417"}}},"pull_request":{"url":"https://api.github.com/repos/ampproject/amphtml/pulls/5417","id":87990679,"html_url":"https://github.com/ampproject/amphtml/pull/5417","diff_url":"https://github.com/ampproject/amphtml/pull/5417.diff","patch_url":"https://github.com/ampproject/amphtml/pull/5417.patch","issue_url":"https://api.github.com/repos/ampproject/amphtml/issues/5417","number":5417,"state":"open","locked":false,"title":"Refactor 3p ad unit test to remove dependency on amp-ad.js.","user":{"login":"lannka","id":8496897,"avatar_url":"https://avatars.githubusercontent.com/u/8496897?v=3","gravatar_id":"","url":"https://api.github.com/users/lannka","html_url":"https://github.com/lannka","followers_url":"https://api.github.com/users/lannka/followers","following_url":"https://api.github.com/users/lannka/following{/other_user}","gists_url":"https://api.github.com/users/lannka/gists{/gist_id}","starred_url":"https://api.github.com/users/lannka/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lannka/subscriptions","organizations_url":"https://api.github.com/users/lannka/orgs","repos_url":"https://api.github.com/users/lannka/repos","events_url":"https://api.github.com/users/lannka/events{/privacy}","received_events_url":"https://api.github.com/users/lannka/received_events","type":"User","site_admin":false},"body":"","created_at":"2016-10-04T23:03:42Z","updated_at":"2016-10-04T23:40:38Z","closed_at":null,"merged_at":null,"merge_commit_sha":"503ea6ff0a11dc83300d5bea528b16d1af9d99aa","assignee":{"login":"zhouyx","id":5419904,"avatar_url":"https://avatars.githubusercontent.com/u/5419904?v=3","gravatar_id":"","url":"https://api.github.com/users/zhouyx","html_url":"https://github.com/zhouyx","followers_url":"https://api.github.com/users/zhouyx/followers","following_url":"https://api.github.com/users/zhouyx/following{/other_user}","gists_url":"https://api.github.com/users/zhouyx/gists{/gist_id}","starred_url":"https://api.github.com/users/zhouyx/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/zhouyx/subscriptions","organizations_url":"https://api.github.com/users/zhouyx/orgs","repos_url":"https://api.github.com/users/zhouyx/repos","events_url":"https://api.github.com/users/zhouyx/events{/privacy}","received_events_url":"https://api.github.com/users/zhouyx/received_events","type":"User","site_admin":false},"assignees":[{"login":"zhouyx","id":5419904,"avatar_url":"https://avatars.githubusercontent.com/u/5419904?v=3","gravatar_id":"","url":"https://api.github.com/users/zhouyx","html_url":"https://github.com/zhouyx","followers_url":"https://api.github.com/users/zhouyx/followers","following_url":"https://api.github.com/users/zhouyx/following{/other_user}","gists_url":"https://api.github.com/users/zhouyx/gists{/gist_id}","starred_url":"https://api.github.com/users/zhouyx/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/zhouyx/subscriptions","organizations_url":"https://api.github.com/users/zhouyx/orgs","repos_url":"https://api.github.com/users/zhouyx/repos","events_url":"https://api.github.com/users/zhouyx/events{/privacy}","received_events_url":"https://api.github.com/users/zhouyx/received_events","type":"User","site_admin":false}],"milestone":null,"commits_url":"https://api.github.com/repos/ampproject/amphtml/pulls/5417/commits","review_comments_url":"https://api.github.com/repos/ampproject/amphtml/pulls/5417/comments","review_comment_url":"https://api.github.com/repos/ampproject/amphtml/pulls/comments{/number}","comments_url":"https://api.github.com/repos/ampproject/amphtml/issues/5417/comments","statuses_url":"https://api.github.com/repos/ampproject/amphtml/statuses/c438fe511d6f734f1439a543762019b7f126dfd4","head":{"label":"lannka:refactor_3p_ad_test","ref":"refactor_3p_ad_test","sha":"c438fe511d6f734f1439a543762019b7f126dfd4","user":{"login":"lannka","id":8496897,"avatar_url":"https://avatars.githubusercontent.com/u/8496897?v=3","gravatar_id":"","url":"https://api.github.com/users/lannka","html_url":"https://github.com/lannka","followers_url":"https://api.github.com/users/lannka/followers","following_url":"https://api.github.com/users/lannka/following{/other_user}","gists_url":"https://api.github.com/users/lannka/gists{/gist_id}","starred_url":"https://api.github.com/users/lannka/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lannka/subscriptions","organizations_url":"https://api.github.com/users/lannka/orgs","repos_url":"https://api.github.com/users/lannka/repos","events_url":"https://api.github.com/users/lannka/events{/privacy}","received_events_url":"https://api.github.com/users/lannka/received_events","type":"User","site_admin":false},"repo":{"id":60651806,"name":"amphtml","full_name":"lannka/amphtml","owner":{"login":"lannka","id":8496897,"avatar_url":"https://avatars.githubusercontent.com/u/8496897?v=3","gravatar_id":"","url":"https://api.github.com/users/lannka","html_url":"https://github.com/lannka","followers_url":"https://api.github.com/users/lannka/followers","following_url":"https://api.github.com/users/lannka/following{/other_user}","gists_url":"https://api.github.com/users/lannka/gists{/gist_id}","starred_url":"https://api.github.com/users/lannka/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lannka/subscriptions","organizations_url":"https://api.github.com/users/lannka/orgs","repos_url":"https://api.github.com/users/lannka/repos","events_url":"https://api.github.com/users/lannka/events{/privacy}","received_events_url":"https://api.github.com/users/lannka/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/lannka/amphtml","description":"AMP HTML source code, samples, and documentation.  See below for more info.","fork":true,"url":"https://api.github.com/repos/lannka/amphtml","forks_url":"https://api.github.com/repos/lannka/amphtml/forks","keys_url":"https://api.github.com/repos/lannka/amphtml/keys{/key_id}","collaborators_url":"https://api.github.com/repos/lannka/amphtml/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/lannka/amphtml/teams","hooks_url":"https://api.github.com/repos/lannka/amphtml/hooks","issue_events_url":"https://api.github.com/repos/lannka/amphtml/issues/events{/number}","events_url":"https://api.github.com/repos/lannka/amphtml/events","assignees_url":"https://api.github.com/repos/lannka/amphtml/assignees{/user}","branches_url":"https://api.github.com/repos/lannka/amphtml/branches{/branch}","tags_url":"https://api.github.com/repos/lannka/amphtml/tags","blobs_url":"https://api.github.com/repos/lannka/amphtml/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/lannka/amphtml/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/lannka/amphtml/git/refs{/sha}","trees_url":"https://api.github.com/repos/lannka/amphtml/git/trees{/sha}","statuses_url":"https://api.github.com/repos/lannka/amphtml/statuses/{sha}","languages_url":"https://api.github.com/repos/lannka/amphtml/languages","stargazers_url":"https://api.github.com/repos/lannka/amphtml/stargazers","contributors_url":"https://api.github.com/repos/lannka/amphtml/contributors","subscribers_url":"https://api.github.com/repos/lannka/amphtml/subscribers","subscription_url":"https://api.github.com/repos/lannka/amphtml/subscription","commits_url":"https://api.github.com/repos/lannka/amphtml/commits{/sha}","git_commits_url":"https://api.github.com/repos/lannka/amphtml/git/commits{/sha}","comments_url":"https://api.github.com/repos/lannka/amphtml/comments{/number}","issue_comment_url":"https://api.github.com/repos/lannka/amphtml/issues/comments{/number}","contents_url":"https://api.github.com/repos/lannka/amphtml/contents/{+path}","compare_url":"https://api.github.com/repos/lannka/amphtml/compare/{base}...{head}","merges_url":"https://api.github.com/repos/lannka/amphtml/merges","archive_url":"https://api.github.com/repos/lannka/amphtml/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/lannka/amphtml/downloads","issues_url":"https://api.github.com/repos/lannka/amphtml/issues{/number}","pulls_url":"https://api.github.com/repos/lannka/amphtml/pulls{/number}","milestones_url":"https://api.github.com/repos/lannka/amphtml/milestones{/number}","notifications_url":"https://api.github.com/repos/lannka/amphtml/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/lannka/amphtml/labels{/name}","releases_url":"https://api.github.com/repos/lannka/amphtml/releases{/id}","deployments_url":"https://api.github.com/repos/lannka/amphtml/deployments","created_at":"2016-06-07T22:50:13Z","updated_at":"2016-06-07T22:50:18Z","pushed_at":"2016-10-04T23:01:09Z","git_url":"git://github.com/lannka/amphtml.git","ssh_url":"git@github.com:lannka/amphtml.git","clone_url":"https://github.com/lannka/amphtml.git","svn_url":"https://github.com/lannka/amphtml","homepage":"https://ampproject.org","size":165257,"stargazers_count":0,"watchers_count":0,"language":"JavaScript","has_issues":false,"has_downloads":false,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"ampproject:master","ref":"master","sha":"91df5562164c041def8ac267db7f7cb3edec91b5","user":{"login":"ampproject","id":14114390,"avatar_url":"https://avatars.githubusercontent.com/u/14114390?v=3","gravatar_id":"","url":"https://api.github.com/users/ampproject","html_url":"https://github.com/ampproject","followers_url":"https://api.github.com/users/ampproject/followers","following_url":"https://api.github.com/users/ampproject/following{/other_user}","gists_url":"https://api.github.com/users/ampproject/gists{/gist_id}","starred_url":"https://api.github.com/users/ampproject/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ampproject/subscriptions","organizations_url":"https://api.github.com/users/ampproject/orgs","repos_url":"https://api.github.com/users/ampproject/repos","events_url":"https://api.github.com/users/ampproject/events{/privacy}","received_events_url":"https://api.github.com/users/ampproject/received_events","type":"Organization","site_admin":false},"repo":{"id":41766002,"name":"amphtml","full_name":"ampproject/amphtml","owner":{"login":"ampproject","id":14114390,"avatar_url":"https://avatars.githubusercontent.com/u/14114390?v=3","gravatar_id":"","url":"https://api.github.com/users/ampproject","html_url":"https://github.com/ampproject","followers_url":"https://api.github.com/users/ampproject/followers","following_url":"https://api.github.com/users/ampproject/following{/other_user}","gists_url":"https://api.github.com/users/ampproject/gists{/gist_id}","starred_url":"https://api.github.com/users/ampproject/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ampproject/subscriptions","organizations_url":"https://api.github.com/users/ampproject/orgs","repos_url":"https://api.github.com/users/ampproject/repos","events_url":"https://api.github.com/users/ampproject/events{/privacy}","received_events_url":"https://api.github.com/users/ampproject/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/ampproject/amphtml","description":"AMP HTML source code, samples, and documentation.  See below for more info.","fork":false,"url":"https://api.github.com/repos/ampproject/amphtml","forks_url":"https://api.github.com/repos/ampproject/amphtml/forks","keys_url":"https://api.github.com/repos/ampproject/amphtml/keys{/key_id}","collaborators_url":"https://api.github.com/repos/ampproject/amphtml/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/ampproject/amphtml/teams","hooks_url":"https://api.github.com/repos/ampproject/amphtml/hooks","issue_events_url":"https://api.github.com/repos/ampproject/amphtml/issues/events{/number}","events_url":"https://api.github.com/repos/ampproject/amphtml/events","assignees_url":"https://api.github.com/repos/ampproject/amphtml/assignees{/user}","branches_url":"https://api.github.com/repos/ampproject/amphtml/branches{/branch}","tags_url":"https://api.github.com/repos/ampproject/amphtml/tags","blobs_url":"https://api.github.com/repos/ampproject/amphtml/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/ampproject/amphtml/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/ampproject/amphtml/git/refs{/sha}","trees_url":"https://api.github.com/repos/ampproject/amphtml/git/trees{/sha}","statuses_url":"https://api.github.com/repos/ampproject/amphtml/statuses/{sha}","languages_url":"https://api.github.com/repos/ampproject/amphtml/languages","stargazers_url":"https://api.github.com/repos/ampproject/amphtml/stargazers","contributors_url":"https://api.github.com/repos/ampproject/amphtml/contributors","subscribers_url":"https://api.github.com/repos/ampproject/amphtml/subscribers","subscription_url":"https://api.github.com/repos/ampproject/amphtml/subscription","commits_url":"https://api.github.com/repos/ampproject/amphtml/commits{/sha}","git_commits_url":"https://api.github.com/repos/ampproject/amphtml/git/commits{/sha}","comments_url":"https://api.github.com/repos/ampproject/amphtml/comments{/number}","issue_comment_url":"https://api.github.com/repos/ampproject/amphtml/issues/comments{/number}","contents_url":"https://api.github.com/repos/ampproject/amphtml/contents/{+path}","compare_url":"https://api.github.com/repos/ampproject/amphtml/compare/{base}...{head}","merges_url":"https://api.github.com/repos/ampproject/amphtml/merges","archive_url":"https://api.github.com/repos/ampproject/amphtml/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/ampproject/amphtml/downloads","issues_url":"https://api.github.com/repos/ampproject/amphtml/issues{/number}","pulls_url":"https://api.github.com/repos/ampproject/amphtml/pulls{/number}","milestones_url":"https://api.github.com/repos/ampproject/amphtml/milestones{/number}","notifications_url":"https://api.github.com/repos/ampproject/amphtml/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/ampproject/amphtml/labels{/name}","releases_url":"https://api.github.com/repos/ampproject/amphtml/releases{/id}","deployments_url":"https://api.github.com/repos/ampproject/amphtml/deployments","created_at":"2015-09-01T22:10:53Z","updated_at":"2016-10-04T15:07:28Z","pushed_at":"2016-10-04T23:32:54Z","git_url":"git://github.com/ampproject/amphtml.git","ssh_url":"git@github.com:ampproject/amphtml.git","clone_url":"https://github.com/ampproject/amphtml.git","svn_url":"https://github.com/ampproject/amphtml","homepage":"https://ampproject.org","size":205568,"stargazers_count":8712,"watchers_count":8712,"language":"JavaScript","has_issues":true,"has_downloads":false,"has_wiki":false,"has_pages":false,"forks_count":1292,"mirror_url":null,"open_issues_count":830,"forks":1292,"open_issues":830,"watchers":8712,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/ampproject/amphtml/pulls/5417"},"html":{"href":"https://github.com/ampproject/amphtml/pull/5417"},"issue":{"href":"https://api.github.com/repos/ampproject/amphtml/issues/5417"},"comments":{"href":"https://api.github.com/repos/ampproject/amphtml/issues/5417/comments"},"review_comments":{"href":"https://api.github.com/repos/ampproject/amphtml/pulls/5417/comments"},"review_comment":{"href":"https://api.github.com/repos/ampproject/amphtml/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/ampproject/amphtml/pulls/5417/commits"},"statuses":{"href":"https://api.github.com/repos/ampproject/amphtml/statuses/c438fe511d6f734f1439a543762019b7f126dfd4"}}}}
{"actor":{"display_login":"zhouyx"}}