{"action":"created","comment":{"url":"https://api.github.com/repos/Khan/react-components/pulls/comments/32664780","id":32664780,"diff_hunk":"@@ -0,0 +1,464 @@\n+/**\n+ * KaTeX A11y\n+ * A library for converting KaTeX math into readable strings.\n+ */\n+var _ = require(\"underscore\");\n+\n+if (typeof katex === \"undefined\" && typeof require !== \"undefined\") {\n+    // NOTE(jeresig): This is mad hacky and used for testing\n+    // We want katex to exist in the mocha environment, but we don't\n+    // want it to be included in normal builds.\n+    var tmp = require;\n+    katex = tmp(\"../docs/js/katex\");\n+}\n+\n+var stringMap = {\n+    \"(\": \"left parenthesis\",\n+    \")\": \"right parenthesis\",\n+    \"[\": \"open bracket\",\n+    \"]\": \"close bracket\",\n+    \"\\\\{\": \"left brace\",\n+    \"\\\\}\": \"right brace\",\n+    \"\\\\lvert\": \"open vertical bar\",\n+    \"\\\\rvert\": \"close vertical bar\",\n+    \"|\": \"vertical bar\",\n+    \"\\\\uparrow\": \"up arrow\",\n+    \"\\\\Uparrow\": \"up arrow\",\n+    \"\\\\downarrow\": \"down arrow\",\n+    \"\\\\Downarrow\": \"down arrow\",\n+    \"\\\\updownarrow\": \"up down arrow\",\n+    \"\\\\leftarrow\": \"left arrow\",\n+    \"\\\\Leftarrow\": \"left arrow\",\n+    \"\\\\rightarrow\": \"right arrow\",\n+    \"\\\\Rightarrow\": \"right arrow\",\n+    \"\\\\langle\": \"open angle\",\n+    \"\\\\rangle\": \"close angle\",\n+    \"\\\\lfloor\": \"open floor\",\n+    \"\\\\rfloor\": \"close floor\",\n+    \"\\\\int\": \"integral\",\n+    \"\\\\intop\": \"integral\",\n+    \"\\\\lim\": \"limit\",\n+    \"\\\\ln\": \"natural log\",\n+    \"\\\\log\": \"log\",\n+    \"\\\\sin\": \"sine\",\n+    \"\\\\cos\": \"cosine\",\n+    \"\\\\tan\": \"tangent\",\n+    \"\\\\cot\": \"cotangent\",\n+    \"\\\\sum\": \"sum\",\n+    \"/\": \"slash\",\n+    \",\": \"comma\",\n+    \".\": \"point\",\n+    \"-\": \"negative\",\n+    \"+\": \"plus\",\n+    \"~\": \"tilde\",\n+    \":\": \"colon\",\n+    \"?\": \"question mark\",\n+    \"'\": \"apostrophe\",\n+    \"\\\\%\": \"percent\",\n+    \" \": \"space\",\n+    \"\\\\ \": \"space\",\n+    \"\\\\$\": \"dollar sign\",\n+    \"\\\\angle\": \"angle\",\n+    \"\\\\degree\": \"degree\",\n+    \"\\\\circ\": \"circle\",\n+    \"\\\\vec\": \"vector\",\n+    \"\\\\triangle\": \"triangle\",\n+    \"\\\\pi\": \"pi\",\n+    \"\\\\prime\": \"prime\",\n+    \"\\\\infty\": \"infinity\",\n+    \"\\\\alpha\": \"alpha\",\n+    \"\\\\beta\": \"beta\",\n+    \"\\\\gamma\": \"gamma\",\n+    \"\\\\omega\": \"omega\",\n+    \"\\\\theta\": \"theta\",\n+    \"\\\\sigma\": \"sigma\",\n+    \"\\\\lambda\": \"lambda\",\n+    \"\\\\tau\": \"tau\",\n+    \"\\\\Delta\": \"delta\",\n+    \"\\\\delta\": \"delta\",\n+    \"\\\\mu\": \"mu\",\n+    \"\\\\rho\": \"rho\",\n+    \"\\\\nabla\": \"del\",\n+    \"\\\\ell\": \"ell\",\n+    \"\\\\ldots\": \"dots\"\n+};\n+\n+var powerMap = {\n+    \"\\\\prime\": \"prime\",\n+    \"\\\\degree\": \"degree\",\n+    \"\\\\circ\": \"degree\"\n+};\n+\n+var openMap = {\n+    \"|\": \"open vertical bar\",\n+    \".\": \"\"\n+};\n+\n+var closeMap = {\n+    \"|\": \"close vertical bar\",\n+    \".\": \"\"\n+};\n+\n+var binMap = {\n+    \"+\": \"plus\",\n+    \"-\": \"minus\",\n+    \"\\\\pm\": \"plus minus\",\n+    \"\\\\cdot\": \"dot\",\n+    \"*\": \"times\",\n+    \"/\": \"divided by\",\n+    \"\\\\times\": \"times\",\n+    \"\\\\div\": \"divided by\",\n+    \"\\\\circ\": \"circle\",\n+    \"\\\\bullet\": \"bullet\"\n+};\n+\n+var relMap = {\n+    \"=\": \"equals\",\n+    \"\\\\approx\": \"approximately equals\",\n+    \"\\\\neq\": \"does not equal\",\n+    \"\\\\ne\": \"does not equal\",\n+    \"\\\\geq\": \"is greater than or equal to\",\n+    \"\\\\ge\": \"is greater than or equal to\",\n+    \"\\\\leq\": \"is less than or equal to\",\n+    \"\\\\le\": \"is less than or equal to\",\n+    \">\": \"is greater than\",\n+    \"<\": \"is less than\",\n+    \"\\\\leftarrow\": \"left arrow\",\n+    \"\\\\Leftarrow\": \"left arrow\",\n+    \"\\\\rightarrow\": \"right arrow\",\n+    \"\\\\Rightarrow\": \"right arrow\",\n+    \":\": \"colon\"\n+};\n+\n+var buildString = function(str, type, a11yStrings) {\n+    if (!str) {\n+        return;\n+    }\n+\n+    var ret;\n+\n+    if (type === \"open\") {\n+        ret = (str in openMap ? openMap[str] : stringMap[str] || str);\n+    } else if (type === \"close\") {\n+        ret = (str in closeMap ? closeMap[str] : stringMap[str] || str);\n+    } else if (type === \"math\") {\n+        ret = mathMap[str] || str;\n+    } else if (type === \"bin\") {\n+        ret = binMap[str] || str;\n+    } else if (type === \"rel\") {\n+        ret = relMap[str] || str;\n+    } else {\n+        ret = stringMap[str] || str;\n+    }\n+\n+    // If nothing was found and it's not a plain string or number\n+    if (ret === str && !/^\\w+$/.test(str)) {\n+        // This is likely a case that we'll need to handle\n+        throw \"KaTeX a11y \" + type + \" string not found: \" + str;\n+    }\n+\n+    // If the text to add is a number and there is already a string\n+    // in the list and the last string is a number then we should\n+    // combine them into a single number\n+    if (/^\\d+$/.test(ret) && a11yStrings.length > 0 &&\n+            /^\\d+$/.test(a11yStrings[a11yStrings.length - 1])) {\n+        a11yStrings[a11yStrings.length - 1] += ret;\n+\n+    } else if (ret) {\n+        a11yStrings.push(ret);\n+    }\n+};\n+\n+var buildRegion = function(a11yStrings, callback) {\n+    var region = [];\n+    a11yStrings.push(region);\n+    callback(region);\n+};\n+\n+var typeHandlers = {\n+    accent: function(tree, a11yStrings) {\n+        buildRegion(a11yStrings, function(a11yStrings) {\n+            buildA11yStrings(tree.value.base, a11yStrings);\n+            a11yStrings.push(\"with\");\n+            buildA11yStrings(tree.value.accent, a11yStrings);\n+            a11yStrings.push(\"on top\");\n+        });\n+    },\n+\n+    bin: function(tree, a11yStrings) {\n+        buildString(tree.value, \"bin\", a11yStrings);\n+    },\n+\n+    close: function(tree, a11yStrings) {\n+        buildString(tree.value, \"close\", a11yStrings);\n+    },\n+\n+    color: function(tree, a11yStrings) {\n+        var color = tree.value.color.replace(/katex-/, \"\");\n+\n+        buildRegion(a11yStrings, function(a11yStrings) {\n+            a11yStrings.push(\"start color \" + color);\n+            buildA11yStrings(tree.value.value, a11yStrings);\n+            a11yStrings.push(\"end color \" + color);\n+        });\n+    },\n+\n+    delimsizing: function(tree, a11yStrings) {\n+        if (tree.value.value && tree.value.value !== \".\") {\n+            buildString(tree.value.value, \"normal\", a11yStrings);\n+        }\n+    },\n+\n+    genfrac: function(tree, a11yStrings) {\n+        buildRegion(a11yStrings, function(a11yStrings) {\n+            // NOTE: Not sure if this is a safe assumption\n+            // hasBarLine true -> fraction, false -> binomial\n+            if (tree.value.hasBarLine) {\n+                a11yStrings.push(\"start fraction\");\n+                buildString(tree.value.leftDelim, \"open\", a11yStrings);\n+                buildA11yStrings(tree.value.numer, a11yStrings);\n+                a11yStrings.push(\"divided by\");\n+                buildA11yStrings(tree.value.denom, a11yStrings);\n+                buildString(tree.value.rightDelim, \"close\", a11yStrings);\n+                a11yStrings.push(\"end fraction\");\n+            } else {\n+                a11yStrings.push(\"start binomial\");\n+                buildString(tree.value.leftDelim, \"open\", a11yStrings);\n+                buildA11yStrings(tree.value.numer, a11yStrings);\n+                a11yStrings.push(\"over\");\n+                buildA11yStrings(tree.value.denom, a11yStrings);\n+                buildString(tree.value.rightDelim, \"close\", a11yStrings);\n+                a11yStrings.push(\"end binomial\");\n+            }\n+        });\n+    },\n+\n+    // inner\n+\n+    katex: function(tree, a11yStrings) {\n+        a11yStrings.push(\"KaTeX\");\n+    },\n+\n+    leftright: function(tree, a11yStrings) {\n+        buildRegion(a11yStrings, function(a11yStrings) {\n+            buildString(tree.value.left, \"open\", a11yStrings);\n+            buildA11yStrings(tree.value.body, a11yStrings);\n+            buildString(tree.value.right, \"close\", a11yStrings);\n+        });\n+    },\n+\n+    llap: function(tree, a11yStrings) {\n+        buildA11yStrings(tree.value.body, a11yStrings);\n+    },\n+\n+    mathord: function(tree, a11yStrings) {\n+        buildA11yStrings(tree.value, a11yStrings);\n+    },\n+\n+    op: function(tree, a11yStrings) {\n+        buildString(tree.value.body, \"normal\", a11yStrings);\n+    },\n+\n+    open: function(tree, a11yStrings) {\n+        buildString(tree.value, \"open\", a11yStrings);\n+    },\n+\n+    ordgroup: function(tree, a11yStrings) {\n+        buildA11yStrings(tree.value, a11yStrings);\n+    },\n+\n+    overline: function(tree, a11yStrings) {\n+        buildRegion(a11yStrings, function(a11yStrings) {\n+            a11yStrings.push(\"start overline\");\n+            buildA11yStrings(tree.value.body, a11yStrings);\n+            a11yStrings.push(\"end overline\");\n+        });\n+    },\n+\n+    phantom: function(tree, a11yStrings) {\n+        a11yStrings.push(\"empty space\");\n+    },\n+\n+    punct: function(tree, a11yStrings) {\n+        buildString(tree.value, \"punct\", a11yStrings);\n+    },\n+\n+    rel: function(tree, a11yStrings) {\n+        buildString(tree.value, \"rel\", a11yStrings);\n+    },\n+\n+    rlap: function(tree, a11yStrings) {\n+        buildA11yStrings(tree.value.body, a11yStrings);\n+    },\n+\n+    rule: function(tree, a11yStrings) {\n+        // NOTE: Is there something more useful that we can put here?\n+        a11yStrings.push(\"rule\");\n+    },\n+\n+    sizing: function(tree, a11yStrings) {\n+        buildA11yStrings(tree.value.value, a11yStrings);\n+    },\n+\n+    spacing: function(tree, a11yStrings) {\n+        a11yStrings.push(\"space\");\n+    },\n+\n+    styling: function(tree, a11yStrings) {\n+        // We ignore the styling and just pass through the contents\n+        buildA11yStrings(tree.value.value, a11yStrings);\n+    },\n+\n+    sqrt: function(tree, a11yStrings) {\n+        buildRegion(a11yStrings, function(a11yStrings) {\n+            if (tree.value.index) {\n+                a11yStrings.push(\"square root\");\n+                a11yStrings.push(\"start index\");\n+                buildA11yStrings(tree.value.index, a11yStrings);\n+                a11yStrings.push(\"end index\");\n+            }\n+\n+            a11yStrings.push(\"square root of\");\n+            buildA11yStrings(tree.value.body, a11yStrings);\n+            a11yStrings.push(\"end square root\");\n+        });\n+    },\n+\n+    supsub: function(tree, a11yStrings) {\n+        if (tree.value.base) {\n+            buildA11yStrings(tree.value.base, a11yStrings);\n+        }\n+\n+        if (tree.value.sub) {\n+            buildRegion(a11yStrings, function(a11yStrings) {\n+                a11yStrings.push(\"start subscript\");\n+                buildA11yStrings(tree.value.sub, a11yStrings);\n+                a11yStrings.push(\"end subscript\");\n+            });\n+        }\n+\n+        if (tree.value.sup) {\n+            // There are some cases that just read better if we don't have\n+            // the extra start/end baggage, so we skip the extra text\n+            var newPower = (powerMap[tree.value.sup] ||\n+                tree.value.sup.value && tree.value.sup.value[0] &&\n+                powerMap[tree.value.sup.value[0].value] ||\n+                tree.value.sup.value &&\n+                powerMap[tree.value.sup.value]);\n+\n+            buildRegion(a11yStrings, function(a11yStrings) {\n+                if (newPower) {\n+                    a11yStrings.push(newPower);\n+                    return;\n+                }\n+\n+                a11yStrings.push(\"start superscript\");\n+                buildA11yStrings(tree.value.sup, a11yStrings);\n+                a11yStrings.push(\"end superscript\");\n+            });\n+        }\n+    },\n+\n+    text: function(tree, a11yStrings) {\n+        if (typeof tree.value !== \"string\") {\n+            buildA11yStrings(tree.value.body, a11yStrings);\n+        } else {\n+            buildString(tree, \"normal\", a11yStrings);\n+        }\n+    },\n+\n+    textord: function(tree, a11yStrings) {\n+        buildA11yStrings(tree.value, a11yStrings);\n+    }\n+};\n+\n+var buildA11yStrings = function(tree, a11yStrings) {\n+    a11yStrings = a11yStrings || [];\n+\n+    // Handle strings\n+    if (typeof tree === \"string\") {\n+        buildString(tree, \"normal\", a11yStrings);\n+\n+    // Handle arrays\n+    } else if (tree.constructor === Array) {\n+        for (var i = 0; i < tree.length; i++) {\n+            buildA11yStrings(tree[i], a11yStrings);\n+        }\n+\n+    // Everything else is assumed to be an object...\n+    } else {\n+        if (!tree.type || !(tree.type in typeHandlers)) {\n+            throw \"KaTeX a11y un-recognized type: \" + tree.type;\n+        } else {\n+            typeHandlers[tree.type](tree, a11yStrings);\n+        }\n+    }\n+\n+    return a11yStrings;\n+};\n+\n+var renderStrings = function(a11yStrings, a11yNode) {\n+    var doc = a11yNode.ownerDocument;\n+\n+    for (var i = 0; i < a11yStrings.length; i++) {\n+        var a11yString = a11yStrings[i];\n+\n+        if (i > 0) {\n+            a11yNode.appendChild(doc.createTextNode(\", \"));\n+        }\n+\n+        if (typeof a11yString === \"string\") {\n+            a11yNode.appendChild(doc.createTextNode(a11yString));\n+        } else {\n+            var newBaseNode = doc.createElement(\"span\");\n+            //newBaseNode.tabIndex = 0;","path":"js/katex-a11y.js","position":414,"original_position":414,"commit_id":"15bfb385bc9e74b63c3c8d94d2957550f8b141e7","original_commit_id":"15bfb385bc9e74b63c3c8d94d2957550f8b141e7","user":{"login":"xymostech","id":217900,"avatar_url":"https://avatars.githubusercontent.com/u/217900?v=3","gravatar_id":"","url":"https://api.github.com/users/xymostech","html_url":"https://github.com/xymostech","followers_url":"https://api.github.com/users/xymostech/followers","following_url":"https://api.github.com/users/xymostech/following{/other_user}","gists_url":"https://api.github.com/users/xymostech/gists{/gist_id}","starred_url":"https://api.github.com/users/xymostech/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/xymostech/subscriptions","organizations_url":"https://api.github.com/users/xymostech/orgs","repos_url":"https://api.github.com/users/xymostech/repos","events_url":"https://api.github.com/users/xymostech/events{/privacy}","received_events_url":"https://api.github.com/users/xymostech/received_events","type":"User","site_admin":false},"body":"Remove?","created_at":"2015-06-17T19:27:02Z","updated_at":"2015-06-17T19:27:02Z","html_url":"https://github.com/Khan/react-components/pull/41#discussion_r32664780","pull_request_url":"https://api.github.com/repos/Khan/react-components/pulls/41","_links":{"self":{"href":"https://api.github.com/repos/Khan/react-components/pulls/comments/32664780"},"html":{"href":"https://github.com/Khan/react-components/pull/41#discussion_r32664780"},"pull_request":{"href":"https://api.github.com/repos/Khan/react-components/pulls/41"}}},"pull_request":{"url":"https://api.github.com/repos/Khan/react-components/pulls/41","id":37934324,"html_url":"https://github.com/Khan/react-components/pull/41","diff_url":"https://github.com/Khan/react-components/pull/41.diff","patch_url":"https://github.com/Khan/react-components/pull/41.patch","issue_url":"https://api.github.com/repos/Khan/react-components/issues/41","number":41,"state":"open","locked":false,"title":"KaTeX A11y Mode","user":{"login":"jeresig","id":1615,"avatar_url":"https://avatars.githubusercontent.com/u/1615?v=3","gravatar_id":"","url":"https://api.github.com/users/jeresig","html_url":"https://github.com/jeresig","followers_url":"https://api.github.com/users/jeresig/followers","following_url":"https://api.github.com/users/jeresig/following{/other_user}","gists_url":"https://api.github.com/users/jeresig/gists{/gist_id}","starred_url":"https://api.github.com/users/jeresig/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jeresig/subscriptions","organizations_url":"https://api.github.com/users/jeresig/orgs","repos_url":"https://api.github.com/users/jeresig/repos","events_url":"https://api.github.com/users/jeresig/events{/privacy}","received_events_url":"https://api.github.com/users/jeresig/received_events","type":"User","site_admin":false},"body":"This adds a new mode to the TeX.jsx module in which a new English-string form of the Math formula will be generated.\r\n\r\nFor example, if given the math string \"4 + x\" it'll generate something that looks like:\r\n\r\n```\r\n<span>\r\n    <span class=\"mathjax\" aria-hidden=\"true\">...</span>\r\n    <span class=\"katex\" aria-hidden=\"true\">...</span>\r\n    <span class=\"katexA11y sr-only\">4, plus, x</span>\r\n</span>\r\n```\r\n\r\nThus when someone accesses the above with a screen reader it'll read off \"4, plus, x\" and ignore the mathjax and katex spans. Likewise for a user that isn't using a screen reader they'll see the katex/mathjax render as normal. Note that the above only happens if the new katex-a11y module can successfully translate the math string into an English string. If it cannot then it abandons the attempt and just leaves the katex/mathjax in place, letting the screen reader handle it as-is.\r\n\r\nTo ensure that everything works as we expect it to I've added a bunch of tests. Specifically I've brought over the KaTeX tests and ensured that all of the existing TeX strings are converted into an English form that makes sense. Additionally I've exported every single KaTeX-parseable Math string from a selection of our curriculum on Khan Academy and have ensured that the new katex-a11y module is capable of translating them into an English string (I don't check the conversions as there are 15,000+ math strings and it would be really time consuming).\r\n\r\nThe important files are:\r\n\r\n* `js/katex-a11y.js`: This is all of the new logic for converting a KaTeX-generated tree into an English string. I attempted to handle all the cases that I could find, although I'm sure there are a bunch that I haven't been able to spot and even more where the conversion doesn't make sense. This is probably a decent first attempt, though.\r\n* `js/tex.jsx`: This is the module into which `katex-a11y.js` is imported and used. Some light modifications where made to make sure that the right spans were visible/invisible to the screen reader.\r\n* `test/katex-a11y-test.jsx`: These are the tests which are run in the main mocha test runner.\r\n\r\nThere are two additional areas that I want to explore, but can wait a little bit to attempt:\r\n\r\n* I've started work on making the math much more navigable. I've started to break the text into sub-spans with the hope of making it possible to navigate them using a keyboard. I initially added a `tabIndex=\"0\"` to them but that made things pretty confusing, especially for non-screen-reader users.\r\n* I want to mark all the strings up for i18n. Some more thought is going to have to go in to this but we primarily are worried about the English case, at the moment.","created_at":"2015-06-17T18:55:55Z","updated_at":"2015-06-17T19:27:03Z","closed_at":null,"merged_at":null,"merge_commit_sha":"32f50ab95bbb8d3c304c6203425846a93fba815a","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/Khan/react-components/pulls/41/commits","review_comments_url":"https://api.github.com/repos/Khan/react-components/pulls/41/comments","review_comment_url":"https://api.github.com/repos/Khan/react-components/pulls/comments{/number}","comments_url":"https://api.github.com/repos/Khan/react-components/issues/41/comments","statuses_url":"https://api.github.com/repos/Khan/react-components/statuses/15bfb385bc9e74b63c3c8d94d2957550f8b141e7","head":{"label":"Khan:katex-a11y","ref":"katex-a11y","sha":"15bfb385bc9e74b63c3c8d94d2957550f8b141e7","user":{"login":"Khan","id":15455,"avatar_url":"https://avatars.githubusercontent.com/u/15455?v=3","gravatar_id":"","url":"https://api.github.com/users/Khan","html_url":"https://github.com/Khan","followers_url":"https://api.github.com/users/Khan/followers","following_url":"https://api.github.com/users/Khan/following{/other_user}","gists_url":"https://api.github.com/users/Khan/gists{/gist_id}","starred_url":"https://api.github.com/users/Khan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Khan/subscriptions","organizations_url":"https://api.github.com/users/Khan/orgs","repos_url":"https://api.github.com/users/Khan/repos","events_url":"https://api.github.com/users/Khan/events{/privacy}","received_events_url":"https://api.github.com/users/Khan/received_events","type":"Organization","site_admin":false},"repo":{"id":18577404,"name":"react-components","full_name":"Khan/react-components","owner":{"login":"Khan","id":15455,"avatar_url":"https://avatars.githubusercontent.com/u/15455?v=3","gravatar_id":"","url":"https://api.github.com/users/Khan","html_url":"https://github.com/Khan","followers_url":"https://api.github.com/users/Khan/followers","following_url":"https://api.github.com/users/Khan/following{/other_user}","gists_url":"https://api.github.com/users/Khan/gists{/gist_id}","starred_url":"https://api.github.com/users/Khan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Khan/subscriptions","organizations_url":"https://api.github.com/users/Khan/orgs","repos_url":"https://api.github.com/users/Khan/repos","events_url":"https://api.github.com/users/Khan/events{/privacy}","received_events_url":"https://api.github.com/users/Khan/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Khan/react-components","description":"","fork":false,"url":"https://api.github.com/repos/Khan/react-components","forks_url":"https://api.github.com/repos/Khan/react-components/forks","keys_url":"https://api.github.com/repos/Khan/react-components/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Khan/react-components/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Khan/react-components/teams","hooks_url":"https://api.github.com/repos/Khan/react-components/hooks","issue_events_url":"https://api.github.com/repos/Khan/react-components/issues/events{/number}","events_url":"https://api.github.com/repos/Khan/react-components/events","assignees_url":"https://api.github.com/repos/Khan/react-components/assignees{/user}","branches_url":"https://api.github.com/repos/Khan/react-components/branches{/branch}","tags_url":"https://api.github.com/repos/Khan/react-components/tags","blobs_url":"https://api.github.com/repos/Khan/react-components/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Khan/react-components/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Khan/react-components/git/refs{/sha}","trees_url":"https://api.github.com/repos/Khan/react-components/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Khan/react-components/statuses/{sha}","languages_url":"https://api.github.com/repos/Khan/react-components/languages","stargazers_url":"https://api.github.com/repos/Khan/react-components/stargazers","contributors_url":"https://api.github.com/repos/Khan/react-components/contributors","subscribers_url":"https://api.github.com/repos/Khan/react-components/subscribers","subscription_url":"https://api.github.com/repos/Khan/react-components/subscription","commits_url":"https://api.github.com/repos/Khan/react-components/commits{/sha}","git_commits_url":"https://api.github.com/repos/Khan/react-components/git/commits{/sha}","comments_url":"https://api.github.com/repos/Khan/react-components/comments{/number}","issue_comment_url":"https://api.github.com/repos/Khan/react-components/issues/comments{/number}","contents_url":"https://api.github.com/repos/Khan/react-components/contents/{+path}","compare_url":"https://api.github.com/repos/Khan/react-components/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Khan/react-components/merges","archive_url":"https://api.github.com/repos/Khan/react-components/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Khan/react-components/downloads","issues_url":"https://api.github.com/repos/Khan/react-components/issues{/number}","pulls_url":"https://api.github.com/repos/Khan/react-components/pulls{/number}","milestones_url":"https://api.github.com/repos/Khan/react-components/milestones{/number}","notifications_url":"https://api.github.com/repos/Khan/react-components/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Khan/react-components/labels{/name}","releases_url":"https://api.github.com/repos/Khan/react-components/releases{/id}","created_at":"2014-04-08T22:38:15Z","updated_at":"2015-06-17T14:53:34Z","pushed_at":"2015-06-17T19:11:16Z","git_url":"git://github.com/Khan/react-components.git","ssh_url":"git@github.com:Khan/react-components.git","clone_url":"https://github.com/Khan/react-components.git","svn_url":"https://github.com/Khan/react-components","homepage":"khan.github.io/react-components/","size":39018,"stargazers_count":389,"watchers_count":389,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":33,"mirror_url":null,"open_issues_count":15,"forks":33,"open_issues":15,"watchers":389,"default_branch":"master"}},"base":{"label":"Khan:master","ref":"master","sha":"622fe2a54acec5b3e764d3fce7d5af51844e2806","user":{"login":"Khan","id":15455,"avatar_url":"https://avatars.githubusercontent.com/u/15455?v=3","gravatar_id":"","url":"https://api.github.com/users/Khan","html_url":"https://github.com/Khan","followers_url":"https://api.github.com/users/Khan/followers","following_url":"https://api.github.com/users/Khan/following{/other_user}","gists_url":"https://api.github.com/users/Khan/gists{/gist_id}","starred_url":"https://api.github.com/users/Khan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Khan/subscriptions","organizations_url":"https://api.github.com/users/Khan/orgs","repos_url":"https://api.github.com/users/Khan/repos","events_url":"https://api.github.com/users/Khan/events{/privacy}","received_events_url":"https://api.github.com/users/Khan/received_events","type":"Organization","site_admin":false},"repo":{"id":18577404,"name":"react-components","full_name":"Khan/react-components","owner":{"login":"Khan","id":15455,"avatar_url":"https://avatars.githubusercontent.com/u/15455?v=3","gravatar_id":"","url":"https://api.github.com/users/Khan","html_url":"https://github.com/Khan","followers_url":"https://api.github.com/users/Khan/followers","following_url":"https://api.github.com/users/Khan/following{/other_user}","gists_url":"https://api.github.com/users/Khan/gists{/gist_id}","starred_url":"https://api.github.com/users/Khan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Khan/subscriptions","organizations_url":"https://api.github.com/users/Khan/orgs","repos_url":"https://api.github.com/users/Khan/repos","events_url":"https://api.github.com/users/Khan/events{/privacy}","received_events_url":"https://api.github.com/users/Khan/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Khan/react-components","description":"","fork":false,"url":"https://api.github.com/repos/Khan/react-components","forks_url":"https://api.github.com/repos/Khan/react-components/forks","keys_url":"https://api.github.com/repos/Khan/react-components/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Khan/react-components/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Khan/react-components/teams","hooks_url":"https://api.github.com/repos/Khan/react-components/hooks","issue_events_url":"https://api.github.com/repos/Khan/react-components/issues/events{/number}","events_url":"https://api.github.com/repos/Khan/react-components/events","assignees_url":"https://api.github.com/repos/Khan/react-components/assignees{/user}","branches_url":"https://api.github.com/repos/Khan/react-components/branches{/branch}","tags_url":"https://api.github.com/repos/Khan/react-components/tags","blobs_url":"https://api.github.com/repos/Khan/react-components/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Khan/react-components/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Khan/react-components/git/refs{/sha}","trees_url":"https://api.github.com/repos/Khan/react-components/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Khan/react-components/statuses/{sha}","languages_url":"https://api.github.com/repos/Khan/react-components/languages","stargazers_url":"https://api.github.com/repos/Khan/react-components/stargazers","contributors_url":"https://api.github.com/repos/Khan/react-components/contributors","subscribers_url":"https://api.github.com/repos/Khan/react-components/subscribers","subscription_url":"https://api.github.com/repos/Khan/react-components/subscription","commits_url":"https://api.github.com/repos/Khan/react-components/commits{/sha}","git_commits_url":"https://api.github.com/repos/Khan/react-components/git/commits{/sha}","comments_url":"https://api.github.com/repos/Khan/react-components/comments{/number}","issue_comment_url":"https://api.github.com/repos/Khan/react-components/issues/comments{/number}","contents_url":"https://api.github.com/repos/Khan/react-components/contents/{+path}","compare_url":"https://api.github.com/repos/Khan/react-components/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Khan/react-components/merges","archive_url":"https://api.github.com/repos/Khan/react-components/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Khan/react-components/downloads","issues_url":"https://api.github.com/repos/Khan/react-components/issues{/number}","pulls_url":"https://api.github.com/repos/Khan/react-components/pulls{/number}","milestones_url":"https://api.github.com/repos/Khan/react-components/milestones{/number}","notifications_url":"https://api.github.com/repos/Khan/react-components/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Khan/react-components/labels{/name}","releases_url":"https://api.github.com/repos/Khan/react-components/releases{/id}","created_at":"2014-04-08T22:38:15Z","updated_at":"2015-06-17T14:53:34Z","pushed_at":"2015-06-17T19:11:16Z","git_url":"git://github.com/Khan/react-components.git","ssh_url":"git@github.com:Khan/react-components.git","clone_url":"https://github.com/Khan/react-components.git","svn_url":"https://github.com/Khan/react-components","homepage":"khan.github.io/react-components/","size":39018,"stargazers_count":389,"watchers_count":389,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":33,"mirror_url":null,"open_issues_count":15,"forks":33,"open_issues":15,"watchers":389,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/Khan/react-components/pulls/41"},"html":{"href":"https://github.com/Khan/react-components/pull/41"},"issue":{"href":"https://api.github.com/repos/Khan/react-components/issues/41"},"comments":{"href":"https://api.github.com/repos/Khan/react-components/issues/41/comments"},"review_comments":{"href":"https://api.github.com/repos/Khan/react-components/pulls/41/comments"},"review_comment":{"href":"https://api.github.com/repos/Khan/react-components/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/Khan/react-components/pulls/41/commits"},"statuses":{"href":"https://api.github.com/repos/Khan/react-components/statuses/15bfb385bc9e74b63c3c8d94d2957550f8b141e7"}}}}