{"action":"created","comment":{"url":"https://api.github.com/repos/mundya/rig/pulls/comments/25495046","id":25495046,"diff_hunk":"@@ -0,0 +1,382 @@\n+import collections\n+import pkg_resources\n+import socket\n+import struct\n+\n+from .consts import SCPCommands, DataType\n+from . import boot, consts\n+from .scp_connection import SCPConnection\n+from rig.utils.contexts import ContextMixin, Required\n+\n+\n+class MachineController(ContextMixin):\n+    \"\"\"TODO\n+\n+    Attributes\n+    ----------\n+    \"\"\"\n+    def __init__(self, initial_host, n_tries=5, timeout=0.5, app_id=None,\n+                 boot_data=None, struct_data=None):\n+        \"\"\"Create a new controller for a SpiNNaker machine.\n+\n+        Parameters\n+        ----------\n+        initial_host : string\n+        n_tries : int\n+        timeout : float\n+        app_id : int or None\n+        boot_data : bytes or None\n+            Data to boot the machine with.  If None then the default boot file\n+            provided with rig will be used.\n+        struct_data : bytes or None\n+            Data to interpret as a representation of the memory layout of data\n+            within the memory of a running core.  If None then the default\n+            struct file provided with rig will be used.\n+        \"\"\"\n+        # Initialise the context stack\n+        ContextMixin.__init__(self, {app_id: app_id})\n+\n+        # Store the initial parameters\n+        self.initial_host = initial_host\n+        self.n_tries = n_tries\n+        self.timeout = timeout\n+        self.app_id = app_id\n+\n+        # Store the struct and boot data\n+        if struct_data is None:\n+            struct_data = pkg_resources.resource_string(\"rig\",\n+                                                        \"boot/sark.struct\")\n+        self.struct_data = struct_data\n+\n+        if boot_data is None:\n+            boot_data = pkg_resources.resource_string(\"rig\", \"boot/scamp.boot\")\n+        self.boot_data = boot_data\n+\n+        # Create the initial connection\n+        self.connections = [\n+            SCPConnection(initial_host, n_tries, timeout)\n+        ]\n+\n+    def __call__(self, **context_args):\n+        \"\"\"Create a new context for use with `with`.\n+\n+        E.g:\n+            with controller(x=3, y=4):\n+                # All commands will now communicate with chip (3, 4)\n+        \"\"\"\n+        return self.get_new_context(**context_args)\n+\n+    def send_scp(self, x, y, *args, **kwargs):\n+        \"\"\"Determine the best connection to use to send an SCP packet and use\n+        it to transmit.\n+\n+        See the arguments for\n+        :py:method:`~rig.machine_controller.scp_connection.SCPConnection` for\n+        details.\n+        \"\"\"\n+        return self.connections[0].send_scp(x, y, *args, **kwargs)\n+\n+    def boot(self, width, height, **boot_kwargs):\n+        \"\"\"Boot a SpiNNaker machine of the given size.\n+\n+        Parameters\n+        ----------\n+        width : int\n+            Width of the machine (0 < w < 256)\n+        height : int\n+            Height of the machine (0 < h < 256)\n+\n+        For further boot arguments see\n+        :py:func:`~rig.machine_controller.boot.boot`.  **Regardless** of the\n+        values passed to this method the struct and boot data from `__init__`\n+        will be used.\n+\n+        Notes\n+        -----\n+        The constants `rig.boot.spinX_boot_options` can be used to specify boot\n+        parameters, for example:\n+\n+            controller.boot(**spin5_boot_options)\n+\n+        Will boot the Spin5 board connected to by `controller`.\n+        \"\"\"\n+        boot_kwargs.update({\n+            \"boot_data\": self.boot_data,\n+            \"struct_data\": self.struct_data,\n+        })\n+        boot.boot(self.initial_host, width=width, height=height, **boot_kwargs)\n+\n+    @ContextMixin.use_contextual_arguments\n+    def software_version(self, x=Required, y=Required, processor=0):\n+        \"\"\"Get the software version for a given SpiNNaker core.\n+        \"\"\"\n+        sver = self.send_scp(x, y, processor, SCPCommands.sver)\n+\n+        # Format the result\n+        # arg1 => p2p address, physical cpu, virtual cpu\n+        p2p = sver.arg1 >> 16\n+        pcpu = (sver.arg1 >> 8) & 0xff\n+        vcpu = sver.arg1 & 0xff\n+\n+        # arg2 => version number and buffer size\n+        version = (sver.arg2 >> 16) / 100.\n+        buffer_size = (sver.arg2 & 0xffff)\n+\n+        return CoreInfo(p2p, pcpu, vcpu, version, buffer_size, sver.arg3,\n+                        sver.data)\n+\n+    @ContextMixin.use_contextual_arguments\n+    def write(self, address, data, x=Required, y=Required, p=Required):\n+        \"\"\"Write a bytestring to an address in memory.\n+\n+        Parameters\n+        ----------\n+        address : int\n+            The address at which to start writing the data.\n+        data : :py:class:`bytes`\n+            Data to write into memory.\n+        \"\"\"\n+        # While there is still data perform a write: get the block to write\n+        # this time around, determine the data type, perform the write and\n+        # increment the address\n+        while len(data) > 0:\n+            block, data = data[:256], data[256:]\n+            dtype = address_length_dtype[(address % 4, len(block) % 4)]\n+            self._write(x, y, p, address, block, dtype)\n+            address += len(block)\n+\n+    def _write(self, x, y, p, address, data, data_type=DataType.byte):\n+        \"\"\"Write a bytestring to an address in memory.\n+\n+        It is better to use :py:func:`~.write` which wraps this method and\n+        allows writing bytestrings of arbitrary length.\n+\n+        Parameters\n+        ----------\n+        address : int\n+            The address at which to start writing the data.\n+        data : :py:class:`bytes`\n+            Data to write into memory.  Must be <= 256 bytes.\n+        data_type : :py:class:`~rig.machine_controller.consts.DataType`\n+            The size of the data to write into memory.\n+        \"\"\"\n+        length_bytes = len(data)\n+        self.send_scp(x, y, p, SCPCommands.write, address, length_bytes,\n+                      int(data_type), data, expected_args=0)\n+\n+    @ContextMixin.use_contextual_arguments\n+    def read(self, address, length_bytes, x=Required, y=Required, p=Required):\n+        \"\"\"Read a bytestring from an address in memory.\n+\n+        Parameters\n+        ----------\n+        address : int\n+            The address at which to start reading the data.\n+        length_bytes : int\n+            The number of bytes to read from memory.\n+\n+        Returns\n+        -------\n+        :py:class:`bytes`\n+            The data is read back from memory as a bytestring.\n+        \"\"\"\n+        # Make calls to the lower level read method until we have read\n+        # sufficient bytes.\n+        data = b''\n+        while len(data) < length_bytes:\n+            # Determine the number of bytes to read\n+            reads = min(256, length_bytes - len(data))\n+\n+            # Determine the data type to use\n+            dtype = address_length_dtype[(address % 4, reads % 4)]\n+\n+            # Perform the read and increment the address\n+            data += self._read(x, y, p, address, reads, dtype)\n+            address += reads\n+\n+        return data\n+\n+    def _read(self, x, y, p, address, length_bytes, data_type=DataType.byte):\n+        \"\"\"Read a bytestring from an address in memory.\n+\n+        It is better to use :py:func:`~.read` which wraps this method and\n+        allows reading bytestrings of arbitrary length.\n+\n+        Parameters\n+        ----------\n+        address : int\n+            The address at which to start reading the data.\n+        length_bytes : int\n+            The number of bytes to read from memory, must be <= 256.\n+        data_type : DataType\n+            The size of the data to write into memory.\n+\n+        Returns\n+        -------\n+        :py:class:`bytes`\n+            The data is read back from memory as a bytestring.\n+        \"\"\"\n+        read_scp = self.send_scp(x, y, p, SCPCommands.read, address,\n+                                 length_bytes, int(data_type),\n+                                 expected_args=0)\n+        return read_scp.data\n+\n+    @ContextMixin.use_contextual_arguments\n+    def iptag_set(self, iptag, addr, port, x=Required, y=Required):\n+        \"\"\"Set the value of an IPTag.\n+\n+        Parameters\n+        ----------\n+        iptag : int\n+            Index of the IPTag to set\n+        \"\"\"\n+        # Format the IP address\n+        ip_addr = struct.pack('!4B',\n+                              *map(int, socket.gethostbyname(addr).split('.')))\n+        self.send_scp(x, y, 0, SCPCommands.iptag,\n+                      int(consts.IPTagCommands.set) << 16 | iptag,\n+                      port, struct.unpack('<I', ip_addr)[0])\n+\n+    @ContextMixin.use_contextual_arguments\n+    def iptag_get(self, iptag, x=Required, y=Required):\n+        \"\"\"Get the value of an IPTag.\n+\n+        Parameters\n+        ----------\n+        iptag : int\n+            Index of the IPTag to get\n+\n+        Returns\n+        -------\n+        :py:class:`IPTag`\n+            The IPTag returned from SpiNNaker.\n+        \"\"\"\n+        ack = self.send_scp(x, y, 0, SCPCommands.iptag,\n+                            int(consts.IPTagCommands.get) << 16 | iptag, 1,\n+                            expected_args=0)\n+        return IPTag.from_bytestring(ack.data)\n+\n+    @ContextMixin.use_contextual_arguments\n+    def iptag_clear(self, iptag, x=Required, y=Required):\n+        \"\"\"Clear an IPTag.\n+\n+        Parameters\n+        ----------\n+        iptag : int\n+            Index of the IPTag to clear.\n+        \"\"\"\n+        self.send_scp(x, y, 0, SCPCommands.iptag,\n+                      int(consts.IPTagCommands.clear) << 16 | iptag)\n+\n+    @ContextMixin.use_contextual_arguments\n+    def led_on(self, led, x=Required, y=Required):\n+        \"\"\"Turn an LED on.\n+\n+        Parameters\n+        ----------\n+        led : int\n+            Number of the LED to set the state of (0-3)\n+        \"\"\"\n+        arg1 = int(consts.LEDAction.on) << (led * 2)\n+        self.send_scp(x, y, 0, SCPCommands.led, arg1=arg1, expected_args=0)\n+\n+    @ContextMixin.use_contextual_arguments\n+    def led_off(self, led, x=Required, y=Required):\n+        \"\"\"Turn an LED off.\n+\n+        Parameters\n+        ----------\n+        led : int\n+            Number of the LED to set the state of (0-3)\n+        \"\"\"\n+        arg1 = int(consts.LEDAction.off) << (led * 2)\n+        self.send_scp(x, y, 0, SCPCommands.led, arg1=arg1, expected_args=0)\n+\n+    @ContextMixin.use_contextual_arguments\n+    def led_toggle(self, led, x=Required, y=Required):\n+        \"\"\"Toggle the state of an LED.\n+\n+        Parameters\n+        ----------\n+        led : int\n+            Number of the LED to set the state of (0-3)\n+        \"\"\"\n+        arg1 = int(consts.LEDAction.toggle) << (led * 2)\n+        self.send_scp(x, y, 0, SCPCommands.led, arg1=arg1, expected_args=0)\n+\n+    @ContextMixin.use_contextual_arguments\n+    def sdram_alloc(self, size, tag=0, x=Required, y=Required,\n+                    app_id=Required):\n+        \"\"\"Allocate a region of SDRAM for the given application.\n+\n+        Parameters\n+        ----------\n+        size : int\n+            Number of bytes to attempt to allocate in SDRAM.\n+        tag : int\n+            8-bit tag that can be used identify the region of memory later.  If\n+            `0` then no tag is applied.\n+\n+        Returns\n+        -------\n+        int\n+            Address of the start of the region.\n+\n+        Raises\n+        ------\n+        SpiNNakerMemoryError\n+            If the memory cannot be allocated, or the tag is already taken or\n+            invalid.\n+        \"\"\"\n+        assert 0 <= tag < 256\n+\n+        # Construct arg1 (op_code << 8) | app_id\n+        arg1 = (consts.AllocOperations.alloc_sdram << 8 |\n+                (self.app_id if app_id is None else app_id))\n+\n+        # Send the packet and retrieve the address\n+        rv = self.send_scp(x, y, 0, SCPCommands.alloc_free, arg1, size, tag)\n+        if rv.arg1 == 0:\n+            # Allocation failed\n+            raise SpiNNakerMemoryError(size, x, y)\n+        return rv.arg1\n+\n+CoreInfo = collections.namedtuple(\n+    'CoreInfo', \"p2p_address physical_cpu virt_cpu version \"\n+                \"buffer_size build_date version_string\")\n+\n+\n+class IPTag(collections.namedtuple(\"IPTag\",\n+                                   \"addr max port timeout flags count rx_port \"\n+                                   \"spin_addr spin_port\")):\n+    \"\"\"An IPTag as read from a SpiNNaker machine.\"\"\"\n+    @classmethod\n+    def from_bytestring(cls, bytestring):\n+        (ip, max, port, timeout, flags, count, rx_port, spin_addr,\n+         spin_port) = struct.unpack(\"4s 6s 3H I 2H B\", bytestring[:25])","path":"rig/machine_control/machine_controller.py","position":356,"original_position":356,"commit_id":"2fd1fc9b4c3967c4b8a389b6e5e6fb953fbcb35a","original_commit_id":"2fd1fc9b4c3967c4b8a389b6e5e6fb953fbcb35a","user":{"login":"mossblaser","id":193514,"avatar_url":"https://avatars.githubusercontent.com/u/193514?v=3","gravatar_id":"","url":"https://api.github.com/users/mossblaser","html_url":"https://github.com/mossblaser","followers_url":"https://api.github.com/users/mossblaser/followers","following_url":"https://api.github.com/users/mossblaser/following{/other_user}","gists_url":"https://api.github.com/users/mossblaser/gists{/gist_id}","starred_url":"https://api.github.com/users/mossblaser/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mossblaser/subscriptions","organizations_url":"https://api.github.com/users/mossblaser/orgs","repos_url":"https://api.github.com/users/mossblaser/repos","events_url":"https://api.github.com/users/mossblaser/events{/privacy}","received_events_url":"https://api.github.com/users/mossblaser/received_events","type":"User","site_admin":false},"body":"Struct format should start with \"<\" to force little-endian, standard-sizes and no alignment.","created_at":"2015-02-27T09:19:58Z","updated_at":"2015-02-27T09:19:58Z","html_url":"https://github.com/mundya/rig/pull/29#discussion_r25495046","pull_request_url":"https://api.github.com/repos/mundya/rig/pulls/29","_links":{"self":{"href":"https://api.github.com/repos/mundya/rig/pulls/comments/25495046"},"html":{"href":"https://github.com/mundya/rig/pull/29#discussion_r25495046"},"pull_request":{"href":"https://api.github.com/repos/mundya/rig/pulls/29"}}},"pull_request":{"url":"https://api.github.com/repos/mundya/rig/pulls/29","id":30086833,"html_url":"https://github.com/mundya/rig/pull/29","diff_url":"https://github.com/mundya/rig/pull/29.diff","patch_url":"https://github.com/mundya/rig/pull/29.patch","issue_url":"https://api.github.com/repos/mundya/rig/issues/29","number":29,"state":"open","locked":false,"title":"Refactor of SCP code","user":{"login":"mossblaser","id":193514,"avatar_url":"https://avatars.githubusercontent.com/u/193514?v=3","gravatar_id":"","url":"https://api.github.com/users/mossblaser","html_url":"https://github.com/mossblaser","followers_url":"https://api.github.com/users/mossblaser/followers","following_url":"https://api.github.com/users/mossblaser/following{/other_user}","gists_url":"https://api.github.com/users/mossblaser/gists{/gist_id}","starred_url":"https://api.github.com/users/mossblaser/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mossblaser/subscriptions","organizations_url":"https://api.github.com/users/mossblaser/orgs","repos_url":"https://api.github.com/users/mossblaser/repos","events_url":"https://api.github.com/users/mossblaser/events{/privacy}","received_events_url":"https://api.github.com/users/mossblaser/received_events","type":"User","site_admin":false},"body":"","created_at":"2015-02-26T15:29:01Z","updated_at":"2015-02-27T09:19:58Z","closed_at":null,"merged_at":null,"merge_commit_sha":"72d6d327418dcb5cd68f1a55e23f16a95d177583","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/mundya/rig/pulls/29/commits","review_comments_url":"https://api.github.com/repos/mundya/rig/pulls/29/comments","review_comment_url":"https://api.github.com/repos/mundya/rig/pulls/comments{/number}","comments_url":"https://api.github.com/repos/mundya/rig/issues/29/comments","statuses_url":"https://api.github.com/repos/mundya/rig/statuses/2fd1fc9b4c3967c4b8a389b6e5e6fb953fbcb35a","head":{"label":"mundya:scp_refactor2","ref":"scp_refactor2","sha":"2fd1fc9b4c3967c4b8a389b6e5e6fb953fbcb35a","user":{"login":"mundya","id":3439837,"avatar_url":"https://avatars.githubusercontent.com/u/3439837?v=3","gravatar_id":"","url":"https://api.github.com/users/mundya","html_url":"https://github.com/mundya","followers_url":"https://api.github.com/users/mundya/followers","following_url":"https://api.github.com/users/mundya/following{/other_user}","gists_url":"https://api.github.com/users/mundya/gists{/gist_id}","starred_url":"https://api.github.com/users/mundya/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mundya/subscriptions","organizations_url":"https://api.github.com/users/mundya/orgs","repos_url":"https://api.github.com/users/mundya/repos","events_url":"https://api.github.com/users/mundya/events{/privacy}","received_events_url":"https://api.github.com/users/mundya/received_events","type":"User","site_admin":false},"repo":{"id":29497314,"name":"rig","full_name":"mundya/rig","owner":{"login":"mundya","id":3439837,"avatar_url":"https://avatars.githubusercontent.com/u/3439837?v=3","gravatar_id":"","url":"https://api.github.com/users/mundya","html_url":"https://github.com/mundya","followers_url":"https://api.github.com/users/mundya/followers","following_url":"https://api.github.com/users/mundya/following{/other_user}","gists_url":"https://api.github.com/users/mundya/gists{/gist_id}","starred_url":"https://api.github.com/users/mundya/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mundya/subscriptions","organizations_url":"https://api.github.com/users/mundya/orgs","repos_url":"https://api.github.com/users/mundya/repos","events_url":"https://api.github.com/users/mundya/events{/privacy}","received_events_url":"https://api.github.com/users/mundya/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/mundya/rig","description":"A set of tools for rigging SpiNNaker programs.","fork":false,"url":"https://api.github.com/repos/mundya/rig","forks_url":"https://api.github.com/repos/mundya/rig/forks","keys_url":"https://api.github.com/repos/mundya/rig/keys{/key_id}","collaborators_url":"https://api.github.com/repos/mundya/rig/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/mundya/rig/teams","hooks_url":"https://api.github.com/repos/mundya/rig/hooks","issue_events_url":"https://api.github.com/repos/mundya/rig/issues/events{/number}","events_url":"https://api.github.com/repos/mundya/rig/events","assignees_url":"https://api.github.com/repos/mundya/rig/assignees{/user}","branches_url":"https://api.github.com/repos/mundya/rig/branches{/branch}","tags_url":"https://api.github.com/repos/mundya/rig/tags","blobs_url":"https://api.github.com/repos/mundya/rig/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/mundya/rig/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/mundya/rig/git/refs{/sha}","trees_url":"https://api.github.com/repos/mundya/rig/git/trees{/sha}","statuses_url":"https://api.github.com/repos/mundya/rig/statuses/{sha}","languages_url":"https://api.github.com/repos/mundya/rig/languages","stargazers_url":"https://api.github.com/repos/mundya/rig/stargazers","contributors_url":"https://api.github.com/repos/mundya/rig/contributors","subscribers_url":"https://api.github.com/repos/mundya/rig/subscribers","subscription_url":"https://api.github.com/repos/mundya/rig/subscription","commits_url":"https://api.github.com/repos/mundya/rig/commits{/sha}","git_commits_url":"https://api.github.com/repos/mundya/rig/git/commits{/sha}","comments_url":"https://api.github.com/repos/mundya/rig/comments{/number}","issue_comment_url":"https://api.github.com/repos/mundya/rig/issues/comments{/number}","contents_url":"https://api.github.com/repos/mundya/rig/contents/{+path}","compare_url":"https://api.github.com/repos/mundya/rig/compare/{base}...{head}","merges_url":"https://api.github.com/repos/mundya/rig/merges","archive_url":"https://api.github.com/repos/mundya/rig/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/mundya/rig/downloads","issues_url":"https://api.github.com/repos/mundya/rig/issues{/number}","pulls_url":"https://api.github.com/repos/mundya/rig/pulls{/number}","milestones_url":"https://api.github.com/repos/mundya/rig/milestones{/number}","notifications_url":"https://api.github.com/repos/mundya/rig/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/mundya/rig/labels{/name}","releases_url":"https://api.github.com/repos/mundya/rig/releases{/id}","created_at":"2015-01-19T21:20:40Z","updated_at":"2015-02-26T15:48:22Z","pushed_at":"2015-02-26T15:48:24Z","git_url":"git://github.com/mundya/rig.git","ssh_url":"git@github.com:mundya/rig.git","clone_url":"https://github.com/mundya/rig.git","svn_url":"https://github.com/mundya/rig","homepage":"","size":728,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":7,"forks":0,"open_issues":7,"watchers":0,"default_branch":"master"}},"base":{"label":"mundya:master","ref":"master","sha":"ff2f4865e238d3c329d3157a08fb567fa4dc4246","user":{"login":"mundya","id":3439837,"avatar_url":"https://avatars.githubusercontent.com/u/3439837?v=3","gravatar_id":"","url":"https://api.github.com/users/mundya","html_url":"https://github.com/mundya","followers_url":"https://api.github.com/users/mundya/followers","following_url":"https://api.github.com/users/mundya/following{/other_user}","gists_url":"https://api.github.com/users/mundya/gists{/gist_id}","starred_url":"https://api.github.com/users/mundya/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mundya/subscriptions","organizations_url":"https://api.github.com/users/mundya/orgs","repos_url":"https://api.github.com/users/mundya/repos","events_url":"https://api.github.com/users/mundya/events{/privacy}","received_events_url":"https://api.github.com/users/mundya/received_events","type":"User","site_admin":false},"repo":{"id":29497314,"name":"rig","full_name":"mundya/rig","owner":{"login":"mundya","id":3439837,"avatar_url":"https://avatars.githubusercontent.com/u/3439837?v=3","gravatar_id":"","url":"https://api.github.com/users/mundya","html_url":"https://github.com/mundya","followers_url":"https://api.github.com/users/mundya/followers","following_url":"https://api.github.com/users/mundya/following{/other_user}","gists_url":"https://api.github.com/users/mundya/gists{/gist_id}","starred_url":"https://api.github.com/users/mundya/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mundya/subscriptions","organizations_url":"https://api.github.com/users/mundya/orgs","repos_url":"https://api.github.com/users/mundya/repos","events_url":"https://api.github.com/users/mundya/events{/privacy}","received_events_url":"https://api.github.com/users/mundya/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/mundya/rig","description":"A set of tools for rigging SpiNNaker programs.","fork":false,"url":"https://api.github.com/repos/mundya/rig","forks_url":"https://api.github.com/repos/mundya/rig/forks","keys_url":"https://api.github.com/repos/mundya/rig/keys{/key_id}","collaborators_url":"https://api.github.com/repos/mundya/rig/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/mundya/rig/teams","hooks_url":"https://api.github.com/repos/mundya/rig/hooks","issue_events_url":"https://api.github.com/repos/mundya/rig/issues/events{/number}","events_url":"https://api.github.com/repos/mundya/rig/events","assignees_url":"https://api.github.com/repos/mundya/rig/assignees{/user}","branches_url":"https://api.github.com/repos/mundya/rig/branches{/branch}","tags_url":"https://api.github.com/repos/mundya/rig/tags","blobs_url":"https://api.github.com/repos/mundya/rig/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/mundya/rig/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/mundya/rig/git/refs{/sha}","trees_url":"https://api.github.com/repos/mundya/rig/git/trees{/sha}","statuses_url":"https://api.github.com/repos/mundya/rig/statuses/{sha}","languages_url":"https://api.github.com/repos/mundya/rig/languages","stargazers_url":"https://api.github.com/repos/mundya/rig/stargazers","contributors_url":"https://api.github.com/repos/mundya/rig/contributors","subscribers_url":"https://api.github.com/repos/mundya/rig/subscribers","subscription_url":"https://api.github.com/repos/mundya/rig/subscription","commits_url":"https://api.github.com/repos/mundya/rig/commits{/sha}","git_commits_url":"https://api.github.com/repos/mundya/rig/git/commits{/sha}","comments_url":"https://api.github.com/repos/mundya/rig/comments{/number}","issue_comment_url":"https://api.github.com/repos/mundya/rig/issues/comments{/number}","contents_url":"https://api.github.com/repos/mundya/rig/contents/{+path}","compare_url":"https://api.github.com/repos/mundya/rig/compare/{base}...{head}","merges_url":"https://api.github.com/repos/mundya/rig/merges","archive_url":"https://api.github.com/repos/mundya/rig/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/mundya/rig/downloads","issues_url":"https://api.github.com/repos/mundya/rig/issues{/number}","pulls_url":"https://api.github.com/repos/mundya/rig/pulls{/number}","milestones_url":"https://api.github.com/repos/mundya/rig/milestones{/number}","notifications_url":"https://api.github.com/repos/mundya/rig/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/mundya/rig/labels{/name}","releases_url":"https://api.github.com/repos/mundya/rig/releases{/id}","created_at":"2015-01-19T21:20:40Z","updated_at":"2015-02-26T15:48:22Z","pushed_at":"2015-02-26T15:48:24Z","git_url":"git://github.com/mundya/rig.git","ssh_url":"git@github.com:mundya/rig.git","clone_url":"https://github.com/mundya/rig.git","svn_url":"https://github.com/mundya/rig","homepage":"","size":728,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":7,"forks":0,"open_issues":7,"watchers":0,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/mundya/rig/pulls/29"},"html":{"href":"https://github.com/mundya/rig/pull/29"},"issue":{"href":"https://api.github.com/repos/mundya/rig/issues/29"},"comments":{"href":"https://api.github.com/repos/mundya/rig/issues/29/comments"},"review_comments":{"href":"https://api.github.com/repos/mundya/rig/pulls/29/comments"},"review_comment":{"href":"https://api.github.com/repos/mundya/rig/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/mundya/rig/pulls/29/commits"},"statuses":{"href":"https://api.github.com/repos/mundya/rig/statuses/2fd1fc9b4c3967c4b8a389b6e5e6fb953fbcb35a"}}}}