{"action":"created","comment":{"url":"https://api.github.com/repos/ampproject/amphtml/pulls/comments/62103196","id":62103196,"diff_hunk":"@@ -0,0 +1,171 @@\n+/**\n+ * Copyright 2016 The AMP HTML Authors. All Rights Reserved.\n+ *\n+ * Licensed under the Apache License, Version 2.0 (the \"License\");\n+ * you may not use this file except in compliance with the License.\n+ * You may obtain a copy of the License at\n+ *\n+ *      http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an \"AS-IS\" BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+ * See the License for the specific language governing permissions and\n+ * limitations under the License.\n+ */\n+\n+import {Poller} from './poller';\n+import {getService} from '../../../src/service';\n+import {user} from '../../../src/log';\n+import {viewerFor} from '../../../src/viewer';\n+import {whenDocumentReady} from '../../../src/document-ready';\n+import {xhrFor} from '../../../src/xhr';\n+\n+\n+/**\n+ * Manages registered AmpLiveList components.\n+ * Primarily handles network requests and updates the components\n+ * if necessary.\n+ *\n+ * @visibleForTesting\n+ */\n+export class LiveListManager {\n+\n+  constructor(win) {\n+    this.win = win;\n+\n+    /** @private @const {!Object<string, !AmpLiveList>} */\n+    this.liveLists_ = Object.create(null);\n+\n+    /** @private @const {!Viewer} */\n+    this.viewer_ = viewerFor(this.win);\n+\n+    /** @private {number} */\n+    this.interval_ = 15000;\n+\n+    /** @private @const {!Array<number>} */\n+    this.intervals_ = [this.interval_];\n+\n+    /** @private {?Poller} */\n+    this.poller_ = null;\n+\n+    /** @private @const {string} */\n+    this.url_ = this.win.location.href;\n+\n+    /** @private @const {function(): Promise} */\n+    this.work_ = this.fetchDocument_.bind(this, this.url_);\n+\n+    // Only start polling when doc is ready and when the viewer is visible.\n+    this.whenDocReady_().then(() => {\n+      // Switch out the poller interval if we can find a lower one and\n+      // then make sure to stop polling if viewer is not visible.\n+      this.interval_ = Math.min.apply(Math, this.intervals_);\n+      this.poller_ = new Poller(this.win, this.interval_, this.work_);\n+\n+      if (this.viewer_.isVisible()) {\n+        this.poller_.start();\n+      }\n+      this.setupVisibilityHandler_();\n+    });\n+  }\n+\n+  /**\n+   * Makes a request to the given url for the latest document.\n+   *\n+   * @param {string} url\n+   * @private\n+   */\n+  fetchDocument_(url) {\n+    return xhrFor(this.win)\n+        // TODO(erwinm): add update time here when possible.\n+        .fetchDocument(url)\n+        .then(this.getLiveLists_.bind(this));\n+  }\n+\n+  /**\n+   * Extract the `Document` instance parsed through responseType=document\n+   * from the default xhr parser. This is important because we dont want\n+   * to do any parsing in the UI thread.\n+   *\n+   * @param {!FetchResponse} res\n+   * @return {!HTMLDocument}\n+   */\n+  getDoc(res) {\n+    const doc = res.doc();\n+    user.assert(doc instanceof Document,\n+        'response must be an html `Document`, got %s', doc);\n+    return doc;\n+  }\n+\n+  /**\n+   * Queries the document for all `amp-live-list` tags.\n+   *\n+   * @param {!HTMLDocument} doc\n+   */\n+  getLiveLists_(doc) {\n+    const lists = Array.prototype.slice.call(\n+        doc.getElementsByTagName('amp-live-list'));\n+    lists.forEach(this.updateLiveList_.bind(this));\n+  }\n+\n+  /**\n+   * Updates the appropriate `amp-live-list` with its updates from the server.\n+   *\n+   * @param {!HTMLElement} liveList\n+   */\n+  updateLiveList_(liveList) {\n+    const id = liveList.getAttribute('id');\n+    user.assert(id, 'amp-live-list must have an id.');\n+    if (id in this.liveLists_) {\n+      this.liveLists_[id].update(liveList);\n+    }\n+  }\n+\n+  /**\n+   * Register an `amp-live-list` instance for updates.\n+   *\n+   * @param {number} id\n+   * @param {!AmpLiveList} liveList\n+   */\n+  register(id, liveList) {\n+    const isNotRegistered = !(id in this.liveLists_);\n+    if (isNotRegistered) {\n+      this.liveLists_[id] = liveList;\n+      this.intervals_.push(liveList.getInterval());\n+    }\n+  }\n+\n+  /**\n+   * Returns a promise that is resolved when the document is ready.\n+   * @return {!Promise}\n+   * @private\n+   */\n+  whenDocReady_() {\n+    return whenDocumentReady(this.win.document);\n+  }\n+\n+  /**\n+   * Listens to he viewer visibility changed event.\n+   * @private\n+   */\n+  setupVisibilityHandler_() {\n+    // Polling should always be stopped when document is no longer visible.\n+    this.viewer_.onVisibilityChanged(() => {\n+      if (this.viewer_.isVisible()) {\n+        this.poller_.start();","path":"extensions/amp-live-list/0.1/live-list-manager.js","position":155,"original_position":155,"commit_id":"e49b2ab2587f7aaa3b8367a2d8ee617e0a2f77dc","original_commit_id":"e49b2ab2587f7aaa3b8367a2d8ee617e0a2f77dc","user":{"login":"cramforce","id":89679,"avatar_url":"https://avatars.githubusercontent.com/u/89679?v=3","gravatar_id":"","url":"https://api.github.com/users/cramforce","html_url":"https://github.com/cramforce","followers_url":"https://api.github.com/users/cramforce/followers","following_url":"https://api.github.com/users/cramforce/following{/other_user}","gists_url":"https://api.github.com/users/cramforce/gists{/gist_id}","starred_url":"https://api.github.com/users/cramforce/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cramforce/subscriptions","organizations_url":"https://api.github.com/users/cramforce/orgs","repos_url":"https://api.github.com/users/cramforce/repos","events_url":"https://api.github.com/users/cramforce/events{/privacy}","received_events_url":"https://api.github.com/users/cramforce/received_events","type":"User","site_admin":false},"body":"Does this trigger an immediate invocation?","created_at":"2016-05-04T19:53:39Z","updated_at":"2016-05-04T19:53:39Z","html_url":"https://github.com/ampproject/amphtml/pull/3094#discussion_r62103196","pull_request_url":"https://api.github.com/repos/ampproject/amphtml/pulls/3094","_links":{"self":{"href":"https://api.github.com/repos/ampproject/amphtml/pulls/comments/62103196"},"html":{"href":"https://github.com/ampproject/amphtml/pull/3094#discussion_r62103196"},"pull_request":{"href":"https://api.github.com/repos/ampproject/amphtml/pulls/3094"}}},"pull_request":{"url":"https://api.github.com/repos/ampproject/amphtml/pulls/3094","id":68846257,"html_url":"https://github.com/ampproject/amphtml/pull/3094","diff_url":"https://github.com/ampproject/amphtml/pull/3094.diff","patch_url":"https://github.com/ampproject/amphtml/pull/3094.patch","issue_url":"https://api.github.com/repos/ampproject/amphtml/issues/3094","number":3094,"state":"open","locked":false,"title":"add amp-live-list manager","user":{"login":"erwinmombay","id":354746,"avatar_url":"https://avatars.githubusercontent.com/u/354746?v=3","gravatar_id":"","url":"https://api.github.com/users/erwinmombay","html_url":"https://github.com/erwinmombay","followers_url":"https://api.github.com/users/erwinmombay/followers","following_url":"https://api.github.com/users/erwinmombay/following{/other_user}","gists_url":"https://api.github.com/users/erwinmombay/gists{/gist_id}","starred_url":"https://api.github.com/users/erwinmombay/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/erwinmombay/subscriptions","organizations_url":"https://api.github.com/users/erwinmombay/orgs","repos_url":"https://api.github.com/users/erwinmombay/repos","events_url":"https://api.github.com/users/erwinmombay/events{/privacy}","received_events_url":"https://api.github.com/users/erwinmombay/received_events","type":"User","site_admin":false},"body":"","created_at":"2016-05-04T11:22:35Z","updated_at":"2016-05-04T19:53:39Z","closed_at":null,"merged_at":null,"merge_commit_sha":"b153fcf5297f8b4dc0641a4d408eb6cfb153b9b3","assignee":{"login":"cramforce","id":89679,"avatar_url":"https://avatars.githubusercontent.com/u/89679?v=3","gravatar_id":"","url":"https://api.github.com/users/cramforce","html_url":"https://github.com/cramforce","followers_url":"https://api.github.com/users/cramforce/followers","following_url":"https://api.github.com/users/cramforce/following{/other_user}","gists_url":"https://api.github.com/users/cramforce/gists{/gist_id}","starred_url":"https://api.github.com/users/cramforce/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cramforce/subscriptions","organizations_url":"https://api.github.com/users/cramforce/orgs","repos_url":"https://api.github.com/users/cramforce/repos","events_url":"https://api.github.com/users/cramforce/events{/privacy}","received_events_url":"https://api.github.com/users/cramforce/received_events","type":"User","site_admin":false},"milestone":null,"commits_url":"https://api.github.com/repos/ampproject/amphtml/pulls/3094/commits","review_comments_url":"https://api.github.com/repos/ampproject/amphtml/pulls/3094/comments","review_comment_url":"https://api.github.com/repos/ampproject/amphtml/pulls/comments{/number}","comments_url":"https://api.github.com/repos/ampproject/amphtml/issues/3094/comments","statuses_url":"https://api.github.com/repos/ampproject/amphtml/statuses/e49b2ab2587f7aaa3b8367a2d8ee617e0a2f77dc","head":{"label":"erwinmombay:amp-live-list-manager","ref":"amp-live-list-manager","sha":"e49b2ab2587f7aaa3b8367a2d8ee617e0a2f77dc","user":{"login":"erwinmombay","id":354746,"avatar_url":"https://avatars.githubusercontent.com/u/354746?v=3","gravatar_id":"","url":"https://api.github.com/users/erwinmombay","html_url":"https://github.com/erwinmombay","followers_url":"https://api.github.com/users/erwinmombay/followers","following_url":"https://api.github.com/users/erwinmombay/following{/other_user}","gists_url":"https://api.github.com/users/erwinmombay/gists{/gist_id}","starred_url":"https://api.github.com/users/erwinmombay/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/erwinmombay/subscriptions","organizations_url":"https://api.github.com/users/erwinmombay/orgs","repos_url":"https://api.github.com/users/erwinmombay/repos","events_url":"https://api.github.com/users/erwinmombay/events{/privacy}","received_events_url":"https://api.github.com/users/erwinmombay/received_events","type":"User","site_admin":false},"repo":{"id":43843790,"name":"amphtml","full_name":"erwinmombay/amphtml","owner":{"login":"erwinmombay","id":354746,"avatar_url":"https://avatars.githubusercontent.com/u/354746?v=3","gravatar_id":"","url":"https://api.github.com/users/erwinmombay","html_url":"https://github.com/erwinmombay","followers_url":"https://api.github.com/users/erwinmombay/followers","following_url":"https://api.github.com/users/erwinmombay/following{/other_user}","gists_url":"https://api.github.com/users/erwinmombay/gists{/gist_id}","starred_url":"https://api.github.com/users/erwinmombay/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/erwinmombay/subscriptions","organizations_url":"https://api.github.com/users/erwinmombay/orgs","repos_url":"https://api.github.com/users/erwinmombay/repos","events_url":"https://api.github.com/users/erwinmombay/events{/privacy}","received_events_url":"https://api.github.com/users/erwinmombay/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/erwinmombay/amphtml","description":"","fork":true,"url":"https://api.github.com/repos/erwinmombay/amphtml","forks_url":"https://api.github.com/repos/erwinmombay/amphtml/forks","keys_url":"https://api.github.com/repos/erwinmombay/amphtml/keys{/key_id}","collaborators_url":"https://api.github.com/repos/erwinmombay/amphtml/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/erwinmombay/amphtml/teams","hooks_url":"https://api.github.com/repos/erwinmombay/amphtml/hooks","issue_events_url":"https://api.github.com/repos/erwinmombay/amphtml/issues/events{/number}","events_url":"https://api.github.com/repos/erwinmombay/amphtml/events","assignees_url":"https://api.github.com/repos/erwinmombay/amphtml/assignees{/user}","branches_url":"https://api.github.com/repos/erwinmombay/amphtml/branches{/branch}","tags_url":"https://api.github.com/repos/erwinmombay/amphtml/tags","blobs_url":"https://api.github.com/repos/erwinmombay/amphtml/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/erwinmombay/amphtml/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/erwinmombay/amphtml/git/refs{/sha}","trees_url":"https://api.github.com/repos/erwinmombay/amphtml/git/trees{/sha}","statuses_url":"https://api.github.com/repos/erwinmombay/amphtml/statuses/{sha}","languages_url":"https://api.github.com/repos/erwinmombay/amphtml/languages","stargazers_url":"https://api.github.com/repos/erwinmombay/amphtml/stargazers","contributors_url":"https://api.github.com/repos/erwinmombay/amphtml/contributors","subscribers_url":"https://api.github.com/repos/erwinmombay/amphtml/subscribers","subscription_url":"https://api.github.com/repos/erwinmombay/amphtml/subscription","commits_url":"https://api.github.com/repos/erwinmombay/amphtml/commits{/sha}","git_commits_url":"https://api.github.com/repos/erwinmombay/amphtml/git/commits{/sha}","comments_url":"https://api.github.com/repos/erwinmombay/amphtml/comments{/number}","issue_comment_url":"https://api.github.com/repos/erwinmombay/amphtml/issues/comments{/number}","contents_url":"https://api.github.com/repos/erwinmombay/amphtml/contents/{+path}","compare_url":"https://api.github.com/repos/erwinmombay/amphtml/compare/{base}...{head}","merges_url":"https://api.github.com/repos/erwinmombay/amphtml/merges","archive_url":"https://api.github.com/repos/erwinmombay/amphtml/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/erwinmombay/amphtml/downloads","issues_url":"https://api.github.com/repos/erwinmombay/amphtml/issues{/number}","pulls_url":"https://api.github.com/repos/erwinmombay/amphtml/pulls{/number}","milestones_url":"https://api.github.com/repos/erwinmombay/amphtml/milestones{/number}","notifications_url":"https://api.github.com/repos/erwinmombay/amphtml/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/erwinmombay/amphtml/labels{/name}","releases_url":"https://api.github.com/repos/erwinmombay/amphtml/releases{/id}","deployments_url":"https://api.github.com/repos/erwinmombay/amphtml/deployments","created_at":"2015-10-07T20:45:56Z","updated_at":"2016-02-03T02:51:51Z","pushed_at":"2016-05-04T17:29:23Z","git_url":"git://github.com/erwinmombay/amphtml.git","ssh_url":"git@github.com:erwinmombay/amphtml.git","clone_url":"https://github.com/erwinmombay/amphtml.git","svn_url":"https://github.com/erwinmombay/amphtml","homepage":"","size":80172,"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":"77d68a81e48ea07bb55ade8488266764b2bb40f0","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-05-04T17:51:50Z","pushed_at":"2016-05-04T19:45:33Z","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":85810,"stargazers_count":7354,"watchers_count":7354,"language":"JavaScript","has_issues":true,"has_downloads":false,"has_wiki":false,"has_pages":false,"forks_count":965,"mirror_url":null,"open_issues_count":401,"forks":965,"open_issues":401,"watchers":7354,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/ampproject/amphtml/pulls/3094"},"html":{"href":"https://github.com/ampproject/amphtml/pull/3094"},"issue":{"href":"https://api.github.com/repos/ampproject/amphtml/issues/3094"},"comments":{"href":"https://api.github.com/repos/ampproject/amphtml/issues/3094/comments"},"review_comments":{"href":"https://api.github.com/repos/ampproject/amphtml/pulls/3094/comments"},"review_comment":{"href":"https://api.github.com/repos/ampproject/amphtml/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/ampproject/amphtml/pulls/3094/commits"},"statuses":{"href":"https://api.github.com/repos/ampproject/amphtml/statuses/e49b2ab2587f7aaa3b8367a2d8ee617e0a2f77dc"}}}}