{"action":"created","comment":{"url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/pulls/comments/38262682","id":38262682,"diff_hunk":"@@ -20,302 +36,589 @@ var prefs = Cc[\"@mozilla.org/preferences-service;1\"].getService(Ci.nsIPrefServic\n var Request = require(\"sdk/request\").Request;\n var tabs = require(\"sdk/tabs\");\n \n+const DEBUG = true;\n+const TAG = \"bitcoin-price-ticker\";\n+const DATA_PROVIDERS_URL = \"https://raw.githubusercontent.com/neoranga55/bitcoin-price-ticker/master/data/data-providers.json\";\n+const ADDON_UPDATE_DOCUMENT_URL = \"http://neoranga55.github.io/bitcoin-price-ticker/\";\n+const ADDON_ID = \"jid0-ziK34XHkBWB9ezxd4l9Q1yC7RP0@jetpack\";\n+const DEFAULT_REFRESH_RATE = 60;\n+const DEFAULT_FONT_SIZE = 14;\n+const WIDGET_SUFFIX = \"-widget\";\n+const IFRAME_SUFFIX = \"-iframe\";\n+const IFRAME_URL = \"chrome://bitcoin-price-ticker/content/index.html\";\n+const EXTRA_FRAME_SPACING = 8;\n+const log = console.log.bind(console);\n+\n+function dlog(message) {\n+  if (DEBUG) {\n+    log(TAG + \" \" + message);\n+  }\n+}\n+\n var orderedTickers = [];\n-var tickers = {}; // Store all tickers here\n-var tickersFrame = null\n+var tickers = {}; // Store all tickers configuration here\n+var tickersFrame = null;\n var toolbar = null;\n+var usingWidgets = false;\n+var draggingWidget = false;\n \n-exports.main = function() {\n \n-  function getPreference(prefName, type) {\n-    if (typeof Preferences.prefs[prefName] == \"undefined\") {\n-      if (DEBUG) {\n-        console.log(TAG + \" addon error: \" + prefName + \" preference is not defined\");\n-      }\n-      switch (type) {\n-        case \"boolean\":\n-          return false;\n-        case \"integer\":\n-          return -1;\n-        case \"string\":\n-          return \"\";\n-        default:\n-          return null;\n+// Methods to interact with Mozilla's preferences\n+\n+\n+function getPreference(prefName, type) {\n+  if (typeof Preferences.prefs[prefName] === undefined) {\n+    dlog(\"Addon error: \" + prefName + \" preference is not defined\");\n+    switch (type) {\n+      case \"boolean\":\n+        return false;\n+      case \"integer\":\n+        return -1;\n+      case \"string\":\n+        return \"\";\n+      default:\n+        return null;\n+    }\n+  }\n+  return Preferences.prefs[prefName];\n+}\n+\n+function getBooleanPreference(prefName) {\n+  return getPreference(prefName, \"boolean\");\n+}\n+\n+function getIntegerPreference(prefName) {\n+  return getPreference(prefName, \"integer\");\n+}\n+\n+function getStringPreference(prefName) {\n+  return getPreference(prefName, \"string\");\n+}\n+\n+function getBackgroundColor(id) {\n+  var lowId = id.toLowerCase();\n+  var otherBgCryptos = [ \"dogecoin\", \"worldcoin\", \"namecoin\",\n+                      \"auroracoin\", \"blackcoin\", \"nxt\", \"bitshares\",\n+                      \"ripple\", \"maidsafe\", \"bitcoindark\", \"monero\",\n+                      \"dash\", \"burst\", \"ether\" ];\n+  for (var i = 0; i < otherBgCryptos.length; i++) {\n+    if (lowId.indexOf(otherBgCryptos[i]) != -1) {  // Alt-coin\n+      if (getBooleanPreference(\"other-background\")) {\n+        return otherBgCryptos[i];\n       }\n     }\n-    return Preferences.prefs[prefName];\n   }\n-\n-  function getBooleanPreference(prefName) {\n-    return getPreference(prefName, \"boolean\");\n+  if (lowId.indexOf(\"litecoin\") != -1) {\n+    if (getBooleanPreference(\"silver-background\")) { // Currency is Litecoin\n+      return \"silver\";\n+    }\n+  } else if (getBooleanPreference(\"gold-background\")) { // Currency is Bitcoin\n+    return \"gold\";\n   }\n+  return null;\n+}\n \n-  function getIntegerPreference(prefName) {\n-    return getPreference(prefName, \"integer\");\n+function registerTickerEvents(tickerId) {\n+  Preferences.on(\"p\" + tickerId, function() { // Create event to enable/disable of tickers\n+    toggleTicker(tickerId);\n+  });\n+  // Create events to update ticker when a particular option is changed\n+  Preferences.on(\"p\" + tickerId + \"Color\", function() {\n+    if (tickers[tickerId] !== null) {\n+      updateTickerConfiguration(tickerId);\n+    }\n+  });\n+}\n+\n+// Register general settings' events\n+Preferences.on(\"toolbar\", toggleBarDisplay);\n+Preferences.on(\"Timer\", updateTickerRefreshInterval);\n+Preferences.on(\"defaultFontSize\", updateActiveTickersSharedStyle);\n+Preferences.on(\"gold-background\", updateActiveTickersSharedStyle);\n+Preferences.on(\"silver-background\", updateActiveTickersSharedStyle);\n+Preferences.on(\"other-background\", updateActiveTickersSharedStyle);\n+// Preferences.on(\"show-long-trend\", updateAllTickers);\n+// Preferences.on(\"show-short-trend\", updateAllTickers);\n+Preferences.on(\"show-currency-label\", updateActiveTickersSharedStyle);\n+\n+Preferences.on(\"infoButton\", showAddonUpdateDocument);\n+// Check updated version\n+AddonManager.getAddonByID(ADDON_ID, function(addon) {\n+  showAddonUpdate(addon.version);\n+});\n+\n+function registerEvents() {\n+  for (var tickerId in tickers) {\n+    if (tickers.hasOwnProperty(tickerId)) {\n+      registerTickerEvents(tickerId);\n+    }\n   }\n-\n-  function getStringPreference(prefName) {\n-    return getPreference(prefName, \"string\");\n+}\n+\n+function getWidgetWindow(tickerId) {\n+  var doc = tickers[tickerId].doc;\n+  if ((doc !== undefined) && (doc !== null) &&\n+        (doc.getElementById(tickerId + IFRAME_SUFFIX))) { // Widgets\n+    return doc.getElementById(tickerId + IFRAME_SUFFIX).contentWindow;\n+  } else {\n+    return null;\n   }\n+}\n \n-  function getBackgroundColor(id) {\n-    var lowId = id.toLowerCase();\n-    var otherBgCryptos = [ \"dogecoin\", \"worldcoin\", \"namecoin\", \"auroracoin\", \"blackcoin\", \"nxt\",\n-      \"bitshares\", \"ripple\", \"maidsafe\", \"bitcoindark\", \"monero\", \"dash\", \"burst\" ];\n-    for (var i = 0; i < otherBgCryptos.length; i++) {\n-      if (lowId.indexOf(otherBgCryptos[i]) != -1) {  // Alt-coin\n-        if (getBooleanPreference(\"other-background\")) {\n-          return otherBgCryptos[i];\n-        }\n+function getTickerConfigurationData(tickerId) {\n+  var fontSize = getIntegerPreference(\"defaultFontSize\");\n+  if (fontSize <= 0) {\n+    fontSize = DEFAULT_FONT_SIZE;\n+  }\n+  if (tickers[tickerId]) {\n+    tickers[tickerId].enabled = getBooleanPreference(\"p\" + tickerId);\n+    tickers[tickerId].currencyPosition = getStringPreference(\"show-currency-label\");\n+    tickers[tickerId].color = getStringPreference(\"p\" + tickerId + \"Color\");\n+    tickers[tickerId].fontSize = fontSize;\n+    tickers[tickerId].background = getBackgroundColor(tickerId);\n+  }\n+}\n+\n+/**\n+ * Load tickers in the order that they are enabled in preferences\n+ **/\n+function loadDefaultTickers() {\n+  for (var tickerId in tickers) {\n+    if ( getBooleanPreference(\"p\" + tickerId) ) { // Create Ticker\n+      dlog(\"Loading ticker for \" + tickerId);\n+      updateTickerConfiguration(tickerId);\n+      if (usingWidgets) {\n+        createNewTickersWidget(tickerId);\n       }\n-    }\n-    if (lowId.indexOf(\"litecoin\") != -1) {\n-      if (getBooleanPreference(\"silver-background\")) { // Currency is Litecoin\n-        return \"silver\";\n+      if (tickers[tickerId].enabled) {\n+        orderedTickers.push(tickerId);\n       }\n-    } else if (getBooleanPreference(\"gold-background\")) { // Currency is Bitcoin\n-      return \"gold\";\n     }\n-    return null;\n   }\n-\n-  function getTickerConfigurationData(tickerId) {\n-    var fontSize = getIntegerPreference(\"defaultFontSize\");\n-    if (fontSize <= 0) {\n-      fontSize = DEFAULT_FONT_SIZE;\n+  if ((orderedTickers != null) && (orderedTickers.length > 0)) {\n+    storeTickersOrder();\n+  }\n+}\n+\n+/**\n+ * Load the order of the tickers from Firefox's profile and create them\n+ **/\n+function loadTickersInOrder() {\n+  var orderedActiveTickers = \"\";\n+  try {\n+    orderedActiveTickers = prefs.getCharPref(\"extensions.ADDON_ID.tickers_order\");\n+    if (orderedActiveTickers.length < 1) { // There is no order of tickers in addon set yet\n+      loadDefaultTickers();\n+      return;\n     }\n-    if (tickers[tickerId]) {\n-      tickers[tickerId].enabled = getBooleanPreference(\"p\" + tickerId);\n-      tickers[tickerId].currencyPosition = getStringPreference(\"show-currency-label\");\n-      tickers[tickerId].color = getStringPreference(\"p\" + tickerId + \"Color\");\n-      tickers[tickerId].fontSize = fontSize;\n-      tickers[tickerId].background = getBackgroundColor(tickerId);\n+    var listOrderedTickers = orderedActiveTickers.split(\",\");\n+    if (listOrderedTickers.length < 1) { // There is no order of tickers in addon set yet\n+      loadDefaultTickers();\n+      return;\n     }\n-  }\n-\n-  // Use tickers enabled in preferences to load in that order regardless of stored order\n-  function loadDefaultTickers() {\n-    for (var tickerId in tickers) {\n-      if ( getBooleanPreference(\"p\" + tickerId) ) { // Create Ticker\n-        updateTickerConfiguration(tickerId);\n-        if (tickers[tickerId].enabled) {\n-          orderedTickers.push(tickerId);\n-        }\n+    for (var i in listOrderedTickers) {\n+      var tickerId = listOrderedTickers[i];\n+      updateTickerConfiguration(tickerId);\n+      if (usingWidgets) {\n+        createNewTickersWidget(tickerId);\n       }\n     }\n-    if ((orderedTickers != null) && (orderedTickers.length > 0)) {\n-      storeTickersOrder();\n-    }\n+  } catch (e) { // There is no order of tickers in addon set yet\n+    loadDefaultTickers();\n   }\n-\n-  // Load the order of the tickers and simultaneously create them\n-  function loadTickersInOrder() {\n+}\n+\n+/**\n+ * Store the order of the active tickers in Firefox's profile\n+ **/\n+function storeTickersOrder() {\n+  if ((orderedTickers == null) || (orderedTickers.length == 0)) {\n+    loadDefaultTickers();\n+  } else {\n     var orderedActiveTickers = \"\";\n-    try {\n-      orderedActiveTickers = prefs.getCharPref(\"extensions.ADDON_ID.tickers_order\");\n-      if (orderedActiveTickers.length < 1) { // There is no order of tickers in addon set yet\n-        loadDefaultTickers();\n-        return;\n-      }\n-      var listOrderedTickers = orderedActiveTickers.split(\",\");\n-      if (listOrderedTickers.length < 1) { // There is no order of tickers in addon set yet\n-        loadDefaultTickers();\n-        return;\n-      }\n-      for (var i in listOrderedTickers) {\n-        loadTicker(listOrderedTickers[i]);\n-        if (tickers[tickerId].enabled) {\n-          orderedTickers.push(tickerId);\n+    if ((orderedTickers != null) && (orderedTickers.length > 0)) {\n+      for (var i = 0; i < orderedTickers.length; i++) { // Traverse skipping empty\n+        if (orderedActiveTickers.length > 0) {\n+          orderedActiveTickers += \",\" + orderedTickers[i];\n+        } else {\n+          orderedActiveTickers = orderedTickers[i];\n         }\n       }\n-    } catch (e) { // There is no order of tickers in addon set yet\n-      loadDefaultTickers();\n     }\n-  }\n-\n-  // Store the order of the active tickers\n-  function storeTickersOrder() {\n-    if ((orderedTickers == null) || (orderedTickers.length == 0)) {\n-      loadDefaultTickers();\n-    } else {\n-      var orderedActiveTickers = \"\";\n-      if ((orderedTickers != null) && (orderedTickers.length > 0)) {\n-        for (var i = 0; i < orderedTickers.length; i++) { // Traverse skipping empty\n-          if (orderedActiveTickers.length > 0) {\n-            orderedActiveTickers += \",\" + orderedTickers[i];\n-          } else {\n-            orderedActiveTickers = orderedTickers[i];\n-          }\n-        }\n-      }\n-      if (DEBUG) {\n-        console.log(TAG + \" Storing tickers in order:\" + orderedActiveTickers);\n-      }\n-      prefs.setCharPref(\"extensions.ADDON_ID.tickers_order\", orderedActiveTickers); // Update list of tickers active in order in preferences\n+    if (DEBUG) {\n+      console.dir(orderedTickers);\n+      dlog(\"Storing tickers in order:\" + orderedActiveTickers);\n     }\n+    // Update ordered list of active tickers in Firefox's profile\n+    prefs.setCharPref(\"extensions.ADDON_ID.tickers_order\", orderedActiveTickers);\n   }\n-\n-  // Live enable/disable ticker from options checkbox\n-  function toggleTicker(tickerId) {\n-    if ( getBooleanPreference(\"p\" + tickerId) ) { // Enable Ticker\n-      updateTickerConfiguration(tickerId);\n+}\n+\n+/**\n+ * Live enable/disable ticker from options checkbox\n+ **/\n+function toggleTicker(tickerId) {\n+  if ( getBooleanPreference(\"p\" + tickerId) ) { // Enable Ticker\n+    updateTickerConfiguration(tickerId);\n+    if (usingWidgets) {\n+      createNewTickersWidget(tickerId);\n+    } else {\n       updateTickerRefreshIntervalForTicker(tickerId);\n-      orderedTickers.push(tickerId);\n-      storeTickersOrder();\n-    } else if (tickers[tickerId].enabled) { // Disable Ticker if it exists\n-      tickers[tickerId].enabled = false;\n-      stopAutoPriceUpdate(tickerId);\n-      updateTickerConfiguration(tickerId);\n-      for (var i = 0; i < orderedTickers.length; i++) {\n-        if (orderedTickers[i] == tickerId) {\n-          orderedTickers.splice(i, 1); // Remove the ticker completely from the array with reordering\n-          break;\n-        }\n+    }\n+    orderedTickers.push(tickerId);\n+    storeTickersOrder();\n+  } else if (tickers[tickerId].enabled) { // Disable Ticker if it exists\n+    tickers[tickerId].enabled = false;\n+    stopAutoPriceUpdate(tickerId);\n+    updateTickerConfiguration(tickerId);\n+    if (usingWidgets) {\n+      destroyTickersWidget(tickerId);\n+    }\n+    for (var i = 0; i < orderedTickers.length; i++) {\n+      if (orderedTickers[i] == tickerId) {\n+        orderedTickers.splice(i, 1); // Remove the ticker completely from the array with reordering\n+        break;\n       }\n-      storeTickersOrder();\n     }\n+    storeTickersOrder();\n   }\n-\n-  function updateTickerConfiguration(tickerId) {\n-    getTickerConfigurationData(tickerId);\n-    if (DEBUG) {\n-      console.log(TAG + \" Sending config JSON data to frame:\" + tickerId + \n-                  \"-\" + JSON.stringify(tickers[tickerId]));\n-    }\n+}\n+\n+\n+\n+// Methods to comunicate between Addon and Visualization interface\n+\n+\n+/**\n+ * This method loads and updates the configuration of a ticker\n+ * then sends this configuration to client (i)Frame that updates\n+ * the configuration of the ticker or creates it if it didn't exist\n+ *\n+ * tickerId: Unique ID of the ticker to update\n+ **/\n+function updateTickerConfiguration(tickerId) {\n+  getTickerConfigurationData(tickerId);\n+  dlog(\"Updating configuration for ticker:\" + tickerId + \n+                \"-\" + JSON.stringify(tickers[tickerId]));\n+  sendUpdatedTickerConfiguration(tickerId);\n+}\n+\n+function getFilteredTickerData(tickerId) {\n+  var data = JSON.parse(JSON.stringify(tickers[tickerId]));\n+  data.doc = null;\n+  return data;\n+}\n+\n+function sendUpdatedTickerConfiguration(tickerId) {\n+  dlog(\"Sending configuration updated JSON data to \" + tickerId);\n+  var doc = tickers[tickerId].doc;\n+  if (usingWidgets && \n+      (doc !== undefined) && (doc !== null)) { // For Widgets\n+    var win = getWidgetWindow(tickerId);\n+    if ((tickers[tickerId].enabled) && (win)) {\n+      win.postMessage({\n+        \"type\": \"updateTickerConfiguration\",\n+        \"id\": tickerId,\n+        \"data\": getFilteredTickerData(tickerId)\n+      }, \"*\");\n+      adjustWidgetSize(tickerId);\n+    }\n+  } else if (tickersFrame !== null) { // For Toolbar\n     tickersFrame.postMessage({\n       \"type\": \"updateTickerConfiguration\",\n       \"id\": tickerId,\n-      \"data\": tickers[tickerId]\n+      \"data\": getFilteredTickerData(tickerId)\n     }, tickersFrame.url);\n+  } else if (DEBUG) {\n+    dlog(\"Frame & Widget docs are both empty for Widget \" + tickerId);\n   }\n+}\n \n-  function fetchURLData(id, url, jsonPath) {\n-    if (id == \"undefined\" || url == \"undefined\" || jsonPath == \"undefined\") {\n-      return;\n-    }\n-    if (DEBUG) {\n-      console.log(TAG + \" Requesting JSON data from \" + url);\n-    }\n-    Request({\n-      url: url,\n-      onComplete: function (response) {\n-        if ((response !== null) && (response.json !== null)) {\n-          if (DEBUG) {\n-            console.log(TAG + \" Data received, searching in document for path:\" + jsonPath);\n+function fetchURLData(tickerId, url, jsonPath) {\n+  if (tickerId === undefined || url === undefined || jsonPath === undefined) {\n+    return;\n+  }\n+  if (usingWidgets) {\n+    // This update is required becuase the ticker's iframe \n+    // is sometimes destroyed by Firefox's UI updates\n+    updateTickerConfiguration(tickerId);\n+  }\n+  dlog(\"Requesting JSON price data from \" + url);\n+  Request({\n+    url: url,\n+    onComplete: function (response) {\n+      if ((response !== null) && (response.json !== null)) {\n+        dlog(\"Price data received. Searching in document for path:\" + jsonPath);\n+        var price = response.json;\n+        for (var i = 0; i < jsonPath.length; i++) { // Parse JSON path\n+          if (typeof price[jsonPath[i]] === undefined) {\n+            dlog(\"Error loading ticker \" + tickerId + \n+                          \". URL is not correctly responding:\" + url);\n+            return;\n           }\n-          var price = response.json;\n-          for (var i = 0; i < jsonPath.length; i++) { // Parse JSON path\n-            if (typeof price[jsonPath[i]] == \"undefined\") {\n-              if (DEBUG) {\n-                console.log(TAG + \" error loading ticker \" + id + \n-                            \". URL is not correctly responding:\" + url);\n+          price = price[jsonPath[i]];\n+        }\n+        dlog(\"Price received and parsed for \" + tickerId + \": \" + price);\n+        var doc = tickers[tickerId].doc;\n+        if (usingWidgets && \n+            (doc !== undefined) && (doc !== null)) { // For Widgets\n+          var win = getWidgetWindow(tickerId);\n+          if (win) {\n+            win.postMessage({\n+              \"type\": \"updateTickerModelPrice\",\n+              \"id\": tickerId,\n+              \"data\": {\n+                \"price\": price\n               }\n-              return;\n-            }\n-            price = price[jsonPath[i]];\n-          }\n-          if (DEBUG) {\n-            console.log(TAG + \" Price received and parsed: \" + price);\n+            }, \"*\");\n+            adjustWidgetSize(tickerId);\n           }\n+        } else if (tickersFrame !== null) { // For Toolbar\n           tickersFrame.postMessage({\n             \"type\": \"updateTickerModelPrice\",\n-            \"id\": id,\n+            \"id\": tickerId,\n             \"data\": {\n               \"price\": price\n             }\n           }, tickersFrame.url);\n+        } else {\n+          dlog(\"Frame and Widget document are both empty for Widget \" + tickerId);\n         }\n       }\n-    }).get();\n-  }\n+    }\n+  }).get();\n+}\n+\n+\n+\n+// Methods to create tickers and manipulate them\n+\n+\n+/**\n+ * Create a Widget, attach listeners and trigger update on Widget Added to window\n+ **/\n+function createNewTickersWidget(tickerId) {\n+  dlog(\"Creating widget for ticker \" + tickerId);\n+  var tickerTitle = tickers[tickerId].exchangeName + \" \" + \n+                      tickers[tickerId].currency + \"/\" + tickers[tickerId].baseCurrency","path":"index.js","position":573,"original_position":573,"commit_id":"ecf7315e95573610ed937a7afdabb63b96f47769","original_commit_id":"ecf7315e95573610ed937a7afdabb63b96f47769","user":{"login":"houndci","id":6697940,"avatar_url":"https://avatars.githubusercontent.com/u/6697940?v=3","gravatar_id":"","url":"https://api.github.com/users/houndci","html_url":"https://github.com/houndci","followers_url":"https://api.github.com/users/houndci/followers","following_url":"https://api.github.com/users/houndci/following{/other_user}","gists_url":"https://api.github.com/users/houndci/gists{/gist_id}","starred_url":"https://api.github.com/users/houndci/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/houndci/subscriptions","organizations_url":"https://api.github.com/users/houndci/orgs","repos_url":"https://api.github.com/users/houndci/repos","events_url":"https://api.github.com/users/houndci/events{/privacy}","received_events_url":"https://api.github.com/users/houndci/received_events","type":"User","site_admin":false},"body":"Line is too long.<br>Missing semicolon.","created_at":"2015-08-29T14:45:34Z","updated_at":"2015-08-29T14:45:34Z","html_url":"https://github.com/neoranga55/bitcoin-price-ticker/pull/14#discussion_r38262682","pull_request_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/pulls/14","_links":{"self":{"href":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/pulls/comments/38262682"},"html":{"href":"https://github.com/neoranga55/bitcoin-price-ticker/pull/14#discussion_r38262682"},"pull_request":{"href":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/pulls/14"}}},"pull_request":{"url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/pulls/14","id":43694452,"html_url":"https://github.com/neoranga55/bitcoin-price-ticker/pull/14","diff_url":"https://github.com/neoranga55/bitcoin-price-ticker/pull/14.diff","patch_url":"https://github.com/neoranga55/bitcoin-price-ticker/pull/14.patch","issue_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/issues/14","number":14,"state":"open","locked":false,"title":"Firefox customizable ui","user":{"login":"neoranga55","id":1936647,"avatar_url":"https://avatars.githubusercontent.com/u/1936647?v=3","gravatar_id":"","url":"https://api.github.com/users/neoranga55","html_url":"https://github.com/neoranga55","followers_url":"https://api.github.com/users/neoranga55/followers","following_url":"https://api.github.com/users/neoranga55/following{/other_user}","gists_url":"https://api.github.com/users/neoranga55/gists{/gist_id}","starred_url":"https://api.github.com/users/neoranga55/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/neoranga55/subscriptions","organizations_url":"https://api.github.com/users/neoranga55/orgs","repos_url":"https://api.github.com/users/neoranga55/repos","events_url":"https://api.github.com/users/neoranga55/events{/privacy}","received_events_url":"https://api.github.com/users/neoranga55/received_events","type":"User","site_admin":false},"body":"Creation of a custom Widget element to behave like the old (Firefox <29) Widget\r\nInclude lots of bug fixes","created_at":"2015-08-29T13:16:23Z","updated_at":"2015-08-29T14:45:35Z","closed_at":null,"merged_at":null,"merge_commit_sha":"a7ee3ed8e1eafdc4da42b7d20f91d366b5ecee0e","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/pulls/14/commits","review_comments_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/pulls/14/comments","review_comment_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/pulls/comments{/number}","comments_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/issues/14/comments","statuses_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/statuses/ecf7315e95573610ed937a7afdabb63b96f47769","head":{"label":"neoranga55:firefox-customizable-ui","ref":"firefox-customizable-ui","sha":"ecf7315e95573610ed937a7afdabb63b96f47769","user":{"login":"neoranga55","id":1936647,"avatar_url":"https://avatars.githubusercontent.com/u/1936647?v=3","gravatar_id":"","url":"https://api.github.com/users/neoranga55","html_url":"https://github.com/neoranga55","followers_url":"https://api.github.com/users/neoranga55/followers","following_url":"https://api.github.com/users/neoranga55/following{/other_user}","gists_url":"https://api.github.com/users/neoranga55/gists{/gist_id}","starred_url":"https://api.github.com/users/neoranga55/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/neoranga55/subscriptions","organizations_url":"https://api.github.com/users/neoranga55/orgs","repos_url":"https://api.github.com/users/neoranga55/repos","events_url":"https://api.github.com/users/neoranga55/events{/privacy}","received_events_url":"https://api.github.com/users/neoranga55/received_events","type":"User","site_admin":false},"repo":{"id":13824499,"name":"bitcoin-price-ticker","full_name":"neoranga55/bitcoin-price-ticker","owner":{"login":"neoranga55","id":1936647,"avatar_url":"https://avatars.githubusercontent.com/u/1936647?v=3","gravatar_id":"","url":"https://api.github.com/users/neoranga55","html_url":"https://github.com/neoranga55","followers_url":"https://api.github.com/users/neoranga55/followers","following_url":"https://api.github.com/users/neoranga55/following{/other_user}","gists_url":"https://api.github.com/users/neoranga55/gists{/gist_id}","starred_url":"https://api.github.com/users/neoranga55/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/neoranga55/subscriptions","organizations_url":"https://api.github.com/users/neoranga55/orgs","repos_url":"https://api.github.com/users/neoranga55/repos","events_url":"https://api.github.com/users/neoranga55/events{/privacy}","received_events_url":"https://api.github.com/users/neoranga55/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/neoranga55/bitcoin-price-ticker","description":"Bitcoin Price Ticker Firefox Addon with multiple price sources and configuration options","fork":false,"url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker","forks_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/forks","keys_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/keys{/key_id}","collaborators_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/teams","hooks_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/hooks","issue_events_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/issues/events{/number}","events_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/events","assignees_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/assignees{/user}","branches_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/branches{/branch}","tags_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/tags","blobs_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/git/refs{/sha}","trees_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/git/trees{/sha}","statuses_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/statuses/{sha}","languages_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/languages","stargazers_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/stargazers","contributors_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/contributors","subscribers_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/subscribers","subscription_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/subscription","commits_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/commits{/sha}","git_commits_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/git/commits{/sha}","comments_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/comments{/number}","issue_comment_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/issues/comments{/number}","contents_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/contents/{+path}","compare_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/compare/{base}...{head}","merges_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/merges","archive_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/downloads","issues_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/issues{/number}","pulls_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/pulls{/number}","milestones_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/milestones{/number}","notifications_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/labels{/name}","releases_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/releases{/id}","created_at":"2013-10-24T06:39:00Z","updated_at":"2015-06-08T06:07:53Z","pushed_at":"2015-08-29T14:45:28Z","git_url":"git://github.com/neoranga55/bitcoin-price-ticker.git","ssh_url":"git@github.com:neoranga55/bitcoin-price-ticker.git","clone_url":"https://github.com/neoranga55/bitcoin-price-ticker.git","svn_url":"https://github.com/neoranga55/bitcoin-price-ticker","homepage":"https://addons.mozilla.org/en-US/firefox/addon/bitcoin-price-ticker/","size":5843,"stargazers_count":8,"watchers_count":8,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":6,"mirror_url":null,"open_issues_count":1,"forks":6,"open_issues":1,"watchers":8,"default_branch":"master"}},"base":{"label":"neoranga55:master","ref":"master","sha":"e52fc938fba701dc42e900de76476f5ad8389369","user":{"login":"neoranga55","id":1936647,"avatar_url":"https://avatars.githubusercontent.com/u/1936647?v=3","gravatar_id":"","url":"https://api.github.com/users/neoranga55","html_url":"https://github.com/neoranga55","followers_url":"https://api.github.com/users/neoranga55/followers","following_url":"https://api.github.com/users/neoranga55/following{/other_user}","gists_url":"https://api.github.com/users/neoranga55/gists{/gist_id}","starred_url":"https://api.github.com/users/neoranga55/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/neoranga55/subscriptions","organizations_url":"https://api.github.com/users/neoranga55/orgs","repos_url":"https://api.github.com/users/neoranga55/repos","events_url":"https://api.github.com/users/neoranga55/events{/privacy}","received_events_url":"https://api.github.com/users/neoranga55/received_events","type":"User","site_admin":false},"repo":{"id":13824499,"name":"bitcoin-price-ticker","full_name":"neoranga55/bitcoin-price-ticker","owner":{"login":"neoranga55","id":1936647,"avatar_url":"https://avatars.githubusercontent.com/u/1936647?v=3","gravatar_id":"","url":"https://api.github.com/users/neoranga55","html_url":"https://github.com/neoranga55","followers_url":"https://api.github.com/users/neoranga55/followers","following_url":"https://api.github.com/users/neoranga55/following{/other_user}","gists_url":"https://api.github.com/users/neoranga55/gists{/gist_id}","starred_url":"https://api.github.com/users/neoranga55/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/neoranga55/subscriptions","organizations_url":"https://api.github.com/users/neoranga55/orgs","repos_url":"https://api.github.com/users/neoranga55/repos","events_url":"https://api.github.com/users/neoranga55/events{/privacy}","received_events_url":"https://api.github.com/users/neoranga55/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/neoranga55/bitcoin-price-ticker","description":"Bitcoin Price Ticker Firefox Addon with multiple price sources and configuration options","fork":false,"url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker","forks_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/forks","keys_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/keys{/key_id}","collaborators_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/teams","hooks_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/hooks","issue_events_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/issues/events{/number}","events_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/events","assignees_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/assignees{/user}","branches_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/branches{/branch}","tags_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/tags","blobs_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/git/refs{/sha}","trees_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/git/trees{/sha}","statuses_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/statuses/{sha}","languages_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/languages","stargazers_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/stargazers","contributors_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/contributors","subscribers_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/subscribers","subscription_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/subscription","commits_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/commits{/sha}","git_commits_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/git/commits{/sha}","comments_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/comments{/number}","issue_comment_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/issues/comments{/number}","contents_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/contents/{+path}","compare_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/compare/{base}...{head}","merges_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/merges","archive_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/downloads","issues_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/issues{/number}","pulls_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/pulls{/number}","milestones_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/milestones{/number}","notifications_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/labels{/name}","releases_url":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/releases{/id}","created_at":"2013-10-24T06:39:00Z","updated_at":"2015-06-08T06:07:53Z","pushed_at":"2015-08-29T14:45:28Z","git_url":"git://github.com/neoranga55/bitcoin-price-ticker.git","ssh_url":"git@github.com:neoranga55/bitcoin-price-ticker.git","clone_url":"https://github.com/neoranga55/bitcoin-price-ticker.git","svn_url":"https://github.com/neoranga55/bitcoin-price-ticker","homepage":"https://addons.mozilla.org/en-US/firefox/addon/bitcoin-price-ticker/","size":5843,"stargazers_count":8,"watchers_count":8,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":6,"mirror_url":null,"open_issues_count":1,"forks":6,"open_issues":1,"watchers":8,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/pulls/14"},"html":{"href":"https://github.com/neoranga55/bitcoin-price-ticker/pull/14"},"issue":{"href":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/issues/14"},"comments":{"href":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/issues/14/comments"},"review_comments":{"href":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/pulls/14/comments"},"review_comment":{"href":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/pulls/14/commits"},"statuses":{"href":"https://api.github.com/repos/neoranga55/bitcoin-price-ticker/statuses/ecf7315e95573610ed937a7afdabb63b96f47769"}}}}