{"action":"created","comment":{"url":"https://api.github.com/repos/doomspork/elixir-school/pulls/comments/90753837","pull_request_review_id":11274060,"id":90753837,"diff_hunk":"@@ -0,0 +1,261 @@\n+---\n+layout: page\n+title: GenStage\n+category: advanced\n+order: 11\n+lang: ru\n+---\n+\n+В этом уроке мы поближе рассмотрим GenStage, узнаем, какую роль он выполняет, и как мы можем использовать его в наших приложениях.\n+\n+{% include toc.html %}\n+\n+## Вступление\n+\n+Так что же такое GenStage? В официальной документации написано, что это \"спецификация и поток вычислений для Elixir\", но что это означает для нас?\n+\n+Это означает, что GenStage предоставляет нам возможность определить конвейер задач, который будет выполняться независимыми шагами (или этапами) в отдельных процессах. Если вы уже работали с конвейерами, тогда некоторые из этих понятий могут быть вам знакомы.\n+\n+Чтобы лучше понять, как это работает, давайте визуализируем простой поток производитель-потребитель:\n+\n+```\n+[A] -> [B] -> [C]\n+```\n+\n+В этом примере у нас три стадии: `A` — производитель, `B` — производитель-потребитель, и `C` — потребитель.  `A` производит значение, которое потребляет `B`, `B` выполняет какую-то работу и возвращает значение, которое отправляется нашему потребителю `C`. Роль нашей стадии важна, что мы увидим в следующей секции.\n+\n+Пока в нашем примере производитель относится к потребителю один к одному, но можно одновременно иметь несколько производителей и множество потребителей на любой стадии.\n+\n+Чтобы лучше проиллюстрировать эти понятия, мы построим конвейер с помощью GenStage, но сначала давайте рассмотрим чуть подробнее роли, на которые GenStage опирается.\n+\n+## Производитель и потребитель\n+\n+Как мы уже рассмотрели, роль которую мы даем нашей стадии важна. Спецификация GenStage принимает три роли:\n+\n++ `:producer` — Источник.  Производители ждут требования от потребителей и реагируют, выполняя запрошенные действия.\n+\n++ `:producer_consumer` — И источник, и поглотитель.  Производитель-потребитель может как реагировать на требования от потребителей, так и запрашивать выполнение действий от производителей.\n+\n++ `:consumer` — Поглотитель. Потребитель запрашивает и получает данные от производителя.\n+\n+Заметили, что наши производители _ожидают_ требования?  Благодаря GenStage наши потребители посылают требование вверх по потоку и обрабатывают данные от производителя.  Это облегчает механизм, который называется обратное давление.  Обратное давление перекладывает ответственность на неперегруженного производителя, когда потребители заняты.\n+\n+Теперь, когда мы рассмотрели роли в GenStage, займёмся нашим приложением.\n+\n+## Начало работы\n+\n+В этом примере мы соберем GenStage приложение, которое генерирует числа, выбирает четные и в конце печатает их.\n+\n+Для нашего приложения мы будем использовать все три GenStage роли.  Наш производитель будет отвечать за подсчет и генерацию чисел.  Мы будем использовать производителя-потребителя, чтобы отфильтровать только четные числа, а затем реагировать на запросы снизу потока.  В конце мы создадим потребителя, который будет отображать все числа для нас.\n+\n+Мы начнем с создания проекта с деревом надзора:\n+\n+```shell\n+$ mix new genstage_example --sup\n+$ cd genstage_example\n+```\n+\n+Давайте обновим наши зависимости в `mix.exs`, добавив `gen_stage`:\n+\n+```elixir\n+  defp deps do\n+    [\n+      {:gen_stage, \"~> 0.7\"},\n+    ]\n+  end\n+```\n+\n+Мы должны скачать зависимости и скомпилировать их прежде чем двигаться дальше:\n+\n+```shell\n+$ mix do deps.get, compile\n+```\n+\n+Теперь мы готовы к созданию нашего приложения!\n+\n+## Производитель\n+\n+Первый шаг нашего GenStage приложения — это создание нашего производителя. Как мы обсуждали ранее, мы хотим создать производителя, который генерирует постоянный поток чисел. Давайте создадим файл нашего производителя:\n+\n+```shell\n+$ mkdir lib/genstage_example\n+$ touch lib/genstage_example/producer.ex\n+```\n+\n+Теперь мы можем добавить код:\n+\n+```elixir\n+defmodule GenstageExample.Producer do\n+  alias Experimental.GenStage\n+\n+  use GenStage\n+\n+  def start_link(initial \\\\ 0) do\n+    GenStage.start_link(__MODULE__, initial, name: __MODULE__)\n+  end\n+\n+  def init(counter), do: {:producer, counter}\n+\n+  def handle_demand(demand, state) do\n+    events = Enum.to_list(state..state + demand - 1)\n+    {:noreply, events, (state + demand)}\n+  end\n+end\n+```\n+\n+Две наиболее важные части, которые нужно принять к сведению &mdash; `init/1` и `handle_demand/2`.  В `init/1` мы устанавливаем начальное состояние, как мы делали в наших GenServer, но, что более важно, мы помечаем себя производителем.  Результат нашей `init/1` функции — это то, на что GenStage полагается при классификации нашего процесса.\n+\n+В функции `handle_demand/2` находится основная часть нашего производителя, и она должна быть реализована всеми производителями GenStage.  Здесь мы возвращаем множество чисел, затребованных нашими потребителями, и увеличиваем наш счетчик.  Требование от потребителей, `demand` в нашем коде, представляется в виде целого числа, соответствующего числу событий, которые они могут обрабатывать, по умолчанию 1000.\n+\n+## Производитель-потребитель\n+\n+Теперь, когда у нас есть производитель, генерирующий числа, перейдем к нашему производителю-потребителю.  Мы хотим запрашивать числа от производителя, фильтровать от нечетных и реагировать на требования.\n+\n+```shell\n+$ touch lib/genstage_example/producer_consumer.ex\n+```\n+\n+Обновим наш файл:\n+\n+```elixir\n+defmodule GenstageExample.ProducerConsumer  do\n+  alias Experimental.GenStage\n+  use GenStage\n+\n+  require Integer\n+\n+  def start_link do\n+    GenStage.start_link(__MODULE__, :state_doesnt_matter, name: __MODULE__)\n+  end\n+\n+  def init(state) do\n+    {:producer_consumer, state, subscribe_to: [GenstageExample.Producer]}\n+  end\n+\n+  def handle_events(events, _from, state) do\n+    numbers =\n+      events\n+      |> Enum.filter(&Integer.is_even/1)\n+\n+    {:noreply, numbers, state}\n+  end\n+end\n+```\n+\n+Вы могли заметить, что вместе с нашим производителем-потребителем мы ввели новую функцию `handle_events/3` и опцию в `init/1`.  С помощью опции `subscribe_to` мы поручаем GenStage связать нас с конкретным производителем.\n+\n+Метод `handle_events/3` — наша рабочая лошадка, где мы получаем наши входящие события, обрабатываем их и возвращаем преобразованный набор.  Как мы увидим, потребители реализуются во многом таким же образом, но есть важное отличие — что именно наш `handle_events/3` возвращает и как это используется. Когда мы назначаем наш процесс потребителем, второй аргумент кортежа, `numbers` в нашем случае, используется для удовлетворения требования потребителей ниже по потоку.  В потребителях это значение сбрасывается.\n+\n+## Потребитель\n+\n+Остался последний по порядку, но не по важности процесс — потребитель. Начнём:\n+\n+```shell\n+$ touch lib/genstage_example/consumer.ex\n+```\n+\n+Поскольку потребитель и производитель-потребитель очень схожи, наш код не будет сильно отличатся:\n+\n+```elixir\n+defmodule GenstageExample.Consumer do\n+  alias Experimental.GenStage\n+  use GenStage\n+\n+  def start_link do\n+    GenStage.start_link(__MODULE__, :state_doesnt_matter)\n+  end\n+\n+  def init(state) do\n+    {:consumer, state, subscribe_to: [GenstageExample.ProducerConsumer]}\n+  end\n+\n+  def handle_events(events, _from, state) do\n+    for event <- events do\n+      IO.inspect {self(), event, state}\n+    end\n+\n+    # Так как мы потребители, мы не создаем события\n+    {:noreply, [], state}\n+  end\n+end\n+```\n+\n+Как мы рассмотрели в предыдущем разделе, наш потребитель не создает события, так что второе значение в нашем кортеже будут отброшено.\n+\n+## Собираем все вместе\n+\n+Теперь, когда мы создали производителя, производитель-потребителя и потребителя, мы готовы соединить это все вместе.\n+\n+Давайте откроем файл `lib/genstage_example.ex` и добавим наши новые процессы в дерево надзора:\n+\n+```elixir\n+def start(_type, _args) do\n+  import Supervisor.Spec, warn: false\n+\n+  children = [\n+    worker(GenstageExample.Producer, [0]),\n+    worker(GenstageExample.ProducerConsumer, []),\n+    worker(GenstageExample.Consumer, []),\n+  ]\n+\n+  opts = [strategy: :one_for_one, name: GenstageExample.Supervisor]\n+  Supervisor.start_link(children, opts)\n+end\n+```\n+\n+Если все правильно, мы можем запустить наш проект и мы должны увидеть что все работает:\n+\n+```shell\n+$ mix run --no-halt\n+{#PID<0.109.0>, 2, :state_doesnt_matter}\n+{#PID<0.109.0>, 4, :state_doesnt_matter}\n+{#PID<0.109.0>, 6, :state_doesnt_matter}\n+...\n+{#PID<0.109.0>, 229062, :state_doesnt_matter}\n+{#PID<0.109.0>, 229064, :state_doesnt_matter}\n+{#PID<0.109.0>, 229066, :state_doesnt_matter}\n+```\n+\n+Мы сделали это!  Как мы и ожидали, наше приложение пропускает только четные числа и делает это _быстро_.\n+\n+На данный момент у нас есть рабочий конвейер.  Производитель генерирует числа, производитель-потребитель отбрасывает нечетные числа и потребитель отображает все это и продолжает процесс. Мы уже упоминали во вступлении, что возможно реализовать более одного производителя или потребителя. Давайте взглянем на это.\n+\n+Если мы рассмотрим вывод `IO.inspect/1` из нашего приложения, мы увидим, что каждое событие обрабатывается одним PID. Давайте внесем некоторые корректировки для нескольких работников путем изменения `lib/genstage_example.ex`:\n+\n+```elixir\n+children = [\n+  worker(GenstageExample.Producer, [0]),\n+  worker(GenstageExample.ProducerConsumer, []),\n+  worker(GenstageExample.Consumer, [], id: 1),\n+  worker(GenstageExample.Consumer, [], id: 2),\n+]\n+```\n+\n+Теперь, когда мы настроили два потребителя, давайте посмотрим, что мы получим, если мы запустим наше приложение:\n+\n+```shell\n+$ mix run --no-halt\n+{#PID<0.120.0>, 2, :state_doesnt_matter}\n+{#PID<0.121.0>, 4, :state_doesnt_matter}\n+{#PID<0.120.0>, 6, :state_doesnt_matter}\n+{#PID<0.120.0>, 8, :state_doesnt_matter}\n+...\n+{#PID<0.120.0>, 86478, :state_doesnt_matter}\n+{#PID<0.121.0>, 87338, :state_doesnt_matter}\n+{#PID<0.120.0>, 86480, :state_doesnt_matter}\n+{#PID<0.120.0>, 86482, :state_doesnt_matter}\n+```\n+\n+Как вы можете видеть, теперь мы получили несколько PID, просто добавив строку кода и назначив нашим потребителям ID.\n+\n+## Случаи использования\n+\n+Сейчас мы рассмотрели GenStage и построили наш первый пример приложения. А в каких случаях можно _реально_ использовать GenStage?\n+\n++ Конвейер преобразования данных — Производители не должны быть простыми генераторами чисел, мы могли бы создавать события из базы данных или даже из другого источника, например Apache Kafka. Благодаря сочетанию производителей-потребителей и потребителей мы могли бы обрабатывать, сортировать, каталогизировать и хранить метрики как только они становятся доступными.","path":"ru/lessons/advanced/gen-stage.md","position":255,"original_position":255,"commit_id":"bd5373a8d171b39c8477f7c6b59cac6faef0b1f7","original_commit_id":"bd5373a8d171b39c8477f7c6b59cac6faef0b1f7","user":{"login":"brain-geek","id":307982,"avatar_url":"https://avatars.githubusercontent.com/u/307982?v=3","gravatar_id":"","url":"https://api.github.com/users/brain-geek","html_url":"https://github.com/brain-geek","followers_url":"https://api.github.com/users/brain-geek/followers","following_url":"https://api.github.com/users/brain-geek/following{/other_user}","gists_url":"https://api.github.com/users/brain-geek/gists{/gist_id}","starred_url":"https://api.github.com/users/brain-geek/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/brain-geek/subscriptions","organizations_url":"https://api.github.com/users/brain-geek/orgs","repos_url":"https://api.github.com/users/brain-geek/repos","events_url":"https://api.github.com/users/brain-geek/events{/privacy}","received_events_url":"https://api.github.com/users/brain-geek/received_events","type":"User","site_admin":false},"body":"`Производители` should not start with capital letter","created_at":"2016-12-03T09:08:12Z","updated_at":"2016-12-03T09:09:32Z","html_url":"https://github.com/doomspork/elixir-school/pull/845#discussion_r90753837","pull_request_url":"https://api.github.com/repos/doomspork/elixir-school/pulls/845","_links":{"self":{"href":"https://api.github.com/repos/doomspork/elixir-school/pulls/comments/90753837"},"html":{"href":"https://github.com/doomspork/elixir-school/pull/845#discussion_r90753837"},"pull_request":{"href":"https://api.github.com/repos/doomspork/elixir-school/pulls/845"}}},"pull_request":{"url":"https://api.github.com/repos/doomspork/elixir-school/pulls/845","id":96160749,"html_url":"https://github.com/doomspork/elixir-school/pull/845","diff_url":"https://github.com/doomspork/elixir-school/pull/845.diff","patch_url":"https://github.com/doomspork/elixir-school/pull/845.patch","issue_url":"https://api.github.com/repos/doomspork/elixir-school/issues/845","number":845,"state":"open","locked":false,"title":"[RU] Russian translate GenStage lesson","user":{"login":"saneery","id":11743366,"avatar_url":"https://avatars.githubusercontent.com/u/11743366?v=3","gravatar_id":"","url":"https://api.github.com/users/saneery","html_url":"https://github.com/saneery","followers_url":"https://api.github.com/users/saneery/followers","following_url":"https://api.github.com/users/saneery/following{/other_user}","gists_url":"https://api.github.com/users/saneery/gists{/gist_id}","starred_url":"https://api.github.com/users/saneery/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/saneery/subscriptions","organizations_url":"https://api.github.com/users/saneery/orgs","repos_url":"https://api.github.com/users/saneery/repos","events_url":"https://api.github.com/users/saneery/events{/privacy}","received_events_url":"https://api.github.com/users/saneery/received_events","type":"User","site_admin":false},"body":"Hello, please check my translation.","created_at":"2016-12-01T20:07:26Z","updated_at":"2016-12-03T09:09:32Z","closed_at":null,"merged_at":null,"merge_commit_sha":"0c322fde368aa0cada8b978cfd4443754130044e","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/doomspork/elixir-school/pulls/845/commits","review_comments_url":"https://api.github.com/repos/doomspork/elixir-school/pulls/845/comments","review_comment_url":"https://api.github.com/repos/doomspork/elixir-school/pulls/comments{/number}","comments_url":"https://api.github.com/repos/doomspork/elixir-school/issues/845/comments","statuses_url":"https://api.github.com/repos/doomspork/elixir-school/statuses/bd5373a8d171b39c8477f7c6b59cac6faef0b1f7","head":{"label":"saneery:genstage-rus","ref":"genstage-rus","sha":"bd5373a8d171b39c8477f7c6b59cac6faef0b1f7","user":{"login":"saneery","id":11743366,"avatar_url":"https://avatars.githubusercontent.com/u/11743366?v=3","gravatar_id":"","url":"https://api.github.com/users/saneery","html_url":"https://github.com/saneery","followers_url":"https://api.github.com/users/saneery/followers","following_url":"https://api.github.com/users/saneery/following{/other_user}","gists_url":"https://api.github.com/users/saneery/gists{/gist_id}","starred_url":"https://api.github.com/users/saneery/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/saneery/subscriptions","organizations_url":"https://api.github.com/users/saneery/orgs","repos_url":"https://api.github.com/users/saneery/repos","events_url":"https://api.github.com/users/saneery/events{/privacy}","received_events_url":"https://api.github.com/users/saneery/received_events","type":"User","site_admin":false},"repo":{"id":75324383,"name":"elixir-school","full_name":"saneery/elixir-school","owner":{"login":"saneery","id":11743366,"avatar_url":"https://avatars.githubusercontent.com/u/11743366?v=3","gravatar_id":"","url":"https://api.github.com/users/saneery","html_url":"https://github.com/saneery","followers_url":"https://api.github.com/users/saneery/followers","following_url":"https://api.github.com/users/saneery/following{/other_user}","gists_url":"https://api.github.com/users/saneery/gists{/gist_id}","starred_url":"https://api.github.com/users/saneery/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/saneery/subscriptions","organizations_url":"https://api.github.com/users/saneery/orgs","repos_url":"https://api.github.com/users/saneery/repos","events_url":"https://api.github.com/users/saneery/events{/privacy}","received_events_url":"https://api.github.com/users/saneery/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/saneery/elixir-school","description":"Lessons about the Elixir programming language","fork":true,"url":"https://api.github.com/repos/saneery/elixir-school","forks_url":"https://api.github.com/repos/saneery/elixir-school/forks","keys_url":"https://api.github.com/repos/saneery/elixir-school/keys{/key_id}","collaborators_url":"https://api.github.com/repos/saneery/elixir-school/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/saneery/elixir-school/teams","hooks_url":"https://api.github.com/repos/saneery/elixir-school/hooks","issue_events_url":"https://api.github.com/repos/saneery/elixir-school/issues/events{/number}","events_url":"https://api.github.com/repos/saneery/elixir-school/events","assignees_url":"https://api.github.com/repos/saneery/elixir-school/assignees{/user}","branches_url":"https://api.github.com/repos/saneery/elixir-school/branches{/branch}","tags_url":"https://api.github.com/repos/saneery/elixir-school/tags","blobs_url":"https://api.github.com/repos/saneery/elixir-school/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/saneery/elixir-school/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/saneery/elixir-school/git/refs{/sha}","trees_url":"https://api.github.com/repos/saneery/elixir-school/git/trees{/sha}","statuses_url":"https://api.github.com/repos/saneery/elixir-school/statuses/{sha}","languages_url":"https://api.github.com/repos/saneery/elixir-school/languages","stargazers_url":"https://api.github.com/repos/saneery/elixir-school/stargazers","contributors_url":"https://api.github.com/repos/saneery/elixir-school/contributors","subscribers_url":"https://api.github.com/repos/saneery/elixir-school/subscribers","subscription_url":"https://api.github.com/repos/saneery/elixir-school/subscription","commits_url":"https://api.github.com/repos/saneery/elixir-school/commits{/sha}","git_commits_url":"https://api.github.com/repos/saneery/elixir-school/git/commits{/sha}","comments_url":"https://api.github.com/repos/saneery/elixir-school/comments{/number}","issue_comment_url":"https://api.github.com/repos/saneery/elixir-school/issues/comments{/number}","contents_url":"https://api.github.com/repos/saneery/elixir-school/contents/{+path}","compare_url":"https://api.github.com/repos/saneery/elixir-school/compare/{base}...{head}","merges_url":"https://api.github.com/repos/saneery/elixir-school/merges","archive_url":"https://api.github.com/repos/saneery/elixir-school/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/saneery/elixir-school/downloads","issues_url":"https://api.github.com/repos/saneery/elixir-school/issues{/number}","pulls_url":"https://api.github.com/repos/saneery/elixir-school/pulls{/number}","milestones_url":"https://api.github.com/repos/saneery/elixir-school/milestones{/number}","notifications_url":"https://api.github.com/repos/saneery/elixir-school/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/saneery/elixir-school/labels{/name}","releases_url":"https://api.github.com/repos/saneery/elixir-school/releases{/id}","deployments_url":"https://api.github.com/repos/saneery/elixir-school/deployments","created_at":"2016-12-01T19:16:33Z","updated_at":"2016-12-01T19:16:35Z","pushed_at":"2016-12-03T08:30:45Z","git_url":"git://github.com/saneery/elixir-school.git","ssh_url":"git@github.com:saneery/elixir-school.git","clone_url":"https://github.com/saneery/elixir-school.git","svn_url":"https://github.com/saneery/elixir-school","homepage":"https://elixirschool.com","size":3366,"stargazers_count":0,"watchers_count":0,"language":"CSS","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":"doomspork:master","ref":"master","sha":"dabb87d1d38afdac6a90329b95d9a83c215a834b","user":{"login":"doomspork","id":73386,"avatar_url":"https://avatars.githubusercontent.com/u/73386?v=3","gravatar_id":"","url":"https://api.github.com/users/doomspork","html_url":"https://github.com/doomspork","followers_url":"https://api.github.com/users/doomspork/followers","following_url":"https://api.github.com/users/doomspork/following{/other_user}","gists_url":"https://api.github.com/users/doomspork/gists{/gist_id}","starred_url":"https://api.github.com/users/doomspork/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/doomspork/subscriptions","organizations_url":"https://api.github.com/users/doomspork/orgs","repos_url":"https://api.github.com/users/doomspork/repos","events_url":"https://api.github.com/users/doomspork/events{/privacy}","received_events_url":"https://api.github.com/users/doomspork/received_events","type":"User","site_admin":false},"repo":{"id":36616176,"name":"elixir-school","full_name":"doomspork/elixir-school","owner":{"login":"doomspork","id":73386,"avatar_url":"https://avatars.githubusercontent.com/u/73386?v=3","gravatar_id":"","url":"https://api.github.com/users/doomspork","html_url":"https://github.com/doomspork","followers_url":"https://api.github.com/users/doomspork/followers","following_url":"https://api.github.com/users/doomspork/following{/other_user}","gists_url":"https://api.github.com/users/doomspork/gists{/gist_id}","starred_url":"https://api.github.com/users/doomspork/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/doomspork/subscriptions","organizations_url":"https://api.github.com/users/doomspork/orgs","repos_url":"https://api.github.com/users/doomspork/repos","events_url":"https://api.github.com/users/doomspork/events{/privacy}","received_events_url":"https://api.github.com/users/doomspork/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/doomspork/elixir-school","description":"Lessons about the Elixir programming language","fork":false,"url":"https://api.github.com/repos/doomspork/elixir-school","forks_url":"https://api.github.com/repos/doomspork/elixir-school/forks","keys_url":"https://api.github.com/repos/doomspork/elixir-school/keys{/key_id}","collaborators_url":"https://api.github.com/repos/doomspork/elixir-school/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/doomspork/elixir-school/teams","hooks_url":"https://api.github.com/repos/doomspork/elixir-school/hooks","issue_events_url":"https://api.github.com/repos/doomspork/elixir-school/issues/events{/number}","events_url":"https://api.github.com/repos/doomspork/elixir-school/events","assignees_url":"https://api.github.com/repos/doomspork/elixir-school/assignees{/user}","branches_url":"https://api.github.com/repos/doomspork/elixir-school/branches{/branch}","tags_url":"https://api.github.com/repos/doomspork/elixir-school/tags","blobs_url":"https://api.github.com/repos/doomspork/elixir-school/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/doomspork/elixir-school/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/doomspork/elixir-school/git/refs{/sha}","trees_url":"https://api.github.com/repos/doomspork/elixir-school/git/trees{/sha}","statuses_url":"https://api.github.com/repos/doomspork/elixir-school/statuses/{sha}","languages_url":"https://api.github.com/repos/doomspork/elixir-school/languages","stargazers_url":"https://api.github.com/repos/doomspork/elixir-school/stargazers","contributors_url":"https://api.github.com/repos/doomspork/elixir-school/contributors","subscribers_url":"https://api.github.com/repos/doomspork/elixir-school/subscribers","subscription_url":"https://api.github.com/repos/doomspork/elixir-school/subscription","commits_url":"https://api.github.com/repos/doomspork/elixir-school/commits{/sha}","git_commits_url":"https://api.github.com/repos/doomspork/elixir-school/git/commits{/sha}","comments_url":"https://api.github.com/repos/doomspork/elixir-school/comments{/number}","issue_comment_url":"https://api.github.com/repos/doomspork/elixir-school/issues/comments{/number}","contents_url":"https://api.github.com/repos/doomspork/elixir-school/contents/{+path}","compare_url":"https://api.github.com/repos/doomspork/elixir-school/compare/{base}...{head}","merges_url":"https://api.github.com/repos/doomspork/elixir-school/merges","archive_url":"https://api.github.com/repos/doomspork/elixir-school/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/doomspork/elixir-school/downloads","issues_url":"https://api.github.com/repos/doomspork/elixir-school/issues{/number}","pulls_url":"https://api.github.com/repos/doomspork/elixir-school/pulls{/number}","milestones_url":"https://api.github.com/repos/doomspork/elixir-school/milestones{/number}","notifications_url":"https://api.github.com/repos/doomspork/elixir-school/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/doomspork/elixir-school/labels{/name}","releases_url":"https://api.github.com/repos/doomspork/elixir-school/releases{/id}","deployments_url":"https://api.github.com/repos/doomspork/elixir-school/deployments","created_at":"2015-05-31T18:27:42Z","updated_at":"2016-12-02T15:10:42Z","pushed_at":"2016-12-03T08:30:45Z","git_url":"git://github.com/doomspork/elixir-school.git","ssh_url":"git@github.com:doomspork/elixir-school.git","clone_url":"https://github.com/doomspork/elixir-school.git","svn_url":"https://github.com/doomspork/elixir-school","homepage":"https://elixirschool.com","size":4218,"stargazers_count":774,"watchers_count":774,"language":"CSS","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":274,"mirror_url":null,"open_issues_count":79,"forks":274,"open_issues":79,"watchers":774,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/doomspork/elixir-school/pulls/845"},"html":{"href":"https://github.com/doomspork/elixir-school/pull/845"},"issue":{"href":"https://api.github.com/repos/doomspork/elixir-school/issues/845"},"comments":{"href":"https://api.github.com/repos/doomspork/elixir-school/issues/845/comments"},"review_comments":{"href":"https://api.github.com/repos/doomspork/elixir-school/pulls/845/comments"},"review_comment":{"href":"https://api.github.com/repos/doomspork/elixir-school/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/doomspork/elixir-school/pulls/845/commits"},"statuses":{"href":"https://api.github.com/repos/doomspork/elixir-school/statuses/bd5373a8d171b39c8477f7c6b59cac6faef0b1f7"}}}}
{"actor":{"display_login":"brain-geek"}}