{"action":"created","comment":{"url":"https://api.github.com/repos/wallabag/wallabagger/pulls/comments/108288379","pull_request_review_id":29310912,"id":108288379,"diff_hunk":"@@ -1,207 +1,457 @@\n-/* globals WallabagApi */\n+//* globals WallabagApi */\n+\n+// declarations\n+\n if (typeof (browser) === 'undefined' && typeof (chrome) === 'object') {\n     browser = chrome;\n }\n \n-const icon = {\n+let Port = null;\n+let portConnected = false;\n+\n+var CacheType = function (enable) {\n+    this.enabled = enable;\n+    this._cache = [];\n+};\n+\n+CacheType.prototype = {\n+    _cache: null,\n+    enabled: null,\n+\n+    str: function (some) {\n+        return btoa(JSON.stringify(some));\n+    },\n+\n+    set: function (key, data) {\n+        if (this.enabled) {\n+            this._cache[this.str(key)] = data;\n+        }\n+    },\n+\n+    clear: function (key) {\n+        if (this.enabled) {\n+            delete this._cache[this.str(key)];\n+        }\n+    },\n+\n+    check: function (key) {\n+        return this.enabled && (this._cache[this.str(key)] !== undefined);\n+    },\n+\n+    get: function (key) {\n+        return this.enabled ? this._cache[this.str(key)] : undefined;\n+    }\n+};\n+\n+const icons = {\n     'default': browser.runtime.getManifest().browser_action.default_icon,\n     'good': 'img/wallabagger-green.svg',\n     'wip': 'img/wallabagger-yellow.svg',\n     'bad': 'img/wallabagger-red.svg'\n \n };\n \n-const GetApi = () => {\n-    const api = new WallabagApi();\n-    return api.init()\n-        .then(data => {\n-            if (api.needNewAppToken()) {\n-                return api.GetAppToken()\n-                    .then(r => api);\n-            }\n-            return api;\n-        })\n-        .catch(error => {\n-            throw error;\n-        });\n+const wallabagContextMenus = [\n+    {\n+        id: 'wallabagger-add-link',\n+        title: 'Wallabag it!',\n+        contexts: ['link', 'page']\n+    },\n+    {\n+        type: 'separator',\n+        contexts: ['browser_action']\n+    },\n+    {\n+        id: 'unread',\n+        title: 'Unread articles',\n+        contexts: ['browser_action']\n+    },\n+    {\n+        id: 'starred',\n+        title: 'Starred articles',\n+        contexts: ['browser_action']\n+    },\n+    {\n+        id: 'archive',\n+        title: 'Archived articles',\n+        contexts: ['browser_action']\n+    },\n+    {\n+        id: 'all',\n+        title: 'All articles',\n+        contexts: ['browser_action']\n+    },\n+    {\n+        id: 'tag',\n+        title: 'Tag list',\n+        contexts: ['browser_action']\n+    }\n+];\n+\n+const existStates = {\n+    exists: 'exists',\n+    notexists: 'notexists',\n+    wip: 'wip'\n };\n \n-browser.contextMenus.create({\n-    id: 'wallabagger-add-link',\n-    title: 'Wallabag it!',\n-    contexts: ['link', 'page']\n-});\n+const cache = new CacheType(true); // TODO - here checking option\n+const dirtyCache = new CacheType(true);\n+const existCache = new CacheType(true);\n \n-browser.contextMenus.create({\n-    type: 'separator',\n-    contexts: ['browser_action']\n-});\n+const api = new WallabagApi();\n \n-browser.contextMenus.create({\n-    id: 'Unread-articles',\n-    title: 'Unread articles',\n-    contexts: ['browser_action']\n-});\n+// Code\n \n-browser.contextMenus.create({\n-    id: 'Favorite-articles',\n-    title: 'Starred articles',\n-    contexts: ['browser_action']\n+api.init().then(data => {\n+    addExistCheckListeners(api.data.AllowExistCheck);\n+    api.GetTags().then(tags => { cache.set('allTags', tags); });\n });\n \n-browser.contextMenus.create({\n-    id: 'Archived-articles',\n-    title: 'Archived articles',\n-    contexts: ['browser_action']\n-});\n+addListeners();\n+createContextMenus();\n \n-browser.contextMenus.create({\n-    id: 'All-articles',\n-    title: 'All articles',\n-    contexts: ['browser_action']\n-});\n+// Functions\n+function createContextMenus () {\n+    wallabagContextMenus.map(menu => { browser.contextMenus.create(menu); });\n+}\n \n-browser.contextMenus.create({\n-    id: 'Tag-list',\n-    title: 'Tag list',\n-    contexts: ['browser_action']\n-});\n+function onTabActivatedListener (activeInfo) {\n+    setIcon(icons.default);\n+    const { tabId } = activeInfo;\n+    browser.tabs.get(tabId, function (tab) {\n+        checkExist(tab.url);\n+    });\n+}\n \n-function savePageToWallabag (url) {\n-    browser.browserAction.setIcon({ path: icon.wip });\n-\n-    GetApi().then(api => api.SavePage(url))\n-        .then(r => {\n-            browser.browserAction.setIcon({ path: icon.good });\n-            setTimeout(function () { browser.browserAction.setIcon({ path: icon.default }); }, 5000);\n-        })\n-        .catch(e => {\n-            browser.browserAction.setIcon({ path: icon.bad });\n-            setTimeout(function () { browser.browserAction.setIcon({ path: icon.default }); }, 5000);\n-        });\n-};\n+function onTabCreatedListener (tab) {\n+    setIcon(icons.default);\n+}\n+\n+function onTabUpdatedListener (tabId, changeInfo, tab) {\n+    if (changeInfo.status === 'loading' && tab.active) {\n+        saveExistFlag(tab.url, existStates.notexists);\n+        requestExists(tab.url);\n+    }\n+}\n+\n+function addExistCheckListeners (enable) {\n+    if (enable) {\n+        browser.tabs.onActivated.addListener(onTabActivatedListener);\n+        browser.tabs.onCreated.addListener(onTabCreatedListener);\n+        browser.tabs.onUpdated.addListener(onTabUpdatedListener);\n+    } else {\n+        if (browser.tab && browser.tab.onActivated.hasListener(onTabActivatedListener)) {\n+            browser.tab.onActivated.removeListener(onTabActivatedListener);\n+        }\n+        if (browser.tab && browser.tabs.onCreated.hasListener(onTabCreatedListener)) {\n+            browser.tabs.onCreated.removeListener(onTabCreatedListener);\n+        }\n+        if (browser.tab && browser.tabs.onUpdated.hasListener(onTabUpdatedListener)) {\n+            browser.tabs.onUpdated.remoneListener(onTabUpdatedListener);\n+        }\n+    }\n+}\n \n-browser.contextMenus.onClicked.addListener(function (info) {\n+function onContextMenusClicked (info) {\n     switch (info.menuItemId) {\n         case 'wallabagger-add-link':\n-            const url = typeof (info.linkUrl) === 'string' ? info.linkUrl : info.pageUrl;\n-            savePageToWallabag(url);\n-            break;\n-        case 'Unread-articles':\n-            GotoWallabag('unread');\n-            break;\n-        case 'Favorite-articles':\n-            GotoWallabag('starred');\n-            break;\n-        case 'Archived-articles':\n-            GotoWallabag('archive');\n-            break;\n-        case 'All-articles':\n-            GotoWallabag('all');\n+            if (typeof (info.linkUrl) === 'string') {\n+                savePageToWallabag(info.linkUrl, true);\n+            } else {\n+                savePageToWallabag(info.pageUrl, false);\n+            }\n             break;\n-        case 'Tag-list':\n-            GotoWallabag('tag');\n+        case 'unread':\n+        case 'starred':\n+        case 'archive':\n+        case 'all':\n+        case 'tag':\n+            GotoWallabag(info.menuItemId);\n             break;\n     }\n-});\n-\n-const GotoWallabag = (part) =>\n-    GetApi().then(api => browser.tabs.create({ url: `${api.data.Url}/${part}/list` }));\n+}\n \n-browser.commands.onCommand.addListener(function (command) {\n+function onCommandsCommand (command) {\n     if (command === 'wallabag-it') {\n-        browser.tabs.query({ 'active': true }, function (tabs) {\n+        browser.tabs.query({ 'active': true, 'currentWindow': true }, function (tabs) {\n             if (tabs[0] != null) {\n-                savePageToWallabag(tabs[0].url);\n+                savePageToWallabag(tabs[0].url, false);\n             }\n         });\n     }\n-});\n+}\n \n-GetApi().then(api => {\n-    api.resetDebug();\n-    if (api.data.AllowExistCheck) {\n-        browser.tabs.onActivated.addListener(function (activeInfo) {\n-            browser.browserAction.setIcon({ path: icon.default });\n-            const { tabId } = activeInfo;\n-            browser.tabs.get(tabId, function (tab) {\n-                checkExist(tab.url);\n-            });\n-        });\n+function postIfConnected (obj) {\n+    portConnected && Port.postMessage(obj);\n+}\n+function onPortMessage (msg) {\n+    try {\n+        switch (msg.request) {\n+            case 'save':\n+                savePageToWallabag(msg.tabUrl);\n+                break;\n+            case 'tags':\n+                if (!cache.check('allTags')) {\n+                    api.GetTags()\n+                            .then(data => {\n+                                postIfConnected({ response: 'tags', tags: data });\n+                                cache.set('allTags', data);\n+                            });\n+                } else {\n+                    postIfConnected({ response: 'tags', tags: cache.get('allTags') });\n+                }\n+                break;\n+            case 'saveTitle':\n+                if (msg.articleId !== -1) {\n+                    api.SaveTitle(msg.articleId, msg.title).then(data => {\n+                        postIfConnected({ response: 'title', title: data.title });\n+                        cache.set(msg.tabUrl, data);\n+                    });\n+                } else {\n+                    dirtyCacheSet(msg.tabUrl, {title: msg.title});\n+                }\n+                break;\n+            case 'deleteArticle':\n+                if (msg.articleId !== -1) {\n+                    api.DeleteArticle(msg.articleId).then(data => {\n+                        cache.clear(msg.tabUrl);\n+                    });\n+                } else {\n+                    dirtyCacheSet(msg.tabUrl, {deleted: true});\n+                }\n+                setIcon(icons.default);\n+                saveExistFlag(msg.tabUrl, existStates.notexists);\n+                break;\n+            case 'setup':\n+                postIfConnected({ response: 'setup', data: api.data });\n+                break;\n+            case 'setup-save':\n+                api.setsave(msg.data);\n+                postIfConnected({ response: 'setup-save', data: api.data });\n+                addExistCheckListeners(msg.data.AllowExistCheck);\n+                break;\n+            case 'setup-gettoken':\n+                api.setsave(msg.data);\n+                api.GetAppToken()\n+                        .then(a => {\n+                            api.save();\n+                            postIfConnected({ response: 'setup-gettoken', data: api.data, result: true });\n+                            if (!cache.check('allTags')) {\n+                                api.GetTags()\n+                                .then(data => { cache.set('allTags', data); });\n+                            }\n+                        })\n+                        .catch(a => {\n+                            postIfConnected({ response: 'setup-gettoken', data: api.data, result: false });\n+                        });\n+                break;\n+            case 'setup-checkurl':\n+                api.setsave(msg.data);\n+                api.CheckUrl()\n+                        .then(a => {\n+                            postIfConnected({ response: 'setup-checkurl', data: api.data, result: true });\n+                        })\n+                        .catch(a => {\n+                            api.clear();\n+                            // api.save();\n+                            postIfConnected({ response: 'setup-checkurl', data: api.data, result: false });\n+                        });\n+                break;\n+            case 'deleteArticleTag':\n+                if (msg.articleId !== -1) {\n+                    api.DeleteArticleTag(msg.articleId, msg.tagId).then(data => {\n+                        postIfConnected({ response: 'articleTags', tags: data.tags });\n+                        cache.set(msg.tabUrl, data);\n+                    });\n+                } else {\n+                    dirtyCacheSet(msg.tabUrl, {tagList: msg.tags});\n+                }\n+                break;\n+            case 'saveTags':\n+                if (msg.articleId !== -1) {\n+                    api.SaveTags(msg.articleId, msg.tags).then(data => {\n+                        postIfConnected({ response: 'articleTags', tags: data.tags });\n+                        cache.set(msg.tabUrl, data);\n+                    });\n+                } else {\n+                    dirtyCacheSet(msg.tabUrl, {tagList: msg.tags});\n+                }\n+                break;\n+            case 'SaveStarred':\n+            case 'SaveArchived':\n+                if (msg.articleId !== -1) {\n+                    api[msg.request](msg.articleId, msg.value ? 1 : 0).then(data => {\n+                        postIfConnected({ response: 'action', value: {starred: data.is_starred === 1, archived: data.is_archived === 1} });\n+                        cache.set(msg.tabUrl, data);\n+                    });\n+                } else {\n+                    dirtyCacheSet(msg.tabUrl, (msg.request === 'SaveStarred') ? {is_starred: msg.value ? 1 : 0} : {is_archived: msg.value ? 1 : 0});\n+                }\n+                break;\n+            default: {\n+                console.log(`unknown request ${JSON.stringify(msg)}`);\n+            }\n+        }\n+    } catch (error) {\n+        setIcon(icons.bad);\n+        setTimeout(function () { setIcon(icons.default); }, 5000);\n+        postIfConnected({ response: 'error', error: error });\n+    }\n+}\n \n-        browser.tabs.onCreated.addListener(function (tab) {\n-            browser.browserAction.setIcon({ path: icon.default });\n-        });\n+function onRuntimeConnect (port) {\n+    Port = port;\n+    portConnected = true;\n \n-        browser.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {\n-            if (changeInfo.status === 'loading' && tab.active) {\n-                requestExists(tab.url);\n-            }\n-        });\n+    Port.onDisconnect.addListener(function () { portConnected = false; });\n+    Port.onMessage.addListener(onPortMessage);\n+}\n+\n+function addListeners () {\n+    browser.contextMenus.onClicked.addListener(onContextMenusClicked);\n+    browser.commands.onCommand.addListener(onCommandsCommand);","path":"wallabagger/js/background.js","position":416,"original_position":416,"commit_id":"b524f1b13b07f9a91e05cdd0b6d2c11ee4c768cc","original_commit_id":"b524f1b13b07f9a91e05cdd0b6d2c11ee4c768cc","user":{"login":"Simounet","id":582666,"avatar_url":"https://avatars2.githubusercontent.com/u/582666?v=3","gravatar_id":"","url":"https://api.github.com/users/Simounet","html_url":"https://github.com/Simounet","followers_url":"https://api.github.com/users/Simounet/followers","following_url":"https://api.github.com/users/Simounet/following{/other_user}","gists_url":"https://api.github.com/users/Simounet/gists{/gist_id}","starred_url":"https://api.github.com/users/Simounet/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Simounet/subscriptions","organizations_url":"https://api.github.com/users/Simounet/orgs","repos_url":"https://api.github.com/users/Simounet/repos","events_url":"https://api.github.com/users/Simounet/events{/privacy}","received_events_url":"https://api.github.com/users/Simounet/received_events","type":"User","site_admin":false},"body":"I'm sorry but I don't get what's the difference between this custom handling and the basic one with `_execute_browser_action`? It seems to me that both doing the same thing.","created_at":"2017-03-27T21:47:43Z","updated_at":"2017-03-27T21:47:44Z","html_url":"https://github.com/wallabag/wallabagger/pull/65#discussion_r108288379","pull_request_url":"https://api.github.com/repos/wallabag/wallabagger/pulls/65","_links":{"self":{"href":"https://api.github.com/repos/wallabag/wallabagger/pulls/comments/108288379"},"html":{"href":"https://github.com/wallabag/wallabagger/pull/65#discussion_r108288379"},"pull_request":{"href":"https://api.github.com/repos/wallabag/wallabagger/pulls/65"}}},"pull_request":{"url":"https://api.github.com/repos/wallabag/wallabagger/pulls/65","id":110387403,"html_url":"https://github.com/wallabag/wallabagger/pull/65","diff_url":"https://github.com/wallabag/wallabagger/pull/65.diff","patch_url":"https://github.com/wallabag/wallabagger/pull/65.patch","issue_url":"https://api.github.com/repos/wallabag/wallabagger/issues/65","number":65,"state":"open","locked":false,"title":"v1.4 beta !","user":{"login":"Rurik19","id":1955806,"avatar_url":"https://avatars2.githubusercontent.com/u/1955806?v=3","gravatar_id":"","url":"https://api.github.com/users/Rurik19","html_url":"https://github.com/Rurik19","followers_url":"https://api.github.com/users/Rurik19/followers","following_url":"https://api.github.com/users/Rurik19/following{/other_user}","gists_url":"https://api.github.com/users/Rurik19/gists{/gist_id}","starred_url":"https://api.github.com/users/Rurik19/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Rurik19/subscriptions","organizations_url":"https://api.github.com/users/Rurik19/orgs","repos_url":"https://api.github.com/users/Rurik19/repos","events_url":"https://api.github.com/users/Rurik19/events{/privacy}","received_events_url":"https://api.github.com/users/Rurik19/received_events","type":"User","site_admin":false},"body":"This PR solves a lot of issues, it improves users workflow by removing all api calls from interface to async backgroud. I think all issues authors should test it before release.\r\nIssues solved:\r\n#27 #28 #48 #49 #52 #59 #62 #63 ","created_at":"2017-03-13T11:46:11Z","updated_at":"2017-03-27T21:47:44Z","closed_at":null,"merged_at":null,"merge_commit_sha":"7dee376449836e4e5e51178c424f9fe9ab0fd391","assignee":{"login":"Rurik19","id":1955806,"avatar_url":"https://avatars2.githubusercontent.com/u/1955806?v=3","gravatar_id":"","url":"https://api.github.com/users/Rurik19","html_url":"https://github.com/Rurik19","followers_url":"https://api.github.com/users/Rurik19/followers","following_url":"https://api.github.com/users/Rurik19/following{/other_user}","gists_url":"https://api.github.com/users/Rurik19/gists{/gist_id}","starred_url":"https://api.github.com/users/Rurik19/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Rurik19/subscriptions","organizations_url":"https://api.github.com/users/Rurik19/orgs","repos_url":"https://api.github.com/users/Rurik19/repos","events_url":"https://api.github.com/users/Rurik19/events{/privacy}","received_events_url":"https://api.github.com/users/Rurik19/received_events","type":"User","site_admin":false},"assignees":[{"login":"Rurik19","id":1955806,"avatar_url":"https://avatars2.githubusercontent.com/u/1955806?v=3","gravatar_id":"","url":"https://api.github.com/users/Rurik19","html_url":"https://github.com/Rurik19","followers_url":"https://api.github.com/users/Rurik19/followers","following_url":"https://api.github.com/users/Rurik19/following{/other_user}","gists_url":"https://api.github.com/users/Rurik19/gists{/gist_id}","starred_url":"https://api.github.com/users/Rurik19/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Rurik19/subscriptions","organizations_url":"https://api.github.com/users/Rurik19/orgs","repos_url":"https://api.github.com/users/Rurik19/repos","events_url":"https://api.github.com/users/Rurik19/events{/privacy}","received_events_url":"https://api.github.com/users/Rurik19/received_events","type":"User","site_admin":false}],"milestone":null,"commits_url":"https://api.github.com/repos/wallabag/wallabagger/pulls/65/commits","review_comments_url":"https://api.github.com/repos/wallabag/wallabagger/pulls/65/comments","review_comment_url":"https://api.github.com/repos/wallabag/wallabagger/pulls/comments{/number}","comments_url":"https://api.github.com/repos/wallabag/wallabagger/issues/65/comments","statuses_url":"https://api.github.com/repos/wallabag/wallabagger/statuses/b524f1b13b07f9a91e05cdd0b6d2c11ee4c768cc","head":{"label":"wallabag:background-api","ref":"background-api","sha":"b524f1b13b07f9a91e05cdd0b6d2c11ee4c768cc","user":{"login":"wallabag","id":4143872,"avatar_url":"https://avatars0.githubusercontent.com/u/4143872?v=3","gravatar_id":"","url":"https://api.github.com/users/wallabag","html_url":"https://github.com/wallabag","followers_url":"https://api.github.com/users/wallabag/followers","following_url":"https://api.github.com/users/wallabag/following{/other_user}","gists_url":"https://api.github.com/users/wallabag/gists{/gist_id}","starred_url":"https://api.github.com/users/wallabag/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wallabag/subscriptions","organizations_url":"https://api.github.com/users/wallabag/orgs","repos_url":"https://api.github.com/users/wallabag/repos","events_url":"https://api.github.com/users/wallabag/events{/privacy}","received_events_url":"https://api.github.com/users/wallabag/received_events","type":"Organization","site_admin":false},"repo":{"id":59825410,"name":"wallabagger","full_name":"wallabag/wallabagger","owner":{"login":"wallabag","id":4143872,"avatar_url":"https://avatars0.githubusercontent.com/u/4143872?v=3","gravatar_id":"","url":"https://api.github.com/users/wallabag","html_url":"https://github.com/wallabag","followers_url":"https://api.github.com/users/wallabag/followers","following_url":"https://api.github.com/users/wallabag/following{/other_user}","gists_url":"https://api.github.com/users/wallabag/gists{/gist_id}","starred_url":"https://api.github.com/users/wallabag/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wallabag/subscriptions","organizations_url":"https://api.github.com/users/wallabag/orgs","repos_url":"https://api.github.com/users/wallabag/repos","events_url":"https://api.github.com/users/wallabag/events{/privacy}","received_events_url":"https://api.github.com/users/wallabag/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/wallabag/wallabagger","description":"Chrome / Firefox plugin for wallabag v2.","fork":false,"url":"https://api.github.com/repos/wallabag/wallabagger","forks_url":"https://api.github.com/repos/wallabag/wallabagger/forks","keys_url":"https://api.github.com/repos/wallabag/wallabagger/keys{/key_id}","collaborators_url":"https://api.github.com/repos/wallabag/wallabagger/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/wallabag/wallabagger/teams","hooks_url":"https://api.github.com/repos/wallabag/wallabagger/hooks","issue_events_url":"https://api.github.com/repos/wallabag/wallabagger/issues/events{/number}","events_url":"https://api.github.com/repos/wallabag/wallabagger/events","assignees_url":"https://api.github.com/repos/wallabag/wallabagger/assignees{/user}","branches_url":"https://api.github.com/repos/wallabag/wallabagger/branches{/branch}","tags_url":"https://api.github.com/repos/wallabag/wallabagger/tags","blobs_url":"https://api.github.com/repos/wallabag/wallabagger/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/wallabag/wallabagger/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/wallabag/wallabagger/git/refs{/sha}","trees_url":"https://api.github.com/repos/wallabag/wallabagger/git/trees{/sha}","statuses_url":"https://api.github.com/repos/wallabag/wallabagger/statuses/{sha}","languages_url":"https://api.github.com/repos/wallabag/wallabagger/languages","stargazers_url":"https://api.github.com/repos/wallabag/wallabagger/stargazers","contributors_url":"https://api.github.com/repos/wallabag/wallabagger/contributors","subscribers_url":"https://api.github.com/repos/wallabag/wallabagger/subscribers","subscription_url":"https://api.github.com/repos/wallabag/wallabagger/subscription","commits_url":"https://api.github.com/repos/wallabag/wallabagger/commits{/sha}","git_commits_url":"https://api.github.com/repos/wallabag/wallabagger/git/commits{/sha}","comments_url":"https://api.github.com/repos/wallabag/wallabagger/comments{/number}","issue_comment_url":"https://api.github.com/repos/wallabag/wallabagger/issues/comments{/number}","contents_url":"https://api.github.com/repos/wallabag/wallabagger/contents/{+path}","compare_url":"https://api.github.com/repos/wallabag/wallabagger/compare/{base}...{head}","merges_url":"https://api.github.com/repos/wallabag/wallabagger/merges","archive_url":"https://api.github.com/repos/wallabag/wallabagger/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/wallabag/wallabagger/downloads","issues_url":"https://api.github.com/repos/wallabag/wallabagger/issues{/number}","pulls_url":"https://api.github.com/repos/wallabag/wallabagger/pulls{/number}","milestones_url":"https://api.github.com/repos/wallabag/wallabagger/milestones{/number}","notifications_url":"https://api.github.com/repos/wallabag/wallabagger/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/wallabag/wallabagger/labels{/name}","releases_url":"https://api.github.com/repos/wallabag/wallabagger/releases{/id}","deployments_url":"https://api.github.com/repos/wallabag/wallabagger/deployments","created_at":"2016-05-27T10:08:49Z","updated_at":"2017-03-24T22:41:09Z","pushed_at":"2017-03-21T05:17:55Z","git_url":"git://github.com/wallabag/wallabagger.git","ssh_url":"git@github.com:wallabag/wallabagger.git","clone_url":"https://github.com/wallabag/wallabagger.git","svn_url":"https://github.com/wallabag/wallabagger","homepage":"http://wallabag.github.io/wallabagger/","size":3744,"stargazers_count":31,"watchers_count":31,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":4,"mirror_url":null,"open_issues_count":20,"forks":4,"open_issues":20,"watchers":31,"default_branch":"master"}},"base":{"label":"wallabag:master","ref":"master","sha":"d0ed272e24915b0ac7c780bb736bd324381fc287","user":{"login":"wallabag","id":4143872,"avatar_url":"https://avatars0.githubusercontent.com/u/4143872?v=3","gravatar_id":"","url":"https://api.github.com/users/wallabag","html_url":"https://github.com/wallabag","followers_url":"https://api.github.com/users/wallabag/followers","following_url":"https://api.github.com/users/wallabag/following{/other_user}","gists_url":"https://api.github.com/users/wallabag/gists{/gist_id}","starred_url":"https://api.github.com/users/wallabag/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wallabag/subscriptions","organizations_url":"https://api.github.com/users/wallabag/orgs","repos_url":"https://api.github.com/users/wallabag/repos","events_url":"https://api.github.com/users/wallabag/events{/privacy}","received_events_url":"https://api.github.com/users/wallabag/received_events","type":"Organization","site_admin":false},"repo":{"id":59825410,"name":"wallabagger","full_name":"wallabag/wallabagger","owner":{"login":"wallabag","id":4143872,"avatar_url":"https://avatars0.githubusercontent.com/u/4143872?v=3","gravatar_id":"","url":"https://api.github.com/users/wallabag","html_url":"https://github.com/wallabag","followers_url":"https://api.github.com/users/wallabag/followers","following_url":"https://api.github.com/users/wallabag/following{/other_user}","gists_url":"https://api.github.com/users/wallabag/gists{/gist_id}","starred_url":"https://api.github.com/users/wallabag/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/wallabag/subscriptions","organizations_url":"https://api.github.com/users/wallabag/orgs","repos_url":"https://api.github.com/users/wallabag/repos","events_url":"https://api.github.com/users/wallabag/events{/privacy}","received_events_url":"https://api.github.com/users/wallabag/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/wallabag/wallabagger","description":"Chrome / Firefox plugin for wallabag v2.","fork":false,"url":"https://api.github.com/repos/wallabag/wallabagger","forks_url":"https://api.github.com/repos/wallabag/wallabagger/forks","keys_url":"https://api.github.com/repos/wallabag/wallabagger/keys{/key_id}","collaborators_url":"https://api.github.com/repos/wallabag/wallabagger/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/wallabag/wallabagger/teams","hooks_url":"https://api.github.com/repos/wallabag/wallabagger/hooks","issue_events_url":"https://api.github.com/repos/wallabag/wallabagger/issues/events{/number}","events_url":"https://api.github.com/repos/wallabag/wallabagger/events","assignees_url":"https://api.github.com/repos/wallabag/wallabagger/assignees{/user}","branches_url":"https://api.github.com/repos/wallabag/wallabagger/branches{/branch}","tags_url":"https://api.github.com/repos/wallabag/wallabagger/tags","blobs_url":"https://api.github.com/repos/wallabag/wallabagger/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/wallabag/wallabagger/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/wallabag/wallabagger/git/refs{/sha}","trees_url":"https://api.github.com/repos/wallabag/wallabagger/git/trees{/sha}","statuses_url":"https://api.github.com/repos/wallabag/wallabagger/statuses/{sha}","languages_url":"https://api.github.com/repos/wallabag/wallabagger/languages","stargazers_url":"https://api.github.com/repos/wallabag/wallabagger/stargazers","contributors_url":"https://api.github.com/repos/wallabag/wallabagger/contributors","subscribers_url":"https://api.github.com/repos/wallabag/wallabagger/subscribers","subscription_url":"https://api.github.com/repos/wallabag/wallabagger/subscription","commits_url":"https://api.github.com/repos/wallabag/wallabagger/commits{/sha}","git_commits_url":"https://api.github.com/repos/wallabag/wallabagger/git/commits{/sha}","comments_url":"https://api.github.com/repos/wallabag/wallabagger/comments{/number}","issue_comment_url":"https://api.github.com/repos/wallabag/wallabagger/issues/comments{/number}","contents_url":"https://api.github.com/repos/wallabag/wallabagger/contents/{+path}","compare_url":"https://api.github.com/repos/wallabag/wallabagger/compare/{base}...{head}","merges_url":"https://api.github.com/repos/wallabag/wallabagger/merges","archive_url":"https://api.github.com/repos/wallabag/wallabagger/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/wallabag/wallabagger/downloads","issues_url":"https://api.github.com/repos/wallabag/wallabagger/issues{/number}","pulls_url":"https://api.github.com/repos/wallabag/wallabagger/pulls{/number}","milestones_url":"https://api.github.com/repos/wallabag/wallabagger/milestones{/number}","notifications_url":"https://api.github.com/repos/wallabag/wallabagger/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/wallabag/wallabagger/labels{/name}","releases_url":"https://api.github.com/repos/wallabag/wallabagger/releases{/id}","deployments_url":"https://api.github.com/repos/wallabag/wallabagger/deployments","created_at":"2016-05-27T10:08:49Z","updated_at":"2017-03-24T22:41:09Z","pushed_at":"2017-03-21T05:17:55Z","git_url":"git://github.com/wallabag/wallabagger.git","ssh_url":"git@github.com:wallabag/wallabagger.git","clone_url":"https://github.com/wallabag/wallabagger.git","svn_url":"https://github.com/wallabag/wallabagger","homepage":"http://wallabag.github.io/wallabagger/","size":3744,"stargazers_count":31,"watchers_count":31,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":4,"mirror_url":null,"open_issues_count":20,"forks":4,"open_issues":20,"watchers":31,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/wallabag/wallabagger/pulls/65"},"html":{"href":"https://github.com/wallabag/wallabagger/pull/65"},"issue":{"href":"https://api.github.com/repos/wallabag/wallabagger/issues/65"},"comments":{"href":"https://api.github.com/repos/wallabag/wallabagger/issues/65/comments"},"review_comments":{"href":"https://api.github.com/repos/wallabag/wallabagger/pulls/65/comments"},"review_comment":{"href":"https://api.github.com/repos/wallabag/wallabagger/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/wallabag/wallabagger/pulls/65/commits"},"statuses":{"href":"https://api.github.com/repos/wallabag/wallabagger/statuses/b524f1b13b07f9a91e05cdd0b6d2c11ee4c768cc"}}}}
{"actor":{"display_login":"Simounet"}}