{"action":"created","comment":{"url":"https://api.github.com/repos/mozilla-b2g/gaia/pulls/comments/36543110","id":36543110,"diff_hunk":"@@ -0,0 +1,335 @@\n+/* global asyncStorage, Database */\n+/* exported PlaybackQueue */\n+'use strict';\n+\n+var PlaybackQueue = (function() {\n+\n+  // The key for storing the repeat and shuffle options.\n+  var SETTINGS_OPTION_KEY = 'settings_option_key';\n+\n+  var Repeat = {\n+    OFF: 0,\n+    LIST: 1,\n+    SONG: 2,\n+\n+    /**\n+     * Return the \"next\" repeat setting in its canonical order; OFF -> LIST ->\n+     * SONG -> OFF.\n+     *\n+     * @param {Repeat} val The current value.\n+     * @return {Repeat} The next value.\n+     */\n+    next: function(val) {\n+      return (val + 1) % 3;\n+    }\n+  };\n+\n+  /**\n+   * Return a % b, ensuring that the result is always positive.\n+   *\n+   * @param {Number} a The dividend.\n+   * @param {Number} b The divisor.\n+   * @return {Number} The positive remainder.\n+   */\n+  function posmod(a, b) {\n+    var r = a % b;\n+    return r < 0 ? r + b : r;\n+  }\n+\n+  /**\n+   * Fill an array with values from 0..n.\n+   *\n+   * @param {Number} length The length of the array.\n+   * @return {Array} The array.\n+   */\n+  function fillIndices(length) {\n+    var indices = new Array(length);\n+    for (var i = 0; i < indices.length; i++) {\n+      indices[i] = i;\n+    }\n+    return indices;\n+  }\n+\n+  /**\n+   * Shuffle the elements of an array in-place using Yates shuffle. See:\n+   * <http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle>.\n+   *\n+   * @param {Array} list The array to shuffle.\n+   */\n+  function shuffle(list) {\n+    for (var i = list.length - 1; i >= 1; i--) {\n+      var j = Math.floor(Math.random() * (i + 1));\n+      if (j < i) {\n+        var tmp = list[j];\n+        list[j] = list[i];\n+        list[i] = tmp;\n+      }\n+    }\n+  }\n+\n+  /**\n+   * The base for playback queue types.\n+   */\n+  function BaseQueue() {\n+    this._index = null;\n+  }\n+\n+  BaseQueue.prototype = {\n+    /**\n+     * Initialize the playback queue.\n+     *\n+     * @param {Number} [index] The index of the queue to start at.\n+     */\n+    _init: function(index) {\n+      if (this.length === 0) {\n+        throw Error('cannot have an empty queue');\n+      }\n+      this._index = index || 0;\n+      this._shuffle(playbackSettings.shuffle, index !== undefined);\n+    },\n+\n+    /**\n+     * Shuffle or unshuffle the playback queue. If the queue is already\n+     * shuffled, this will reshuffle it.\n+     *\n+     * @param {Boolean} enabled True if the queue should be shuffled, false\n+     *        otherwise.\n+     * @param {Boolean} keepIndex True if the current queue index should be\n+     *        retained, false otherwise.\n+     */\n+    _shuffle: function(enabled, keepIndex = true) {\n+      this._shuffleTime = Date.now();\n+      if (!enabled) {\n+        if (keepIndex) {\n+          this._index = this.index;\n+        }\n+        delete this._shuffledList;\n+        return;\n+      }\n+\n+      this._shuffledList = fillIndices(this.length);\n+      var oldIndex = null;\n+      if (keepIndex) {\n+        oldIndex = this._shuffledList.splice(this._index, 1)[0];\n+        this._index = 0;\n+      }\n+\n+      shuffle(this._shuffledList);\n+\n+      if (keepIndex) {\n+        this._shuffledList.unshift(oldIndex);\n+      }\n+    },\n+\n+    /**\n+     * Move the queue's current pointer to the next track.\n+     *\n+     * @param {Boolean} automatic True if this action is happening automatically\n+     *        (i.e. when a track ends).\n+     */\n+    next: function(automatic = false) {\n+      return this.advance(1, automatic);\n+    },\n+\n+    /**\n+     * Move the queue's current pointer to the previous track.\n+     */\n+    previous: function() {\n+      this.advance(-1);\n+    },\n+\n+    /**\n+     * Move the queue's current pointer to another track.\n+     *\n+     * @param {Number} offset The offset to move by.\n+     * @param {Boolean} automatic True if this action is happening automatically\n+     *        (i.e. when a track ends).\n+     */\n+    advance: function(offset, automatic = false) {\n+      var next;\n+      var justShuffled = false;\n+\n+      // If the shuffle setting was changed after we last updated, shuffle\n+      // (or unshuffle, as necessary).\n+      if (this._shuffleTime < shuffleTime) {\n+        this._shuffle(playbackSettings.shuffle);\n+        justShuffled = true;\n+      }\n+\n+      switch (PlaybackQueue.repeat) {\n+      case Repeat.OFF:\n+        next = Math.max(this._index + offset, 0);\n+        break;\n+      case Repeat.LIST:\n+        next = posmod(this._index + offset, this.length);\n+        var cycled = next !== this._index + offset;\n+        // If we cycled around the list, reshuffle if necessary.\n+        if (playbackSettings.shuffle && cycled && !justShuffled) {\n+          this._shuffle(true);\n+        }\n+        break;\n+      case Repeat.SONG:","path":"apps/music/js/queue.js","position":171,"original_position":171,"commit_id":"cbd74b6a4555e7db7779aaa85d616830a4dd0b31","original_commit_id":"cbd74b6a4555e7db7779aaa85d616830a4dd0b31","user":{"login":"jimporter","id":826865,"avatar_url":"https://avatars.githubusercontent.com/u/826865?v=3","gravatar_id":"","url":"https://api.github.com/users/jimporter","html_url":"https://github.com/jimporter","followers_url":"https://api.github.com/users/jimporter/followers","following_url":"https://api.github.com/users/jimporter/following{/other_user}","gists_url":"https://api.github.com/users/jimporter/gists{/gist_id}","starred_url":"https://api.github.com/users/jimporter/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jimporter/subscriptions","organizations_url":"https://api.github.com/users/jimporter/orgs","repos_url":"https://api.github.com/users/jimporter/repos","events_url":"https://api.github.com/users/jimporter/events{/privacy}","received_events_url":"https://api.github.com/users/jimporter/received_events","type":"User","site_admin":false},"body":"Yeah, I thought about that, but it's actually more work to do it that way. I think this is probably the clearest we can make it.","created_at":"2015-08-07T17:50:51Z","updated_at":"2015-08-07T17:50:51Z","html_url":"https://github.com/mozilla-b2g/gaia/pull/31047#discussion_r36543110","pull_request_url":"https://api.github.com/repos/mozilla-b2g/gaia/pulls/31047","_links":{"self":{"href":"https://api.github.com/repos/mozilla-b2g/gaia/pulls/comments/36543110"},"html":{"href":"https://github.com/mozilla-b2g/gaia/pull/31047#discussion_r36543110"},"pull_request":{"href":"https://api.github.com/repos/mozilla-b2g/gaia/pulls/31047"}}},"pull_request":{"url":"https://api.github.com/repos/mozilla-b2g/gaia/pulls/31047","id":40405075,"html_url":"https://github.com/mozilla-b2g/gaia/pull/31047","diff_url":"https://github.com/mozilla-b2g/gaia/pull/31047.diff","patch_url":"https://github.com/mozilla-b2g/gaia/pull/31047.patch","issue_url":"https://api.github.com/repos/mozilla-b2g/gaia/issues/31047","number":31047,"state":"open","locked":false,"title":"Bug 1166416 - [music] Move audio playback to the \"backend\"","user":{"login":"jimporter","id":826865,"avatar_url":"https://avatars.githubusercontent.com/u/826865?v=3","gravatar_id":"","url":"https://api.github.com/users/jimporter","html_url":"https://github.com/jimporter","followers_url":"https://api.github.com/users/jimporter/followers","following_url":"https://api.github.com/users/jimporter/following{/other_user}","gists_url":"https://api.github.com/users/jimporter/gists{/gist_id}","starred_url":"https://api.github.com/users/jimporter/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jimporter/subscriptions","organizations_url":"https://api.github.com/users/jimporter/orgs","repos_url":"https://api.github.com/users/jimporter/repos","events_url":"https://api.github.com/users/jimporter/events{/privacy}","received_events_url":"https://api.github.com/users/jimporter/received_events","type":"User","site_admin":false},"body":"WIP, not ready to land yet.","created_at":"2015-07-20T22:35:58Z","updated_at":"2015-08-07T17:50:51Z","closed_at":null,"merged_at":null,"merge_commit_sha":"3624cac884fa65b387e1c1f315247fc60f7f6be7","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/mozilla-b2g/gaia/pulls/31047/commits","review_comments_url":"https://api.github.com/repos/mozilla-b2g/gaia/pulls/31047/comments","review_comment_url":"https://api.github.com/repos/mozilla-b2g/gaia/pulls/comments{/number}","comments_url":"https://api.github.com/repos/mozilla-b2g/gaia/issues/31047/comments","statuses_url":"https://api.github.com/repos/mozilla-b2g/gaia/statuses/cbd74b6a4555e7db7779aaa85d616830a4dd0b31","head":{"label":"jimporter:music-player-cleanup","ref":"music-player-cleanup","sha":"cbd74b6a4555e7db7779aaa85d616830a4dd0b31","user":{"login":"jimporter","id":826865,"avatar_url":"https://avatars.githubusercontent.com/u/826865?v=3","gravatar_id":"","url":"https://api.github.com/users/jimporter","html_url":"https://github.com/jimporter","followers_url":"https://api.github.com/users/jimporter/followers","following_url":"https://api.github.com/users/jimporter/following{/other_user}","gists_url":"https://api.github.com/users/jimporter/gists{/gist_id}","starred_url":"https://api.github.com/users/jimporter/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jimporter/subscriptions","organizations_url":"https://api.github.com/users/jimporter/orgs","repos_url":"https://api.github.com/users/jimporter/repos","events_url":"https://api.github.com/users/jimporter/events{/privacy}","received_events_url":"https://api.github.com/users/jimporter/received_events","type":"User","site_admin":false},"repo":{"id":7586186,"name":"gaia","full_name":"jimporter/gaia","owner":{"login":"jimporter","id":826865,"avatar_url":"https://avatars.githubusercontent.com/u/826865?v=3","gravatar_id":"","url":"https://api.github.com/users/jimporter","html_url":"https://github.com/jimporter","followers_url":"https://api.github.com/users/jimporter/followers","following_url":"https://api.github.com/users/jimporter/following{/other_user}","gists_url":"https://api.github.com/users/jimporter/gists{/gist_id}","starred_url":"https://api.github.com/users/jimporter/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jimporter/subscriptions","organizations_url":"https://api.github.com/users/jimporter/orgs","repos_url":"https://api.github.com/users/jimporter/repos","events_url":"https://api.github.com/users/jimporter/events{/privacy}","received_events_url":"https://api.github.com/users/jimporter/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/jimporter/gaia","description":"Gaia is a HTML5-based Phone UI for the Boot 2 Gecko Project","fork":true,"url":"https://api.github.com/repos/jimporter/gaia","forks_url":"https://api.github.com/repos/jimporter/gaia/forks","keys_url":"https://api.github.com/repos/jimporter/gaia/keys{/key_id}","collaborators_url":"https://api.github.com/repos/jimporter/gaia/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/jimporter/gaia/teams","hooks_url":"https://api.github.com/repos/jimporter/gaia/hooks","issue_events_url":"https://api.github.com/repos/jimporter/gaia/issues/events{/number}","events_url":"https://api.github.com/repos/jimporter/gaia/events","assignees_url":"https://api.github.com/repos/jimporter/gaia/assignees{/user}","branches_url":"https://api.github.com/repos/jimporter/gaia/branches{/branch}","tags_url":"https://api.github.com/repos/jimporter/gaia/tags","blobs_url":"https://api.github.com/repos/jimporter/gaia/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/jimporter/gaia/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/jimporter/gaia/git/refs{/sha}","trees_url":"https://api.github.com/repos/jimporter/gaia/git/trees{/sha}","statuses_url":"https://api.github.com/repos/jimporter/gaia/statuses/{sha}","languages_url":"https://api.github.com/repos/jimporter/gaia/languages","stargazers_url":"https://api.github.com/repos/jimporter/gaia/stargazers","contributors_url":"https://api.github.com/repos/jimporter/gaia/contributors","subscribers_url":"https://api.github.com/repos/jimporter/gaia/subscribers","subscription_url":"https://api.github.com/repos/jimporter/gaia/subscription","commits_url":"https://api.github.com/repos/jimporter/gaia/commits{/sha}","git_commits_url":"https://api.github.com/repos/jimporter/gaia/git/commits{/sha}","comments_url":"https://api.github.com/repos/jimporter/gaia/comments{/number}","issue_comment_url":"https://api.github.com/repos/jimporter/gaia/issues/comments{/number}","contents_url":"https://api.github.com/repos/jimporter/gaia/contents/{+path}","compare_url":"https://api.github.com/repos/jimporter/gaia/compare/{base}...{head}","merges_url":"https://api.github.com/repos/jimporter/gaia/merges","archive_url":"https://api.github.com/repos/jimporter/gaia/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/jimporter/gaia/downloads","issues_url":"https://api.github.com/repos/jimporter/gaia/issues{/number}","pulls_url":"https://api.github.com/repos/jimporter/gaia/pulls{/number}","milestones_url":"https://api.github.com/repos/jimporter/gaia/milestones{/number}","notifications_url":"https://api.github.com/repos/jimporter/gaia/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/jimporter/gaia/labels{/name}","releases_url":"https://api.github.com/repos/jimporter/gaia/releases{/id}","created_at":"2013-01-13T08:57:30Z","updated_at":"2015-04-30T21:44:46Z","pushed_at":"2015-08-04T20:48:16Z","git_url":"git://github.com/jimporter/gaia.git","ssh_url":"git@github.com:jimporter/gaia.git","clone_url":"https://github.com/jimporter/gaia.git","svn_url":"https://github.com/jimporter/gaia","homepage":"https://wiki.mozilla.org/B2G","size":905255,"stargazers_count":0,"watchers_count":0,"language":"JavaScript","has_issues":false,"has_downloads":true,"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":"mozilla-b2g:master","ref":"master","sha":"87d04acf6599f7965697f6651f3a34f110bb6624","user":{"login":"mozilla-b2g","id":1261292,"avatar_url":"https://avatars.githubusercontent.com/u/1261292?v=3","gravatar_id":"","url":"https://api.github.com/users/mozilla-b2g","html_url":"https://github.com/mozilla-b2g","followers_url":"https://api.github.com/users/mozilla-b2g/followers","following_url":"https://api.github.com/users/mozilla-b2g/following{/other_user}","gists_url":"https://api.github.com/users/mozilla-b2g/gists{/gist_id}","starred_url":"https://api.github.com/users/mozilla-b2g/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mozilla-b2g/subscriptions","organizations_url":"https://api.github.com/users/mozilla-b2g/orgs","repos_url":"https://api.github.com/users/mozilla-b2g/repos","events_url":"https://api.github.com/users/mozilla-b2g/events{/privacy}","received_events_url":"https://api.github.com/users/mozilla-b2g/received_events","type":"Organization","site_admin":false},"repo":{"id":2317369,"name":"gaia","full_name":"mozilla-b2g/gaia","owner":{"login":"mozilla-b2g","id":1261292,"avatar_url":"https://avatars.githubusercontent.com/u/1261292?v=3","gravatar_id":"","url":"https://api.github.com/users/mozilla-b2g","html_url":"https://github.com/mozilla-b2g","followers_url":"https://api.github.com/users/mozilla-b2g/followers","following_url":"https://api.github.com/users/mozilla-b2g/following{/other_user}","gists_url":"https://api.github.com/users/mozilla-b2g/gists{/gist_id}","starred_url":"https://api.github.com/users/mozilla-b2g/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mozilla-b2g/subscriptions","organizations_url":"https://api.github.com/users/mozilla-b2g/orgs","repos_url":"https://api.github.com/users/mozilla-b2g/repos","events_url":"https://api.github.com/users/mozilla-b2g/events{/privacy}","received_events_url":"https://api.github.com/users/mozilla-b2g/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/mozilla-b2g/gaia","description":"Gaia is a HTML5-based Phone UI for the Boot 2 Gecko Project. NOTE: For details of what branches are used for what releases, see","fork":false,"url":"https://api.github.com/repos/mozilla-b2g/gaia","forks_url":"https://api.github.com/repos/mozilla-b2g/gaia/forks","keys_url":"https://api.github.com/repos/mozilla-b2g/gaia/keys{/key_id}","collaborators_url":"https://api.github.com/repos/mozilla-b2g/gaia/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/mozilla-b2g/gaia/teams","hooks_url":"https://api.github.com/repos/mozilla-b2g/gaia/hooks","issue_events_url":"https://api.github.com/repos/mozilla-b2g/gaia/issues/events{/number}","events_url":"https://api.github.com/repos/mozilla-b2g/gaia/events","assignees_url":"https://api.github.com/repos/mozilla-b2g/gaia/assignees{/user}","branches_url":"https://api.github.com/repos/mozilla-b2g/gaia/branches{/branch}","tags_url":"https://api.github.com/repos/mozilla-b2g/gaia/tags","blobs_url":"https://api.github.com/repos/mozilla-b2g/gaia/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/mozilla-b2g/gaia/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/mozilla-b2g/gaia/git/refs{/sha}","trees_url":"https://api.github.com/repos/mozilla-b2g/gaia/git/trees{/sha}","statuses_url":"https://api.github.com/repos/mozilla-b2g/gaia/statuses/{sha}","languages_url":"https://api.github.com/repos/mozilla-b2g/gaia/languages","stargazers_url":"https://api.github.com/repos/mozilla-b2g/gaia/stargazers","contributors_url":"https://api.github.com/repos/mozilla-b2g/gaia/contributors","subscribers_url":"https://api.github.com/repos/mozilla-b2g/gaia/subscribers","subscription_url":"https://api.github.com/repos/mozilla-b2g/gaia/subscription","commits_url":"https://api.github.com/repos/mozilla-b2g/gaia/commits{/sha}","git_commits_url":"https://api.github.com/repos/mozilla-b2g/gaia/git/commits{/sha}","comments_url":"https://api.github.com/repos/mozilla-b2g/gaia/comments{/number}","issue_comment_url":"https://api.github.com/repos/mozilla-b2g/gaia/issues/comments{/number}","contents_url":"https://api.github.com/repos/mozilla-b2g/gaia/contents/{+path}","compare_url":"https://api.github.com/repos/mozilla-b2g/gaia/compare/{base}...{head}","merges_url":"https://api.github.com/repos/mozilla-b2g/gaia/merges","archive_url":"https://api.github.com/repos/mozilla-b2g/gaia/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/mozilla-b2g/gaia/downloads","issues_url":"https://api.github.com/repos/mozilla-b2g/gaia/issues{/number}","pulls_url":"https://api.github.com/repos/mozilla-b2g/gaia/pulls{/number}","milestones_url":"https://api.github.com/repos/mozilla-b2g/gaia/milestones{/number}","notifications_url":"https://api.github.com/repos/mozilla-b2g/gaia/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/mozilla-b2g/gaia/labels{/name}","releases_url":"https://api.github.com/repos/mozilla-b2g/gaia/releases{/id}","created_at":"2011-09-03T01:38:46Z","updated_at":"2015-08-06T19:49:17Z","pushed_at":"2015-08-07T17:14:52Z","git_url":"git://github.com/mozilla-b2g/gaia.git","ssh_url":"git@github.com:mozilla-b2g/gaia.git","clone_url":"https://github.com/mozilla-b2g/gaia.git","svn_url":"https://github.com/mozilla-b2g/gaia","homepage":"https://wiki.mozilla.org/B2G","size":1666644,"stargazers_count":1965,"watchers_count":1965,"language":"JavaScript","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":true,"forks_count":2386,"mirror_url":null,"open_issues_count":1118,"forks":2386,"open_issues":1118,"watchers":1965,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/mozilla-b2g/gaia/pulls/31047"},"html":{"href":"https://github.com/mozilla-b2g/gaia/pull/31047"},"issue":{"href":"https://api.github.com/repos/mozilla-b2g/gaia/issues/31047"},"comments":{"href":"https://api.github.com/repos/mozilla-b2g/gaia/issues/31047/comments"},"review_comments":{"href":"https://api.github.com/repos/mozilla-b2g/gaia/pulls/31047/comments"},"review_comment":{"href":"https://api.github.com/repos/mozilla-b2g/gaia/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/mozilla-b2g/gaia/pulls/31047/commits"},"statuses":{"href":"https://api.github.com/repos/mozilla-b2g/gaia/statuses/cbd74b6a4555e7db7779aaa85d616830a4dd0b31"}}}}