{"action":"created","comment":{"url":"https://api.github.com/repos/openclimatedata/openscm/pulls/comments/236258761","pull_request_review_id":178258456,"id":236258761,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIzNjI1ODc2MQ==","diff_hunk":"@@ -0,0 +1,513 @@\n+\"\"\"\n+Different climate models often use different time frames for their input and output\n+data. This includes different start of time steps (e.g. beginning vs middle of year) and\n+different lengths of the time steps (e.g. years vs months). Accordingly, OpenSCM\n+supports the conversion of timeseries data between such timeframes, which is handled in\n+this module. A thorough explaination of the procedure used is given in a dedicated\n+`Jupyter Notebook\n+<https://github.com/openclimatedata/openscm/blob/master/notebooks/timeframes.ipynb>`_.\n+\"\"\"\n+\n+from copy import copy\n+import numpy as np\n+from typing import NamedTuple, Tuple\n+\n+\n+class InsufficientDataError(Exception):\n+    \"\"\"\n+    Exception raised when not enough data overlap is available when converting from one\n+    timeframe to another (e.g. when the target timeframe is far too early than the\n+    source timeframe) or when data is too short (less than 3 data points).\n+    \"\"\"\n+\n+\n+class Timeframe:\n+    \"\"\"\n+    Convenience class representing a timeframe consisting of a start time and a period\n+    length.\n+    \"\"\"\n+\n+    start_time: int\n+    \"\"\"Start time (seconds since :literal:`1970-01-01 00:00:00`)\"\"\"\n+\n+    period_length: int\n+    \"\"\"Period length in seconds\"\"\"\n+\n+    def __init__(self, start_time, period_length):\n+        \"\"\"\n+        Initialize.\n+\n+        Parameters\n+        ----------\n+        start_time\n+            Start time (seconds since ``1970-01-01 00:00:00``)\n+        period_length\n+            Period length (in seconds)\n+        \"\"\"\n+        self.start_time = start_time\n+        self.period_length = period_length\n+\n+    def __repr__(self) -> str:\n+        \"\"\"\n+        Get string representation.\n+\n+        Returns\n+        -------\n+        str\n+            String representation\n+        \"\"\"\n+        return \"<openscm.timeframes.Timeframe(start_time={}, period_length={})>\".format(\n+            self.start_time, self.period_length\n+        )\n+\n+    def get_points(self, count: int) -> np.ndarray:\n+        \"\"\"\n+        Get the ``count`` first points in time corresponding to the timeframe.\n+\n+        Parameters\n+        ----------\n+        count\n+            Number of time points to return\n+\n+        Returns\n+        -------\n+        np.ndarray\n+            Array of time points\n+        \"\"\"\n+        return np.linspace(self.start_time, self.get_stop_time(count), count)\n+\n+    def get_stop_time(self, count: int) -> int:\n+        \"\"\"\n+        Get the point in time at which a timeseries of ``count`` points stops according\n+        to this timeframe.\n+\n+        Parameters\n+        ----------\n+        count\n+            Number of time points\n+\n+        Returns\n+        -------\n+        int\n+            Time point (seconds since ``1970-01-01 00:00:00``)\n+        \"\"\"\n+        return self.start_time + (count - 1) * self.period_length\n+\n+    def get_length_until(self, stop_time: int) -> int:\n+        \"\"\"\n+        Get the number of time points in this timeframe until ``stop_time`` (including).\n+\n+        Parameters\n+        ----------\n+        stop_time\n+            Stop time(seconds since ``1970-01-01 00:00:00``)\n+\n+        Returns\n+        -------\n+        int\n+            Number of time points\n+        \"\"\"\n+        return (stop_time - self.start_time) // self.period_length + 1\n+\n+\n+def _running_mean(values: np.ndarray, n: int) -> np.ndarray:\n+    \"\"\"\n+    Calculate the running mean over ``values`` with a window width of ``n``.\n+\n+    Parameters\n+    ----------\n+    values\n+        Input array\n+    n\n+        Window width\n+\n+    Returns\n+    -------\n+    np.ndarray\n+        Running mean (of length ``len(values) - n + 1``)\n+    \"\"\"\n+    c = np.cumsum(np.concatenate(([0], values)))\n+    return (c[n:] - c[:-n]) / n\n+\n+\n+def _calc_linearization_values(values: np.ndarray) -> np.ndarray:\n+    \"\"\"\n+    Calculate the \"linearization\" values of the array ``values`` which is assumed to\n+    represent averages over time periods. Values at the edges of the periods are taken\n+    as the average of adjacent periods, values at the period middles are taken such that\n+    the integral over a period is the same as for the input data.\n+\n+    Parameters\n+    ----------\n+    values\n+        Timeseries values of period averages\n+\n+    Returns\n+    -------\n+    np.ndarray\n+        Values of linearization (of length ``2 * len(values) + 1``)\n+    \"\"\"\n+    edge_points = _running_mean(values, 2)\n+    middle_points = 3 * values[1:-1] / 2 - (values[0:-2] + values[2:]) / 4\n+    first_edge_point = 2 * values[0] - edge_points[0]\n+    last_edge_point = 2 * values[-1] - edge_points[-1]\n+    return np.concatenate(\n+        (\n+            np.array(\n+                [\n+                    np.concatenate(([first_edge_point], edge_points)),\n+                    np.concatenate(([values[0]], middle_points, [values[-1]])),\n+                ]\n+            ).T.reshape(2 * len(values)),\n+            [last_edge_point],\n+        )\n+    )\n+\n+\n+def _calc_linearization(\n+    values: np.ndarray, timeframe: Timeframe\n+) -> Tuple[np.ndarray, np.ndarray]:\n+    \"\"\"\n+    Calculate the \"linearization\" time points and values (see\n+    :func:`openscm.timeframes._calc_linearization_values`) of the array ``values``\n+    according to timeframe ``timeframe``.\n+\n+    Parameters\n+    ----------\n+    values\n+        Timeseries values of period averages\n+    timeframe\n+        Timeframe\n+\n+    Returns\n+    -------\n+    linearization_points\n+        Linearization time points (\"x-values\")\n+    linearization_values\n+        Linearization values (\"y-values\")\n+    \"\"\"\n+    stop_time = timeframe.start_time + len(values) * timeframe.period_length\n+    linearization_points = np.linspace(\n+        timeframe.start_time, stop_time, 2 * len(values) + 1\n+    )\n+    linearization_values = _calc_linearization_values(values)\n+    return linearization_points, linearization_values\n+\n+\n+class _Interpolation(NamedTuple):\n+    \"\"\"\n+    Collection of interpolation points and associated information.\n+    \"\"\"\n+\n+    data_len: int\n+    \"\"\"\n+    Length of source data array for which these interpolation points have been\n+    calculated\n+    \"\"\"\n+\n+    first_interval_length: int\n+    \"\"\"\n+    Length of the first interval/period (can be smaller than ``period_length``\n+    when not enough data overlap is available)\n+    \"\"\"\n+\n+    last_interval_length: int\n+    \"\"\"\n+    Length of the last interval/period (can be smaller than ``period_length``\n+    when not enough data overlap is available)\n+    \"\"\"\n+\n+    points: np.ndarray\n+    \"\"\"Array of interpolation time points\"\"\"\n+\n+    period_length: int\n+    \"\"\"\n+    Length of the middle intervals/periods\n+    \"\"\"\n+\n+    target_indices: np.ndarray\n+    \"\"\"\n+    Array of indices in ``interpolation_points`` that correspond to edges of target\n+    periods\n+    \"\"\"\n+\n+\n+def _calc_interpolation_points(\n+    source_len: int, source: Timeframe, target: Timeframe\n+) -> _Interpolation:\n+    \"\"\"\n+    Calculate the \"interpolation\" time points that correspond to edges of the target\n+    periods and the sampling points for the linearization of source values (i.e. edges\n+    and middle points of the source periods).\n+\n+    Parameters\n+    ----------\n+    source_len\n+        Length of source data values\n+    source\n+        Source timeframe\n+    target\n+        Target timeframe\n+\n+    Returns\n+    -------\n+    _Interpolation\n+        Object wrapping the actual interpolation points and additional information\n+    \"\"\"\n+    linearization_points_len = 2 * source_len + 1\n+    # Use double the time points to stick to integers when using half the source period\n+    # length:\n+    source = Timeframe(2 * source.start_time, 1 * source.period_length)\n+    target = Timeframe(2 * target.start_time, 2 * target.period_length)\n+\n+    if target.start_time >= source.start_time:\n+        skip_len = 1 + (target.start_time - source.start_time) // source.period_length\n+        linearization_points_len -= skip_len\n+        source.start_time += skip_len * source.period_length\n+        first_target_point = target.start_time\n+        first_interval_length = target.period_length\n+    else:\n+        first_target_point = target.start_time + target.period_length\n+        first_interval_length = source.start_time - target.start_time\n+\n+    source_stop_time = source.get_stop_time(linearization_points_len)\n+    target_len = 1 + (source_stop_time - first_target_point) // target.period_length\n+    target_stop_time = target.get_stop_time(target_len)\n+\n+    if source_stop_time > target_stop_time:\n+        last_interval_length = source_stop_time - target_stop_time\n+    else:\n+        last_interval_length = target.period_length\n+\n+    interpolation_points, indices = np.unique(\n+        np.concatenate(\n+            (target.get_points(target_len), source.get_points(linearization_points_len))\n+        ),\n+        return_index=True,\n+    )\n+    target_indices = np.where(indices < target_len)[0]\n+\n+    if source_stop_time <= target_stop_time:\n+        target_indices = target_indices[:-1]\n+\n+    return _Interpolation(\n+        data_len=source_len,\n+        first_interval_length=first_interval_length // 2,\n+        last_interval_length=last_interval_length // 2,\n+        period_length=target.period_length // 2,\n+        points=interpolation_points / 2,\n+        target_indices=target_indices,\n+    )\n+\n+\n+def _calc_interval_averages(\n+    interpolation: _Interpolation, interpolation_values: np.ndarray\n+) -> np.ndarray:\n+    \"\"\"\n+    Calculate the average value for each period (i.e. integral over the period divided\n+    by the period length) for the \"interpolated\" values (see\n+    :func:`openscm.timeframes._calc_interpolation_points`) array\n+    ``interpolation_values`` at the time points ``interpolation_points``.\n+\n+    Parameters\n+    ----------\n+    interpolation\n+        Object wrapping the interpolation points in time (\"x-values\" corresponding to\n+        ``interpolation_values``) and additional information\n+    interpolation_values\n+        Interpolation values (\"y-values\")\n+\n+    Returns\n+    -------\n+    np.ndarray\n+        Array of the interval/period averages\n+    \"\"\"\n+    interval_sums = (","path":"openscm/timeframes.py","position":325,"original_position":325,"commit_id":"ade40d6d6304d2234b2175e3060be3bc2f524a69","original_commit_id":"ade40d6d6304d2234b2175e3060be3bc2f524a69","user":{"login":"znicholls","id":23625371,"node_id":"MDQ6VXNlcjIzNjI1Mzcx","avatar_url":"https://avatars2.githubusercontent.com/u/23625371?v=4","gravatar_id":"","url":"https://api.github.com/users/znicholls","html_url":"https://github.com/znicholls","followers_url":"https://api.github.com/users/znicholls/followers","following_url":"https://api.github.com/users/znicholls/following{/other_user}","gists_url":"https://api.github.com/users/znicholls/gists{/gist_id}","starred_url":"https://api.github.com/users/znicholls/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/znicholls/subscriptions","organizations_url":"https://api.github.com/users/znicholls/orgs","repos_url":"https://api.github.com/users/znicholls/repos","events_url":"https://api.github.com/users/znicholls/events{/privacy}","received_events_url":"https://api.github.com/users/znicholls/received_events","type":"User","site_admin":false},"body":"add comment something like interval_sums = (x2 - x1) * (y2 + y1) / 2 i.e. trapezium rule","created_at":"2018-11-26T13:44:32Z","updated_at":"2018-11-26T13:48:15Z","html_url":"https://github.com/openclimatedata/openscm/pull/44#discussion_r236258761","pull_request_url":"https://api.github.com/repos/openclimatedata/openscm/pulls/44","author_association":"COLLABORATOR","_links":{"self":{"href":"https://api.github.com/repos/openclimatedata/openscm/pulls/comments/236258761"},"html":{"href":"https://github.com/openclimatedata/openscm/pull/44#discussion_r236258761"},"pull_request":{"href":"https://api.github.com/repos/openclimatedata/openscm/pulls/44"}}},"pull_request":{"url":"https://api.github.com/repos/openclimatedata/openscm/pulls/44","id":228351380,"node_id":"MDExOlB1bGxSZXF1ZXN0MjI4MzUxMzgw","html_url":"https://github.com/openclimatedata/openscm/pull/44","diff_url":"https://github.com/openclimatedata/openscm/pull/44.diff","patch_url":"https://github.com/openclimatedata/openscm/pull/44.patch","issue_url":"https://api.github.com/repos/openclimatedata/openscm/issues/44","number":44,"state":"open","locked":false,"title":"Low-level: Timeframe conversion","user":{"login":"swillner","id":7057049,"node_id":"MDQ6VXNlcjcwNTcwNDk=","avatar_url":"https://avatars1.githubusercontent.com/u/7057049?v=4","gravatar_id":"","url":"https://api.github.com/users/swillner","html_url":"https://github.com/swillner","followers_url":"https://api.github.com/users/swillner/followers","following_url":"https://api.github.com/users/swillner/following{/other_user}","gists_url":"https://api.github.com/users/swillner/gists{/gist_id}","starred_url":"https://api.github.com/users/swillner/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/swillner/subscriptions","organizations_url":"https://api.github.com/users/swillner/orgs","repos_url":"https://api.github.com/users/swillner/repos","events_url":"https://api.github.com/users/swillner/events{/privacy}","received_events_url":"https://api.github.com/users/swillner/received_events","type":"User","site_admin":false},"body":"- [x] Implementation finished\r\n- [x] Tests added\r\n- [x] Documentation added\r\n- [x] Description in ``CHANGELOG.rst`` added\r\n","created_at":"2018-11-05T13:25:53Z","updated_at":"2018-11-26T13:48:13Z","closed_at":null,"merged_at":null,"merge_commit_sha":"6526cd66d7b3a90ce28a3f1039900bf5ae263b0c","assignee":{"login":"swillner","id":7057049,"node_id":"MDQ6VXNlcjcwNTcwNDk=","avatar_url":"https://avatars1.githubusercontent.com/u/7057049?v=4","gravatar_id":"","url":"https://api.github.com/users/swillner","html_url":"https://github.com/swillner","followers_url":"https://api.github.com/users/swillner/followers","following_url":"https://api.github.com/users/swillner/following{/other_user}","gists_url":"https://api.github.com/users/swillner/gists{/gist_id}","starred_url":"https://api.github.com/users/swillner/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/swillner/subscriptions","organizations_url":"https://api.github.com/users/swillner/orgs","repos_url":"https://api.github.com/users/swillner/repos","events_url":"https://api.github.com/users/swillner/events{/privacy}","received_events_url":"https://api.github.com/users/swillner/received_events","type":"User","site_admin":false},"assignees":[{"login":"swillner","id":7057049,"node_id":"MDQ6VXNlcjcwNTcwNDk=","avatar_url":"https://avatars1.githubusercontent.com/u/7057049?v=4","gravatar_id":"","url":"https://api.github.com/users/swillner","html_url":"https://github.com/swillner","followers_url":"https://api.github.com/users/swillner/followers","following_url":"https://api.github.com/users/swillner/following{/other_user}","gists_url":"https://api.github.com/users/swillner/gists{/gist_id}","starred_url":"https://api.github.com/users/swillner/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/swillner/subscriptions","organizations_url":"https://api.github.com/users/swillner/orgs","repos_url":"https://api.github.com/users/swillner/repos","events_url":"https://api.github.com/users/swillner/events{/privacy}","received_events_url":"https://api.github.com/users/swillner/received_events","type":"User","site_admin":false}],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/openclimatedata/openscm/pulls/44/commits","review_comments_url":"https://api.github.com/repos/openclimatedata/openscm/pulls/44/comments","review_comment_url":"https://api.github.com/repos/openclimatedata/openscm/pulls/comments{/number}","comments_url":"https://api.github.com/repos/openclimatedata/openscm/issues/44/comments","statuses_url":"https://api.github.com/repos/openclimatedata/openscm/statuses/ade40d6d6304d2234b2175e3060be3bc2f524a69","head":{"label":"openclimatedata:timeframes","ref":"timeframes","sha":"ade40d6d6304d2234b2175e3060be3bc2f524a69","user":{"login":"openclimatedata","id":20420557,"node_id":"MDEyOk9yZ2FuaXphdGlvbjIwNDIwNTU3","avatar_url":"https://avatars3.githubusercontent.com/u/20420557?v=4","gravatar_id":"","url":"https://api.github.com/users/openclimatedata","html_url":"https://github.com/openclimatedata","followers_url":"https://api.github.com/users/openclimatedata/followers","following_url":"https://api.github.com/users/openclimatedata/following{/other_user}","gists_url":"https://api.github.com/users/openclimatedata/gists{/gist_id}","starred_url":"https://api.github.com/users/openclimatedata/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/openclimatedata/subscriptions","organizations_url":"https://api.github.com/users/openclimatedata/orgs","repos_url":"https://api.github.com/users/openclimatedata/repos","events_url":"https://api.github.com/users/openclimatedata/events{/privacy}","received_events_url":"https://api.github.com/users/openclimatedata/received_events","type":"Organization","site_admin":false},"repo":{"id":143128174,"node_id":"MDEwOlJlcG9zaXRvcnkxNDMxMjgxNzQ=","name":"openscm","full_name":"openclimatedata/openscm","private":false,"owner":{"login":"openclimatedata","id":20420557,"node_id":"MDEyOk9yZ2FuaXphdGlvbjIwNDIwNTU3","avatar_url":"https://avatars3.githubusercontent.com/u/20420557?v=4","gravatar_id":"","url":"https://api.github.com/users/openclimatedata","html_url":"https://github.com/openclimatedata","followers_url":"https://api.github.com/users/openclimatedata/followers","following_url":"https://api.github.com/users/openclimatedata/following{/other_user}","gists_url":"https://api.github.com/users/openclimatedata/gists{/gist_id}","starred_url":"https://api.github.com/users/openclimatedata/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/openclimatedata/subscriptions","organizations_url":"https://api.github.com/users/openclimatedata/orgs","repos_url":"https://api.github.com/users/openclimatedata/repos","events_url":"https://api.github.com/users/openclimatedata/events{/privacy}","received_events_url":"https://api.github.com/users/openclimatedata/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/openclimatedata/openscm","description":"Unified access to simple climate models (work in progress)","fork":false,"url":"https://api.github.com/repos/openclimatedata/openscm","forks_url":"https://api.github.com/repos/openclimatedata/openscm/forks","keys_url":"https://api.github.com/repos/openclimatedata/openscm/keys{/key_id}","collaborators_url":"https://api.github.com/repos/openclimatedata/openscm/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/openclimatedata/openscm/teams","hooks_url":"https://api.github.com/repos/openclimatedata/openscm/hooks","issue_events_url":"https://api.github.com/repos/openclimatedata/openscm/issues/events{/number}","events_url":"https://api.github.com/repos/openclimatedata/openscm/events","assignees_url":"https://api.github.com/repos/openclimatedata/openscm/assignees{/user}","branches_url":"https://api.github.com/repos/openclimatedata/openscm/branches{/branch}","tags_url":"https://api.github.com/repos/openclimatedata/openscm/tags","blobs_url":"https://api.github.com/repos/openclimatedata/openscm/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/openclimatedata/openscm/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/openclimatedata/openscm/git/refs{/sha}","trees_url":"https://api.github.com/repos/openclimatedata/openscm/git/trees{/sha}","statuses_url":"https://api.github.com/repos/openclimatedata/openscm/statuses/{sha}","languages_url":"https://api.github.com/repos/openclimatedata/openscm/languages","stargazers_url":"https://api.github.com/repos/openclimatedata/openscm/stargazers","contributors_url":"https://api.github.com/repos/openclimatedata/openscm/contributors","subscribers_url":"https://api.github.com/repos/openclimatedata/openscm/subscribers","subscription_url":"https://api.github.com/repos/openclimatedata/openscm/subscription","commits_url":"https://api.github.com/repos/openclimatedata/openscm/commits{/sha}","git_commits_url":"https://api.github.com/repos/openclimatedata/openscm/git/commits{/sha}","comments_url":"https://api.github.com/repos/openclimatedata/openscm/comments{/number}","issue_comment_url":"https://api.github.com/repos/openclimatedata/openscm/issues/comments{/number}","contents_url":"https://api.github.com/repos/openclimatedata/openscm/contents/{+path}","compare_url":"https://api.github.com/repos/openclimatedata/openscm/compare/{base}...{head}","merges_url":"https://api.github.com/repos/openclimatedata/openscm/merges","archive_url":"https://api.github.com/repos/openclimatedata/openscm/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/openclimatedata/openscm/downloads","issues_url":"https://api.github.com/repos/openclimatedata/openscm/issues{/number}","pulls_url":"https://api.github.com/repos/openclimatedata/openscm/pulls{/number}","milestones_url":"https://api.github.com/repos/openclimatedata/openscm/milestones{/number}","notifications_url":"https://api.github.com/repos/openclimatedata/openscm/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/openclimatedata/openscm/labels{/name}","releases_url":"https://api.github.com/repos/openclimatedata/openscm/releases{/id}","deployments_url":"https://api.github.com/repos/openclimatedata/openscm/deployments","created_at":"2018-08-01T08:38:43Z","updated_at":"2018-11-22T15:56:34Z","pushed_at":"2018-11-16T06:47:43Z","git_url":"git://github.com/openclimatedata/openscm.git","ssh_url":"git@github.com:openclimatedata/openscm.git","clone_url":"https://github.com/openclimatedata/openscm.git","svn_url":"https://github.com/openclimatedata/openscm","homepage":"","size":603,"stargazers_count":5,"watchers_count":5,"language":"Python","has_issues":true,"has_projects":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":23,"license":{"key":"agpl-3.0","name":"GNU Affero General Public License v3.0","spdx_id":"AGPL-3.0","url":"https://api.github.com/licenses/agpl-3.0","node_id":"MDc6TGljZW5zZTE="},"forks":0,"open_issues":23,"watchers":5,"default_branch":"master"}},"base":{"label":"openclimatedata:master","ref":"master","sha":"d61e5d7d2b7c9d80bc4cde21e2061c2174dd8ada","user":{"login":"openclimatedata","id":20420557,"node_id":"MDEyOk9yZ2FuaXphdGlvbjIwNDIwNTU3","avatar_url":"https://avatars3.githubusercontent.com/u/20420557?v=4","gravatar_id":"","url":"https://api.github.com/users/openclimatedata","html_url":"https://github.com/openclimatedata","followers_url":"https://api.github.com/users/openclimatedata/followers","following_url":"https://api.github.com/users/openclimatedata/following{/other_user}","gists_url":"https://api.github.com/users/openclimatedata/gists{/gist_id}","starred_url":"https://api.github.com/users/openclimatedata/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/openclimatedata/subscriptions","organizations_url":"https://api.github.com/users/openclimatedata/orgs","repos_url":"https://api.github.com/users/openclimatedata/repos","events_url":"https://api.github.com/users/openclimatedata/events{/privacy}","received_events_url":"https://api.github.com/users/openclimatedata/received_events","type":"Organization","site_admin":false},"repo":{"id":143128174,"node_id":"MDEwOlJlcG9zaXRvcnkxNDMxMjgxNzQ=","name":"openscm","full_name":"openclimatedata/openscm","private":false,"owner":{"login":"openclimatedata","id":20420557,"node_id":"MDEyOk9yZ2FuaXphdGlvbjIwNDIwNTU3","avatar_url":"https://avatars3.githubusercontent.com/u/20420557?v=4","gravatar_id":"","url":"https://api.github.com/users/openclimatedata","html_url":"https://github.com/openclimatedata","followers_url":"https://api.github.com/users/openclimatedata/followers","following_url":"https://api.github.com/users/openclimatedata/following{/other_user}","gists_url":"https://api.github.com/users/openclimatedata/gists{/gist_id}","starred_url":"https://api.github.com/users/openclimatedata/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/openclimatedata/subscriptions","organizations_url":"https://api.github.com/users/openclimatedata/orgs","repos_url":"https://api.github.com/users/openclimatedata/repos","events_url":"https://api.github.com/users/openclimatedata/events{/privacy}","received_events_url":"https://api.github.com/users/openclimatedata/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/openclimatedata/openscm","description":"Unified access to simple climate models (work in progress)","fork":false,"url":"https://api.github.com/repos/openclimatedata/openscm","forks_url":"https://api.github.com/repos/openclimatedata/openscm/forks","keys_url":"https://api.github.com/repos/openclimatedata/openscm/keys{/key_id}","collaborators_url":"https://api.github.com/repos/openclimatedata/openscm/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/openclimatedata/openscm/teams","hooks_url":"https://api.github.com/repos/openclimatedata/openscm/hooks","issue_events_url":"https://api.github.com/repos/openclimatedata/openscm/issues/events{/number}","events_url":"https://api.github.com/repos/openclimatedata/openscm/events","assignees_url":"https://api.github.com/repos/openclimatedata/openscm/assignees{/user}","branches_url":"https://api.github.com/repos/openclimatedata/openscm/branches{/branch}","tags_url":"https://api.github.com/repos/openclimatedata/openscm/tags","blobs_url":"https://api.github.com/repos/openclimatedata/openscm/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/openclimatedata/openscm/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/openclimatedata/openscm/git/refs{/sha}","trees_url":"https://api.github.com/repos/openclimatedata/openscm/git/trees{/sha}","statuses_url":"https://api.github.com/repos/openclimatedata/openscm/statuses/{sha}","languages_url":"https://api.github.com/repos/openclimatedata/openscm/languages","stargazers_url":"https://api.github.com/repos/openclimatedata/openscm/stargazers","contributors_url":"https://api.github.com/repos/openclimatedata/openscm/contributors","subscribers_url":"https://api.github.com/repos/openclimatedata/openscm/subscribers","subscription_url":"https://api.github.com/repos/openclimatedata/openscm/subscription","commits_url":"https://api.github.com/repos/openclimatedata/openscm/commits{/sha}","git_commits_url":"https://api.github.com/repos/openclimatedata/openscm/git/commits{/sha}","comments_url":"https://api.github.com/repos/openclimatedata/openscm/comments{/number}","issue_comment_url":"https://api.github.com/repos/openclimatedata/openscm/issues/comments{/number}","contents_url":"https://api.github.com/repos/openclimatedata/openscm/contents/{+path}","compare_url":"https://api.github.com/repos/openclimatedata/openscm/compare/{base}...{head}","merges_url":"https://api.github.com/repos/openclimatedata/openscm/merges","archive_url":"https://api.github.com/repos/openclimatedata/openscm/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/openclimatedata/openscm/downloads","issues_url":"https://api.github.com/repos/openclimatedata/openscm/issues{/number}","pulls_url":"https://api.github.com/repos/openclimatedata/openscm/pulls{/number}","milestones_url":"https://api.github.com/repos/openclimatedata/openscm/milestones{/number}","notifications_url":"https://api.github.com/repos/openclimatedata/openscm/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/openclimatedata/openscm/labels{/name}","releases_url":"https://api.github.com/repos/openclimatedata/openscm/releases{/id}","deployments_url":"https://api.github.com/repos/openclimatedata/openscm/deployments","created_at":"2018-08-01T08:38:43Z","updated_at":"2018-11-22T15:56:34Z","pushed_at":"2018-11-16T06:47:43Z","git_url":"git://github.com/openclimatedata/openscm.git","ssh_url":"git@github.com:openclimatedata/openscm.git","clone_url":"https://github.com/openclimatedata/openscm.git","svn_url":"https://github.com/openclimatedata/openscm","homepage":"","size":603,"stargazers_count":5,"watchers_count":5,"language":"Python","has_issues":true,"has_projects":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":23,"license":{"key":"agpl-3.0","name":"GNU Affero General Public License v3.0","spdx_id":"AGPL-3.0","url":"https://api.github.com/licenses/agpl-3.0","node_id":"MDc6TGljZW5zZTE="},"forks":0,"open_issues":23,"watchers":5,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/openclimatedata/openscm/pulls/44"},"html":{"href":"https://github.com/openclimatedata/openscm/pull/44"},"issue":{"href":"https://api.github.com/repos/openclimatedata/openscm/issues/44"},"comments":{"href":"https://api.github.com/repos/openclimatedata/openscm/issues/44/comments"},"review_comments":{"href":"https://api.github.com/repos/openclimatedata/openscm/pulls/44/comments"},"review_comment":{"href":"https://api.github.com/repos/openclimatedata/openscm/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/openclimatedata/openscm/pulls/44/commits"},"statuses":{"href":"https://api.github.com/repos/openclimatedata/openscm/statuses/ade40d6d6304d2234b2175e3060be3bc2f524a69"}},"author_association":"MEMBER"}}
{"actor":{"display_login":"znicholls"}}