{"action":"created","comment":{"url":"https://api.github.com/repos/domokit/sky_engine/pulls/comments/37572869","id":37572869,"diff_hunk":"@@ -254,6 +284,359 @@ class StopSky(object):\n         pids.clear()\n \n \n+class IOSDevice(object):\n+    _has_ios_deploy = None\n+    @classmethod\n+    def has_ios_deploy(cls):\n+        if cls._has_ios_deploy is not None:\n+            return cls._has_ios_deploy\n+        cmd = [\n+            'which',\n+            'ios-deploy'\n+        ]\n+        process = subprocess.Popen(cmd, stdout=subprocess.PIPE)\n+        out, err = process.communicate()\n+        match = re.search(r'ios-deploy', out)\n+        cls._has_ios_deploy = match is not None\n+        return cls._has_ios_deploy\n+\n+    _is_connected = False\n+    @classmethod\n+    def is_connected(cls):\n+        if not cls.has_ios_deploy():\n+            return False\n+        if cls._is_connected:\n+            return True\n+        cmd = [\n+            'ios-deploy',\n+            '--detect',\n+            '--timeout',\n+            '1'\n+        ]\n+        process = subprocess.Popen(cmd, stdout=subprocess.PIPE)\n+        out, err = process.communicate()\n+        match = re.search(r'\\[\\.\\.\\.\\.\\] Found [^\\)]*\\) connected', out)\n+        cls._is_connected = match is not None\n+        return cls._is_connected\n+\n+    @classmethod\n+    def install_app(cls, ios_app_path):\n+        if not cls.has_ios_deploy():\n+            return\n+        cmd = [\n+            'ios-deploy',\n+            '--justlaunch',\n+            '--timeout',\n+            '10', # Smaller timeouts cause it to exit before having launched the app\n+            '--bundle',\n+            ios_app_path\n+        ]\n+        subprocess.check_call(cmd)\n+\n+    @classmethod\n+    def copy_file(cls, bundle_id, local_path, device_path):\n+        if not cls.has_ios_deploy():\n+            return\n+        cmd = [\n+            'ios-deploy',\n+            '-t',\n+            '1',\n+            '--bundle_id',\n+            bundle_id,\n+            '--upload',\n+            local_path,\n+            '--to',\n+            device_path\n+        ]\n+        subprocess.check_call(cmd)\n+\n+\n+class IOSSimulator(object):\n+    @classmethod\n+    def is_booted(cls):\n+        return cls.get_simulator_device_id() is not None\n+\n+    _device_id = None\n+    @classmethod\n+    def get_simulator_device_id(cls):\n+        if cls._device_id is not None:\n+            return cls._device_id\n+        cmd = [\n+            'xcrun',\n+            'simctl',\n+            'list',\n+            'devices',\n+        ]\n+        process = subprocess.Popen(cmd, stdout=subprocess.PIPE)\n+        out, err = process.communicate()\n+        match = re.search(r'[^\\(]+\\(([^\\)]+)\\) \\(Booted\\)', out)\n+        if match is not None and match.group(1) is not None:\n+            cls._device_id = match.group(1)\n+            return cls._device_id\n+        else:\n+            logging.warning('No running simulators found')\n+            # TODO: Maybe start the simulator?\n+            return None\n+        if err is not None:\n+            print(err)\n+            exit(-1)\n+\n+    _simulator_path = None\n+    @classmethod\n+    def get_simulator_path(cls):\n+        if cls._simulator_path is not None:\n+            return cls._simulator_path\n+        home_dir = os.path.expanduser(\"~\")\n+        device_id = cls.get_simulator_device_id()\n+        if device_id is None:\n+            # TODO: Maybe start the simulator?\n+            return None\n+        cls._simulator_path = home_dir + '/Library/Developer/CoreSimulator/Devices/' + device_id\n+        return cls._simulator_path\n+\n+    _simulator_app_id = None\n+    @classmethod\n+    def get_simulator_app_id(cls):\n+        if cls._simulator_app_id is not None:\n+            return cls._simulator_app_id\n+        simulator_path = cls.get_simulator_path()\n+        cmd = [\n+            'find',\n+            simulator_path + '/data/Containers/Data/Application',\n+            '-name',\n+            SKY_SHELL_APP_ID\n+        ]\n+        process = subprocess.Popen(cmd, stdout=subprocess.PIPE)\n+        out, err = process.communicate()\n+        match = re.search(r'Data\\/Application\\/([^\\/]+)\\/Documents\\/' + SKY_SHELL_APP_ID, out)\n+        if match is not None and match.group(1) is not None:\n+            cls._simulator_app_id = match.group(1)\n+            return cls._simulator_app_id\n+        else:\n+            logging.warning(SKY_SHELL_APP_ID + ' is not installed on the simulator')\n+            # TODO: Maybe install the app?\n+            return None\n+        if err is not None:\n+            print(err)\n+            exit(-1)\n+\n+    _simulator_app_documents_dir = None\n+    @classmethod\n+    def get_simulator_app_documents_dir(cls):\n+        if cls._simulator_app_documents_dir is not None:\n+            return cls._simulator_app_documents_dir\n+        if not cls.is_booted():\n+            return None\n+        simulator_path = cls.get_simulator_path()\n+        simulator_app_id = cls.get_simulator_app_id()\n+        if simulator_app_id is None:\n+            return None\n+        cls._simulator_app_documents_dir = simulator_path + '/data/Containers/Data/Application/' + simulator_app_id + '/Documents/'\n+        return cls._simulator_app_documents_dir\n+\n+    @classmethod\n+    def fork_install_app(cls, ios_app_path):\n+        cmd = [\n+            os.path.abspath(__file__),\n+            'ios_sim',\n+            '-p',\n+            # This path manipulation is to work around an issue where simctl fails to correctly parse\n+            # paths that start with ../\n+            ios_app_path,\n+            'launch'\n+        ]\n+        subprocess.check_call(cmd)\n+\n+    def get_application_identifier(self, path):\n+      identifier = subprocess.check_output( PLIST_BUDDY_PATH + [\n+        '-c',\n+        'Print CFBundleIdentifier',\n+        '%s/Info.plist' % path,\n+      ])\n+      return identifier.strip()\n+\n+    def is_simulator_booted(self):\n+      devices = subprocess.check_output( SIMCTL_PATH + [ 'list', 'devices' ]).strip().split('\\n')\n+      for device in devices:\n+        if re.search(r'\\(Booted\\)', device):\n+          return True\n+      return False\n+\n+    # Launch whatever simulator the user last used, rather than try to guess which of their simulators they might want to use\n+    def boot_simulator(self, args, pids):\n+      if self.is_simulator_booted():\n+        return\n+      # Use Popen here because launching the simulator from the command line in this manner doesn't return, so we can't check the result.\n+      if args.ios_sim_path:\n+        subprocess.Popen(args.ios_sim_path)\n+      else:\n+        subprocess.Popen(IOS_SIM_PATH)\n+      while not is_simulator_booted():\n+        print('Waiting for iOS Simulator to boot...')\n+        time.sleep(0.5)\n+\n+    def install_app(self, args, pids):\n+      self.boot_simulator(args, pids)\n+      cmd = SIMCTL_PATH + [\n+        'install',\n+        'booted',\n+        args.path,\n+      ]\n+      return subprocess.check_call(cmd)\n+\n+    def install_launch_and_wait(self, args, pids, wait):\n+      res = self.install_app(args, pids)\n+      if res != 0:\n+        return res\n+      identifier = self.get_application_identifier(args.path)\n+      launch_args = [ 'launch' ]\n+      if wait:\n+        launch_args += [ '-w' ]\n+      launch_args += [\n+        'booted',\n+        identifier,\n+        '-target',\n+        args.target,\n+        '-server',\n+        args.server\n+      ]\n+      return subprocess.check_output( SIMCTL_PATH + launch_args ).strip()\n+\n+    def launch_app(self, args, pids):\n+      self.install_launch_and_wait(args, pids, False)\n+\n+    def debug_app(self, args, pids):\n+      launch_res = self.install_launch_and_wait(args, pids, True)\n+      launch_pid = re.search('.*: (\\d+)', launch_res).group(1)\n+      return os.system(' '.join([\n+        '/usr/bin/env',\n+        'xcrun',\n+        'lldb',\n+        # TODO(iansf): get this working again\n+        # '-s',\n+        # os.path.join(os.path.dirname(__file__), 'lldb_start_commands.txt'),\n+        '-p',\n+        launch_pid,\n+      ]))\n+\n+    def add_subparser(self, subparsers):\n+        simulator_parser = subparsers.add_parser('ios_sim',\n+            help='A script that launches an'\n+                 ' application in the simulator and attaches'\n+                 ' the debugger to it.')\n+        simulator_parser.add_argument('-p', dest='path', required=True,\n+            help='Path to the simulator application.')\n+        simulator_parser.add_argument('-t', dest='target', required=False,\n+            default='examples/demo_launcher/lib/main.dart',\n+            help='Sky server-relative path to the Sky app to run.')\n+        simulator_parser.add_argument('-s', dest='server', required=False,\n+            default='localhost:8080',\n+            help='Sky server address.')\n+        simulator_parser.add_argument('--ios_sim_path', dest='ios_sim_path',\n+            help='Path to your iOS Simulator executable. '\n+                 'Not normally required.')\n+\n+        subparsers = simulator_parser.add_subparsers()\n+        launch_parser = subparsers.add_parser('launch', help='Launch app')\n+        launch_parser.set_defaults(func=self.launch_app)\n+        install_parser = subparsers.add_parser('install', help='Install app')\n+        install_parser.set_defaults(func=self.install_app)\n+        debug_parser = subparsers.add_parser('debug', help='Debug app')\n+        debug_parser.set_defaults(func=self.debug_app)\n+\n+    def run(self, args, pids):\n+      return args.func(args)\n+\n+\n+class StartListening(object):\n+    def add_subparser(self, subparsers):\n+        listen_parser = subparsers.add_parser('listen',\n+            help=('Listen for changes to files and reload the running app on all connected devices'))\n+        listen_parser.set_defaults(func=self.run)\n+\n+    def run(self, args, pids):\n+        cmd = [\n+            'which',\n+            'fswatch'\n+        ]\n+        process = subprocess.Popen(cmd, stdout=subprocess.PIPE)\n+        out, err = process.communicate()\n+        match = re.search(r'fswatch', out)\n+        if match is None:\n+            logging.error('\"listen\" command is only useful if you have installed fswatch.  Run \"brew install fswatch\" to install it with homebrew.')\n+            return\n+\n+        tempdir = None\n+        currdir = None\n+        while True:\n+            # Watch filesystem for changes\n+            cmd = [\n+                'fswatch',\n+                '-r',\n+                '-v',\n+                '-1',\n+                '.'\n+            ]\n+            subprocess.check_call(cmd)\n+\n+            logging.info('Updating running Sky apps...')\n+\n+            # Restart the app on Android.  Android does not currently restart using skyx files.\n+            cmd = [\n+                os.path.abspath(__file__),\n+                'start',\n+                '--poke'\n+            ]\n+            subprocess.check_call(cmd)\n+\n+            if not args.local_build:\n+                # Currently sending to iOS only works if you are building Sky locally\n+                # since we aren't shipping the sky_snapshot binary yet.\n+                continue\n+\n+            if tempdir is None:\n+                tempdir = tempfile.mkdtemp()","path":"sky/packages/sky/lib/sky_tool","position":406,"original_position":406,"commit_id":"1db1e3c5e9f2974076289492baf818a86f17b345","original_commit_id":"1db1e3c5e9f2974076289492baf818a86f17b345","user":{"login":"iansf","id":12631059,"avatar_url":"https://avatars.githubusercontent.com/u/12631059?v=3","gravatar_id":"","url":"https://api.github.com/users/iansf","html_url":"https://github.com/iansf","followers_url":"https://api.github.com/users/iansf/followers","following_url":"https://api.github.com/users/iansf/following{/other_user}","gists_url":"https://api.github.com/users/iansf/gists{/gist_id}","starred_url":"https://api.github.com/users/iansf/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/iansf/subscriptions","organizations_url":"https://api.github.com/users/iansf/orgs","repos_url":"https://api.github.com/users/iansf/repos","events_url":"https://api.github.com/users/iansf/events{/privacy}","received_events_url":"https://api.github.com/users/iansf/received_events","type":"User","site_admin":false},"body":"Cool -- thanks!","created_at":"2015-08-20T19:46:48Z","updated_at":"2015-08-20T19:46:48Z","html_url":"https://github.com/domokit/sky_engine/pull/719#discussion_r37572869","pull_request_url":"https://api.github.com/repos/domokit/sky_engine/pulls/719","_links":{"self":{"href":"https://api.github.com/repos/domokit/sky_engine/pulls/comments/37572869"},"html":{"href":"https://github.com/domokit/sky_engine/pull/719#discussion_r37572869"},"pull_request":{"href":"https://api.github.com/repos/domokit/sky_engine/pulls/719"}}},"pull_request":{"url":"https://api.github.com/repos/domokit/sky_engine/pulls/719","id":42968143,"html_url":"https://github.com/domokit/sky_engine/pull/719","diff_url":"https://github.com/domokit/sky_engine/pull/719.diff","patch_url":"https://github.com/domokit/sky_engine/pull/719.patch","issue_url":"https://api.github.com/repos/domokit/sky_engine/issues/719","number":719,"state":"open","locked":false,"title":"Add listen command to sky_tool, and related changes.","user":{"login":"iansf","id":12631059,"avatar_url":"https://avatars.githubusercontent.com/u/12631059?v=3","gravatar_id":"","url":"https://api.github.com/users/iansf","html_url":"https://github.com/iansf","followers_url":"https://api.github.com/users/iansf/followers","following_url":"https://api.github.com/users/iansf/following{/other_user}","gists_url":"https://api.github.com/users/iansf/gists{/gist_id}","starred_url":"https://api.github.com/users/iansf/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/iansf/subscriptions","organizations_url":"https://api.github.com/users/iansf/orgs","repos_url":"https://api.github.com/users/iansf/repos","events_url":"https://api.github.com/users/iansf/events{/privacy}","received_events_url":"https://api.github.com/users/iansf/received_events","type":"User","site_admin":false},"body":null,"created_at":"2015-08-20T19:26:40Z","updated_at":"2015-08-20T19:46:48Z","closed_at":null,"merged_at":null,"merge_commit_sha":"4583b96765b3534aee2fa502727757fb2ec0d392","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/domokit/sky_engine/pulls/719/commits","review_comments_url":"https://api.github.com/repos/domokit/sky_engine/pulls/719/comments","review_comment_url":"https://api.github.com/repos/domokit/sky_engine/pulls/comments{/number}","comments_url":"https://api.github.com/repos/domokit/sky_engine/issues/719/comments","statuses_url":"https://api.github.com/repos/domokit/sky_engine/statuses/1db1e3c5e9f2974076289492baf818a86f17b345","head":{"label":"iansf:add_listen_command","ref":"add_listen_command","sha":"1db1e3c5e9f2974076289492baf818a86f17b345","user":{"login":"iansf","id":12631059,"avatar_url":"https://avatars.githubusercontent.com/u/12631059?v=3","gravatar_id":"","url":"https://api.github.com/users/iansf","html_url":"https://github.com/iansf","followers_url":"https://api.github.com/users/iansf/followers","following_url":"https://api.github.com/users/iansf/following{/other_user}","gists_url":"https://api.github.com/users/iansf/gists{/gist_id}","starred_url":"https://api.github.com/users/iansf/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/iansf/subscriptions","organizations_url":"https://api.github.com/users/iansf/orgs","repos_url":"https://api.github.com/users/iansf/repos","events_url":"https://api.github.com/users/iansf/events{/privacy}","received_events_url":"https://api.github.com/users/iansf/received_events","type":"User","site_admin":false},"repo":{"id":39264948,"name":"sky_engine","full_name":"iansf/sky_engine","owner":{"login":"iansf","id":12631059,"avatar_url":"https://avatars.githubusercontent.com/u/12631059?v=3","gravatar_id":"","url":"https://api.github.com/users/iansf","html_url":"https://github.com/iansf","followers_url":"https://api.github.com/users/iansf/followers","following_url":"https://api.github.com/users/iansf/following{/other_user}","gists_url":"https://api.github.com/users/iansf/gists{/gist_id}","starred_url":"https://api.github.com/users/iansf/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/iansf/subscriptions","organizations_url":"https://api.github.com/users/iansf/orgs","repos_url":"https://api.github.com/users/iansf/repos","events_url":"https://api.github.com/users/iansf/events{/privacy}","received_events_url":"https://api.github.com/users/iansf/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/iansf/sky_engine","description":"The Sky engine","fork":true,"url":"https://api.github.com/repos/iansf/sky_engine","forks_url":"https://api.github.com/repos/iansf/sky_engine/forks","keys_url":"https://api.github.com/repos/iansf/sky_engine/keys{/key_id}","collaborators_url":"https://api.github.com/repos/iansf/sky_engine/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/iansf/sky_engine/teams","hooks_url":"https://api.github.com/repos/iansf/sky_engine/hooks","issue_events_url":"https://api.github.com/repos/iansf/sky_engine/issues/events{/number}","events_url":"https://api.github.com/repos/iansf/sky_engine/events","assignees_url":"https://api.github.com/repos/iansf/sky_engine/assignees{/user}","branches_url":"https://api.github.com/repos/iansf/sky_engine/branches{/branch}","tags_url":"https://api.github.com/repos/iansf/sky_engine/tags","blobs_url":"https://api.github.com/repos/iansf/sky_engine/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/iansf/sky_engine/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/iansf/sky_engine/git/refs{/sha}","trees_url":"https://api.github.com/repos/iansf/sky_engine/git/trees{/sha}","statuses_url":"https://api.github.com/repos/iansf/sky_engine/statuses/{sha}","languages_url":"https://api.github.com/repos/iansf/sky_engine/languages","stargazers_url":"https://api.github.com/repos/iansf/sky_engine/stargazers","contributors_url":"https://api.github.com/repos/iansf/sky_engine/contributors","subscribers_url":"https://api.github.com/repos/iansf/sky_engine/subscribers","subscription_url":"https://api.github.com/repos/iansf/sky_engine/subscription","commits_url":"https://api.github.com/repos/iansf/sky_engine/commits{/sha}","git_commits_url":"https://api.github.com/repos/iansf/sky_engine/git/commits{/sha}","comments_url":"https://api.github.com/repos/iansf/sky_engine/comments{/number}","issue_comment_url":"https://api.github.com/repos/iansf/sky_engine/issues/comments{/number}","contents_url":"https://api.github.com/repos/iansf/sky_engine/contents/{+path}","compare_url":"https://api.github.com/repos/iansf/sky_engine/compare/{base}...{head}","merges_url":"https://api.github.com/repos/iansf/sky_engine/merges","archive_url":"https://api.github.com/repos/iansf/sky_engine/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/iansf/sky_engine/downloads","issues_url":"https://api.github.com/repos/iansf/sky_engine/issues{/number}","pulls_url":"https://api.github.com/repos/iansf/sky_engine/pulls{/number}","milestones_url":"https://api.github.com/repos/iansf/sky_engine/milestones{/number}","notifications_url":"https://api.github.com/repos/iansf/sky_engine/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/iansf/sky_engine/labels{/name}","releases_url":"https://api.github.com/repos/iansf/sky_engine/releases{/id}","created_at":"2015-07-17T16:51:06Z","updated_at":"2015-07-17T16:51:25Z","pushed_at":"2015-08-20T19:26:18Z","git_url":"git://github.com/iansf/sky_engine.git","ssh_url":"git@github.com:iansf/sky_engine.git","clone_url":"https://github.com/iansf/sky_engine.git","svn_url":"https://github.com/iansf/sky_engine","homepage":null,"size":71136,"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":"domokit:master","ref":"master","sha":"7dfac2f1ca094a8ded29b053103da17875a1fc7d","user":{"login":"domokit","id":8664152,"avatar_url":"https://avatars.githubusercontent.com/u/8664152?v=3","gravatar_id":"","url":"https://api.github.com/users/domokit","html_url":"https://github.com/domokit","followers_url":"https://api.github.com/users/domokit/followers","following_url":"https://api.github.com/users/domokit/following{/other_user}","gists_url":"https://api.github.com/users/domokit/gists{/gist_id}","starred_url":"https://api.github.com/users/domokit/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/domokit/subscriptions","organizations_url":"https://api.github.com/users/domokit/orgs","repos_url":"https://api.github.com/users/domokit/repos","events_url":"https://api.github.com/users/domokit/events{/privacy}","received_events_url":"https://api.github.com/users/domokit/received_events","type":"Organization","site_admin":false},"repo":{"id":39211337,"name":"sky_engine","full_name":"domokit/sky_engine","owner":{"login":"domokit","id":8664152,"avatar_url":"https://avatars.githubusercontent.com/u/8664152?v=3","gravatar_id":"","url":"https://api.github.com/users/domokit","html_url":"https://github.com/domokit","followers_url":"https://api.github.com/users/domokit/followers","following_url":"https://api.github.com/users/domokit/following{/other_user}","gists_url":"https://api.github.com/users/domokit/gists{/gist_id}","starred_url":"https://api.github.com/users/domokit/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/domokit/subscriptions","organizations_url":"https://api.github.com/users/domokit/orgs","repos_url":"https://api.github.com/users/domokit/repos","events_url":"https://api.github.com/users/domokit/events{/privacy}","received_events_url":"https://api.github.com/users/domokit/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/domokit/sky_engine","description":"The Sky engine","fork":false,"url":"https://api.github.com/repos/domokit/sky_engine","forks_url":"https://api.github.com/repos/domokit/sky_engine/forks","keys_url":"https://api.github.com/repos/domokit/sky_engine/keys{/key_id}","collaborators_url":"https://api.github.com/repos/domokit/sky_engine/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/domokit/sky_engine/teams","hooks_url":"https://api.github.com/repos/domokit/sky_engine/hooks","issue_events_url":"https://api.github.com/repos/domokit/sky_engine/issues/events{/number}","events_url":"https://api.github.com/repos/domokit/sky_engine/events","assignees_url":"https://api.github.com/repos/domokit/sky_engine/assignees{/user}","branches_url":"https://api.github.com/repos/domokit/sky_engine/branches{/branch}","tags_url":"https://api.github.com/repos/domokit/sky_engine/tags","blobs_url":"https://api.github.com/repos/domokit/sky_engine/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/domokit/sky_engine/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/domokit/sky_engine/git/refs{/sha}","trees_url":"https://api.github.com/repos/domokit/sky_engine/git/trees{/sha}","statuses_url":"https://api.github.com/repos/domokit/sky_engine/statuses/{sha}","languages_url":"https://api.github.com/repos/domokit/sky_engine/languages","stargazers_url":"https://api.github.com/repos/domokit/sky_engine/stargazers","contributors_url":"https://api.github.com/repos/domokit/sky_engine/contributors","subscribers_url":"https://api.github.com/repos/domokit/sky_engine/subscribers","subscription_url":"https://api.github.com/repos/domokit/sky_engine/subscription","commits_url":"https://api.github.com/repos/domokit/sky_engine/commits{/sha}","git_commits_url":"https://api.github.com/repos/domokit/sky_engine/git/commits{/sha}","comments_url":"https://api.github.com/repos/domokit/sky_engine/comments{/number}","issue_comment_url":"https://api.github.com/repos/domokit/sky_engine/issues/comments{/number}","contents_url":"https://api.github.com/repos/domokit/sky_engine/contents/{+path}","compare_url":"https://api.github.com/repos/domokit/sky_engine/compare/{base}...{head}","merges_url":"https://api.github.com/repos/domokit/sky_engine/merges","archive_url":"https://api.github.com/repos/domokit/sky_engine/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/domokit/sky_engine/downloads","issues_url":"https://api.github.com/repos/domokit/sky_engine/issues{/number}","pulls_url":"https://api.github.com/repos/domokit/sky_engine/pulls{/number}","milestones_url":"https://api.github.com/repos/domokit/sky_engine/milestones{/number}","notifications_url":"https://api.github.com/repos/domokit/sky_engine/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/domokit/sky_engine/labels{/name}","releases_url":"https://api.github.com/repos/domokit/sky_engine/releases{/id}","created_at":"2015-07-16T17:39:56Z","updated_at":"2015-08-20T06:11:46Z","pushed_at":"2015-08-20T19:32:52Z","git_url":"git://github.com/domokit/sky_engine.git","ssh_url":"git@github.com:domokit/sky_engine.git","clone_url":"https://github.com/domokit/sky_engine.git","svn_url":"https://github.com/domokit/sky_engine","homepage":null,"size":80513,"stargazers_count":138,"watchers_count":138,"language":"C++","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":47,"mirror_url":null,"open_issues_count":151,"forks":47,"open_issues":151,"watchers":138,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/domokit/sky_engine/pulls/719"},"html":{"href":"https://github.com/domokit/sky_engine/pull/719"},"issue":{"href":"https://api.github.com/repos/domokit/sky_engine/issues/719"},"comments":{"href":"https://api.github.com/repos/domokit/sky_engine/issues/719/comments"},"review_comments":{"href":"https://api.github.com/repos/domokit/sky_engine/pulls/719/comments"},"review_comment":{"href":"https://api.github.com/repos/domokit/sky_engine/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/domokit/sky_engine/pulls/719/commits"},"statuses":{"href":"https://api.github.com/repos/domokit/sky_engine/statuses/1db1e3c5e9f2974076289492baf818a86f17b345"}}}}