GitHub PullRequestReviewCommentEvent at 2014-08-31 02:18:39
Repository: erlang-katana
Actor: elvisinaka
Payload: {"action":"created","comment":{"url":"https://api.github.com/repos/inaka/erlang-katana/pulls/comments/16932745","id":16932745,"diff_hunk":"@@ -0,0 +1,397 @@\n+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n+%%% ktn_recipe: a tool to structure code that consists of sequential steps\n+%%%             in which decisions are made.\n+%%%\n+%%% * What is a recipe?\n+%%%\n+%%% Recipe (noun): A set of conditions and parameters of an industrial process\n+%%% to obtain a given result.\n+%%%\n+%%% A recipe is a series of steps to obtain a result. This word was chosen\n+%%% because 'procedure' is overloaded in computer sciences, and it is not\n+%%% exactly a finite state machine.\n+%%%\n+%%% ktn_recipe arose from the need to restructure code implementing large\n+%%% application business logic decision trees.\n+%%% Long functions, deeply nested case expressions, code with several\n+%%% responsibilities, all make for unreadable and unmaintainable code.\n+%%% Every time one needs to make a change or add a feature, one must think about\n+%%% the non-obvious data flow, complex logic, possible side effects.\n+%%% Exceptions pile upon exceptions, until the code is a house of cards.\n+%%% If one is lucky (or responsible), one has comprehensive test suites covering\n+%%% all cases.\n+%%%\n+%%% A better way to structure the code would be preferable, one that makes the\n+%%% flow obvious and separates responsibilities into appropriate code segments.\n+%%% One way is a finite state machine. OTP even has a behaviour for exactly this\n+%%% purpose. However, gen_fsm does not exactly fit our needs:\n+%%% To begin with, gen_fsms run in their own process, which may not be what is\n+%%% needed. Second, logic flow is not immediately obvious because the fsm's\n+%%% state depends on the result of each state function. Finally, a gen_fsm\n+%%% transitions only on receiving input, whereas we are looking for something\n+%%% that runs like normal code, \"on its own\". So, our fsm will be defined by\n+%%% something like a transition table, a single place you can look at and know\n+%%% how it executes. This specification will \"drive\" the recipe.\n+%%%\n+%%% The most common case envisioned is a sequential series of steps, each of\n+%%% which makes a decision affecting later outcomes, so our design should be\n+%%% optimized for a single, linear execution flow, allowing for writing the\n+%%% minimum amount of code for this particular case. Keep the common case fast.\n+%%%\n+%%% * How do I use it?\n+%%%\n+%%% The simplest use case: create a module using the ktn_recipe behaviour.\n+%%% It must export transitions/0, process_result/1, process_error/1 and a series\n+%%% of unary functions called step functions.\n+%%% transitions/0 must return a list of atoms naming the step functions, in the\n+%%% order in which they must be called. Each step function takes a State\n+%%% variable as input and if the step was succesful emits {ok, NewState} with\n+%%% the updated state, or {error, NewState} if it was unsuccessful.\n+%%% After running all the steps, process_result will take the resulting state\n+%%% as input and should emit whatever you need.\n+%%% If one of the state functions returns {error, NewState}, then\n+%%% process_error/1 will be called taking the resulting state as input and\n+%%% should handle all expected error conditions.\n+%%%\n+%%% To run the recipe, call ktn_recipe:run(CALLBACK_MODULE, INITIAL_STATE).\n+%%%\n+%%% For more advanced uses, continue reading.\n+%%%\n+%%% * How does it work?\n+%%%\n+%%% The main functions are ktn_recipe:run/2-4. These will run a recipe and\n+%%% return the result.\n+%%%\n+%%% Recipes may be specified in two ways, which we call \"implicit\" and\n+%%% \"explicit\", for lack of better words. In implicit mode, we pass run/2 a\n+%%% callback module implementing the ktn_recipe behavior, which implements all\n+%%% necessary functions. In explicit mode, we explicitly give run/4 the\n+%%% transition table, a function to process the state resulting from running all\n+%%% recipe steps to completion, a function to process erroneous states, and the\n+%%% initial state of the recipe.\n+%%%\n+%%% * Step functions\n+%%%\n+%%% Step functions have the following type:\n+%%%\n+%%%   -type state()  :: term().\n+%%%   -type output() :: term().\n+%%%   -spec Step(state()) -> {ok, state()}\n+%%%                        | {output(), state()}\n+%%%                        | {error, state()}\n+%%%                        | {halt, state()}.\n+%%%\n+%%% The recipe state may be any value you need, a list, a proplist, a record, a\n+%%% map, etc. ktn_recipe does not use maps itself, although the test suite does.\n+%%%\n+%%% The initial state passed to run/2-4 will be passed to the first step as-is,\n+%%% and the subsequent resulting states will be fed to each step.\n+%%%\n+%%% The step functions should, if possible, have no side effects. If so, and the\n+%%% recipe ends in an error state, it can be aborted without worrying about\n+%%% rolling back the side effects.\n+%%%\n+%%% For example, if the recipe involves making changes in a database, these\n+%%% should be made in the process_result/1 function, once it is certain that\n+%%% all steps completed successfully.\n+%%%\n+%%% * Result and Error processing\n+%%%\n+%%% In implicit mode, the module must export process_error/1 and\n+%%% process_result/1; in explicit mode you may pass whichever function you\n+%%% desire.\n+%%% The purpose of the 'result processing function' is to transform the\n+%%% resulting state into a usable value.\n+%%% The purpose of the 'error processing function' is to extract the error value\n+%%% from the state and do something according. If you are unfortunate enough\n+%%% to have unavoidable side effects in your step functions, you may undo them\n+%%% here.\n+%%%\n+%%% * Specifying transitions\n+%%%\n+%%% Transition tables are lists.\n+%%% As stated, the simplest transition table is a list of atoms naming the step\n+%%% functions, but this is not the only way recipe states may be specified.\n+%%% A transition table is a list of transitions.\n+%%% What is permissible as a transition depends on whether we are running in\n+%%% implicit or explicit mode.\n+%%%\n+%%% In explicit mode, a transition may be either be an external function, i.e.\n+%%% fun module:function/arity, or a ternary tuple {F1, I, F2} in which the F1\n+%%% and F2 elements are explicit functions and the I is the transition input.\n+%%% This form reprensents a transition from step F1 to step F2, if F1 outputs\n+%%% {Input, State} instead of {ok, State}.\n+%%%\n+%%% In implicit mode, in addition to the se two forms of specifying step\n+%%% functions, an atom may be used. The module in which the function resides is\n+%%% assumed to be the provided callback module, hence it is 'implicit'.\n+%%%\n+%%% Also as stated, in any mode, the return value of step functions must be one\n+%%% of:\n+%%% - {ok, State}\n+%%% - {Output, State}\n+%%% - {halt, State}\n+%%% - {error, State}\n+%%%\n+%%% If {error, State} is returned, run/2-4 will call the error processing\n+%%% function. If {halt, State} is called, run/2-4 will call the result\n+%%% processing function.\n+%%% If {ok, State} is returned, run will call the next function in the\n+%%% transition table. That is, it will search the transition table until it\n+%%% finds the current's functions position, if necessary skip over entries\n+%%% corresponding to the current function, and call the first function with a\n+%%% different name it encounters.\n+%%% If {Output, State} is returned, run will search the transition table for an\n+%%% entry matching {Step, Output, NextStep, and select NextStep as the function\n+%%% to call. In this way, non-linear recipes that jump ahead or loop back may\n+%%% be specified. It is recommended that the transition table describe a DAG,\n+%%% unless the program logic really requires loops.\n+%%%\n+%%% Before running a recipe, run/2-4 will 'normalize' the transition table to\n+%%% remove implicit assumptions and so that it is composed only of ternary\n+%%% tuples explicitly listing every transition. As a debugging aid, this\n+%%% function normalize/1 is exported by the ktn_recipe module.\n+%%%\n+%%% Example\n+%%%\n+%%% Suppose you have a web server with an endpoint /conversations, accepting the\n+%%% DELETE method to delete conversations between users. To delete a conversation,","path":"src/ktn_recipe.erl","position":158,"original_position":158,"commit_id":"6aa03732cfa0fbc07819e878ad1c676e49b8814f","original_commit_id":"6aa03732cfa0fbc07819e878ad1c676e49b8814f","user":{"login":"elvisinaka","id":8136322,"avatar_url":"https://avatars.githubusercontent.com/u/8136322?v=2","gravatar_id":"47b5c879277b0fe925b435177fd64a55","url":"https://api.github.com/users/elvisinaka","html_url":"https://github.com/elvisinaka","followers_url":"https://api.github.com/users/elvisinaka/followers","following_url":"https://api.github.com/users/elvisinaka/following{/other_user}","gists_url":"https://api.github.com/users/elvisinaka/gists{/gist_id}","starred_url":"https://api.github.com/users/elvisinaka/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/elvisinaka/subscriptions","organizations_url":"https://api.github.com/users/elvisinaka/orgs","repos_url":"https://api.github.com/users/elvisinaka/repos","events_url":"https://api.github.com/users/elvisinaka/events{/privacy}","received_events_url":"https://api.github.com/users/elvisinaka/received_events","type":"User","site_admin":false},"body":"Line 158 is too long: \"%%% DELETE method to delete conversations between users. To delete a conversation,\".","created_at":"2014-08-31T02:18:39Z","updated_at":"2014-08-31T02:18:39Z","html_url":"https://github.com/inaka/erlang-katana/pull/12#discussion_r16932745","pull_request_url":"https://api.github.com/repos/inaka/erlang-katana/pulls/12","_links":{"self":{"href":"https://api.github.com/repos/inaka/erlang-katana/pulls/comments/16932745"},"html":{"href":"https://github.com/inaka/erlang-katana/pull/12#discussion_r16932745"},"pull_request":{"href":"https://api.github.com/repos/inaka/erlang-katana/pulls/12"}}},"pull_request":{"url":"https://api.github.com/repos/inaka/erlang-katana/pulls/12","id":20541374,"html_url":"https://github.com/inaka/erlang-katana/pull/12","diff_url":"https://github.com/inaka/erlang-katana/pull/12.diff","patch_url":"https://github.com/inaka/erlang-katana/pull/12.patch","issue_url":"https://api.github.com/repos/inaka/erlang-katana/issues/12","number":12,"state":"open","locked":false,"title":"Igaray.recipe","user":{"login":"igaray","id":167193,"avatar_url":"https://avatars.githubusercontent.com/u/167193?v=2","gravatar_id":"928d7a2e176438f4c8bc7802d05b4f2f","url":"https://api.github.com/users/igaray","html_url":"https://github.com/igaray","followers_url":"https://api.github.com/users/igaray/followers","following_url":"https://api.github.com/users/igaray/following{/other_user}","gists_url":"https://api.github.com/users/igaray/gists{/gist_id}","starred_url":"https://api.github.com/users/igaray/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/igaray/subscriptions","organizations_url":"https://api.github.com/users/igaray/orgs","repos_url":"https://api.github.com/users/igaray/repos","events_url":"https://api.github.com/users/igaray/events{/privacy}","received_events_url":"https://api.github.com/users/igaray/received_events","type":"User","site_admin":false},"body":"","created_at":"2014-08-31T02:18:38Z","updated_at":"2014-08-31T02:18:39Z","closed_at":null,"merged_at":null,"merge_commit_sha":"e219f6f6fa51d981a6c293826c887046eaaf55eb","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/inaka/erlang-katana/pulls/12/commits","review_comments_url":"https://api.github.com/repos/inaka/erlang-katana/pulls/12/comments","review_comment_url":"https://api.github.com/repos/inaka/erlang-katana/pulls/comments/{number}","comments_url":"https://api.github.com/repos/inaka/erlang-katana/issues/12/comments","statuses_url":"https://api.github.com/repos/inaka/erlang-katana/statuses/6aa03732cfa0fbc07819e878ad1c676e49b8814f","head":{"label":"inaka:igaray.recipe","ref":"igaray.recipe","sha":"6aa03732cfa0fbc07819e878ad1c676e49b8814f","user":{"login":"inaka","id":867053,"avatar_url":"https://avatars.githubusercontent.com/u/867053?v=2","gravatar_id":"1965362c650bbdd4cbaadf0f1ac45f7e","url":"https://api.github.com/users/inaka","html_url":"https://github.com/inaka","followers_url":"https://api.github.com/users/inaka/followers","following_url":"https://api.github.com/users/inaka/following{/other_user}","gists_url":"https://api.github.com/users/inaka/gists{/gist_id}","starred_url":"https://api.github.com/users/inaka/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/inaka/subscriptions","organizations_url":"https://api.github.com/users/inaka/orgs","repos_url":"https://api.github.com/users/inaka/repos","events_url":"https://api.github.com/users/inaka/events{/privacy}","received_events_url":"https://api.github.com/users/inaka/received_events","type":"Organization","site_admin":false},"repo":{"id":22760152,"name":"erlang-katana","full_name":"inaka/erlang-katana","owner":{"login":"inaka","id":867053,"avatar_url":"https://avatars.githubusercontent.com/u/867053?v=2","gravatar_id":"1965362c650bbdd4cbaadf0f1ac45f7e","url":"https://api.github.com/users/inaka","html_url":"https://github.com/inaka","followers_url":"https://api.github.com/users/inaka/followers","following_url":"https://api.github.com/users/inaka/following{/other_user}","gists_url":"https://api.github.com/users/inaka/gists{/gist_id}","starred_url":"https://api.github.com/users/inaka/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/inaka/subscriptions","organizations_url":"https://api.github.com/users/inaka/orgs","repos_url":"https://api.github.com/users/inaka/repos","events_url":"https://api.github.com/users/inaka/events{/privacy}","received_events_url":"https://api.github.com/users/inaka/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/inaka/erlang-katana","description":"Erlang grab bag of useful functions. it should have been called swiss army knife but katanas are deadlier","fork":true,"url":"https://api.github.com/repos/inaka/erlang-katana","forks_url":"https://api.github.com/repos/inaka/erlang-katana/forks","keys_url":"https://api.github.com/repos/inaka/erlang-katana/keys{/key_id}","collaborators_url":"https://api.github.com/repos/inaka/erlang-katana/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/inaka/erlang-katana/teams","hooks_url":"https://api.github.com/repos/inaka/erlang-katana/hooks","issue_events_url":"https://api.github.com/repos/inaka/erlang-katana/issues/events{/number}","events_url":"https://api.github.com/repos/inaka/erlang-katana/events","assignees_url":"https://api.github.com/repos/inaka/erlang-katana/assignees{/user}","branches_url":"https://api.github.com/repos/inaka/erlang-katana/branches{/branch}","tags_url":"https://api.github.com/repos/inaka/erlang-katana/tags","blobs_url":"https://api.github.com/repos/inaka/erlang-katana/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/inaka/erlang-katana/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/inaka/erlang-katana/git/refs{/sha}","trees_url":"https://api.github.com/repos/inaka/erlang-katana/git/trees{/sha}","statuses_url":"https://api.github.com/repos/inaka/erlang-katana/statuses/{sha}","languages_url":"https://api.github.com/repos/inaka/erlang-katana/languages","stargazers_url":"https://api.github.com/repos/inaka/erlang-katana/stargazers","contributors_url":"https://api.github.com/repos/inaka/erlang-katana/contributors","subscribers_url":"https://api.github.com/repos/inaka/erlang-katana/subscribers","subscription_url":"https://api.github.com/repos/inaka/erlang-katana/subscription","commits_url":"https://api.github.com/repos/inaka/erlang-katana/commits{/sha}","git_commits_url":"https://api.github.com/repos/inaka/erlang-katana/git/commits{/sha}","comments_url":"https://api.github.com/repos/inaka/erlang-katana/comments{/number}","issue_comment_url":"https://api.github.com/repos/inaka/erlang-katana/issues/comments/{number}","contents_url":"https://api.github.com/repos/inaka/erlang-katana/contents/{+path}","compare_url":"https://api.github.com/repos/inaka/erlang-katana/compare/{base}...{head}","merges_url":"https://api.github.com/repos/inaka/erlang-katana/merges","archive_url":"https://api.github.com/repos/inaka/erlang-katana/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/inaka/erlang-katana/downloads","issues_url":"https://api.github.com/repos/inaka/erlang-katana/issues{/number}","pulls_url":"https://api.github.com/repos/inaka/erlang-katana/pulls{/number}","milestones_url":"https://api.github.com/repos/inaka/erlang-katana/milestones{/number}","notifications_url":"https://api.github.com/repos/inaka/erlang-katana/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/inaka/erlang-katana/labels{/name}","releases_url":"https://api.github.com/repos/inaka/erlang-katana/releases{/id}","created_at":"2014-08-08T14:20:25Z","updated_at":"2014-08-29T06:13:44Z","pushed_at":"2014-08-31T02:18:29Z","git_url":"git://github.com/inaka/erlang-katana.git","ssh_url":"git@github.com:inaka/erlang-katana.git","clone_url":"https://github.com/inaka/erlang-katana.git","svn_url":"https://github.com/inaka/erlang-katana","homepage":"","size":497,"stargazers_count":4,"watchers_count":4,"language":"Erlang","has_issues":true,"has_downloads":true,"has_wiki":true,"forks_count":0,"mirror_url":null,"open_issues_count":2,"forks":0,"open_issues":2,"watchers":4,"default_branch":"master"}},"base":{"label":"inaka:master","ref":"master","sha":"d6123afe5afaf1e201bc509c323cf0593300941c","user":{"login":"inaka","id":867053,"avatar_url":"https://avatars.githubusercontent.com/u/867053?v=2","gravatar_id":"1965362c650bbdd4cbaadf0f1ac45f7e","url":"https://api.github.com/users/inaka","html_url":"https://github.com/inaka","followers_url":"https://api.github.com/users/inaka/followers","following_url":"https://api.github.com/users/inaka/following{/other_user}","gists_url":"https://api.github.com/users/inaka/gists{/gist_id}","starred_url":"https://api.github.com/users/inaka/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/inaka/subscriptions","organizations_url":"https://api.github.com/users/inaka/orgs","repos_url":"https://api.github.com/users/inaka/repos","events_url":"https://api.github.com/users/inaka/events{/privacy}","received_events_url":"https://api.github.com/users/inaka/received_events","type":"Organization","site_admin":false},"repo":{"id":22760152,"name":"erlang-katana","full_name":"inaka/erlang-katana","owner":{"login":"inaka","id":867053,"avatar_url":"https://avatars.githubusercontent.com/u/867053?v=2","gravatar_id":"1965362c650bbdd4cbaadf0f1ac45f7e","url":"https://api.github.com/users/inaka","html_url":"https://github.com/inaka","followers_url":"https://api.github.com/users/inaka/followers","following_url":"https://api.github.com/users/inaka/following{/other_user}","gists_url":"https://api.github.com/users/inaka/gists{/gist_id}","starred_url":"https://api.github.com/users/inaka/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/inaka/subscriptions","organizations_url":"https://api.github.com/users/inaka/orgs","repos_url":"https://api.github.com/users/inaka/repos","events_url":"https://api.github.com/users/inaka/events{/privacy}","received_events_url":"https://api.github.com/users/inaka/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/inaka/erlang-katana","description":"Erlang grab bag of useful functions. it should have been called swiss army knife but katanas are deadlier","fork":true,"url":"https://api.github.com/repos/inaka/erlang-katana","forks_url":"https://api.github.com/repos/inaka/erlang-katana/forks","keys_url":"https://api.github.com/repos/inaka/erlang-katana/keys{/key_id}","collaborators_url":"https://api.github.com/repos/inaka/erlang-katana/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/inaka/erlang-katana/teams","hooks_url":"https://api.github.com/repos/inaka/erlang-katana/hooks","issue_events_url":"https://api.github.com/repos/inaka/erlang-katana/issues/events{/number}","events_url":"https://api.github.com/repos/inaka/erlang-katana/events","assignees_url":"https://api.github.com/repos/inaka/erlang-katana/assignees{/user}","branches_url":"https://api.github.com/repos/inaka/erlang-katana/branches{/branch}","tags_url":"https://api.github.com/repos/inaka/erlang-katana/tags","blobs_url":"https://api.github.com/repos/inaka/erlang-katana/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/inaka/erlang-katana/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/inaka/erlang-katana/git/refs{/sha}","trees_url":"https://api.github.com/repos/inaka/erlang-katana/git/trees{/sha}","statuses_url":"https://api.github.com/repos/inaka/erlang-katana/statuses/{sha}","languages_url":"https://api.github.com/repos/inaka/erlang-katana/languages","stargazers_url":"https://api.github.com/repos/inaka/erlang-katana/stargazers","contributors_url":"https://api.github.com/repos/inaka/erlang-katana/contributors","subscribers_url":"https://api.github.com/repos/inaka/erlang-katana/subscribers","subscription_url":"https://api.github.com/repos/inaka/erlang-katana/subscription","commits_url":"https://api.github.com/repos/inaka/erlang-katana/commits{/sha}","git_commits_url":"https://api.github.com/repos/inaka/erlang-katana/git/commits{/sha}","comments_url":"https://api.github.com/repos/inaka/erlang-katana/comments{/number}","issue_comment_url":"https://api.github.com/repos/inaka/erlang-katana/issues/comments/{number}","contents_url":"https://api.github.com/repos/inaka/erlang-katana/contents/{+path}","compare_url":"https://api.github.com/repos/inaka/erlang-katana/compare/{base}...{head}","merges_url":"https://api.github.com/repos/inaka/erlang-katana/merges","archive_url":"https://api.github.com/repos/inaka/erlang-katana/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/inaka/erlang-katana/downloads","issues_url":"https://api.github.com/repos/inaka/erlang-katana/issues{/number}","pulls_url":"https://api.github.com/repos/inaka/erlang-katana/pulls{/number}","milestones_url":"https://api.github.com/repos/inaka/erlang-katana/milestones{/number}","notifications_url":"https://api.github.com/repos/inaka/erlang-katana/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/inaka/erlang-katana/labels{/name}","releases_url":"https://api.github.com/repos/inaka/erlang-katana/releases{/id}","created_at":"2014-08-08T14:20:25Z","updated_at":"2014-08-29T06:13:44Z","pushed_at":"2014-08-31T02:18:29Z","git_url":"git://github.com/inaka/erlang-katana.git","ssh_url":"git@github.com:inaka/erlang-katana.git","clone_url":"https://github.com/inaka/erlang-katana.git","svn_url":"https://github.com/inaka/erlang-katana","homepage":"","size":497,"stargazers_count":4,"watchers_count":4,"language":"Erlang","has_issues":true,"has_downloads":true,"has_wiki":true,"forks_count":0,"mirror_url":null,"open_issues_count":2,"forks":0,"open_issues":2,"watchers":4,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/inaka/erlang-katana/pulls/12"},"html":{"href":"https://github.com/inaka/erlang-katana/pull/12"},"issue":{"href":"https://api.github.com/repos/inaka/erlang-katana/issues/12"},"comments":{"href":"https://api.github.com/repos/inaka/erlang-katana/issues/12/comments"},"review_comments":{"href":"https://api.github.com/repos/inaka/erlang-katana/pulls/12/comments"},"review_comment":{"href":"https://api.github.com/repos/inaka/erlang-katana/pulls/comments/{number}"},"commits":{"href":"https://api.github.com/repos/inaka/erlang-katana/pulls/12/commits"},"statuses":{"href":"https://api.github.com/repos/inaka/erlang-katana/statuses/6aa03732cfa0fbc07819e878ad1c676e49b8814f"}}}}