{"action":"created","comment":{"url":"https://api.github.com/repos/ReCodEx/api/pulls/comments/227502650","pull_request_review_id":167559585,"id":227502650,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIyNzUwMjY1MA==","diff_hunk":"@@ -14,19 +17,255 @@\n  */\n class BoxesOptimizer {\n \n+  /**\n+   * Determine if given variables can be optimized or not.\n+   * @param Variable|null $first\n+   * @param Variable|null $second\n+   * @return bool\n+   */\n+  private static function canVariablesBeOptimized(?Variable $first, ?Variable $second) {\n+    if ($first === null && $second === null) {\n+      return true;\n+    }\n+\n+    if ($first === null || $second === null ||\n+      $first->getValue() !== $second->getValue()) {\n+      return false;\n+    }\n+\n+    if ($first->getType() !== $second->getType()) {\n+      return false;\n+    }\n+\n+    return true;\n+  }\n+\n+  /**\n+   * Determine if given ports can be optimized or not.\n+   * @param Port $first could not be null\n+   * @param Port $second could not be null\n+   * @return bool\n+   */\n+  private static function canPortsBeOptimized(Port $first, Port $second) {\n+    if ($first->getType() !== $second->getType()) {\n+      return false;\n+    }\n+\n+    $variableValue = $first->getVariableValue();\n+    $otherVariableValue = $second->getVariableValue();\n+    if (self::canVariablesBeOptimized($variableValue, $otherVariableValue) === false) {\n+      return false;\n+    }\n+\n+    return true;\n+  }\n+\n+  /**\n+   * Compare two given nodes and determine if they can be optimized.\n+   * @param Node $first\n+   * @param Node $second\n+   * @return bool\n+   */\n+  private static function canNodesBeOptimized(Node $first, Node $second): bool {\n+    if ($first->getBox() === null || $second->getBox() === null) {\n+      return false;\n+    }\n+\n+    $firstBox = $first->getBox();\n+    $secondBox = $second->getBox();\n+\n+    // check box types\n+    if ($firstBox->getType() !== $secondBox->getType()) {\n+      return false;\n+    }\n+\n+    // check ports counts\n+    if (count($firstBox->getInputPorts()) !== count($secondBox->getInputPorts()) ||\n+        count($firstBox->getOutputPorts()) !== count($secondBox->getOutputPorts())) {\n+      return false;\n+    }\n+\n+    // check input ports for equality\n+    foreach ($firstBox->getInputPorts() as $port) {\n+      $otherPort = $secondBox->getInputPort($port->getName());\n+      if ($otherPort === null ||\n+          self::canPortsBeOptimized($port, $otherPort) === false) {\n+        return false;\n+      }\n+    }\n+\n+    // check output ports for equality\n+    foreach ($firstBox->getOutputPorts() as $port) {\n+      $otherPort = $secondBox->getOutputPort($port->getName());\n+      if ($otherPort === null ||\n+          self::canPortsBeOptimized($port, $otherPort) === false) {\n+        return false;\n+      }\n+    }\n+\n+    // special case if boxes are of data type, then they have special input variable which has to be checked as well\n+    if ($firstBox instanceof DataInBox && $secondBox instanceof DataInBox &&\n+        self::canVariablesBeOptimized($firstBox->getInputVariable(), $secondBox->getInputVariable()) === false) {\n+      return false;\n+    }\n+\n+    return true;\n+  }\n+\n+  /**\n+   * This function should be called after optimisation of two nodes to repair dependencies and variables.\n+   * @param Node $node\n+   * @param Node $removedNode\n+   */\n+  private function repairDependencies(Node $node, Node $removedNode) {\n+    // resolve dependencies transfer from compared to child\n+    foreach ($removedNode->getDependencies() as $dependency) {\n+      $node->addDependency($dependency);\n+    }\n+\n+    // in this case, the node was probably created in tests, omit it completely\n+    if ($removedNode->getPortNode() === null) {\n+      return;\n+    }\n+\n+    // repair dependencies of all children\n+    foreach ($removedNode->getPortNode()->getChildren() as $child) {\n+      $child->getNode()->removeDependency($removedNode);\n+      $child->getNode()->addDependency($node);\n+    }\n+\n+    // repair variables\n+    // first we need to prepare old and new ones and then replace them in children\n+    $oldVars = [];\n+    $newVars = [];\n+    foreach ($removedNode->getBox()->getOutputPorts() as $outputPort) {\n+      $variable = $outputPort->getVariableValue();\n+      if ($variable) {\n+        $oldVars[] = $variable;\n+        $newVars[] = $node->getBox()->getOutputPort($outputPort->getName())->getVariableValue();\n+      }\n+    }\n+\n+    // repair variables in all children of removed node\n+    foreach ($removedNode->getPortNode()->getChildren() as $child) {\n+      foreach ($child->getBox()->getInputPorts() as $inputPort) {\n+        $searchIt = array_search($inputPort->getVariableValue(), $oldVars, true);\n+        if ($searchIt !== false) {\n+          $inputPort->setVariableValue($newVars[$searchIt]);\n+        }\n+      }\n+    }\n+  }\n+\n+  /**\n+   * In-place optimisation of the given tree.\n+   * @param Node $rootNode\n+   */\n+  private function optimizeTree(Node $rootNode) {\n+    // Ok, here it goes...\n+    // The whole optimisation is based on following heuristic. We were given a\n+    // rooted tree which can have multiple root nodes. The tree is traversed by\n+    // levels and can be implemented with recursion. At first all root nodes are\n+    // compared if there are any duplicates. If duplicates are found, then these\n+    // nodes are merged into one. The next step is to process all subtrees which\n+    // were created. Thus if there were 4 nodes and 2 and 2 are the same, these\n+    // four nodes are contracted into 2 nodes. These two nodes then contain\n+    // subtrees from the 2 nodes of which they are composed. After this,\n+    // the procedure is repeated for all nodes from subtrees.\n+    // Therefore this heuristics is capable only optimise the beginning of the\n+    // trees and not the ends. This is generally fine for our usage, because\n+    // usually the same thing for all tests is compilation which is the first\n+    // set of tasks in the tree.\n+\n+    // processing queue simulating breadth-first search\n+    $queue = [$rootNode];\n+    while (!empty($queue)) {\n+      $node = array_shift($queue); /** @var Node $node */\n+      $children = $node->getChildren();\n+\n+      if (count($children) < 2) {\n+        // there is nothing to optimize if node has only one or none children\n+        continue;\n+      }\n+\n+      // go through all children from currently processed node\n+      // all children are taken as a base for further comparisons\n+      while (!empty($children)) {\n+        $child = array_shift($children);\n+        $copyChildren = $children;\n+\n+        // base $child has to be compared against all other children\n+        // if the children are equal, then they should be optimised\n+        while(!empty($copyChildren)) {\n+          $compared = array_shift($copyChildren);\n+\n+          // children can be optimized... so do it\n+          if (self::canNodesBeOptimized($child, $compared)) {\n+            // delete the children from the base children array\n+            $children = array_filter($children, function ($n) use ($compared) {\n+              return $n === $compared;\n+            });\n+            $child->setTestId(null); // clear the test identification\n+\n+            foreach ($compared->getChildren() as $comparedChild) {\n+              $comparedChild->removeParent($compared);\n+              $comparedChild->addParent($child);\n+              $child->addChild($comparedChild);\n+            }\n+\n+            foreach ($compared->getParents() as $comparedParent) {\n+              $comparedParent->removeChild($compared);\n+              $comparedParent->addChild($child);\n+              $child->addParent($comparedParent);\n+            }\n+\n+            $this->repairDependencies($child, $compared);\n+          }\n+        }\n+      }\n+\n+      // do not forget to add newly created children from current node to\n+      // processing queue, only if the node was optimised... otherwise we should not proceed\n+      foreach ($node->getChildren() as $child) {\n+        if ($child->getTestId() === null) {\n+          $queue[] = $child;\n+        }\n+      }\n+    }\n+  }\n+\n   /**\n    * Optimize given array of boxes in tests and remove duplicate boxes.\n-   * Resulting array will be multidimensional sort-of tree.\n+   * The optimizer should return RootedTree which should be similar to given\n+   * trees.\n    * @param RootedTree[] $tests\n    * @return RootedTree\n    */\n   public function optimize(array $tests): RootedTree {\n-    $tree = new RootedTree();\n+    // create new root node which contains all root nodes from given subtrees\n+    $rootNode = new Node();\n     foreach ($tests as $testName => $test) {\n-      foreach ($test->getRootNodes() as $rootNode) {\n-        $tree->addRootNode($rootNode);\n+      foreach ($test->getRootNodes() as $node) {\n+        $rootNode->addChild($node);\n+        $node->addParent($rootNode);\n       }\n     }\n+\n+    // The hell of optimisation awaits...\n+    // Forth, and fear no darkness! Arise! Arise, Riders of ReCodEx! Spears\n+    // shall be shaken, shields shall be splintered! A sword day... a red day...\n+    // ere the sun rises!\n+    // Optimize! Optimize! OPTIMIZE!","path":"app/helpers/ExerciseConfig/Compilation/BoxesOptimizer.php","position":259,"original_position":259,"commit_id":"eee45350fa0ca96b4df2f78b0126a9a4bc02ac5b","original_commit_id":"eee45350fa0ca96b4df2f78b0126a9a4bc02ac5b","user":{"login":"krulis-martin","id":26253487,"node_id":"MDQ6VXNlcjI2MjUzNDg3","avatar_url":"https://avatars3.githubusercontent.com/u/26253487?v=4","gravatar_id":"","url":"https://api.github.com/users/krulis-martin","html_url":"https://github.com/krulis-martin","followers_url":"https://api.github.com/users/krulis-martin/followers","following_url":"https://api.github.com/users/krulis-martin/following{/other_user}","gists_url":"https://api.github.com/users/krulis-martin/gists{/gist_id}","starred_url":"https://api.github.com/users/krulis-martin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/krulis-martin/subscriptions","organizations_url":"https://api.github.com/users/krulis-martin/orgs","repos_url":"https://api.github.com/users/krulis-martin/repos","events_url":"https://api.github.com/users/krulis-martin/events{/privacy}","received_events_url":"https://api.github.com/users/krulis-martin/received_events","type":"User","site_admin":false},"body":"I would suggest minor modifications: Riders => Coders, Spears => Mice, shields => keys, sword => code.","created_at":"2018-10-23T18:01:42Z","updated_at":"2018-10-23T18:01:42Z","html_url":"https://github.com/ReCodEx/api/pull/255#discussion_r227502650","pull_request_url":"https://api.github.com/repos/ReCodEx/api/pulls/255","author_association":"MEMBER","_links":{"self":{"href":"https://api.github.com/repos/ReCodEx/api/pulls/comments/227502650"},"html":{"href":"https://github.com/ReCodEx/api/pull/255#discussion_r227502650"},"pull_request":{"href":"https://api.github.com/repos/ReCodEx/api/pulls/255"}}},"pull_request":{"url":"https://api.github.com/repos/ReCodEx/api/pulls/255","id":222704003,"node_id":"MDExOlB1bGxSZXF1ZXN0MjIyNzA0MDAz","html_url":"https://github.com/ReCodEx/api/pull/255","diff_url":"https://github.com/ReCodEx/api/pull/255.diff","patch_url":"https://github.com/ReCodEx/api/pull/255.patch","issue_url":"https://api.github.com/repos/ReCodEx/api/issues/255","number":255,"state":"open","locked":false,"title":"Compilation optimisation","user":{"login":"Neloop","id":15379972,"node_id":"MDQ6VXNlcjE1Mzc5OTcy","avatar_url":"https://avatars3.githubusercontent.com/u/15379972?v=4","gravatar_id":"","url":"https://api.github.com/users/Neloop","html_url":"https://github.com/Neloop","followers_url":"https://api.github.com/users/Neloop/followers","following_url":"https://api.github.com/users/Neloop/following{/other_user}","gists_url":"https://api.github.com/users/Neloop/gists{/gist_id}","starred_url":"https://api.github.com/users/Neloop/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Neloop/subscriptions","organizations_url":"https://api.github.com/users/Neloop/orgs","repos_url":"https://api.github.com/users/Neloop/repos","events_url":"https://api.github.com/users/Neloop/events{/privacy}","received_events_url":"https://api.github.com/users/Neloop/received_events","type":"User","site_admin":false},"body":"**Note:** Do not merge until properly tested.","created_at":"2018-10-14T09:40:45Z","updated_at":"2018-10-23T18:01:42Z","closed_at":null,"merged_at":null,"merge_commit_sha":"8e4420735991f997de67aeb8a7fb80c315319856","assignee":null,"assignees":[],"requested_reviewers":[{"login":"Teyras","id":461515,"node_id":"MDQ6VXNlcjQ2MTUxNQ==","avatar_url":"https://avatars3.githubusercontent.com/u/461515?v=4","gravatar_id":"","url":"https://api.github.com/users/Teyras","html_url":"https://github.com/Teyras","followers_url":"https://api.github.com/users/Teyras/followers","following_url":"https://api.github.com/users/Teyras/following{/other_user}","gists_url":"https://api.github.com/users/Teyras/gists{/gist_id}","starred_url":"https://api.github.com/users/Teyras/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Teyras/subscriptions","organizations_url":"https://api.github.com/users/Teyras/orgs","repos_url":"https://api.github.com/users/Teyras/repos","events_url":"https://api.github.com/users/Teyras/events{/privacy}","received_events_url":"https://api.github.com/users/Teyras/received_events","type":"User","site_admin":false},{"login":"SemaiCZE","id":12883607,"node_id":"MDQ6VXNlcjEyODgzNjA3","avatar_url":"https://avatars3.githubusercontent.com/u/12883607?v=4","gravatar_id":"","url":"https://api.github.com/users/SemaiCZE","html_url":"https://github.com/SemaiCZE","followers_url":"https://api.github.com/users/SemaiCZE/followers","following_url":"https://api.github.com/users/SemaiCZE/following{/other_user}","gists_url":"https://api.github.com/users/SemaiCZE/gists{/gist_id}","starred_url":"https://api.github.com/users/SemaiCZE/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/SemaiCZE/subscriptions","organizations_url":"https://api.github.com/users/SemaiCZE/orgs","repos_url":"https://api.github.com/users/SemaiCZE/repos","events_url":"https://api.github.com/users/SemaiCZE/events{/privacy}","received_events_url":"https://api.github.com/users/SemaiCZE/received_events","type":"User","site_admin":false}],"requested_teams":[],"labels":[{"id":733905895,"node_id":"MDU6TGFiZWw3MzM5MDU4OTU=","url":"https://api.github.com/repos/ReCodEx/api/labels/DO%20NOT%20MERGE","name":"DO NOT MERGE","color":"d93f0b","default":false}],"milestone":null,"commits_url":"https://api.github.com/repos/ReCodEx/api/pulls/255/commits","review_comments_url":"https://api.github.com/repos/ReCodEx/api/pulls/255/comments","review_comment_url":"https://api.github.com/repos/ReCodEx/api/pulls/comments{/number}","comments_url":"https://api.github.com/repos/ReCodEx/api/issues/255/comments","statuses_url":"https://api.github.com/repos/ReCodEx/api/statuses/eee45350fa0ca96b4df2f78b0126a9a4bc02ac5b","head":{"label":"ReCodEx:compilation-optimisation","ref":"compilation-optimisation","sha":"eee45350fa0ca96b4df2f78b0126a9a4bc02ac5b","user":{"login":"ReCodEx","id":15342590,"node_id":"MDEyOk9yZ2FuaXphdGlvbjE1MzQyNTkw","avatar_url":"https://avatars0.githubusercontent.com/u/15342590?v=4","gravatar_id":"","url":"https://api.github.com/users/ReCodEx","html_url":"https://github.com/ReCodEx","followers_url":"https://api.github.com/users/ReCodEx/followers","following_url":"https://api.github.com/users/ReCodEx/following{/other_user}","gists_url":"https://api.github.com/users/ReCodEx/gists{/gist_id}","starred_url":"https://api.github.com/users/ReCodEx/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ReCodEx/subscriptions","organizations_url":"https://api.github.com/users/ReCodEx/orgs","repos_url":"https://api.github.com/users/ReCodEx/repos","events_url":"https://api.github.com/users/ReCodEx/events{/privacy}","received_events_url":"https://api.github.com/users/ReCodEx/received_events","type":"Organization","site_admin":false},"repo":{"id":64029948,"node_id":"MDEwOlJlcG9zaXRvcnk2NDAyOTk0OA==","name":"api","full_name":"ReCodEx/api","private":false,"owner":{"login":"ReCodEx","id":15342590,"node_id":"MDEyOk9yZ2FuaXphdGlvbjE1MzQyNTkw","avatar_url":"https://avatars0.githubusercontent.com/u/15342590?v=4","gravatar_id":"","url":"https://api.github.com/users/ReCodEx","html_url":"https://github.com/ReCodEx","followers_url":"https://api.github.com/users/ReCodEx/followers","following_url":"https://api.github.com/users/ReCodEx/following{/other_user}","gists_url":"https://api.github.com/users/ReCodEx/gists{/gist_id}","starred_url":"https://api.github.com/users/ReCodEx/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ReCodEx/subscriptions","organizations_url":"https://api.github.com/users/ReCodEx/orgs","repos_url":"https://api.github.com/users/ReCodEx/repos","events_url":"https://api.github.com/users/ReCodEx/events{/privacy}","received_events_url":"https://api.github.com/users/ReCodEx/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/ReCodEx/api","description":"Publicly accessible REST API for ReCodEx system","fork":false,"url":"https://api.github.com/repos/ReCodEx/api","forks_url":"https://api.github.com/repos/ReCodEx/api/forks","keys_url":"https://api.github.com/repos/ReCodEx/api/keys{/key_id}","collaborators_url":"https://api.github.com/repos/ReCodEx/api/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/ReCodEx/api/teams","hooks_url":"https://api.github.com/repos/ReCodEx/api/hooks","issue_events_url":"https://api.github.com/repos/ReCodEx/api/issues/events{/number}","events_url":"https://api.github.com/repos/ReCodEx/api/events","assignees_url":"https://api.github.com/repos/ReCodEx/api/assignees{/user}","branches_url":"https://api.github.com/repos/ReCodEx/api/branches{/branch}","tags_url":"https://api.github.com/repos/ReCodEx/api/tags","blobs_url":"https://api.github.com/repos/ReCodEx/api/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/ReCodEx/api/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/ReCodEx/api/git/refs{/sha}","trees_url":"https://api.github.com/repos/ReCodEx/api/git/trees{/sha}","statuses_url":"https://api.github.com/repos/ReCodEx/api/statuses/{sha}","languages_url":"https://api.github.com/repos/ReCodEx/api/languages","stargazers_url":"https://api.github.com/repos/ReCodEx/api/stargazers","contributors_url":"https://api.github.com/repos/ReCodEx/api/contributors","subscribers_url":"https://api.github.com/repos/ReCodEx/api/subscribers","subscription_url":"https://api.github.com/repos/ReCodEx/api/subscription","commits_url":"https://api.github.com/repos/ReCodEx/api/commits{/sha}","git_commits_url":"https://api.github.com/repos/ReCodEx/api/git/commits{/sha}","comments_url":"https://api.github.com/repos/ReCodEx/api/comments{/number}","issue_comment_url":"https://api.github.com/repos/ReCodEx/api/issues/comments{/number}","contents_url":"https://api.github.com/repos/ReCodEx/api/contents/{+path}","compare_url":"https://api.github.com/repos/ReCodEx/api/compare/{base}...{head}","merges_url":"https://api.github.com/repos/ReCodEx/api/merges","archive_url":"https://api.github.com/repos/ReCodEx/api/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/ReCodEx/api/downloads","issues_url":"https://api.github.com/repos/ReCodEx/api/issues{/number}","pulls_url":"https://api.github.com/repos/ReCodEx/api/pulls{/number}","milestones_url":"https://api.github.com/repos/ReCodEx/api/milestones{/number}","notifications_url":"https://api.github.com/repos/ReCodEx/api/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/ReCodEx/api/labels{/name}","releases_url":"https://api.github.com/repos/ReCodEx/api/releases{/id}","deployments_url":"https://api.github.com/repos/ReCodEx/api/deployments","created_at":"2016-07-23T18:30:47Z","updated_at":"2018-10-23T08:44:47Z","pushed_at":"2018-10-23T08:44:45Z","git_url":"git://github.com/ReCodEx/api.git","ssh_url":"git@github.com:ReCodEx/api.git","clone_url":"https://github.com/ReCodEx/api.git","svn_url":"https://github.com/ReCodEx/api","homepage":"https://recodex.mff.cuni.cz/api/v1","size":6024,"stargazers_count":4,"watchers_count":4,"language":"PHP","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":true,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":1,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"forks":0,"open_issues":1,"watchers":4,"default_branch":"master"}},"base":{"label":"ReCodEx:master","ref":"master","sha":"417c9ccb6119a43dd76c2e567b18012af95479ab","user":{"login":"ReCodEx","id":15342590,"node_id":"MDEyOk9yZ2FuaXphdGlvbjE1MzQyNTkw","avatar_url":"https://avatars0.githubusercontent.com/u/15342590?v=4","gravatar_id":"","url":"https://api.github.com/users/ReCodEx","html_url":"https://github.com/ReCodEx","followers_url":"https://api.github.com/users/ReCodEx/followers","following_url":"https://api.github.com/users/ReCodEx/following{/other_user}","gists_url":"https://api.github.com/users/ReCodEx/gists{/gist_id}","starred_url":"https://api.github.com/users/ReCodEx/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ReCodEx/subscriptions","organizations_url":"https://api.github.com/users/ReCodEx/orgs","repos_url":"https://api.github.com/users/ReCodEx/repos","events_url":"https://api.github.com/users/ReCodEx/events{/privacy}","received_events_url":"https://api.github.com/users/ReCodEx/received_events","type":"Organization","site_admin":false},"repo":{"id":64029948,"node_id":"MDEwOlJlcG9zaXRvcnk2NDAyOTk0OA==","name":"api","full_name":"ReCodEx/api","private":false,"owner":{"login":"ReCodEx","id":15342590,"node_id":"MDEyOk9yZ2FuaXphdGlvbjE1MzQyNTkw","avatar_url":"https://avatars0.githubusercontent.com/u/15342590?v=4","gravatar_id":"","url":"https://api.github.com/users/ReCodEx","html_url":"https://github.com/ReCodEx","followers_url":"https://api.github.com/users/ReCodEx/followers","following_url":"https://api.github.com/users/ReCodEx/following{/other_user}","gists_url":"https://api.github.com/users/ReCodEx/gists{/gist_id}","starred_url":"https://api.github.com/users/ReCodEx/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ReCodEx/subscriptions","organizations_url":"https://api.github.com/users/ReCodEx/orgs","repos_url":"https://api.github.com/users/ReCodEx/repos","events_url":"https://api.github.com/users/ReCodEx/events{/privacy}","received_events_url":"https://api.github.com/users/ReCodEx/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/ReCodEx/api","description":"Publicly accessible REST API for ReCodEx system","fork":false,"url":"https://api.github.com/repos/ReCodEx/api","forks_url":"https://api.github.com/repos/ReCodEx/api/forks","keys_url":"https://api.github.com/repos/ReCodEx/api/keys{/key_id}","collaborators_url":"https://api.github.com/repos/ReCodEx/api/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/ReCodEx/api/teams","hooks_url":"https://api.github.com/repos/ReCodEx/api/hooks","issue_events_url":"https://api.github.com/repos/ReCodEx/api/issues/events{/number}","events_url":"https://api.github.com/repos/ReCodEx/api/events","assignees_url":"https://api.github.com/repos/ReCodEx/api/assignees{/user}","branches_url":"https://api.github.com/repos/ReCodEx/api/branches{/branch}","tags_url":"https://api.github.com/repos/ReCodEx/api/tags","blobs_url":"https://api.github.com/repos/ReCodEx/api/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/ReCodEx/api/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/ReCodEx/api/git/refs{/sha}","trees_url":"https://api.github.com/repos/ReCodEx/api/git/trees{/sha}","statuses_url":"https://api.github.com/repos/ReCodEx/api/statuses/{sha}","languages_url":"https://api.github.com/repos/ReCodEx/api/languages","stargazers_url":"https://api.github.com/repos/ReCodEx/api/stargazers","contributors_url":"https://api.github.com/repos/ReCodEx/api/contributors","subscribers_url":"https://api.github.com/repos/ReCodEx/api/subscribers","subscription_url":"https://api.github.com/repos/ReCodEx/api/subscription","commits_url":"https://api.github.com/repos/ReCodEx/api/commits{/sha}","git_commits_url":"https://api.github.com/repos/ReCodEx/api/git/commits{/sha}","comments_url":"https://api.github.com/repos/ReCodEx/api/comments{/number}","issue_comment_url":"https://api.github.com/repos/ReCodEx/api/issues/comments{/number}","contents_url":"https://api.github.com/repos/ReCodEx/api/contents/{+path}","compare_url":"https://api.github.com/repos/ReCodEx/api/compare/{base}...{head}","merges_url":"https://api.github.com/repos/ReCodEx/api/merges","archive_url":"https://api.github.com/repos/ReCodEx/api/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/ReCodEx/api/downloads","issues_url":"https://api.github.com/repos/ReCodEx/api/issues{/number}","pulls_url":"https://api.github.com/repos/ReCodEx/api/pulls{/number}","milestones_url":"https://api.github.com/repos/ReCodEx/api/milestones{/number}","notifications_url":"https://api.github.com/repos/ReCodEx/api/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/ReCodEx/api/labels{/name}","releases_url":"https://api.github.com/repos/ReCodEx/api/releases{/id}","deployments_url":"https://api.github.com/repos/ReCodEx/api/deployments","created_at":"2016-07-23T18:30:47Z","updated_at":"2018-10-23T08:44:47Z","pushed_at":"2018-10-23T08:44:45Z","git_url":"git://github.com/ReCodEx/api.git","ssh_url":"git@github.com:ReCodEx/api.git","clone_url":"https://github.com/ReCodEx/api.git","svn_url":"https://github.com/ReCodEx/api","homepage":"https://recodex.mff.cuni.cz/api/v1","size":6024,"stargazers_count":4,"watchers_count":4,"language":"PHP","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":true,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":1,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"forks":0,"open_issues":1,"watchers":4,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/ReCodEx/api/pulls/255"},"html":{"href":"https://github.com/ReCodEx/api/pull/255"},"issue":{"href":"https://api.github.com/repos/ReCodEx/api/issues/255"},"comments":{"href":"https://api.github.com/repos/ReCodEx/api/issues/255/comments"},"review_comments":{"href":"https://api.github.com/repos/ReCodEx/api/pulls/255/comments"},"review_comment":{"href":"https://api.github.com/repos/ReCodEx/api/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/ReCodEx/api/pulls/255/commits"},"statuses":{"href":"https://api.github.com/repos/ReCodEx/api/statuses/eee45350fa0ca96b4df2f78b0126a9a4bc02ac5b"}},"author_association":"MEMBER"}}
{"actor":{"display_login":"krulis-martin"}}