{"action":"created","comment":{"url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/pulls/comments/170759818","pull_request_review_id":99494556,"id":170759818,"diff_hunk":"@@ -1,919 +1,916 @@\n-// Mafia chat plugin.\n-// By bumbadadabum, with input from Zarel and art by crobat.\n-\n 'use strict';\n \n-let MafiaData = require('./mafia-data');\n-\n-const deadImage = '<img width=\"75\" height=\"75\" src=\"//play.pokemonshowdown.com/fx/mafia-dead.png\" />';\n-const meetingMsg = {town: 'The town has lynched a suspect!', mafia: 'The mafia strikes again!'};\n-\n-const defaultSettings = {anonVotes: false, allowWills: false, autoModchat: false};\n+let MafiaData = require('./mafia-data.js');\n \n class MafiaPlayer extends Rooms.RoomGamePlayer {\n \tconstructor(user, game) {\n \t\tsuper(user, game);\n+\t\tthis.name = Chat.escapeHTML(this.name);\n+\t\t// Used for when a player changes their name\n+\t\t/*this.originalName = this.name;\n+\t\tthis.originalId = this.userid;*/\n+\t\tthis.role = null;\n+\t\tthis.lynching = '';\n \t}\n \n-\tget targeting() {\n-\t\treturn this.validTargets && Object.keys(this.validTargets).length > 0;\n+\tgetRole() {\n+\t\tif (!this.role) return;\n+\t\treturn `<span style=\"font-weight:bold;color:${MafiaData.alignments[this.role.alignment].color}\">${this.role.name}</span>`;\n \t}\n \n-\tget voting() {\n-\t\treturn this.validVotes && Object.keys(this.validVotes).length > 0;\n+\tupdateHtmlRoom() {\n+\t\tlet user = Users(this.userid);\n+\t\tif (!user || !user.connected) return;\n+\t\tif (this.game.ended) return user.send(`>view-mafia-${this.game.room.id}\\n|deinit`);\n+\t\tlet buf = Chat.pages.mafia([this.game.room.id], user);\n+\t\tthis.send(`>view-mafia-${this.game.room.id}\\n|init|html\\n${buf}`);\n \t}\n+}\n \n-\tget done() {\n-\t\treturn (!this.voting || this.game.currentVote.has(this)) && (!this.targeting || this.target);\n-\t}\n+class MafiaTracker extends Rooms.RoomGame {\n+\tconstructor(room, host) {\n+\t\tsuper(room);\n \n-\tevent(event) {\n-\t\tif (this.class[event].target) {\n-\t\t\tif (this.class[event].oneshot) {\n-\t\t\t\tif (!this.used) this.used = {};\n-\t\t\t\tif (this.used[event]) return;\n-\t\t\t\tthis.using = event;\n-\t\t\t}\n-\t\t\tthis.toExecute = this.class[event].callback;\n-\t\t\tif (this.class[event].target.count === 'single') {\n-\t\t\t\tthis.singleTarget(this.class[event].target.side);\n-\t\t\t}\n-\t\t\tthis.targetWindow(this.class.image, this.class[event].flavorText);\n-\t\t} else {\n-\t\t\tthis.toExecute = this.class[event].function;\n-\t\t}\n+\t\tthis.gameid = 'mafia';\n+\t\tthis.title = 'Mafia';\n+\t\tthis.playerCap = 20;\n+\t\tthis.allowRenames = false;\n+\t\tthis.started = false;\n+\t\tthis.ended = false;\n+\n+\t\tthis.hostid = host.userid;\n+\t\tthis.host = Chat.escapeHTML(host.name);\n+\n+\t\tthis.players = {};\n+\t\tthis.dead = {};\n+\t\tthis.subs = [];\n+\t\tthis.requestedSub = [];\n+\t\tthis.played = [];\n+\n+\t\tthis.lynches = {};\n+\n+\t\tthis.originalRoles = [];\n+\t\tthis.originalRoleString = '';\n+\t\tthis.roles = [];\n+\t\tthis.roleString = '';\n+\n+\t\tthis.phase = \"signups\";\n+\t\tthis.dayNum = 0;\n+\t\tthis.closedSetup = false;\n+\t\tthis.noReveal = false;\n+\t\tthis.selfEnabled = false;\n+\t\tthis.timer = null;\n \n-\t\tthis.game.executionOrder.push(this);\n+\t\tthis.sendRoom(this.roomWindow(), {uhtml: true});\n \t}\n \n-\tkill(flavorText) {\n-\t\tif (this.invincible) return;\n-\n-\t\tlet message = flavorText + '<br />' + Chat.escapeHTML(this.name + ', the ' + this.class.name) + ' lies dead on the ground.';\n-\n-\t\tif (this.allowWills && this.will) {\n-\t\t\tmessage += '<br />' + Chat.escapeHTML(this.name) + '\\'s will: ' + Chat.escapeHTML(this.will);\n+\tjoin(user) {\n+\t\tif (this.phase !== 'signups') return user.sendTo(this.room, `|error|The game of ${this.title} has already started.`);\n+\t\tif (user.userid === this.hostid) return user.sendTo(this.room, `|error|You cannot host and play!`);\n+\t\tlet alts = user.getAltUsers(true);\n+\t\tfor (let alt of alts) {\n+\t\t\tif (Object.keys(this.players).includes(alt)) return user.sendTo(this.room, `|error|You already have an alt in the game.`);\n \t\t}\n-\n-\t\tthis.game.announcementWindow(deadImage, message);\n-\t\tthis.game.playerCount--;\n-\t\tthis.game.dead.push(this.name);\n-\t\tdelete this.game.players[this.userid];\n-\t\tthis.destroy();\n-\t}\n-\n-\teliminate() {\n-\t\tif (this.game.gamestate === 'pregame') {\n-\t\t\tthis.game.announcementWindow('', Chat.escapeHTML(this.name) + ' was kicked from the game.');\n+\t\tif (this.addPlayer(user)) {\n+\t\t\tthis.updatePlayers();\n \t\t} else {\n-\t\t\tthis.game.announcementWindow(deadImage, Chat.escapeHTML(this.name + ', the ' + this.class.name) + ' was eliminated from the game.');\n+\t\t\treturn user.sendTo(this.room, `|error|You have already joined the game of ${this.title}.`);\n \t\t}\n-\t\tthis.game.playerCount--;\n-\t\tthis.game.dead.push(this.name);\n-\t\tdelete this.game.players[this.userid];\n-\t\tthis.destroy();\n \t}\n \n-\tplayerWindow(image, content) {\n-\t\tthis.sendRoom('|html|' + this.game.mafiaWindow(image, content));\n+\tleave(user) {\n+\t\tif (!(user.userid in this.players)) return user.sendTo(this.room, `|error|You have not joined the game of ${this.title}.`);\n+\t\tif (this.phase !== 'signups') return user.sendTo(this.room, `|error|The game of ${this.title} has already started.`);\n+\t\tthis.players[user.userid].destroy();\n+\t\tdelete this.players[user.userid];\n+\t\tthis.updatePlayers();\n+\t\tuser.send(`>view-mafia-${this.room.id}\\n|init|html\\n${Chat.pages.mafia([this.room.id], user)}`);\n \t}\n \n-\tgetRole() {\n-\t\tthis.sendRoom('|html|' + this.game.mafiaWindow(this.class.image, Chat.escapeHTML(this.class.flavorText)));\n+\tmakePlayer(user) {\n+\t\treturn new MafiaPlayer(user, this);\n \t}\n \n-\ttargetWindow(image, content, update) {\n-\t\tlet output = content;\n-\t\toutput += '<br /><p>Who do you wish to target?</p>';\n-\t\tfor (let i in this.validTargets) {\n-\t\t\toutput += '<button value=\"/choose target ' + this.validTargets[i].userid + '\" name=\"send\">' + Chat.escapeHTML(this.validTargets[i].name) + '</button>';\n-\t\t}\n-\t\toutput += '<button value=\"/choose target none\" name=\"send\">Nobody</button>';\n-\n-\t\tif (update) {\n-\t\t\tthis.sendRoom('|uhtmlchange|mafia' + this.game.room.gameNumber + 'target' + this.game.gamestate + this.game.day + '|' + this.game.mafiaWindow(image, output));\n-\t\t} else {\n-\t\t\tthis.sendRoom('|uhtml|mafia' + this.game.room.gameNumber + 'target' + this.game.gamestate + this.game.day + '|' + this.game.mafiaWindow(image, output));\n-\t\t}\n+\tsetRoles(roleString) {\n+\t\tlet roles = roleString.split(',').map(x => { return x.trim().split(' '); });\n+\t\tif (roles.length !== this.playerCount) return ['You have not provided enough roles for the players.'];\n+\t\tif (this.originalRoles.length) {\n+\t\t\t// Reset roles\n+\t\t\tthis.originalRoles = [];\n+\t\t\tthis.originalRoleString = '';\n+\t\t\tthis.roles = [];\n+\t\t\tthis.roleString = '';\n+\t\t}\n+\t\tlet problems = [];\n+\t\tlet hasProblem = true;\n+\t\tlet alignments = [];\n+\t\tfor (let r of roles) {\n+\t\t\thasProblem = false;\n+\t\t\tlet role = {};\n+\t\t\tlet target = r.slice();\n+\t\t\tfor (let j = 0; j < target.length; j++) {\n+\t\t\t\tlet id = toId(target[j]);\n+\t\t\t\tif (MafiaData.roles[id]) {\n+\t\t\t\t\tif (typeof MafiaData.roles[id] === 'string') {\n+\t\t\t\t\t\ttarget[j] = MafiaData.roles[MafiaData.roles[id]].name;\n+\t\t\t\t\t\tid = toId(target[j]);\n+\t\t\t\t\t}\n+\t\t\t\t\tif (role.id) {\n+\t\t\t\t\t\thasProblem = true;\n+\t\t\t\t\t\tproblems.push(`The role \"${role.name}\" has multiple possible base roles (${MafiaData.roles[id].id} or ${role.baseRole})`);\n+\t\t\t\t\t\tbreak;\n+\t\t\t\t\t}\n+\t\t\t\t\trole = Object.assign({}, MafiaData.roles[id]);\n+\t\t\t\t\trole.baseRole = toId(role.name);\n+\t\t\t\t\trole.name = target.slice().map(p => { return toId(p) === 'solo' ? '' : p; }).join(' ');\n+\t\t\t\t\trole.id = toId(role.name);\n+\t\t\t\t\tif (!role.memo) role.memo = [];\n+\t\t\t\t\trole.memo.unshift('During the Day, you may vote for whomever you want lynched.');\n+\t\t\t\t\ttarget.splice(j, 1);\n+\t\t\t\t\tj++;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif (hasProblem) continue;\n+\t\t\tif (!role.name) role = {name: target.join(' '), id: toId(target.join('')), memo: []};\n+\t\t\t// Add modifiers\n+\t\t\tfor (let j = 0; j < target.length; j++) {\n+\t\t\t\tlet id = toId(target[j]);\n+\t\t\t\tif (id.endsWith('shot') && parseInt(target[j].substring(0, 1))) {\n+\t\t\t\t\t// Special case for X-Shot modifiers\n+\t\t\t\t\tlet number = target[j].substring(0, 1);\n+\t\t\t\t\tlet memo = MafiaData.modifiers.xshot.memo.slice();\n+\t\t\t\t\tmemo = memo.map(m => { return m.replace(/X/g, number); });\n+\t\t\t\t\trole.memo = role.memo.concat(memo);\n+\t\t\t\t\ttarget.splice(j, 1);\n+\t\t\t\t\tj--;\n+\t\t\t\t} else if (MafiaData.modifiers[id]) {\n+\t\t\t\t\tif (typeof MafiaData.modifiers[id] === 'string') target[j] = MafiaData.modifiers[id];\n+\t\t\t\t\tif (MafiaData.modifiers[id].memo) role.memo = role.memo.concat(MafiaData.modifiers[id].memo);\n+\t\t\t\t\ttarget.splice(j, 1);\n+\t\t\t\t\tj--;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif (hasProblem) continue;\n+\t\t\t// Determine the role's alignment\n+\t\t\tfor (let j = 0; j < target.length; j++) {\n+\t\t\t\tlet id = toId(target[j]);\n+\t\t\t\tif (MafiaData.alignments[id]) {\n+\t\t\t\t\tif (typeof MafiaData.alignments[id] === 'string') target[j] = MafiaData.alignments[id];\n+\t\t\t\t\tif (role.alignment) {\n+\t\t\t\t\t\t// A role cant have multiple alignments\n+\t\t\t\t\t\thasProblem = true;\n+\t\t\t\t\t\tproblems.push(`The role \"${role.name}\" has multiple possible alignments (${MafiaData.alignments[id].id} or ${role.alignment})`);\n+\t\t\t\t\t\tbreak;\n+\t\t\t\t\t}\n+\t\t\t\t\trole.alignment = MafiaData.alignments[id].id;\n+\t\t\t\t\trole.memo = role.memo.concat(MafiaData.alignments[id].memo);\n+\t\t\t\t\tif (!role.image && MafiaData.alignments[id].image) role.image = MafiaData.alignments[id].image;\n+\t\t\t\t\ttarget.splice(j, 1);\n+\t\t\t\t\tj--;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\tif (!role.alignment) role.alignment = 'town'; // Default to town\n+\t\t\tif (alignments.indexOf(role.alignment) === -1) alignments.push(role.alignment);\n+\t\t\t// Handle anything that is unknown\n+\t\t\tif (target.length) {\n+\t\t\t\trole.memo.push(`To learn more about your role, PM the host (${this.host}).`);\n+\t\t\t}\n+\t\t\tthis.originalRoles.push(role);\n+\t\t}\n+\t\tif (alignments.length < 2) problems.push(`There must be at least 2 different alignments in a game!`);\n+\t\tif (problems.length) {\n+\t\t\tthis.originalRoles = [];\n+\t\t\treturn problems;\n+\t\t}\n+\t\tthis.roles = this.originalRoles.slice();\n+\t\tthis.originalRoleString = this.originalRoles.slice().map(r => { return `<span style=\"font-weight:bold;color:${MafiaData.alignments[r.alignment].color || '#FFF'}\">${r.name}</span>`; }).join(', ');\n+\t\tthis.roleString = this.originalRoleString;\n+\t\tthis.updatePlayers();\n+\t\treturn [];","path":"chat-plugins/mafia.js","position":261,"original_position":261,"commit_id":"a19178b4a78aba4ca6e388d96e506ee4fb68a54c","original_commit_id":"a19178b4a78aba4ca6e388d96e506ee4fb68a54c","user":{"login":"panpawn","id":5314189,"avatar_url":"https://avatars3.githubusercontent.com/u/5314189?v=4","gravatar_id":"","url":"https://api.github.com/users/panpawn","html_url":"https://github.com/panpawn","followers_url":"https://api.github.com/users/panpawn/followers","following_url":"https://api.github.com/users/panpawn/following{/other_user}","gists_url":"https://api.github.com/users/panpawn/gists{/gist_id}","starred_url":"https://api.github.com/users/panpawn/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/panpawn/subscriptions","organizations_url":"https://api.github.com/users/panpawn/orgs","repos_url":"https://api.github.com/users/panpawn/repos","events_url":"https://api.github.com/users/panpawn/events{/privacy}","received_events_url":"https://api.github.com/users/panpawn/received_events","type":"User","site_admin":false},"body":"Manually returning an empty array here seems like a strange behavior, could it return ``false`` or ``null`` (preferably) instead?","created_at":"2018-02-26T22:36:46Z","updated_at":"2018-02-26T22:49:34Z","html_url":"https://github.com/Zarel/Pokemon-Showdown/pull/4438#discussion_r170759818","pull_request_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/pulls/4438","author_association":"CONTRIBUTOR","_links":{"self":{"href":"https://api.github.com/repos/Zarel/Pokemon-Showdown/pulls/comments/170759818"},"html":{"href":"https://github.com/Zarel/Pokemon-Showdown/pull/4438#discussion_r170759818"},"pull_request":{"href":"https://api.github.com/repos/Zarel/Pokemon-Showdown/pulls/4438"}}},"pull_request":{"url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/pulls/4438","id":171509600,"html_url":"https://github.com/Zarel/Pokemon-Showdown/pull/4438","diff_url":"https://github.com/Zarel/Pokemon-Showdown/pull/4438.diff","patch_url":"https://github.com/Zarel/Pokemon-Showdown/pull/4438.patch","issue_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/issues/4438","number":4438,"state":"open","locked":false,"title":"Reprogram Mafia Plugin","user":{"login":"HoeenCoder","id":11671268,"avatar_url":"https://avatars2.githubusercontent.com/u/11671268?v=4","gravatar_id":"","url":"https://api.github.com/users/HoeenCoder","html_url":"https://github.com/HoeenCoder","followers_url":"https://api.github.com/users/HoeenCoder/followers","following_url":"https://api.github.com/users/HoeenCoder/following{/other_user}","gists_url":"https://api.github.com/users/HoeenCoder/gists{/gist_id}","starred_url":"https://api.github.com/users/HoeenCoder/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/HoeenCoder/subscriptions","organizations_url":"https://api.github.com/users/HoeenCoder/orgs","repos_url":"https://api.github.com/users/HoeenCoder/repos","events_url":"https://api.github.com/users/HoeenCoder/events{/privacy}","received_events_url":"https://api.github.com/users/HoeenCoder/received_events","type":"User","site_admin":false},"body":"The current mafia plugin is unused (by all public rooms including mafia at least), and doesn't run a proper game of classic mafia (the only mode it supports). With the mafia room losing access to a reliable bot host, the room owners have decided that its time to restart work on the server script.\r\n\r\n**Features/TODO** (Do not merge till these are all complete)\r\n- [x] Mafia Game Tracker - The most important part. The tracker assists the host with running the game by tracking players, roles, game phase, and lynch counts. It features an HTML room for displaying information, and taking actions (buttons), and uses the chat room the game was created in for game discussion. It also adds multiple new features such as limiting who can talk during a game (this allows us to stop roomvoicing unauthed hosts in the mafia room, and discontinue using modchat at night).\r\n- [ ] Play/Host logs. (Only works in the Mafia room) Simply put, data that would be stored as JSON that tracks how often a user has played/hosted for the past month. \r\n- [ ] Official Games Leaderbord. (Only works in the Mafia room) The mafia room hosts official games 2-4 times per day, winning these games awards you with points and a winner is determined at the end of the month. The data would, once again, be stored in JSON.\r\n- [ ] Role Compendium & Terms List. Contains information about common mafia roles, modifiers and alignments, and terms. This information is displayed as appropriate to players, and will also be accessible via a broadcastable command. These will also support aliases such as VT -> Villager. _(Partially implemented, see mafia-data.js)_\r\n---\r\nI'm pull requesting this now so the code can be reviewed.\r\n\r\nA possible concern (that @Zarel brought up when i was coding help tickets, and applys to this as well) is bandwidth usage when automatically updating the HTML room. The functions that do this are `game#updatePlayers()` (updates host's and all players rooms) and `game#updateHost()` (updates the host's HTML room only).\r\n\r\nAnother issue that I've run into is properly updating the host's HTML room, the host can use buttons to change what is displayed in the room (like with the help ticket form), this changes the room id (ex: `view-mafia-mafia` -> `view-mafia-mafia-general`). The update function just refreshes the default view causing the host to have 2 HTML rooms up. Any thoughts on a fix for this? I could use and style a `details` tag i suppose but I thought I would ask here first.","created_at":"2018-02-26T22:25:10Z","updated_at":"2018-02-26T22:49:35Z","closed_at":null,"merged_at":null,"merge_commit_sha":"ba22d188682d83fc416b3110fd832d7f467b8dae","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[{"id":301796557,"url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/labels/do%20not%20merge","name":"do not merge","color":"555555","default":false}],"milestone":null,"commits_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/pulls/4438/commits","review_comments_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/pulls/4438/comments","review_comment_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/pulls/comments{/number}","comments_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/issues/4438/comments","statuses_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/statuses/a19178b4a78aba4ca6e388d96e506ee4fb68a54c","head":{"label":"HoeenCoder:mafia","ref":"mafia","sha":"a19178b4a78aba4ca6e388d96e506ee4fb68a54c","user":{"login":"HoeenCoder","id":11671268,"avatar_url":"https://avatars2.githubusercontent.com/u/11671268?v=4","gravatar_id":"","url":"https://api.github.com/users/HoeenCoder","html_url":"https://github.com/HoeenCoder","followers_url":"https://api.github.com/users/HoeenCoder/followers","following_url":"https://api.github.com/users/HoeenCoder/following{/other_user}","gists_url":"https://api.github.com/users/HoeenCoder/gists{/gist_id}","starred_url":"https://api.github.com/users/HoeenCoder/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/HoeenCoder/subscriptions","organizations_url":"https://api.github.com/users/HoeenCoder/orgs","repos_url":"https://api.github.com/users/HoeenCoder/repos","events_url":"https://api.github.com/users/HoeenCoder/events{/privacy}","received_events_url":"https://api.github.com/users/HoeenCoder/received_events","type":"User","site_admin":false},"repo":{"id":87460200,"name":"Pokemon-Showdown","full_name":"HoeenCoder/Pokemon-Showdown","owner":{"login":"HoeenCoder","id":11671268,"avatar_url":"https://avatars2.githubusercontent.com/u/11671268?v=4","gravatar_id":"","url":"https://api.github.com/users/HoeenCoder","html_url":"https://github.com/HoeenCoder","followers_url":"https://api.github.com/users/HoeenCoder/followers","following_url":"https://api.github.com/users/HoeenCoder/following{/other_user}","gists_url":"https://api.github.com/users/HoeenCoder/gists{/gist_id}","starred_url":"https://api.github.com/users/HoeenCoder/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/HoeenCoder/subscriptions","organizations_url":"https://api.github.com/users/HoeenCoder/orgs","repos_url":"https://api.github.com/users/HoeenCoder/repos","events_url":"https://api.github.com/users/HoeenCoder/events{/privacy}","received_events_url":"https://api.github.com/users/HoeenCoder/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/HoeenCoder/Pokemon-Showdown","description":"Pokémon battle simulator.","fork":true,"url":"https://api.github.com/repos/HoeenCoder/Pokemon-Showdown","forks_url":"https://api.github.com/repos/HoeenCoder/Pokemon-Showdown/forks","keys_url":"https://api.github.com/repos/HoeenCoder/Pokemon-Showdown/keys{/key_id}","collaborators_url":"https://api.github.com/repos/HoeenCoder/Pokemon-Showdown/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/HoeenCoder/Pokemon-Showdown/teams","hooks_url":"https://api.github.com/repos/HoeenCoder/Pokemon-Showdown/hooks","issue_events_url":"https://api.github.com/repos/HoeenCoder/Pokemon-Showdown/issues/events{/number}","events_url":"https://api.github.com/repos/HoeenCoder/Pokemon-Showdown/events","assignees_url":"https://api.github.com/repos/HoeenCoder/Pokemon-Showdown/assignees{/user}","branches_url":"https://api.github.com/repos/HoeenCoder/Pokemon-Showdown/branches{/branch}","tags_url":"https://api.github.com/repos/HoeenCoder/Pokemon-Showdown/tags","blobs_url":"https://api.github.com/repos/HoeenCoder/Pokemon-Showdown/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/HoeenCoder/Pokemon-Showdown/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/HoeenCoder/Pokemon-Showdown/git/refs{/sha}","trees_url":"https://api.github.com/repos/HoeenCoder/Pokemon-Showdown/git/trees{/sha}","statuses_url":"https://api.github.com/repos/HoeenCoder/Pokemon-Showdown/statuses/{sha}","languages_url":"https://api.github.com/repos/HoeenCoder/Pokemon-Showdown/languages","stargazers_url":"https://api.github.com/repos/HoeenCoder/Pokemon-Showdown/stargazers","contributors_url":"https://api.github.com/repos/HoeenCoder/Pokemon-Showdown/contributors","subscribers_url":"https://api.github.com/repos/HoeenCoder/Pokemon-Showdown/subscribers","subscription_url":"https://api.github.com/repos/HoeenCoder/Pokemon-Showdown/subscription","commits_url":"https://api.github.com/repos/HoeenCoder/Pokemon-Showdown/commits{/sha}","git_commits_url":"https://api.github.com/repos/HoeenCoder/Pokemon-Showdown/git/commits{/sha}","comments_url":"https://api.github.com/repos/HoeenCoder/Pokemon-Showdown/comments{/number}","issue_comment_url":"https://api.github.com/repos/HoeenCoder/Pokemon-Showdown/issues/comments{/number}","contents_url":"https://api.github.com/repos/HoeenCoder/Pokemon-Showdown/contents/{+path}","compare_url":"https://api.github.com/repos/HoeenCoder/Pokemon-Showdown/compare/{base}...{head}","merges_url":"https://api.github.com/repos/HoeenCoder/Pokemon-Showdown/merges","archive_url":"https://api.github.com/repos/HoeenCoder/Pokemon-Showdown/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/HoeenCoder/Pokemon-Showdown/downloads","issues_url":"https://api.github.com/repos/HoeenCoder/Pokemon-Showdown/issues{/number}","pulls_url":"https://api.github.com/repos/HoeenCoder/Pokemon-Showdown/pulls{/number}","milestones_url":"https://api.github.com/repos/HoeenCoder/Pokemon-Showdown/milestones{/number}","notifications_url":"https://api.github.com/repos/HoeenCoder/Pokemon-Showdown/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/HoeenCoder/Pokemon-Showdown/labels{/name}","releases_url":"https://api.github.com/repos/HoeenCoder/Pokemon-Showdown/releases{/id}","deployments_url":"https://api.github.com/repos/HoeenCoder/Pokemon-Showdown/deployments","created_at":"2017-04-06T18:10:57Z","updated_at":"2017-09-02T16:27:08Z","pushed_at":"2018-02-26T22:05:01Z","git_url":"git://github.com/HoeenCoder/Pokemon-Showdown.git","ssh_url":"git@github.com:HoeenCoder/Pokemon-Showdown.git","clone_url":"https://github.com/HoeenCoder/Pokemon-Showdown.git","svn_url":"https://github.com/HoeenCoder/Pokemon-Showdown","homepage":"http://pokemonshowdown.com","size":61113,"stargazers_count":0,"watchers_count":0,"language":"JavaScript","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":7,"license":null,"forks":0,"open_issues":7,"watchers":0,"default_branch":"master"}},"base":{"label":"Zarel:master","ref":"master","sha":"586861eb795ddf873e0d8105e2ec681a9ba99493","user":{"login":"Zarel","id":551184,"avatar_url":"https://avatars3.githubusercontent.com/u/551184?v=4","gravatar_id":"","url":"https://api.github.com/users/Zarel","html_url":"https://github.com/Zarel","followers_url":"https://api.github.com/users/Zarel/followers","following_url":"https://api.github.com/users/Zarel/following{/other_user}","gists_url":"https://api.github.com/users/Zarel/gists{/gist_id}","starred_url":"https://api.github.com/users/Zarel/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Zarel/subscriptions","organizations_url":"https://api.github.com/users/Zarel/orgs","repos_url":"https://api.github.com/users/Zarel/repos","events_url":"https://api.github.com/users/Zarel/events{/privacy}","received_events_url":"https://api.github.com/users/Zarel/received_events","type":"User","site_admin":false},"repo":{"id":3038446,"name":"Pokemon-Showdown","full_name":"Zarel/Pokemon-Showdown","owner":{"login":"Zarel","id":551184,"avatar_url":"https://avatars3.githubusercontent.com/u/551184?v=4","gravatar_id":"","url":"https://api.github.com/users/Zarel","html_url":"https://github.com/Zarel","followers_url":"https://api.github.com/users/Zarel/followers","following_url":"https://api.github.com/users/Zarel/following{/other_user}","gists_url":"https://api.github.com/users/Zarel/gists{/gist_id}","starred_url":"https://api.github.com/users/Zarel/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Zarel/subscriptions","organizations_url":"https://api.github.com/users/Zarel/orgs","repos_url":"https://api.github.com/users/Zarel/repos","events_url":"https://api.github.com/users/Zarel/events{/privacy}","received_events_url":"https://api.github.com/users/Zarel/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/Zarel/Pokemon-Showdown","description":"Pokémon battle simulator.","fork":false,"url":"https://api.github.com/repos/Zarel/Pokemon-Showdown","forks_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/forks","keys_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/teams","hooks_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/hooks","issue_events_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/issues/events{/number}","events_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/events","assignees_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/assignees{/user}","branches_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/branches{/branch}","tags_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/tags","blobs_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/git/refs{/sha}","trees_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/statuses/{sha}","languages_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/languages","stargazers_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/stargazers","contributors_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/contributors","subscribers_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/subscribers","subscription_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/subscription","commits_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/commits{/sha}","git_commits_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/git/commits{/sha}","comments_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/comments{/number}","issue_comment_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/issues/comments{/number}","contents_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/contents/{+path}","compare_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/merges","archive_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/downloads","issues_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/issues{/number}","pulls_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/pulls{/number}","milestones_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/milestones{/number}","notifications_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/labels{/name}","releases_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/releases{/id}","deployments_url":"https://api.github.com/repos/Zarel/Pokemon-Showdown/deployments","created_at":"2011-12-23T04:52:33Z","updated_at":"2018-02-26T02:42:27Z","pushed_at":"2018-02-26T22:25:11Z","git_url":"git://github.com/Zarel/Pokemon-Showdown.git","ssh_url":"git@github.com:Zarel/Pokemon-Showdown.git","clone_url":"https://github.com/Zarel/Pokemon-Showdown.git","svn_url":"https://github.com/Zarel/Pokemon-Showdown","homepage":"http://pokemonshowdown.com","size":61514,"stargazers_count":1391,"watchers_count":1391,"language":"JavaScript","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":1270,"mirror_url":null,"archived":false,"open_issues_count":55,"license":{"key":"other","name":"Other","spdx_id":null,"url":null},"forks":1270,"open_issues":55,"watchers":1391,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/Zarel/Pokemon-Showdown/pulls/4438"},"html":{"href":"https://github.com/Zarel/Pokemon-Showdown/pull/4438"},"issue":{"href":"https://api.github.com/repos/Zarel/Pokemon-Showdown/issues/4438"},"comments":{"href":"https://api.github.com/repos/Zarel/Pokemon-Showdown/issues/4438/comments"},"review_comments":{"href":"https://api.github.com/repos/Zarel/Pokemon-Showdown/pulls/4438/comments"},"review_comment":{"href":"https://api.github.com/repos/Zarel/Pokemon-Showdown/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/Zarel/Pokemon-Showdown/pulls/4438/commits"},"statuses":{"href":"https://api.github.com/repos/Zarel/Pokemon-Showdown/statuses/a19178b4a78aba4ca6e388d96e506ee4fb68a54c"}},"author_association":"COLLABORATOR"}}
{"actor":{"display_login":"panpawn"}}