{"action":"created","comment":{"url":"https://api.github.com/repos/meew0/discordcr/pulls/comments/200835871","pull_request_review_id":135228265,"id":200835871,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIwMDgzNTg3MQ==","diff_hunk":"@@ -1,272 +1,66 @@\n-require \"./mappings/*\"\n-\n module Discord\n-  # A cache is a utility class that stores various kinds of Discord objects,\n-  # like `User`s, `Role`s etc. Its purpose is to reduce both the load on\n-  # Discord's servers and reduce the latency caused by having to do an API call.\n-  # It is recommended to use caching for bots that interact heavily with\n-  # Discord-provided data, like for example administration bots, as opposed to\n-  # bots that only interact by sending and receiving messages. For that latter\n-  # kind, caching is usually even counter-productive as it only unnecessarily\n-  # increases memory usage.\n-  #\n-  # Caching can either be used standalone, in a purely REST-based way:\n-  # ```\n-  # client = Discord::Client.new(token: \"Bot token\", client_id: 123_u64)\n-  # cache = Discord::Cache.new(client)\n-  #\n-  # puts cache.resolve_user(66237334693085184) # will perform API call\n-  # puts cache.resolve_user(66237334693085184) # will not perform an API call, as the data is now cached\n-  # ```\n-  #\n-  # It can also be integrated more deeply into a `Client` (specifically one that\n-  # uses a gateway connection) to reduce cache misses even more by automatically\n-  # caching data received over the gateway:\n-  # ```\n-  # client = Discord::Client.new(token: \"Bot token\", client_id: 123_u64)\n-  # cache = Discord::Cache.new(client)\n-  # client.cache = cache # Integrate the cache into the client\n-  # ```\n-  #\n-  # Note that if a cache is *not* used this way, its data will slowly go out of\n-  # sync with Discord, and unless it is used in an environment with few changes\n-  # likely to occur, a client without a gateway connection should probably\n-  # refrain from caching at all.\n-  class Cache\n-    # A map of cached users. These aren't necessarily all the users in servers\n-    # the bot has access to, but rather all the users that have been seen by\n-    # the bot in the past (and haven't been deleted by means of `delete_user`).\n-    getter users\n-\n-    # A map of cached channels, i. e. all channels on all servers the bot is on,\n-    # as well as all DM channels.\n-    getter channels\n-\n-    # A map of guilds (servers) the bot is on. Doesn't ignore guilds temporarily\n-    # deleted due to an outage; so if an outage is going on right now the\n-    # affected guilds would be missing here too.\n-    getter guilds\n-\n-    # A double map of members on servers, represented as {guild ID => {user ID\n-    # => member}}. Will only contain previously and currently online members as\n-    # well as all members that have been chunked (see\n-    # `Client#request_guild_members`).\n-    getter members\n-\n-    # A map of all roles on servers the bot is on. Does not discriminate by\n-    # guild, as role IDs are unique even across guilds.\n-    getter roles\n-\n-    # Mapping of users to the respective DM channels the bot has open with them,\n-    # represented as {user ID => channel ID}.\n-    getter dm_channels\n-\n-    # Mapping of guilds to the roles on them, represented as {guild ID =>\n-    # [role IDs]}.\n-    getter guild_roles\n-\n-    # Mapping of guilds to the channels on them, represented as {guild ID =>\n-    # [channel IDs]}.\n-    getter guild_channels\n-\n-    # Creates a new cache with a *client* that requests (in case of cache\n-    # misses) should be done on.\n-    def initialize(@client : Client)\n-      @users = Hash(UInt64, User).new\n-      @channels = Hash(UInt64, Channel).new\n-      @guilds = Hash(UInt64, Guild).new\n-      @members = Hash(UInt64, Hash(UInt64, GuildMember)).new\n-      @roles = Hash(UInt64, Role).new\n-\n-      @dm_channels = Hash(UInt64, UInt64).new\n-\n-      @guild_roles = Hash(UInt64, Array(UInt64)).new\n-      @guild_channels = Hash(UInt64, Array(UInt64)).new\n-    end\n-\n-    # Resolves a user by its *ID*. If the requested object is not cached, it\n-    # will do an API call.\n-    def resolve_user(id : UInt64 | Snowflake) : User\n-      id = id.to_u64\n-      @users.fetch(id) { @users[id] = @client.get_user(id) }\n-    end\n-\n-    # Resolves a channel by its *ID*. If the requested object is not cached, it\n-    # will do an API call.\n-    def resolve_channel(id : UInt64 | Snowflake) : Channel\n-      id = id.to_u64\n-      @channels.fetch(id) { @channels[id] = @client.get_channel(id) }\n-    end\n-\n-    # Resolves a guild by its *ID*. If the requested object is not cached, it\n-    # will do an API call.\n-    def resolve_guild(id : UInt64 | Snowflake) : Guild\n-      id = id.to_u64\n-      @guilds.fetch(id) { @guilds[id] = @client.get_guild(id) }\n-    end\n-\n-    # Resolves a member by the *guild_id* of the guild the member is on, and the\n-    # *user_id* of the member itself. An API request will be performed if the\n-    # object is not cached.\n-    def resolve_member(guild_id : UInt64 | Snowflake, user_id : UInt64 | Snowflake) : GuildMember\n-      guild_id = guild_id.to_u64\n-      user_id = user_id.to_u64\n-      local_members = @members[guild_id] ||= Hash(UInt64, GuildMember).new\n-      local_members.fetch(user_id) { local_members[user_id] = @client.get_guild_member(guild_id, user_id) }\n-    end\n-\n-    # Resolves a role by its *ID*. No API request will be performed if the role\n-    # is not cached, because there is no endpoint for individual roles; however\n-    # all roles should be cached at all times so it won't be a problem.\n-    def resolve_role(id : UInt64 | Snowflake) : Role\n-      @roles[id.to_u64] # There is no endpoint for getting an individual role, so we will have to ignore that case for now.\n-    end\n-\n-    # Resolves the ID of a DM channel with a particular user by the recipient's\n-    # *recipient_id*. If there is no such channel cached, one will be created.\n-    def resolve_dm_channel(recipient_id : UInt64 | Snowflake) : UInt64\n-      recipient_id = recipient_id.to_u64\n-      @dm_channels.fetch(recipient_id) do\n-        channel = @client.create_dm(recipient_id)\n-        cache(Channel.new(channel))\n-        channel.id\n-      end\n-    end\n-\n-    # Resolves the current user's profile. Requires no parameters since the\n-    # endpoint has none either. If there is a gateway connection this should\n-    # always be cached.\n-    def resolve_current_user : User\n-      @current_user ||= @client.get_current_user\n-    end\n-\n-    # Deletes a user from the cache given its *ID*.\n-    def delete_user(id : UInt64 | Snowflake)\n-      @users.delete(id.to_u64)\n-    end\n-\n-    # Deletes a channel from the cache given its *ID*.\n-    def delete_channel(id : UInt64 | Snowflake)\n-      @channels.delete(id.to_u64)\n-    end\n-\n-    # Deletes a guild from the cache given its *ID*.\n-    def delete_guild(id : UInt64 | Snowflake)\n-      @guilds.delete(id.to_u64)\n-    end\n-\n-    # Deletes a member from the cache given its *user_id* and the *guild_id* it\n-    # is on.\n-    def delete_member(guild_id : UInt64 | Snowflake, user_id : UInt64 | Snowflake)\n-      guild_id = guild_id.to_u64\n-      user_id = user_id.to_u64\n-      @members[guild_id]?.try &.delete(user_id)\n+  abstract class Cache(K, V)\n+    class Error < Exception\n     end\n \n-    # Deletes a role from the cache given its *ID*.\n-    def delete_role(id : UInt64 | Snowflake)\n-      @roles.delete(id.to_u64)\n-    end\n+    abstract def resolve?(key : K)\n \n-    # Deletes a DM channel with a particular user given the *recipient_id*.\n-    def delete_dm_channel(recipient_id : UInt64 | Snowflake)\n-      @dm_channels.delete(recipient_id.to_u64)\n+    def fetch(key : K) : V\n+      resolve?(key) || cache(key, yield)\n     end\n \n-    # Deletes the current user from the cache, if that will ever be necessary.\n-    def delete_current_user\n-      @current_user = nil\n+    def resolve(key : K) : V\n+      resolve?(key) || raise Error.new(\"Cache member not found: #{key}\")\n     end\n \n-    # Adds a specific *user* to the cache.\n-    def cache(user : User)\n-      @users[user.id.to_u64] = user\n-    end\n+    abstract def cache(key : K, value : V)\n \n-    # Adds a specific *channel* to the cache.\n-    def cache(channel : Channel)\n-      @channels[channel.id.to_u64] = channel\n-    end\n+    abstract def remove(key : K)\n \n-    # Adds a specific *guild* to the cache.\n-    def cache(guild : Guild)\n-      @guilds[guild.id.to_u64] = guild\n-    end\n+    abstract def each(&block : Tuple(K, V) ->)\n+  end\n \n-    # Adds a specific *member* to the cache, given the *guild_id* it is on.\n-    def cache(member : GuildMember, guild_id : UInt64 | Snowflake)\n-      guild_id = guild_id.to_u64\n-      local_members = @members[guild_id] ||= Hash(UInt64, GuildMember).new\n-      local_members[member.user.id.to_u64] = member\n-    end\n+  class MemoryCache(K, V) < Cache(K, V)\n+    include Enumerable(Tuple(K, V))","path":"src/discordcr/cache.cr","position":214,"original_position":214,"commit_id":"5f586adce8cfdc092ba5991b6039cc72c355c6dd","original_commit_id":"5f586adce8cfdc092ba5991b6039cc72c355c6dd","user":{"login":"RX14","id":2788811,"node_id":"MDQ6VXNlcjI3ODg4MTE=","avatar_url":"https://avatars0.githubusercontent.com/u/2788811?v=4","gravatar_id":"","url":"https://api.github.com/users/RX14","html_url":"https://github.com/RX14","followers_url":"https://api.github.com/users/RX14/followers","following_url":"https://api.github.com/users/RX14/following{/other_user}","gists_url":"https://api.github.com/users/RX14/gists{/gist_id}","starred_url":"https://api.github.com/users/RX14/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/RX14/subscriptions","organizations_url":"https://api.github.com/users/RX14/orgs","repos_url":"https://api.github.com/users/RX14/repos","events_url":"https://api.github.com/users/RX14/events{/privacy}","received_events_url":"https://api.github.com/users/RX14/received_events","type":"User","site_admin":false},"body":"If you want this, then put `include Enumerable({K, V})` in the abstract `Cache`, not each individual instance. Otherwise you can't use it.","created_at":"2018-07-08T10:13:25Z","updated_at":"2018-07-08T10:13:26Z","html_url":"https://github.com/meew0/discordcr/pull/136#discussion_r200835871","pull_request_url":"https://api.github.com/repos/meew0/discordcr/pulls/136","author_association":"COLLABORATOR","_links":{"self":{"href":"https://api.github.com/repos/meew0/discordcr/pulls/comments/200835871"},"html":{"href":"https://github.com/meew0/discordcr/pull/136#discussion_r200835871"},"pull_request":{"href":"https://api.github.com/repos/meew0/discordcr/pulls/136"}},"in_reply_to_id":200834216},"pull_request":{"url":"https://api.github.com/repos/meew0/discordcr/pulls/136","id":187150132,"node_id":"MDExOlB1bGxSZXF1ZXN0MTg3MTUwMTMy","html_url":"https://github.com/meew0/discordcr/pull/136","diff_url":"https://github.com/meew0/discordcr/pull/136.diff","patch_url":"https://github.com/meew0/discordcr/pull/136.patch","issue_url":"https://api.github.com/repos/meew0/discordcr/issues/136","number":136,"state":"open","locked":false,"title":"Reimplement Cache","user":{"login":"z64","id":6119032,"node_id":"MDQ6VXNlcjYxMTkwMzI=","avatar_url":"https://avatars0.githubusercontent.com/u/6119032?v=4","gravatar_id":"","url":"https://api.github.com/users/z64","html_url":"https://github.com/z64","followers_url":"https://api.github.com/users/z64/followers","following_url":"https://api.github.com/users/z64/following{/other_user}","gists_url":"https://api.github.com/users/z64/gists{/gist_id}","starred_url":"https://api.github.com/users/z64/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/z64/subscriptions","organizations_url":"https://api.github.com/users/z64/orgs","repos_url":"https://api.github.com/users/z64/repos","events_url":"https://api.github.com/users/z64/events{/privacy}","received_events_url":"https://api.github.com/users/z64/received_events","type":"User","site_admin":false},"body":"Supersedes #92 \r\nCloses #31 \r\nCloses #32 \r\nCloses #33 \r\n\r\n- ~~Can cache configuration be improved?~~ Done, we now have `client.configure_caches`\r\n- ~~Should we provide an alias for each cache type? It might be easy to specify the wrong generic.~~ This is now taken care of by `CacheConfigurator` macros that inject the correct generic\r\n\r\n---\r\nTodo: \r\n- [ ] Documentation\r\n- [ ] Rework `Cache` API to be more hash-like\r\n- [x] `CacheConfigurator` - `macro all_caches`\r\n- [ ] Rework index cache usage in caching handlers\r\n- [ ] `Cache#clear`","created_at":"2018-05-10T09:59:34Z","updated_at":"2018-07-08T10:13:26Z","closed_at":null,"merged_at":null,"merge_commit_sha":"52a3d1b6ccd24e46633b8eae926b830b5f17221f","assignee":null,"assignees":[],"requested_reviewers":[{"login":"meew0","id":3662915,"node_id":"MDQ6VXNlcjM2NjI5MTU=","avatar_url":"https://avatars0.githubusercontent.com/u/3662915?v=4","gravatar_id":"","url":"https://api.github.com/users/meew0","html_url":"https://github.com/meew0","followers_url":"https://api.github.com/users/meew0/followers","following_url":"https://api.github.com/users/meew0/following{/other_user}","gists_url":"https://api.github.com/users/meew0/gists{/gist_id}","starred_url":"https://api.github.com/users/meew0/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/meew0/subscriptions","organizations_url":"https://api.github.com/users/meew0/orgs","repos_url":"https://api.github.com/users/meew0/repos","events_url":"https://api.github.com/users/meew0/events{/privacy}","received_events_url":"https://api.github.com/users/meew0/received_events","type":"User","site_admin":false}],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/meew0/discordcr/pulls/136/commits","review_comments_url":"https://api.github.com/repos/meew0/discordcr/pulls/136/comments","review_comment_url":"https://api.github.com/repos/meew0/discordcr/pulls/comments{/number}","comments_url":"https://api.github.com/repos/meew0/discordcr/issues/136/comments","statuses_url":"https://api.github.com/repos/meew0/discordcr/statuses/5f586adce8cfdc092ba5991b6039cc72c355c6dd","head":{"label":"z64:refactor/cache-2","ref":"refactor/cache-2","sha":"5f586adce8cfdc092ba5991b6039cc72c355c6dd","user":{"login":"z64","id":6119032,"node_id":"MDQ6VXNlcjYxMTkwMzI=","avatar_url":"https://avatars0.githubusercontent.com/u/6119032?v=4","gravatar_id":"","url":"https://api.github.com/users/z64","html_url":"https://github.com/z64","followers_url":"https://api.github.com/users/z64/followers","following_url":"https://api.github.com/users/z64/following{/other_user}","gists_url":"https://api.github.com/users/z64/gists{/gist_id}","starred_url":"https://api.github.com/users/z64/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/z64/subscriptions","organizations_url":"https://api.github.com/users/z64/orgs","repos_url":"https://api.github.com/users/z64/repos","events_url":"https://api.github.com/users/z64/events{/privacy}","received_events_url":"https://api.github.com/users/z64/received_events","type":"User","site_admin":false},"repo":{"id":82604279,"node_id":"MDEwOlJlcG9zaXRvcnk4MjYwNDI3OQ==","name":"discordcr","full_name":"z64/discordcr","owner":{"login":"z64","id":6119032,"node_id":"MDQ6VXNlcjYxMTkwMzI=","avatar_url":"https://avatars0.githubusercontent.com/u/6119032?v=4","gravatar_id":"","url":"https://api.github.com/users/z64","html_url":"https://github.com/z64","followers_url":"https://api.github.com/users/z64/followers","following_url":"https://api.github.com/users/z64/following{/other_user}","gists_url":"https://api.github.com/users/z64/gists{/gist_id}","starred_url":"https://api.github.com/users/z64/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/z64/subscriptions","organizations_url":"https://api.github.com/users/z64/orgs","repos_url":"https://api.github.com/users/z64/repos","events_url":"https://api.github.com/users/z64/events{/privacy}","received_events_url":"https://api.github.com/users/z64/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/z64/discordcr","description":"Minimalist Discord library for Crystal. (Still WIP, but usable)","fork":true,"url":"https://api.github.com/repos/z64/discordcr","forks_url":"https://api.github.com/repos/z64/discordcr/forks","keys_url":"https://api.github.com/repos/z64/discordcr/keys{/key_id}","collaborators_url":"https://api.github.com/repos/z64/discordcr/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/z64/discordcr/teams","hooks_url":"https://api.github.com/repos/z64/discordcr/hooks","issue_events_url":"https://api.github.com/repos/z64/discordcr/issues/events{/number}","events_url":"https://api.github.com/repos/z64/discordcr/events","assignees_url":"https://api.github.com/repos/z64/discordcr/assignees{/user}","branches_url":"https://api.github.com/repos/z64/discordcr/branches{/branch}","tags_url":"https://api.github.com/repos/z64/discordcr/tags","blobs_url":"https://api.github.com/repos/z64/discordcr/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/z64/discordcr/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/z64/discordcr/git/refs{/sha}","trees_url":"https://api.github.com/repos/z64/discordcr/git/trees{/sha}","statuses_url":"https://api.github.com/repos/z64/discordcr/statuses/{sha}","languages_url":"https://api.github.com/repos/z64/discordcr/languages","stargazers_url":"https://api.github.com/repos/z64/discordcr/stargazers","contributors_url":"https://api.github.com/repos/z64/discordcr/contributors","subscribers_url":"https://api.github.com/repos/z64/discordcr/subscribers","subscription_url":"https://api.github.com/repos/z64/discordcr/subscription","commits_url":"https://api.github.com/repos/z64/discordcr/commits{/sha}","git_commits_url":"https://api.github.com/repos/z64/discordcr/git/commits{/sha}","comments_url":"https://api.github.com/repos/z64/discordcr/comments{/number}","issue_comment_url":"https://api.github.com/repos/z64/discordcr/issues/comments{/number}","contents_url":"https://api.github.com/repos/z64/discordcr/contents/{+path}","compare_url":"https://api.github.com/repos/z64/discordcr/compare/{base}...{head}","merges_url":"https://api.github.com/repos/z64/discordcr/merges","archive_url":"https://api.github.com/repos/z64/discordcr/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/z64/discordcr/downloads","issues_url":"https://api.github.com/repos/z64/discordcr/issues{/number}","pulls_url":"https://api.github.com/repos/z64/discordcr/pulls{/number}","milestones_url":"https://api.github.com/repos/z64/discordcr/milestones{/number}","notifications_url":"https://api.github.com/repos/z64/discordcr/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/z64/discordcr/labels{/name}","releases_url":"https://api.github.com/repos/z64/discordcr/releases{/id}","deployments_url":"https://api.github.com/repos/z64/discordcr/deployments","created_at":"2017-02-20T21:26:01Z","updated_at":"2018-05-16T13:56:29Z","pushed_at":"2018-07-07T15:47:31Z","git_url":"git://github.com/z64/discordcr.git","ssh_url":"git@github.com:z64/discordcr.git","clone_url":"https://github.com/z64/discordcr.git","svn_url":"https://github.com/z64/discordcr","homepage":"","size":715,"stargazers_count":0,"watchers_count":0,"language":"Crystal","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"meew0:master","ref":"master","sha":"21ea6bcf82107f21e05cb38068127b391989519e","user":{"login":"meew0","id":3662915,"node_id":"MDQ6VXNlcjM2NjI5MTU=","avatar_url":"https://avatars0.githubusercontent.com/u/3662915?v=4","gravatar_id":"","url":"https://api.github.com/users/meew0","html_url":"https://github.com/meew0","followers_url":"https://api.github.com/users/meew0/followers","following_url":"https://api.github.com/users/meew0/following{/other_user}","gists_url":"https://api.github.com/users/meew0/gists{/gist_id}","starred_url":"https://api.github.com/users/meew0/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/meew0/subscriptions","organizations_url":"https://api.github.com/users/meew0/orgs","repos_url":"https://api.github.com/users/meew0/repos","events_url":"https://api.github.com/users/meew0/events{/privacy}","received_events_url":"https://api.github.com/users/meew0/received_events","type":"User","site_admin":false},"repo":{"id":67284615,"node_id":"MDEwOlJlcG9zaXRvcnk2NzI4NDYxNQ==","name":"discordcr","full_name":"meew0/discordcr","owner":{"login":"meew0","id":3662915,"node_id":"MDQ6VXNlcjM2NjI5MTU=","avatar_url":"https://avatars0.githubusercontent.com/u/3662915?v=4","gravatar_id":"","url":"https://api.github.com/users/meew0","html_url":"https://github.com/meew0","followers_url":"https://api.github.com/users/meew0/followers","following_url":"https://api.github.com/users/meew0/following{/other_user}","gists_url":"https://api.github.com/users/meew0/gists{/gist_id}","starred_url":"https://api.github.com/users/meew0/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/meew0/subscriptions","organizations_url":"https://api.github.com/users/meew0/orgs","repos_url":"https://api.github.com/users/meew0/repos","events_url":"https://api.github.com/users/meew0/events{/privacy}","received_events_url":"https://api.github.com/users/meew0/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/meew0/discordcr","description":"Minimalist Discord library for Crystal. (Still WIP, but usable)","fork":false,"url":"https://api.github.com/repos/meew0/discordcr","forks_url":"https://api.github.com/repos/meew0/discordcr/forks","keys_url":"https://api.github.com/repos/meew0/discordcr/keys{/key_id}","collaborators_url":"https://api.github.com/repos/meew0/discordcr/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/meew0/discordcr/teams","hooks_url":"https://api.github.com/repos/meew0/discordcr/hooks","issue_events_url":"https://api.github.com/repos/meew0/discordcr/issues/events{/number}","events_url":"https://api.github.com/repos/meew0/discordcr/events","assignees_url":"https://api.github.com/repos/meew0/discordcr/assignees{/user}","branches_url":"https://api.github.com/repos/meew0/discordcr/branches{/branch}","tags_url":"https://api.github.com/repos/meew0/discordcr/tags","blobs_url":"https://api.github.com/repos/meew0/discordcr/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/meew0/discordcr/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/meew0/discordcr/git/refs{/sha}","trees_url":"https://api.github.com/repos/meew0/discordcr/git/trees{/sha}","statuses_url":"https://api.github.com/repos/meew0/discordcr/statuses/{sha}","languages_url":"https://api.github.com/repos/meew0/discordcr/languages","stargazers_url":"https://api.github.com/repos/meew0/discordcr/stargazers","contributors_url":"https://api.github.com/repos/meew0/discordcr/contributors","subscribers_url":"https://api.github.com/repos/meew0/discordcr/subscribers","subscription_url":"https://api.github.com/repos/meew0/discordcr/subscription","commits_url":"https://api.github.com/repos/meew0/discordcr/commits{/sha}","git_commits_url":"https://api.github.com/repos/meew0/discordcr/git/commits{/sha}","comments_url":"https://api.github.com/repos/meew0/discordcr/comments{/number}","issue_comment_url":"https://api.github.com/repos/meew0/discordcr/issues/comments{/number}","contents_url":"https://api.github.com/repos/meew0/discordcr/contents/{+path}","compare_url":"https://api.github.com/repos/meew0/discordcr/compare/{base}...{head}","merges_url":"https://api.github.com/repos/meew0/discordcr/merges","archive_url":"https://api.github.com/repos/meew0/discordcr/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/meew0/discordcr/downloads","issues_url":"https://api.github.com/repos/meew0/discordcr/issues{/number}","pulls_url":"https://api.github.com/repos/meew0/discordcr/pulls{/number}","milestones_url":"https://api.github.com/repos/meew0/discordcr/milestones{/number}","notifications_url":"https://api.github.com/repos/meew0/discordcr/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/meew0/discordcr/labels{/name}","releases_url":"https://api.github.com/repos/meew0/discordcr/releases{/id}","deployments_url":"https://api.github.com/repos/meew0/discordcr/deployments","created_at":"2016-09-03T10:30:24Z","updated_at":"2018-07-07T19:43:57Z","pushed_at":"2018-07-07T19:44:52Z","git_url":"git://github.com/meew0/discordcr.git","ssh_url":"git@github.com:meew0/discordcr.git","clone_url":"https://github.com/meew0/discordcr.git","svn_url":"https://github.com/meew0/discordcr","homepage":"https://discord.gg/puaxPkK","size":2341,"stargazers_count":67,"watchers_count":67,"language":"Crystal","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":29,"mirror_url":null,"archived":false,"open_issues_count":19,"license":{"key":"mit","name":"MIT License","spdx_id":"MIT","url":"https://api.github.com/licenses/mit","node_id":"MDc6TGljZW5zZTEz"},"forks":29,"open_issues":19,"watchers":67,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/meew0/discordcr/pulls/136"},"html":{"href":"https://github.com/meew0/discordcr/pull/136"},"issue":{"href":"https://api.github.com/repos/meew0/discordcr/issues/136"},"comments":{"href":"https://api.github.com/repos/meew0/discordcr/issues/136/comments"},"review_comments":{"href":"https://api.github.com/repos/meew0/discordcr/pulls/136/comments"},"review_comment":{"href":"https://api.github.com/repos/meew0/discordcr/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/meew0/discordcr/pulls/136/commits"},"statuses":{"href":"https://api.github.com/repos/meew0/discordcr/statuses/5f586adce8cfdc092ba5991b6039cc72c355c6dd"}},"author_association":"CONTRIBUTOR"}}
{"actor":{"display_login":"RX14"}}