{"action":"created","comment":{"url":"https://api.github.com/repos/bra1n/judgebot/pulls/comments/86100739","pull_request_review_id":6773822,"id":86100739,"diff_hunk":"@@ -1,87 +1,79 @@\n const request = require(\"request\");\n+const _ = require(\"lodash\");\n+\n class MtgCardLoader {\n     constructor() {\n         this.cardApi = \"https://api.magicthegathering.io/v1/cards?name=\";\n     }\n+    cardToString(card) {\n+        const manaCost = card.manaCost ? \" \" + card.manaCost : \"\";\n+        const cardInfo = [\"**\" + card.name + \"**\" + manaCost];\n+        if (card.type) {\n+            cardInfo.push(card.type);\n+        }\n+        if (card.text) {\n+            cardInfo.push(card.text.replace(/\\*/g, '\\\\*'));\n+        }\n+        if (card.loyalty) {\n+            cardInfo.push(card.loyalty);\n+        }\n+        if (card.power) {\n+            cardInfo.push(card.power.replace(/\\*/g, '\\\\*') + \"/\" + card.toughness.replace(/\\*/g, '\\\\*'));\n+        }\n+        if (card.printings) {\n+            cardInfo.push(card.printings.join(\", \"));\n+        }\n+        cardInfo.push(\"http://magiccards.info/query?q=!\" + encodeURIComponent(card.name));\n+        return cardInfo.join(\"\\n\");\n+    }\n+    findCard(cardName, cards) {\n+        // create an array containing each card exactly once, preferring cards with image\n+        const [cardsWithImage, cardsWithoutImage] = _.partition(cards, \"imageUrl\");\n+        const differentCardsWithoutImage = _.differenceBy(cardsWithoutImage, cardsWithImage, \"name\");\n+        const uniqCards = _.uniqBy(_.concat(cardsWithImage, differentCardsWithoutImage), \"name\");\n \n-    find(cardName, callback) {\n+        // Look for an exact match by name\n+        let card = uniqCards.find(c => c.name.toLowerCase() === cardName);\n+        if (!card){\n+            // Use a hit which shares the longest common prefix with the search term\n+            card = _.maxBy(uniqCards, c => longestCommonPrefix(cardName, c.name.toLowerCase()));\n+        }\n+        return card;\n+    }\n+    getContent(command , parameter, callback) {\n+        const cardName = parameter.toLowerCase();\n         request({\n-                url: this.cardApi + cardName,\n-                json: true\n-            },\n-            /**\n-             * @param response\n-             * @param error\n-             * @param body\n-             * @param body.cards array of cards\n-             * @param body.cards.loyalty string\n-             * @param body.cards.power string\n-             * @param body.cards.imageUrl string\n-             * @param body.cards.toughness string\n-             * @param body.cards.printings array of printings\n-             **/\n-            (error, response, body) => {\n-                if (!error && response.statusCode === 200 && body.cards && body.cards.length) {\n-                    const cardMap = new Map();\n-                    body.cards.forEach(function(card){\n-                        if(cardMap.has(card.name)){\n-                            if(!cardMap.get(card.name).imageUrl && card.imageUrl){\n-                                cardMap.set(card.name,card);\n-                            }\n-                        }else{\n-                            cardMap.set(card.name,card);\n-                        }\n-                    });\n-                    const cards =  Array.from(cardMap).map(function(element){\n-                        return element[1];\n-                    });\n-                    let card = cards.find(function(card){\n-                        return card.name.toLowerCase() === cardName;\n-                    });\n-                    if(!card){\n-                        card = cards.find(function (card) {\n-                           return card.name.toLowerCase().startsWith(cardName);\n-                        })\n-                    }\n-                    if(!card){\n-                        card = cards[0];\n-                    }\n-                    const cardInfo = [\"**\" + card.name + \"**\"];\n-                    if (card.type) {\n-                        cardInfo.push(card.type);\n-                    }\n-                    if (card.text) {\n-                        cardInfo.push(card.text.replace(/\\*/g, '\\\\*'));\n-                    }\n-                    if (card.loyalty) {\n-                        cardInfo.push(card.loyalty);\n-                    }\n-                    if (card.power) {\n-                        cardInfo.push(card.power.replace(/\\*/g, '\\\\*') + \"/\" + card.toughness.replace(/\\*/g, '\\\\*'));\n-                    }\n-                    if (card.printings) {\n-                        cardInfo.push(card.printings.join(\", \"));\n-                    }\n-                    cardInfo.push(\"http://magiccards.info/query?q=!\" + encodeURIComponent(card.name));\n-                    if (card.imageUrl) {\n-                        cardInfo.push(card.imageUrl);\n-                    }\n-                    callback(cardInfo.join(\"\\n\"));\n-                    if(cards.length>1){\n-                        const cardNames = [];\n-                        cards.forEach(function(element){\n-                            if(!(element.name===card.name)){\n-                                cardNames.push((element.name));\n-                            }\n-                        });\n-                        callback(\"Other matching cards are: \" + cardNames.join(\", \"))\n-                    }\n+            url: this.cardApi + cardName,\n+            json: true\n+        },\n+        (error, response, body) => {\n+            if (!error && response.statusCode === 200 && body.cards && body.cards.length) {\n+                const card = this.findCard(cardName, body.cards);\n+                let response = this.cardToString(card);\n+                let otherCardNames = body.cards.map(c => c.name).filter(n => n !== card.name);\n+                if (otherCardNames.length) {\n+                    otherCardNames.sort();\n+                    otherCardNames = _.sortedUniq(otherCardNames);\n+                    response += \"\\n\\nOther matching cards: \" + otherCardNames.join(\", \");\n                 }\n-            });\n+                callback(response, card.imageUrl, _.snakeCase(_.deburr(card.name)) + \".jpg\");\n+            }\n+        });\n     }\n+}\n \n-    getContent(command , parameter, callback) {\n-        this.find(parameter.toLowerCase(), callback);\n+function longestCommonPrefix(...strings) {","path":"aggregators/mtg_cards/cards.js","position":139,"original_position":139,"commit_id":"471dbaadc34c48f954af97edfd79faa8f6ab1327","original_commit_id":"471dbaadc34c48f954af97edfd79faa8f6ab1327","user":{"login":"hcschild","id":535870,"avatar_url":"https://avatars.githubusercontent.com/u/535870?v=3","gravatar_id":"","url":"https://api.github.com/users/hcschild","html_url":"https://github.com/hcschild","followers_url":"https://api.github.com/users/hcschild/followers","following_url":"https://api.github.com/users/hcschild/following{/other_user}","gists_url":"https://api.github.com/users/hcschild/gists{/gist_id}","starred_url":"https://api.github.com/users/hcschild/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hcschild/subscriptions","organizations_url":"https://api.github.com/users/hcschild/orgs","repos_url":"https://api.github.com/users/hcschild/repos","events_url":"https://api.github.com/users/hcschild/events{/privacy}","received_events_url":"https://api.github.com/users/hcschild/received_events","type":"User","site_admin":false},"body":"As I said in my comment for line `39` I don't know if this is needed. ","created_at":"2016-11-02T09:27:28Z","updated_at":"2016-11-02T09:33:23Z","html_url":"https://github.com/bra1n/judgebot/pull/15#discussion_r86100739","pull_request_url":"https://api.github.com/repos/bra1n/judgebot/pulls/15","_links":{"self":{"href":"https://api.github.com/repos/bra1n/judgebot/pulls/comments/86100739"},"html":{"href":"https://github.com/bra1n/judgebot/pull/15#discussion_r86100739"},"pull_request":{"href":"https://api.github.com/repos/bra1n/judgebot/pulls/15"}}},"pull_request":{"url":"https://api.github.com/repos/bra1n/judgebot/pulls/15","id":91846701,"html_url":"https://github.com/bra1n/judgebot/pull/15","diff_url":"https://github.com/bra1n/judgebot/pull/15.diff","patch_url":"https://github.com/bra1n/judgebot/pull/15.patch","issue_url":"https://api.github.com/repos/bra1n/judgebot/issues/15","number":15,"state":"open","locked":false,"title":"Upload cards as attachment and cleanup cards.js","user":{"login":"hgarus","id":4396799,"avatar_url":"https://avatars.githubusercontent.com/u/4396799?v=3","gravatar_id":"","url":"https://api.github.com/users/hgarus","html_url":"https://github.com/hgarus","followers_url":"https://api.github.com/users/hgarus/followers","following_url":"https://api.github.com/users/hgarus/following{/other_user}","gists_url":"https://api.github.com/users/hgarus/gists{/gist_id}","starred_url":"https://api.github.com/users/hgarus/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hgarus/subscriptions","organizations_url":"https://api.github.com/users/hgarus/orgs","repos_url":"https://api.github.com/users/hgarus/repos","events_url":"https://api.github.com/users/hgarus/events{/privacy}","received_events_url":"https://api.github.com/users/hgarus/received_events","type":"User","site_admin":false},"body":"Fixes #4 .\r\n\r\nNot quite sure where to put `longestCommonPrefix`. Definitely doesn't belong on the class, feels like it should be in it's own module, but I'm not sure if we want relative paths all over the place (such as `require(\"../../helpers/stringhelper\")`. An alternative would be using common-prefix from npm.\r\n\r\nI have replaced the use of a map to find cards with card images with a slightly different approach using lodash, personally I find it more readable, if you think differently feel free to let me know.\r\n\r\nI have tested this by running a selfbot and there is a noticable delay on answer times due to the image upload. I'm not sure if the added cleanliness is actually worth the delay, compared to just adding the cardImage URL to the message. ","created_at":"2016-11-01T19:23:06Z","updated_at":"2016-11-02T09:33:23Z","closed_at":null,"merged_at":null,"merge_commit_sha":"b62b6ac9ff4ea5e58735a8b3fcfe8ff763e8a016","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/bra1n/judgebot/pulls/15/commits","review_comments_url":"https://api.github.com/repos/bra1n/judgebot/pulls/15/comments","review_comment_url":"https://api.github.com/repos/bra1n/judgebot/pulls/comments{/number}","comments_url":"https://api.github.com/repos/bra1n/judgebot/issues/15/comments","statuses_url":"https://api.github.com/repos/bra1n/judgebot/statuses/471dbaadc34c48f954af97edfd79faa8f6ab1327","head":{"label":"hgarus:develop","ref":"develop","sha":"471dbaadc34c48f954af97edfd79faa8f6ab1327","user":{"login":"hgarus","id":4396799,"avatar_url":"https://avatars.githubusercontent.com/u/4396799?v=3","gravatar_id":"","url":"https://api.github.com/users/hgarus","html_url":"https://github.com/hgarus","followers_url":"https://api.github.com/users/hgarus/followers","following_url":"https://api.github.com/users/hgarus/following{/other_user}","gists_url":"https://api.github.com/users/hgarus/gists{/gist_id}","starred_url":"https://api.github.com/users/hgarus/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hgarus/subscriptions","organizations_url":"https://api.github.com/users/hgarus/orgs","repos_url":"https://api.github.com/users/hgarus/repos","events_url":"https://api.github.com/users/hgarus/events{/privacy}","received_events_url":"https://api.github.com/users/hgarus/received_events","type":"User","site_admin":false},"repo":{"id":72155471,"name":"judgebot","full_name":"hgarus/judgebot","owner":{"login":"hgarus","id":4396799,"avatar_url":"https://avatars.githubusercontent.com/u/4396799?v=3","gravatar_id":"","url":"https://api.github.com/users/hgarus","html_url":"https://github.com/hgarus","followers_url":"https://api.github.com/users/hgarus/followers","following_url":"https://api.github.com/users/hgarus/following{/other_user}","gists_url":"https://api.github.com/users/hgarus/gists{/gist_id}","starred_url":"https://api.github.com/users/hgarus/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hgarus/subscriptions","organizations_url":"https://api.github.com/users/hgarus/orgs","repos_url":"https://api.github.com/users/hgarus/repos","events_url":"https://api.github.com/users/hgarus/events{/privacy}","received_events_url":"https://api.github.com/users/hgarus/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/hgarus/judgebot","description":"Discord Bot for Magic / Judge related content","fork":true,"url":"https://api.github.com/repos/hgarus/judgebot","forks_url":"https://api.github.com/repos/hgarus/judgebot/forks","keys_url":"https://api.github.com/repos/hgarus/judgebot/keys{/key_id}","collaborators_url":"https://api.github.com/repos/hgarus/judgebot/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/hgarus/judgebot/teams","hooks_url":"https://api.github.com/repos/hgarus/judgebot/hooks","issue_events_url":"https://api.github.com/repos/hgarus/judgebot/issues/events{/number}","events_url":"https://api.github.com/repos/hgarus/judgebot/events","assignees_url":"https://api.github.com/repos/hgarus/judgebot/assignees{/user}","branches_url":"https://api.github.com/repos/hgarus/judgebot/branches{/branch}","tags_url":"https://api.github.com/repos/hgarus/judgebot/tags","blobs_url":"https://api.github.com/repos/hgarus/judgebot/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/hgarus/judgebot/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/hgarus/judgebot/git/refs{/sha}","trees_url":"https://api.github.com/repos/hgarus/judgebot/git/trees{/sha}","statuses_url":"https://api.github.com/repos/hgarus/judgebot/statuses/{sha}","languages_url":"https://api.github.com/repos/hgarus/judgebot/languages","stargazers_url":"https://api.github.com/repos/hgarus/judgebot/stargazers","contributors_url":"https://api.github.com/repos/hgarus/judgebot/contributors","subscribers_url":"https://api.github.com/repos/hgarus/judgebot/subscribers","subscription_url":"https://api.github.com/repos/hgarus/judgebot/subscription","commits_url":"https://api.github.com/repos/hgarus/judgebot/commits{/sha}","git_commits_url":"https://api.github.com/repos/hgarus/judgebot/git/commits{/sha}","comments_url":"https://api.github.com/repos/hgarus/judgebot/comments{/number}","issue_comment_url":"https://api.github.com/repos/hgarus/judgebot/issues/comments{/number}","contents_url":"https://api.github.com/repos/hgarus/judgebot/contents/{+path}","compare_url":"https://api.github.com/repos/hgarus/judgebot/compare/{base}...{head}","merges_url":"https://api.github.com/repos/hgarus/judgebot/merges","archive_url":"https://api.github.com/repos/hgarus/judgebot/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/hgarus/judgebot/downloads","issues_url":"https://api.github.com/repos/hgarus/judgebot/issues{/number}","pulls_url":"https://api.github.com/repos/hgarus/judgebot/pulls{/number}","milestones_url":"https://api.github.com/repos/hgarus/judgebot/milestones{/number}","notifications_url":"https://api.github.com/repos/hgarus/judgebot/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/hgarus/judgebot/labels{/name}","releases_url":"https://api.github.com/repos/hgarus/judgebot/releases{/id}","deployments_url":"https://api.github.com/repos/hgarus/judgebot/deployments","created_at":"2016-10-27T23:10:00Z","updated_at":"2016-10-27T23:10:01Z","pushed_at":"2016-11-01T19:33:01Z","git_url":"git://github.com/hgarus/judgebot.git","ssh_url":"git@github.com:hgarus/judgebot.git","clone_url":"https://github.com/hgarus/judgebot.git","svn_url":"https://github.com/hgarus/judgebot","homepage":null,"size":20,"stargazers_count":0,"watchers_count":0,"language":"JavaScript","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"develop"}},"base":{"label":"bra1n:develop","ref":"develop","sha":"3b0199935aedfc4ca4714ae5817a045d636e0264","user":{"login":"bra1n","id":325521,"avatar_url":"https://avatars.githubusercontent.com/u/325521?v=3","gravatar_id":"","url":"https://api.github.com/users/bra1n","html_url":"https://github.com/bra1n","followers_url":"https://api.github.com/users/bra1n/followers","following_url":"https://api.github.com/users/bra1n/following{/other_user}","gists_url":"https://api.github.com/users/bra1n/gists{/gist_id}","starred_url":"https://api.github.com/users/bra1n/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bra1n/subscriptions","organizations_url":"https://api.github.com/users/bra1n/orgs","repos_url":"https://api.github.com/users/bra1n/repos","events_url":"https://api.github.com/users/bra1n/events{/privacy}","received_events_url":"https://api.github.com/users/bra1n/received_events","type":"User","site_admin":false},"repo":{"id":71932182,"name":"judgebot","full_name":"bra1n/judgebot","owner":{"login":"bra1n","id":325521,"avatar_url":"https://avatars.githubusercontent.com/u/325521?v=3","gravatar_id":"","url":"https://api.github.com/users/bra1n","html_url":"https://github.com/bra1n","followers_url":"https://api.github.com/users/bra1n/followers","following_url":"https://api.github.com/users/bra1n/following{/other_user}","gists_url":"https://api.github.com/users/bra1n/gists{/gist_id}","starred_url":"https://api.github.com/users/bra1n/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bra1n/subscriptions","organizations_url":"https://api.github.com/users/bra1n/orgs","repos_url":"https://api.github.com/users/bra1n/repos","events_url":"https://api.github.com/users/bra1n/events{/privacy}","received_events_url":"https://api.github.com/users/bra1n/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/bra1n/judgebot","description":"Discord Bot for Magic / Judge related content","fork":false,"url":"https://api.github.com/repos/bra1n/judgebot","forks_url":"https://api.github.com/repos/bra1n/judgebot/forks","keys_url":"https://api.github.com/repos/bra1n/judgebot/keys{/key_id}","collaborators_url":"https://api.github.com/repos/bra1n/judgebot/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/bra1n/judgebot/teams","hooks_url":"https://api.github.com/repos/bra1n/judgebot/hooks","issue_events_url":"https://api.github.com/repos/bra1n/judgebot/issues/events{/number}","events_url":"https://api.github.com/repos/bra1n/judgebot/events","assignees_url":"https://api.github.com/repos/bra1n/judgebot/assignees{/user}","branches_url":"https://api.github.com/repos/bra1n/judgebot/branches{/branch}","tags_url":"https://api.github.com/repos/bra1n/judgebot/tags","blobs_url":"https://api.github.com/repos/bra1n/judgebot/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/bra1n/judgebot/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/bra1n/judgebot/git/refs{/sha}","trees_url":"https://api.github.com/repos/bra1n/judgebot/git/trees{/sha}","statuses_url":"https://api.github.com/repos/bra1n/judgebot/statuses/{sha}","languages_url":"https://api.github.com/repos/bra1n/judgebot/languages","stargazers_url":"https://api.github.com/repos/bra1n/judgebot/stargazers","contributors_url":"https://api.github.com/repos/bra1n/judgebot/contributors","subscribers_url":"https://api.github.com/repos/bra1n/judgebot/subscribers","subscription_url":"https://api.github.com/repos/bra1n/judgebot/subscription","commits_url":"https://api.github.com/repos/bra1n/judgebot/commits{/sha}","git_commits_url":"https://api.github.com/repos/bra1n/judgebot/git/commits{/sha}","comments_url":"https://api.github.com/repos/bra1n/judgebot/comments{/number}","issue_comment_url":"https://api.github.com/repos/bra1n/judgebot/issues/comments{/number}","contents_url":"https://api.github.com/repos/bra1n/judgebot/contents/{+path}","compare_url":"https://api.github.com/repos/bra1n/judgebot/compare/{base}...{head}","merges_url":"https://api.github.com/repos/bra1n/judgebot/merges","archive_url":"https://api.github.com/repos/bra1n/judgebot/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/bra1n/judgebot/downloads","issues_url":"https://api.github.com/repos/bra1n/judgebot/issues{/number}","pulls_url":"https://api.github.com/repos/bra1n/judgebot/pulls{/number}","milestones_url":"https://api.github.com/repos/bra1n/judgebot/milestones{/number}","notifications_url":"https://api.github.com/repos/bra1n/judgebot/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/bra1n/judgebot/labels{/name}","releases_url":"https://api.github.com/repos/bra1n/judgebot/releases{/id}","deployments_url":"https://api.github.com/repos/bra1n/judgebot/deployments","created_at":"2016-10-25T19:36:02Z","updated_at":"2016-10-27T11:23:22Z","pushed_at":"2016-11-02T08:53:32Z","git_url":"git://github.com/bra1n/judgebot.git","ssh_url":"git@github.com:bra1n/judgebot.git","clone_url":"https://github.com/bra1n/judgebot.git","svn_url":"https://github.com/bra1n/judgebot","homepage":null,"size":29,"stargazers_count":1,"watchers_count":1,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":2,"mirror_url":null,"open_issues_count":12,"forks":2,"open_issues":12,"watchers":1,"default_branch":"develop"}},"_links":{"self":{"href":"https://api.github.com/repos/bra1n/judgebot/pulls/15"},"html":{"href":"https://github.com/bra1n/judgebot/pull/15"},"issue":{"href":"https://api.github.com/repos/bra1n/judgebot/issues/15"},"comments":{"href":"https://api.github.com/repos/bra1n/judgebot/issues/15/comments"},"review_comments":{"href":"https://api.github.com/repos/bra1n/judgebot/pulls/15/comments"},"review_comment":{"href":"https://api.github.com/repos/bra1n/judgebot/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/bra1n/judgebot/pulls/15/commits"},"statuses":{"href":"https://api.github.com/repos/bra1n/judgebot/statuses/471dbaadc34c48f954af97edfd79faa8f6ab1327"}}}}
{"actor":{"display_login":"hcschild"}}