{"action":"created","comment":{"url":"https://api.github.com/repos/shaarli/Shaarli/pulls/comments/66607487","id":66607487,"diff_hunk":"@@ -0,0 +1,820 @@\n+<?php\n+\n+class Account {\n+    public $name = \"\";\n+    public $num = 0;\n+    public $version = 0;\n+    \n+    public function __construct($name,$num,$version) {\n+        $this->name = $name;\n+        $this->num = $num;\n+        $this->version = $version;\n+    }\n+}\n+\n+class Api\n+{\n+    const LINK_DATE_DAY = 'Ymd';\n+\n+    const PARAM_OBJECT = 'object';\n+    const PARAM_METHOD = 'method';\n+    \n+    const O_ACCOUNT = 'account';\n+    const O_LINKS = 'links';\n+    const O_LINK = 'link';\n+    const O_TAGS = 'tags';\n+    const O_HISTORY = 'history';\n+    \n+    const M_SEARCH = 'search';\n+    const M_UPDATED = 'updated';\n+    const M_DELETED = 'deleted';\n+    \n+    const M_SEARCH_SEARCH_TERM = 'searchterm';\n+    const M_SEARCH_SEARCH_TAGS = 'searchtags';\n+    const M_SEARCH_KEY = 'key';\n+    \n+    const PARAM_START_DATE='start_date';\n+    const PARAM_END_DATE='end_date';\n+    const PARAM_PER_PAGE = 'per_page';\n+    const PARAM_TYPE='type';\n+    \n+    const LOGIN_ERROR_UNKNOWN = 'LOGIN_ERROR_UNKNOWN';\n+    const LOGIN_ERROR_DATE_NOT_FOUND = 'LOGIN_ERROR_DATE_NOT_FOUND';\n+    const LOGIN_ERROR_CLIENT_SERVER_TIME_SYNC = 'LOGIN_ERROR_CLIENT_SERVER_TIME_SYNC';\n+    const LOGIN_ERROR_TOKEN_VERIFICATION_FAILED = 'LOGIN_ERROR_TOKEN_VERIFICATION_FAILED';\n+\n+    const POST_EDIT_ERROR_URL_EMPTY = 'POST_EDIT_ERROR_URL_EMPTY';\n+    const POST_EDIT_ERROR_LINK_NOT_FOUND = 'POST_EDIT_ERROR_LINK_NOT_FOUND';\n+    const POST_EDIT_ERROR_DUPLICATE_URL = 'POST_EDIT_ERROR_DUPLICATE_URL';\n+    \n+    const MAX_TIMESTAMP_CLIENT_SERVER_DIFF = 5;\n+    \n+    const VALUE_ALL = 'all';\n+    \n+    private $loggedin; // Is the used logged in ? (used to filter private links)\n+    private $allowed_methods = array('get', 'post', 'delete');\n+    private $linkdb;\n+    private $linkhistorydb;\n+    \n+    /**\n+     * Creates a new Api\n+     *\n+     */\n+    public function __construct()\n+    {\n+        $this->getLoggedIn();\n+    \n+        $method = $this->getMethod();\n+        if ($method === null) {\n+            exit;\n+        }\n+        $this->linkdb = new LinkDB(\n+            $GLOBALS['config']['DATASTORE'],\n+            $this->loggedin,\n+            $GLOBALS['config']['HIDE_PUBLIC_LINKS'],\n+            $GLOBALS['redirector']\n+        );\n+        $this->linkhistorydb = new LinkHistoryDB(\n+            $GLOBALS['config']['DATASTORE_HISTORY'],\n+            $this->loggedin\n+        );\n+        $this->$method();\n+    }\n+    \n+    /**\n+     * Identify request method\n+     *\n+     * @return method allowed (get, post, delete) or 400 or 405\n+     */    \n+    private function getMethod()\n+    {\n+        if (isset($_SERVER['REQUEST_METHOD']) === false) {\n+            $this->send(400);\n+            return null;\n+        }\n+    \n+        $method = strtolower($_SERVER['REQUEST_METHOD']);\n+    \n+        if (in_array($method, $this->allowed_methods) === false) {\n+            $this->send(405);\n+            return null;\n+        }\n+    \n+        return $method;\n+    }\n+    \n+    /**\n+     * Check if a parameter is in the request\n+     *\n+     * @param string $name parameter to check\n+     * @param string $table request. Optionnal : if null check get request\n+     *\n+     * @return boolean\n+     */\n+    private function checkParam($name, $table = null)\n+    {\n+        if ($table === null) {\n+            $table = $_GET;\n+        }\n+        return (isset($table[$name]) === true\n+                &&\n+                is_string($table[$name]) === true\n+                &&\n+                empty($table[$name]) === false\n+                );\n+    }\n+    \n+    /**\n+     * Check if the token provided is legitimate\n+     *\n+     * See https://www.ida.liu.se/~TDP024/labs/hmacarticle.pdf for method explanation.\n+     *\n+     * @return boolean\n+     */\n+    private function getLoggedIn()\n+    {\n+        $this->loggedin = false;\n+    \n+        $date_request = null;\n+        $authorization_client = null;\n+        $android_version = null;\n+    \n+        $headers = apache_request_headers();\n+        foreach ($headers as $header => $value) {\n+            if ($header==='Authorization') $authorization_client=$value;\n+            if ($header==='Date') $date_request=strtotime($value);\n+            if ($header==='X-SHAARLI-ANDROID-VERSION') $android_version=$value;\n+        }\n+    \n+        if (empty($date_request) && empty($_SERVER['HTTP_DATE'])) {\n+            $this->send(403, Api::LOGIN_ERROR_DATE_NOT_FOUND); \n+            exit;\n+        } elseif (empty($date_request)) {\n+            $date_request = strtotime($_SERVER['HTTP_DATE']);\n+        }\n+\n+        if (empty($authorization_client) && empty($_SERVER['REMOTE_USER'])) {\n+            $this->send(403, Api::LOGIN_ERROR_TOKEN_VERIFICATION_FAILED); \n+            exit;\n+        } elseif (empty($authorization_client)) {\n+            $authorization_client = $_SERVER['REMOTE_USER'];\n+        }\n+        \n+        if (empty($android_version) && isset($_SERVER['X-SHAARLI-ANDROID-VERSION'])) {\n+            $android_version = $_SERVER['X-SHAARLI-ANDROID-VERSION'];\n+        } \n+      \n+        $date_server = time();\n+        $seconds = $date_server - $date_request;\n+    \n+        if ($seconds > Api::MAX_TIMESTAMP_CLIENT_SERVER_DIFF) {\n+            $this->send(403, Api::LOGIN_ERROR_CLIENT_SERVER_TIME_SYNC);\n+            exit;\n+        }\n+        \n+        if (empty($authorization_client)) {\n+            $this->send(403, Api::LOGIN_ERROR_TOKEN_VERIFICATION_FAILED);\n+            exit;\n+        }\n+                \n+        $authorization_client_array = explode(\":\", $authorization_client);\n+        $authorization_client_name = $authorization_client_array[0];\n+        $authorization_client_hash = $authorization_client_array[1];\n+    \n+        $calculated_hash = $_SERVER['REQUEST_METHOD'].\"\\n\".$_SERVER['CONTENT_TYPE']\n+            .\"\\n\".$_SERVER['HTTP_DATE'].\"\\n\".$_SERVER['QUERY_STRING'];\n+    \n+        if (hash_hmac('sha256', $GLOBALS['api_secret_key'], $calculated_hash) \n+                !== $authorization_client_hash) {\n+            $this->send(403, Api::LOGIN_ERROR_TOKEN_VERIFICATION_FAILED); \n+            exit;\n+        }\n+    \n+        $this->loggedin = true;\n+    }\n+    \n+    /**\n+     * Router for the GET request\n+     *\n+     */\n+    private function get()\n+    {\n+        if ($this->checkParam(Api::PARAM_OBJECT) === true) {\n+            switch ($_GET[Api::PARAM_OBJECT]) {\n+                case Api::O_ACCOUNT:\n+                    $this->checkaccount();\n+                    break;\n+                case Api::O_LINKS:\n+                    if ($this->checkParam(Api::PARAM_METHOD) === true) {\n+                        switch ($_GET[Api::PARAM_METHOD]) {\n+                            case Api::M_SEARCH:\n+                                if ($this->checkParam(LinkFilter::$FILTER_DAY) === true) {\n+                                    $this->getLinksByDay($_GET[LinkFilter::$FILTER_DAY]);\n+                                } else {\n+                                    $this->search();\n+                                }\n+                                break;\n+                            case Api::M_UPDATED:\n+                                $this->getLinksUpdated();\n+                                break;\n+                            case Api::M_DELETED:\n+                                $this->getLinksDeleted();\n+                                break;\n+                            default:\n+                                $this->send(400, 'Bad Request');\n+                                return;\n+                        }\n+                    } else {\n+                        $this->send(400, 'Bad Request');\n+                        return;\n+                    }\n+                    break;\n+                case Api::O_TAGS:\n+                    $this->getTags();\n+                    break;\n+                case Api::O_LINK:\n+                    if ($this->checkParam(Api::PARAM_METHOD) === true) {\n+                        switch ($_GET[Api::PARAM_METHOD]) {\n+                            case Api::M_SEARCH:\n+                                if ($this->checkParam(Api::M_SEARCH_KEY) === true) {\n+                                    $this->getLinkByKey($_GET[Api::M_SEARCH_KEY]);\n+                                } else {\n+                                    $this->send(400, 'Bad Request');\n+                                    return;\n+                                }\n+                                break;\n+                            case Api::M_DELETED:\n+                                if ($this->checkParam(Api::M_SEARCH_KEY) === true) {\n+                                    $this->getLinkDeletedByKey($_GET[Api::M_SEARCH_KEY]);\n+                                } else {\n+                                    $this->send(400, 'Bad Request');\n+                                    return;\n+                                }\n+                                break;\n+                        }\n+                    } else {\n+                        $this->send(400, 'Bad Request');\n+                        return;\n+                    }\n+                    break;\n+                case Api::O_HISTORY:\n+                    $type='';\n+                    if (!empty($_GET[Api::PARAM_TYPE])) {\n+                        $type=$_GET[Api::PARAM_TYPE];\n+                    }\n+                    $this->getHistory($type);\n+                    break;\n+                default:\n+                    $this->send(400, 'Bad Request');\n+                    return;\n+            }\n+        } else {\n+            $this->send(400, 'Bad Request');\n+            return;\n+        }\n+        \n+    }\n+    \n+    /**\n+     * GET Method : check is the account is legitimate\n+     * \n+     * @url param : do=api\n+     * @url param : object=account\n+     * \n+     * @return JSON Object (name = Name of the account, num = number of links saved, \n+     * version = version of Shaarli)\n+     */\n+    private function checkAccount(){\n+        $account = new Account($GLOBALS['title'],\n+                count($this->linkdb), shaarli_version);\n+        $this->send(200, $account);\n+    }\n+    \n+    /**\n+     * GET Method : retrieve all tags\n+     * \n+     * @url param : do=api\n+     * @url param : object=tags\n+     * \n+     * @return JSON Array List of tags (title = name of the tag, count = occurences of the tag)\n+     *  sort by title\n+     */\n+    private function getTags()\n+    {\n+        $tags= $this->linkdb->allTags();\n+        $maxcount=0; foreach($tags as $key=>$value) $maxcount=max($maxcount,$value);\n+        ksort($tags);\n+        $tagList=array();\n+        foreach($tags as $key=>$value)\n+        {\n+            $tag = array(\n+                    'title' => $key,\n+                    'count' => $value\n+            );\n+            $tagList[] = $tag;\n+        }\n+        $this->send(200, $tagList);\n+        \n+    }\n+    \n+    /**\n+     * GET Method : get history of modification on links\n+     * \n+     * @url param : do=api\n+     * @url param : object=history\n+     * @url param : type=DELETED or UPDATED (optionnal, default = both)\n+     * @url param : startdate (optionnal). Format: YYYYMMDD_HHMMSS or YYYYMMDD.\n+     * @url param : enddate (optionnal). Format: YYYYMMDD_HHMMSS or YYYYMMDD.\n+     * @url param : per_page. page size (optionnal, default = 2)\n+     * @url param : page. (optionnal, default = 1)\n+     * \n+     * @return JSON Array List of history (linkdate = linkdate of the link, \n+     * editdate = edit date of the link, type = type of action\n+     * on the link (e.g. DELETED, UPDATED))\n+     */\n+    private function getHistory($type)\n+    {\n+        $filtered = $this->linkhistorydb->filterSearch($type);\n+        $filtered = $this->filterByDate($filtered,'editdate');\n+        $filtered = $this->filterByPage($filtered);\n+        $this->send(200, $filtered); \n+    }\n+    \n+    /**\n+     * GET Method : get links updated\n+     * \n+     * @url param : do=api\n+     * @url param : object=links\n+     * @url param : method=updated\n+     * @url param : startdate (optionnal). Format: YYYYMMDD_HHMMSS or YYYYMMDD.\n+     * @url param : enddate (optionnal). Format: YYYYMMDD_HHMMSS or YYYYMMDD.\n+     * @url param : per_page. page size (optionnal, default = 2)\n+     * @url param : page. (optionnal, default = 1)\n+     * \n+     * @return JSON Array List of links (linkdate, url, title, description, private, tags)\n+     */\n+    private function getLinksUpdated()\n+    {\n+        $filtered = $this->linkhistorydb->filterSearch('UPDATED');\n+        $filtered = $this->filterByDate($filtered,'editdate');\n+        $filtered = $this->filterByPage($filtered);\n+\n+        $dateLastEdited='';\n+        $links = array();\n+        foreach ($filtered as $l) {\n+            $key = $l['linkdate'];\n+            $link = isset($this->linkdb[$key]) === true ? $this->linkdb[$key] : false;\n+            if ($link !== false) {\n+                if (empty($dateLastEdited)) $dateLastEdited=$l['editdate'];\n+                $links[]=$link;\n+            }\n+        }\n+        \n+        $headers = array();\n+        $headers = $this->add_header($headers, 'X-DATE-LAST-EDITED', $dateLastEdited);\n+       \n+        $this->send(200, $links, $headers);\n+    }\n+    \n+    \n+    /**\n+     * GET Method : get links deleted\n+     * \n+     * @url param : do=api\n+     * @url param : object=links\n+     * @url param : method=deleted\n+     * @url param : startdate (optionnal). Format: YYYYMMDD_HHMMSS or YYYYMMDD.\n+     * @url param : enddate (optionnal). Format: YYYYMMDD_HHMMSS or YYYYMMDD.\n+     * @url param : per_page. page size (optionnal, default = 2)\n+     * @url param : page. (optionnal, default = 1)\n+     * \n+     * @return JSON Array List of deleted links (linkdate, editdate = edit date of the link)\n+     */\n+    private function getLinksDeleted(){\n+        $filtered = $this->linkhistorydb->filterSearch('DELETED');\n+        $filtered = $this->filterByDate($filtered,'editdate');\n+        $filtered = $this->filterByPage($filtered);\n+        foreach ($filtered as &$l) {\n+            unset($l['type']);\n+        }\n+        $this->send(200, $filtered);\n+    }\n+    \n+\n+    /**\n+     * GET Method : get link deleted by linkdate\n+     * \n+     * @url param : do=api\n+     * @url param : object=link\n+     * @url param : method=deleted\n+     * @url param : key. Format : YYYYMMDD_HHMMSS.\n+     * \n+     * @return JSON Object (linkdate, editdate = edit date of the link)\n+     *  or a 404 error\n+     */\n+    private function getLinkDeletedByKey($key)\n+    {\n+        $link = isset($this->linkhistorydb[$key]) === true ? $this->linkhistorydb[$key] : false;\n+        if ($link === false) {\n+            $this->send(404, 'Not Found');\n+            return;\n+        }\n+        unset($link['type']);\n+        $this->send(200, $link);\n+    }\n+    \n+    \n+    /**\n+     * GET Method : retrieve links, optionnaly filter by term or tags \n+     * \n+     * @url param : do=api\n+     * @url param : object=links\n+     * @url param : method=search\n+     * @url param : searchterm (optionnal)\n+     * @url param : searchtags (optionnal)\n+     * @url param : startdate (optionnal). Format: YYYYMMDD_HHMMSS or YYYYMMDD.\n+     * @url param : enddate (optionnal). Format: YYYYMMDD_HHMMSS or YYYYMMDD.\n+     * @url param : per_page. page size (optionnal, default = 2)\n+     * @url param : page. (optionnal, default = 1)\n+     * \n+     * @return JSON Array List of links (linkdate, url, title, description, private, tags)\n+     */\n+    private function search()\n+    {\n+        $filtered = $this->linkdb->filterSearch($_GET, false, false);\n+        $filtered = $this->filterByDate($filtered,'linkdate');\n+        $filtered = $this->filterByPage($filtered);\n+        $this->send(200, $filtered);\n+    }\n+    \n+    /**\n+     * GET Method : Returns the list of articles for a given day.\n+     *\n+     * @url param : do=api\n+     * @url param : object=links\n+     * @url param : method=search\n+     * @url param : FILTER_DAY day to filter. Format: YYYYMMDD.\n+     * @url param : per_page. page size (optionnal, default = 2)\n+     * @url param : page. (optionnal, default = 1)\n+     *\n+     * @return JSON Array List of links (linkdate, url, title, description, private, tags)\n+     *  or a 400 error\n+     */\n+    private function getLinksByDay($day)\n+    {\n+        try {\n+            $links = $this->linkdb->filterDay($day);\n+            $filtered = $this->filterByPage($links);\n+            $this->send(200, $filtered);\n+        } catch (Exception $e) {\n+            $this->send(400, 'Bad Request');\n+            return;\n+        }\n+    }\n+    \n+    /**\n+     * GET Method : get link by linkdate\n+     * \n+     * @url param : do=api\n+     * @url param : object=link\n+     * @url param : method=search\n+     * @url param : key. Format : YYYYMMDD_HHMMSS.\n+     * \n+     * @return JSON Object (linkdate, url, title, description, private, tags)\n+     *  or a 404 error\n+     */\n+    private function getLinkByKey($key)\n+    {\n+        $link = isset($this->linkdb[$key]) === true ? $this->linkdb[$key] : false;\n+        if ($link === false) {\n+            $this->send(404, 'Not Found');\n+            return;\n+        }\n+        $this->send(200, $link);\n+    }\n+    \n+    /**\n+     * filter by date\n+     *\n+     * @param string $linksToDisplay links to filter\n+     * @param string $field field use to filter (e.g. linkdate, date...)\n+     * \n+     * @url param : startdate (optionnal). Format: YYYYMMDD_HHMMSS or YYYYMMDD.\n+     * @url param : enddate (optionnal). Format: YYYYMMDD_HHMMSS or YYYYMMDD.\n+     * \n+     * @return JSON Array List filtered or whole array list if no date provided\n+     */\n+    private function filterByDate($linksToDisplay,$field)\n+    {\n+        if (empty($_GET[Api::PARAM_START_DATE]) && empty($_GET[Api::PARAM_END_DATE])) {\n+            return $linksToDisplay;\n+        }  \n+                \n+        $start = null;\n+        if (!empty($_GET[Api::PARAM_START_DATE])) ","path":"application/Api.php","position":514,"original_position":514,"commit_id":"2c6ed818e28f18063833b4f9ffd4188f5635330d","original_commit_id":"2c6ed818e28f18063833b4f9ffd4188f5635330d","user":{"login":"ArthurHoaro","id":1962678,"avatar_url":"https://avatars.githubusercontent.com/u/1962678?v=3","gravatar_id":"","url":"https://api.github.com/users/ArthurHoaro","html_url":"https://github.com/ArthurHoaro","followers_url":"https://api.github.com/users/ArthurHoaro/followers","following_url":"https://api.github.com/users/ArthurHoaro/following{/other_user}","gists_url":"https://api.github.com/users/ArthurHoaro/gists{/gist_id}","starred_url":"https://api.github.com/users/ArthurHoaro/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ArthurHoaro/subscriptions","organizations_url":"https://api.github.com/users/ArthurHoaro/orgs","repos_url":"https://api.github.com/users/ArthurHoaro/repos","events_url":"https://api.github.com/users/ArthurHoaro/events{/privacy}","received_events_url":"https://api.github.com/users/ArthurHoaro/received_events","type":"User","site_admin":false},"body":"brackets","created_at":"2016-06-10T12:51:31Z","updated_at":"2016-06-10T12:51:31Z","html_url":"https://github.com/shaarli/Shaarli/pull/586#discussion_r66607487","pull_request_url":"https://api.github.com/repos/shaarli/Shaarli/pulls/586","_links":{"self":{"href":"https://api.github.com/repos/shaarli/Shaarli/pulls/comments/66607487"},"html":{"href":"https://github.com/shaarli/Shaarli/pull/586#discussion_r66607487"},"pull_request":{"href":"https://api.github.com/repos/shaarli/Shaarli/pulls/586"}}},"pull_request":{"url":"https://api.github.com/repos/shaarli/Shaarli/pulls/586","id":72727280,"html_url":"https://github.com/shaarli/Shaarli/pull/586","diff_url":"https://github.com/shaarli/Shaarli/pull/586.diff","patch_url":"https://github.com/shaarli/Shaarli/pull/586.patch","issue_url":"https://api.github.com/repos/shaarli/Shaarli/issues/586","number":586,"state":"open","locked":false,"title":"Api Web Service","user":{"login":"toneiv","id":17043920,"avatar_url":"https://avatars.githubusercontent.com/u/17043920?v=3","gravatar_id":"","url":"https://api.github.com/users/toneiv","html_url":"https://github.com/toneiv","followers_url":"https://api.github.com/users/toneiv/followers","following_url":"https://api.github.com/users/toneiv/following{/other_user}","gists_url":"https://api.github.com/users/toneiv/gists{/gist_id}","starred_url":"https://api.github.com/users/toneiv/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/toneiv/subscriptions","organizations_url":"https://api.github.com/users/toneiv/orgs","repos_url":"https://api.github.com/users/toneiv/repos","events_url":"https://api.github.com/users/toneiv/events{/privacy}","received_events_url":"https://api.github.com/users/toneiv/received_events","type":"User","site_admin":false},"body":"Hello there,\r\n\r\nI have made a patch that allows to present the features of Shaarli in the form of Web Service. Minor changes were made in order to add a publishing date to a link and keep track of deleted links. \r\n\r\nAn Android application to view, add and manage links is being finalized and I plan to publish it to the Play Store soon.\r\n\r\nI'm not a PHP developer and I'm not at all familiar with Git. Thank you tell me if something needs to be add to complete this request.\r\n\r\nRegards, \r\nToneiv","created_at":"2016-06-06T15:19:30Z","updated_at":"2016-06-10T12:51:31Z","closed_at":null,"merged_at":null,"merge_commit_sha":"dfcde7a74f90197e54cd69b175b15cc66f87a2b1","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/shaarli/Shaarli/pulls/586/commits","review_comments_url":"https://api.github.com/repos/shaarli/Shaarli/pulls/586/comments","review_comment_url":"https://api.github.com/repos/shaarli/Shaarli/pulls/comments{/number}","comments_url":"https://api.github.com/repos/shaarli/Shaarli/issues/586/comments","statuses_url":"https://api.github.com/repos/shaarli/Shaarli/statuses/2c6ed818e28f18063833b4f9ffd4188f5635330d","head":{"label":"toneiv:ws-api","ref":"ws-api","sha":"2c6ed818e28f18063833b4f9ffd4188f5635330d","user":{"login":"toneiv","id":17043920,"avatar_url":"https://avatars.githubusercontent.com/u/17043920?v=3","gravatar_id":"","url":"https://api.github.com/users/toneiv","html_url":"https://github.com/toneiv","followers_url":"https://api.github.com/users/toneiv/followers","following_url":"https://api.github.com/users/toneiv/following{/other_user}","gists_url":"https://api.github.com/users/toneiv/gists{/gist_id}","starred_url":"https://api.github.com/users/toneiv/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/toneiv/subscriptions","organizations_url":"https://api.github.com/users/toneiv/orgs","repos_url":"https://api.github.com/users/toneiv/repos","events_url":"https://api.github.com/users/toneiv/events{/privacy}","received_events_url":"https://api.github.com/users/toneiv/received_events","type":"User","site_admin":false},"repo":{"id":51000925,"name":"Shaarli","full_name":"toneiv/Shaarli","owner":{"login":"toneiv","id":17043920,"avatar_url":"https://avatars.githubusercontent.com/u/17043920?v=3","gravatar_id":"","url":"https://api.github.com/users/toneiv","html_url":"https://github.com/toneiv","followers_url":"https://api.github.com/users/toneiv/followers","following_url":"https://api.github.com/users/toneiv/following{/other_user}","gists_url":"https://api.github.com/users/toneiv/gists{/gist_id}","starred_url":"https://api.github.com/users/toneiv/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/toneiv/subscriptions","organizations_url":"https://api.github.com/users/toneiv/orgs","repos_url":"https://api.github.com/users/toneiv/repos","events_url":"https://api.github.com/users/toneiv/events{/privacy}","received_events_url":"https://api.github.com/users/toneiv/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/toneiv/Shaarli","description":"The personal, minimalist, super-fast, no-database delicious clone - community repo","fork":true,"url":"https://api.github.com/repos/toneiv/Shaarli","forks_url":"https://api.github.com/repos/toneiv/Shaarli/forks","keys_url":"https://api.github.com/repos/toneiv/Shaarli/keys{/key_id}","collaborators_url":"https://api.github.com/repos/toneiv/Shaarli/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/toneiv/Shaarli/teams","hooks_url":"https://api.github.com/repos/toneiv/Shaarli/hooks","issue_events_url":"https://api.github.com/repos/toneiv/Shaarli/issues/events{/number}","events_url":"https://api.github.com/repos/toneiv/Shaarli/events","assignees_url":"https://api.github.com/repos/toneiv/Shaarli/assignees{/user}","branches_url":"https://api.github.com/repos/toneiv/Shaarli/branches{/branch}","tags_url":"https://api.github.com/repos/toneiv/Shaarli/tags","blobs_url":"https://api.github.com/repos/toneiv/Shaarli/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/toneiv/Shaarli/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/toneiv/Shaarli/git/refs{/sha}","trees_url":"https://api.github.com/repos/toneiv/Shaarli/git/trees{/sha}","statuses_url":"https://api.github.com/repos/toneiv/Shaarli/statuses/{sha}","languages_url":"https://api.github.com/repos/toneiv/Shaarli/languages","stargazers_url":"https://api.github.com/repos/toneiv/Shaarli/stargazers","contributors_url":"https://api.github.com/repos/toneiv/Shaarli/contributors","subscribers_url":"https://api.github.com/repos/toneiv/Shaarli/subscribers","subscription_url":"https://api.github.com/repos/toneiv/Shaarli/subscription","commits_url":"https://api.github.com/repos/toneiv/Shaarli/commits{/sha}","git_commits_url":"https://api.github.com/repos/toneiv/Shaarli/git/commits{/sha}","comments_url":"https://api.github.com/repos/toneiv/Shaarli/comments{/number}","issue_comment_url":"https://api.github.com/repos/toneiv/Shaarli/issues/comments{/number}","contents_url":"https://api.github.com/repos/toneiv/Shaarli/contents/{+path}","compare_url":"https://api.github.com/repos/toneiv/Shaarli/compare/{base}...{head}","merges_url":"https://api.github.com/repos/toneiv/Shaarli/merges","archive_url":"https://api.github.com/repos/toneiv/Shaarli/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/toneiv/Shaarli/downloads","issues_url":"https://api.github.com/repos/toneiv/Shaarli/issues{/number}","pulls_url":"https://api.github.com/repos/toneiv/Shaarli/pulls{/number}","milestones_url":"https://api.github.com/repos/toneiv/Shaarli/milestones{/number}","notifications_url":"https://api.github.com/repos/toneiv/Shaarli/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/toneiv/Shaarli/labels{/name}","releases_url":"https://api.github.com/repos/toneiv/Shaarli/releases{/id}","deployments_url":"https://api.github.com/repos/toneiv/Shaarli/deployments","created_at":"2016-02-03T13:20:29Z","updated_at":"2016-02-03T13:20:30Z","pushed_at":"2016-06-10T11:39:12Z","git_url":"git://github.com/toneiv/Shaarli.git","ssh_url":"git@github.com:toneiv/Shaarli.git","clone_url":"https://github.com/toneiv/Shaarli.git","svn_url":"https://github.com/toneiv/Shaarli","homepage":"https://github.com/shaarli/Shaarli","size":2420,"stargazers_count":0,"watchers_count":0,"language":"PHP","has_issues":false,"has_downloads":true,"has_wiki":true,"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":"shaarli:master","ref":"master","sha":"92a381f51737de1e4a03c482fe7c43da311ad556","user":{"login":"shaarli","id":8275533,"avatar_url":"https://avatars.githubusercontent.com/u/8275533?v=3","gravatar_id":"","url":"https://api.github.com/users/shaarli","html_url":"https://github.com/shaarli","followers_url":"https://api.github.com/users/shaarli/followers","following_url":"https://api.github.com/users/shaarli/following{/other_user}","gists_url":"https://api.github.com/users/shaarli/gists{/gist_id}","starred_url":"https://api.github.com/users/shaarli/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/shaarli/subscriptions","organizations_url":"https://api.github.com/users/shaarli/orgs","repos_url":"https://api.github.com/users/shaarli/repos","events_url":"https://api.github.com/users/shaarli/events{/privacy}","received_events_url":"https://api.github.com/users/shaarli/received_events","type":"Organization","site_admin":false},"repo":{"id":22287975,"name":"Shaarli","full_name":"shaarli/Shaarli","owner":{"login":"shaarli","id":8275533,"avatar_url":"https://avatars.githubusercontent.com/u/8275533?v=3","gravatar_id":"","url":"https://api.github.com/users/shaarli","html_url":"https://github.com/shaarli","followers_url":"https://api.github.com/users/shaarli/followers","following_url":"https://api.github.com/users/shaarli/following{/other_user}","gists_url":"https://api.github.com/users/shaarli/gists{/gist_id}","starred_url":"https://api.github.com/users/shaarli/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/shaarli/subscriptions","organizations_url":"https://api.github.com/users/shaarli/orgs","repos_url":"https://api.github.com/users/shaarli/repos","events_url":"https://api.github.com/users/shaarli/events{/privacy}","received_events_url":"https://api.github.com/users/shaarli/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/shaarli/Shaarli","description":"The personal, minimalist, super-fast, database free, bookmarking service - community repo","fork":true,"url":"https://api.github.com/repos/shaarli/Shaarli","forks_url":"https://api.github.com/repos/shaarli/Shaarli/forks","keys_url":"https://api.github.com/repos/shaarli/Shaarli/keys{/key_id}","collaborators_url":"https://api.github.com/repos/shaarli/Shaarli/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/shaarli/Shaarli/teams","hooks_url":"https://api.github.com/repos/shaarli/Shaarli/hooks","issue_events_url":"https://api.github.com/repos/shaarli/Shaarli/issues/events{/number}","events_url":"https://api.github.com/repos/shaarli/Shaarli/events","assignees_url":"https://api.github.com/repos/shaarli/Shaarli/assignees{/user}","branches_url":"https://api.github.com/repos/shaarli/Shaarli/branches{/branch}","tags_url":"https://api.github.com/repos/shaarli/Shaarli/tags","blobs_url":"https://api.github.com/repos/shaarli/Shaarli/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/shaarli/Shaarli/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/shaarli/Shaarli/git/refs{/sha}","trees_url":"https://api.github.com/repos/shaarli/Shaarli/git/trees{/sha}","statuses_url":"https://api.github.com/repos/shaarli/Shaarli/statuses/{sha}","languages_url":"https://api.github.com/repos/shaarli/Shaarli/languages","stargazers_url":"https://api.github.com/repos/shaarli/Shaarli/stargazers","contributors_url":"https://api.github.com/repos/shaarli/Shaarli/contributors","subscribers_url":"https://api.github.com/repos/shaarli/Shaarli/subscribers","subscription_url":"https://api.github.com/repos/shaarli/Shaarli/subscription","commits_url":"https://api.github.com/repos/shaarli/Shaarli/commits{/sha}","git_commits_url":"https://api.github.com/repos/shaarli/Shaarli/git/commits{/sha}","comments_url":"https://api.github.com/repos/shaarli/Shaarli/comments{/number}","issue_comment_url":"https://api.github.com/repos/shaarli/Shaarli/issues/comments{/number}","contents_url":"https://api.github.com/repos/shaarli/Shaarli/contents/{+path}","compare_url":"https://api.github.com/repos/shaarli/Shaarli/compare/{base}...{head}","merges_url":"https://api.github.com/repos/shaarli/Shaarli/merges","archive_url":"https://api.github.com/repos/shaarli/Shaarli/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/shaarli/Shaarli/downloads","issues_url":"https://api.github.com/repos/shaarli/Shaarli/issues{/number}","pulls_url":"https://api.github.com/repos/shaarli/Shaarli/pulls{/number}","milestones_url":"https://api.github.com/repos/shaarli/Shaarli/milestones{/number}","notifications_url":"https://api.github.com/repos/shaarli/Shaarli/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/shaarli/Shaarli/labels{/name}","releases_url":"https://api.github.com/repos/shaarli/Shaarli/releases{/id}","deployments_url":"https://api.github.com/repos/shaarli/Shaarli/deployments","created_at":"2014-07-26T14:10:30Z","updated_at":"2016-06-09T18:24:23Z","pushed_at":"2016-06-10T11:39:13Z","git_url":"git://github.com/shaarli/Shaarli.git","ssh_url":"git@github.com:shaarli/Shaarli.git","clone_url":"https://github.com/shaarli/Shaarli.git","svn_url":"https://github.com/shaarli/Shaarli","homepage":"https://github.com/shaarli/Shaarli","size":3526,"stargazers_count":322,"watchers_count":322,"language":"PHP","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":54,"mirror_url":null,"open_issues_count":93,"forks":54,"open_issues":93,"watchers":322,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/shaarli/Shaarli/pulls/586"},"html":{"href":"https://github.com/shaarli/Shaarli/pull/586"},"issue":{"href":"https://api.github.com/repos/shaarli/Shaarli/issues/586"},"comments":{"href":"https://api.github.com/repos/shaarli/Shaarli/issues/586/comments"},"review_comments":{"href":"https://api.github.com/repos/shaarli/Shaarli/pulls/586/comments"},"review_comment":{"href":"https://api.github.com/repos/shaarli/Shaarli/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/shaarli/Shaarli/pulls/586/commits"},"statuses":{"href":"https://api.github.com/repos/shaarli/Shaarli/statuses/2c6ed818e28f18063833b4f9ffd4188f5635330d"}}}}
{"actor":{"display_login":"ArthurHoaro"}}