{"action":"created","comment":{"url":"https://api.github.com/repos/KnowSheet/CTFO_BE/pulls/comments/31703922","id":31703922,"diff_hunk":"@@ -0,0 +1,240 @@\n+/*******************************************************************************\n+The MIT License (MIT)\n+\n+Copyright (c) 2015 Dmitry \"Dima\" Korolev <dmitry.korolev@gmail.com>\n+          (c) 2015 Maxim Zhurovich <zhurovich@gmail.com>\n+\n+Permission is hereby granted, free of charge, to any person obtaining a copy\n+of this software and associated documentation files (the \"Software\"), to deal\n+in the Software without restriction, including without limitation the rights\n+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n+copies of the Software, and to permit persons to whom the Software is\n+furnished to do so, subject to the following conditions:\n+\n+The above copyright notice and this permission notice shall be included in all\n+copies or substantial portions of the Software.\n+\n+THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n+SOFTWARE.\n+*******************************************************************************/\n+\n+#ifndef CTFO_SERVER_H\n+#define CTFO_SERVER_H\n+\n+#include <cassert>\n+#include <cstdlib>\n+#include <vector>\n+#include <string>\n+#include <random>\n+\n+#include \"../Current/Bricks/file/file.h\"\n+#include \"../Current/Bricks/strings/split.h\"\n+#include \"../Current/Bricks/net/api/api.h\"\n+\n+#include \"schema.h\"\n+\n+using namespace yoda;\n+using namespace bricks::strings;\n+\n+class CTFOServer {\n+ public:\n+  explicit CTFOServer(int http_port, int rand_seed)\n+      : http_port_(http_port),\n+        rng_(rand_seed),\n+        random_uint64_(std::bind(std::uniform_int_distribution<uint64_t>(0, -1ll), rng_)),\n+        random_0_1_picker_(std::bind(std::uniform_real_distribution<double>(0.0, 1.0), rng_)),\n+        random_10_99_picker_(std::bind(std::uniform_int_distribution<int>(10, 99), rng_)),\n+        storage_(\"CTFO storage\"),\n+        cards_(Split<ByLines>(bricks::FileSystem::ReadFileAsString(\"cards.txt\"))) {\n+    assert(cards_.size() >= 2u);\n+    assert(cards_[0] == \"ZERO_INDEX_SHOULD_BE_KEPT_UNUSED\");\n+\n+    storage_.Transaction([this](StorageAPI::T_DATA data) {\n+      for (const auto text : cards_) {\n+        CID cid;\n+        do {\n+          cid = RandomCID();\n+        } while (data.Get(cid));\n+        Card card(cid, text);\n+        card.ctfo_count = random_10_99_picker_();\n+        card.tfu_count = random_10_99_picker_();\n+        card.tifb_count = random_10_99_picker_();\n+        data.Add(card);\n+      }\n+    });\n+\n+    HTTP(http_port_)\n+        .Register(\"/auth/browser\", [this](Request r) {\n+          if (r.method != \"POST\") {\n+            r(\"METHOD NOT ALLOWED\\n\", HTTPResponseCode.MethodNotAllowed);\n+          } else {\n+            const std::string device_id = r.url.query.get(\"device_id\", \"\");\n+            if (device_id.empty()) {\n+              r(\"NEED VALID DEVICE ID\\n\", HTTPResponseCode.BadRequest);\n+            } else {\n+              UID uid = UID::INVALID;\n+              User user;\n+              ResponseUserEntry user_entry;\n+\n+              // Searching for users with provided device ID.\n+              storage_.Transaction([&](StorageAPI::T_DATA data) {\n+                                     const auto accessor = MatrixEntry<DeviceIdUIDPair>::Accessor(data);\n+                                     if (accessor.Rows().has(device_id)) {\n+                                       assert(accessor[device_id].size() == 1);\n+                                       uid = accessor[device_id].begin()->uid;\n+                                     }\n+                                   }).Go();\n+\n+              if (uid != UID::INVALID) {  // Existing user.\n+                // Invalidating all old tokens.\n+                storage_.Transaction([&](StorageAPI::T_DATA data) {\n+                                       auto mutator = MatrixEntry<UIDTokenPair>::Mutator(data);\n+                                       for (const auto& uid_token : mutator[uid]) {\n+                                         UIDTokenPair invalid_token(uid_token.uid, uid_token.token, false);\n+                                         mutator.Add(invalid_token);\n+                                       }\n+                                       user = data.Get(uid);\n+                                     }).Go();\n+                user_entry.score = user.score;\n+              } else {  // New user.\n+                uid = RandomUID();\n+                user.uid = uid;\n+                storage_.Add(user).Go();\n+              }\n+\n+              CopyUserInfoToResponseEntry(user, user_entry);\n+              // Generating a new token.\n+              const std::string token = RandomToken();\n+              user_entry.token = token;\n+              storage_.Add(UIDTokenPair(uid, token)).Go();\n+\n+              RespondWithFeed(user_entry, FromString<size_t>(r.url.query.get(\"feed_count\", \"20\")),\n+                              std::move(r));\n+            }\n+          }\n+        });\n+\n+    HTTP(http_port_)\n+        .Register(\"/feed\", [this](Request r) {\n+          const UID uid = StringToUID(r.url.query[\"uid\"]);\n+          const std::string token = r.url.query[\"token\"];\n+          if (r.method != \"GET\") {\n+            r(\"METHOD NOT ALLOWED\\n\", HTTPResponseCode.MethodNotAllowed);\n+          } else {\n+            if (uid == UID::INVALID) {\n+              r(\"NEED VALID UID\\n\", HTTPResponseCode.BadRequest);\n+            } else {\n+              bool valid_token = storage_.Get(uid, token).Go();\n+              if (!valid_token) {\n+                r(\"NEED VALID TOKEN\\n\", HTTPResponseCode.Unauthorized);\n+              } else {\n+                const auto user = storage_.Get(uid).Go();\n+                ResponseUserEntry user_entry;\n+                CopyUserInfoToResponseEntry(user, user_entry);\n+                user_entry.token = token;\n+                RespondWithFeed(user_entry, FromString<size_t>(r.url.query.get(\"feed_count\", \"20\")),\n+                                std::move(r));\n+              }\n+            }\n+          }\n+        });\n+  }  // CTFOServer(...)\n+\n+  void RespondWithFeed(ResponseUserEntry user_entry, size_t max_count, Request r) {\n+    storage_.Transaction(\n+        [&, user_entry, max_count](StorageAPI::T_DATA data) {\n+          ResponseFeed response;\n+          response.user = user_entry;\n+\n+          std::vector<CID> candidates;\n+          const UID uid = StringToUID(response.user.uid);\n+          const auto answers = MatrixEntry<Answer>::Accessor(data);\n+          const auto cards = Dictionary<Card>::Accessor(data);\n+          for (const auto& card : cards) {\n+            if (!answers.Get(uid, card.cid)) {\n+              candidates.push_back(card.cid);\n+            }\n+          }\n+          std::shuffle(candidates.begin(), candidates.end(), rng_);\n+\n+          for (size_t i = 0; i < candidates.size() && (max_count ? (i < max_count) : true); ++i) {\n+            const CID cid = candidates[i];\n+            response.cards.resize(response.cards.size() + 1);\n+            ResponseCardEntry& card_entry = response.cards.back();\n+            card_entry.cid = CIDToString(cid);\n+            const Card& card = data.Get(cid);\n+            card_entry.text = card.text;\n+            card_entry.relevance = random_0_1_picker_();\n+            card_entry.score = random_10_99_picker_();\n+            const uint64_t total_answers = card.ctfo_count + card.tfu_count;\n+            if (total_answers > 0) {\n+              card_entry.ctfo_percentage = static_cast<double>(card.ctfo_count) / total_answers;\n+            } else {\n+              card_entry.ctfo_percentage = 0.5;\n+            }\n+          }\n+\n+          response.ts = static_cast<uint64_t>(bricks::time::Now());\n+          return response;\n+        },\n+        std::move(r));\n+  }\n+\n+  void Join() { HTTP(http_port_).Join(); }\n+\n+ private:\n+  const int http_port_;\n+  std::mt19937_64 rng_;\n+  std::function<uint64_t()> random_uint64_;\n+  std::function<double()> random_0_1_picker_;\n+  std::function<int()> random_10_99_picker_;\n+\n+  typedef API<Dictionary<User>,\n+              MatrixEntry<UIDTokenPair>,\n+              MatrixEntry<DeviceIdUIDPair>,\n+              Dictionary<Card>,\n+              MatrixEntry<Answer>> StorageAPI;\n+  StorageAPI storage_;\n+  std::vector<std::string> cards_;\n+\n+  const std::map<std::string, ANSWER> valid_answers_ = {\n+      {\"ctfo\", ANSWER::CTFO}, {\"tfu\", ANSWER::TFU}, {\"tifb\", ANSWER::TIFB}};\n+\n+  UID RandomUID() { return static_cast<UID>(random_uint64_() % 1000000000000000000 + 1000000000000000000); }","path":"server.h","position":208,"original_position":208,"commit_id":"d45ade696031dfa920f5db12075b1f177467c6de","original_commit_id":"d45ade696031dfa920f5db12075b1f177467c6de","user":{"login":"dkorolev","id":2159447,"avatar_url":"https://avatars.githubusercontent.com/u/2159447?v=3","gravatar_id":"","url":"https://api.github.com/users/dkorolev","html_url":"https://github.com/dkorolev","followers_url":"https://api.github.com/users/dkorolev/followers","following_url":"https://api.github.com/users/dkorolev/following{/other_user}","gists_url":"https://api.github.com/users/dkorolev/gists{/gist_id}","starred_url":"https://api.github.com/users/dkorolev/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dkorolev/subscriptions","organizations_url":"https://api.github.com/users/dkorolev/orgs","repos_url":"https://api.github.com/users/dkorolev/repos","events_url":"https://api.github.com/users/dkorolev/events{/privacy}","received_events_url":"https://api.github.com/users/dkorolev/received_events","type":"User","site_admin":false},"body":"Why not use `random_uid_picker_` and `random_cid_picker_` with proper ranges?","created_at":"2015-06-04T09:05:26Z","updated_at":"2015-06-04T09:05:26Z","html_url":"https://github.com/KnowSheet/CTFO_BE/pull/2#discussion_r31703922","pull_request_url":"https://api.github.com/repos/KnowSheet/CTFO_BE/pulls/2","_links":{"self":{"href":"https://api.github.com/repos/KnowSheet/CTFO_BE/pulls/comments/31703922"},"html":{"href":"https://github.com/KnowSheet/CTFO_BE/pull/2#discussion_r31703922"},"pull_request":{"href":"https://api.github.com/repos/KnowSheet/CTFO_BE/pulls/2"}}},"pull_request":{"url":"https://api.github.com/repos/KnowSheet/CTFO_BE/pulls/2","id":36905953,"html_url":"https://github.com/KnowSheet/CTFO_BE/pull/2","diff_url":"https://github.com/KnowSheet/CTFO_BE/pull/2.diff","patch_url":"https://github.com/KnowSheet/CTFO_BE/pull/2.patch","issue_url":"https://api.github.com/repos/KnowSheet/CTFO_BE/issues/2","number":2,"state":"open","locked":false,"title":"Reworked version of backend with Yoda.","user":{"login":"mzhurovich","id":11226961,"avatar_url":"https://avatars.githubusercontent.com/u/11226961?v=3","gravatar_id":"","url":"https://api.github.com/users/mzhurovich","html_url":"https://github.com/mzhurovich","followers_url":"https://api.github.com/users/mzhurovich/followers","following_url":"https://api.github.com/users/mzhurovich/following{/other_user}","gists_url":"https://api.github.com/users/mzhurovich/gists{/gist_id}","starred_url":"https://api.github.com/users/mzhurovich/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mzhurovich/subscriptions","organizations_url":"https://api.github.com/users/mzhurovich/orgs","repos_url":"https://api.github.com/users/mzhurovich/repos","events_url":"https://api.github.com/users/mzhurovich/events{/privacy}","received_events_url":"https://api.github.com/users/mzhurovich/received_events","type":"User","site_admin":false},"body":"","created_at":"2015-06-04T06:34:03Z","updated_at":"2015-06-04T09:05:26Z","closed_at":null,"merged_at":null,"merge_commit_sha":"52148020bb611d670c596dd3ca06ed69342a6d0e","assignee":{"login":"dkorolev","id":2159447,"avatar_url":"https://avatars.githubusercontent.com/u/2159447?v=3","gravatar_id":"","url":"https://api.github.com/users/dkorolev","html_url":"https://github.com/dkorolev","followers_url":"https://api.github.com/users/dkorolev/followers","following_url":"https://api.github.com/users/dkorolev/following{/other_user}","gists_url":"https://api.github.com/users/dkorolev/gists{/gist_id}","starred_url":"https://api.github.com/users/dkorolev/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dkorolev/subscriptions","organizations_url":"https://api.github.com/users/dkorolev/orgs","repos_url":"https://api.github.com/users/dkorolev/repos","events_url":"https://api.github.com/users/dkorolev/events{/privacy}","received_events_url":"https://api.github.com/users/dkorolev/received_events","type":"User","site_admin":false},"milestone":null,"commits_url":"https://api.github.com/repos/KnowSheet/CTFO_BE/pulls/2/commits","review_comments_url":"https://api.github.com/repos/KnowSheet/CTFO_BE/pulls/2/comments","review_comment_url":"https://api.github.com/repos/KnowSheet/CTFO_BE/pulls/comments{/number}","comments_url":"https://api.github.com/repos/KnowSheet/CTFO_BE/issues/2/comments","statuses_url":"https://api.github.com/repos/KnowSheet/CTFO_BE/statuses/d45ade696031dfa920f5db12075b1f177467c6de","head":{"label":"mzhurovich:master","ref":"master","sha":"d45ade696031dfa920f5db12075b1f177467c6de","user":{"login":"mzhurovich","id":11226961,"avatar_url":"https://avatars.githubusercontent.com/u/11226961?v=3","gravatar_id":"","url":"https://api.github.com/users/mzhurovich","html_url":"https://github.com/mzhurovich","followers_url":"https://api.github.com/users/mzhurovich/followers","following_url":"https://api.github.com/users/mzhurovich/following{/other_user}","gists_url":"https://api.github.com/users/mzhurovich/gists{/gist_id}","starred_url":"https://api.github.com/users/mzhurovich/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mzhurovich/subscriptions","organizations_url":"https://api.github.com/users/mzhurovich/orgs","repos_url":"https://api.github.com/users/mzhurovich/repos","events_url":"https://api.github.com/users/mzhurovich/events{/privacy}","received_events_url":"https://api.github.com/users/mzhurovich/received_events","type":"User","site_admin":false},"repo":{"id":34410534,"name":"CTFO_BE","full_name":"mzhurovich/CTFO_BE","owner":{"login":"mzhurovich","id":11226961,"avatar_url":"https://avatars.githubusercontent.com/u/11226961?v=3","gravatar_id":"","url":"https://api.github.com/users/mzhurovich","html_url":"https://github.com/mzhurovich","followers_url":"https://api.github.com/users/mzhurovich/followers","following_url":"https://api.github.com/users/mzhurovich/following{/other_user}","gists_url":"https://api.github.com/users/mzhurovich/gists{/gist_id}","starred_url":"https://api.github.com/users/mzhurovich/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mzhurovich/subscriptions","organizations_url":"https://api.github.com/users/mzhurovich/orgs","repos_url":"https://api.github.com/users/mzhurovich/repos","events_url":"https://api.github.com/users/mzhurovich/events{/privacy}","received_events_url":"https://api.github.com/users/mzhurovich/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/mzhurovich/CTFO_BE","description":"CTFO Backend","fork":true,"url":"https://api.github.com/repos/mzhurovich/CTFO_BE","forks_url":"https://api.github.com/repos/mzhurovich/CTFO_BE/forks","keys_url":"https://api.github.com/repos/mzhurovich/CTFO_BE/keys{/key_id}","collaborators_url":"https://api.github.com/repos/mzhurovich/CTFO_BE/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/mzhurovich/CTFO_BE/teams","hooks_url":"https://api.github.com/repos/mzhurovich/CTFO_BE/hooks","issue_events_url":"https://api.github.com/repos/mzhurovich/CTFO_BE/issues/events{/number}","events_url":"https://api.github.com/repos/mzhurovich/CTFO_BE/events","assignees_url":"https://api.github.com/repos/mzhurovich/CTFO_BE/assignees{/user}","branches_url":"https://api.github.com/repos/mzhurovich/CTFO_BE/branches{/branch}","tags_url":"https://api.github.com/repos/mzhurovich/CTFO_BE/tags","blobs_url":"https://api.github.com/repos/mzhurovich/CTFO_BE/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/mzhurovich/CTFO_BE/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/mzhurovich/CTFO_BE/git/refs{/sha}","trees_url":"https://api.github.com/repos/mzhurovich/CTFO_BE/git/trees{/sha}","statuses_url":"https://api.github.com/repos/mzhurovich/CTFO_BE/statuses/{sha}","languages_url":"https://api.github.com/repos/mzhurovich/CTFO_BE/languages","stargazers_url":"https://api.github.com/repos/mzhurovich/CTFO_BE/stargazers","contributors_url":"https://api.github.com/repos/mzhurovich/CTFO_BE/contributors","subscribers_url":"https://api.github.com/repos/mzhurovich/CTFO_BE/subscribers","subscription_url":"https://api.github.com/repos/mzhurovich/CTFO_BE/subscription","commits_url":"https://api.github.com/repos/mzhurovich/CTFO_BE/commits{/sha}","git_commits_url":"https://api.github.com/repos/mzhurovich/CTFO_BE/git/commits{/sha}","comments_url":"https://api.github.com/repos/mzhurovich/CTFO_BE/comments{/number}","issue_comment_url":"https://api.github.com/repos/mzhurovich/CTFO_BE/issues/comments{/number}","contents_url":"https://api.github.com/repos/mzhurovich/CTFO_BE/contents/{+path}","compare_url":"https://api.github.com/repos/mzhurovich/CTFO_BE/compare/{base}...{head}","merges_url":"https://api.github.com/repos/mzhurovich/CTFO_BE/merges","archive_url":"https://api.github.com/repos/mzhurovich/CTFO_BE/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/mzhurovich/CTFO_BE/downloads","issues_url":"https://api.github.com/repos/mzhurovich/CTFO_BE/issues{/number}","pulls_url":"https://api.github.com/repos/mzhurovich/CTFO_BE/pulls{/number}","milestones_url":"https://api.github.com/repos/mzhurovich/CTFO_BE/milestones{/number}","notifications_url":"https://api.github.com/repos/mzhurovich/CTFO_BE/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/mzhurovich/CTFO_BE/labels{/name}","releases_url":"https://api.github.com/repos/mzhurovich/CTFO_BE/releases{/id}","created_at":"2015-04-22T19:15:30Z","updated_at":"2015-06-04T06:29:46Z","pushed_at":"2015-06-04T06:33:17Z","git_url":"git://github.com/mzhurovich/CTFO_BE.git","ssh_url":"git@github.com:mzhurovich/CTFO_BE.git","clone_url":"https://github.com/mzhurovich/CTFO_BE.git","svn_url":"https://github.com/mzhurovich/CTFO_BE","homepage":null,"size":107,"stargazers_count":0,"watchers_count":0,"language":"C++","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":"KnowSheet:master","ref":"master","sha":"0de8e25e3ac3c221ea044b3eab07442608f0dbae","user":{"login":"KnowSheet","id":9897562,"avatar_url":"https://avatars.githubusercontent.com/u/9897562?v=3","gravatar_id":"","url":"https://api.github.com/users/KnowSheet","html_url":"https://github.com/KnowSheet","followers_url":"https://api.github.com/users/KnowSheet/followers","following_url":"https://api.github.com/users/KnowSheet/following{/other_user}","gists_url":"https://api.github.com/users/KnowSheet/gists{/gist_id}","starred_url":"https://api.github.com/users/KnowSheet/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/KnowSheet/subscriptions","organizations_url":"https://api.github.com/users/KnowSheet/orgs","repos_url":"https://api.github.com/users/KnowSheet/repos","events_url":"https://api.github.com/users/KnowSheet/events{/privacy}","received_events_url":"https://api.github.com/users/KnowSheet/received_events","type":"Organization","site_admin":false},"repo":{"id":34405022,"name":"CTFO_BE","full_name":"KnowSheet/CTFO_BE","owner":{"login":"KnowSheet","id":9897562,"avatar_url":"https://avatars.githubusercontent.com/u/9897562?v=3","gravatar_id":"","url":"https://api.github.com/users/KnowSheet","html_url":"https://github.com/KnowSheet","followers_url":"https://api.github.com/users/KnowSheet/followers","following_url":"https://api.github.com/users/KnowSheet/following{/other_user}","gists_url":"https://api.github.com/users/KnowSheet/gists{/gist_id}","starred_url":"https://api.github.com/users/KnowSheet/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/KnowSheet/subscriptions","organizations_url":"https://api.github.com/users/KnowSheet/orgs","repos_url":"https://api.github.com/users/KnowSheet/repos","events_url":"https://api.github.com/users/KnowSheet/events{/privacy}","received_events_url":"https://api.github.com/users/KnowSheet/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/KnowSheet/CTFO_BE","description":"CTFO Backend","fork":false,"url":"https://api.github.com/repos/KnowSheet/CTFO_BE","forks_url":"https://api.github.com/repos/KnowSheet/CTFO_BE/forks","keys_url":"https://api.github.com/repos/KnowSheet/CTFO_BE/keys{/key_id}","collaborators_url":"https://api.github.com/repos/KnowSheet/CTFO_BE/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/KnowSheet/CTFO_BE/teams","hooks_url":"https://api.github.com/repos/KnowSheet/CTFO_BE/hooks","issue_events_url":"https://api.github.com/repos/KnowSheet/CTFO_BE/issues/events{/number}","events_url":"https://api.github.com/repos/KnowSheet/CTFO_BE/events","assignees_url":"https://api.github.com/repos/KnowSheet/CTFO_BE/assignees{/user}","branches_url":"https://api.github.com/repos/KnowSheet/CTFO_BE/branches{/branch}","tags_url":"https://api.github.com/repos/KnowSheet/CTFO_BE/tags","blobs_url":"https://api.github.com/repos/KnowSheet/CTFO_BE/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/KnowSheet/CTFO_BE/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/KnowSheet/CTFO_BE/git/refs{/sha}","trees_url":"https://api.github.com/repos/KnowSheet/CTFO_BE/git/trees{/sha}","statuses_url":"https://api.github.com/repos/KnowSheet/CTFO_BE/statuses/{sha}","languages_url":"https://api.github.com/repos/KnowSheet/CTFO_BE/languages","stargazers_url":"https://api.github.com/repos/KnowSheet/CTFO_BE/stargazers","contributors_url":"https://api.github.com/repos/KnowSheet/CTFO_BE/contributors","subscribers_url":"https://api.github.com/repos/KnowSheet/CTFO_BE/subscribers","subscription_url":"https://api.github.com/repos/KnowSheet/CTFO_BE/subscription","commits_url":"https://api.github.com/repos/KnowSheet/CTFO_BE/commits{/sha}","git_commits_url":"https://api.github.com/repos/KnowSheet/CTFO_BE/git/commits{/sha}","comments_url":"https://api.github.com/repos/KnowSheet/CTFO_BE/comments{/number}","issue_comment_url":"https://api.github.com/repos/KnowSheet/CTFO_BE/issues/comments{/number}","contents_url":"https://api.github.com/repos/KnowSheet/CTFO_BE/contents/{+path}","compare_url":"https://api.github.com/repos/KnowSheet/CTFO_BE/compare/{base}...{head}","merges_url":"https://api.github.com/repos/KnowSheet/CTFO_BE/merges","archive_url":"https://api.github.com/repos/KnowSheet/CTFO_BE/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/KnowSheet/CTFO_BE/downloads","issues_url":"https://api.github.com/repos/KnowSheet/CTFO_BE/issues{/number}","pulls_url":"https://api.github.com/repos/KnowSheet/CTFO_BE/pulls{/number}","milestones_url":"https://api.github.com/repos/KnowSheet/CTFO_BE/milestones{/number}","notifications_url":"https://api.github.com/repos/KnowSheet/CTFO_BE/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/KnowSheet/CTFO_BE/labels{/name}","releases_url":"https://api.github.com/repos/KnowSheet/CTFO_BE/releases{/id}","created_at":"2015-04-22T17:25:40Z","updated_at":"2015-04-22T17:25:40Z","pushed_at":"2015-06-04T06:34:04Z","git_url":"git://github.com/KnowSheet/CTFO_BE.git","ssh_url":"git@github.com:KnowSheet/CTFO_BE.git","clone_url":"https://github.com/KnowSheet/CTFO_BE.git","svn_url":"https://github.com/KnowSheet/CTFO_BE","homepage":null,"size":158,"stargazers_count":0,"watchers_count":0,"language":null,"has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1,"mirror_url":null,"open_issues_count":2,"forks":1,"open_issues":2,"watchers":0,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/KnowSheet/CTFO_BE/pulls/2"},"html":{"href":"https://github.com/KnowSheet/CTFO_BE/pull/2"},"issue":{"href":"https://api.github.com/repos/KnowSheet/CTFO_BE/issues/2"},"comments":{"href":"https://api.github.com/repos/KnowSheet/CTFO_BE/issues/2/comments"},"review_comments":{"href":"https://api.github.com/repos/KnowSheet/CTFO_BE/pulls/2/comments"},"review_comment":{"href":"https://api.github.com/repos/KnowSheet/CTFO_BE/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/KnowSheet/CTFO_BE/pulls/2/commits"},"statuses":{"href":"https://api.github.com/repos/KnowSheet/CTFO_BE/statuses/d45ade696031dfa920f5db12075b1f177467c6de"}}}}